diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11a Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11a Checkpoint.ipynb new file mode 100644 index 0000000..5dffaa0 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11a Checkpoint.ipynb @@ -0,0 +1,231 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.1 Agricultural Environments\n", + "# Checkpoint: A11a\n", + "# Authors: Sherrie Wang, George Azzari\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##############################\n", + "# 1. Pull all Landsat 7 and 8 images over study area\n", + "##############################\n", + "\n", + "# Define study area.\n", + "TIGER = ee.FeatureCollection('TIGER/2018/Counties')\n", + "region = ee.Feature(TIGER \\\n", + " .filter(ee.Filter.eq('STATEFP', '17')) \\\n", + " .filter(ee.Filter.eq('NAME', 'McLean')) \\\n", + " .first())\n", + "geometry = region.geometry()\n", + "Map.centerObject(region)\n", + "Map.addLayer(region, {\n", + " 'color': 'red'\n", + "}, 'McLean County')\n", + "\n", + "# Import Landsat imagery.\n", + "landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2')\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "\n", + "# Functions to rename Landsat 7 and 8 images.\n", + "def renameL7(img):\n", + " return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1',\n", + " 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD',\n", + " 'ATRAN', 'CDIST',\n", + " 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD',\n", + " 'QA_PIXEL',\n", + " 'QA_RADSAT'\n", + " ])\n", + "\n", + "\n", + "def renameL8(img):\n", + " return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR',\n", + " 'SWIR1',\n", + " 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST',\n", + " 'DRAD', 'EMIS',\n", + " 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT'\n", + " ])\n", + "\n", + "\n", + "# Functions to mask out clouds, shadows, and other unwanted features.\n", + "def addMask(img):\n", + " # Bit 0: Fill\n", + " # Bit 1: Dilated Cloud\n", + " # Bit 2: Cirrus (high confidence) (L8) or unused (L7)\n", + " # Bit 3: Cloud\n", + " # Bit 4: Cloud Shadow\n", + " # Bit 5: Snow\n", + " # Bit 6: Clear\n", + " # 0: Cloud or Dilated Cloud bits are set\n", + " # 1: Cloud and Dilated Cloud bits are not set\n", + " # Bit 7: Water\n", + " clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0)\n", + " clear = clear.updateMask(clear).rename(['pxqa_clear'])\n", + "\n", + " water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0)\n", + " water = water.updateMask(water).rename(['pxqa_water'])\n", + "\n", + " cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0)\n", + " cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([\n", + " 'pxqa_cloudshadow'\n", + " ])\n", + "\n", + " snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0)\n", + " snow = snow.updateMask(snow).rename(['pxqa_snow'])\n", + "\n", + " masks = ee.Image.cat([\n", + " clear, water, cloud_shadow, snow\n", + " ])\n", + "\n", + " return img.addBands(masks)\n", + "\n", + "\n", + "def maskQAClear(img):\n", + " return img.updateMask(img.select('pxqa_clear'))\n", + "\n", + "\n", + "# Function to add GCVI as a band.\n", + "def addVIs(img):\n", + " gcvi = img.expression('(nir / green) - 1', {\n", + " 'nir': img.select('NIR'),\n", + " 'green': img.select('GREEN')\n", + " }).select([0], ['GCVI'])\n", + "\n", + " return ee.Image.cat([img, gcvi])\n", + "\n", + "\n", + "# Define study time period.\n", + "start_date = '2020-01-01'\n", + "end_date = '2020-12-31'\n", + "\n", + "# Pull Landsat 7 and 8 imagery over the study area between start and end dates.\n", + "landsat7coll = landsat7 \\\n", + " .filterBounds(geometry) \\\n", + " .filterDate(start_date, end_date) \\\n", + " .map(renameL7)\n", + "\n", + "landsat8coll = landsat8 \\\n", + " .filterDate(start_date, end_date) \\\n", + " .filterBounds(geometry) \\\n", + " .map(renameL8)\n", + "\n", + "# Merge Landsat 7 and 8 collections.\n", + "landsat = landsat7coll.merge(landsat8coll) \\\n", + " .sort('system:time_start')\n", + "\n", + "# Mask out non-clear pixels, add VIs and time variables.\n", + "landsat = landsat.map(addMask) \\\n", + " .map(maskQAClear) \\\n", + " .map(addVIs)\n", + "\n", + "# Visualize GCVI time series at one location.\n", + "point = ee.Geometry.Point([-88.81417685576481,\n", + " 40.579804398254005\n", + "])\n", + "landsatChart = ui.Chart.image.series(landsat.select('GCVI'),\n", + " point) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat GCVI time series',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsatChart)\n", + "\n", + "# Get crop type dataset.\n", + "cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland'])\n", + "Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11a Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11a Checkpoint.js new file mode 100644 index 0000000..3c3ee80 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11a Checkpoint.js @@ -0,0 +1,138 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.1 Agricultural Environments +// Checkpoint: A11a +// Authors: Sherrie Wang, George Azzari +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//////////////////////////////////////////////////////////// +// 1. Pull all Landsat 7 and 8 images over study area +//////////////////////////////////////////////////////////// + +// Define study area. +var TIGER = ee.FeatureCollection('TIGER/2018/Counties'); +var region = ee.Feature(TIGER + .filter(ee.Filter.eq('STATEFP', '17')) + .filter(ee.Filter.eq('NAME', 'McLean')) + .first()); +var geometry = region.geometry(); +Map.centerObject(region); +Map.addLayer(region, { + 'color': 'red' +}, 'McLean County'); + +// Import Landsat imagery. +var landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2'); +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); + +// Functions to rename Landsat 7 and 8 images. +function renameL7(img) { + return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', + 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD', + 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD', + 'QA_PIXEL', + 'QA_RADSAT' + ]); +} + +function renameL8(img) { + return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR', + 'SWIR1', + 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', + 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT' + ]); +} + +// Functions to mask out clouds, shadows, and other unwanted features. +function addMask(img) { + // Bit 0: Fill + // Bit 1: Dilated Cloud + // Bit 2: Cirrus (high confidence) (L8) or unused (L7) + // Bit 3: Cloud + // Bit 4: Cloud Shadow + // Bit 5: Snow + // Bit 6: Clear + // 0: Cloud or Dilated Cloud bits are set + // 1: Cloud and Dilated Cloud bits are not set + // Bit 7: Water + var clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0); + clear = clear.updateMask(clear).rename(['pxqa_clear']); + + var water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0); + water = water.updateMask(water).rename(['pxqa_water']); + + var cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0); + cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([ + 'pxqa_cloudshadow' + ]); + + var snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0); + snow = snow.updateMask(snow).rename(['pxqa_snow']); + + var masks = ee.Image.cat([ + clear, water, cloud_shadow, snow + ]); + + return img.addBands(masks); +} + +function maskQAClear(img) { + return img.updateMask(img.select('pxqa_clear')); +} + +// Function to add GCVI as a band. +function addVIs(img){ + var gcvi = img.expression('(nir / green) - 1', { + nir: img.select('NIR'), + green: img.select('GREEN') + }).select([0], ['GCVI']); + + return ee.Image.cat([img, gcvi]); +} + +// Define study time period. +var start_date = '2020-01-01'; +var end_date = '2020-12-31'; + +// Pull Landsat 7 and 8 imagery over the study area between start and end dates. +var landsat7coll = landsat7 + .filterBounds(geometry) + .filterDate(start_date, end_date) + .map(renameL7); + +var landsat8coll = landsat8 + .filterDate(start_date, end_date) + .filterBounds(geometry) + .map(renameL8); + +// Merge Landsat 7 and 8 collections. +var landsat = landsat7coll.merge(landsat8coll) + .sort('system:time_start'); + +// Mask out non-clear pixels, add VIs and time variables. +landsat = landsat.map(addMask) + .map(maskQAClear) + .map(addVIs); + +// Visualize GCVI time series at one location. +var point = ee.Geometry.Point([-88.81417685576481, + 40.579804398254005 +]); +var landsatChart = ui.Chart.image.series(landsat.select('GCVI'), + point) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat GCVI time series', + lineWidth: 1, + pointSize: 3, + }); +print(landsatChart); + +// Get crop type dataset. +var cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland']); +Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11a Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11a Checkpoint.py new file mode 100644 index 0000000..c2be07c --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11a Checkpoint.py @@ -0,0 +1,144 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.1 Agricultural Environments +# Checkpoint: A11a +# Authors: Sherrie Wang, George Azzari +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +############################## +# 1. Pull all Landsat 7 and 8 images over study area +############################## + +# Define study area. +TIGER = ee.FeatureCollection('TIGER/2018/Counties') +region = ee.Feature(TIGER \ + .filter(ee.Filter.eq('STATEFP', '17')) \ + .filter(ee.Filter.eq('NAME', 'McLean')) \ + .first()) +geometry = region.geometry() +Map.centerObject(region) +Map.addLayer(region, { + 'color': 'red' +}, 'McLean County') + +# Import Landsat imagery. +landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + +# Functions to rename Landsat 7 and 8 images. +def renameL7(img): + return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', + 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD', + 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD', + 'QA_PIXEL', + 'QA_RADSAT' + ]) + + +def renameL8(img): + return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR', + 'SWIR1', + 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', + 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT' + ]) + + +# Functions to mask out clouds, shadows, and other unwanted features. +def addMask(img): + # Bit 0: Fill + # Bit 1: Dilated Cloud + # Bit 2: Cirrus (high confidence) (L8) or unused (L7) + # Bit 3: Cloud + # Bit 4: Cloud Shadow + # Bit 5: Snow + # Bit 6: Clear + # 0: Cloud or Dilated Cloud bits are set + # 1: Cloud and Dilated Cloud bits are not set + # Bit 7: Water + clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0) + clear = clear.updateMask(clear).rename(['pxqa_clear']) + + water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0) + water = water.updateMask(water).rename(['pxqa_water']) + + cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0) + cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([ + 'pxqa_cloudshadow' + ]) + + snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0) + snow = snow.updateMask(snow).rename(['pxqa_snow']) + + masks = ee.Image.cat([ + clear, water, cloud_shadow, snow + ]) + + return img.addBands(masks) + + +def maskQAClear(img): + return img.updateMask(img.select('pxqa_clear')) + + +# Function to add GCVI as a band. +def addVIs(img): + gcvi = img.expression('(nir / green) - 1', { + 'nir': img.select('NIR'), + 'green': img.select('GREEN') + }).select([0], ['GCVI']) + + return ee.Image.cat([img, gcvi]) + + +# Define study time period. +start_date = '2020-01-01' +end_date = '2020-12-31' + +# Pull Landsat 7 and 8 imagery over the study area between start and end dates. +landsat7coll = landsat7 \ + .filterBounds(geometry) \ + .filterDate(start_date, end_date) \ + .map(renameL7) + +landsat8coll = landsat8 \ + .filterDate(start_date, end_date) \ + .filterBounds(geometry) \ + .map(renameL8) + +# Merge Landsat 7 and 8 collections. +landsat = landsat7coll.merge(landsat8coll) \ + .sort('system:time_start') + +# Mask out non-clear pixels, add VIs and time variables. +landsat = landsat.map(addMask) \ + .map(maskQAClear) \ + .map(addVIs) + +# Visualize GCVI time series at one location. +point = ee.Geometry.Point([-88.81417685576481, + 40.579804398254005 +]) +landsatChart = ui.Chart.image.series(landsat.select('GCVI'), + point) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat GCVI time series', + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsatChart) + +# Get crop type dataset. +cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland']) +Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11b Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11b Checkpoint.ipynb new file mode 100644 index 0000000..7fd3fb1 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11b Checkpoint.ipynb @@ -0,0 +1,276 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.1 Agricultural Environments\n", + "# Checkpoint: A11b\n", + "# Authors: Sherrie Wang, George Azzari\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##############################\n", + "# 1. Pull all Landsat 7 and 8 images over study area\n", + "##############################\n", + "\n", + "# Define study area.\n", + "TIGER = ee.FeatureCollection('TIGER/2018/Counties')\n", + "region = ee.Feature(TIGER \\\n", + " .filter(ee.Filter.eq('STATEFP', '17')) \\\n", + " .filter(ee.Filter.eq('NAME', 'McLean')) \\\n", + " .first())\n", + "geometry = region.geometry()\n", + "Map.centerObject(region)\n", + "Map.addLayer(region, {\n", + " 'color': 'red'\n", + "}, 'McLean County')\n", + "\n", + "# Import Landsat imagery.\n", + "landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2')\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "\n", + "# Functions to rename Landsat 7 and 8 images.\n", + "def renameL7(img):\n", + " return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1',\n", + " 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD',\n", + " 'ATRAN', 'CDIST',\n", + " 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD',\n", + " 'QA_PIXEL',\n", + " 'QA_RADSAT'\n", + " ])\n", + "\n", + "\n", + "def renameL8(img):\n", + " return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR',\n", + " 'SWIR1',\n", + " 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST',\n", + " 'DRAD', 'EMIS',\n", + " 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT'\n", + " ])\n", + "\n", + "\n", + "# Functions to mask out clouds, shadows, and other unwanted features.\n", + "def addMask(img):\n", + " # Bit 0: Fill\n", + " # Bit 1: Dilated Cloud\n", + " # Bit 2: Cirrus (high confidence) (L8) or unused (L7)\n", + " # Bit 3: Cloud\n", + " # Bit 4: Cloud Shadow\n", + " # Bit 5: Snow\n", + " # Bit 6: Clear\n", + " # 0: Cloud or Dilated Cloud bits are set\n", + " # 1: Cloud and Dilated Cloud bits are not set\n", + " # Bit 7: Water\n", + " clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0)\n", + " clear = clear.updateMask(clear).rename(['pxqa_clear'])\n", + "\n", + " water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0)\n", + " water = water.updateMask(water).rename(['pxqa_water'])\n", + "\n", + " cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0)\n", + " cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([\n", + " 'pxqa_cloudshadow'\n", + " ])\n", + "\n", + " snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0)\n", + " snow = snow.updateMask(snow).rename(['pxqa_snow'])\n", + "\n", + " masks = ee.Image.cat([\n", + " clear, water, cloud_shadow, snow\n", + " ])\n", + "\n", + " return img.addBands(masks)\n", + "\n", + "\n", + "def maskQAClear(img):\n", + " return img.updateMask(img.select('pxqa_clear'))\n", + "\n", + "\n", + "# Function to add GCVI as a band.\n", + "def addVIs(img):\n", + " gcvi = img.expression('(nir / green) - 1', {\n", + " 'nir': img.select('NIR'),\n", + " 'green': img.select('GREEN')\n", + " }).select([0], ['GCVI'])\n", + "\n", + " return ee.Image.cat([img, gcvi])\n", + "\n", + "\n", + "# Define study time period.\n", + "start_date = '2020-01-01'\n", + "end_date = '2020-12-31'\n", + "\n", + "# Pull Landsat 7 and 8 imagery over the study area between start and end dates.\n", + "landsat7coll = landsat7 \\\n", + " .filterBounds(geometry) \\\n", + " .filterDate(start_date, end_date) \\\n", + " .map(renameL7)\n", + "\n", + "landsat8coll = landsat8 \\\n", + " .filterDate(start_date, end_date) \\\n", + " .filterBounds(geometry) \\\n", + " .map(renameL8)\n", + "\n", + "# Merge Landsat 7 and 8 collections.\n", + "landsat = landsat7coll.merge(landsat8coll) \\\n", + " .sort('system:time_start')\n", + "\n", + "# Mask out non-clear pixels, add VIs and time variables.\n", + "landsat = landsat.map(addMask) \\\n", + " .map(maskQAClear) \\\n", + " .map(addVIs)\n", + "\n", + "# Visualize GCVI time series at one location.\n", + "point = ee.Geometry.Point([-88.81417685576481,\n", + " 40.579804398254005\n", + "])\n", + "landsatChart = ui.Chart.image.series(landsat.select('GCVI'),\n", + " point) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat GCVI time series',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsatChart)\n", + "\n", + "# Get crop type dataset.\n", + "cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland'])\n", + "Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##############################\n", + "# 2. Add bands for harmonics\n", + "##############################\n", + "\n", + "# Function that adds time band to an image.\n", + "def addTimeUnit(image, refdate):\n", + " date = image.date()\n", + "\n", + " dyear = date.difference(refdate, 'year')\n", + " t = image.select(0).multiply(0).add(dyear).select([0], ['t']) \\\n", + " .float()\n", + "\n", + " imageplus = image.addBands(t)\n", + "\n", + " return imageplus\n", + "\n", + "\n", + "# Function that adds harmonic basis to an image.\n", + "def addHarmonics(image, omega, refdate):\n", + " image = addTimeUnit(image, refdate)\n", + " timeRadians = image.select('t').multiply(2 * math.pi * omega)\n", + " timeRadians2 = image.select('t').multiply(4 * math.pi *\n", + " omega)\n", + "\n", + " return image \\\n", + " .addBands(timeRadians.cos().rename('cos')) \\\n", + " .addBands(timeRadians.sin().rename('sin')) \\\n", + " .addBands(timeRadians2.cos().rename('cos2')) \\\n", + " .addBands(timeRadians2.sin().rename('sin2')) \\\n", + " .addBands(timeRadians.divide(timeRadians) \\\n", + " .rename('constant'))\n", + "\n", + "\n", + "# Apply addHarmonics to Landsat image collection.\n", + "omega = 1\n", + "landsatPlus = landsat.map(\n", + " def function(image):\n", + " return addHarmonics(image, omega, start_date)\n", + " )\n", + "print('Landsat collection with harmonic basis: ', landsatPlus)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11b Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11b Checkpoint.js new file mode 100644 index 0000000..51c646e --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11b Checkpoint.js @@ -0,0 +1,184 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.1 Agricultural Environments +// Checkpoint: A11b +// Authors: Sherrie Wang, George Azzari +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//////////////////////////////////////////////////////////// +// 1. Pull all Landsat 7 and 8 images over study area +//////////////////////////////////////////////////////////// + +// Define study area. +var TIGER = ee.FeatureCollection('TIGER/2018/Counties'); +var region = ee.Feature(TIGER + .filter(ee.Filter.eq('STATEFP', '17')) + .filter(ee.Filter.eq('NAME', 'McLean')) + .first()); +var geometry = region.geometry(); +Map.centerObject(region); +Map.addLayer(region, { + 'color': 'red' +}, 'McLean County'); + +// Import Landsat imagery. +var landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2'); +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); + +// Functions to rename Landsat 7 and 8 images. +function renameL7(img) { + return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', + 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD', + 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD', + 'QA_PIXEL', + 'QA_RADSAT' + ]); +} + +function renameL8(img) { + return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR', + 'SWIR1', + 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', + 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT' + ]); +} + +// Functions to mask out clouds, shadows, and other unwanted features. +function addMask(img) { + // Bit 0: Fill + // Bit 1: Dilated Cloud + // Bit 2: Cirrus (high confidence) (L8) or unused (L7) + // Bit 3: Cloud + // Bit 4: Cloud Shadow + // Bit 5: Snow + // Bit 6: Clear + // 0: Cloud or Dilated Cloud bits are set + // 1: Cloud and Dilated Cloud bits are not set + // Bit 7: Water + var clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0); + clear = clear.updateMask(clear).rename(['pxqa_clear']); + + var water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0); + water = water.updateMask(water).rename(['pxqa_water']); + + var cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0); + cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([ + 'pxqa_cloudshadow' + ]); + + var snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0); + snow = snow.updateMask(snow).rename(['pxqa_snow']); + + var masks = ee.Image.cat([ + clear, water, cloud_shadow, snow + ]); + + return img.addBands(masks); +} + +function maskQAClear(img) { + return img.updateMask(img.select('pxqa_clear')); +} + +// Function to add GCVI as a band. +function addVIs(img){ + var gcvi = img.expression('(nir / green) - 1', { + nir: img.select('NIR'), + green: img.select('GREEN') + }).select([0], ['GCVI']); + + return ee.Image.cat([img, gcvi]); +} + +// Define study time period. +var start_date = '2020-01-01'; +var end_date = '2020-12-31'; + +// Pull Landsat 7 and 8 imagery over the study area between start and end dates. +var landsat7coll = landsat7 + .filterBounds(geometry) + .filterDate(start_date, end_date) + .map(renameL7); + +var landsat8coll = landsat8 + .filterDate(start_date, end_date) + .filterBounds(geometry) + .map(renameL8); + +// Merge Landsat 7 and 8 collections. +var landsat = landsat7coll.merge(landsat8coll) + .sort('system:time_start'); + +// Mask out non-clear pixels, add VIs and time variables. +landsat = landsat.map(addMask) + .map(maskQAClear) + .map(addVIs); + +// Visualize GCVI time series at one location. +var point = ee.Geometry.Point([-88.81417685576481, + 40.579804398254005 +]); +var landsatChart = ui.Chart.image.series(landsat.select('GCVI'), + point) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat GCVI time series', + lineWidth: 1, + pointSize: 3, + }); +print(landsatChart); + +// Get crop type dataset. +var cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland']); +Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//////////////////////////////////////////////////////////// +// 2. Add bands for harmonics +//////////////////////////////////////////////////////////// + +// Function that adds time band to an image. +function addTimeUnit(image, refdate) { + var date = image.date(); + + var dyear = date.difference(refdate, 'year'); + var t = image.select(0).multiply(0).add(dyear).select([0], ['t']) + .float(); + + var imageplus = image.addBands(t); + + return imageplus; +} + +// Function that adds harmonic basis to an image. +function addHarmonics(image, omega, refdate) { + image = addTimeUnit(image, refdate); + var timeRadians = image.select('t').multiply(2 * Math.PI * omega); + var timeRadians2 = image.select('t').multiply(4 * Math.PI * + omega); + + return image + .addBands(timeRadians.cos().rename('cos')) + .addBands(timeRadians.sin().rename('sin')) + .addBands(timeRadians2.cos().rename('cos2')) + .addBands(timeRadians2.sin().rename('sin2')) + .addBands(timeRadians.divide(timeRadians) + .rename('constant')); +} + +// Apply addHarmonics to Landsat image collection. +var omega = 1; +var landsatPlus = landsat.map( + function(image) { + return addHarmonics(image, omega, start_date); + }); +print('Landsat collection with harmonic basis: ', landsatPlus); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11b Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11b Checkpoint.py new file mode 100644 index 0000000..c24ab3c --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11b Checkpoint.py @@ -0,0 +1,191 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.1 Agricultural Environments +# Checkpoint: A11b +# Authors: Sherrie Wang, George Azzari +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +############################## +# 1. Pull all Landsat 7 and 8 images over study area +############################## + +# Define study area. +TIGER = ee.FeatureCollection('TIGER/2018/Counties') +region = ee.Feature(TIGER \ + .filter(ee.Filter.eq('STATEFP', '17')) \ + .filter(ee.Filter.eq('NAME', 'McLean')) \ + .first()) +geometry = region.geometry() +Map.centerObject(region) +Map.addLayer(region, { + 'color': 'red' +}, 'McLean County') + +# Import Landsat imagery. +landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + +# Functions to rename Landsat 7 and 8 images. +def renameL7(img): + return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', + 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD', + 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD', + 'QA_PIXEL', + 'QA_RADSAT' + ]) + + +def renameL8(img): + return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR', + 'SWIR1', + 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', + 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT' + ]) + + +# Functions to mask out clouds, shadows, and other unwanted features. +def addMask(img): + # Bit 0: Fill + # Bit 1: Dilated Cloud + # Bit 2: Cirrus (high confidence) (L8) or unused (L7) + # Bit 3: Cloud + # Bit 4: Cloud Shadow + # Bit 5: Snow + # Bit 6: Clear + # 0: Cloud or Dilated Cloud bits are set + # 1: Cloud and Dilated Cloud bits are not set + # Bit 7: Water + clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0) + clear = clear.updateMask(clear).rename(['pxqa_clear']) + + water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0) + water = water.updateMask(water).rename(['pxqa_water']) + + cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0) + cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([ + 'pxqa_cloudshadow' + ]) + + snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0) + snow = snow.updateMask(snow).rename(['pxqa_snow']) + + masks = ee.Image.cat([ + clear, water, cloud_shadow, snow + ]) + + return img.addBands(masks) + + +def maskQAClear(img): + return img.updateMask(img.select('pxqa_clear')) + + +# Function to add GCVI as a band. +def addVIs(img): + gcvi = img.expression('(nir / green) - 1', { + 'nir': img.select('NIR'), + 'green': img.select('GREEN') + }).select([0], ['GCVI']) + + return ee.Image.cat([img, gcvi]) + + +# Define study time period. +start_date = '2020-01-01' +end_date = '2020-12-31' + +# Pull Landsat 7 and 8 imagery over the study area between start and end dates. +landsat7coll = landsat7 \ + .filterBounds(geometry) \ + .filterDate(start_date, end_date) \ + .map(renameL7) + +landsat8coll = landsat8 \ + .filterDate(start_date, end_date) \ + .filterBounds(geometry) \ + .map(renameL8) + +# Merge Landsat 7 and 8 collections. +landsat = landsat7coll.merge(landsat8coll) \ + .sort('system:time_start') + +# Mask out non-clear pixels, add VIs and time variables. +landsat = landsat.map(addMask) \ + .map(maskQAClear) \ + .map(addVIs) + +# Visualize GCVI time series at one location. +point = ee.Geometry.Point([-88.81417685576481, + 40.579804398254005 +]) +landsatChart = ui.Chart.image.series(landsat.select('GCVI'), + point) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat GCVI time series', + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsatChart) + +# Get crop type dataset. +cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland']) +Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +############################## +# 2. Add bands for harmonics +############################## + +# Function that adds time band to an image. +def addTimeUnit(image, refdate): + date = image.date() + + dyear = date.difference(refdate, 'year') + t = image.select(0).multiply(0).add(dyear).select([0], ['t']) \ + .float() + + imageplus = image.addBands(t) + + return imageplus + + +# Function that adds harmonic basis to an image. +def addHarmonics(image, omega, refdate): + image = addTimeUnit(image, refdate) + timeRadians = image.select('t').multiply(2 * math.pi * omega) + timeRadians2 = image.select('t').multiply(4 * math.pi * + omega) + + return image \ + .addBands(timeRadians.cos().rename('cos')) \ + .addBands(timeRadians.sin().rename('sin')) \ + .addBands(timeRadians2.cos().rename('cos2')) \ + .addBands(timeRadians2.sin().rename('sin2')) \ + .addBands(timeRadians.divide(timeRadians) \ + .rename('constant')) + + +# Apply addHarmonics to Landsat image collection. +omega = 1 +landsatPlus = landsat.map( + def function(image): + return addHarmonics(image, omega, start_date) + ) +print('Landsat collection with harmonic basis: ', landsatPlus) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11c Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11c Checkpoint.ipynb new file mode 100644 index 0000000..bf86007 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11c Checkpoint.ipynb @@ -0,0 +1,414 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.1 Agricultural Environments\n", + "# Checkpoint: A11c\n", + "# Authors: Sherrie Wang, George Azzari\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##############################\n", + "# 1. Pull all Landsat 7 and 8 images over study area\n", + "##############################\n", + "\n", + "# Define study area.\n", + "TIGER = ee.FeatureCollection('TIGER/2018/Counties')\n", + "region = ee.Feature(TIGER \\\n", + " .filter(ee.Filter.eq('STATEFP', '17')) \\\n", + " .filter(ee.Filter.eq('NAME', 'McLean')) \\\n", + " .first())\n", + "geometry = region.geometry()\n", + "Map.centerObject(region)\n", + "Map.addLayer(region, {\n", + " 'color': 'red'\n", + "}, 'McLean County')\n", + "\n", + "# Import Landsat imagery.\n", + "landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2')\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "\n", + "# Functions to rename Landsat 7 and 8 images.\n", + "def renameL7(img):\n", + " return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1',\n", + " 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD',\n", + " 'ATRAN', 'CDIST',\n", + " 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD',\n", + " 'QA_PIXEL',\n", + " 'QA_RADSAT'\n", + " ])\n", + "\n", + "\n", + "def renameL8(img):\n", + " return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR',\n", + " 'SWIR1',\n", + " 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST',\n", + " 'DRAD', 'EMIS',\n", + " 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT'\n", + " ])\n", + "\n", + "\n", + "# Functions to mask out clouds, shadows, and other unwanted features.\n", + "def addMask(img):\n", + " # Bit 0: Fill\n", + " # Bit 1: Dilated Cloud\n", + " # Bit 2: Cirrus (high confidence) (L8) or unused (L7)\n", + " # Bit 3: Cloud\n", + " # Bit 4: Cloud Shadow\n", + " # Bit 5: Snow\n", + " # Bit 6: Clear\n", + " # 0: Cloud or Dilated Cloud bits are set\n", + " # 1: Cloud and Dilated Cloud bits are not set\n", + " # Bit 7: Water\n", + " clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0)\n", + " clear = clear.updateMask(clear).rename(['pxqa_clear'])\n", + "\n", + " water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0)\n", + " water = water.updateMask(water).rename(['pxqa_water'])\n", + "\n", + " cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0)\n", + " cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([\n", + " 'pxqa_cloudshadow'\n", + " ])\n", + "\n", + " snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0)\n", + " snow = snow.updateMask(snow).rename(['pxqa_snow'])\n", + "\n", + " masks = ee.Image.cat([\n", + " clear, water, cloud_shadow, snow\n", + " ])\n", + "\n", + " return img.addBands(masks)\n", + "\n", + "\n", + "def maskQAClear(img):\n", + " return img.updateMask(img.select('pxqa_clear'))\n", + "\n", + "\n", + "# Function to add GCVI as a band.\n", + "def addVIs(img):\n", + " gcvi = img.expression('(nir / green) - 1', {\n", + " 'nir': img.select('NIR'),\n", + " 'green': img.select('GREEN')\n", + " }).select([0], ['GCVI'])\n", + "\n", + " return ee.Image.cat([img, gcvi])\n", + "\n", + "\n", + "# Define study time period.\n", + "start_date = '2020-01-01'\n", + "end_date = '2020-12-31'\n", + "\n", + "# Pull Landsat 7 and 8 imagery over the study area between start and end dates.\n", + "landsat7coll = landsat7 \\\n", + " .filterBounds(geometry) \\\n", + " .filterDate(start_date, end_date) \\\n", + " .map(renameL7)\n", + "\n", + "landsat8coll = landsat8 \\\n", + " .filterDate(start_date, end_date) \\\n", + " .filterBounds(geometry) \\\n", + " .map(renameL8)\n", + "\n", + "# Merge Landsat 7 and 8 collections.\n", + "landsat = landsat7coll.merge(landsat8coll) \\\n", + " .sort('system:time_start')\n", + "\n", + "# Mask out non-clear pixels, add VIs and time variables.\n", + "landsat = landsat.map(addMask) \\\n", + " .map(maskQAClear) \\\n", + " .map(addVIs)\n", + "\n", + "# Visualize GCVI time series at one location.\n", + "point = ee.Geometry.Point([-88.81417685576481,\n", + " 40.579804398254005\n", + "])\n", + "landsatChart = ui.Chart.image.series(landsat.select('GCVI'),\n", + " point) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat GCVI time series',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsatChart)\n", + "\n", + "# Get crop type dataset.\n", + "cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland'])\n", + "Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##############################\n", + "# 2. Add bands for harmonics\n", + "##############################\n", + "\n", + "# Function that adds time band to an image.\n", + "def addTimeUnit(image, refdate):\n", + " date = image.date()\n", + "\n", + " dyear = date.difference(refdate, 'year')\n", + " t = image.select(0).multiply(0).add(dyear).select([0], ['t']) \\\n", + " .float()\n", + "\n", + " imageplus = image.addBands(t)\n", + "\n", + " return imageplus\n", + "\n", + "\n", + "# Function that adds harmonic basis to an image.\n", + "def addHarmonics(image, omega, refdate):\n", + " image = addTimeUnit(image, refdate)\n", + " timeRadians = image.select('t').multiply(2 * math.pi * omega)\n", + " timeRadians2 = image.select('t').multiply(4 * math.pi *\n", + " omega)\n", + "\n", + " return image \\\n", + " .addBands(timeRadians.cos().rename('cos')) \\\n", + " .addBands(timeRadians.sin().rename('sin')) \\\n", + " .addBands(timeRadians2.cos().rename('cos2')) \\\n", + " .addBands(timeRadians2.sin().rename('sin2')) \\\n", + " .addBands(timeRadians.divide(timeRadians) \\\n", + " .rename('constant'))\n", + "\n", + "\n", + "# Apply addHarmonics to Landsat image collection.\n", + "omega = 1\n", + "landsatPlus = landsat.map(\n", + " def function(image):\n", + " return addHarmonics(image, omega, start_date)\n", + " )\n", + "print('Landsat collection with harmonic basis: ', landsatPlus)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##############################\n", + "# 3. Get harmonic coefficients\n", + "##############################\n", + "\n", + "# Function to run linear regression on an image.\n", + "def arrayimgHarmonicRegr(harmonicColl, dependent, independents):\n", + "\n", + " independents = ee.List(independents)\n", + " dependent = ee.String(dependent)\n", + "\n", + " regression = harmonicColl \\\n", + " .select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(),\n", + " 1))\n", + "\n", + " return regression\n", + "\n", + "\n", + "# Function to extract and rename regression coefficients.\n", + "def imageHarmonicRegr(harmonicColl, dependent, independents):\n", + "\n", + " hregr = arrayimgHarmonicRegr(harmonicColl, dependent,\n", + " independents)\n", + "\n", + " independents = ee.List(independents)\n", + " dependent = ee.String(dependent)\n", + "\n", + "\n", + "def func_afr(b):\n", + " return dependent.cat(ee.String('_')).cat(ee.String(\n", + " b))\n", + "\n", + " newNames = independents.map(func_afr)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " imgCoeffs = hregr.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents]) \\\n", + " .select(independents, newNames)\n", + "\n", + " return imgCoeffs\n", + "\n", + "\n", + "# Function to apply imageHarmonicRegr and create a multi-band image.\n", + "def getHarmonicCoeffs(harmonicColl, bands, independents):\n", + " coefficients = ee.ImageCollection.fromImages(bands.map(\n", + " def function(band):\n", + " return imageHarmonicRegr(harmonicColl, band,\n", + " independents)\n", + " ))\n", + " return coefficients.toBands()\n", + "\n", + "\n", + "# Apply getHarmonicCoeffs to ImageCollection.\n", + "bands = ['NIR', 'SWIR1', 'SWIR2', 'GCVI']\n", + "independents = ee.List(['constant', 'cos', 'sin', 'cos2',\n", + "'sin2'])\n", + "harmonics = getHarmonicCoeffs(landsatPlus, bands, independents)\n", + "\n", + "harmonics = harmonics.clip(geometry)\n", + "harmonics = harmonics.multiply(10000).toInt32()\n", + "\n", + "# Compute fitted values.\n", + "gcviHarmonicCoefficients = harmonics \\\n", + " .select([\n", + " '3_GCVI_constant', '3_GCVI_cos',\n", + " '3_GCVI_sin', '3_GCVI_cos2', '3_GCVI_sin2'\n", + " ]) \\\n", + " .divide(10000)\n", + "\n", + "\n", + "def func_gnr(image):\n", + " return image.addBands(\n", + " image.select(independents) \\\n", + " .multiply(gcviHarmonicCoefficients) \\\n", + " .reduce('sum') \\\n", + " .rename('fitted')\n", + " )\n", + "\n", + "fittedHarmonic = landsatPlus.map(func_gnr)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Visualize the fitted harmonics in a chart.\n", + "harmonicsChart = ui.Chart.image.series(\n", + " fittedHarmonic.select(\n", + " ['fitted', 'GCVI']), point, ee.Reducer.mean(), 30) \\\n", + " .setSeriesNames(['GCVI', 'Fitted']) \\\n", + " .setOptions({\n", + " 'title': 'Landsat GCVI time series and fitted harmonic regression values',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "\n", + "print(harmonicsChart)\n", + "\n", + "# Add CDL as a band to the harmonics.\n", + "harmonicsPlus = ee.Image.cat([harmonics, cdl])\n", + "\n", + "# Export image to asset.\n", + "filename = 'McLean_County_harmonics'\n", + "Export.image.toAsset({\n", + " 'image': harmonicsPlus,\n", + " 'description': filename,\n", + " 'assetId': 'your_asset_path_here/' + filename,\n", + " 'dimensions': None,\n", + " 'region': region,\n", + " 'scale': 30,\n", + " 'maxPixels': 1e12\n", + "})\n", + "\n", + "\n", + "# Visualize harmonic coefficients on map.\n", + "visImage = ee.Image.cat([\n", + " harmonics.select('3_GCVI_cos').divide(7000).add(0.6),\n", + " harmonics.select('3_GCVI_sin').divide(7000).add(0.5),\n", + " harmonics.select('3_GCVI_constant').divide(7000).subtract(\n", + " 0.6)\n", + "])\n", + "\n", + "Map.addLayer(visImage, {\n", + " 'min': -0.5,\n", + " 'max': 0.5\n", + "}, 'Harmonic coefficient False color')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11c Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11c Checkpoint.js new file mode 100644 index 0000000..2cf8725 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11c Checkpoint.js @@ -0,0 +1,306 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.1 Agricultural Environments +// Checkpoint: A11c +// Authors: Sherrie Wang, George Azzari +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//////////////////////////////////////////////////////////// +// 1. Pull all Landsat 7 and 8 images over study area +//////////////////////////////////////////////////////////// + +// Define study area. +var TIGER = ee.FeatureCollection('TIGER/2018/Counties'); +var region = ee.Feature(TIGER + .filter(ee.Filter.eq('STATEFP', '17')) + .filter(ee.Filter.eq('NAME', 'McLean')) + .first()); +var geometry = region.geometry(); +Map.centerObject(region); +Map.addLayer(region, { + 'color': 'red' +}, 'McLean County'); + +// Import Landsat imagery. +var landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2'); +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); + +// Functions to rename Landsat 7 and 8 images. +function renameL7(img) { + return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', + 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD', + 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD', + 'QA_PIXEL', + 'QA_RADSAT' + ]); +} + +function renameL8(img) { + return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR', + 'SWIR1', + 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', + 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT' + ]); +} + +// Functions to mask out clouds, shadows, and other unwanted features. +function addMask(img) { + // Bit 0: Fill + // Bit 1: Dilated Cloud + // Bit 2: Cirrus (high confidence) (L8) or unused (L7) + // Bit 3: Cloud + // Bit 4: Cloud Shadow + // Bit 5: Snow + // Bit 6: Clear + // 0: Cloud or Dilated Cloud bits are set + // 1: Cloud and Dilated Cloud bits are not set + // Bit 7: Water + var clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0); + clear = clear.updateMask(clear).rename(['pxqa_clear']); + + var water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0); + water = water.updateMask(water).rename(['pxqa_water']); + + var cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0); + cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([ + 'pxqa_cloudshadow' + ]); + + var snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0); + snow = snow.updateMask(snow).rename(['pxqa_snow']); + + var masks = ee.Image.cat([ + clear, water, cloud_shadow, snow + ]); + + return img.addBands(masks); +} + +function maskQAClear(img) { + return img.updateMask(img.select('pxqa_clear')); +} + +// Function to add GCVI as a band. +function addVIs(img){ + var gcvi = img.expression('(nir / green) - 1', { + nir: img.select('NIR'), + green: img.select('GREEN') + }).select([0], ['GCVI']); + + return ee.Image.cat([img, gcvi]); +} + +// Define study time period. +var start_date = '2020-01-01'; +var end_date = '2020-12-31'; + +// Pull Landsat 7 and 8 imagery over the study area between start and end dates. +var landsat7coll = landsat7 + .filterBounds(geometry) + .filterDate(start_date, end_date) + .map(renameL7); + +var landsat8coll = landsat8 + .filterDate(start_date, end_date) + .filterBounds(geometry) + .map(renameL8); + +// Merge Landsat 7 and 8 collections. +var landsat = landsat7coll.merge(landsat8coll) + .sort('system:time_start'); + +// Mask out non-clear pixels, add VIs and time variables. +landsat = landsat.map(addMask) + .map(maskQAClear) + .map(addVIs); + +// Visualize GCVI time series at one location. +var point = ee.Geometry.Point([-88.81417685576481, + 40.579804398254005 +]); +var landsatChart = ui.Chart.image.series(landsat.select('GCVI'), + point) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat GCVI time series', + lineWidth: 1, + pointSize: 3, + }); +print(landsatChart); + +// Get crop type dataset. +var cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland']); +Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//////////////////////////////////////////////////////////// +// 2. Add bands for harmonics +//////////////////////////////////////////////////////////// + +// Function that adds time band to an image. +function addTimeUnit(image, refdate) { + var date = image.date(); + + var dyear = date.difference(refdate, 'year'); + var t = image.select(0).multiply(0).add(dyear).select([0], ['t']) + .float(); + + var imageplus = image.addBands(t); + + return imageplus; +} + +// Function that adds harmonic basis to an image. +function addHarmonics(image, omega, refdate) { + image = addTimeUnit(image, refdate); + var timeRadians = image.select('t').multiply(2 * Math.PI * omega); + var timeRadians2 = image.select('t').multiply(4 * Math.PI * + omega); + + return image + .addBands(timeRadians.cos().rename('cos')) + .addBands(timeRadians.sin().rename('sin')) + .addBands(timeRadians2.cos().rename('cos2')) + .addBands(timeRadians2.sin().rename('sin2')) + .addBands(timeRadians.divide(timeRadians) + .rename('constant')); +} + +// Apply addHarmonics to Landsat image collection. +var omega = 1; +var landsatPlus = landsat.map( + function(image) { + return addHarmonics(image, omega, start_date); + }); +print('Landsat collection with harmonic basis: ', landsatPlus); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//////////////////////////////////////////////////////////// +// 3. Get harmonic coefficients +//////////////////////////////////////////////////////////// + +// Function to run linear regression on an image. +function arrayimgHarmonicRegr(harmonicColl, dependent, independents) { + + independents = ee.List(independents); + dependent = ee.String(dependent); + + var regression = harmonicColl + .select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), + 1)); + + return regression; +} + +// Function to extract and rename regression coefficients. +function imageHarmonicRegr(harmonicColl, dependent, independents) { + + var hregr = arrayimgHarmonicRegr(harmonicColl, dependent, + independents); + + independents = ee.List(independents); + dependent = ee.String(dependent); + + var newNames = independents.map(function(b) { + return dependent.cat(ee.String('_')).cat(ee.String( + b)); + }); + + var imgCoeffs = hregr.select('coefficients') + .arrayProject([0]) + .arrayFlatten([independents]) + .select(independents, newNames); + + return imgCoeffs; +} + +// Function to apply imageHarmonicRegr and create a multi-band image. +function getHarmonicCoeffs(harmonicColl, bands, independents) { + var coefficients = ee.ImageCollection.fromImages(bands.map( + function(band) { + return imageHarmonicRegr(harmonicColl, band, + independents); + })); + return coefficients.toBands(); +} + +// Apply getHarmonicCoeffs to ImageCollection. +var bands = ['NIR', 'SWIR1', 'SWIR2', 'GCVI']; +var independents = ee.List(['constant', 'cos', 'sin', 'cos2', +'sin2']); +var harmonics = getHarmonicCoeffs(landsatPlus, bands, independents); + +harmonics = harmonics.clip(geometry); +harmonics = harmonics.multiply(10000).toInt32(); + +// Compute fitted values. +var gcviHarmonicCoefficients = harmonics + .select([ + '3_GCVI_constant', '3_GCVI_cos', + '3_GCVI_sin', '3_GCVI_cos2', '3_GCVI_sin2' + ]) + .divide(10000); + +var fittedHarmonic = landsatPlus.map(function(image) { + return image.addBands( + image.select(independents) + .multiply(gcviHarmonicCoefficients) + .reduce('sum') + .rename('fitted') + ); +}); + +// Visualize the fitted harmonics in a chart. +var harmonicsChart = ui.Chart.image.series( + fittedHarmonic.select( + ['fitted', 'GCVI']), point, ee.Reducer.mean(), 30) + .setSeriesNames(['GCVI', 'Fitted']) + .setOptions({ + title: 'Landsat GCVI time series and fitted harmonic regression values', + lineWidth: 1, + pointSize: 3, + }); + +print(harmonicsChart); + +// Add CDL as a band to the harmonics. +var harmonicsPlus = ee.Image.cat([harmonics, cdl]); + +// Export image to asset. +var filename = 'McLean_County_harmonics'; +Export.image.toAsset({ + image: harmonicsPlus, + description: filename, + assetId: 'your_asset_path_here/' + filename, + dimensions: null, + region: region, + scale: 30, + maxPixels: 1e12 +}); + + +// Visualize harmonic coefficients on map. +var visImage = ee.Image.cat([ + harmonics.select('3_GCVI_cos').divide(7000).add(0.6), + harmonics.select('3_GCVI_sin').divide(7000).add(0.5), + harmonics.select('3_GCVI_constant').divide(7000).subtract( + 0.6) +]); + +Map.addLayer(visImage, { + min: -0.5, + max: 0.5 +}, 'Harmonic coefficient false color'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11c Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11c Checkpoint.py new file mode 100644 index 0000000..a01c895 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11c Checkpoint.py @@ -0,0 +1,329 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.1 Agricultural Environments +# Checkpoint: A11c +# Authors: Sherrie Wang, George Azzari +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +############################## +# 1. Pull all Landsat 7 and 8 images over study area +############################## + +# Define study area. +TIGER = ee.FeatureCollection('TIGER/2018/Counties') +region = ee.Feature(TIGER \ + .filter(ee.Filter.eq('STATEFP', '17')) \ + .filter(ee.Filter.eq('NAME', 'McLean')) \ + .first()) +geometry = region.geometry() +Map.centerObject(region) +Map.addLayer(region, { + 'color': 'red' +}, 'McLean County') + +# Import Landsat imagery. +landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + +# Functions to rename Landsat 7 and 8 images. +def renameL7(img): + return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', + 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD', + 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD', + 'QA_PIXEL', + 'QA_RADSAT' + ]) + + +def renameL8(img): + return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR', + 'SWIR1', + 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', + 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT' + ]) + + +# Functions to mask out clouds, shadows, and other unwanted features. +def addMask(img): + # Bit 0: Fill + # Bit 1: Dilated Cloud + # Bit 2: Cirrus (high confidence) (L8) or unused (L7) + # Bit 3: Cloud + # Bit 4: Cloud Shadow + # Bit 5: Snow + # Bit 6: Clear + # 0: Cloud or Dilated Cloud bits are set + # 1: Cloud and Dilated Cloud bits are not set + # Bit 7: Water + clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0) + clear = clear.updateMask(clear).rename(['pxqa_clear']) + + water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0) + water = water.updateMask(water).rename(['pxqa_water']) + + cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0) + cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([ + 'pxqa_cloudshadow' + ]) + + snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0) + snow = snow.updateMask(snow).rename(['pxqa_snow']) + + masks = ee.Image.cat([ + clear, water, cloud_shadow, snow + ]) + + return img.addBands(masks) + + +def maskQAClear(img): + return img.updateMask(img.select('pxqa_clear')) + + +# Function to add GCVI as a band. +def addVIs(img): + gcvi = img.expression('(nir / green) - 1', { + 'nir': img.select('NIR'), + 'green': img.select('GREEN') + }).select([0], ['GCVI']) + + return ee.Image.cat([img, gcvi]) + + +# Define study time period. +start_date = '2020-01-01' +end_date = '2020-12-31' + +# Pull Landsat 7 and 8 imagery over the study area between start and end dates. +landsat7coll = landsat7 \ + .filterBounds(geometry) \ + .filterDate(start_date, end_date) \ + .map(renameL7) + +landsat8coll = landsat8 \ + .filterDate(start_date, end_date) \ + .filterBounds(geometry) \ + .map(renameL8) + +# Merge Landsat 7 and 8 collections. +landsat = landsat7coll.merge(landsat8coll) \ + .sort('system:time_start') + +# Mask out non-clear pixels, add VIs and time variables. +landsat = landsat.map(addMask) \ + .map(maskQAClear) \ + .map(addVIs) + +# Visualize GCVI time series at one location. +point = ee.Geometry.Point([-88.81417685576481, + 40.579804398254005 +]) +landsatChart = ui.Chart.image.series(landsat.select('GCVI'), + point) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat GCVI time series', + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsatChart) + +# Get crop type dataset. +cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland']) +Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +############################## +# 2. Add bands for harmonics +############################## + +# Function that adds time band to an image. +def addTimeUnit(image, refdate): + date = image.date() + + dyear = date.difference(refdate, 'year') + t = image.select(0).multiply(0).add(dyear).select([0], ['t']) \ + .float() + + imageplus = image.addBands(t) + + return imageplus + + +# Function that adds harmonic basis to an image. +def addHarmonics(image, omega, refdate): + image = addTimeUnit(image, refdate) + timeRadians = image.select('t').multiply(2 * math.pi * omega) + timeRadians2 = image.select('t').multiply(4 * math.pi * + omega) + + return image \ + .addBands(timeRadians.cos().rename('cos')) \ + .addBands(timeRadians.sin().rename('sin')) \ + .addBands(timeRadians2.cos().rename('cos2')) \ + .addBands(timeRadians2.sin().rename('sin2')) \ + .addBands(timeRadians.divide(timeRadians) \ + .rename('constant')) + + +# Apply addHarmonics to Landsat image collection. +omega = 1 +landsatPlus = landsat.map( + def function(image): + return addHarmonics(image, omega, start_date) + ) +print('Landsat collection with harmonic basis: ', landsatPlus) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +############################## +# 3. Get harmonic coefficients +############################## + +# Function to run linear regression on an image. +def arrayimgHarmonicRegr(harmonicColl, dependent, independents): + + independents = ee.List(independents) + dependent = ee.String(dependent) + + regression = harmonicColl \ + .select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), + 1)) + + return regression + + +# Function to extract and rename regression coefficients. +def imageHarmonicRegr(harmonicColl, dependent, independents): + + hregr = arrayimgHarmonicRegr(harmonicColl, dependent, + independents) + + independents = ee.List(independents) + dependent = ee.String(dependent) + + +def func_afr(b): + return dependent.cat(ee.String('_')).cat(ee.String( + b)) + + newNames = independents.map(func_afr) + + + + + + imgCoeffs = hregr.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) \ + .select(independents, newNames) + + return imgCoeffs + + +# Function to apply imageHarmonicRegr and create a multi-band image. +def getHarmonicCoeffs(harmonicColl, bands, independents): + coefficients = ee.ImageCollection.fromImages(bands.map( + def function(band): + return imageHarmonicRegr(harmonicColl, band, + independents) + )) + return coefficients.toBands() + + +# Apply getHarmonicCoeffs to ImageCollection. +bands = ['NIR', 'SWIR1', 'SWIR2', 'GCVI'] +independents = ee.List(['constant', 'cos', 'sin', 'cos2', +'sin2']) +harmonics = getHarmonicCoeffs(landsatPlus, bands, independents) + +harmonics = harmonics.clip(geometry) +harmonics = harmonics.multiply(10000).toInt32() + +# Compute fitted values. +gcviHarmonicCoefficients = harmonics \ + .select([ + '3_GCVI_constant', '3_GCVI_cos', + '3_GCVI_sin', '3_GCVI_cos2', '3_GCVI_sin2' + ]) \ + .divide(10000) + + +def func_gnr(image): + return image.addBands( + image.select(independents) \ + .multiply(gcviHarmonicCoefficients) \ + .reduce('sum') \ + .rename('fitted') + ) + +fittedHarmonic = landsatPlus.map(func_gnr) + + + + + + + + + +# Visualize the fitted harmonics in a chart. +harmonicsChart = ui.Chart.image.series( + fittedHarmonic.select( + ['fitted', 'GCVI']), point, ee.Reducer.mean(), 30) \ + .setSeriesNames(['GCVI', 'Fitted']) \ + .setOptions({ + 'title': 'Landsat GCVI time series and fitted harmonic regression values', + 'lineWidth': 1, + 'pointSize': 3, + }) + +print(harmonicsChart) + +# Add CDL as a band to the harmonics. +harmonicsPlus = ee.Image.cat([harmonics, cdl]) + +# Export image to asset. +filename = 'McLean_County_harmonics' +Export.image.toAsset({ + 'image': harmonicsPlus, + 'description': filename, + 'assetId': 'your_asset_path_here/' + filename, + 'dimensions': None, + 'region': region, + 'scale': 30, + 'maxPixels': 1e12 +}) + + +# Visualize harmonic coefficients on map. +visImage = ee.Image.cat([ + harmonics.select('3_GCVI_cos').divide(7000).add(0.6), + harmonics.select('3_GCVI_sin').divide(7000).add(0.5), + harmonics.select('3_GCVI_constant').divide(7000).subtract( + 0.6) +]) + +Map.addLayer(visImage, { + 'min': -0.5, + 'max': 0.5 +}, 'Harmonic coefficient False color') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11d Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11d Checkpoint.ipynb new file mode 100644 index 0000000..ab04712 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11d Checkpoint.ipynb @@ -0,0 +1,473 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.1 Agricultural Environments\n", + "# Checkpoint: A11d\n", + "# Authors: Sherrie Wang, George Azzari\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##############################\n", + "# 1. Pull all Landsat 7 and 8 images over study area\n", + "##############################\n", + "\n", + "# Define study area.\n", + "TIGER = ee.FeatureCollection('TIGER/2018/Counties')\n", + "region = ee.Feature(TIGER \\\n", + " .filter(ee.Filter.eq('STATEFP', '17')) \\\n", + " .filter(ee.Filter.eq('NAME', 'McLean')) \\\n", + " .first())\n", + "geometry = region.geometry()\n", + "Map.centerObject(region)\n", + "Map.addLayer(region, {\n", + " 'color': 'red'\n", + "}, 'McLean County')\n", + "\n", + "# Import Landsat imagery.\n", + "landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2')\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "\n", + "# Functions to rename Landsat 7 and 8 images.\n", + "def renameL7(img):\n", + " return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1',\n", + " 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD',\n", + " 'ATRAN', 'CDIST',\n", + " 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD',\n", + " 'QA_PIXEL',\n", + " 'QA_RADSAT'\n", + " ])\n", + "\n", + "\n", + "def renameL8(img):\n", + " return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR',\n", + " 'SWIR1',\n", + " 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST',\n", + " 'DRAD', 'EMIS',\n", + " 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT'\n", + " ])\n", + "\n", + "\n", + "# Functions to mask out clouds, shadows, and other unwanted features.\n", + "def addMask(img):\n", + " # Bit 0: Fill\n", + " # Bit 1: Dilated Cloud\n", + " # Bit 2: Cirrus (high confidence) (L8) or unused (L7)\n", + " # Bit 3: Cloud\n", + " # Bit 4: Cloud Shadow\n", + " # Bit 5: Snow\n", + " # Bit 6: Clear\n", + " # 0: Cloud or Dilated Cloud bits are set\n", + " # 1: Cloud and Dilated Cloud bits are not set\n", + " # Bit 7: Water\n", + " clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0)\n", + " clear = clear.updateMask(clear).rename(['pxqa_clear'])\n", + "\n", + " water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0)\n", + " water = water.updateMask(water).rename(['pxqa_water'])\n", + "\n", + " cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0)\n", + " cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([\n", + " 'pxqa_cloudshadow'\n", + " ])\n", + "\n", + " snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0)\n", + " snow = snow.updateMask(snow).rename(['pxqa_snow'])\n", + "\n", + " masks = ee.Image.cat([\n", + " clear, water, cloud_shadow, snow\n", + " ])\n", + "\n", + " return img.addBands(masks)\n", + "\n", + "\n", + "def maskQAClear(img):\n", + " return img.updateMask(img.select('pxqa_clear'))\n", + "\n", + "\n", + "# Function to add GCVI as a band.\n", + "def addVIs(img):\n", + " gcvi = img.expression('(nir / green) - 1', {\n", + " 'nir': img.select('NIR'),\n", + " 'green': img.select('GREEN')\n", + " }).select([0], ['GCVI'])\n", + "\n", + " return ee.Image.cat([img, gcvi])\n", + "\n", + "\n", + "# Define study time period.\n", + "start_date = '2020-01-01'\n", + "end_date = '2020-12-31'\n", + "\n", + "# Pull Landsat 7 and 8 imagery over the study area between start and end dates.\n", + "landsat7coll = landsat7 \\\n", + " .filterBounds(geometry) \\\n", + " .filterDate(start_date, end_date) \\\n", + " .map(renameL7)\n", + "\n", + "landsat8coll = landsat8 \\\n", + " .filterDate(start_date, end_date) \\\n", + " .filterBounds(geometry) \\\n", + " .map(renameL8)\n", + "\n", + "# Merge Landsat 7 and 8 collections.\n", + "landsat = landsat7coll.merge(landsat8coll) \\\n", + " .sort('system:time_start')\n", + "\n", + "# Mask out non-clear pixels, add VIs and time variables.\n", + "landsat = landsat.map(addMask) \\\n", + " .map(maskQAClear) \\\n", + " .map(addVIs)\n", + "\n", + "# Visualize GCVI time series at one location.\n", + "point = ee.Geometry.Point([-88.81417685576481,\n", + " 40.579804398254005\n", + "])\n", + "landsatChart = ui.Chart.image.series(landsat.select('GCVI'),\n", + " point) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat GCVI time series',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsatChart)\n", + "\n", + "# Get crop type dataset.\n", + "cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland'])\n", + "Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##############################\n", + "# 2. Add bands for harmonics\n", + "##############################\n", + "\n", + "# Function that adds time band to an image.\n", + "def addTimeUnit(image, refdate):\n", + " date = image.date()\n", + "\n", + " dyear = date.difference(refdate, 'year')\n", + " t = image.select(0).multiply(0).add(dyear).select([0], ['t']) \\\n", + " .float()\n", + "\n", + " imageplus = image.addBands(t)\n", + "\n", + " return imageplus\n", + "\n", + "\n", + "# Function that adds harmonic basis to an image.\n", + "def addHarmonics(image, omega, refdate):\n", + " image = addTimeUnit(image, refdate)\n", + " timeRadians = image.select('t').multiply(2 * math.pi * omega)\n", + " timeRadians2 = image.select('t').multiply(4 * math.pi *\n", + " omega)\n", + "\n", + " return image \\\n", + " .addBands(timeRadians.cos().rename('cos')) \\\n", + " .addBands(timeRadians.sin().rename('sin')) \\\n", + " .addBands(timeRadians2.cos().rename('cos2')) \\\n", + " .addBands(timeRadians2.sin().rename('sin2')) \\\n", + " .addBands(timeRadians.divide(timeRadians) \\\n", + " .rename('constant'))\n", + "\n", + "\n", + "# Apply addHarmonics to Landsat image collection.\n", + "omega = 1\n", + "landsatPlus = landsat.map(\n", + " def function(image):\n", + " return addHarmonics(image, omega, start_date)\n", + " )\n", + "print('Landsat collection with harmonic basis: ', landsatPlus)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##############################\n", + "# 3. Get harmonic coefficients\n", + "##############################\n", + "\n", + "# Function to run linear regression on an image.\n", + "def arrayimgHarmonicRegr(harmonicColl, dependent, independents):\n", + "\n", + " independents = ee.List(independents)\n", + " dependent = ee.String(dependent)\n", + "\n", + " regression = harmonicColl \\\n", + " .select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(),\n", + " 1))\n", + "\n", + " return regression\n", + "\n", + "\n", + "# Function to extract and rename regression coefficients.\n", + "def imageHarmonicRegr(harmonicColl, dependent, independents):\n", + "\n", + " hregr = arrayimgHarmonicRegr(harmonicColl, dependent,\n", + " independents)\n", + "\n", + " independents = ee.List(independents)\n", + " dependent = ee.String(dependent)\n", + "\n", + "\n", + "def func_mxk(b):\n", + " return dependent.cat(ee.String('_')).cat(ee.String(\n", + " b))\n", + "\n", + " newNames = independents.map(func_mxk)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " imgCoeffs = hregr.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents]) \\\n", + " .select(independents, newNames)\n", + "\n", + " return imgCoeffs\n", + "\n", + "\n", + "# Function to apply imageHarmonicRegr and create a multi-band image.\n", + "def getHarmonicCoeffs(harmonicColl, bands, independents):\n", + " coefficients = ee.ImageCollection.fromImages(bands.map(\n", + " def function(band):\n", + " return imageHarmonicRegr(harmonicColl, band,\n", + " independents)\n", + " ))\n", + " return coefficients.toBands()\n", + "\n", + "\n", + "# Apply getHarmonicCoeffs to ImageCollection.\n", + "bands = ['NIR', 'SWIR1', 'SWIR2', 'GCVI']\n", + "independents = ee.List(['constant', 'cos', 'sin', 'cos2',\n", + "'sin2'])\n", + "harmonics = getHarmonicCoeffs(landsatPlus, bands, independents)\n", + "\n", + "harmonics = harmonics.clip(geometry)\n", + "harmonics = harmonics.multiply(10000).toInt32()\n", + "\n", + "# Compute fitted values.\n", + "gcviHarmonicCoefficients = harmonics \\\n", + " .select([\n", + " '3_GCVI_constant', '3_GCVI_cos',\n", + " '3_GCVI_sin', '3_GCVI_cos2', '3_GCVI_sin2'\n", + " ]) \\\n", + " .divide(10000)\n", + "\n", + "\n", + "def func_szs(image):\n", + " return image.addBands(\n", + " image.select(independents) \\\n", + " .multiply(gcviHarmonicCoefficients) \\\n", + " .reduce('sum') \\\n", + " .rename('fitted')\n", + " )\n", + "\n", + "fittedHarmonic = landsatPlus.map(func_szs)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Visualize the fitted harmonics in a chart.\n", + "harmonicsChart = ui.Chart.image.series(\n", + " fittedHarmonic.select(\n", + " ['fitted', 'GCVI']), point, ee.Reducer.mean(), 30) \\\n", + " .setSeriesNames(['GCVI', 'Fitted']) \\\n", + " .setOptions({\n", + " 'title': 'Landsat GCVI time series and fitted harmonic regression values',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "\n", + "print(harmonicsChart)\n", + "\n", + "# Add CDL as a band to the harmonics.\n", + "harmonicsPlus = ee.Image.cat([harmonics, cdl])\n", + "\n", + "# Export image to asset.\n", + "filename = 'McLean_County_harmonics'\n", + "Export.image.toAsset({\n", + " 'image': harmonicsPlus,\n", + " 'description': filename,\n", + " 'assetId': 'your_asset_path_here/' + filename,\n", + " 'dimensions': None,\n", + " 'region': region,\n", + " 'scale': 30,\n", + " 'maxPixels': 1e12\n", + "})\n", + "\n", + "\n", + "# Visualize harmonic coefficients on map.\n", + "visImage = ee.Image.cat([\n", + " harmonics.select('3_GCVI_cos').divide(7000).add(0.6),\n", + " harmonics.select('3_GCVI_sin').divide(7000).add(0.5),\n", + " harmonics.select('3_GCVI_constant').divide(7000).subtract(\n", + " 0.6)\n", + "])\n", + "\n", + "Map.addLayer(visImage, {\n", + " 'min': -0.5,\n", + " 'max': 0.5\n", + "}, 'Harmonic coefficient False color')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##############################\n", + "# 4. Classify crop types\n", + "##############################\n", + "\n", + "# Define a random forest classifier.\n", + "rf = ee.Classifier.smileRandomForest({\n", + " 'numberOfTrees': 50,\n", + " 'minLeafPopulation': 10,\n", + " 'seed': 0\n", + "})\n", + "\n", + "# Get harmonic coefficient band names.\n", + "bands = harmonicsPlus.bandNames()\n", + "bands = bands.remove('cropland').remove('system:index')\n", + "\n", + "# Transform CDL into a 3-class band and add to harmonics.\n", + "cornSoyOther = harmonicsPlus.select('cropland').eq(1) \\\n", + " .add(harmonicsPlus.select('cropland').eq(5).multiply(2))\n", + "dataset = ee.Image.cat([harmonicsPlus.select(bands),\n", + " cornSoyOther])\n", + "\n", + "# Sample training points.\n", + "train_points = dataset.sample(geometry, 30, None, None, 100, 0)\n", + "print('Training points', train_points)\n", + "\n", + "# Train the model!\n", + "model = rf.train(train_points, 'cropland', bands)\n", + "trainCM = model.confusionMatrix()\n", + "print('Training error matrix: ', trainCM)\n", + "print('Training overall accuracy: ', trainCM.accuracy())\n", + "\n", + "# Sample test points and apply the model to them.\n", + "test_points = dataset.sample(geometry, 30, None, None, 50, 1)\n", + "tested = test_points.classify(model)\n", + "\n", + "# Compute the confusion matrix and accuracy on the test set.\n", + "testAccuracy = tested.errorMatrix('cropland', 'classification')\n", + "print('Test error matrix: ', testAccuracy)\n", + "print('Test overall accuracy: ', testAccuracy.accuracy())\n", + "\n", + "# Apply the model to the entire study region.\n", + "regionClassified = harmonicsPlus.select(bands).classify(model)\n", + "predPalette = ['gray', 'yellow', 'green']\n", + "Map.addLayer(regionClassified, {\n", + " 'min': 0,\n", + " 'max': 2,\n", + " 'palette': predPalette\n", + "}, 'Classifier prediction')\n", + "\n", + "# Visualize agreements/disagreements between prediction and CDL.\n", + "Map.addLayer(regionClassified.eq(cornSoyOther), {\n", + " 'min': 0,\n", + " 'max': 1\n", + "}, 'Classifier agreement')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11d Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11d Checkpoint.js new file mode 100644 index 0000000..6bba866 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11d Checkpoint.js @@ -0,0 +1,364 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.1 Agricultural Environments +// Checkpoint: A11d +// Authors: Sherrie Wang, George Azzari +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//////////////////////////////////////////////////////////// +// 1. Pull all Landsat 7 and 8 images over study area +//////////////////////////////////////////////////////////// + +// Define study area. +var TIGER = ee.FeatureCollection('TIGER/2018/Counties'); +var region = ee.Feature(TIGER + .filter(ee.Filter.eq('STATEFP', '17')) + .filter(ee.Filter.eq('NAME', 'McLean')) + .first()); +var geometry = region.geometry(); +Map.centerObject(region); +Map.addLayer(region, { + 'color': 'red' +}, 'McLean County'); + +// Import Landsat imagery. +var landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2'); +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); + +// Functions to rename Landsat 7 and 8 images. +function renameL7(img) { + return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', + 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD', + 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD', + 'QA_PIXEL', + 'QA_RADSAT' + ]); +} + +function renameL8(img) { + return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR', + 'SWIR1', + 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', + 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT' + ]); +} + +// Functions to mask out clouds, shadows, and other unwanted features. +function addMask(img) { + // Bit 0: Fill + // Bit 1: Dilated Cloud + // Bit 2: Cirrus (high confidence) (L8) or unused (L7) + // Bit 3: Cloud + // Bit 4: Cloud Shadow + // Bit 5: Snow + // Bit 6: Clear + // 0: Cloud or Dilated Cloud bits are set + // 1: Cloud and Dilated Cloud bits are not set + // Bit 7: Water + var clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0); + clear = clear.updateMask(clear).rename(['pxqa_clear']); + + var water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0); + water = water.updateMask(water).rename(['pxqa_water']); + + var cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0); + cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([ + 'pxqa_cloudshadow' + ]); + + var snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0); + snow = snow.updateMask(snow).rename(['pxqa_snow']); + + var masks = ee.Image.cat([ + clear, water, cloud_shadow, snow + ]); + + return img.addBands(masks); +} + +function maskQAClear(img) { + return img.updateMask(img.select('pxqa_clear')); +} + +// Function to add GCVI as a band. +function addVIs(img){ + var gcvi = img.expression('(nir / green) - 1', { + nir: img.select('NIR'), + green: img.select('GREEN') + }).select([0], ['GCVI']); + + return ee.Image.cat([img, gcvi]); +} + +// Define study time period. +var start_date = '2020-01-01'; +var end_date = '2020-12-31'; + +// Pull Landsat 7 and 8 imagery over the study area between start and end dates. +var landsat7coll = landsat7 + .filterBounds(geometry) + .filterDate(start_date, end_date) + .map(renameL7); + +var landsat8coll = landsat8 + .filterDate(start_date, end_date) + .filterBounds(geometry) + .map(renameL8); + +// Merge Landsat 7 and 8 collections. +var landsat = landsat7coll.merge(landsat8coll) + .sort('system:time_start'); + +// Mask out non-clear pixels, add VIs and time variables. +landsat = landsat.map(addMask) + .map(maskQAClear) + .map(addVIs); + +// Visualize GCVI time series at one location. +var point = ee.Geometry.Point([-88.81417685576481, + 40.579804398254005 +]); +var landsatChart = ui.Chart.image.series(landsat.select('GCVI'), + point) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat GCVI time series', + lineWidth: 1, + pointSize: 3, + }); +print(landsatChart); + +// Get crop type dataset. +var cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland']); +Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//////////////////////////////////////////////////////////// +// 2. Add bands for harmonics +//////////////////////////////////////////////////////////// + +// Function that adds time band to an image. +function addTimeUnit(image, refdate) { + var date = image.date(); + + var dyear = date.difference(refdate, 'year'); + var t = image.select(0).multiply(0).add(dyear).select([0], ['t']) + .float(); + + var imageplus = image.addBands(t); + + return imageplus; +} + +// Function that adds harmonic basis to an image. +function addHarmonics(image, omega, refdate) { + image = addTimeUnit(image, refdate); + var timeRadians = image.select('t').multiply(2 * Math.PI * omega); + var timeRadians2 = image.select('t').multiply(4 * Math.PI * + omega); + + return image + .addBands(timeRadians.cos().rename('cos')) + .addBands(timeRadians.sin().rename('sin')) + .addBands(timeRadians2.cos().rename('cos2')) + .addBands(timeRadians2.sin().rename('sin2')) + .addBands(timeRadians.divide(timeRadians) + .rename('constant')); +} + +// Apply addHarmonics to Landsat image collection. +var omega = 1; +var landsatPlus = landsat.map( + function(image) { + return addHarmonics(image, omega, start_date); + }); +print('Landsat collection with harmonic basis: ', landsatPlus); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//////////////////////////////////////////////////////////// +// 3. Get harmonic coefficients +//////////////////////////////////////////////////////////// + +// Function to run linear regression on an image. +function arrayimgHarmonicRegr(harmonicColl, dependent, independents) { + + independents = ee.List(independents); + dependent = ee.String(dependent); + + var regression = harmonicColl + .select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), + 1)); + + return regression; +} + +// Function to extract and rename regression coefficients. +function imageHarmonicRegr(harmonicColl, dependent, independents) { + + var hregr = arrayimgHarmonicRegr(harmonicColl, dependent, + independents); + + independents = ee.List(independents); + dependent = ee.String(dependent); + + var newNames = independents.map(function(b) { + return dependent.cat(ee.String('_')).cat(ee.String( + b)); + }); + + var imgCoeffs = hregr.select('coefficients') + .arrayProject([0]) + .arrayFlatten([independents]) + .select(independents, newNames); + + return imgCoeffs; +} + +// Function to apply imageHarmonicRegr and create a multi-band image. +function getHarmonicCoeffs(harmonicColl, bands, independents) { + var coefficients = ee.ImageCollection.fromImages(bands.map( + function(band) { + return imageHarmonicRegr(harmonicColl, band, + independents); + })); + return coefficients.toBands(); +} + +// Apply getHarmonicCoeffs to ImageCollection. +var bands = ['NIR', 'SWIR1', 'SWIR2', 'GCVI']; +var independents = ee.List(['constant', 'cos', 'sin', 'cos2', +'sin2']); +var harmonics = getHarmonicCoeffs(landsatPlus, bands, independents); + +harmonics = harmonics.clip(geometry); +harmonics = harmonics.multiply(10000).toInt32(); + +// Compute fitted values. +var gcviHarmonicCoefficients = harmonics + .select([ + '3_GCVI_constant', '3_GCVI_cos', + '3_GCVI_sin', '3_GCVI_cos2', '3_GCVI_sin2' + ]) + .divide(10000); + +var fittedHarmonic = landsatPlus.map(function(image) { + return image.addBands( + image.select(independents) + .multiply(gcviHarmonicCoefficients) + .reduce('sum') + .rename('fitted') + ); +}); + +// Visualize the fitted harmonics in a chart. +var harmonicsChart = ui.Chart.image.series( + fittedHarmonic.select( + ['fitted', 'GCVI']), point, ee.Reducer.mean(), 30) + .setSeriesNames(['GCVI', 'Fitted']) + .setOptions({ + title: 'Landsat GCVI time series and fitted harmonic regression values', + lineWidth: 1, + pointSize: 3, + }); + +print(harmonicsChart); + +// Add CDL as a band to the harmonics. +var harmonicsPlus = ee.Image.cat([harmonics, cdl]); + +// Export image to asset. +var filename = 'McLean_County_harmonics'; +Export.image.toAsset({ + image: harmonicsPlus, + description: filename, + assetId: 'your_asset_path_here/' + filename, + dimensions: null, + region: region, + scale: 30, + maxPixels: 1e12 +}); + + +// Visualize harmonic coefficients on map. +var visImage = ee.Image.cat([ + harmonics.select('3_GCVI_cos').divide(7000).add(0.6), + harmonics.select('3_GCVI_sin').divide(7000).add(0.5), + harmonics.select('3_GCVI_constant').divide(7000).subtract( + 0.6) +]); + +Map.addLayer(visImage, { + min: -0.5, + max: 0.5 +}, 'Harmonic coefficient false color'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//////////////////////////////////////////////////////////// +// 4. Classify crop types +//////////////////////////////////////////////////////////// + +// Define a random forest classifier. +var rf = ee.Classifier.smileRandomForest({ + numberOfTrees: 50, + minLeafPopulation: 10, + seed: 0 +}); + +// Get harmonic coefficient band names. +var bands = harmonicsPlus.bandNames(); +bands = bands.remove('cropland').remove('system:index'); + +// Transform CDL into a 3-class band and add to harmonics. +var cornSoyOther = harmonicsPlus.select('cropland').eq(1) + .add(harmonicsPlus.select('cropland').eq(5).multiply(2)); +var dataset = ee.Image.cat([harmonicsPlus.select(bands), + cornSoyOther]); + +// Sample training points. +var train_points = dataset.sample(geometry, 30, null, null, 100, 0); +print('Training points', train_points); + +// Train the model! +var model = rf.train(train_points, 'cropland', bands); +var trainCM = model.confusionMatrix(); +print('Training error matrix: ', trainCM); +print('Training overall accuracy: ', trainCM.accuracy()); + +// Sample test points and apply the model to them. +var test_points = dataset.sample(geometry, 30, null, null, 50, 1); +var tested = test_points.classify(model); + +// Compute the confusion matrix and accuracy on the test set. +var testAccuracy = tested.errorMatrix('cropland', 'classification'); +print('Test error matrix: ', testAccuracy); +print('Test overall accuracy: ', testAccuracy.accuracy()); + +// Apply the model to the entire study region. +var regionClassified = harmonicsPlus.select(bands).classify(model); +var predPalette = ['gray', 'yellow', 'green']; +Map.addLayer(regionClassified, { + min: 0, + max: 2, + palette: predPalette +}, 'Classifier prediction'); + +// Visualize agreements/disagreements between prediction and CDL. +Map.addLayer(regionClassified.eq(cornSoyOther), { + min: 0, + max: 1 +}, 'Classifier agreement'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11d Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11d Checkpoint.py new file mode 100644 index 0000000..77d5d0d --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.1 Agricultural Environments/A11d Checkpoint.py @@ -0,0 +1,387 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.1 Agricultural Environments +# Checkpoint: A11d +# Authors: Sherrie Wang, George Azzari +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +############################## +# 1. Pull all Landsat 7 and 8 images over study area +############################## + +# Define study area. +TIGER = ee.FeatureCollection('TIGER/2018/Counties') +region = ee.Feature(TIGER \ + .filter(ee.Filter.eq('STATEFP', '17')) \ + .filter(ee.Filter.eq('NAME', 'McLean')) \ + .first()) +geometry = region.geometry() +Map.centerObject(region) +Map.addLayer(region, { + 'color': 'red' +}, 'McLean County') + +# Import Landsat imagery. +landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + +# Functions to rename Landsat 7 and 8 images. +def renameL7(img): + return img.rename(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', + 'SWIR2', 'TEMP1', 'ATMOS_OPACITY', 'QA_CLOUD', + 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', 'EMSD', 'QA', 'TRAD', 'URAD', + 'QA_PIXEL', + 'QA_RADSAT' + ]) + + +def renameL8(img): + return img.rename(['AEROS', 'BLUE', 'GREEN', 'RED', 'NIR', + 'SWIR1', + 'SWIR2', 'TEMP1', 'QA_AEROSOL', 'ATRAN', 'CDIST', + 'DRAD', 'EMIS', + 'EMSD', 'QA', 'TRAD', 'URAD', 'QA_PIXEL', 'QA_RADSAT' + ]) + + +# Functions to mask out clouds, shadows, and other unwanted features. +def addMask(img): + # Bit 0: Fill + # Bit 1: Dilated Cloud + # Bit 2: Cirrus (high confidence) (L8) or unused (L7) + # Bit 3: Cloud + # Bit 4: Cloud Shadow + # Bit 5: Snow + # Bit 6: Clear + # 0: Cloud or Dilated Cloud bits are set + # 1: Cloud and Dilated Cloud bits are not set + # Bit 7: Water + clear = img.select('QA_PIXEL').bitwiseAnd(64).neq(0) + clear = clear.updateMask(clear).rename(['pxqa_clear']) + + water = img.select('QA_PIXEL').bitwiseAnd(128).neq(0) + water = water.updateMask(water).rename(['pxqa_water']) + + cloud_shadow = img.select('QA_PIXEL').bitwiseAnd(16).neq(0) + cloud_shadow = cloud_shadow.updateMask(cloud_shadow).rename([ + 'pxqa_cloudshadow' + ]) + + snow = img.select('QA_PIXEL').bitwiseAnd(32).neq(0) + snow = snow.updateMask(snow).rename(['pxqa_snow']) + + masks = ee.Image.cat([ + clear, water, cloud_shadow, snow + ]) + + return img.addBands(masks) + + +def maskQAClear(img): + return img.updateMask(img.select('pxqa_clear')) + + +# Function to add GCVI as a band. +def addVIs(img): + gcvi = img.expression('(nir / green) - 1', { + 'nir': img.select('NIR'), + 'green': img.select('GREEN') + }).select([0], ['GCVI']) + + return ee.Image.cat([img, gcvi]) + + +# Define study time period. +start_date = '2020-01-01' +end_date = '2020-12-31' + +# Pull Landsat 7 and 8 imagery over the study area between start and end dates. +landsat7coll = landsat7 \ + .filterBounds(geometry) \ + .filterDate(start_date, end_date) \ + .map(renameL7) + +landsat8coll = landsat8 \ + .filterDate(start_date, end_date) \ + .filterBounds(geometry) \ + .map(renameL8) + +# Merge Landsat 7 and 8 collections. +landsat = landsat7coll.merge(landsat8coll) \ + .sort('system:time_start') + +# Mask out non-clear pixels, add VIs and time variables. +landsat = landsat.map(addMask) \ + .map(maskQAClear) \ + .map(addVIs) + +# Visualize GCVI time series at one location. +point = ee.Geometry.Point([-88.81417685576481, + 40.579804398254005 +]) +landsatChart = ui.Chart.image.series(landsat.select('GCVI'), + point) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat GCVI time series', + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsatChart) + +# Get crop type dataset. +cdl = ee.Image('USDA/NASS/CDL/2020').select(['cropland']) +Map.addLayer(cdl.clip(geometry), {}, 'CDL 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +############################## +# 2. Add bands for harmonics +############################## + +# Function that adds time band to an image. +def addTimeUnit(image, refdate): + date = image.date() + + dyear = date.difference(refdate, 'year') + t = image.select(0).multiply(0).add(dyear).select([0], ['t']) \ + .float() + + imageplus = image.addBands(t) + + return imageplus + + +# Function that adds harmonic basis to an image. +def addHarmonics(image, omega, refdate): + image = addTimeUnit(image, refdate) + timeRadians = image.select('t').multiply(2 * math.pi * omega) + timeRadians2 = image.select('t').multiply(4 * math.pi * + omega) + + return image \ + .addBands(timeRadians.cos().rename('cos')) \ + .addBands(timeRadians.sin().rename('sin')) \ + .addBands(timeRadians2.cos().rename('cos2')) \ + .addBands(timeRadians2.sin().rename('sin2')) \ + .addBands(timeRadians.divide(timeRadians) \ + .rename('constant')) + + +# Apply addHarmonics to Landsat image collection. +omega = 1 +landsatPlus = landsat.map( + def function(image): + return addHarmonics(image, omega, start_date) + ) +print('Landsat collection with harmonic basis: ', landsatPlus) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +############################## +# 3. Get harmonic coefficients +############################## + +# Function to run linear regression on an image. +def arrayimgHarmonicRegr(harmonicColl, dependent, independents): + + independents = ee.List(independents) + dependent = ee.String(dependent) + + regression = harmonicColl \ + .select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), + 1)) + + return regression + + +# Function to extract and rename regression coefficients. +def imageHarmonicRegr(harmonicColl, dependent, independents): + + hregr = arrayimgHarmonicRegr(harmonicColl, dependent, + independents) + + independents = ee.List(independents) + dependent = ee.String(dependent) + + +def func_mxk(b): + return dependent.cat(ee.String('_')).cat(ee.String( + b)) + + newNames = independents.map(func_mxk) + + + + + + imgCoeffs = hregr.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) \ + .select(independents, newNames) + + return imgCoeffs + + +# Function to apply imageHarmonicRegr and create a multi-band image. +def getHarmonicCoeffs(harmonicColl, bands, independents): + coefficients = ee.ImageCollection.fromImages(bands.map( + def function(band): + return imageHarmonicRegr(harmonicColl, band, + independents) + )) + return coefficients.toBands() + + +# Apply getHarmonicCoeffs to ImageCollection. +bands = ['NIR', 'SWIR1', 'SWIR2', 'GCVI'] +independents = ee.List(['constant', 'cos', 'sin', 'cos2', +'sin2']) +harmonics = getHarmonicCoeffs(landsatPlus, bands, independents) + +harmonics = harmonics.clip(geometry) +harmonics = harmonics.multiply(10000).toInt32() + +# Compute fitted values. +gcviHarmonicCoefficients = harmonics \ + .select([ + '3_GCVI_constant', '3_GCVI_cos', + '3_GCVI_sin', '3_GCVI_cos2', '3_GCVI_sin2' + ]) \ + .divide(10000) + + +def func_szs(image): + return image.addBands( + image.select(independents) \ + .multiply(gcviHarmonicCoefficients) \ + .reduce('sum') \ + .rename('fitted') + ) + +fittedHarmonic = landsatPlus.map(func_szs) + + + + + + + + + +# Visualize the fitted harmonics in a chart. +harmonicsChart = ui.Chart.image.series( + fittedHarmonic.select( + ['fitted', 'GCVI']), point, ee.Reducer.mean(), 30) \ + .setSeriesNames(['GCVI', 'Fitted']) \ + .setOptions({ + 'title': 'Landsat GCVI time series and fitted harmonic regression values', + 'lineWidth': 1, + 'pointSize': 3, + }) + +print(harmonicsChart) + +# Add CDL as a band to the harmonics. +harmonicsPlus = ee.Image.cat([harmonics, cdl]) + +# Export image to asset. +filename = 'McLean_County_harmonics' +Export.image.toAsset({ + 'image': harmonicsPlus, + 'description': filename, + 'assetId': 'your_asset_path_here/' + filename, + 'dimensions': None, + 'region': region, + 'scale': 30, + 'maxPixels': 1e12 +}) + + +# Visualize harmonic coefficients on map. +visImage = ee.Image.cat([ + harmonics.select('3_GCVI_cos').divide(7000).add(0.6), + harmonics.select('3_GCVI_sin').divide(7000).add(0.5), + harmonics.select('3_GCVI_constant').divide(7000).subtract( + 0.6) +]) + +Map.addLayer(visImage, { + 'min': -0.5, + 'max': 0.5 +}, 'Harmonic coefficient False color') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +############################## +# 4. Classify crop types +############################## + +# Define a random forest classifier. +rf = ee.Classifier.smileRandomForest({ + 'numberOfTrees': 50, + 'minLeafPopulation': 10, + 'seed': 0 +}) + +# Get harmonic coefficient band names. +bands = harmonicsPlus.bandNames() +bands = bands.remove('cropland').remove('system:index') + +# Transform CDL into a 3-class band and add to harmonics. +cornSoyOther = harmonicsPlus.select('cropland').eq(1) \ + .add(harmonicsPlus.select('cropland').eq(5).multiply(2)) +dataset = ee.Image.cat([harmonicsPlus.select(bands), + cornSoyOther]) + +# Sample training points. +train_points = dataset.sample(geometry, 30, None, None, 100, 0) +print('Training points', train_points) + +# Train the model! +model = rf.train(train_points, 'cropland', bands) +trainCM = model.confusionMatrix() +print('Training error matrix: ', trainCM) +print('Training overall accuracy: ', trainCM.accuracy()) + +# Sample test points and apply the model to them. +test_points = dataset.sample(geometry, 30, None, None, 50, 1) +tested = test_points.classify(model) + +# Compute the confusion matrix and accuracy on the test set. +testAccuracy = tested.errorMatrix('cropland', 'classification') +print('Test error matrix: ', testAccuracy) +print('Test overall accuracy: ', testAccuracy.accuracy()) + +# Apply the model to the entire study region. +regionClassified = harmonicsPlus.select(bands).classify(model) +predPalette = ['gray', 'yellow', 'green'] +Map.addLayer(regionClassified, { + 'min': 0, + 'max': 2, + 'palette': predPalette +}, 'Classifier prediction') + +# Visualize agreements/disagreements between prediction and CDL. +Map.addLayer(regionClassified.eq(cornSoyOther), { + 'min': 0, + 'max': 1 +}, 'Classifier agreement') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12a Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12a Checkpoint.ipynb new file mode 100644 index 0000000..5fd47d1 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12a Checkpoint.ipynb @@ -0,0 +1,137 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometry =\n", + "\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[77.65634552256087, 13.221993749480964],\n", + " [77.65634552256087, 13.170852478759896],\n", + " [77.75041595713118, 13.170852478759896],\n", + " [77.75041595713118, 13.221993749480964]]], None, False),\n", + " L8 = ee.ImageCollection(\"LANDSAT/LC08/C02/T1_L2\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.2 Urban Environments\n", + "# Checkpoint: A12a\n", + "# Authors: Michelle Stuhlmacher and Ran Goldblatt\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "Map.centerObject(geometry)\n", + "\n", + "# Filter collection.\n", + "collection = L8 \\\n", + " .filterBounds(geometry) \\\n", + " .filterDate('2010-01-01', '2020-12-31') \\\n", + " .filter(ee.Filter.lte('CLOUD_COVER_LAND', 3))\n", + "\n", + "# Define GIF visualization arguments.\n", + "gifParams = {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 0.07 * 65536,\n", + " 'max': 0.3 * 65536,\n", + " 'region': geometry,\n", + " 'framesPerSecond': 15,\n", + " format: 'gif'\n", + "}\n", + "\n", + "# Render the GIF animation in the console.\n", + "print(ui.Thumbnail(collection, gifParams))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12a Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12a Checkpoint.js new file mode 100644 index 0000000..c6ccd99 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12a Checkpoint.js @@ -0,0 +1,44 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometry = + /* color: #00ffff */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[77.65634552256087, 13.221993749480964], + [77.65634552256087, 13.170852478759896], + [77.75041595713118, 13.170852478759896], + [77.75041595713118, 13.221993749480964]]], null, false), + L8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.2 Urban Environments +// Checkpoint: A12a +// Authors: Michelle Stuhlmacher and Ran Goldblatt +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Map.centerObject(geometry); + +// Filter collection. +var collection = L8 + .filterBounds(geometry) + .filterDate('2010-01-01', '2020-12-31') + .filter(ee.Filter.lte('CLOUD_COVER_LAND', 3)); + +// Define GIF visualization arguments. +var gifParams = { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 0.07 * 65536, + max: 0.3 * 65536, + region: geometry, + framesPerSecond: 15, + format: 'gif' +}; + +// Render the GIF animation in the console. +print(ui.Thumbnail(collection, gifParams)); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12a Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12a Checkpoint.py new file mode 100644 index 0000000..5282343 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12a Checkpoint.py @@ -0,0 +1,50 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometry = + + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[77.65634552256087, 13.221993749480964], + [77.65634552256087, 13.170852478759896], + [77.75041595713118, 13.170852478759896], + [77.75041595713118, 13.221993749480964]]], None, False), + L8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.2 Urban Environments +# Checkpoint: A12a +# Authors: Michelle Stuhlmacher and Ran Goldblatt +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Map.centerObject(geometry) + +# Filter collection. +collection = L8 \ + .filterBounds(geometry) \ + .filterDate('2010-01-01', '2020-12-31') \ + .filter(ee.Filter.lte('CLOUD_COVER_LAND', 3)) + +# Define GIF visualization arguments. +gifParams = { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 0.07 * 65536, + 'max': 0.3 * 65536, + 'region': geometry, + 'framesPerSecond': 15, + format: 'gif' +} + +# Render the GIF animation in the console. +print(ui.Thumbnail(collection, gifParams)) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12b Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12b Checkpoint.ipynb new file mode 100644 index 0000000..a10a554 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12b Checkpoint.ipynb @@ -0,0 +1,137 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "MODIS = ee.ImageCollection(\"MODIS/006/MCD12Q1\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.2 Urban Environments\n", + "# Checkpoint: A12b\n", + "# Authors: Michelle Stuhlmacher and Ran Goldblatt\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# MODIS (Accra)\n", + "# Center over Accra.\n", + "Map.setCenter(-0.2264, 5.5801, 10)\n", + "\n", + "# Visualize the full classification.\n", + "MODIS_lc = MODIS.select('LC_Type1')\n", + "igbpLandCoverVis = {\n", + " 'min': 1.0,\n", + " 'max': 17.0,\n", + " 'palette': ['05450a', '086a10', '54a708', '78d203', '009900',\n", + " 'c6b044', 'dcd159', 'dade48', 'fbff13', 'b6ff05',\n", + " '27ff87', 'c24f44', 'a5a5a5', 'ff6d4c', '69fff8',\n", + " 'f9ffa4', '1c0dff'\n", + " ],\n", + "}\n", + "Map.addLayer(MODIS_lc, igbpLandCoverVis, 'IGBP Land Cover')\n", + "\n", + "# Visualize the urban extent in 2001 and 2019.\n", + "# 2019\n", + "MODIS_2019 = MODIS_lc.filterDate(ee.Date('2019-01-01'))\n", + "\n", + "M_urb_2019 = MODIS_2019.mosaic().eq(13)\n", + "Map.addLayer(M_urb_2019.mask(M_urb_2019), {\n", + " 'palette': 'FF0000'\n", + "}, 'MODIS Urban 2019')\n", + "\n", + "MODIS_2001 = MODIS_lc.filterDate(ee.Date('2001-01-01'))\n", + "M_urb_2001 = MODIS_2001.mosaic().eq(13)\n", + "Map.addLayer(M_urb_2001.mask(M_urb_2001), {\n", + " 'palette': 'a5a5a5'\n", + "}, 'MODIS Urban 2001')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12b Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12b Checkpoint.js new file mode 100644 index 0000000..4909080 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12b Checkpoint.js @@ -0,0 +1,44 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var MODIS = ee.ImageCollection("MODIS/006/MCD12Q1"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.2 Urban Environments +// Checkpoint: A12b +// Authors: Michelle Stuhlmacher and Ran Goldblatt +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// MODIS (Accra) +// Center over Accra. +Map.setCenter(-0.2264, 5.5801, 10); + +// Visualize the full classification. +var MODIS_lc = MODIS.select('LC_Type1'); +var igbpLandCoverVis = { + min: 1.0, + max: 17.0, + palette: ['05450a', '086a10', '54a708', '78d203', '009900', + 'c6b044', 'dcd159', 'dade48', 'fbff13', 'b6ff05', + '27ff87', 'c24f44', 'a5a5a5', 'ff6d4c', '69fff8', + 'f9ffa4', '1c0dff' + ], +}; +Map.addLayer(MODIS_lc, igbpLandCoverVis, 'IGBP Land Cover'); + +// Visualize the urban extent in 2001 and 2019. +// 2019 +var MODIS_2019 = MODIS_lc.filterDate(ee.Date('2019-01-01')); + +var M_urb_2019 = MODIS_2019.mosaic().eq(13); +Map.addLayer(M_urb_2019.mask(M_urb_2019), { + 'palette': 'FF0000' +}, 'MODIS Urban 2019'); + +var MODIS_2001 = MODIS_lc.filterDate(ee.Date('2001-01-01')); +var M_urb_2001 = MODIS_2001.mosaic().eq(13); +Map.addLayer(M_urb_2001.mask(M_urb_2001), { + 'palette': 'a5a5a5' +}, 'MODIS Urban 2001'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12b Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12b Checkpoint.py new file mode 100644 index 0000000..da84fd2 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12b Checkpoint.py @@ -0,0 +1,50 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +MODIS = ee.ImageCollection("MODIS/006/MCD12Q1") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.2 Urban Environments +# Checkpoint: A12b +# Authors: Michelle Stuhlmacher and Ran Goldblatt +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# MODIS (Accra) +# Center over Accra. +Map.setCenter(-0.2264, 5.5801, 10) + +# Visualize the full classification. +MODIS_lc = MODIS.select('LC_Type1') +igbpLandCoverVis = { + 'min': 1.0, + 'max': 17.0, + 'palette': ['05450a', '086a10', '54a708', '78d203', '009900', + 'c6b044', 'dcd159', 'dade48', 'fbff13', 'b6ff05', + '27ff87', 'c24f44', 'a5a5a5', 'ff6d4c', '69fff8', + 'f9ffa4', '1c0dff' + ], +} +Map.addLayer(MODIS_lc, igbpLandCoverVis, 'IGBP Land Cover') + +# Visualize the urban extent in 2001 and 2019. +# 2019 +MODIS_2019 = MODIS_lc.filterDate(ee.Date('2019-01-01')) + +M_urb_2019 = MODIS_2019.mosaic().eq(13) +Map.addLayer(M_urb_2019.mask(M_urb_2019), { + 'palette': 'FF0000' +}, 'MODIS Urban 2019') + +MODIS_2001 = MODIS_lc.filterDate(ee.Date('2001-01-01')) +M_urb_2001 = MODIS_2001.mosaic().eq(13) +Map.addLayer(M_urb_2001.mask(M_urb_2001), { + 'palette': 'a5a5a5' +}, 'MODIS Urban 2001') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12c Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12c Checkpoint.ipynb new file mode 100644 index 0000000..a1a6dde --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12c Checkpoint.ipynb @@ -0,0 +1,127 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "CORINE = ee.ImageCollection(\"COPERNICUS/CORINE/V20/100m\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.2 Urban Environments\n", + "# Checkpoint: A12c\n", + "# Authors: Michelle Stuhlmacher and Ran Goldblatt\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# CORINE (London)\n", + "# Center over London\n", + "Map.setCenter(-0.1795, 51.4931, 10)\n", + "\n", + "# Visualize the urban extent in 2000 and 2018.\n", + "# 2018 (2017-2018)\n", + "CORINE_2018 = CORINE.select('landcover').filterDate(ee.Date(\n", + " '2017-01-01'))\n", + "\n", + "C_urb_2018 = CORINE_2018.mosaic().lte(133); #Select urban areas\n", + "Map.addLayer(C_urb_2018.mask(C_urb_2018), {\n", + " 'palette': 'FF0000'\n", + "}, 'CORINE Urban 2018')\n", + "\n", + "# 2000 (1999-2001)\n", + "CORINE_2000 = CORINE.select('landcover').filterDate(ee.Date(\n", + " '1999-01-01'))\n", + "C_urb_2000 = CORINE_2000.mosaic().lte(133); #Select urban areas\n", + "Map.addLayer(C_urb_2000.mask(C_urb_2000), {\n", + " 'palette': 'a5a5a5'\n", + "}, 'CORINE Urban 2000')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12c Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12c Checkpoint.js new file mode 100644 index 0000000..6f9a21a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12c Checkpoint.js @@ -0,0 +1,34 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var CORINE = ee.ImageCollection("COPERNICUS/CORINE/V20/100m"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.2 Urban Environments +// Checkpoint: A12c +// Authors: Michelle Stuhlmacher and Ran Goldblatt +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// CORINE (London) +// Center over London +Map.setCenter(-0.1795, 51.4931, 10); + +// Visualize the urban extent in 2000 and 2018. +// 2018 (2017-2018) +var CORINE_2018 = CORINE.select('landcover').filterDate(ee.Date( + '2017-01-01')); + +var C_urb_2018 = CORINE_2018.mosaic().lte(133); //Select urban areas +Map.addLayer(C_urb_2018.mask(C_urb_2018), { + 'palette': 'FF0000' +}, 'CORINE Urban 2018'); + +// 2000 (1999-2001) +var CORINE_2000 = CORINE.select('landcover').filterDate(ee.Date( + '1999-01-01')); +var C_urb_2000 = CORINE_2000.mosaic().lte(133); //Select urban areas +Map.addLayer(C_urb_2000.mask(C_urb_2000), { + 'palette': 'a5a5a5' +}, 'CORINE Urban 2000'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12c Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12c Checkpoint.py new file mode 100644 index 0000000..b4dfcfb --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12c Checkpoint.py @@ -0,0 +1,40 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +CORINE = ee.ImageCollection("COPERNICUS/CORINE/V20/100m") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.2 Urban Environments +# Checkpoint: A12c +# Authors: Michelle Stuhlmacher and Ran Goldblatt +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# CORINE (London) +# Center over London +Map.setCenter(-0.1795, 51.4931, 10) + +# Visualize the urban extent in 2000 and 2018. +# 2018 (2017-2018) +CORINE_2018 = CORINE.select('landcover').filterDate(ee.Date( + '2017-01-01')) + +C_urb_2018 = CORINE_2018.mosaic().lte(133); #Select urban areas +Map.addLayer(C_urb_2018.mask(C_urb_2018), { + 'palette': 'FF0000' +}, 'CORINE Urban 2018') + +# 2000 (1999-2001) +CORINE_2000 = CORINE.select('landcover').filterDate(ee.Date( + '1999-01-01')) +C_urb_2000 = CORINE_2000.mosaic().lte(133); #Select urban areas +Map.addLayer(C_urb_2000.mask(C_urb_2000), { + 'palette': 'a5a5a5' +}, 'CORINE Urban 2000') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12d Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12d Checkpoint.ipynb new file mode 100644 index 0000000..dd97ecf --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12d Checkpoint.ipynb @@ -0,0 +1,139 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "NLCD = ee.ImageCollection(\"USGS/NLCD_RELEASES/2019_REL/NLCD\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.2 Urban Environments\n", + "# Checkpoint: A12d\n", + "# Authors: Michelle Stuhlmacher and Ran Goldblatt\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# NLCD (Chicago)\n", + "# Center over Chicago.\n", + "Map.setCenter(-87.6324, 41.8799, 10)\n", + "\n", + "# Select the land cover band.\n", + "NLCD_lc = NLCD.select('landcover')\n", + "\n", + "# Filter NLCD collection to 2016.\n", + "NLCD_2016 = NLCD_lc.filter(ee.Filter.eq('system:index', '2016')) \\\n", + " .first()\n", + "Map.addLayer(NLCD_2016, {}, 'NLCD 2016')\n", + "\n", + "# Calculate the total area of the 'Developed high intensity' class (24) in Chicago.\n", + "Chicago = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-2/Chicago')\n", + "\n", + "# Clip classification to Chicago\n", + "NLCD_2016_chi = NLCD_2016.clip(Chicago)\n", + "\n", + "# Set class 24 pixels to 1 and mask the rest.\n", + "NLCD_2016_chi_24 = NLCD_2016_chi.eq(24).selfMask()\n", + "Map.addLayer(NLCD_2016_chi_24, {},\n", + " 'Chicago developed high intensity')\n", + "\n", + "# Area calculation.\n", + "areaDev = NLCD_2016_chi_24.multiply(ee.Image.pixelArea()) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': Chicago.geometry(),\n", + " 'scale': 30\n", + " }) \\\n", + " .get('landcover')\n", + "print(areaDev)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12d Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12d Checkpoint.js new file mode 100644 index 0000000..a332796 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12d Checkpoint.js @@ -0,0 +1,46 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var NLCD = ee.ImageCollection("USGS/NLCD_RELEASES/2019_REL/NLCD"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.2 Urban Environments +// Checkpoint: A12d +// Authors: Michelle Stuhlmacher and Ran Goldblatt +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// NLCD (Chicago) +// Center over Chicago. +Map.setCenter(-87.6324, 41.8799, 10); + +// Select the land cover band. +var NLCD_lc = NLCD.select('landcover'); + +// Filter NLCD collection to 2016. +var NLCD_2016 = NLCD_lc.filter(ee.Filter.eq('system:index', '2016')) + .first(); +Map.addLayer(NLCD_2016, {}, 'NLCD 2016'); + +// Calculate the total area of the 'Developed high intensity' class (24) in Chicago. +var Chicago = ee.FeatureCollection( + 'projects/gee-book/assets/A1-2/Chicago'); + +// Clip classification to Chicago +var NLCD_2016_chi = NLCD_2016.clip(Chicago); + +// Set class 24 pixels to 1 and mask the rest. +var NLCD_2016_chi_24 = NLCD_2016_chi.eq(24).selfMask(); +Map.addLayer(NLCD_2016_chi_24, {}, + 'Chicago developed high intensity'); + +// Area calculation. +var areaDev = NLCD_2016_chi_24.multiply(ee.Image.pixelArea()) + .reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: Chicago.geometry(), + scale: 30 + }) + .get('landcover'); +print(areaDev); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12d Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12d Checkpoint.py new file mode 100644 index 0000000..cdb8961 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12d Checkpoint.py @@ -0,0 +1,52 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +NLCD = ee.ImageCollection("USGS/NLCD_RELEASES/2019_REL/NLCD") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.2 Urban Environments +# Checkpoint: A12d +# Authors: Michelle Stuhlmacher and Ran Goldblatt +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# NLCD (Chicago) +# Center over Chicago. +Map.setCenter(-87.6324, 41.8799, 10) + +# Select the land cover band. +NLCD_lc = NLCD.select('landcover') + +# Filter NLCD collection to 2016. +NLCD_2016 = NLCD_lc.filter(ee.Filter.eq('system:index', '2016')) \ + .first() +Map.addLayer(NLCD_2016, {}, 'NLCD 2016') + +# Calculate the total area of the 'Developed high intensity' class (24) in Chicago. +Chicago = ee.FeatureCollection( + 'projects/gee-book/assets/A1-2/Chicago') + +# Clip classification to Chicago +NLCD_2016_chi = NLCD_2016.clip(Chicago) + +# Set class 24 pixels to 1 and mask the rest. +NLCD_2016_chi_24 = NLCD_2016_chi.eq(24).selfMask() +Map.addLayer(NLCD_2016_chi_24, {}, + 'Chicago developed high intensity') + +# Area calculation. +areaDev = NLCD_2016_chi_24.multiply(ee.Image.pixelArea()) \ + .reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': Chicago.geometry(), + 'scale': 30 + }) \ + .get('landcover') +print(areaDev) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12e Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12e Checkpoint.ipynb new file mode 100644 index 0000000..987929e --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12e Checkpoint.ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "L7 = ee.ImageCollection(\"LANDSAT/LE07/C02/T1_L2\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.2 Urban Environments\n", + "# Checkpoint: A12e\n", + "# Authors: Michelle Stuhlmacher and Ran Goldblatt\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Surface reflectance function from example:\n", + "def maskL457sr(image):\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBand = image.select('ST_B6').multiply(0.00341802).add(\n", + " 149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " return image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBand, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + "\n", + "\n", + "# Map the function over one year of data.\n", + "collection = L7.filterDate('2020-01-01', '2021-01-01').map(\n", + " maskL457sr)\n", + "landsat7_2020 = collection.median()\n", + "\n", + "Map.addLayer(landsat7_2020, {\n", + " 'bands': ['SR_B3', 'SR_B2', 'SR_B1'],\n", + " 'min': 0,\n", + " 'max': 0.3\n", + "}, 'landsat 7, 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12e Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12e Checkpoint.js new file mode 100644 index 0000000..2f1bfa2 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12e Checkpoint.js @@ -0,0 +1,42 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var L7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_L2"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.2 Urban Environments +// Checkpoint: A12e +// Authors: Michelle Stuhlmacher and Ran Goldblatt +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Surface reflectance function from example: +function maskL457sr(image) { + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0); + + // Replace the original bands with the scaled ones and apply the masks. + return image.addBands(opticalBands, null, true) + .addBands(thermalBand, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); +} + +// Map the function over one year of data. +var collection = L7.filterDate('2020-01-01', '2021-01-01').map( + maskL457sr); +var landsat7_2020 = collection.median(); + +Map.addLayer(landsat7_2020, { + bands: ['SR_B3', 'SR_B2', 'SR_B1'], + min: 0, + max: 0.3 +}, 'landsat 7, 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12e Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12e Checkpoint.py new file mode 100644 index 0000000..9557f67 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12e Checkpoint.py @@ -0,0 +1,48 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +L7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_L2") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.2 Urban Environments +# Checkpoint: A12e +# Authors: Michelle Stuhlmacher and Ran Goldblatt +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Surface reflectance function from example: +def maskL457sr(image): + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0) + + # Replace the original bands with the scaled ones and apply the masks. + return image.addBands(opticalBands, None, True) \ + .addBands(thermalBand, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + + +# Map the function over one year of data. +collection = L7.filterDate('2020-01-01', '2021-01-01').map( + maskL457sr) +landsat7_2020 = collection.median() + +Map.addLayer(landsat7_2020, { + 'bands': ['SR_B3', 'SR_B2', 'SR_B1'], + 'min': 0, + 'max': 0.3 +}, 'landsat 7, 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12f Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12f Checkpoint.ipynb new file mode 100644 index 0000000..f27554a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12f Checkpoint.ipynb @@ -0,0 +1,1453 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "nbu =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.48565466309753, 23.013090225731943],\n", + " [72.48565466309753, 23.01218172380882],\n", + " [72.4868562927362, 23.01218172380882],\n", + " [72.4868562927362, 23.013090225731943]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.48151333237854, 23.0108387097585],\n", + " [72.48151333237854, 23.009890691790975],\n", + " [72.48273641968933, 23.009890691790975],\n", + " [72.48273641968933, 23.0108387097585]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.48265058900085, 23.00720460470793],\n", + " [72.48265058900085, 23.006236810228593],\n", + " [72.48398096467224, 23.006236810228593],\n", + " [72.48398096467224, 23.00720460470793]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50040144826141, 23.010868335212642],\n", + " [72.50040144826141, 23.010379514387374],\n", + " [72.50116319562164, 23.010379514387374],\n", + " [72.50116319562164, 23.010868335212642]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49854535962311, 23.009821565220278],\n", + " [72.49854535962311, 23.009426555565323],\n", + " [72.49904425049988, 23.009426555565323],\n", + " [72.49904425049988, 23.009821565220278]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49695212746826, 23.00991044223325],\n", + " [72.49695212746826, 23.00942161793733],\n", + " [72.49754757786957, 23.00942161793733],\n", + " [72.49754757786957, 23.00991044223325]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50098740533024, 23.012437718666618],\n", + " [72.50098740533024, 23.01211677963381],\n", + " [72.501486296207, 23.01211677963381],\n", + " [72.501486296207, 23.012437718666618]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49612187817722, 23.012250092863223],\n", + " [72.49612187817722, 23.011953841063395],\n", + " [72.49648129418522, 23.011953841063395],\n", + " [72.49648129418522, 23.012250092863223]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49531185105472, 23.011835340161273],\n", + " [72.49531185105472, 23.01150946214379],\n", + " [72.49571954682499, 23.01150946214379],\n", + " [72.49571954682499, 23.011835340161273]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50769643206644, 23.01452064371778],\n", + " [72.50769643206644, 23.014145397644366],\n", + " [72.50847963709879, 23.014145397644366],\n", + " [72.50847963709879, 23.01452064371778]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5057974280839, 23.013256652780115],\n", + " [72.5057974280839, 23.012486402494627],\n", + " [72.50663427729654, 23.012486402494627],\n", + " [72.50663427729654, 23.013256652780115]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5091126384263, 23.013799775337404],\n", + " [72.5091126384263, 23.013266527755206],\n", + " [72.50970272440958, 23.013266527755206],\n", + " [72.50970272440958, 23.013799775337404]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50782517809915, 23.01674247407806],\n", + " [72.50782517809915, 23.01673259935746],\n", + " [72.50811485667276, 23.01673259935746],\n", + " [72.50811485667276, 23.01674247407806]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50090507884073, 23.016702975191237],\n", + " [72.50090507884073, 23.01607099142841],\n", + " [72.50158099551248, 23.01607099142841],\n", + " [72.50158099551248, 23.016702975191237]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49740747828531, 23.016051241888096],\n", + " [72.49740747828531, 23.015715499260445],\n", + " [72.49777225871134, 23.015715499260445],\n", + " [72.49777225871134, 23.016051241888096]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49698905367899, 23.013394902365846],\n", + " [72.49698905367899, 23.012960403190835],\n", + " [72.49771861453104, 23.012960403190835],\n", + " [72.49771861453104, 23.013394902365846]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.4941459121232, 23.01318752793418],\n", + " [72.4941459121232, 23.01289127819304],\n", + " [72.49488620181131, 23.01289127819304],\n", + " [72.49488620181131, 23.01318752793418]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51445546856034, 23.025081565200995],\n", + " [72.51445546856034, 23.024607607106788],\n", + " [72.51517430057633, 23.024607607106788],\n", + " [72.51517430057633, 23.025081565200995]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5175990175258, 23.028952160599992],\n", + " [72.5175990175258, 23.028488089974577],\n", + " [72.51818910350907, 23.028488089974577],\n", + " [72.51818910350907, 23.028952160599992]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51869335880387, 23.028932412946357],\n", + " [72.51869335880387, 23.02818199996423],\n", + " [72.5195623945247, 23.02818199996423],\n", + " [72.5195623945247, 23.028932412946357]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52084471850465, 23.026596214980795],\n", + " [72.52084471850465, 23.02604326992137],\n", + " [72.52137043147157, 23.02604326992137],\n", + " [72.52137043147157, 23.026596214980795]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53553214246043, 23.03997960346422],\n", + " [72.53553214246043, 23.03879483608005],\n", + " [72.53699126416453, 23.03879483608005],\n", + " [72.53699126416453, 23.03997960346422]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52233567410715, 23.044086716392354],\n", + " [72.52233567410715, 23.0435535886138],\n", + " [72.5232798116804, 23.0435535886138],\n", + " [72.5232798116804, 23.044086716392354]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52499642544993, 23.043198168922416],\n", + " [72.52499642544993, 23.04248732672617],\n", + " [72.52587619000681, 23.04248732672617],\n", + " [72.52587619000681, 23.043198168922416]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52400937253245, 23.04181597231865],\n", + " [72.52400937253245, 23.040986647548742],\n", + " [72.52491059476145, 23.040986647548742],\n", + " [72.52491059476145, 23.04181597231865]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.57306172713966, 23.03598378282248],\n", + " [72.57306172713966, 23.034562018547053],\n", + " [72.57426335677833, 23.034562018547053],\n", + " [72.57426335677833, 23.03598378282248]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.57566066969198, 23.052508342763684],\n", + " [72.57566066969198, 23.050928797545748],\n", + " [72.57720562208456, 23.050928797545748],\n", + " [72.57720562208456, 23.052508342763684]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5743302940206, 23.02486362694267],\n", + " [72.5743302940206, 23.023323254554423],\n", + " [72.57561775434775, 23.023323254554423],\n", + " [72.57561775434775, 23.02486362694267]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.68683489184394, 23.01212531748654],\n", + " [72.68683489184394, 23.010910679849328],\n", + " [72.68822964053169, 23.010910679849328],\n", + " [72.68822964053169, 23.01212531748654]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.69045050959602, 23.01332019424718],\n", + " [72.69045050959602, 23.012174692768948],\n", + " [72.69152339320198, 23.012174692768948],\n", + " [72.69152339320198, 23.01332019424718]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.6833158336164, 23.01301406980455],\n", + " [72.6833158336164, 23.012233943083956],\n", + " [72.68446381907478, 23.012233943083956],\n", + " [72.68446381907478, 23.01301406980455]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.67707165102973, 23.01268819463449],\n", + " [72.67707165102973, 23.0117796900038],\n", + " [72.67849858622566, 23.0117796900038],\n", + " [72.67849858622566, 23.01268819463449]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.67816599230781, 23.014544685070533],\n", + " [72.67816599230781, 23.01347819368771],\n", + " [72.67923887591377, 23.01347819368771],\n", + " [72.67923887591377, 23.014544685070533]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.6903217635633, 23.016075282967993],\n", + " [72.6903217635633, 23.015413671814553],\n", + " [72.69105132441535, 23.015413671814553],\n", + " [72.69105132441535, 23.016075282967993]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.68663104395881, 23.015630917625792],\n", + " [72.68663104395881, 23.014890305468796],\n", + " [72.68773611407295, 23.014890305468796],\n", + " [72.68773611407295, 23.015630917625792]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.71553840093799, 23.017830754660782],\n", + " [72.71553840093799, 23.016606293669707],\n", + " [72.71675075941272, 23.016606293669707],\n", + " [72.71675075941272, 23.017830754660782]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.71506633215137, 23.01600393378011],\n", + " [72.71506633215137, 23.01512507600062],\n", + " [72.7161714022655, 23.01512507600062],\n", + " [72.7161714022655, 23.01600393378011]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.71916474752612, 23.017870253217335],\n", + " [72.71916474752612, 23.01693215937388],\n", + " [72.72010888509936, 23.01693215937388],\n", + " [72.72010888509936, 23.017870253217335]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.70868267469592, 23.018521977730355],\n", + " [72.70868267469592, 23.01767276031886],\n", + " [72.70984138899036, 23.01767276031886],\n", + " [72.70984138899036, 23.018521977730355]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.7059039061565, 23.015302822979788],\n", + " [72.7059039061565, 23.014473335073],\n", + " [72.70708407812305, 23.014473335073],\n", + " [72.70708407812305, 23.015302822979788]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64443317494984, 22.995586380713714],\n", + " [72.64443317494984, 22.994895040144375],\n", + " [72.6453451260149, 22.994895040144375],\n", + " [72.6453451260149, 22.995586380713714]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.6488749130785, 22.99306790874182],\n", + " [72.6488749130785, 22.992317296243893],\n", + " [72.64966884694691, 22.992317296243893],\n", + " [72.64966884694691, 22.99306790874182]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64429370008106, 22.992188901582924],\n", + " [72.64429370008106, 22.991566679573463],\n", + " [72.6448945149004, 22.991566679573463],\n", + " [72.6448945149004, 22.992188901582924]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.65110651097889, 22.996988803565362],\n", + " [72.65110651097889, 22.99634685125117],\n", + " [72.65186825833912, 22.99634685125117],\n", + " [72.65186825833912, 22.996988803565362]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.650044356209, 22.99654437536528],\n", + " [72.650044356209, 22.995872792198217],\n", + " [72.65091339192982, 22.995872792198217],\n", + " [72.65091339192982, 22.99654437536528]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.65456119619007, 22.997166574435727],\n", + " [72.65456119619007, 22.996574003957473],\n", + " [72.65529075704212, 22.996574003957473],\n", + " [72.65529075704212, 22.997166574435727]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58544230346283, 22.989353118858265],\n", + " [72.58544230346283, 22.987812341050095],\n", + " [72.58773827437957, 22.987812341050095],\n", + " [72.58773827437957, 22.989353118858265]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61881659486005, 23.010174527999478],\n", + " [72.61881659486005, 23.009621515605502],\n", + " [72.61955688454816, 23.009621515605502],\n", + " [72.61955688454816, 23.010174527999478]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61806557633588, 23.008890745751035],\n", + " [72.61806557633588, 23.008150096589624],\n", + " [72.6190419004173, 23.008150096589624],\n", + " [72.6190419004173, 23.008890745751035]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61948212543246, 23.041104493489044],\n", + " [72.61948212543246, 23.039919735997568],\n", + " [72.6207695857596, 23.039919735997568],\n", + " [72.6207695857596, 23.041104493489044]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"49\"\n", + " })]),\n", + " bu =\n", + "\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55821826634332, 23.050534019942667],\n", + " [72.55821826634332, 23.049497430284074],\n", + " [72.55952718434258, 23.049497430284074],\n", + " [72.55952718434258, 23.050534019942667]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55760672268792, 23.052212291042135],\n", + " [72.55760672268792, 23.05108686449766],\n", + " [72.55907657322808, 23.05108686449766],\n", + " [72.55907657322808, 23.052212291042135]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56838920292779, 23.0515311129416],\n", + " [72.56838920292779, 23.05024772454887],\n", + " [72.56966593441888, 23.05024772454887],\n", + " [72.56966593441888, 23.0515311129416]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5620699184887, 23.049053175130464],\n", + " [72.5620699184887, 23.048016574072317],\n", + " [72.56340029416009, 23.048016574072317],\n", + " [72.56340029416009, 23.049053175130464]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52369259789576, 23.06300015365502],\n", + " [72.52369259789576, 23.061440474438808],\n", + " [72.5262031455337, 23.061440474438808],\n", + " [72.5262031455337, 23.06300015365502]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53285502389063, 23.064342647870983],\n", + " [72.53285502389063, 23.06258555714626],\n", + " [72.53459309533228, 23.06258555714626],\n", + " [72.53459309533228, 23.064342647870983]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52989386513819, 23.057866964035462],\n", + " [72.52989386513819, 23.05597158299574],\n", + " [72.53223275139918, 23.05597158299574],\n", + " [72.53223275139918, 23.057866964035462]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54572776915181, 23.069331684613978],\n", + " [72.54572776915181, 23.06821627216258],\n", + " [72.54719761969197, 23.06821627216258],\n", + " [72.54719761969197, 23.069331684613978]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54864601256001, 23.07097023834584],\n", + " [72.54864601256001, 23.069558714334168],\n", + " [72.5504269993459, 23.069558714334168],\n", + " [72.5504269993459, 23.07097023834584]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55111364485371, 23.0716908008372],\n", + " [72.55111364485371, 23.070377992312263],\n", + " [72.55256203772176, 23.070377992312263],\n", + " [72.55256203772176, 23.0716908008372]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50879440014218, 23.072620621975275],\n", + " [72.50879440014218, 23.071524978205787],\n", + " [72.51023206417416, 23.071524978205787],\n", + " [72.51023206417416, 23.072620621975275]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51449141208981, 23.071446012544282],\n", + " [72.51449141208981, 23.07000488107922],\n", + " [72.51615438167904, 23.07000488107922],\n", + " [72.51615438167904, 23.071446012544282]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49643476836059, 23.085681827252344],\n", + " [72.49643476836059, 23.08495640486992],\n", + " [72.49716969363067, 23.08495640486992],\n", + " [72.49716969363067, 23.085681827252344]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.47903499012024, 23.102978841643285],\n", + " [72.47903499012024, 23.101498574207657],\n", + " [72.48085889225037, 23.101498574207657],\n", + " [72.48085889225037, 23.102978841643285]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5935841682897, 23.027281425151706],\n", + " [72.5935841682897, 23.026639616972762],\n", + " [72.5942332628713, 23.026639616972762],\n", + " [72.5942332628713, 23.027281425151706]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59038697514394, 23.027562832389627],\n", + " [72.59038697514394, 23.026950647471846],\n", + " [72.59123991761068, 23.026950647471846],\n", + " [72.59123991761068, 23.027562832389627]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.60934988735686, 23.029828009881232],\n", + " [72.60934988735686, 23.028504919287915],\n", + " [72.61101285694609, 23.028504919287915],\n", + " [72.61101285694609, 23.029828009881232]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59274164913664, 23.030756140307705],\n", + " [72.59274164913664, 23.0301933385778],\n", + " [72.59362141369353, 23.0301933385778],\n", + " [72.59362141369353, 23.030756140307705]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58861710173579, 23.038054851303],\n", + " [72.58861710173579, 23.036445516746404],\n", + " [72.5900225792596, 23.036445516746404],\n", + " [72.5900225792596, 23.038054851303]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58457233054133, 23.03763030478965],\n", + " [72.58457233054133, 23.03652450294007],\n", + " [72.58590270621272, 23.03652450294007],\n", + " [72.58590270621272, 23.03763030478965]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59348799330684, 23.037047785303628],\n", + " [72.59348799330684, 23.035892612094273],\n", + " [72.594957843847, 23.035892612094273],\n", + " [72.594957843847, 23.037047785303628]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56456097369993, 23.08033152381615],\n", + " [72.56456097369993, 23.078999059324314],\n", + " [72.56592353587949, 23.078999059324314],\n", + " [72.56592353587949, 23.08033152381615]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.57296165233457, 23.08137774594047],\n", + " [72.57296165233457, 23.080084772128696],\n", + " [72.57410963779294, 23.080084772128696],\n", + " [72.57410963779294, 23.08137774594047]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56100972896421, 23.079423475373336],\n", + " [72.56100972896421, 23.078456199634683],\n", + " [72.56255468135679, 23.078456199634683],\n", + " [72.56255468135679, 23.079423475373336]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59244395909863, 23.08886205587978],\n", + " [72.59244395909863, 23.088195867560096],\n", + " [72.59312524018841, 23.088195867560096],\n", + " [72.59312524018841, 23.08886205587978]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58891417203503, 23.08902490141124],\n", + " [72.58891417203503, 23.087914587055902],\n", + " [72.59019090352612, 23.087914587055902],\n", + " [72.59019090352612, 23.08902490141124]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.63284367422881, 23.083747187676313],\n", + " [72.63284367422881, 23.082246968536918],\n", + " [72.63458174567046, 23.082246968536918],\n", + " [72.63458174567046, 23.083747187676313]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61123781615103, 23.03548171268339],\n", + " [72.61123781615103, 23.034583235045087],\n", + " [72.61229997092093, 23.034583235045087],\n", + " [72.61229997092093, 23.03548171268339]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61444573813284, 23.03697257994195],\n", + " [72.61444573813284, 23.035649559490157],\n", + " [72.61594777518118, 23.035649559490157],\n", + " [72.61594777518118, 23.03697257994195]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.60209577668272, 23.04857847538297],\n", + " [72.60209577668272, 23.047275313883606],\n", + " [72.60400550950132, 23.047275313883606],\n", + " [72.60400550950132, 23.04857847538297]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51149811879407, 23.047834507790366],\n", + " [72.51149811879407, 23.04608707415321],\n", + " [72.51345076695691, 23.04608707415321],\n", + " [72.51345076695691, 23.047834507790366]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49712295504843, 23.062788240255994],\n", + " [72.49712295504843, 23.06162341641217],\n", + " [72.49815292331014, 23.06162341641217],\n", + " [72.49815292331014, 23.062788240255994]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54670277405151, 23.075491479960288],\n", + " [72.54670277405151, 23.072964630315727],\n", + " [72.5489343719519, 23.072964630315727],\n", + " [72.5489343719519, 23.075491479960288]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55421295929321, 23.07580733282782],\n", + " [72.55421295929321, 23.07367531157657],\n", + " [72.55751744079956, 23.07367531157657],\n", + " [72.55751744079956, 23.07580733282782]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53350630569824, 23.074001039232826],\n", + " [72.53350630569824, 23.072036790796002],\n", + " [72.53615632820495, 23.072036790796002],\n", + " [72.53615632820495, 23.074001039232826]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52723091860975, 23.03366481301143],\n", + " [72.52723091860975, 23.032420748682313],\n", + " [72.52894753237928, 23.032420748682313],\n", + " [72.52894753237928, 23.03366481301143]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52270334979261, 23.035698734716632],\n", + " [72.52270334979261, 23.034118992365073],\n", + " [72.52474182864393, 23.034118992365073],\n", + " [72.52474182864393, 23.035698734716632]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54976147433484, 23.028668739099235],\n", + " [72.54976147433484, 23.026970426741123],\n", + " [72.55210036059583, 23.026970426741123],\n", + " [72.55210036059583, 23.028668739099235]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55617731829847, 23.032835438068055],\n", + " [72.55617731829847, 23.03024854533837],\n", + " [72.55915993472303, 23.03024854533837],\n", + " [72.55915993472303, 23.032835438068055]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64766142687054, 22.9969522718421],\n", + " [72.64766142687054, 22.99607328997167],\n", + " [72.64864847978802, 22.99607328997167],\n", + " [72.64864847978802, 22.9969522718421]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.65313313326092, 22.99596465136559],\n", + " [72.65313313326092, 22.99518936422971],\n", + " [72.65385196527691, 22.99518936422971],\n", + " [72.65385196527691, 22.99596465136559]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64301113330575, 23.006479138035033],\n", + " [72.64301113330575, 23.005649595875003],\n", + " [72.64406792365762, 23.005649595875003],\n", + " [72.64406792365762, 23.006479138035033]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.63917020999642, 23.00445958899076],\n", + " [72.63917020999642, 23.003802858706333],\n", + " [72.64008216106149, 23.003802858706333],\n", + " [72.64008216106149, 23.00445958899076]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.62459470431035, 23.015117807565044],\n", + " [72.62459470431035, 23.014110570204384],\n", + " [72.62584997812932, 23.014110570204384],\n", + " [72.62584997812932, 23.015117807565044]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.62965335051244, 23.015483176121137],\n", + " [72.62965335051244, 23.01433769301113],\n", + " [72.63109101454442, 23.01433769301113],\n", + " [72.63109101454442, 23.015483176121137]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5929084117717, 23.018501870267272],\n", + " [72.5929084117717, 23.017763742536697],\n", + " [72.5937720830745, 23.017763742536697],\n", + " [72.5937720830745, 23.018501870267272]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56404451603258, 23.017177110456608],\n", + " [72.56404451603258, 23.015725523443777],\n", + " [72.565922062343, 23.015725523443777],\n", + " [72.565922062343, 23.017177110456608]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52290852145079, 23.033167515925737],\n", + " [72.52290852145079, 23.031962941433807],\n", + " [72.52428181246641, 23.031962941433807],\n", + " [72.52428181246641, 23.033167515925737]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52419598177794, 23.03062999809512],\n", + " [72.52419598177794, 23.02921805114397],\n", + " [72.52598769739988, 23.02921805114397],\n", + " [72.52598769739988, 23.03062999809512]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53902594674939, 23.05493608122571],\n", + " [72.53902594674939, 23.053850165460744],\n", + " [72.54044215310925, 23.053850165460744],\n", + " [72.54044215310925, 23.05493608122571]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"49\"\n", + " })]),\n", + " L7 = ee.ImageCollection(\"LANDSAT/LE07/C02/T1_L2\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.2 Urban Environments\n", + "# Checkpoint: A12f\n", + "# Authors: Michelle Stuhlmacher and Ran Goldblatt\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "Map.centerObject(bu, 13)\n", + "\n", + "# Surface reflectance function from example:\n", + "def maskL457sr(image):\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBand = image.select('ST_B6').multiply(0.00341802).add(\n", + " 149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " return image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBand, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + "\n", + "\n", + "# Map the function over one year of data.\n", + "collection = L7.filterDate('2020-01-01', '2021-01-01').map(\n", + " maskL457sr)\n", + "landsat7_2020 = collection.median()\n", + "\n", + "Map.addLayer(landsat7_2020, {\n", + " 'bands': ['SR_B3', 'SR_B2', 'SR_B1'],\n", + " 'min': 0,\n", + " 'max': 0.3\n", + "}, 'landsat 7, 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "lc = nbu.merge(bu)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12f Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12f Checkpoint.js new file mode 100644 index 0000000..f8947b6 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12f Checkpoint.js @@ -0,0 +1,1360 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var nbu = + /* color: #28d659 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.48565466309753, 23.013090225731943], + [72.48565466309753, 23.01218172380882], + [72.4868562927362, 23.01218172380882], + [72.4868562927362, 23.013090225731943]]], null, false), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48151333237854, 23.0108387097585], + [72.48151333237854, 23.009890691790975], + [72.48273641968933, 23.009890691790975], + [72.48273641968933, 23.0108387097585]]], null, false), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48265058900085, 23.00720460470793], + [72.48265058900085, 23.006236810228593], + [72.48398096467224, 23.006236810228593], + [72.48398096467224, 23.00720460470793]]], null, false), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50040144826141, 23.010868335212642], + [72.50040144826141, 23.010379514387374], + [72.50116319562164, 23.010379514387374], + [72.50116319562164, 23.010868335212642]]], null, false), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49854535962311, 23.009821565220278], + [72.49854535962311, 23.009426555565323], + [72.49904425049988, 23.009426555565323], + [72.49904425049988, 23.009821565220278]]], null, false), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49695212746826, 23.00991044223325], + [72.49695212746826, 23.00942161793733], + [72.49754757786957, 23.00942161793733], + [72.49754757786957, 23.00991044223325]]], null, false), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50098740533024, 23.012437718666618], + [72.50098740533024, 23.01211677963381], + [72.501486296207, 23.01211677963381], + [72.501486296207, 23.012437718666618]]], null, false), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49612187817722, 23.012250092863223], + [72.49612187817722, 23.011953841063395], + [72.49648129418522, 23.011953841063395], + [72.49648129418522, 23.012250092863223]]], null, false), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49531185105472, 23.011835340161273], + [72.49531185105472, 23.01150946214379], + [72.49571954682499, 23.01150946214379], + [72.49571954682499, 23.011835340161273]]], null, false), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50769643206644, 23.01452064371778], + [72.50769643206644, 23.014145397644366], + [72.50847963709879, 23.014145397644366], + [72.50847963709879, 23.01452064371778]]], null, false), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5057974280839, 23.013256652780115], + [72.5057974280839, 23.012486402494627], + [72.50663427729654, 23.012486402494627], + [72.50663427729654, 23.013256652780115]]], null, false), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5091126384263, 23.013799775337404], + [72.5091126384263, 23.013266527755206], + [72.50970272440958, 23.013266527755206], + [72.50970272440958, 23.013799775337404]]], null, false), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50782517809915, 23.01674247407806], + [72.50782517809915, 23.01673259935746], + [72.50811485667276, 23.01673259935746], + [72.50811485667276, 23.01674247407806]]], null, false), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50090507884073, 23.016702975191237], + [72.50090507884073, 23.01607099142841], + [72.50158099551248, 23.01607099142841], + [72.50158099551248, 23.016702975191237]]], null, false), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49740747828531, 23.016051241888096], + [72.49740747828531, 23.015715499260445], + [72.49777225871134, 23.015715499260445], + [72.49777225871134, 23.016051241888096]]], null, false), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49698905367899, 23.013394902365846], + [72.49698905367899, 23.012960403190835], + [72.49771861453104, 23.012960403190835], + [72.49771861453104, 23.013394902365846]]], null, false), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.4941459121232, 23.01318752793418], + [72.4941459121232, 23.01289127819304], + [72.49488620181131, 23.01289127819304], + [72.49488620181131, 23.01318752793418]]], null, false), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51445546856034, 23.025081565200995], + [72.51445546856034, 23.024607607106788], + [72.51517430057633, 23.024607607106788], + [72.51517430057633, 23.025081565200995]]], null, false), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5175990175258, 23.028952160599992], + [72.5175990175258, 23.028488089974577], + [72.51818910350907, 23.028488089974577], + [72.51818910350907, 23.028952160599992]]], null, false), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51869335880387, 23.028932412946357], + [72.51869335880387, 23.02818199996423], + [72.5195623945247, 23.02818199996423], + [72.5195623945247, 23.028932412946357]]], null, false), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52084471850465, 23.026596214980795], + [72.52084471850465, 23.02604326992137], + [72.52137043147157, 23.02604326992137], + [72.52137043147157, 23.026596214980795]]], null, false), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53553214246043, 23.03997960346422], + [72.53553214246043, 23.03879483608005], + [72.53699126416453, 23.03879483608005], + [72.53699126416453, 23.03997960346422]]], null, false), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52233567410715, 23.044086716392354], + [72.52233567410715, 23.0435535886138], + [72.5232798116804, 23.0435535886138], + [72.5232798116804, 23.044086716392354]]], null, false), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52499642544993, 23.043198168922416], + [72.52499642544993, 23.04248732672617], + [72.52587619000681, 23.04248732672617], + [72.52587619000681, 23.043198168922416]]], null, false), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52400937253245, 23.04181597231865], + [72.52400937253245, 23.040986647548742], + [72.52491059476145, 23.040986647548742], + [72.52491059476145, 23.04181597231865]]], null, false), + { + "class": 0, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57306172713966, 23.03598378282248], + [72.57306172713966, 23.034562018547053], + [72.57426335677833, 23.034562018547053], + [72.57426335677833, 23.03598378282248]]], null, false), + { + "class": 0, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57566066969198, 23.052508342763684], + [72.57566066969198, 23.050928797545748], + [72.57720562208456, 23.050928797545748], + [72.57720562208456, 23.052508342763684]]], null, false), + { + "class": 0, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5743302940206, 23.02486362694267], + [72.5743302940206, 23.023323254554423], + [72.57561775434775, 23.023323254554423], + [72.57561775434775, 23.02486362694267]]], null, false), + { + "class": 0, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68683489184394, 23.01212531748654], + [72.68683489184394, 23.010910679849328], + [72.68822964053169, 23.010910679849328], + [72.68822964053169, 23.01212531748654]]], null, false), + { + "class": 0, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.69045050959602, 23.01332019424718], + [72.69045050959602, 23.012174692768948], + [72.69152339320198, 23.012174692768948], + [72.69152339320198, 23.01332019424718]]], null, false), + { + "class": 0, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6833158336164, 23.01301406980455], + [72.6833158336164, 23.012233943083956], + [72.68446381907478, 23.012233943083956], + [72.68446381907478, 23.01301406980455]]], null, false), + { + "class": 0, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67707165102973, 23.01268819463449], + [72.67707165102973, 23.0117796900038], + [72.67849858622566, 23.0117796900038], + [72.67849858622566, 23.01268819463449]]], null, false), + { + "class": 0, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67816599230781, 23.014544685070533], + [72.67816599230781, 23.01347819368771], + [72.67923887591377, 23.01347819368771], + [72.67923887591377, 23.014544685070533]]], null, false), + { + "class": 0, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6903217635633, 23.016075282967993], + [72.6903217635633, 23.015413671814553], + [72.69105132441535, 23.015413671814553], + [72.69105132441535, 23.016075282967993]]], null, false), + { + "class": 0, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68663104395881, 23.015630917625792], + [72.68663104395881, 23.014890305468796], + [72.68773611407295, 23.014890305468796], + [72.68773611407295, 23.015630917625792]]], null, false), + { + "class": 0, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71553840093799, 23.017830754660782], + [72.71553840093799, 23.016606293669707], + [72.71675075941272, 23.016606293669707], + [72.71675075941272, 23.017830754660782]]], null, false), + { + "class": 0, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71506633215137, 23.01600393378011], + [72.71506633215137, 23.01512507600062], + [72.7161714022655, 23.01512507600062], + [72.7161714022655, 23.01600393378011]]], null, false), + { + "class": 0, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71916474752612, 23.017870253217335], + [72.71916474752612, 23.01693215937388], + [72.72010888509936, 23.01693215937388], + [72.72010888509936, 23.017870253217335]]], null, false), + { + "class": 0, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.70868267469592, 23.018521977730355], + [72.70868267469592, 23.01767276031886], + [72.70984138899036, 23.01767276031886], + [72.70984138899036, 23.018521977730355]]], null, false), + { + "class": 0, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.7059039061565, 23.015302822979788], + [72.7059039061565, 23.014473335073], + [72.70708407812305, 23.014473335073], + [72.70708407812305, 23.015302822979788]]], null, false), + { + "class": 0, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64443317494984, 22.995586380713714], + [72.64443317494984, 22.994895040144375], + [72.6453451260149, 22.994895040144375], + [72.6453451260149, 22.995586380713714]]], null, false), + { + "class": 0, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6488749130785, 22.99306790874182], + [72.6488749130785, 22.992317296243893], + [72.64966884694691, 22.992317296243893], + [72.64966884694691, 22.99306790874182]]], null, false), + { + "class": 0, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64429370008106, 22.992188901582924], + [72.64429370008106, 22.991566679573463], + [72.6448945149004, 22.991566679573463], + [72.6448945149004, 22.992188901582924]]], null, false), + { + "class": 0, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65110651097889, 22.996988803565362], + [72.65110651097889, 22.99634685125117], + [72.65186825833912, 22.99634685125117], + [72.65186825833912, 22.996988803565362]]], null, false), + { + "class": 0, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.650044356209, 22.99654437536528], + [72.650044356209, 22.995872792198217], + [72.65091339192982, 22.995872792198217], + [72.65091339192982, 22.99654437536528]]], null, false), + { + "class": 0, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65456119619007, 22.997166574435727], + [72.65456119619007, 22.996574003957473], + [72.65529075704212, 22.996574003957473], + [72.65529075704212, 22.997166574435727]]], null, false), + { + "class": 0, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58544230346283, 22.989353118858265], + [72.58544230346283, 22.987812341050095], + [72.58773827437957, 22.987812341050095], + [72.58773827437957, 22.989353118858265]]], null, false), + { + "class": 0, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61881659486005, 23.010174527999478], + [72.61881659486005, 23.009621515605502], + [72.61955688454816, 23.009621515605502], + [72.61955688454816, 23.010174527999478]]], null, false), + { + "class": 0, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61806557633588, 23.008890745751035], + [72.61806557633588, 23.008150096589624], + [72.6190419004173, 23.008150096589624], + [72.6190419004173, 23.008890745751035]]], null, false), + { + "class": 0, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61948212543246, 23.041104493489044], + [72.61948212543246, 23.039919735997568], + [72.6207695857596, 23.039919735997568], + [72.6207695857596, 23.041104493489044]]], null, false), + { + "class": 0, + "system:index": "49" + })]), + bu = + /* color: #ff2b10 */ + /* displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.55821826634332, 23.050534019942667], + [72.55821826634332, 23.049497430284074], + [72.55952718434258, 23.049497430284074], + [72.55952718434258, 23.050534019942667]]], null, false), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55760672268792, 23.052212291042135], + [72.55760672268792, 23.05108686449766], + [72.55907657322808, 23.05108686449766], + [72.55907657322808, 23.052212291042135]]], null, false), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56838920292779, 23.0515311129416], + [72.56838920292779, 23.05024772454887], + [72.56966593441888, 23.05024772454887], + [72.56966593441888, 23.0515311129416]]], null, false), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5620699184887, 23.049053175130464], + [72.5620699184887, 23.048016574072317], + [72.56340029416009, 23.048016574072317], + [72.56340029416009, 23.049053175130464]]], null, false), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52369259789576, 23.06300015365502], + [72.52369259789576, 23.061440474438808], + [72.5262031455337, 23.061440474438808], + [72.5262031455337, 23.06300015365502]]], null, false), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53285502389063, 23.064342647870983], + [72.53285502389063, 23.06258555714626], + [72.53459309533228, 23.06258555714626], + [72.53459309533228, 23.064342647870983]]], null, false), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52989386513819, 23.057866964035462], + [72.52989386513819, 23.05597158299574], + [72.53223275139918, 23.05597158299574], + [72.53223275139918, 23.057866964035462]]], null, false), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54572776915181, 23.069331684613978], + [72.54572776915181, 23.06821627216258], + [72.54719761969197, 23.06821627216258], + [72.54719761969197, 23.069331684613978]]], null, false), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54864601256001, 23.07097023834584], + [72.54864601256001, 23.069558714334168], + [72.5504269993459, 23.069558714334168], + [72.5504269993459, 23.07097023834584]]], null, false), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55111364485371, 23.0716908008372], + [72.55111364485371, 23.070377992312263], + [72.55256203772176, 23.070377992312263], + [72.55256203772176, 23.0716908008372]]], null, false), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50879440014218, 23.072620621975275], + [72.50879440014218, 23.071524978205787], + [72.51023206417416, 23.071524978205787], + [72.51023206417416, 23.072620621975275]]], null, false), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51449141208981, 23.071446012544282], + [72.51449141208981, 23.07000488107922], + [72.51615438167904, 23.07000488107922], + [72.51615438167904, 23.071446012544282]]], null, false), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49643476836059, 23.085681827252344], + [72.49643476836059, 23.08495640486992], + [72.49716969363067, 23.08495640486992], + [72.49716969363067, 23.085681827252344]]], null, false), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.47903499012024, 23.102978841643285], + [72.47903499012024, 23.101498574207657], + [72.48085889225037, 23.101498574207657], + [72.48085889225037, 23.102978841643285]]], null, false), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5935841682897, 23.027281425151706], + [72.5935841682897, 23.026639616972762], + [72.5942332628713, 23.026639616972762], + [72.5942332628713, 23.027281425151706]]], null, false), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59038697514394, 23.027562832389627], + [72.59038697514394, 23.026950647471846], + [72.59123991761068, 23.026950647471846], + [72.59123991761068, 23.027562832389627]]], null, false), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60934988735686, 23.029828009881232], + [72.60934988735686, 23.028504919287915], + [72.61101285694609, 23.028504919287915], + [72.61101285694609, 23.029828009881232]]], null, false), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59274164913664, 23.030756140307705], + [72.59274164913664, 23.0301933385778], + [72.59362141369353, 23.0301933385778], + [72.59362141369353, 23.030756140307705]]], null, false), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58861710173579, 23.038054851303], + [72.58861710173579, 23.036445516746404], + [72.5900225792596, 23.036445516746404], + [72.5900225792596, 23.038054851303]]], null, false), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58457233054133, 23.03763030478965], + [72.58457233054133, 23.03652450294007], + [72.58590270621272, 23.03652450294007], + [72.58590270621272, 23.03763030478965]]], null, false), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59348799330684, 23.037047785303628], + [72.59348799330684, 23.035892612094273], + [72.594957843847, 23.035892612094273], + [72.594957843847, 23.037047785303628]]], null, false), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56456097369993, 23.08033152381615], + [72.56456097369993, 23.078999059324314], + [72.56592353587949, 23.078999059324314], + [72.56592353587949, 23.08033152381615]]], null, false), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57296165233457, 23.08137774594047], + [72.57296165233457, 23.080084772128696], + [72.57410963779294, 23.080084772128696], + [72.57410963779294, 23.08137774594047]]], null, false), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56100972896421, 23.079423475373336], + [72.56100972896421, 23.078456199634683], + [72.56255468135679, 23.078456199634683], + [72.56255468135679, 23.079423475373336]]], null, false), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59244395909863, 23.08886205587978], + [72.59244395909863, 23.088195867560096], + [72.59312524018841, 23.088195867560096], + [72.59312524018841, 23.08886205587978]]], null, false), + { + "class": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58891417203503, 23.08902490141124], + [72.58891417203503, 23.087914587055902], + [72.59019090352612, 23.087914587055902], + [72.59019090352612, 23.08902490141124]]], null, false), + { + "class": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63284367422881, 23.083747187676313], + [72.63284367422881, 23.082246968536918], + [72.63458174567046, 23.082246968536918], + [72.63458174567046, 23.083747187676313]]], null, false), + { + "class": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61123781615103, 23.03548171268339], + [72.61123781615103, 23.034583235045087], + [72.61229997092093, 23.034583235045087], + [72.61229997092093, 23.03548171268339]]], null, false), + { + "class": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61444573813284, 23.03697257994195], + [72.61444573813284, 23.035649559490157], + [72.61594777518118, 23.035649559490157], + [72.61594777518118, 23.03697257994195]]], null, false), + { + "class": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60209577668272, 23.04857847538297], + [72.60209577668272, 23.047275313883606], + [72.60400550950132, 23.047275313883606], + [72.60400550950132, 23.04857847538297]]], null, false), + { + "class": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51149811879407, 23.047834507790366], + [72.51149811879407, 23.04608707415321], + [72.51345076695691, 23.04608707415321], + [72.51345076695691, 23.047834507790366]]], null, false), + { + "class": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49712295504843, 23.062788240255994], + [72.49712295504843, 23.06162341641217], + [72.49815292331014, 23.06162341641217], + [72.49815292331014, 23.062788240255994]]], null, false), + { + "class": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54670277405151, 23.075491479960288], + [72.54670277405151, 23.072964630315727], + [72.5489343719519, 23.072964630315727], + [72.5489343719519, 23.075491479960288]]], null, false), + { + "class": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55421295929321, 23.07580733282782], + [72.55421295929321, 23.07367531157657], + [72.55751744079956, 23.07367531157657], + [72.55751744079956, 23.07580733282782]]], null, false), + { + "class": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53350630569824, 23.074001039232826], + [72.53350630569824, 23.072036790796002], + [72.53615632820495, 23.072036790796002], + [72.53615632820495, 23.074001039232826]]], null, false), + { + "class": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52723091860975, 23.03366481301143], + [72.52723091860975, 23.032420748682313], + [72.52894753237928, 23.032420748682313], + [72.52894753237928, 23.03366481301143]]], null, false), + { + "class": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52270334979261, 23.035698734716632], + [72.52270334979261, 23.034118992365073], + [72.52474182864393, 23.034118992365073], + [72.52474182864393, 23.035698734716632]]], null, false), + { + "class": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54976147433484, 23.028668739099235], + [72.54976147433484, 23.026970426741123], + [72.55210036059583, 23.026970426741123], + [72.55210036059583, 23.028668739099235]]], null, false), + { + "class": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55617731829847, 23.032835438068055], + [72.55617731829847, 23.03024854533837], + [72.55915993472303, 23.03024854533837], + [72.55915993472303, 23.032835438068055]]], null, false), + { + "class": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64766142687054, 22.9969522718421], + [72.64766142687054, 22.99607328997167], + [72.64864847978802, 22.99607328997167], + [72.64864847978802, 22.9969522718421]]], null, false), + { + "class": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65313313326092, 22.99596465136559], + [72.65313313326092, 22.99518936422971], + [72.65385196527691, 22.99518936422971], + [72.65385196527691, 22.99596465136559]]], null, false), + { + "class": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64301113330575, 23.006479138035033], + [72.64301113330575, 23.005649595875003], + [72.64406792365762, 23.005649595875003], + [72.64406792365762, 23.006479138035033]]], null, false), + { + "class": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63917020999642, 23.00445958899076], + [72.63917020999642, 23.003802858706333], + [72.64008216106149, 23.003802858706333], + [72.64008216106149, 23.00445958899076]]], null, false), + { + "class": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62459470431035, 23.015117807565044], + [72.62459470431035, 23.014110570204384], + [72.62584997812932, 23.014110570204384], + [72.62584997812932, 23.015117807565044]]], null, false), + { + "class": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62965335051244, 23.015483176121137], + [72.62965335051244, 23.01433769301113], + [72.63109101454442, 23.01433769301113], + [72.63109101454442, 23.015483176121137]]], null, false), + { + "class": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5929084117717, 23.018501870267272], + [72.5929084117717, 23.017763742536697], + [72.5937720830745, 23.017763742536697], + [72.5937720830745, 23.018501870267272]]], null, false), + { + "class": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56404451603258, 23.017177110456608], + [72.56404451603258, 23.015725523443777], + [72.565922062343, 23.015725523443777], + [72.565922062343, 23.017177110456608]]], null, false), + { + "class": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52290852145079, 23.033167515925737], + [72.52290852145079, 23.031962941433807], + [72.52428181246641, 23.031962941433807], + [72.52428181246641, 23.033167515925737]]], null, false), + { + "class": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52419598177794, 23.03062999809512], + [72.52419598177794, 23.02921805114397], + [72.52598769739988, 23.02921805114397], + [72.52598769739988, 23.03062999809512]]], null, false), + { + "class": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53902594674939, 23.05493608122571], + [72.53902594674939, 23.053850165460744], + [72.54044215310925, 23.053850165460744], + [72.54044215310925, 23.05493608122571]]], null, false), + { + "class": 1, + "system:index": "49" + })]), + L7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_L2"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.2 Urban Environments +// Checkpoint: A12f +// Authors: Michelle Stuhlmacher and Ran Goldblatt +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Map.centerObject(bu, 13); + +// Surface reflectance function from example: +function maskL457sr(image) { + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0); + + // Replace the original bands with the scaled ones and apply the masks. + return image.addBands(opticalBands, null, true) + .addBands(thermalBand, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); +} + +// Map the function over one year of data. +var collection = L7.filterDate('2020-01-01', '2021-01-01').map( + maskL457sr); +var landsat7_2020 = collection.median(); + +Map.addLayer(landsat7_2020, { + bands: ['SR_B3', 'SR_B2', 'SR_B1'], + min: 0, + max: 0.3 +}, 'landsat 7, 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var lc = nbu.merge(bu); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12f Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12f Checkpoint.py new file mode 100644 index 0000000..8a985ee --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12f Checkpoint.py @@ -0,0 +1,1366 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +nbu = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.48565466309753, 23.013090225731943], + [72.48565466309753, 23.01218172380882], + [72.4868562927362, 23.01218172380882], + [72.4868562927362, 23.013090225731943]]], None, False), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48151333237854, 23.0108387097585], + [72.48151333237854, 23.009890691790975], + [72.48273641968933, 23.009890691790975], + [72.48273641968933, 23.0108387097585]]], None, False), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48265058900085, 23.00720460470793], + [72.48265058900085, 23.006236810228593], + [72.48398096467224, 23.006236810228593], + [72.48398096467224, 23.00720460470793]]], None, False), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50040144826141, 23.010868335212642], + [72.50040144826141, 23.010379514387374], + [72.50116319562164, 23.010379514387374], + [72.50116319562164, 23.010868335212642]]], None, False), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49854535962311, 23.009821565220278], + [72.49854535962311, 23.009426555565323], + [72.49904425049988, 23.009426555565323], + [72.49904425049988, 23.009821565220278]]], None, False), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49695212746826, 23.00991044223325], + [72.49695212746826, 23.00942161793733], + [72.49754757786957, 23.00942161793733], + [72.49754757786957, 23.00991044223325]]], None, False), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50098740533024, 23.012437718666618], + [72.50098740533024, 23.01211677963381], + [72.501486296207, 23.01211677963381], + [72.501486296207, 23.012437718666618]]], None, False), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49612187817722, 23.012250092863223], + [72.49612187817722, 23.011953841063395], + [72.49648129418522, 23.011953841063395], + [72.49648129418522, 23.012250092863223]]], None, False), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49531185105472, 23.011835340161273], + [72.49531185105472, 23.01150946214379], + [72.49571954682499, 23.01150946214379], + [72.49571954682499, 23.011835340161273]]], None, False), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50769643206644, 23.01452064371778], + [72.50769643206644, 23.014145397644366], + [72.50847963709879, 23.014145397644366], + [72.50847963709879, 23.01452064371778]]], None, False), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5057974280839, 23.013256652780115], + [72.5057974280839, 23.012486402494627], + [72.50663427729654, 23.012486402494627], + [72.50663427729654, 23.013256652780115]]], None, False), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5091126384263, 23.013799775337404], + [72.5091126384263, 23.013266527755206], + [72.50970272440958, 23.013266527755206], + [72.50970272440958, 23.013799775337404]]], None, False), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50782517809915, 23.01674247407806], + [72.50782517809915, 23.01673259935746], + [72.50811485667276, 23.01673259935746], + [72.50811485667276, 23.01674247407806]]], None, False), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50090507884073, 23.016702975191237], + [72.50090507884073, 23.01607099142841], + [72.50158099551248, 23.01607099142841], + [72.50158099551248, 23.016702975191237]]], None, False), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49740747828531, 23.016051241888096], + [72.49740747828531, 23.015715499260445], + [72.49777225871134, 23.015715499260445], + [72.49777225871134, 23.016051241888096]]], None, False), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49698905367899, 23.013394902365846], + [72.49698905367899, 23.012960403190835], + [72.49771861453104, 23.012960403190835], + [72.49771861453104, 23.013394902365846]]], None, False), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.4941459121232, 23.01318752793418], + [72.4941459121232, 23.01289127819304], + [72.49488620181131, 23.01289127819304], + [72.49488620181131, 23.01318752793418]]], None, False), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51445546856034, 23.025081565200995], + [72.51445546856034, 23.024607607106788], + [72.51517430057633, 23.024607607106788], + [72.51517430057633, 23.025081565200995]]], None, False), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5175990175258, 23.028952160599992], + [72.5175990175258, 23.028488089974577], + [72.51818910350907, 23.028488089974577], + [72.51818910350907, 23.028952160599992]]], None, False), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51869335880387, 23.028932412946357], + [72.51869335880387, 23.02818199996423], + [72.5195623945247, 23.02818199996423], + [72.5195623945247, 23.028932412946357]]], None, False), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52084471850465, 23.026596214980795], + [72.52084471850465, 23.02604326992137], + [72.52137043147157, 23.02604326992137], + [72.52137043147157, 23.026596214980795]]], None, False), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53553214246043, 23.03997960346422], + [72.53553214246043, 23.03879483608005], + [72.53699126416453, 23.03879483608005], + [72.53699126416453, 23.03997960346422]]], None, False), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52233567410715, 23.044086716392354], + [72.52233567410715, 23.0435535886138], + [72.5232798116804, 23.0435535886138], + [72.5232798116804, 23.044086716392354]]], None, False), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52499642544993, 23.043198168922416], + [72.52499642544993, 23.04248732672617], + [72.52587619000681, 23.04248732672617], + [72.52587619000681, 23.043198168922416]]], None, False), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52400937253245, 23.04181597231865], + [72.52400937253245, 23.040986647548742], + [72.52491059476145, 23.040986647548742], + [72.52491059476145, 23.04181597231865]]], None, False), + { + "class": 0, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57306172713966, 23.03598378282248], + [72.57306172713966, 23.034562018547053], + [72.57426335677833, 23.034562018547053], + [72.57426335677833, 23.03598378282248]]], None, False), + { + "class": 0, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57566066969198, 23.052508342763684], + [72.57566066969198, 23.050928797545748], + [72.57720562208456, 23.050928797545748], + [72.57720562208456, 23.052508342763684]]], None, False), + { + "class": 0, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5743302940206, 23.02486362694267], + [72.5743302940206, 23.023323254554423], + [72.57561775434775, 23.023323254554423], + [72.57561775434775, 23.02486362694267]]], None, False), + { + "class": 0, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68683489184394, 23.01212531748654], + [72.68683489184394, 23.010910679849328], + [72.68822964053169, 23.010910679849328], + [72.68822964053169, 23.01212531748654]]], None, False), + { + "class": 0, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.69045050959602, 23.01332019424718], + [72.69045050959602, 23.012174692768948], + [72.69152339320198, 23.012174692768948], + [72.69152339320198, 23.01332019424718]]], None, False), + { + "class": 0, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6833158336164, 23.01301406980455], + [72.6833158336164, 23.012233943083956], + [72.68446381907478, 23.012233943083956], + [72.68446381907478, 23.01301406980455]]], None, False), + { + "class": 0, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67707165102973, 23.01268819463449], + [72.67707165102973, 23.0117796900038], + [72.67849858622566, 23.0117796900038], + [72.67849858622566, 23.01268819463449]]], None, False), + { + "class": 0, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67816599230781, 23.014544685070533], + [72.67816599230781, 23.01347819368771], + [72.67923887591377, 23.01347819368771], + [72.67923887591377, 23.014544685070533]]], None, False), + { + "class": 0, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6903217635633, 23.016075282967993], + [72.6903217635633, 23.015413671814553], + [72.69105132441535, 23.015413671814553], + [72.69105132441535, 23.016075282967993]]], None, False), + { + "class": 0, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68663104395881, 23.015630917625792], + [72.68663104395881, 23.014890305468796], + [72.68773611407295, 23.014890305468796], + [72.68773611407295, 23.015630917625792]]], None, False), + { + "class": 0, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71553840093799, 23.017830754660782], + [72.71553840093799, 23.016606293669707], + [72.71675075941272, 23.016606293669707], + [72.71675075941272, 23.017830754660782]]], None, False), + { + "class": 0, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71506633215137, 23.01600393378011], + [72.71506633215137, 23.01512507600062], + [72.7161714022655, 23.01512507600062], + [72.7161714022655, 23.01600393378011]]], None, False), + { + "class": 0, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71916474752612, 23.017870253217335], + [72.71916474752612, 23.01693215937388], + [72.72010888509936, 23.01693215937388], + [72.72010888509936, 23.017870253217335]]], None, False), + { + "class": 0, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.70868267469592, 23.018521977730355], + [72.70868267469592, 23.01767276031886], + [72.70984138899036, 23.01767276031886], + [72.70984138899036, 23.018521977730355]]], None, False), + { + "class": 0, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.7059039061565, 23.015302822979788], + [72.7059039061565, 23.014473335073], + [72.70708407812305, 23.014473335073], + [72.70708407812305, 23.015302822979788]]], None, False), + { + "class": 0, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64443317494984, 22.995586380713714], + [72.64443317494984, 22.994895040144375], + [72.6453451260149, 22.994895040144375], + [72.6453451260149, 22.995586380713714]]], None, False), + { + "class": 0, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6488749130785, 22.99306790874182], + [72.6488749130785, 22.992317296243893], + [72.64966884694691, 22.992317296243893], + [72.64966884694691, 22.99306790874182]]], None, False), + { + "class": 0, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64429370008106, 22.992188901582924], + [72.64429370008106, 22.991566679573463], + [72.6448945149004, 22.991566679573463], + [72.6448945149004, 22.992188901582924]]], None, False), + { + "class": 0, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65110651097889, 22.996988803565362], + [72.65110651097889, 22.99634685125117], + [72.65186825833912, 22.99634685125117], + [72.65186825833912, 22.996988803565362]]], None, False), + { + "class": 0, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.650044356209, 22.99654437536528], + [72.650044356209, 22.995872792198217], + [72.65091339192982, 22.995872792198217], + [72.65091339192982, 22.99654437536528]]], None, False), + { + "class": 0, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65456119619007, 22.997166574435727], + [72.65456119619007, 22.996574003957473], + [72.65529075704212, 22.996574003957473], + [72.65529075704212, 22.997166574435727]]], None, False), + { + "class": 0, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58544230346283, 22.989353118858265], + [72.58544230346283, 22.987812341050095], + [72.58773827437957, 22.987812341050095], + [72.58773827437957, 22.989353118858265]]], None, False), + { + "class": 0, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61881659486005, 23.010174527999478], + [72.61881659486005, 23.009621515605502], + [72.61955688454816, 23.009621515605502], + [72.61955688454816, 23.010174527999478]]], None, False), + { + "class": 0, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61806557633588, 23.008890745751035], + [72.61806557633588, 23.008150096589624], + [72.6190419004173, 23.008150096589624], + [72.6190419004173, 23.008890745751035]]], None, False), + { + "class": 0, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61948212543246, 23.041104493489044], + [72.61948212543246, 23.039919735997568], + [72.6207695857596, 23.039919735997568], + [72.6207695857596, 23.041104493489044]]], None, False), + { + "class": 0, + "system:index": "49" + })]), + bu = + + # displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.55821826634332, 23.050534019942667], + [72.55821826634332, 23.049497430284074], + [72.55952718434258, 23.049497430284074], + [72.55952718434258, 23.050534019942667]]], None, False), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55760672268792, 23.052212291042135], + [72.55760672268792, 23.05108686449766], + [72.55907657322808, 23.05108686449766], + [72.55907657322808, 23.052212291042135]]], None, False), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56838920292779, 23.0515311129416], + [72.56838920292779, 23.05024772454887], + [72.56966593441888, 23.05024772454887], + [72.56966593441888, 23.0515311129416]]], None, False), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5620699184887, 23.049053175130464], + [72.5620699184887, 23.048016574072317], + [72.56340029416009, 23.048016574072317], + [72.56340029416009, 23.049053175130464]]], None, False), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52369259789576, 23.06300015365502], + [72.52369259789576, 23.061440474438808], + [72.5262031455337, 23.061440474438808], + [72.5262031455337, 23.06300015365502]]], None, False), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53285502389063, 23.064342647870983], + [72.53285502389063, 23.06258555714626], + [72.53459309533228, 23.06258555714626], + [72.53459309533228, 23.064342647870983]]], None, False), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52989386513819, 23.057866964035462], + [72.52989386513819, 23.05597158299574], + [72.53223275139918, 23.05597158299574], + [72.53223275139918, 23.057866964035462]]], None, False), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54572776915181, 23.069331684613978], + [72.54572776915181, 23.06821627216258], + [72.54719761969197, 23.06821627216258], + [72.54719761969197, 23.069331684613978]]], None, False), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54864601256001, 23.07097023834584], + [72.54864601256001, 23.069558714334168], + [72.5504269993459, 23.069558714334168], + [72.5504269993459, 23.07097023834584]]], None, False), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55111364485371, 23.0716908008372], + [72.55111364485371, 23.070377992312263], + [72.55256203772176, 23.070377992312263], + [72.55256203772176, 23.0716908008372]]], None, False), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50879440014218, 23.072620621975275], + [72.50879440014218, 23.071524978205787], + [72.51023206417416, 23.071524978205787], + [72.51023206417416, 23.072620621975275]]], None, False), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51449141208981, 23.071446012544282], + [72.51449141208981, 23.07000488107922], + [72.51615438167904, 23.07000488107922], + [72.51615438167904, 23.071446012544282]]], None, False), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49643476836059, 23.085681827252344], + [72.49643476836059, 23.08495640486992], + [72.49716969363067, 23.08495640486992], + [72.49716969363067, 23.085681827252344]]], None, False), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.47903499012024, 23.102978841643285], + [72.47903499012024, 23.101498574207657], + [72.48085889225037, 23.101498574207657], + [72.48085889225037, 23.102978841643285]]], None, False), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5935841682897, 23.027281425151706], + [72.5935841682897, 23.026639616972762], + [72.5942332628713, 23.026639616972762], + [72.5942332628713, 23.027281425151706]]], None, False), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59038697514394, 23.027562832389627], + [72.59038697514394, 23.026950647471846], + [72.59123991761068, 23.026950647471846], + [72.59123991761068, 23.027562832389627]]], None, False), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60934988735686, 23.029828009881232], + [72.60934988735686, 23.028504919287915], + [72.61101285694609, 23.028504919287915], + [72.61101285694609, 23.029828009881232]]], None, False), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59274164913664, 23.030756140307705], + [72.59274164913664, 23.0301933385778], + [72.59362141369353, 23.0301933385778], + [72.59362141369353, 23.030756140307705]]], None, False), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58861710173579, 23.038054851303], + [72.58861710173579, 23.036445516746404], + [72.5900225792596, 23.036445516746404], + [72.5900225792596, 23.038054851303]]], None, False), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58457233054133, 23.03763030478965], + [72.58457233054133, 23.03652450294007], + [72.58590270621272, 23.03652450294007], + [72.58590270621272, 23.03763030478965]]], None, False), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59348799330684, 23.037047785303628], + [72.59348799330684, 23.035892612094273], + [72.594957843847, 23.035892612094273], + [72.594957843847, 23.037047785303628]]], None, False), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56456097369993, 23.08033152381615], + [72.56456097369993, 23.078999059324314], + [72.56592353587949, 23.078999059324314], + [72.56592353587949, 23.08033152381615]]], None, False), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57296165233457, 23.08137774594047], + [72.57296165233457, 23.080084772128696], + [72.57410963779294, 23.080084772128696], + [72.57410963779294, 23.08137774594047]]], None, False), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56100972896421, 23.079423475373336], + [72.56100972896421, 23.078456199634683], + [72.56255468135679, 23.078456199634683], + [72.56255468135679, 23.079423475373336]]], None, False), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59244395909863, 23.08886205587978], + [72.59244395909863, 23.088195867560096], + [72.59312524018841, 23.088195867560096], + [72.59312524018841, 23.08886205587978]]], None, False), + { + "class": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58891417203503, 23.08902490141124], + [72.58891417203503, 23.087914587055902], + [72.59019090352612, 23.087914587055902], + [72.59019090352612, 23.08902490141124]]], None, False), + { + "class": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63284367422881, 23.083747187676313], + [72.63284367422881, 23.082246968536918], + [72.63458174567046, 23.082246968536918], + [72.63458174567046, 23.083747187676313]]], None, False), + { + "class": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61123781615103, 23.03548171268339], + [72.61123781615103, 23.034583235045087], + [72.61229997092093, 23.034583235045087], + [72.61229997092093, 23.03548171268339]]], None, False), + { + "class": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61444573813284, 23.03697257994195], + [72.61444573813284, 23.035649559490157], + [72.61594777518118, 23.035649559490157], + [72.61594777518118, 23.03697257994195]]], None, False), + { + "class": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60209577668272, 23.04857847538297], + [72.60209577668272, 23.047275313883606], + [72.60400550950132, 23.047275313883606], + [72.60400550950132, 23.04857847538297]]], None, False), + { + "class": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51149811879407, 23.047834507790366], + [72.51149811879407, 23.04608707415321], + [72.51345076695691, 23.04608707415321], + [72.51345076695691, 23.047834507790366]]], None, False), + { + "class": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49712295504843, 23.062788240255994], + [72.49712295504843, 23.06162341641217], + [72.49815292331014, 23.06162341641217], + [72.49815292331014, 23.062788240255994]]], None, False), + { + "class": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54670277405151, 23.075491479960288], + [72.54670277405151, 23.072964630315727], + [72.5489343719519, 23.072964630315727], + [72.5489343719519, 23.075491479960288]]], None, False), + { + "class": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55421295929321, 23.07580733282782], + [72.55421295929321, 23.07367531157657], + [72.55751744079956, 23.07367531157657], + [72.55751744079956, 23.07580733282782]]], None, False), + { + "class": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53350630569824, 23.074001039232826], + [72.53350630569824, 23.072036790796002], + [72.53615632820495, 23.072036790796002], + [72.53615632820495, 23.074001039232826]]], None, False), + { + "class": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52723091860975, 23.03366481301143], + [72.52723091860975, 23.032420748682313], + [72.52894753237928, 23.032420748682313], + [72.52894753237928, 23.03366481301143]]], None, False), + { + "class": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52270334979261, 23.035698734716632], + [72.52270334979261, 23.034118992365073], + [72.52474182864393, 23.034118992365073], + [72.52474182864393, 23.035698734716632]]], None, False), + { + "class": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54976147433484, 23.028668739099235], + [72.54976147433484, 23.026970426741123], + [72.55210036059583, 23.026970426741123], + [72.55210036059583, 23.028668739099235]]], None, False), + { + "class": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55617731829847, 23.032835438068055], + [72.55617731829847, 23.03024854533837], + [72.55915993472303, 23.03024854533837], + [72.55915993472303, 23.032835438068055]]], None, False), + { + "class": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64766142687054, 22.9969522718421], + [72.64766142687054, 22.99607328997167], + [72.64864847978802, 22.99607328997167], + [72.64864847978802, 22.9969522718421]]], None, False), + { + "class": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65313313326092, 22.99596465136559], + [72.65313313326092, 22.99518936422971], + [72.65385196527691, 22.99518936422971], + [72.65385196527691, 22.99596465136559]]], None, False), + { + "class": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64301113330575, 23.006479138035033], + [72.64301113330575, 23.005649595875003], + [72.64406792365762, 23.005649595875003], + [72.64406792365762, 23.006479138035033]]], None, False), + { + "class": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63917020999642, 23.00445958899076], + [72.63917020999642, 23.003802858706333], + [72.64008216106149, 23.003802858706333], + [72.64008216106149, 23.00445958899076]]], None, False), + { + "class": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62459470431035, 23.015117807565044], + [72.62459470431035, 23.014110570204384], + [72.62584997812932, 23.014110570204384], + [72.62584997812932, 23.015117807565044]]], None, False), + { + "class": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62965335051244, 23.015483176121137], + [72.62965335051244, 23.01433769301113], + [72.63109101454442, 23.01433769301113], + [72.63109101454442, 23.015483176121137]]], None, False), + { + "class": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5929084117717, 23.018501870267272], + [72.5929084117717, 23.017763742536697], + [72.5937720830745, 23.017763742536697], + [72.5937720830745, 23.018501870267272]]], None, False), + { + "class": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56404451603258, 23.017177110456608], + [72.56404451603258, 23.015725523443777], + [72.565922062343, 23.015725523443777], + [72.565922062343, 23.017177110456608]]], None, False), + { + "class": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52290852145079, 23.033167515925737], + [72.52290852145079, 23.031962941433807], + [72.52428181246641, 23.031962941433807], + [72.52428181246641, 23.033167515925737]]], None, False), + { + "class": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52419598177794, 23.03062999809512], + [72.52419598177794, 23.02921805114397], + [72.52598769739988, 23.02921805114397], + [72.52598769739988, 23.03062999809512]]], None, False), + { + "class": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53902594674939, 23.05493608122571], + [72.53902594674939, 23.053850165460744], + [72.54044215310925, 23.053850165460744], + [72.54044215310925, 23.05493608122571]]], None, False), + { + "class": 1, + "system:index": "49" + })]), + L7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_L2") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.2 Urban Environments +# Checkpoint: A12f +# Authors: Michelle Stuhlmacher and Ran Goldblatt +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Map.centerObject(bu, 13) + +# Surface reflectance function from example: +def maskL457sr(image): + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0) + + # Replace the original bands with the scaled ones and apply the masks. + return image.addBands(opticalBands, None, True) \ + .addBands(thermalBand, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + + +# Map the function over one year of data. +collection = L7.filterDate('2020-01-01', '2021-01-01').map( + maskL457sr) +landsat7_2020 = collection.median() + +Map.addLayer(landsat7_2020, { + 'bands': ['SR_B3', 'SR_B2', 'SR_B1'], + 'min': 0, + 'max': 0.3 +}, 'landsat 7, 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +lc = nbu.merge(bu) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12g Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12g Checkpoint.ipynb new file mode 100644 index 0000000..76629ee --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12g Checkpoint.ipynb @@ -0,0 +1,1487 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "nbu =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.48565466309753, 23.013090225731943],\n", + " [72.48565466309753, 23.01218172380882],\n", + " [72.4868562927362, 23.01218172380882],\n", + " [72.4868562927362, 23.013090225731943]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.48151333237854, 23.0108387097585],\n", + " [72.48151333237854, 23.009890691790975],\n", + " [72.48273641968933, 23.009890691790975],\n", + " [72.48273641968933, 23.0108387097585]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.48265058900085, 23.00720460470793],\n", + " [72.48265058900085, 23.006236810228593],\n", + " [72.48398096467224, 23.006236810228593],\n", + " [72.48398096467224, 23.00720460470793]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50040144826141, 23.010868335212642],\n", + " [72.50040144826141, 23.010379514387374],\n", + " [72.50116319562164, 23.010379514387374],\n", + " [72.50116319562164, 23.010868335212642]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49854535962311, 23.009821565220278],\n", + " [72.49854535962311, 23.009426555565323],\n", + " [72.49904425049988, 23.009426555565323],\n", + " [72.49904425049988, 23.009821565220278]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49695212746826, 23.00991044223325],\n", + " [72.49695212746826, 23.00942161793733],\n", + " [72.49754757786957, 23.00942161793733],\n", + " [72.49754757786957, 23.00991044223325]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50098740533024, 23.012437718666618],\n", + " [72.50098740533024, 23.01211677963381],\n", + " [72.501486296207, 23.01211677963381],\n", + " [72.501486296207, 23.012437718666618]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49612187817722, 23.012250092863223],\n", + " [72.49612187817722, 23.011953841063395],\n", + " [72.49648129418522, 23.011953841063395],\n", + " [72.49648129418522, 23.012250092863223]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49531185105472, 23.011835340161273],\n", + " [72.49531185105472, 23.01150946214379],\n", + " [72.49571954682499, 23.01150946214379],\n", + " [72.49571954682499, 23.011835340161273]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50769643206644, 23.01452064371778],\n", + " [72.50769643206644, 23.014145397644366],\n", + " [72.50847963709879, 23.014145397644366],\n", + " [72.50847963709879, 23.01452064371778]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5057974280839, 23.013256652780115],\n", + " [72.5057974280839, 23.012486402494627],\n", + " [72.50663427729654, 23.012486402494627],\n", + " [72.50663427729654, 23.013256652780115]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5091126384263, 23.013799775337404],\n", + " [72.5091126384263, 23.013266527755206],\n", + " [72.50970272440958, 23.013266527755206],\n", + " [72.50970272440958, 23.013799775337404]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50782517809915, 23.01674247407806],\n", + " [72.50782517809915, 23.01673259935746],\n", + " [72.50811485667276, 23.01673259935746],\n", + " [72.50811485667276, 23.01674247407806]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50090507884073, 23.016702975191237],\n", + " [72.50090507884073, 23.01607099142841],\n", + " [72.50158099551248, 23.01607099142841],\n", + " [72.50158099551248, 23.016702975191237]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49740747828531, 23.016051241888096],\n", + " [72.49740747828531, 23.015715499260445],\n", + " [72.49777225871134, 23.015715499260445],\n", + " [72.49777225871134, 23.016051241888096]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49698905367899, 23.013394902365846],\n", + " [72.49698905367899, 23.012960403190835],\n", + " [72.49771861453104, 23.012960403190835],\n", + " [72.49771861453104, 23.013394902365846]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.4941459121232, 23.01318752793418],\n", + " [72.4941459121232, 23.01289127819304],\n", + " [72.49488620181131, 23.01289127819304],\n", + " [72.49488620181131, 23.01318752793418]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51445546856034, 23.025081565200995],\n", + " [72.51445546856034, 23.024607607106788],\n", + " [72.51517430057633, 23.024607607106788],\n", + " [72.51517430057633, 23.025081565200995]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5175990175258, 23.028952160599992],\n", + " [72.5175990175258, 23.028488089974577],\n", + " [72.51818910350907, 23.028488089974577],\n", + " [72.51818910350907, 23.028952160599992]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51869335880387, 23.028932412946357],\n", + " [72.51869335880387, 23.02818199996423],\n", + " [72.5195623945247, 23.02818199996423],\n", + " [72.5195623945247, 23.028932412946357]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52084471850465, 23.026596214980795],\n", + " [72.52084471850465, 23.02604326992137],\n", + " [72.52137043147157, 23.02604326992137],\n", + " [72.52137043147157, 23.026596214980795]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53553214246043, 23.03997960346422],\n", + " [72.53553214246043, 23.03879483608005],\n", + " [72.53699126416453, 23.03879483608005],\n", + " [72.53699126416453, 23.03997960346422]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52233567410715, 23.044086716392354],\n", + " [72.52233567410715, 23.0435535886138],\n", + " [72.5232798116804, 23.0435535886138],\n", + " [72.5232798116804, 23.044086716392354]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52499642544993, 23.043198168922416],\n", + " [72.52499642544993, 23.04248732672617],\n", + " [72.52587619000681, 23.04248732672617],\n", + " [72.52587619000681, 23.043198168922416]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52400937253245, 23.04181597231865],\n", + " [72.52400937253245, 23.040986647548742],\n", + " [72.52491059476145, 23.040986647548742],\n", + " [72.52491059476145, 23.04181597231865]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.57306172713966, 23.03598378282248],\n", + " [72.57306172713966, 23.034562018547053],\n", + " [72.57426335677833, 23.034562018547053],\n", + " [72.57426335677833, 23.03598378282248]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.57566066969198, 23.052508342763684],\n", + " [72.57566066969198, 23.050928797545748],\n", + " [72.57720562208456, 23.050928797545748],\n", + " [72.57720562208456, 23.052508342763684]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5743302940206, 23.02486362694267],\n", + " [72.5743302940206, 23.023323254554423],\n", + " [72.57561775434775, 23.023323254554423],\n", + " [72.57561775434775, 23.02486362694267]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.68683489184394, 23.01212531748654],\n", + " [72.68683489184394, 23.010910679849328],\n", + " [72.68822964053169, 23.010910679849328],\n", + " [72.68822964053169, 23.01212531748654]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.69045050959602, 23.01332019424718],\n", + " [72.69045050959602, 23.012174692768948],\n", + " [72.69152339320198, 23.012174692768948],\n", + " [72.69152339320198, 23.01332019424718]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.6833158336164, 23.01301406980455],\n", + " [72.6833158336164, 23.012233943083956],\n", + " [72.68446381907478, 23.012233943083956],\n", + " [72.68446381907478, 23.01301406980455]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.67707165102973, 23.01268819463449],\n", + " [72.67707165102973, 23.0117796900038],\n", + " [72.67849858622566, 23.0117796900038],\n", + " [72.67849858622566, 23.01268819463449]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.67816599230781, 23.014544685070533],\n", + " [72.67816599230781, 23.01347819368771],\n", + " [72.67923887591377, 23.01347819368771],\n", + " [72.67923887591377, 23.014544685070533]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.6903217635633, 23.016075282967993],\n", + " [72.6903217635633, 23.015413671814553],\n", + " [72.69105132441535, 23.015413671814553],\n", + " [72.69105132441535, 23.016075282967993]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.68663104395881, 23.015630917625792],\n", + " [72.68663104395881, 23.014890305468796],\n", + " [72.68773611407295, 23.014890305468796],\n", + " [72.68773611407295, 23.015630917625792]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.71553840093799, 23.017830754660782],\n", + " [72.71553840093799, 23.016606293669707],\n", + " [72.71675075941272, 23.016606293669707],\n", + " [72.71675075941272, 23.017830754660782]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.71506633215137, 23.01600393378011],\n", + " [72.71506633215137, 23.01512507600062],\n", + " [72.7161714022655, 23.01512507600062],\n", + " [72.7161714022655, 23.01600393378011]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.71916474752612, 23.017870253217335],\n", + " [72.71916474752612, 23.01693215937388],\n", + " [72.72010888509936, 23.01693215937388],\n", + " [72.72010888509936, 23.017870253217335]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.70868267469592, 23.018521977730355],\n", + " [72.70868267469592, 23.01767276031886],\n", + " [72.70984138899036, 23.01767276031886],\n", + " [72.70984138899036, 23.018521977730355]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.7059039061565, 23.015302822979788],\n", + " [72.7059039061565, 23.014473335073],\n", + " [72.70708407812305, 23.014473335073],\n", + " [72.70708407812305, 23.015302822979788]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64443317494984, 22.995586380713714],\n", + " [72.64443317494984, 22.994895040144375],\n", + " [72.6453451260149, 22.994895040144375],\n", + " [72.6453451260149, 22.995586380713714]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.6488749130785, 22.99306790874182],\n", + " [72.6488749130785, 22.992317296243893],\n", + " [72.64966884694691, 22.992317296243893],\n", + " [72.64966884694691, 22.99306790874182]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64429370008106, 22.992188901582924],\n", + " [72.64429370008106, 22.991566679573463],\n", + " [72.6448945149004, 22.991566679573463],\n", + " [72.6448945149004, 22.992188901582924]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.65110651097889, 22.996988803565362],\n", + " [72.65110651097889, 22.99634685125117],\n", + " [72.65186825833912, 22.99634685125117],\n", + " [72.65186825833912, 22.996988803565362]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.650044356209, 22.99654437536528],\n", + " [72.650044356209, 22.995872792198217],\n", + " [72.65091339192982, 22.995872792198217],\n", + " [72.65091339192982, 22.99654437536528]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.65456119619007, 22.997166574435727],\n", + " [72.65456119619007, 22.996574003957473],\n", + " [72.65529075704212, 22.996574003957473],\n", + " [72.65529075704212, 22.997166574435727]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58544230346283, 22.989353118858265],\n", + " [72.58544230346283, 22.987812341050095],\n", + " [72.58773827437957, 22.987812341050095],\n", + " [72.58773827437957, 22.989353118858265]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61881659486005, 23.010174527999478],\n", + " [72.61881659486005, 23.009621515605502],\n", + " [72.61955688454816, 23.009621515605502],\n", + " [72.61955688454816, 23.010174527999478]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61806557633588, 23.008890745751035],\n", + " [72.61806557633588, 23.008150096589624],\n", + " [72.6190419004173, 23.008150096589624],\n", + " [72.6190419004173, 23.008890745751035]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61948212543246, 23.041104493489044],\n", + " [72.61948212543246, 23.039919735997568],\n", + " [72.6207695857596, 23.039919735997568],\n", + " [72.6207695857596, 23.041104493489044]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"49\"\n", + " })]),\n", + " bu =\n", + "\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55821826634332, 23.050534019942667],\n", + " [72.55821826634332, 23.049497430284074],\n", + " [72.55952718434258, 23.049497430284074],\n", + " [72.55952718434258, 23.050534019942667]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55760672268792, 23.052212291042135],\n", + " [72.55760672268792, 23.05108686449766],\n", + " [72.55907657322808, 23.05108686449766],\n", + " [72.55907657322808, 23.052212291042135]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56838920292779, 23.0515311129416],\n", + " [72.56838920292779, 23.05024772454887],\n", + " [72.56966593441888, 23.05024772454887],\n", + " [72.56966593441888, 23.0515311129416]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5620699184887, 23.049053175130464],\n", + " [72.5620699184887, 23.048016574072317],\n", + " [72.56340029416009, 23.048016574072317],\n", + " [72.56340029416009, 23.049053175130464]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52369259789576, 23.06300015365502],\n", + " [72.52369259789576, 23.061440474438808],\n", + " [72.5262031455337, 23.061440474438808],\n", + " [72.5262031455337, 23.06300015365502]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53285502389063, 23.064342647870983],\n", + " [72.53285502389063, 23.06258555714626],\n", + " [72.53459309533228, 23.06258555714626],\n", + " [72.53459309533228, 23.064342647870983]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52989386513819, 23.057866964035462],\n", + " [72.52989386513819, 23.05597158299574],\n", + " [72.53223275139918, 23.05597158299574],\n", + " [72.53223275139918, 23.057866964035462]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54572776915181, 23.069331684613978],\n", + " [72.54572776915181, 23.06821627216258],\n", + " [72.54719761969197, 23.06821627216258],\n", + " [72.54719761969197, 23.069331684613978]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54864601256001, 23.07097023834584],\n", + " [72.54864601256001, 23.069558714334168],\n", + " [72.5504269993459, 23.069558714334168],\n", + " [72.5504269993459, 23.07097023834584]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55111364485371, 23.0716908008372],\n", + " [72.55111364485371, 23.070377992312263],\n", + " [72.55256203772176, 23.070377992312263],\n", + " [72.55256203772176, 23.0716908008372]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50879440014218, 23.072620621975275],\n", + " [72.50879440014218, 23.071524978205787],\n", + " [72.51023206417416, 23.071524978205787],\n", + " [72.51023206417416, 23.072620621975275]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51449141208981, 23.071446012544282],\n", + " [72.51449141208981, 23.07000488107922],\n", + " [72.51615438167904, 23.07000488107922],\n", + " [72.51615438167904, 23.071446012544282]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49643476836059, 23.085681827252344],\n", + " [72.49643476836059, 23.08495640486992],\n", + " [72.49716969363067, 23.08495640486992],\n", + " [72.49716969363067, 23.085681827252344]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.47903499012024, 23.102978841643285],\n", + " [72.47903499012024, 23.101498574207657],\n", + " [72.48085889225037, 23.101498574207657],\n", + " [72.48085889225037, 23.102978841643285]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5935841682897, 23.027281425151706],\n", + " [72.5935841682897, 23.026639616972762],\n", + " [72.5942332628713, 23.026639616972762],\n", + " [72.5942332628713, 23.027281425151706]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59038697514394, 23.027562832389627],\n", + " [72.59038697514394, 23.026950647471846],\n", + " [72.59123991761068, 23.026950647471846],\n", + " [72.59123991761068, 23.027562832389627]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.60934988735686, 23.029828009881232],\n", + " [72.60934988735686, 23.028504919287915],\n", + " [72.61101285694609, 23.028504919287915],\n", + " [72.61101285694609, 23.029828009881232]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59274164913664, 23.030756140307705],\n", + " [72.59274164913664, 23.0301933385778],\n", + " [72.59362141369353, 23.0301933385778],\n", + " [72.59362141369353, 23.030756140307705]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58861710173579, 23.038054851303],\n", + " [72.58861710173579, 23.036445516746404],\n", + " [72.5900225792596, 23.036445516746404],\n", + " [72.5900225792596, 23.038054851303]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58457233054133, 23.03763030478965],\n", + " [72.58457233054133, 23.03652450294007],\n", + " [72.58590270621272, 23.03652450294007],\n", + " [72.58590270621272, 23.03763030478965]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59348799330684, 23.037047785303628],\n", + " [72.59348799330684, 23.035892612094273],\n", + " [72.594957843847, 23.035892612094273],\n", + " [72.594957843847, 23.037047785303628]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56456097369993, 23.08033152381615],\n", + " [72.56456097369993, 23.078999059324314],\n", + " [72.56592353587949, 23.078999059324314],\n", + " [72.56592353587949, 23.08033152381615]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.57296165233457, 23.08137774594047],\n", + " [72.57296165233457, 23.080084772128696],\n", + " [72.57410963779294, 23.080084772128696],\n", + " [72.57410963779294, 23.08137774594047]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56100972896421, 23.079423475373336],\n", + " [72.56100972896421, 23.078456199634683],\n", + " [72.56255468135679, 23.078456199634683],\n", + " [72.56255468135679, 23.079423475373336]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59244395909863, 23.08886205587978],\n", + " [72.59244395909863, 23.088195867560096],\n", + " [72.59312524018841, 23.088195867560096],\n", + " [72.59312524018841, 23.08886205587978]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58891417203503, 23.08902490141124],\n", + " [72.58891417203503, 23.087914587055902],\n", + " [72.59019090352612, 23.087914587055902],\n", + " [72.59019090352612, 23.08902490141124]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.63284367422881, 23.083747187676313],\n", + " [72.63284367422881, 23.082246968536918],\n", + " [72.63458174567046, 23.082246968536918],\n", + " [72.63458174567046, 23.083747187676313]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61123781615103, 23.03548171268339],\n", + " [72.61123781615103, 23.034583235045087],\n", + " [72.61229997092093, 23.034583235045087],\n", + " [72.61229997092093, 23.03548171268339]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61444573813284, 23.03697257994195],\n", + " [72.61444573813284, 23.035649559490157],\n", + " [72.61594777518118, 23.035649559490157],\n", + " [72.61594777518118, 23.03697257994195]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.60209577668272, 23.04857847538297],\n", + " [72.60209577668272, 23.047275313883606],\n", + " [72.60400550950132, 23.047275313883606],\n", + " [72.60400550950132, 23.04857847538297]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51149811879407, 23.047834507790366],\n", + " [72.51149811879407, 23.04608707415321],\n", + " [72.51345076695691, 23.04608707415321],\n", + " [72.51345076695691, 23.047834507790366]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49712295504843, 23.062788240255994],\n", + " [72.49712295504843, 23.06162341641217],\n", + " [72.49815292331014, 23.06162341641217],\n", + " [72.49815292331014, 23.062788240255994]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54670277405151, 23.075491479960288],\n", + " [72.54670277405151, 23.072964630315727],\n", + " [72.5489343719519, 23.072964630315727],\n", + " [72.5489343719519, 23.075491479960288]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55421295929321, 23.07580733282782],\n", + " [72.55421295929321, 23.07367531157657],\n", + " [72.55751744079956, 23.07367531157657],\n", + " [72.55751744079956, 23.07580733282782]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53350630569824, 23.074001039232826],\n", + " [72.53350630569824, 23.072036790796002],\n", + " [72.53615632820495, 23.072036790796002],\n", + " [72.53615632820495, 23.074001039232826]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52723091860975, 23.03366481301143],\n", + " [72.52723091860975, 23.032420748682313],\n", + " [72.52894753237928, 23.032420748682313],\n", + " [72.52894753237928, 23.03366481301143]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52270334979261, 23.035698734716632],\n", + " [72.52270334979261, 23.034118992365073],\n", + " [72.52474182864393, 23.034118992365073],\n", + " [72.52474182864393, 23.035698734716632]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54976147433484, 23.028668739099235],\n", + " [72.54976147433484, 23.026970426741123],\n", + " [72.55210036059583, 23.026970426741123],\n", + " [72.55210036059583, 23.028668739099235]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55617731829847, 23.032835438068055],\n", + " [72.55617731829847, 23.03024854533837],\n", + " [72.55915993472303, 23.03024854533837],\n", + " [72.55915993472303, 23.032835438068055]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64766142687054, 22.9969522718421],\n", + " [72.64766142687054, 22.99607328997167],\n", + " [72.64864847978802, 22.99607328997167],\n", + " [72.64864847978802, 22.9969522718421]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.65313313326092, 22.99596465136559],\n", + " [72.65313313326092, 22.99518936422971],\n", + " [72.65385196527691, 22.99518936422971],\n", + " [72.65385196527691, 22.99596465136559]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64301113330575, 23.006479138035033],\n", + " [72.64301113330575, 23.005649595875003],\n", + " [72.64406792365762, 23.005649595875003],\n", + " [72.64406792365762, 23.006479138035033]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.63917020999642, 23.00445958899076],\n", + " [72.63917020999642, 23.003802858706333],\n", + " [72.64008216106149, 23.003802858706333],\n", + " [72.64008216106149, 23.00445958899076]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.62459470431035, 23.015117807565044],\n", + " [72.62459470431035, 23.014110570204384],\n", + " [72.62584997812932, 23.014110570204384],\n", + " [72.62584997812932, 23.015117807565044]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.62965335051244, 23.015483176121137],\n", + " [72.62965335051244, 23.01433769301113],\n", + " [72.63109101454442, 23.01433769301113],\n", + " [72.63109101454442, 23.015483176121137]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5929084117717, 23.018501870267272],\n", + " [72.5929084117717, 23.017763742536697],\n", + " [72.5937720830745, 23.017763742536697],\n", + " [72.5937720830745, 23.018501870267272]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56404451603258, 23.017177110456608],\n", + " [72.56404451603258, 23.015725523443777],\n", + " [72.565922062343, 23.015725523443777],\n", + " [72.565922062343, 23.017177110456608]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52290852145079, 23.033167515925737],\n", + " [72.52290852145079, 23.031962941433807],\n", + " [72.52428181246641, 23.031962941433807],\n", + " [72.52428181246641, 23.033167515925737]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52419598177794, 23.03062999809512],\n", + " [72.52419598177794, 23.02921805114397],\n", + " [72.52598769739988, 23.02921805114397],\n", + " [72.52598769739988, 23.03062999809512]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53902594674939, 23.05493608122571],\n", + " [72.53902594674939, 23.053850165460744],\n", + " [72.54044215310925, 23.053850165460744],\n", + " [72.54044215310925, 23.05493608122571]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"49\"\n", + " })]),\n", + " L7 = ee.ImageCollection(\"LANDSAT/LE07/C02/T1_L2\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.2 Urban Environments\n", + "# Checkpoint: A12g\n", + "# Authors: Michelle Stuhlmacher and Ran Goldblatt\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "Map.centerObject(bu, 13)\n", + "\n", + "# Surface reflectance function from example:\n", + "def maskL457sr(image):\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBand = image.select('ST_B6').multiply(0.00341802).add(\n", + " 149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " return image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBand, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + "\n", + "\n", + "# Map the function over one year of data.\n", + "collection = L7.filterDate('2020-01-01', '2021-01-01').map(\n", + " maskL457sr)\n", + "landsat7_2020 = collection.median()\n", + "\n", + "Map.addLayer(landsat7_2020, {\n", + " 'bands': ['SR_B3', 'SR_B2', 'SR_B1'],\n", + " 'min': 0,\n", + " 'max': 0.3\n", + "}, 'landsat 7, 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "lc = nbu.merge(bu)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'ST_B6',\n", + " 'SR_B7'\n", + "]\n", + "\n", + "training = landsat7_2020.select(bands).sampleRegions({\n", + " 'collection': lc,\n", + " 'properties': ['class'],\n", + " 'scale': 30\n", + "})\n", + "\n", + "# Create a random forest classifier with 20 trees.\n", + "classifier = ee.Classifier.smileRandomForest({\n", + " 'numberOfTrees': 20\n", + "}).train({ # Train the classifier.\n", + " # Use the examples we got when we sampled the pixels.\n", + " 'features': training,\n", + " # This is the class that we want to predict.\n", + " 'classProperty': 'class',\n", + " # The bands the classifier will use for training and classification.\n", + " 'inputProperties': bands\n", + "})\n", + "\n", + "# Apply the classifier on the 2020 image.\n", + "classified20 = landsat7_2020.select(bands).classify(classifier)\n", + "\n", + "Map.addLayer(classified20.mask(classified20), {\n", + " 'palette': ['#ff4218'],\n", + " 'opacity': 0.6\n", + "}, 'built-up, 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12g Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12g Checkpoint.js new file mode 100644 index 0000000..cb29493 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12g Checkpoint.js @@ -0,0 +1,1394 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var nbu = + /* color: #28d659 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.48565466309753, 23.013090225731943], + [72.48565466309753, 23.01218172380882], + [72.4868562927362, 23.01218172380882], + [72.4868562927362, 23.013090225731943]]], null, false), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48151333237854, 23.0108387097585], + [72.48151333237854, 23.009890691790975], + [72.48273641968933, 23.009890691790975], + [72.48273641968933, 23.0108387097585]]], null, false), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48265058900085, 23.00720460470793], + [72.48265058900085, 23.006236810228593], + [72.48398096467224, 23.006236810228593], + [72.48398096467224, 23.00720460470793]]], null, false), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50040144826141, 23.010868335212642], + [72.50040144826141, 23.010379514387374], + [72.50116319562164, 23.010379514387374], + [72.50116319562164, 23.010868335212642]]], null, false), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49854535962311, 23.009821565220278], + [72.49854535962311, 23.009426555565323], + [72.49904425049988, 23.009426555565323], + [72.49904425049988, 23.009821565220278]]], null, false), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49695212746826, 23.00991044223325], + [72.49695212746826, 23.00942161793733], + [72.49754757786957, 23.00942161793733], + [72.49754757786957, 23.00991044223325]]], null, false), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50098740533024, 23.012437718666618], + [72.50098740533024, 23.01211677963381], + [72.501486296207, 23.01211677963381], + [72.501486296207, 23.012437718666618]]], null, false), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49612187817722, 23.012250092863223], + [72.49612187817722, 23.011953841063395], + [72.49648129418522, 23.011953841063395], + [72.49648129418522, 23.012250092863223]]], null, false), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49531185105472, 23.011835340161273], + [72.49531185105472, 23.01150946214379], + [72.49571954682499, 23.01150946214379], + [72.49571954682499, 23.011835340161273]]], null, false), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50769643206644, 23.01452064371778], + [72.50769643206644, 23.014145397644366], + [72.50847963709879, 23.014145397644366], + [72.50847963709879, 23.01452064371778]]], null, false), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5057974280839, 23.013256652780115], + [72.5057974280839, 23.012486402494627], + [72.50663427729654, 23.012486402494627], + [72.50663427729654, 23.013256652780115]]], null, false), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5091126384263, 23.013799775337404], + [72.5091126384263, 23.013266527755206], + [72.50970272440958, 23.013266527755206], + [72.50970272440958, 23.013799775337404]]], null, false), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50782517809915, 23.01674247407806], + [72.50782517809915, 23.01673259935746], + [72.50811485667276, 23.01673259935746], + [72.50811485667276, 23.01674247407806]]], null, false), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50090507884073, 23.016702975191237], + [72.50090507884073, 23.01607099142841], + [72.50158099551248, 23.01607099142841], + [72.50158099551248, 23.016702975191237]]], null, false), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49740747828531, 23.016051241888096], + [72.49740747828531, 23.015715499260445], + [72.49777225871134, 23.015715499260445], + [72.49777225871134, 23.016051241888096]]], null, false), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49698905367899, 23.013394902365846], + [72.49698905367899, 23.012960403190835], + [72.49771861453104, 23.012960403190835], + [72.49771861453104, 23.013394902365846]]], null, false), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.4941459121232, 23.01318752793418], + [72.4941459121232, 23.01289127819304], + [72.49488620181131, 23.01289127819304], + [72.49488620181131, 23.01318752793418]]], null, false), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51445546856034, 23.025081565200995], + [72.51445546856034, 23.024607607106788], + [72.51517430057633, 23.024607607106788], + [72.51517430057633, 23.025081565200995]]], null, false), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5175990175258, 23.028952160599992], + [72.5175990175258, 23.028488089974577], + [72.51818910350907, 23.028488089974577], + [72.51818910350907, 23.028952160599992]]], null, false), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51869335880387, 23.028932412946357], + [72.51869335880387, 23.02818199996423], + [72.5195623945247, 23.02818199996423], + [72.5195623945247, 23.028932412946357]]], null, false), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52084471850465, 23.026596214980795], + [72.52084471850465, 23.02604326992137], + [72.52137043147157, 23.02604326992137], + [72.52137043147157, 23.026596214980795]]], null, false), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53553214246043, 23.03997960346422], + [72.53553214246043, 23.03879483608005], + [72.53699126416453, 23.03879483608005], + [72.53699126416453, 23.03997960346422]]], null, false), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52233567410715, 23.044086716392354], + [72.52233567410715, 23.0435535886138], + [72.5232798116804, 23.0435535886138], + [72.5232798116804, 23.044086716392354]]], null, false), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52499642544993, 23.043198168922416], + [72.52499642544993, 23.04248732672617], + [72.52587619000681, 23.04248732672617], + [72.52587619000681, 23.043198168922416]]], null, false), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52400937253245, 23.04181597231865], + [72.52400937253245, 23.040986647548742], + [72.52491059476145, 23.040986647548742], + [72.52491059476145, 23.04181597231865]]], null, false), + { + "class": 0, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57306172713966, 23.03598378282248], + [72.57306172713966, 23.034562018547053], + [72.57426335677833, 23.034562018547053], + [72.57426335677833, 23.03598378282248]]], null, false), + { + "class": 0, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57566066969198, 23.052508342763684], + [72.57566066969198, 23.050928797545748], + [72.57720562208456, 23.050928797545748], + [72.57720562208456, 23.052508342763684]]], null, false), + { + "class": 0, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5743302940206, 23.02486362694267], + [72.5743302940206, 23.023323254554423], + [72.57561775434775, 23.023323254554423], + [72.57561775434775, 23.02486362694267]]], null, false), + { + "class": 0, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68683489184394, 23.01212531748654], + [72.68683489184394, 23.010910679849328], + [72.68822964053169, 23.010910679849328], + [72.68822964053169, 23.01212531748654]]], null, false), + { + "class": 0, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.69045050959602, 23.01332019424718], + [72.69045050959602, 23.012174692768948], + [72.69152339320198, 23.012174692768948], + [72.69152339320198, 23.01332019424718]]], null, false), + { + "class": 0, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6833158336164, 23.01301406980455], + [72.6833158336164, 23.012233943083956], + [72.68446381907478, 23.012233943083956], + [72.68446381907478, 23.01301406980455]]], null, false), + { + "class": 0, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67707165102973, 23.01268819463449], + [72.67707165102973, 23.0117796900038], + [72.67849858622566, 23.0117796900038], + [72.67849858622566, 23.01268819463449]]], null, false), + { + "class": 0, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67816599230781, 23.014544685070533], + [72.67816599230781, 23.01347819368771], + [72.67923887591377, 23.01347819368771], + [72.67923887591377, 23.014544685070533]]], null, false), + { + "class": 0, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6903217635633, 23.016075282967993], + [72.6903217635633, 23.015413671814553], + [72.69105132441535, 23.015413671814553], + [72.69105132441535, 23.016075282967993]]], null, false), + { + "class": 0, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68663104395881, 23.015630917625792], + [72.68663104395881, 23.014890305468796], + [72.68773611407295, 23.014890305468796], + [72.68773611407295, 23.015630917625792]]], null, false), + { + "class": 0, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71553840093799, 23.017830754660782], + [72.71553840093799, 23.016606293669707], + [72.71675075941272, 23.016606293669707], + [72.71675075941272, 23.017830754660782]]], null, false), + { + "class": 0, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71506633215137, 23.01600393378011], + [72.71506633215137, 23.01512507600062], + [72.7161714022655, 23.01512507600062], + [72.7161714022655, 23.01600393378011]]], null, false), + { + "class": 0, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71916474752612, 23.017870253217335], + [72.71916474752612, 23.01693215937388], + [72.72010888509936, 23.01693215937388], + [72.72010888509936, 23.017870253217335]]], null, false), + { + "class": 0, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.70868267469592, 23.018521977730355], + [72.70868267469592, 23.01767276031886], + [72.70984138899036, 23.01767276031886], + [72.70984138899036, 23.018521977730355]]], null, false), + { + "class": 0, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.7059039061565, 23.015302822979788], + [72.7059039061565, 23.014473335073], + [72.70708407812305, 23.014473335073], + [72.70708407812305, 23.015302822979788]]], null, false), + { + "class": 0, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64443317494984, 22.995586380713714], + [72.64443317494984, 22.994895040144375], + [72.6453451260149, 22.994895040144375], + [72.6453451260149, 22.995586380713714]]], null, false), + { + "class": 0, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6488749130785, 22.99306790874182], + [72.6488749130785, 22.992317296243893], + [72.64966884694691, 22.992317296243893], + [72.64966884694691, 22.99306790874182]]], null, false), + { + "class": 0, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64429370008106, 22.992188901582924], + [72.64429370008106, 22.991566679573463], + [72.6448945149004, 22.991566679573463], + [72.6448945149004, 22.992188901582924]]], null, false), + { + "class": 0, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65110651097889, 22.996988803565362], + [72.65110651097889, 22.99634685125117], + [72.65186825833912, 22.99634685125117], + [72.65186825833912, 22.996988803565362]]], null, false), + { + "class": 0, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.650044356209, 22.99654437536528], + [72.650044356209, 22.995872792198217], + [72.65091339192982, 22.995872792198217], + [72.65091339192982, 22.99654437536528]]], null, false), + { + "class": 0, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65456119619007, 22.997166574435727], + [72.65456119619007, 22.996574003957473], + [72.65529075704212, 22.996574003957473], + [72.65529075704212, 22.997166574435727]]], null, false), + { + "class": 0, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58544230346283, 22.989353118858265], + [72.58544230346283, 22.987812341050095], + [72.58773827437957, 22.987812341050095], + [72.58773827437957, 22.989353118858265]]], null, false), + { + "class": 0, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61881659486005, 23.010174527999478], + [72.61881659486005, 23.009621515605502], + [72.61955688454816, 23.009621515605502], + [72.61955688454816, 23.010174527999478]]], null, false), + { + "class": 0, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61806557633588, 23.008890745751035], + [72.61806557633588, 23.008150096589624], + [72.6190419004173, 23.008150096589624], + [72.6190419004173, 23.008890745751035]]], null, false), + { + "class": 0, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61948212543246, 23.041104493489044], + [72.61948212543246, 23.039919735997568], + [72.6207695857596, 23.039919735997568], + [72.6207695857596, 23.041104493489044]]], null, false), + { + "class": 0, + "system:index": "49" + })]), + bu = + /* color: #ff2b10 */ + /* displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.55821826634332, 23.050534019942667], + [72.55821826634332, 23.049497430284074], + [72.55952718434258, 23.049497430284074], + [72.55952718434258, 23.050534019942667]]], null, false), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55760672268792, 23.052212291042135], + [72.55760672268792, 23.05108686449766], + [72.55907657322808, 23.05108686449766], + [72.55907657322808, 23.052212291042135]]], null, false), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56838920292779, 23.0515311129416], + [72.56838920292779, 23.05024772454887], + [72.56966593441888, 23.05024772454887], + [72.56966593441888, 23.0515311129416]]], null, false), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5620699184887, 23.049053175130464], + [72.5620699184887, 23.048016574072317], + [72.56340029416009, 23.048016574072317], + [72.56340029416009, 23.049053175130464]]], null, false), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52369259789576, 23.06300015365502], + [72.52369259789576, 23.061440474438808], + [72.5262031455337, 23.061440474438808], + [72.5262031455337, 23.06300015365502]]], null, false), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53285502389063, 23.064342647870983], + [72.53285502389063, 23.06258555714626], + [72.53459309533228, 23.06258555714626], + [72.53459309533228, 23.064342647870983]]], null, false), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52989386513819, 23.057866964035462], + [72.52989386513819, 23.05597158299574], + [72.53223275139918, 23.05597158299574], + [72.53223275139918, 23.057866964035462]]], null, false), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54572776915181, 23.069331684613978], + [72.54572776915181, 23.06821627216258], + [72.54719761969197, 23.06821627216258], + [72.54719761969197, 23.069331684613978]]], null, false), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54864601256001, 23.07097023834584], + [72.54864601256001, 23.069558714334168], + [72.5504269993459, 23.069558714334168], + [72.5504269993459, 23.07097023834584]]], null, false), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55111364485371, 23.0716908008372], + [72.55111364485371, 23.070377992312263], + [72.55256203772176, 23.070377992312263], + [72.55256203772176, 23.0716908008372]]], null, false), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50879440014218, 23.072620621975275], + [72.50879440014218, 23.071524978205787], + [72.51023206417416, 23.071524978205787], + [72.51023206417416, 23.072620621975275]]], null, false), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51449141208981, 23.071446012544282], + [72.51449141208981, 23.07000488107922], + [72.51615438167904, 23.07000488107922], + [72.51615438167904, 23.071446012544282]]], null, false), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49643476836059, 23.085681827252344], + [72.49643476836059, 23.08495640486992], + [72.49716969363067, 23.08495640486992], + [72.49716969363067, 23.085681827252344]]], null, false), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.47903499012024, 23.102978841643285], + [72.47903499012024, 23.101498574207657], + [72.48085889225037, 23.101498574207657], + [72.48085889225037, 23.102978841643285]]], null, false), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5935841682897, 23.027281425151706], + [72.5935841682897, 23.026639616972762], + [72.5942332628713, 23.026639616972762], + [72.5942332628713, 23.027281425151706]]], null, false), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59038697514394, 23.027562832389627], + [72.59038697514394, 23.026950647471846], + [72.59123991761068, 23.026950647471846], + [72.59123991761068, 23.027562832389627]]], null, false), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60934988735686, 23.029828009881232], + [72.60934988735686, 23.028504919287915], + [72.61101285694609, 23.028504919287915], + [72.61101285694609, 23.029828009881232]]], null, false), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59274164913664, 23.030756140307705], + [72.59274164913664, 23.0301933385778], + [72.59362141369353, 23.0301933385778], + [72.59362141369353, 23.030756140307705]]], null, false), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58861710173579, 23.038054851303], + [72.58861710173579, 23.036445516746404], + [72.5900225792596, 23.036445516746404], + [72.5900225792596, 23.038054851303]]], null, false), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58457233054133, 23.03763030478965], + [72.58457233054133, 23.03652450294007], + [72.58590270621272, 23.03652450294007], + [72.58590270621272, 23.03763030478965]]], null, false), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59348799330684, 23.037047785303628], + [72.59348799330684, 23.035892612094273], + [72.594957843847, 23.035892612094273], + [72.594957843847, 23.037047785303628]]], null, false), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56456097369993, 23.08033152381615], + [72.56456097369993, 23.078999059324314], + [72.56592353587949, 23.078999059324314], + [72.56592353587949, 23.08033152381615]]], null, false), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57296165233457, 23.08137774594047], + [72.57296165233457, 23.080084772128696], + [72.57410963779294, 23.080084772128696], + [72.57410963779294, 23.08137774594047]]], null, false), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56100972896421, 23.079423475373336], + [72.56100972896421, 23.078456199634683], + [72.56255468135679, 23.078456199634683], + [72.56255468135679, 23.079423475373336]]], null, false), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59244395909863, 23.08886205587978], + [72.59244395909863, 23.088195867560096], + [72.59312524018841, 23.088195867560096], + [72.59312524018841, 23.08886205587978]]], null, false), + { + "class": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58891417203503, 23.08902490141124], + [72.58891417203503, 23.087914587055902], + [72.59019090352612, 23.087914587055902], + [72.59019090352612, 23.08902490141124]]], null, false), + { + "class": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63284367422881, 23.083747187676313], + [72.63284367422881, 23.082246968536918], + [72.63458174567046, 23.082246968536918], + [72.63458174567046, 23.083747187676313]]], null, false), + { + "class": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61123781615103, 23.03548171268339], + [72.61123781615103, 23.034583235045087], + [72.61229997092093, 23.034583235045087], + [72.61229997092093, 23.03548171268339]]], null, false), + { + "class": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61444573813284, 23.03697257994195], + [72.61444573813284, 23.035649559490157], + [72.61594777518118, 23.035649559490157], + [72.61594777518118, 23.03697257994195]]], null, false), + { + "class": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60209577668272, 23.04857847538297], + [72.60209577668272, 23.047275313883606], + [72.60400550950132, 23.047275313883606], + [72.60400550950132, 23.04857847538297]]], null, false), + { + "class": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51149811879407, 23.047834507790366], + [72.51149811879407, 23.04608707415321], + [72.51345076695691, 23.04608707415321], + [72.51345076695691, 23.047834507790366]]], null, false), + { + "class": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49712295504843, 23.062788240255994], + [72.49712295504843, 23.06162341641217], + [72.49815292331014, 23.06162341641217], + [72.49815292331014, 23.062788240255994]]], null, false), + { + "class": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54670277405151, 23.075491479960288], + [72.54670277405151, 23.072964630315727], + [72.5489343719519, 23.072964630315727], + [72.5489343719519, 23.075491479960288]]], null, false), + { + "class": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55421295929321, 23.07580733282782], + [72.55421295929321, 23.07367531157657], + [72.55751744079956, 23.07367531157657], + [72.55751744079956, 23.07580733282782]]], null, false), + { + "class": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53350630569824, 23.074001039232826], + [72.53350630569824, 23.072036790796002], + [72.53615632820495, 23.072036790796002], + [72.53615632820495, 23.074001039232826]]], null, false), + { + "class": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52723091860975, 23.03366481301143], + [72.52723091860975, 23.032420748682313], + [72.52894753237928, 23.032420748682313], + [72.52894753237928, 23.03366481301143]]], null, false), + { + "class": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52270334979261, 23.035698734716632], + [72.52270334979261, 23.034118992365073], + [72.52474182864393, 23.034118992365073], + [72.52474182864393, 23.035698734716632]]], null, false), + { + "class": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54976147433484, 23.028668739099235], + [72.54976147433484, 23.026970426741123], + [72.55210036059583, 23.026970426741123], + [72.55210036059583, 23.028668739099235]]], null, false), + { + "class": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55617731829847, 23.032835438068055], + [72.55617731829847, 23.03024854533837], + [72.55915993472303, 23.03024854533837], + [72.55915993472303, 23.032835438068055]]], null, false), + { + "class": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64766142687054, 22.9969522718421], + [72.64766142687054, 22.99607328997167], + [72.64864847978802, 22.99607328997167], + [72.64864847978802, 22.9969522718421]]], null, false), + { + "class": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65313313326092, 22.99596465136559], + [72.65313313326092, 22.99518936422971], + [72.65385196527691, 22.99518936422971], + [72.65385196527691, 22.99596465136559]]], null, false), + { + "class": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64301113330575, 23.006479138035033], + [72.64301113330575, 23.005649595875003], + [72.64406792365762, 23.005649595875003], + [72.64406792365762, 23.006479138035033]]], null, false), + { + "class": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63917020999642, 23.00445958899076], + [72.63917020999642, 23.003802858706333], + [72.64008216106149, 23.003802858706333], + [72.64008216106149, 23.00445958899076]]], null, false), + { + "class": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62459470431035, 23.015117807565044], + [72.62459470431035, 23.014110570204384], + [72.62584997812932, 23.014110570204384], + [72.62584997812932, 23.015117807565044]]], null, false), + { + "class": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62965335051244, 23.015483176121137], + [72.62965335051244, 23.01433769301113], + [72.63109101454442, 23.01433769301113], + [72.63109101454442, 23.015483176121137]]], null, false), + { + "class": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5929084117717, 23.018501870267272], + [72.5929084117717, 23.017763742536697], + [72.5937720830745, 23.017763742536697], + [72.5937720830745, 23.018501870267272]]], null, false), + { + "class": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56404451603258, 23.017177110456608], + [72.56404451603258, 23.015725523443777], + [72.565922062343, 23.015725523443777], + [72.565922062343, 23.017177110456608]]], null, false), + { + "class": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52290852145079, 23.033167515925737], + [72.52290852145079, 23.031962941433807], + [72.52428181246641, 23.031962941433807], + [72.52428181246641, 23.033167515925737]]], null, false), + { + "class": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52419598177794, 23.03062999809512], + [72.52419598177794, 23.02921805114397], + [72.52598769739988, 23.02921805114397], + [72.52598769739988, 23.03062999809512]]], null, false), + { + "class": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53902594674939, 23.05493608122571], + [72.53902594674939, 23.053850165460744], + [72.54044215310925, 23.053850165460744], + [72.54044215310925, 23.05493608122571]]], null, false), + { + "class": 1, + "system:index": "49" + })]), + L7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_L2"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.2 Urban Environments +// Checkpoint: A12g +// Authors: Michelle Stuhlmacher and Ran Goldblatt +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Map.centerObject(bu, 13); + +// Surface reflectance function from example: +function maskL457sr(image) { + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0); + + // Replace the original bands with the scaled ones and apply the masks. + return image.addBands(opticalBands, null, true) + .addBands(thermalBand, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); +} + +// Map the function over one year of data. +var collection = L7.filterDate('2020-01-01', '2021-01-01').map( + maskL457sr); +var landsat7_2020 = collection.median(); + +Map.addLayer(landsat7_2020, { + bands: ['SR_B3', 'SR_B2', 'SR_B1'], + min: 0, + max: 0.3 +}, 'landsat 7, 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var lc = nbu.merge(bu); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'ST_B6', + 'SR_B7' +]; + +var training = landsat7_2020.select(bands).sampleRegions({ + collection: lc, + properties: ['class'], + scale: 30 +}); + +// Create a random forest classifier with 20 trees. +var classifier = ee.Classifier.smileRandomForest({ + numberOfTrees: 20 +}).train({ // Train the classifier. + // Use the examples we got when we sampled the pixels. + features: training, + // This is the class that we want to predict. + classProperty: 'class', + // The bands the classifier will use for training and classification. + inputProperties: bands +}); + +// Apply the classifier on the 2020 image. +var classified20 = landsat7_2020.select(bands).classify(classifier); + +Map.addLayer(classified20.mask(classified20), { + palette: ['#ff4218'], + opacity: 0.6 +}, 'built-up, 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12g Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12g Checkpoint.py new file mode 100644 index 0000000..bc1900e --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12g Checkpoint.py @@ -0,0 +1,1400 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +nbu = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.48565466309753, 23.013090225731943], + [72.48565466309753, 23.01218172380882], + [72.4868562927362, 23.01218172380882], + [72.4868562927362, 23.013090225731943]]], None, False), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48151333237854, 23.0108387097585], + [72.48151333237854, 23.009890691790975], + [72.48273641968933, 23.009890691790975], + [72.48273641968933, 23.0108387097585]]], None, False), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48265058900085, 23.00720460470793], + [72.48265058900085, 23.006236810228593], + [72.48398096467224, 23.006236810228593], + [72.48398096467224, 23.00720460470793]]], None, False), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50040144826141, 23.010868335212642], + [72.50040144826141, 23.010379514387374], + [72.50116319562164, 23.010379514387374], + [72.50116319562164, 23.010868335212642]]], None, False), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49854535962311, 23.009821565220278], + [72.49854535962311, 23.009426555565323], + [72.49904425049988, 23.009426555565323], + [72.49904425049988, 23.009821565220278]]], None, False), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49695212746826, 23.00991044223325], + [72.49695212746826, 23.00942161793733], + [72.49754757786957, 23.00942161793733], + [72.49754757786957, 23.00991044223325]]], None, False), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50098740533024, 23.012437718666618], + [72.50098740533024, 23.01211677963381], + [72.501486296207, 23.01211677963381], + [72.501486296207, 23.012437718666618]]], None, False), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49612187817722, 23.012250092863223], + [72.49612187817722, 23.011953841063395], + [72.49648129418522, 23.011953841063395], + [72.49648129418522, 23.012250092863223]]], None, False), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49531185105472, 23.011835340161273], + [72.49531185105472, 23.01150946214379], + [72.49571954682499, 23.01150946214379], + [72.49571954682499, 23.011835340161273]]], None, False), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50769643206644, 23.01452064371778], + [72.50769643206644, 23.014145397644366], + [72.50847963709879, 23.014145397644366], + [72.50847963709879, 23.01452064371778]]], None, False), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5057974280839, 23.013256652780115], + [72.5057974280839, 23.012486402494627], + [72.50663427729654, 23.012486402494627], + [72.50663427729654, 23.013256652780115]]], None, False), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5091126384263, 23.013799775337404], + [72.5091126384263, 23.013266527755206], + [72.50970272440958, 23.013266527755206], + [72.50970272440958, 23.013799775337404]]], None, False), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50782517809915, 23.01674247407806], + [72.50782517809915, 23.01673259935746], + [72.50811485667276, 23.01673259935746], + [72.50811485667276, 23.01674247407806]]], None, False), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50090507884073, 23.016702975191237], + [72.50090507884073, 23.01607099142841], + [72.50158099551248, 23.01607099142841], + [72.50158099551248, 23.016702975191237]]], None, False), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49740747828531, 23.016051241888096], + [72.49740747828531, 23.015715499260445], + [72.49777225871134, 23.015715499260445], + [72.49777225871134, 23.016051241888096]]], None, False), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49698905367899, 23.013394902365846], + [72.49698905367899, 23.012960403190835], + [72.49771861453104, 23.012960403190835], + [72.49771861453104, 23.013394902365846]]], None, False), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.4941459121232, 23.01318752793418], + [72.4941459121232, 23.01289127819304], + [72.49488620181131, 23.01289127819304], + [72.49488620181131, 23.01318752793418]]], None, False), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51445546856034, 23.025081565200995], + [72.51445546856034, 23.024607607106788], + [72.51517430057633, 23.024607607106788], + [72.51517430057633, 23.025081565200995]]], None, False), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5175990175258, 23.028952160599992], + [72.5175990175258, 23.028488089974577], + [72.51818910350907, 23.028488089974577], + [72.51818910350907, 23.028952160599992]]], None, False), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51869335880387, 23.028932412946357], + [72.51869335880387, 23.02818199996423], + [72.5195623945247, 23.02818199996423], + [72.5195623945247, 23.028932412946357]]], None, False), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52084471850465, 23.026596214980795], + [72.52084471850465, 23.02604326992137], + [72.52137043147157, 23.02604326992137], + [72.52137043147157, 23.026596214980795]]], None, False), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53553214246043, 23.03997960346422], + [72.53553214246043, 23.03879483608005], + [72.53699126416453, 23.03879483608005], + [72.53699126416453, 23.03997960346422]]], None, False), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52233567410715, 23.044086716392354], + [72.52233567410715, 23.0435535886138], + [72.5232798116804, 23.0435535886138], + [72.5232798116804, 23.044086716392354]]], None, False), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52499642544993, 23.043198168922416], + [72.52499642544993, 23.04248732672617], + [72.52587619000681, 23.04248732672617], + [72.52587619000681, 23.043198168922416]]], None, False), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52400937253245, 23.04181597231865], + [72.52400937253245, 23.040986647548742], + [72.52491059476145, 23.040986647548742], + [72.52491059476145, 23.04181597231865]]], None, False), + { + "class": 0, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57306172713966, 23.03598378282248], + [72.57306172713966, 23.034562018547053], + [72.57426335677833, 23.034562018547053], + [72.57426335677833, 23.03598378282248]]], None, False), + { + "class": 0, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57566066969198, 23.052508342763684], + [72.57566066969198, 23.050928797545748], + [72.57720562208456, 23.050928797545748], + [72.57720562208456, 23.052508342763684]]], None, False), + { + "class": 0, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5743302940206, 23.02486362694267], + [72.5743302940206, 23.023323254554423], + [72.57561775434775, 23.023323254554423], + [72.57561775434775, 23.02486362694267]]], None, False), + { + "class": 0, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68683489184394, 23.01212531748654], + [72.68683489184394, 23.010910679849328], + [72.68822964053169, 23.010910679849328], + [72.68822964053169, 23.01212531748654]]], None, False), + { + "class": 0, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.69045050959602, 23.01332019424718], + [72.69045050959602, 23.012174692768948], + [72.69152339320198, 23.012174692768948], + [72.69152339320198, 23.01332019424718]]], None, False), + { + "class": 0, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6833158336164, 23.01301406980455], + [72.6833158336164, 23.012233943083956], + [72.68446381907478, 23.012233943083956], + [72.68446381907478, 23.01301406980455]]], None, False), + { + "class": 0, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67707165102973, 23.01268819463449], + [72.67707165102973, 23.0117796900038], + [72.67849858622566, 23.0117796900038], + [72.67849858622566, 23.01268819463449]]], None, False), + { + "class": 0, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67816599230781, 23.014544685070533], + [72.67816599230781, 23.01347819368771], + [72.67923887591377, 23.01347819368771], + [72.67923887591377, 23.014544685070533]]], None, False), + { + "class": 0, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6903217635633, 23.016075282967993], + [72.6903217635633, 23.015413671814553], + [72.69105132441535, 23.015413671814553], + [72.69105132441535, 23.016075282967993]]], None, False), + { + "class": 0, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68663104395881, 23.015630917625792], + [72.68663104395881, 23.014890305468796], + [72.68773611407295, 23.014890305468796], + [72.68773611407295, 23.015630917625792]]], None, False), + { + "class": 0, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71553840093799, 23.017830754660782], + [72.71553840093799, 23.016606293669707], + [72.71675075941272, 23.016606293669707], + [72.71675075941272, 23.017830754660782]]], None, False), + { + "class": 0, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71506633215137, 23.01600393378011], + [72.71506633215137, 23.01512507600062], + [72.7161714022655, 23.01512507600062], + [72.7161714022655, 23.01600393378011]]], None, False), + { + "class": 0, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71916474752612, 23.017870253217335], + [72.71916474752612, 23.01693215937388], + [72.72010888509936, 23.01693215937388], + [72.72010888509936, 23.017870253217335]]], None, False), + { + "class": 0, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.70868267469592, 23.018521977730355], + [72.70868267469592, 23.01767276031886], + [72.70984138899036, 23.01767276031886], + [72.70984138899036, 23.018521977730355]]], None, False), + { + "class": 0, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.7059039061565, 23.015302822979788], + [72.7059039061565, 23.014473335073], + [72.70708407812305, 23.014473335073], + [72.70708407812305, 23.015302822979788]]], None, False), + { + "class": 0, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64443317494984, 22.995586380713714], + [72.64443317494984, 22.994895040144375], + [72.6453451260149, 22.994895040144375], + [72.6453451260149, 22.995586380713714]]], None, False), + { + "class": 0, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6488749130785, 22.99306790874182], + [72.6488749130785, 22.992317296243893], + [72.64966884694691, 22.992317296243893], + [72.64966884694691, 22.99306790874182]]], None, False), + { + "class": 0, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64429370008106, 22.992188901582924], + [72.64429370008106, 22.991566679573463], + [72.6448945149004, 22.991566679573463], + [72.6448945149004, 22.992188901582924]]], None, False), + { + "class": 0, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65110651097889, 22.996988803565362], + [72.65110651097889, 22.99634685125117], + [72.65186825833912, 22.99634685125117], + [72.65186825833912, 22.996988803565362]]], None, False), + { + "class": 0, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.650044356209, 22.99654437536528], + [72.650044356209, 22.995872792198217], + [72.65091339192982, 22.995872792198217], + [72.65091339192982, 22.99654437536528]]], None, False), + { + "class": 0, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65456119619007, 22.997166574435727], + [72.65456119619007, 22.996574003957473], + [72.65529075704212, 22.996574003957473], + [72.65529075704212, 22.997166574435727]]], None, False), + { + "class": 0, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58544230346283, 22.989353118858265], + [72.58544230346283, 22.987812341050095], + [72.58773827437957, 22.987812341050095], + [72.58773827437957, 22.989353118858265]]], None, False), + { + "class": 0, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61881659486005, 23.010174527999478], + [72.61881659486005, 23.009621515605502], + [72.61955688454816, 23.009621515605502], + [72.61955688454816, 23.010174527999478]]], None, False), + { + "class": 0, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61806557633588, 23.008890745751035], + [72.61806557633588, 23.008150096589624], + [72.6190419004173, 23.008150096589624], + [72.6190419004173, 23.008890745751035]]], None, False), + { + "class": 0, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61948212543246, 23.041104493489044], + [72.61948212543246, 23.039919735997568], + [72.6207695857596, 23.039919735997568], + [72.6207695857596, 23.041104493489044]]], None, False), + { + "class": 0, + "system:index": "49" + })]), + bu = + + # displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.55821826634332, 23.050534019942667], + [72.55821826634332, 23.049497430284074], + [72.55952718434258, 23.049497430284074], + [72.55952718434258, 23.050534019942667]]], None, False), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55760672268792, 23.052212291042135], + [72.55760672268792, 23.05108686449766], + [72.55907657322808, 23.05108686449766], + [72.55907657322808, 23.052212291042135]]], None, False), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56838920292779, 23.0515311129416], + [72.56838920292779, 23.05024772454887], + [72.56966593441888, 23.05024772454887], + [72.56966593441888, 23.0515311129416]]], None, False), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5620699184887, 23.049053175130464], + [72.5620699184887, 23.048016574072317], + [72.56340029416009, 23.048016574072317], + [72.56340029416009, 23.049053175130464]]], None, False), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52369259789576, 23.06300015365502], + [72.52369259789576, 23.061440474438808], + [72.5262031455337, 23.061440474438808], + [72.5262031455337, 23.06300015365502]]], None, False), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53285502389063, 23.064342647870983], + [72.53285502389063, 23.06258555714626], + [72.53459309533228, 23.06258555714626], + [72.53459309533228, 23.064342647870983]]], None, False), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52989386513819, 23.057866964035462], + [72.52989386513819, 23.05597158299574], + [72.53223275139918, 23.05597158299574], + [72.53223275139918, 23.057866964035462]]], None, False), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54572776915181, 23.069331684613978], + [72.54572776915181, 23.06821627216258], + [72.54719761969197, 23.06821627216258], + [72.54719761969197, 23.069331684613978]]], None, False), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54864601256001, 23.07097023834584], + [72.54864601256001, 23.069558714334168], + [72.5504269993459, 23.069558714334168], + [72.5504269993459, 23.07097023834584]]], None, False), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55111364485371, 23.0716908008372], + [72.55111364485371, 23.070377992312263], + [72.55256203772176, 23.070377992312263], + [72.55256203772176, 23.0716908008372]]], None, False), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50879440014218, 23.072620621975275], + [72.50879440014218, 23.071524978205787], + [72.51023206417416, 23.071524978205787], + [72.51023206417416, 23.072620621975275]]], None, False), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51449141208981, 23.071446012544282], + [72.51449141208981, 23.07000488107922], + [72.51615438167904, 23.07000488107922], + [72.51615438167904, 23.071446012544282]]], None, False), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49643476836059, 23.085681827252344], + [72.49643476836059, 23.08495640486992], + [72.49716969363067, 23.08495640486992], + [72.49716969363067, 23.085681827252344]]], None, False), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.47903499012024, 23.102978841643285], + [72.47903499012024, 23.101498574207657], + [72.48085889225037, 23.101498574207657], + [72.48085889225037, 23.102978841643285]]], None, False), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5935841682897, 23.027281425151706], + [72.5935841682897, 23.026639616972762], + [72.5942332628713, 23.026639616972762], + [72.5942332628713, 23.027281425151706]]], None, False), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59038697514394, 23.027562832389627], + [72.59038697514394, 23.026950647471846], + [72.59123991761068, 23.026950647471846], + [72.59123991761068, 23.027562832389627]]], None, False), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60934988735686, 23.029828009881232], + [72.60934988735686, 23.028504919287915], + [72.61101285694609, 23.028504919287915], + [72.61101285694609, 23.029828009881232]]], None, False), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59274164913664, 23.030756140307705], + [72.59274164913664, 23.0301933385778], + [72.59362141369353, 23.0301933385778], + [72.59362141369353, 23.030756140307705]]], None, False), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58861710173579, 23.038054851303], + [72.58861710173579, 23.036445516746404], + [72.5900225792596, 23.036445516746404], + [72.5900225792596, 23.038054851303]]], None, False), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58457233054133, 23.03763030478965], + [72.58457233054133, 23.03652450294007], + [72.58590270621272, 23.03652450294007], + [72.58590270621272, 23.03763030478965]]], None, False), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59348799330684, 23.037047785303628], + [72.59348799330684, 23.035892612094273], + [72.594957843847, 23.035892612094273], + [72.594957843847, 23.037047785303628]]], None, False), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56456097369993, 23.08033152381615], + [72.56456097369993, 23.078999059324314], + [72.56592353587949, 23.078999059324314], + [72.56592353587949, 23.08033152381615]]], None, False), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57296165233457, 23.08137774594047], + [72.57296165233457, 23.080084772128696], + [72.57410963779294, 23.080084772128696], + [72.57410963779294, 23.08137774594047]]], None, False), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56100972896421, 23.079423475373336], + [72.56100972896421, 23.078456199634683], + [72.56255468135679, 23.078456199634683], + [72.56255468135679, 23.079423475373336]]], None, False), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59244395909863, 23.08886205587978], + [72.59244395909863, 23.088195867560096], + [72.59312524018841, 23.088195867560096], + [72.59312524018841, 23.08886205587978]]], None, False), + { + "class": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58891417203503, 23.08902490141124], + [72.58891417203503, 23.087914587055902], + [72.59019090352612, 23.087914587055902], + [72.59019090352612, 23.08902490141124]]], None, False), + { + "class": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63284367422881, 23.083747187676313], + [72.63284367422881, 23.082246968536918], + [72.63458174567046, 23.082246968536918], + [72.63458174567046, 23.083747187676313]]], None, False), + { + "class": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61123781615103, 23.03548171268339], + [72.61123781615103, 23.034583235045087], + [72.61229997092093, 23.034583235045087], + [72.61229997092093, 23.03548171268339]]], None, False), + { + "class": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61444573813284, 23.03697257994195], + [72.61444573813284, 23.035649559490157], + [72.61594777518118, 23.035649559490157], + [72.61594777518118, 23.03697257994195]]], None, False), + { + "class": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60209577668272, 23.04857847538297], + [72.60209577668272, 23.047275313883606], + [72.60400550950132, 23.047275313883606], + [72.60400550950132, 23.04857847538297]]], None, False), + { + "class": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51149811879407, 23.047834507790366], + [72.51149811879407, 23.04608707415321], + [72.51345076695691, 23.04608707415321], + [72.51345076695691, 23.047834507790366]]], None, False), + { + "class": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49712295504843, 23.062788240255994], + [72.49712295504843, 23.06162341641217], + [72.49815292331014, 23.06162341641217], + [72.49815292331014, 23.062788240255994]]], None, False), + { + "class": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54670277405151, 23.075491479960288], + [72.54670277405151, 23.072964630315727], + [72.5489343719519, 23.072964630315727], + [72.5489343719519, 23.075491479960288]]], None, False), + { + "class": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55421295929321, 23.07580733282782], + [72.55421295929321, 23.07367531157657], + [72.55751744079956, 23.07367531157657], + [72.55751744079956, 23.07580733282782]]], None, False), + { + "class": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53350630569824, 23.074001039232826], + [72.53350630569824, 23.072036790796002], + [72.53615632820495, 23.072036790796002], + [72.53615632820495, 23.074001039232826]]], None, False), + { + "class": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52723091860975, 23.03366481301143], + [72.52723091860975, 23.032420748682313], + [72.52894753237928, 23.032420748682313], + [72.52894753237928, 23.03366481301143]]], None, False), + { + "class": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52270334979261, 23.035698734716632], + [72.52270334979261, 23.034118992365073], + [72.52474182864393, 23.034118992365073], + [72.52474182864393, 23.035698734716632]]], None, False), + { + "class": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54976147433484, 23.028668739099235], + [72.54976147433484, 23.026970426741123], + [72.55210036059583, 23.026970426741123], + [72.55210036059583, 23.028668739099235]]], None, False), + { + "class": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55617731829847, 23.032835438068055], + [72.55617731829847, 23.03024854533837], + [72.55915993472303, 23.03024854533837], + [72.55915993472303, 23.032835438068055]]], None, False), + { + "class": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64766142687054, 22.9969522718421], + [72.64766142687054, 22.99607328997167], + [72.64864847978802, 22.99607328997167], + [72.64864847978802, 22.9969522718421]]], None, False), + { + "class": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65313313326092, 22.99596465136559], + [72.65313313326092, 22.99518936422971], + [72.65385196527691, 22.99518936422971], + [72.65385196527691, 22.99596465136559]]], None, False), + { + "class": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64301113330575, 23.006479138035033], + [72.64301113330575, 23.005649595875003], + [72.64406792365762, 23.005649595875003], + [72.64406792365762, 23.006479138035033]]], None, False), + { + "class": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63917020999642, 23.00445958899076], + [72.63917020999642, 23.003802858706333], + [72.64008216106149, 23.003802858706333], + [72.64008216106149, 23.00445958899076]]], None, False), + { + "class": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62459470431035, 23.015117807565044], + [72.62459470431035, 23.014110570204384], + [72.62584997812932, 23.014110570204384], + [72.62584997812932, 23.015117807565044]]], None, False), + { + "class": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62965335051244, 23.015483176121137], + [72.62965335051244, 23.01433769301113], + [72.63109101454442, 23.01433769301113], + [72.63109101454442, 23.015483176121137]]], None, False), + { + "class": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5929084117717, 23.018501870267272], + [72.5929084117717, 23.017763742536697], + [72.5937720830745, 23.017763742536697], + [72.5937720830745, 23.018501870267272]]], None, False), + { + "class": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56404451603258, 23.017177110456608], + [72.56404451603258, 23.015725523443777], + [72.565922062343, 23.015725523443777], + [72.565922062343, 23.017177110456608]]], None, False), + { + "class": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52290852145079, 23.033167515925737], + [72.52290852145079, 23.031962941433807], + [72.52428181246641, 23.031962941433807], + [72.52428181246641, 23.033167515925737]]], None, False), + { + "class": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52419598177794, 23.03062999809512], + [72.52419598177794, 23.02921805114397], + [72.52598769739988, 23.02921805114397], + [72.52598769739988, 23.03062999809512]]], None, False), + { + "class": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53902594674939, 23.05493608122571], + [72.53902594674939, 23.053850165460744], + [72.54044215310925, 23.053850165460744], + [72.54044215310925, 23.05493608122571]]], None, False), + { + "class": 1, + "system:index": "49" + })]), + L7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_L2") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.2 Urban Environments +# Checkpoint: A12g +# Authors: Michelle Stuhlmacher and Ran Goldblatt +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Map.centerObject(bu, 13) + +# Surface reflectance function from example: +def maskL457sr(image): + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0) + + # Replace the original bands with the scaled ones and apply the masks. + return image.addBands(opticalBands, None, True) \ + .addBands(thermalBand, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + + +# Map the function over one year of data. +collection = L7.filterDate('2020-01-01', '2021-01-01').map( + maskL457sr) +landsat7_2020 = collection.median() + +Map.addLayer(landsat7_2020, { + 'bands': ['SR_B3', 'SR_B2', 'SR_B1'], + 'min': 0, + 'max': 0.3 +}, 'landsat 7, 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +lc = nbu.merge(bu) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'ST_B6', + 'SR_B7' +] + +training = landsat7_2020.select(bands).sampleRegions({ + 'collection': lc, + 'properties': ['class'], + 'scale': 30 +}) + +# Create a random forest classifier with 20 trees. +classifier = ee.Classifier.smileRandomForest({ + 'numberOfTrees': 20 +}).train({ # Train the classifier. + # Use the examples we got when we sampled the pixels. + 'features': training, + # This is the class that we want to predict. + 'classProperty': 'class', + # The bands the classifier will use for training and classification. + 'inputProperties': bands +}) + +# Apply the classifier on the 2020 image. +classified20 = landsat7_2020.select(bands).classify(classifier) + +Map.addLayer(classified20.mask(classified20), { + 'palette': ['#ff4218'], + 'opacity': 0.6 +}, 'built-up, 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12h Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12h Checkpoint.ipynb new file mode 100644 index 0000000..1ed4f2b --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12h Checkpoint.ipynb @@ -0,0 +1,1509 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "nbu =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.48565466309753, 23.013090225731943],\n", + " [72.48565466309753, 23.01218172380882],\n", + " [72.4868562927362, 23.01218172380882],\n", + " [72.4868562927362, 23.013090225731943]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.48151333237854, 23.0108387097585],\n", + " [72.48151333237854, 23.009890691790975],\n", + " [72.48273641968933, 23.009890691790975],\n", + " [72.48273641968933, 23.0108387097585]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.48265058900085, 23.00720460470793],\n", + " [72.48265058900085, 23.006236810228593],\n", + " [72.48398096467224, 23.006236810228593],\n", + " [72.48398096467224, 23.00720460470793]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50040144826141, 23.010868335212642],\n", + " [72.50040144826141, 23.010379514387374],\n", + " [72.50116319562164, 23.010379514387374],\n", + " [72.50116319562164, 23.010868335212642]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49854535962311, 23.009821565220278],\n", + " [72.49854535962311, 23.009426555565323],\n", + " [72.49904425049988, 23.009426555565323],\n", + " [72.49904425049988, 23.009821565220278]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49695212746826, 23.00991044223325],\n", + " [72.49695212746826, 23.00942161793733],\n", + " [72.49754757786957, 23.00942161793733],\n", + " [72.49754757786957, 23.00991044223325]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50098740533024, 23.012437718666618],\n", + " [72.50098740533024, 23.01211677963381],\n", + " [72.501486296207, 23.01211677963381],\n", + " [72.501486296207, 23.012437718666618]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49612187817722, 23.012250092863223],\n", + " [72.49612187817722, 23.011953841063395],\n", + " [72.49648129418522, 23.011953841063395],\n", + " [72.49648129418522, 23.012250092863223]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49531185105472, 23.011835340161273],\n", + " [72.49531185105472, 23.01150946214379],\n", + " [72.49571954682499, 23.01150946214379],\n", + " [72.49571954682499, 23.011835340161273]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50769643206644, 23.01452064371778],\n", + " [72.50769643206644, 23.014145397644366],\n", + " [72.50847963709879, 23.014145397644366],\n", + " [72.50847963709879, 23.01452064371778]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5057974280839, 23.013256652780115],\n", + " [72.5057974280839, 23.012486402494627],\n", + " [72.50663427729654, 23.012486402494627],\n", + " [72.50663427729654, 23.013256652780115]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5091126384263, 23.013799775337404],\n", + " [72.5091126384263, 23.013266527755206],\n", + " [72.50970272440958, 23.013266527755206],\n", + " [72.50970272440958, 23.013799775337404]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50782517809915, 23.01674247407806],\n", + " [72.50782517809915, 23.01673259935746],\n", + " [72.50811485667276, 23.01673259935746],\n", + " [72.50811485667276, 23.01674247407806]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50090507884073, 23.016702975191237],\n", + " [72.50090507884073, 23.01607099142841],\n", + " [72.50158099551248, 23.01607099142841],\n", + " [72.50158099551248, 23.016702975191237]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49740747828531, 23.016051241888096],\n", + " [72.49740747828531, 23.015715499260445],\n", + " [72.49777225871134, 23.015715499260445],\n", + " [72.49777225871134, 23.016051241888096]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49698905367899, 23.013394902365846],\n", + " [72.49698905367899, 23.012960403190835],\n", + " [72.49771861453104, 23.012960403190835],\n", + " [72.49771861453104, 23.013394902365846]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.4941459121232, 23.01318752793418],\n", + " [72.4941459121232, 23.01289127819304],\n", + " [72.49488620181131, 23.01289127819304],\n", + " [72.49488620181131, 23.01318752793418]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51445546856034, 23.025081565200995],\n", + " [72.51445546856034, 23.024607607106788],\n", + " [72.51517430057633, 23.024607607106788],\n", + " [72.51517430057633, 23.025081565200995]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5175990175258, 23.028952160599992],\n", + " [72.5175990175258, 23.028488089974577],\n", + " [72.51818910350907, 23.028488089974577],\n", + " [72.51818910350907, 23.028952160599992]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51869335880387, 23.028932412946357],\n", + " [72.51869335880387, 23.02818199996423],\n", + " [72.5195623945247, 23.02818199996423],\n", + " [72.5195623945247, 23.028932412946357]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52084471850465, 23.026596214980795],\n", + " [72.52084471850465, 23.02604326992137],\n", + " [72.52137043147157, 23.02604326992137],\n", + " [72.52137043147157, 23.026596214980795]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53553214246043, 23.03997960346422],\n", + " [72.53553214246043, 23.03879483608005],\n", + " [72.53699126416453, 23.03879483608005],\n", + " [72.53699126416453, 23.03997960346422]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52233567410715, 23.044086716392354],\n", + " [72.52233567410715, 23.0435535886138],\n", + " [72.5232798116804, 23.0435535886138],\n", + " [72.5232798116804, 23.044086716392354]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52499642544993, 23.043198168922416],\n", + " [72.52499642544993, 23.04248732672617],\n", + " [72.52587619000681, 23.04248732672617],\n", + " [72.52587619000681, 23.043198168922416]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52400937253245, 23.04181597231865],\n", + " [72.52400937253245, 23.040986647548742],\n", + " [72.52491059476145, 23.040986647548742],\n", + " [72.52491059476145, 23.04181597231865]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.57306172713966, 23.03598378282248],\n", + " [72.57306172713966, 23.034562018547053],\n", + " [72.57426335677833, 23.034562018547053],\n", + " [72.57426335677833, 23.03598378282248]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.57566066969198, 23.052508342763684],\n", + " [72.57566066969198, 23.050928797545748],\n", + " [72.57720562208456, 23.050928797545748],\n", + " [72.57720562208456, 23.052508342763684]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5743302940206, 23.02486362694267],\n", + " [72.5743302940206, 23.023323254554423],\n", + " [72.57561775434775, 23.023323254554423],\n", + " [72.57561775434775, 23.02486362694267]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.68683489184394, 23.01212531748654],\n", + " [72.68683489184394, 23.010910679849328],\n", + " [72.68822964053169, 23.010910679849328],\n", + " [72.68822964053169, 23.01212531748654]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.69045050959602, 23.01332019424718],\n", + " [72.69045050959602, 23.012174692768948],\n", + " [72.69152339320198, 23.012174692768948],\n", + " [72.69152339320198, 23.01332019424718]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.6833158336164, 23.01301406980455],\n", + " [72.6833158336164, 23.012233943083956],\n", + " [72.68446381907478, 23.012233943083956],\n", + " [72.68446381907478, 23.01301406980455]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.67707165102973, 23.01268819463449],\n", + " [72.67707165102973, 23.0117796900038],\n", + " [72.67849858622566, 23.0117796900038],\n", + " [72.67849858622566, 23.01268819463449]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.67816599230781, 23.014544685070533],\n", + " [72.67816599230781, 23.01347819368771],\n", + " [72.67923887591377, 23.01347819368771],\n", + " [72.67923887591377, 23.014544685070533]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.6903217635633, 23.016075282967993],\n", + " [72.6903217635633, 23.015413671814553],\n", + " [72.69105132441535, 23.015413671814553],\n", + " [72.69105132441535, 23.016075282967993]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.68663104395881, 23.015630917625792],\n", + " [72.68663104395881, 23.014890305468796],\n", + " [72.68773611407295, 23.014890305468796],\n", + " [72.68773611407295, 23.015630917625792]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.71553840093799, 23.017830754660782],\n", + " [72.71553840093799, 23.016606293669707],\n", + " [72.71675075941272, 23.016606293669707],\n", + " [72.71675075941272, 23.017830754660782]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.71506633215137, 23.01600393378011],\n", + " [72.71506633215137, 23.01512507600062],\n", + " [72.7161714022655, 23.01512507600062],\n", + " [72.7161714022655, 23.01600393378011]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.71916474752612, 23.017870253217335],\n", + " [72.71916474752612, 23.01693215937388],\n", + " [72.72010888509936, 23.01693215937388],\n", + " [72.72010888509936, 23.017870253217335]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.70868267469592, 23.018521977730355],\n", + " [72.70868267469592, 23.01767276031886],\n", + " [72.70984138899036, 23.01767276031886],\n", + " [72.70984138899036, 23.018521977730355]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.7059039061565, 23.015302822979788],\n", + " [72.7059039061565, 23.014473335073],\n", + " [72.70708407812305, 23.014473335073],\n", + " [72.70708407812305, 23.015302822979788]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64443317494984, 22.995586380713714],\n", + " [72.64443317494984, 22.994895040144375],\n", + " [72.6453451260149, 22.994895040144375],\n", + " [72.6453451260149, 22.995586380713714]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.6488749130785, 22.99306790874182],\n", + " [72.6488749130785, 22.992317296243893],\n", + " [72.64966884694691, 22.992317296243893],\n", + " [72.64966884694691, 22.99306790874182]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64429370008106, 22.992188901582924],\n", + " [72.64429370008106, 22.991566679573463],\n", + " [72.6448945149004, 22.991566679573463],\n", + " [72.6448945149004, 22.992188901582924]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.65110651097889, 22.996988803565362],\n", + " [72.65110651097889, 22.99634685125117],\n", + " [72.65186825833912, 22.99634685125117],\n", + " [72.65186825833912, 22.996988803565362]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.650044356209, 22.99654437536528],\n", + " [72.650044356209, 22.995872792198217],\n", + " [72.65091339192982, 22.995872792198217],\n", + " [72.65091339192982, 22.99654437536528]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.65456119619007, 22.997166574435727],\n", + " [72.65456119619007, 22.996574003957473],\n", + " [72.65529075704212, 22.996574003957473],\n", + " [72.65529075704212, 22.997166574435727]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58544230346283, 22.989353118858265],\n", + " [72.58544230346283, 22.987812341050095],\n", + " [72.58773827437957, 22.987812341050095],\n", + " [72.58773827437957, 22.989353118858265]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61881659486005, 23.010174527999478],\n", + " [72.61881659486005, 23.009621515605502],\n", + " [72.61955688454816, 23.009621515605502],\n", + " [72.61955688454816, 23.010174527999478]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61806557633588, 23.008890745751035],\n", + " [72.61806557633588, 23.008150096589624],\n", + " [72.6190419004173, 23.008150096589624],\n", + " [72.6190419004173, 23.008890745751035]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61948212543246, 23.041104493489044],\n", + " [72.61948212543246, 23.039919735997568],\n", + " [72.6207695857596, 23.039919735997568],\n", + " [72.6207695857596, 23.041104493489044]]], None, False),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"49\"\n", + " })]),\n", + " bu =\n", + "\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55821826634332, 23.050534019942667],\n", + " [72.55821826634332, 23.049497430284074],\n", + " [72.55952718434258, 23.049497430284074],\n", + " [72.55952718434258, 23.050534019942667]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55760672268792, 23.052212291042135],\n", + " [72.55760672268792, 23.05108686449766],\n", + " [72.55907657322808, 23.05108686449766],\n", + " [72.55907657322808, 23.052212291042135]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56838920292779, 23.0515311129416],\n", + " [72.56838920292779, 23.05024772454887],\n", + " [72.56966593441888, 23.05024772454887],\n", + " [72.56966593441888, 23.0515311129416]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5620699184887, 23.049053175130464],\n", + " [72.5620699184887, 23.048016574072317],\n", + " [72.56340029416009, 23.048016574072317],\n", + " [72.56340029416009, 23.049053175130464]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52369259789576, 23.06300015365502],\n", + " [72.52369259789576, 23.061440474438808],\n", + " [72.5262031455337, 23.061440474438808],\n", + " [72.5262031455337, 23.06300015365502]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53285502389063, 23.064342647870983],\n", + " [72.53285502389063, 23.06258555714626],\n", + " [72.53459309533228, 23.06258555714626],\n", + " [72.53459309533228, 23.064342647870983]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52989386513819, 23.057866964035462],\n", + " [72.52989386513819, 23.05597158299574],\n", + " [72.53223275139918, 23.05597158299574],\n", + " [72.53223275139918, 23.057866964035462]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54572776915181, 23.069331684613978],\n", + " [72.54572776915181, 23.06821627216258],\n", + " [72.54719761969197, 23.06821627216258],\n", + " [72.54719761969197, 23.069331684613978]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54864601256001, 23.07097023834584],\n", + " [72.54864601256001, 23.069558714334168],\n", + " [72.5504269993459, 23.069558714334168],\n", + " [72.5504269993459, 23.07097023834584]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55111364485371, 23.0716908008372],\n", + " [72.55111364485371, 23.070377992312263],\n", + " [72.55256203772176, 23.070377992312263],\n", + " [72.55256203772176, 23.0716908008372]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.50879440014218, 23.072620621975275],\n", + " [72.50879440014218, 23.071524978205787],\n", + " [72.51023206417416, 23.071524978205787],\n", + " [72.51023206417416, 23.072620621975275]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51449141208981, 23.071446012544282],\n", + " [72.51449141208981, 23.07000488107922],\n", + " [72.51615438167904, 23.07000488107922],\n", + " [72.51615438167904, 23.071446012544282]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49643476836059, 23.085681827252344],\n", + " [72.49643476836059, 23.08495640486992],\n", + " [72.49716969363067, 23.08495640486992],\n", + " [72.49716969363067, 23.085681827252344]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.47903499012024, 23.102978841643285],\n", + " [72.47903499012024, 23.101498574207657],\n", + " [72.48085889225037, 23.101498574207657],\n", + " [72.48085889225037, 23.102978841643285]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5935841682897, 23.027281425151706],\n", + " [72.5935841682897, 23.026639616972762],\n", + " [72.5942332628713, 23.026639616972762],\n", + " [72.5942332628713, 23.027281425151706]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59038697514394, 23.027562832389627],\n", + " [72.59038697514394, 23.026950647471846],\n", + " [72.59123991761068, 23.026950647471846],\n", + " [72.59123991761068, 23.027562832389627]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.60934988735686, 23.029828009881232],\n", + " [72.60934988735686, 23.028504919287915],\n", + " [72.61101285694609, 23.028504919287915],\n", + " [72.61101285694609, 23.029828009881232]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59274164913664, 23.030756140307705],\n", + " [72.59274164913664, 23.0301933385778],\n", + " [72.59362141369353, 23.0301933385778],\n", + " [72.59362141369353, 23.030756140307705]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58861710173579, 23.038054851303],\n", + " [72.58861710173579, 23.036445516746404],\n", + " [72.5900225792596, 23.036445516746404],\n", + " [72.5900225792596, 23.038054851303]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58457233054133, 23.03763030478965],\n", + " [72.58457233054133, 23.03652450294007],\n", + " [72.58590270621272, 23.03652450294007],\n", + " [72.58590270621272, 23.03763030478965]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59348799330684, 23.037047785303628],\n", + " [72.59348799330684, 23.035892612094273],\n", + " [72.594957843847, 23.035892612094273],\n", + " [72.594957843847, 23.037047785303628]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56456097369993, 23.08033152381615],\n", + " [72.56456097369993, 23.078999059324314],\n", + " [72.56592353587949, 23.078999059324314],\n", + " [72.56592353587949, 23.08033152381615]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.57296165233457, 23.08137774594047],\n", + " [72.57296165233457, 23.080084772128696],\n", + " [72.57410963779294, 23.080084772128696],\n", + " [72.57410963779294, 23.08137774594047]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56100972896421, 23.079423475373336],\n", + " [72.56100972896421, 23.078456199634683],\n", + " [72.56255468135679, 23.078456199634683],\n", + " [72.56255468135679, 23.079423475373336]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.59244395909863, 23.08886205587978],\n", + " [72.59244395909863, 23.088195867560096],\n", + " [72.59312524018841, 23.088195867560096],\n", + " [72.59312524018841, 23.08886205587978]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.58891417203503, 23.08902490141124],\n", + " [72.58891417203503, 23.087914587055902],\n", + " [72.59019090352612, 23.087914587055902],\n", + " [72.59019090352612, 23.08902490141124]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.63284367422881, 23.083747187676313],\n", + " [72.63284367422881, 23.082246968536918],\n", + " [72.63458174567046, 23.082246968536918],\n", + " [72.63458174567046, 23.083747187676313]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61123781615103, 23.03548171268339],\n", + " [72.61123781615103, 23.034583235045087],\n", + " [72.61229997092093, 23.034583235045087],\n", + " [72.61229997092093, 23.03548171268339]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.61444573813284, 23.03697257994195],\n", + " [72.61444573813284, 23.035649559490157],\n", + " [72.61594777518118, 23.035649559490157],\n", + " [72.61594777518118, 23.03697257994195]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.60209577668272, 23.04857847538297],\n", + " [72.60209577668272, 23.047275313883606],\n", + " [72.60400550950132, 23.047275313883606],\n", + " [72.60400550950132, 23.04857847538297]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.51149811879407, 23.047834507790366],\n", + " [72.51149811879407, 23.04608707415321],\n", + " [72.51345076695691, 23.04608707415321],\n", + " [72.51345076695691, 23.047834507790366]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.49712295504843, 23.062788240255994],\n", + " [72.49712295504843, 23.06162341641217],\n", + " [72.49815292331014, 23.06162341641217],\n", + " [72.49815292331014, 23.062788240255994]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54670277405151, 23.075491479960288],\n", + " [72.54670277405151, 23.072964630315727],\n", + " [72.5489343719519, 23.072964630315727],\n", + " [72.5489343719519, 23.075491479960288]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55421295929321, 23.07580733282782],\n", + " [72.55421295929321, 23.07367531157657],\n", + " [72.55751744079956, 23.07367531157657],\n", + " [72.55751744079956, 23.07580733282782]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53350630569824, 23.074001039232826],\n", + " [72.53350630569824, 23.072036790796002],\n", + " [72.53615632820495, 23.072036790796002],\n", + " [72.53615632820495, 23.074001039232826]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52723091860975, 23.03366481301143],\n", + " [72.52723091860975, 23.032420748682313],\n", + " [72.52894753237928, 23.032420748682313],\n", + " [72.52894753237928, 23.03366481301143]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52270334979261, 23.035698734716632],\n", + " [72.52270334979261, 23.034118992365073],\n", + " [72.52474182864393, 23.034118992365073],\n", + " [72.52474182864393, 23.035698734716632]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.54976147433484, 23.028668739099235],\n", + " [72.54976147433484, 23.026970426741123],\n", + " [72.55210036059583, 23.026970426741123],\n", + " [72.55210036059583, 23.028668739099235]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.55617731829847, 23.032835438068055],\n", + " [72.55617731829847, 23.03024854533837],\n", + " [72.55915993472303, 23.03024854533837],\n", + " [72.55915993472303, 23.032835438068055]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64766142687054, 22.9969522718421],\n", + " [72.64766142687054, 22.99607328997167],\n", + " [72.64864847978802, 22.99607328997167],\n", + " [72.64864847978802, 22.9969522718421]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.65313313326092, 22.99596465136559],\n", + " [72.65313313326092, 22.99518936422971],\n", + " [72.65385196527691, 22.99518936422971],\n", + " [72.65385196527691, 22.99596465136559]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.64301113330575, 23.006479138035033],\n", + " [72.64301113330575, 23.005649595875003],\n", + " [72.64406792365762, 23.005649595875003],\n", + " [72.64406792365762, 23.006479138035033]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.63917020999642, 23.00445958899076],\n", + " [72.63917020999642, 23.003802858706333],\n", + " [72.64008216106149, 23.003802858706333],\n", + " [72.64008216106149, 23.00445958899076]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.62459470431035, 23.015117807565044],\n", + " [72.62459470431035, 23.014110570204384],\n", + " [72.62584997812932, 23.014110570204384],\n", + " [72.62584997812932, 23.015117807565044]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.62965335051244, 23.015483176121137],\n", + " [72.62965335051244, 23.01433769301113],\n", + " [72.63109101454442, 23.01433769301113],\n", + " [72.63109101454442, 23.015483176121137]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.5929084117717, 23.018501870267272],\n", + " [72.5929084117717, 23.017763742536697],\n", + " [72.5937720830745, 23.017763742536697],\n", + " [72.5937720830745, 23.018501870267272]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.56404451603258, 23.017177110456608],\n", + " [72.56404451603258, 23.015725523443777],\n", + " [72.565922062343, 23.015725523443777],\n", + " [72.565922062343, 23.017177110456608]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52290852145079, 23.033167515925737],\n", + " [72.52290852145079, 23.031962941433807],\n", + " [72.52428181246641, 23.031962941433807],\n", + " [72.52428181246641, 23.033167515925737]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.52419598177794, 23.03062999809512],\n", + " [72.52419598177794, 23.02921805114397],\n", + " [72.52598769739988, 23.02921805114397],\n", + " [72.52598769739988, 23.03062999809512]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[72.53902594674939, 23.05493608122571],\n", + " [72.53902594674939, 23.053850165460744],\n", + " [72.54044215310925, 23.053850165460744],\n", + " [72.54044215310925, 23.05493608122571]]], None, False),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"49\"\n", + " })]),\n", + " L7 = ee.ImageCollection(\"LANDSAT/LE07/C02/T1_L2\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.2 Urban Environments\n", + "# Checkpoint: A12h\n", + "# Author: Michelle Stuhlmacher and Ran Goldblatt\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "Map.centerObject(bu, 13)\n", + "\n", + "# Surface reflectance function from example:\n", + "def maskL457sr(image):\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBand = image.select('ST_B6').multiply(0.00341802).add(\n", + " 149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " return image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBand, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + "\n", + "\n", + "# Map the function over one year of data.\n", + "collection = L7.filterDate('2020-01-01', '2021-01-01').map(\n", + " maskL457sr)\n", + "landsat7_2020 = collection.median()\n", + "\n", + "Map.addLayer(landsat7_2020, {\n", + " 'bands': ['SR_B3', 'SR_B2', 'SR_B1'],\n", + " 'min': 0,\n", + " 'max': 0.3\n", + "}, 'landsat 7, 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "lc = nbu.merge(bu)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'ST_B6',\n", + " 'SR_B7'\n", + "]\n", + "\n", + "training = landsat7_2020.select(bands).sampleRegions({\n", + " 'collection': lc,\n", + " 'properties': ['class'],\n", + " 'scale': 30\n", + "})\n", + "\n", + "# Create a random forest classifier with 20 trees.\n", + "classifier = ee.Classifier.smileRandomForest({\n", + " 'numberOfTrees': 20\n", + "}).train({ # Train the classifier.\n", + " # Use the examples we got when we sampled the pixels.\n", + " 'features': training,\n", + " # This is the class that we want to predict.\n", + " 'classProperty': 'class',\n", + " # The bands the classifier will use for training and classification.\n", + " 'inputProperties': bands\n", + "})\n", + "\n", + "# Apply the classifier on the 2020 image.\n", + "classified20 = landsat7_2020.select(bands).classify(classifier)\n", + "\n", + "Map.addLayer(classified20.mask(classified20), {\n", + " 'palette': ['#ff4218'],\n", + " 'opacity': 0.6\n", + "}, 'built-up, 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "landsat7_2010 = L7.filterDate('2010-01-01', '2010-12-31') \\\n", + " .map(maskL457sr).median()\n", + "\n", + "# Apply the classifier to the 2010 image.\n", + "classified10 = landsat7_2010.select(bands).classify(\n", + " classifier)\n", + "Map.addLayer(classified10.mask(classified10), {\n", + " 'palette': ['#f1ff21'],\n", + " 'opacity': 0.6\n", + "}, 'built-up, 2010')\n", + "\n", + "difference = classified20.subtract(classified10)\n", + "\n", + "Map.addLayer(difference.mask(difference), {\n", + " 'palette': ['#315dff'],\n", + " 'opacity': 0.6\n", + "}, 'difference')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12h Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12h Checkpoint.js new file mode 100644 index 0000000..7f095c4 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12h Checkpoint.js @@ -0,0 +1,1416 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var nbu = + /* color: #28d659 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.48565466309753, 23.013090225731943], + [72.48565466309753, 23.01218172380882], + [72.4868562927362, 23.01218172380882], + [72.4868562927362, 23.013090225731943]]], null, false), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48151333237854, 23.0108387097585], + [72.48151333237854, 23.009890691790975], + [72.48273641968933, 23.009890691790975], + [72.48273641968933, 23.0108387097585]]], null, false), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48265058900085, 23.00720460470793], + [72.48265058900085, 23.006236810228593], + [72.48398096467224, 23.006236810228593], + [72.48398096467224, 23.00720460470793]]], null, false), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50040144826141, 23.010868335212642], + [72.50040144826141, 23.010379514387374], + [72.50116319562164, 23.010379514387374], + [72.50116319562164, 23.010868335212642]]], null, false), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49854535962311, 23.009821565220278], + [72.49854535962311, 23.009426555565323], + [72.49904425049988, 23.009426555565323], + [72.49904425049988, 23.009821565220278]]], null, false), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49695212746826, 23.00991044223325], + [72.49695212746826, 23.00942161793733], + [72.49754757786957, 23.00942161793733], + [72.49754757786957, 23.00991044223325]]], null, false), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50098740533024, 23.012437718666618], + [72.50098740533024, 23.01211677963381], + [72.501486296207, 23.01211677963381], + [72.501486296207, 23.012437718666618]]], null, false), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49612187817722, 23.012250092863223], + [72.49612187817722, 23.011953841063395], + [72.49648129418522, 23.011953841063395], + [72.49648129418522, 23.012250092863223]]], null, false), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49531185105472, 23.011835340161273], + [72.49531185105472, 23.01150946214379], + [72.49571954682499, 23.01150946214379], + [72.49571954682499, 23.011835340161273]]], null, false), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50769643206644, 23.01452064371778], + [72.50769643206644, 23.014145397644366], + [72.50847963709879, 23.014145397644366], + [72.50847963709879, 23.01452064371778]]], null, false), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5057974280839, 23.013256652780115], + [72.5057974280839, 23.012486402494627], + [72.50663427729654, 23.012486402494627], + [72.50663427729654, 23.013256652780115]]], null, false), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5091126384263, 23.013799775337404], + [72.5091126384263, 23.013266527755206], + [72.50970272440958, 23.013266527755206], + [72.50970272440958, 23.013799775337404]]], null, false), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50782517809915, 23.01674247407806], + [72.50782517809915, 23.01673259935746], + [72.50811485667276, 23.01673259935746], + [72.50811485667276, 23.01674247407806]]], null, false), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50090507884073, 23.016702975191237], + [72.50090507884073, 23.01607099142841], + [72.50158099551248, 23.01607099142841], + [72.50158099551248, 23.016702975191237]]], null, false), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49740747828531, 23.016051241888096], + [72.49740747828531, 23.015715499260445], + [72.49777225871134, 23.015715499260445], + [72.49777225871134, 23.016051241888096]]], null, false), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49698905367899, 23.013394902365846], + [72.49698905367899, 23.012960403190835], + [72.49771861453104, 23.012960403190835], + [72.49771861453104, 23.013394902365846]]], null, false), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.4941459121232, 23.01318752793418], + [72.4941459121232, 23.01289127819304], + [72.49488620181131, 23.01289127819304], + [72.49488620181131, 23.01318752793418]]], null, false), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51445546856034, 23.025081565200995], + [72.51445546856034, 23.024607607106788], + [72.51517430057633, 23.024607607106788], + [72.51517430057633, 23.025081565200995]]], null, false), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5175990175258, 23.028952160599992], + [72.5175990175258, 23.028488089974577], + [72.51818910350907, 23.028488089974577], + [72.51818910350907, 23.028952160599992]]], null, false), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51869335880387, 23.028932412946357], + [72.51869335880387, 23.02818199996423], + [72.5195623945247, 23.02818199996423], + [72.5195623945247, 23.028932412946357]]], null, false), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52084471850465, 23.026596214980795], + [72.52084471850465, 23.02604326992137], + [72.52137043147157, 23.02604326992137], + [72.52137043147157, 23.026596214980795]]], null, false), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53553214246043, 23.03997960346422], + [72.53553214246043, 23.03879483608005], + [72.53699126416453, 23.03879483608005], + [72.53699126416453, 23.03997960346422]]], null, false), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52233567410715, 23.044086716392354], + [72.52233567410715, 23.0435535886138], + [72.5232798116804, 23.0435535886138], + [72.5232798116804, 23.044086716392354]]], null, false), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52499642544993, 23.043198168922416], + [72.52499642544993, 23.04248732672617], + [72.52587619000681, 23.04248732672617], + [72.52587619000681, 23.043198168922416]]], null, false), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52400937253245, 23.04181597231865], + [72.52400937253245, 23.040986647548742], + [72.52491059476145, 23.040986647548742], + [72.52491059476145, 23.04181597231865]]], null, false), + { + "class": 0, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57306172713966, 23.03598378282248], + [72.57306172713966, 23.034562018547053], + [72.57426335677833, 23.034562018547053], + [72.57426335677833, 23.03598378282248]]], null, false), + { + "class": 0, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57566066969198, 23.052508342763684], + [72.57566066969198, 23.050928797545748], + [72.57720562208456, 23.050928797545748], + [72.57720562208456, 23.052508342763684]]], null, false), + { + "class": 0, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5743302940206, 23.02486362694267], + [72.5743302940206, 23.023323254554423], + [72.57561775434775, 23.023323254554423], + [72.57561775434775, 23.02486362694267]]], null, false), + { + "class": 0, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68683489184394, 23.01212531748654], + [72.68683489184394, 23.010910679849328], + [72.68822964053169, 23.010910679849328], + [72.68822964053169, 23.01212531748654]]], null, false), + { + "class": 0, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.69045050959602, 23.01332019424718], + [72.69045050959602, 23.012174692768948], + [72.69152339320198, 23.012174692768948], + [72.69152339320198, 23.01332019424718]]], null, false), + { + "class": 0, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6833158336164, 23.01301406980455], + [72.6833158336164, 23.012233943083956], + [72.68446381907478, 23.012233943083956], + [72.68446381907478, 23.01301406980455]]], null, false), + { + "class": 0, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67707165102973, 23.01268819463449], + [72.67707165102973, 23.0117796900038], + [72.67849858622566, 23.0117796900038], + [72.67849858622566, 23.01268819463449]]], null, false), + { + "class": 0, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67816599230781, 23.014544685070533], + [72.67816599230781, 23.01347819368771], + [72.67923887591377, 23.01347819368771], + [72.67923887591377, 23.014544685070533]]], null, false), + { + "class": 0, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6903217635633, 23.016075282967993], + [72.6903217635633, 23.015413671814553], + [72.69105132441535, 23.015413671814553], + [72.69105132441535, 23.016075282967993]]], null, false), + { + "class": 0, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68663104395881, 23.015630917625792], + [72.68663104395881, 23.014890305468796], + [72.68773611407295, 23.014890305468796], + [72.68773611407295, 23.015630917625792]]], null, false), + { + "class": 0, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71553840093799, 23.017830754660782], + [72.71553840093799, 23.016606293669707], + [72.71675075941272, 23.016606293669707], + [72.71675075941272, 23.017830754660782]]], null, false), + { + "class": 0, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71506633215137, 23.01600393378011], + [72.71506633215137, 23.01512507600062], + [72.7161714022655, 23.01512507600062], + [72.7161714022655, 23.01600393378011]]], null, false), + { + "class": 0, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71916474752612, 23.017870253217335], + [72.71916474752612, 23.01693215937388], + [72.72010888509936, 23.01693215937388], + [72.72010888509936, 23.017870253217335]]], null, false), + { + "class": 0, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.70868267469592, 23.018521977730355], + [72.70868267469592, 23.01767276031886], + [72.70984138899036, 23.01767276031886], + [72.70984138899036, 23.018521977730355]]], null, false), + { + "class": 0, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.7059039061565, 23.015302822979788], + [72.7059039061565, 23.014473335073], + [72.70708407812305, 23.014473335073], + [72.70708407812305, 23.015302822979788]]], null, false), + { + "class": 0, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64443317494984, 22.995586380713714], + [72.64443317494984, 22.994895040144375], + [72.6453451260149, 22.994895040144375], + [72.6453451260149, 22.995586380713714]]], null, false), + { + "class": 0, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6488749130785, 22.99306790874182], + [72.6488749130785, 22.992317296243893], + [72.64966884694691, 22.992317296243893], + [72.64966884694691, 22.99306790874182]]], null, false), + { + "class": 0, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64429370008106, 22.992188901582924], + [72.64429370008106, 22.991566679573463], + [72.6448945149004, 22.991566679573463], + [72.6448945149004, 22.992188901582924]]], null, false), + { + "class": 0, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65110651097889, 22.996988803565362], + [72.65110651097889, 22.99634685125117], + [72.65186825833912, 22.99634685125117], + [72.65186825833912, 22.996988803565362]]], null, false), + { + "class": 0, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.650044356209, 22.99654437536528], + [72.650044356209, 22.995872792198217], + [72.65091339192982, 22.995872792198217], + [72.65091339192982, 22.99654437536528]]], null, false), + { + "class": 0, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65456119619007, 22.997166574435727], + [72.65456119619007, 22.996574003957473], + [72.65529075704212, 22.996574003957473], + [72.65529075704212, 22.997166574435727]]], null, false), + { + "class": 0, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58544230346283, 22.989353118858265], + [72.58544230346283, 22.987812341050095], + [72.58773827437957, 22.987812341050095], + [72.58773827437957, 22.989353118858265]]], null, false), + { + "class": 0, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61881659486005, 23.010174527999478], + [72.61881659486005, 23.009621515605502], + [72.61955688454816, 23.009621515605502], + [72.61955688454816, 23.010174527999478]]], null, false), + { + "class": 0, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61806557633588, 23.008890745751035], + [72.61806557633588, 23.008150096589624], + [72.6190419004173, 23.008150096589624], + [72.6190419004173, 23.008890745751035]]], null, false), + { + "class": 0, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61948212543246, 23.041104493489044], + [72.61948212543246, 23.039919735997568], + [72.6207695857596, 23.039919735997568], + [72.6207695857596, 23.041104493489044]]], null, false), + { + "class": 0, + "system:index": "49" + })]), + bu = + /* color: #ff2b10 */ + /* displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.55821826634332, 23.050534019942667], + [72.55821826634332, 23.049497430284074], + [72.55952718434258, 23.049497430284074], + [72.55952718434258, 23.050534019942667]]], null, false), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55760672268792, 23.052212291042135], + [72.55760672268792, 23.05108686449766], + [72.55907657322808, 23.05108686449766], + [72.55907657322808, 23.052212291042135]]], null, false), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56838920292779, 23.0515311129416], + [72.56838920292779, 23.05024772454887], + [72.56966593441888, 23.05024772454887], + [72.56966593441888, 23.0515311129416]]], null, false), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5620699184887, 23.049053175130464], + [72.5620699184887, 23.048016574072317], + [72.56340029416009, 23.048016574072317], + [72.56340029416009, 23.049053175130464]]], null, false), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52369259789576, 23.06300015365502], + [72.52369259789576, 23.061440474438808], + [72.5262031455337, 23.061440474438808], + [72.5262031455337, 23.06300015365502]]], null, false), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53285502389063, 23.064342647870983], + [72.53285502389063, 23.06258555714626], + [72.53459309533228, 23.06258555714626], + [72.53459309533228, 23.064342647870983]]], null, false), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52989386513819, 23.057866964035462], + [72.52989386513819, 23.05597158299574], + [72.53223275139918, 23.05597158299574], + [72.53223275139918, 23.057866964035462]]], null, false), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54572776915181, 23.069331684613978], + [72.54572776915181, 23.06821627216258], + [72.54719761969197, 23.06821627216258], + [72.54719761969197, 23.069331684613978]]], null, false), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54864601256001, 23.07097023834584], + [72.54864601256001, 23.069558714334168], + [72.5504269993459, 23.069558714334168], + [72.5504269993459, 23.07097023834584]]], null, false), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55111364485371, 23.0716908008372], + [72.55111364485371, 23.070377992312263], + [72.55256203772176, 23.070377992312263], + [72.55256203772176, 23.0716908008372]]], null, false), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50879440014218, 23.072620621975275], + [72.50879440014218, 23.071524978205787], + [72.51023206417416, 23.071524978205787], + [72.51023206417416, 23.072620621975275]]], null, false), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51449141208981, 23.071446012544282], + [72.51449141208981, 23.07000488107922], + [72.51615438167904, 23.07000488107922], + [72.51615438167904, 23.071446012544282]]], null, false), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49643476836059, 23.085681827252344], + [72.49643476836059, 23.08495640486992], + [72.49716969363067, 23.08495640486992], + [72.49716969363067, 23.085681827252344]]], null, false), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.47903499012024, 23.102978841643285], + [72.47903499012024, 23.101498574207657], + [72.48085889225037, 23.101498574207657], + [72.48085889225037, 23.102978841643285]]], null, false), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5935841682897, 23.027281425151706], + [72.5935841682897, 23.026639616972762], + [72.5942332628713, 23.026639616972762], + [72.5942332628713, 23.027281425151706]]], null, false), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59038697514394, 23.027562832389627], + [72.59038697514394, 23.026950647471846], + [72.59123991761068, 23.026950647471846], + [72.59123991761068, 23.027562832389627]]], null, false), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60934988735686, 23.029828009881232], + [72.60934988735686, 23.028504919287915], + [72.61101285694609, 23.028504919287915], + [72.61101285694609, 23.029828009881232]]], null, false), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59274164913664, 23.030756140307705], + [72.59274164913664, 23.0301933385778], + [72.59362141369353, 23.0301933385778], + [72.59362141369353, 23.030756140307705]]], null, false), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58861710173579, 23.038054851303], + [72.58861710173579, 23.036445516746404], + [72.5900225792596, 23.036445516746404], + [72.5900225792596, 23.038054851303]]], null, false), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58457233054133, 23.03763030478965], + [72.58457233054133, 23.03652450294007], + [72.58590270621272, 23.03652450294007], + [72.58590270621272, 23.03763030478965]]], null, false), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59348799330684, 23.037047785303628], + [72.59348799330684, 23.035892612094273], + [72.594957843847, 23.035892612094273], + [72.594957843847, 23.037047785303628]]], null, false), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56456097369993, 23.08033152381615], + [72.56456097369993, 23.078999059324314], + [72.56592353587949, 23.078999059324314], + [72.56592353587949, 23.08033152381615]]], null, false), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57296165233457, 23.08137774594047], + [72.57296165233457, 23.080084772128696], + [72.57410963779294, 23.080084772128696], + [72.57410963779294, 23.08137774594047]]], null, false), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56100972896421, 23.079423475373336], + [72.56100972896421, 23.078456199634683], + [72.56255468135679, 23.078456199634683], + [72.56255468135679, 23.079423475373336]]], null, false), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59244395909863, 23.08886205587978], + [72.59244395909863, 23.088195867560096], + [72.59312524018841, 23.088195867560096], + [72.59312524018841, 23.08886205587978]]], null, false), + { + "class": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58891417203503, 23.08902490141124], + [72.58891417203503, 23.087914587055902], + [72.59019090352612, 23.087914587055902], + [72.59019090352612, 23.08902490141124]]], null, false), + { + "class": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63284367422881, 23.083747187676313], + [72.63284367422881, 23.082246968536918], + [72.63458174567046, 23.082246968536918], + [72.63458174567046, 23.083747187676313]]], null, false), + { + "class": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61123781615103, 23.03548171268339], + [72.61123781615103, 23.034583235045087], + [72.61229997092093, 23.034583235045087], + [72.61229997092093, 23.03548171268339]]], null, false), + { + "class": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61444573813284, 23.03697257994195], + [72.61444573813284, 23.035649559490157], + [72.61594777518118, 23.035649559490157], + [72.61594777518118, 23.03697257994195]]], null, false), + { + "class": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60209577668272, 23.04857847538297], + [72.60209577668272, 23.047275313883606], + [72.60400550950132, 23.047275313883606], + [72.60400550950132, 23.04857847538297]]], null, false), + { + "class": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51149811879407, 23.047834507790366], + [72.51149811879407, 23.04608707415321], + [72.51345076695691, 23.04608707415321], + [72.51345076695691, 23.047834507790366]]], null, false), + { + "class": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49712295504843, 23.062788240255994], + [72.49712295504843, 23.06162341641217], + [72.49815292331014, 23.06162341641217], + [72.49815292331014, 23.062788240255994]]], null, false), + { + "class": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54670277405151, 23.075491479960288], + [72.54670277405151, 23.072964630315727], + [72.5489343719519, 23.072964630315727], + [72.5489343719519, 23.075491479960288]]], null, false), + { + "class": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55421295929321, 23.07580733282782], + [72.55421295929321, 23.07367531157657], + [72.55751744079956, 23.07367531157657], + [72.55751744079956, 23.07580733282782]]], null, false), + { + "class": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53350630569824, 23.074001039232826], + [72.53350630569824, 23.072036790796002], + [72.53615632820495, 23.072036790796002], + [72.53615632820495, 23.074001039232826]]], null, false), + { + "class": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52723091860975, 23.03366481301143], + [72.52723091860975, 23.032420748682313], + [72.52894753237928, 23.032420748682313], + [72.52894753237928, 23.03366481301143]]], null, false), + { + "class": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52270334979261, 23.035698734716632], + [72.52270334979261, 23.034118992365073], + [72.52474182864393, 23.034118992365073], + [72.52474182864393, 23.035698734716632]]], null, false), + { + "class": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54976147433484, 23.028668739099235], + [72.54976147433484, 23.026970426741123], + [72.55210036059583, 23.026970426741123], + [72.55210036059583, 23.028668739099235]]], null, false), + { + "class": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55617731829847, 23.032835438068055], + [72.55617731829847, 23.03024854533837], + [72.55915993472303, 23.03024854533837], + [72.55915993472303, 23.032835438068055]]], null, false), + { + "class": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64766142687054, 22.9969522718421], + [72.64766142687054, 22.99607328997167], + [72.64864847978802, 22.99607328997167], + [72.64864847978802, 22.9969522718421]]], null, false), + { + "class": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65313313326092, 22.99596465136559], + [72.65313313326092, 22.99518936422971], + [72.65385196527691, 22.99518936422971], + [72.65385196527691, 22.99596465136559]]], null, false), + { + "class": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64301113330575, 23.006479138035033], + [72.64301113330575, 23.005649595875003], + [72.64406792365762, 23.005649595875003], + [72.64406792365762, 23.006479138035033]]], null, false), + { + "class": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63917020999642, 23.00445958899076], + [72.63917020999642, 23.003802858706333], + [72.64008216106149, 23.003802858706333], + [72.64008216106149, 23.00445958899076]]], null, false), + { + "class": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62459470431035, 23.015117807565044], + [72.62459470431035, 23.014110570204384], + [72.62584997812932, 23.014110570204384], + [72.62584997812932, 23.015117807565044]]], null, false), + { + "class": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62965335051244, 23.015483176121137], + [72.62965335051244, 23.01433769301113], + [72.63109101454442, 23.01433769301113], + [72.63109101454442, 23.015483176121137]]], null, false), + { + "class": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5929084117717, 23.018501870267272], + [72.5929084117717, 23.017763742536697], + [72.5937720830745, 23.017763742536697], + [72.5937720830745, 23.018501870267272]]], null, false), + { + "class": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56404451603258, 23.017177110456608], + [72.56404451603258, 23.015725523443777], + [72.565922062343, 23.015725523443777], + [72.565922062343, 23.017177110456608]]], null, false), + { + "class": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52290852145079, 23.033167515925737], + [72.52290852145079, 23.031962941433807], + [72.52428181246641, 23.031962941433807], + [72.52428181246641, 23.033167515925737]]], null, false), + { + "class": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52419598177794, 23.03062999809512], + [72.52419598177794, 23.02921805114397], + [72.52598769739988, 23.02921805114397], + [72.52598769739988, 23.03062999809512]]], null, false), + { + "class": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53902594674939, 23.05493608122571], + [72.53902594674939, 23.053850165460744], + [72.54044215310925, 23.053850165460744], + [72.54044215310925, 23.05493608122571]]], null, false), + { + "class": 1, + "system:index": "49" + })]), + L7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_L2"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.2 Urban Environments +// Checkpoint: A12h +// Author: Michelle Stuhlmacher and Ran Goldblatt +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Map.centerObject(bu, 13); + +// Surface reflectance function from example: +function maskL457sr(image) { + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0); + + // Replace the original bands with the scaled ones and apply the masks. + return image.addBands(opticalBands, null, true) + .addBands(thermalBand, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); +} + +// Map the function over one year of data. +var collection = L7.filterDate('2020-01-01', '2021-01-01').map( + maskL457sr); +var landsat7_2020 = collection.median(); + +Map.addLayer(landsat7_2020, { + bands: ['SR_B3', 'SR_B2', 'SR_B1'], + min: 0, + max: 0.3 +}, 'landsat 7, 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var lc = nbu.merge(bu); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'ST_B6', + 'SR_B7' +]; + +var training = landsat7_2020.select(bands).sampleRegions({ + collection: lc, + properties: ['class'], + scale: 30 +}); + +// Create a random forest classifier with 20 trees. +var classifier = ee.Classifier.smileRandomForest({ + numberOfTrees: 20 +}).train({ // Train the classifier. + // Use the examples we got when we sampled the pixels. + features: training, + // This is the class that we want to predict. + classProperty: 'class', + // The bands the classifier will use for training and classification. + inputProperties: bands +}); + +// Apply the classifier on the 2020 image. +var classified20 = landsat7_2020.select(bands).classify(classifier); + +Map.addLayer(classified20.mask(classified20), { + palette: ['#ff4218'], + opacity: 0.6 +}, 'built-up, 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var landsat7_2010 = L7.filterDate('2010-01-01', '2010-12-31') + .map(maskL457sr).median(); + +// Apply the classifier to the 2010 image. +var classified10 = landsat7_2010.select(bands).classify( + classifier); +Map.addLayer(classified10.mask(classified10), { + palette: ['#f1ff21'], + opacity: 0.6 +}, 'built-up, 2010'); + +var difference = classified20.subtract(classified10); + +Map.addLayer(difference.mask(difference), { + palette: ['#315dff'], + opacity: 0.6 +}, 'difference'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12h Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12h Checkpoint.py new file mode 100644 index 0000000..aefaf65 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.2 Urban Environments/A12h Checkpoint.py @@ -0,0 +1,1422 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +nbu = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.48565466309753, 23.013090225731943], + [72.48565466309753, 23.01218172380882], + [72.4868562927362, 23.01218172380882], + [72.4868562927362, 23.013090225731943]]], None, False), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48151333237854, 23.0108387097585], + [72.48151333237854, 23.009890691790975], + [72.48273641968933, 23.009890691790975], + [72.48273641968933, 23.0108387097585]]], None, False), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.48265058900085, 23.00720460470793], + [72.48265058900085, 23.006236810228593], + [72.48398096467224, 23.006236810228593], + [72.48398096467224, 23.00720460470793]]], None, False), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50040144826141, 23.010868335212642], + [72.50040144826141, 23.010379514387374], + [72.50116319562164, 23.010379514387374], + [72.50116319562164, 23.010868335212642]]], None, False), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49854535962311, 23.009821565220278], + [72.49854535962311, 23.009426555565323], + [72.49904425049988, 23.009426555565323], + [72.49904425049988, 23.009821565220278]]], None, False), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49695212746826, 23.00991044223325], + [72.49695212746826, 23.00942161793733], + [72.49754757786957, 23.00942161793733], + [72.49754757786957, 23.00991044223325]]], None, False), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50098740533024, 23.012437718666618], + [72.50098740533024, 23.01211677963381], + [72.501486296207, 23.01211677963381], + [72.501486296207, 23.012437718666618]]], None, False), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49612187817722, 23.012250092863223], + [72.49612187817722, 23.011953841063395], + [72.49648129418522, 23.011953841063395], + [72.49648129418522, 23.012250092863223]]], None, False), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49531185105472, 23.011835340161273], + [72.49531185105472, 23.01150946214379], + [72.49571954682499, 23.01150946214379], + [72.49571954682499, 23.011835340161273]]], None, False), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50769643206644, 23.01452064371778], + [72.50769643206644, 23.014145397644366], + [72.50847963709879, 23.014145397644366], + [72.50847963709879, 23.01452064371778]]], None, False), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5057974280839, 23.013256652780115], + [72.5057974280839, 23.012486402494627], + [72.50663427729654, 23.012486402494627], + [72.50663427729654, 23.013256652780115]]], None, False), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5091126384263, 23.013799775337404], + [72.5091126384263, 23.013266527755206], + [72.50970272440958, 23.013266527755206], + [72.50970272440958, 23.013799775337404]]], None, False), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50782517809915, 23.01674247407806], + [72.50782517809915, 23.01673259935746], + [72.50811485667276, 23.01673259935746], + [72.50811485667276, 23.01674247407806]]], None, False), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50090507884073, 23.016702975191237], + [72.50090507884073, 23.01607099142841], + [72.50158099551248, 23.01607099142841], + [72.50158099551248, 23.016702975191237]]], None, False), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49740747828531, 23.016051241888096], + [72.49740747828531, 23.015715499260445], + [72.49777225871134, 23.015715499260445], + [72.49777225871134, 23.016051241888096]]], None, False), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49698905367899, 23.013394902365846], + [72.49698905367899, 23.012960403190835], + [72.49771861453104, 23.012960403190835], + [72.49771861453104, 23.013394902365846]]], None, False), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.4941459121232, 23.01318752793418], + [72.4941459121232, 23.01289127819304], + [72.49488620181131, 23.01289127819304], + [72.49488620181131, 23.01318752793418]]], None, False), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51445546856034, 23.025081565200995], + [72.51445546856034, 23.024607607106788], + [72.51517430057633, 23.024607607106788], + [72.51517430057633, 23.025081565200995]]], None, False), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5175990175258, 23.028952160599992], + [72.5175990175258, 23.028488089974577], + [72.51818910350907, 23.028488089974577], + [72.51818910350907, 23.028952160599992]]], None, False), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51869335880387, 23.028932412946357], + [72.51869335880387, 23.02818199996423], + [72.5195623945247, 23.02818199996423], + [72.5195623945247, 23.028932412946357]]], None, False), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52084471850465, 23.026596214980795], + [72.52084471850465, 23.02604326992137], + [72.52137043147157, 23.02604326992137], + [72.52137043147157, 23.026596214980795]]], None, False), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53553214246043, 23.03997960346422], + [72.53553214246043, 23.03879483608005], + [72.53699126416453, 23.03879483608005], + [72.53699126416453, 23.03997960346422]]], None, False), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52233567410715, 23.044086716392354], + [72.52233567410715, 23.0435535886138], + [72.5232798116804, 23.0435535886138], + [72.5232798116804, 23.044086716392354]]], None, False), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52499642544993, 23.043198168922416], + [72.52499642544993, 23.04248732672617], + [72.52587619000681, 23.04248732672617], + [72.52587619000681, 23.043198168922416]]], None, False), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52400937253245, 23.04181597231865], + [72.52400937253245, 23.040986647548742], + [72.52491059476145, 23.040986647548742], + [72.52491059476145, 23.04181597231865]]], None, False), + { + "class": 0, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57306172713966, 23.03598378282248], + [72.57306172713966, 23.034562018547053], + [72.57426335677833, 23.034562018547053], + [72.57426335677833, 23.03598378282248]]], None, False), + { + "class": 0, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57566066969198, 23.052508342763684], + [72.57566066969198, 23.050928797545748], + [72.57720562208456, 23.050928797545748], + [72.57720562208456, 23.052508342763684]]], None, False), + { + "class": 0, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5743302940206, 23.02486362694267], + [72.5743302940206, 23.023323254554423], + [72.57561775434775, 23.023323254554423], + [72.57561775434775, 23.02486362694267]]], None, False), + { + "class": 0, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68683489184394, 23.01212531748654], + [72.68683489184394, 23.010910679849328], + [72.68822964053169, 23.010910679849328], + [72.68822964053169, 23.01212531748654]]], None, False), + { + "class": 0, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.69045050959602, 23.01332019424718], + [72.69045050959602, 23.012174692768948], + [72.69152339320198, 23.012174692768948], + [72.69152339320198, 23.01332019424718]]], None, False), + { + "class": 0, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6833158336164, 23.01301406980455], + [72.6833158336164, 23.012233943083956], + [72.68446381907478, 23.012233943083956], + [72.68446381907478, 23.01301406980455]]], None, False), + { + "class": 0, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67707165102973, 23.01268819463449], + [72.67707165102973, 23.0117796900038], + [72.67849858622566, 23.0117796900038], + [72.67849858622566, 23.01268819463449]]], None, False), + { + "class": 0, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.67816599230781, 23.014544685070533], + [72.67816599230781, 23.01347819368771], + [72.67923887591377, 23.01347819368771], + [72.67923887591377, 23.014544685070533]]], None, False), + { + "class": 0, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6903217635633, 23.016075282967993], + [72.6903217635633, 23.015413671814553], + [72.69105132441535, 23.015413671814553], + [72.69105132441535, 23.016075282967993]]], None, False), + { + "class": 0, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.68663104395881, 23.015630917625792], + [72.68663104395881, 23.014890305468796], + [72.68773611407295, 23.014890305468796], + [72.68773611407295, 23.015630917625792]]], None, False), + { + "class": 0, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71553840093799, 23.017830754660782], + [72.71553840093799, 23.016606293669707], + [72.71675075941272, 23.016606293669707], + [72.71675075941272, 23.017830754660782]]], None, False), + { + "class": 0, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71506633215137, 23.01600393378011], + [72.71506633215137, 23.01512507600062], + [72.7161714022655, 23.01512507600062], + [72.7161714022655, 23.01600393378011]]], None, False), + { + "class": 0, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.71916474752612, 23.017870253217335], + [72.71916474752612, 23.01693215937388], + [72.72010888509936, 23.01693215937388], + [72.72010888509936, 23.017870253217335]]], None, False), + { + "class": 0, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.70868267469592, 23.018521977730355], + [72.70868267469592, 23.01767276031886], + [72.70984138899036, 23.01767276031886], + [72.70984138899036, 23.018521977730355]]], None, False), + { + "class": 0, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.7059039061565, 23.015302822979788], + [72.7059039061565, 23.014473335073], + [72.70708407812305, 23.014473335073], + [72.70708407812305, 23.015302822979788]]], None, False), + { + "class": 0, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64443317494984, 22.995586380713714], + [72.64443317494984, 22.994895040144375], + [72.6453451260149, 22.994895040144375], + [72.6453451260149, 22.995586380713714]]], None, False), + { + "class": 0, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.6488749130785, 22.99306790874182], + [72.6488749130785, 22.992317296243893], + [72.64966884694691, 22.992317296243893], + [72.64966884694691, 22.99306790874182]]], None, False), + { + "class": 0, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64429370008106, 22.992188901582924], + [72.64429370008106, 22.991566679573463], + [72.6448945149004, 22.991566679573463], + [72.6448945149004, 22.992188901582924]]], None, False), + { + "class": 0, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65110651097889, 22.996988803565362], + [72.65110651097889, 22.99634685125117], + [72.65186825833912, 22.99634685125117], + [72.65186825833912, 22.996988803565362]]], None, False), + { + "class": 0, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.650044356209, 22.99654437536528], + [72.650044356209, 22.995872792198217], + [72.65091339192982, 22.995872792198217], + [72.65091339192982, 22.99654437536528]]], None, False), + { + "class": 0, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65456119619007, 22.997166574435727], + [72.65456119619007, 22.996574003957473], + [72.65529075704212, 22.996574003957473], + [72.65529075704212, 22.997166574435727]]], None, False), + { + "class": 0, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58544230346283, 22.989353118858265], + [72.58544230346283, 22.987812341050095], + [72.58773827437957, 22.987812341050095], + [72.58773827437957, 22.989353118858265]]], None, False), + { + "class": 0, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61881659486005, 23.010174527999478], + [72.61881659486005, 23.009621515605502], + [72.61955688454816, 23.009621515605502], + [72.61955688454816, 23.010174527999478]]], None, False), + { + "class": 0, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61806557633588, 23.008890745751035], + [72.61806557633588, 23.008150096589624], + [72.6190419004173, 23.008150096589624], + [72.6190419004173, 23.008890745751035]]], None, False), + { + "class": 0, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61948212543246, 23.041104493489044], + [72.61948212543246, 23.039919735997568], + [72.6207695857596, 23.039919735997568], + [72.6207695857596, 23.041104493489044]]], None, False), + { + "class": 0, + "system:index": "49" + })]), + bu = + + # displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + }, + { + "type": "rectangle" + } + ] # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[72.55821826634332, 23.050534019942667], + [72.55821826634332, 23.049497430284074], + [72.55952718434258, 23.049497430284074], + [72.55952718434258, 23.050534019942667]]], None, False), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55760672268792, 23.052212291042135], + [72.55760672268792, 23.05108686449766], + [72.55907657322808, 23.05108686449766], + [72.55907657322808, 23.052212291042135]]], None, False), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56838920292779, 23.0515311129416], + [72.56838920292779, 23.05024772454887], + [72.56966593441888, 23.05024772454887], + [72.56966593441888, 23.0515311129416]]], None, False), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5620699184887, 23.049053175130464], + [72.5620699184887, 23.048016574072317], + [72.56340029416009, 23.048016574072317], + [72.56340029416009, 23.049053175130464]]], None, False), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52369259789576, 23.06300015365502], + [72.52369259789576, 23.061440474438808], + [72.5262031455337, 23.061440474438808], + [72.5262031455337, 23.06300015365502]]], None, False), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53285502389063, 23.064342647870983], + [72.53285502389063, 23.06258555714626], + [72.53459309533228, 23.06258555714626], + [72.53459309533228, 23.064342647870983]]], None, False), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52989386513819, 23.057866964035462], + [72.52989386513819, 23.05597158299574], + [72.53223275139918, 23.05597158299574], + [72.53223275139918, 23.057866964035462]]], None, False), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54572776915181, 23.069331684613978], + [72.54572776915181, 23.06821627216258], + [72.54719761969197, 23.06821627216258], + [72.54719761969197, 23.069331684613978]]], None, False), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54864601256001, 23.07097023834584], + [72.54864601256001, 23.069558714334168], + [72.5504269993459, 23.069558714334168], + [72.5504269993459, 23.07097023834584]]], None, False), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55111364485371, 23.0716908008372], + [72.55111364485371, 23.070377992312263], + [72.55256203772176, 23.070377992312263], + [72.55256203772176, 23.0716908008372]]], None, False), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.50879440014218, 23.072620621975275], + [72.50879440014218, 23.071524978205787], + [72.51023206417416, 23.071524978205787], + [72.51023206417416, 23.072620621975275]]], None, False), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51449141208981, 23.071446012544282], + [72.51449141208981, 23.07000488107922], + [72.51615438167904, 23.07000488107922], + [72.51615438167904, 23.071446012544282]]], None, False), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49643476836059, 23.085681827252344], + [72.49643476836059, 23.08495640486992], + [72.49716969363067, 23.08495640486992], + [72.49716969363067, 23.085681827252344]]], None, False), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.47903499012024, 23.102978841643285], + [72.47903499012024, 23.101498574207657], + [72.48085889225037, 23.101498574207657], + [72.48085889225037, 23.102978841643285]]], None, False), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5935841682897, 23.027281425151706], + [72.5935841682897, 23.026639616972762], + [72.5942332628713, 23.026639616972762], + [72.5942332628713, 23.027281425151706]]], None, False), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59038697514394, 23.027562832389627], + [72.59038697514394, 23.026950647471846], + [72.59123991761068, 23.026950647471846], + [72.59123991761068, 23.027562832389627]]], None, False), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60934988735686, 23.029828009881232], + [72.60934988735686, 23.028504919287915], + [72.61101285694609, 23.028504919287915], + [72.61101285694609, 23.029828009881232]]], None, False), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59274164913664, 23.030756140307705], + [72.59274164913664, 23.0301933385778], + [72.59362141369353, 23.0301933385778], + [72.59362141369353, 23.030756140307705]]], None, False), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58861710173579, 23.038054851303], + [72.58861710173579, 23.036445516746404], + [72.5900225792596, 23.036445516746404], + [72.5900225792596, 23.038054851303]]], None, False), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58457233054133, 23.03763030478965], + [72.58457233054133, 23.03652450294007], + [72.58590270621272, 23.03652450294007], + [72.58590270621272, 23.03763030478965]]], None, False), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59348799330684, 23.037047785303628], + [72.59348799330684, 23.035892612094273], + [72.594957843847, 23.035892612094273], + [72.594957843847, 23.037047785303628]]], None, False), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56456097369993, 23.08033152381615], + [72.56456097369993, 23.078999059324314], + [72.56592353587949, 23.078999059324314], + [72.56592353587949, 23.08033152381615]]], None, False), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.57296165233457, 23.08137774594047], + [72.57296165233457, 23.080084772128696], + [72.57410963779294, 23.080084772128696], + [72.57410963779294, 23.08137774594047]]], None, False), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56100972896421, 23.079423475373336], + [72.56100972896421, 23.078456199634683], + [72.56255468135679, 23.078456199634683], + [72.56255468135679, 23.079423475373336]]], None, False), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.59244395909863, 23.08886205587978], + [72.59244395909863, 23.088195867560096], + [72.59312524018841, 23.088195867560096], + [72.59312524018841, 23.08886205587978]]], None, False), + { + "class": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.58891417203503, 23.08902490141124], + [72.58891417203503, 23.087914587055902], + [72.59019090352612, 23.087914587055902], + [72.59019090352612, 23.08902490141124]]], None, False), + { + "class": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63284367422881, 23.083747187676313], + [72.63284367422881, 23.082246968536918], + [72.63458174567046, 23.082246968536918], + [72.63458174567046, 23.083747187676313]]], None, False), + { + "class": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61123781615103, 23.03548171268339], + [72.61123781615103, 23.034583235045087], + [72.61229997092093, 23.034583235045087], + [72.61229997092093, 23.03548171268339]]], None, False), + { + "class": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.61444573813284, 23.03697257994195], + [72.61444573813284, 23.035649559490157], + [72.61594777518118, 23.035649559490157], + [72.61594777518118, 23.03697257994195]]], None, False), + { + "class": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.60209577668272, 23.04857847538297], + [72.60209577668272, 23.047275313883606], + [72.60400550950132, 23.047275313883606], + [72.60400550950132, 23.04857847538297]]], None, False), + { + "class": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.51149811879407, 23.047834507790366], + [72.51149811879407, 23.04608707415321], + [72.51345076695691, 23.04608707415321], + [72.51345076695691, 23.047834507790366]]], None, False), + { + "class": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.49712295504843, 23.062788240255994], + [72.49712295504843, 23.06162341641217], + [72.49815292331014, 23.06162341641217], + [72.49815292331014, 23.062788240255994]]], None, False), + { + "class": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54670277405151, 23.075491479960288], + [72.54670277405151, 23.072964630315727], + [72.5489343719519, 23.072964630315727], + [72.5489343719519, 23.075491479960288]]], None, False), + { + "class": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55421295929321, 23.07580733282782], + [72.55421295929321, 23.07367531157657], + [72.55751744079956, 23.07367531157657], + [72.55751744079956, 23.07580733282782]]], None, False), + { + "class": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53350630569824, 23.074001039232826], + [72.53350630569824, 23.072036790796002], + [72.53615632820495, 23.072036790796002], + [72.53615632820495, 23.074001039232826]]], None, False), + { + "class": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52723091860975, 23.03366481301143], + [72.52723091860975, 23.032420748682313], + [72.52894753237928, 23.032420748682313], + [72.52894753237928, 23.03366481301143]]], None, False), + { + "class": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52270334979261, 23.035698734716632], + [72.52270334979261, 23.034118992365073], + [72.52474182864393, 23.034118992365073], + [72.52474182864393, 23.035698734716632]]], None, False), + { + "class": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.54976147433484, 23.028668739099235], + [72.54976147433484, 23.026970426741123], + [72.55210036059583, 23.026970426741123], + [72.55210036059583, 23.028668739099235]]], None, False), + { + "class": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.55617731829847, 23.032835438068055], + [72.55617731829847, 23.03024854533837], + [72.55915993472303, 23.03024854533837], + [72.55915993472303, 23.032835438068055]]], None, False), + { + "class": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64766142687054, 22.9969522718421], + [72.64766142687054, 22.99607328997167], + [72.64864847978802, 22.99607328997167], + [72.64864847978802, 22.9969522718421]]], None, False), + { + "class": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.65313313326092, 22.99596465136559], + [72.65313313326092, 22.99518936422971], + [72.65385196527691, 22.99518936422971], + [72.65385196527691, 22.99596465136559]]], None, False), + { + "class": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.64301113330575, 23.006479138035033], + [72.64301113330575, 23.005649595875003], + [72.64406792365762, 23.005649595875003], + [72.64406792365762, 23.006479138035033]]], None, False), + { + "class": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.63917020999642, 23.00445958899076], + [72.63917020999642, 23.003802858706333], + [72.64008216106149, 23.003802858706333], + [72.64008216106149, 23.00445958899076]]], None, False), + { + "class": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62459470431035, 23.015117807565044], + [72.62459470431035, 23.014110570204384], + [72.62584997812932, 23.014110570204384], + [72.62584997812932, 23.015117807565044]]], None, False), + { + "class": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.62965335051244, 23.015483176121137], + [72.62965335051244, 23.01433769301113], + [72.63109101454442, 23.01433769301113], + [72.63109101454442, 23.015483176121137]]], None, False), + { + "class": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.5929084117717, 23.018501870267272], + [72.5929084117717, 23.017763742536697], + [72.5937720830745, 23.017763742536697], + [72.5937720830745, 23.018501870267272]]], None, False), + { + "class": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.56404451603258, 23.017177110456608], + [72.56404451603258, 23.015725523443777], + [72.565922062343, 23.015725523443777], + [72.565922062343, 23.017177110456608]]], None, False), + { + "class": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52290852145079, 23.033167515925737], + [72.52290852145079, 23.031962941433807], + [72.52428181246641, 23.031962941433807], + [72.52428181246641, 23.033167515925737]]], None, False), + { + "class": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.52419598177794, 23.03062999809512], + [72.52419598177794, 23.02921805114397], + [72.52598769739988, 23.02921805114397], + [72.52598769739988, 23.03062999809512]]], None, False), + { + "class": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[72.53902594674939, 23.05493608122571], + [72.53902594674939, 23.053850165460744], + [72.54044215310925, 23.053850165460744], + [72.54044215310925, 23.05493608122571]]], None, False), + { + "class": 1, + "system:index": "49" + })]), + L7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_L2") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.2 Urban Environments +# Checkpoint: A12h +# Author: Michelle Stuhlmacher and Ran Goldblatt +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Map.centerObject(bu, 13) + +# Surface reflectance function from example: +def maskL457sr(image): + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0) + + # Replace the original bands with the scaled ones and apply the masks. + return image.addBands(opticalBands, None, True) \ + .addBands(thermalBand, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + + +# Map the function over one year of data. +collection = L7.filterDate('2020-01-01', '2021-01-01').map( + maskL457sr) +landsat7_2020 = collection.median() + +Map.addLayer(landsat7_2020, { + 'bands': ['SR_B3', 'SR_B2', 'SR_B1'], + 'min': 0, + 'max': 0.3 +}, 'landsat 7, 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +lc = nbu.merge(bu) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'ST_B6', + 'SR_B7' +] + +training = landsat7_2020.select(bands).sampleRegions({ + 'collection': lc, + 'properties': ['class'], + 'scale': 30 +}) + +# Create a random forest classifier with 20 trees. +classifier = ee.Classifier.smileRandomForest({ + 'numberOfTrees': 20 +}).train({ # Train the classifier. + # Use the examples we got when we sampled the pixels. + 'features': training, + # This is the class that we want to predict. + 'classProperty': 'class', + # The bands the classifier will use for training and classification. + 'inputProperties': bands +}) + +# Apply the classifier on the 2020 image. +classified20 = landsat7_2020.select(bands).classify(classifier) + +Map.addLayer(classified20.mask(classified20), { + 'palette': ['#ff4218'], + 'opacity': 0.6 +}, 'built-up, 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +landsat7_2010 = L7.filterDate('2010-01-01', '2010-12-31') \ + .map(maskL457sr).median() + +# Apply the classifier to the 2010 image. +classified10 = landsat7_2010.select(bands).classify( + classifier) +Map.addLayer(classified10.mask(classified10), { + 'palette': ['#f1ff21'], + 'opacity': 0.6 +}, 'built-up, 2010') + +difference = classified20.subtract(classified10) + +Map.addLayer(difference.mask(difference), { + 'palette': ['#315dff'], + 'opacity': 0.6 +}, 'difference') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13a Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13a Checkpoint.ipynb new file mode 100644 index 0000000..d110a1e --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13a Checkpoint.ipynb @@ -0,0 +1,219 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.3 Built Environments\n", + "# Checkpoint: A13a\n", + "# Author: Erin Trochim\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import roads data.\n", + "grip4_africa = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Africa'),\n", + " grip4_north_america = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/North-America'),\n", + " grip4_europe = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Europe')\n", + "\n", + "# Check the roads data sizes.\n", + "print('Grip4 Africa size', grip4_africa.size())\n", + "print('Grip4 North America size', grip4_north_america.size())\n", + "print('Grip4 Europe size', grip4_europe.size())\n", + "\n", + "# Display the roads data.\n", + "Map.addLayer(ee.FeatureCollection(grip4_africa).style(**{\n", + " 'color': '413B3A',\n", + " 'width': 1\n", + "}), {}, 'Grip4 Africa')\n", + "Map.addLayer(ee.FeatureCollection(grip4_north_america).style(**{\n", + " 'color': '413B3A',\n", + " 'width': 1\n", + "}), {}, 'Grip4 North America')\n", + "Map.addLayer(ee.FeatureCollection(grip4_europe).style(**{\n", + " 'color': '413B3A',\n", + " 'width': 1\n", + "}), {}, 'Grip4 Europe')\n", + "\n", + "# Import simplified countries.\n", + "countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')\n", + "\n", + "# Add a function to calculate the feature's geometry area.\n", + "# Add the function as a property.\n", + "def addArea(feature):\n", + " return feature.set({\n", + " 'areaKm': feature.geometry().area().divide(1000 *\n", + " 1000)\n", + " }); # km2 squared\n", + "\n", + "\n", + "# Map the area getting function over the FeatureCollection.\n", + "countriesArea = countries.map(addArea)\n", + "\n", + "# Filter to the largest country in Africa.\n", + "Algeria = countriesArea.filter(ee.Filter.inList('country_na', [\n", + " 'Algeria'\n", + "]))\n", + "\n", + "# Display the selected countries.\n", + "Map.addLayer(Algeria.style(**{\n", + " 'fillColor': 'b5ffb4',\n", + " 'color': '00909F',\n", + " 'width': 1.0\n", + "}), {}, 'Algeria')\n", + "\n", + "# This function calculates the road length per country for the associated GRIP dataset.\n", + "def roadLength4Country(country, grip4):\n", + "\n", + " # Join roads to countries.\n", + " intersectsFilter = ee.Filter.intersects({\n", + " 'leftField': '.geo',\n", + " 'rightField': '.geo',\n", + " 'maxError': 10\n", + " })\n", + "\n", + " grip4Selected = grip4.filterBounds(country)\n", + "\n", + " countriesWithRds = ee.Join.saveAll('roads').apply({\n", + " 'primary': country,\n", + " 'secondary': grip4Selected,\n", + " 'condition': intersectsFilter\n", + " }).filter(ee.Filter.neq('roads', None))\n", + "\n", + " # Return country with calculation of roadLength and roadsPerArea.\n", + "\n", + "def func_uni(country):\n", + " roadsList = ee.List(country.get('roads'))\n", + " roadLengths = roadsList.map(function(road) {\n", + " return ee.Feature(road).intersection(\n", + " country, 10).length(10)\n", + " })\n", + " roadLength = ee.Number(roadLengths.reduce(ee \\\n", + " .Reducer.sum()))\n", + " return country.set({\n", + " 'roadLength': roadLength.divide(\n", + " 1000), # Convert to km.\n", + " 'roadsPerArea': roadLength.divide(ee \\\n", + " .Number(country.get('areaKm'))\n", + " )\n", + " })\n", + "\n", + " return countriesWithRds.map(func_uni\n", + ").select(['country_na', 'areaKm', 'roadLength',\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").select(['country_na', 'areaKm', 'roadLength',\n", + " 'roadsPerArea'\n", + " ])\n", + "\n", + "\n", + "# Apply the road length function to Algeria.\n", + "roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa)\n", + "\n", + "# Print the road statistics for Algeria.\n", + "print('Roads statistics in Algeria', roadLengthAlgeria)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13a Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13a Checkpoint.js new file mode 100644 index 0000000..a44ee22 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13a Checkpoint.js @@ -0,0 +1,108 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.3 Built Environments +// Checkpoint: A13a +// Author: Erin Trochim +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import roads data. +var grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe'); + +// Check the roads data sizes. +print('Grip4 Africa size', grip4_africa.size()); +print('Grip4 North America size', grip4_north_america.size()); +print('Grip4 Europe size', grip4_europe.size()); + +// Display the roads data. +Map.addLayer(ee.FeatureCollection(grip4_africa).style({ + color: '413B3A', + width: 1 +}), {}, 'Grip4 Africa'); +Map.addLayer(ee.FeatureCollection(grip4_north_america).style({ + color: '413B3A', + width: 1 +}), {}, 'Grip4 North America'); +Map.addLayer(ee.FeatureCollection(grip4_europe).style({ + color: '413B3A', + width: 1 +}), {}, 'Grip4 Europe'); + +// Import simplified countries. +var countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017'); + +// Add a function to calculate the feature's geometry area. +// Add the function as a property. +var addArea = function(feature) { + return feature.set({ + areaKm: feature.geometry().area().divide(1000 * + 1000) + }); // km2 squared +}; + +// Map the area getting function over the FeatureCollection. +var countriesArea = countries.map(addArea); + +// Filter to the largest country in Africa. +var Algeria = countriesArea.filter(ee.Filter.inList('country_na', [ + 'Algeria' +])); + +// Display the selected countries. +Map.addLayer(Algeria.style({ + fillColor: 'b5ffb4', + color: '00909F', + width: 1.0 +}), {}, 'Algeria'); + +// This function calculates the road length per country for the associated GRIP dataset. +var roadLength4Country = function(country, grip4) { + + // Join roads to countries. + var intersectsFilter = ee.Filter.intersects({ + leftField: '.geo', + rightField: '.geo', + maxError: 10 + }); + + var grip4Selected = grip4.filterBounds(country); + + var countriesWithRds = ee.Join.saveAll('roads').apply({ + primary: country, + secondary: grip4Selected, + condition: intersectsFilter + }).filter(ee.Filter.neq('roads', null)); + + // Return country with calculation of roadLength and roadsPerArea. + return countriesWithRds.map(function(country) { + var roadsList = ee.List(country.get('roads')); + var roadLengths = roadsList.map(function(road) { + return ee.Feature(road).intersection( + country, 10).length(10); + }); + var roadLength = ee.Number(roadLengths.reduce(ee + .Reducer.sum())); + return country.set({ + roadLength: roadLength.divide( + 1000), // Convert to km. + roadsPerArea: roadLength.divide(ee + .Number(country.get('areaKm')) + ) + }); + }).select(['country_na', 'areaKm', 'roadLength', + 'roadsPerArea' + ]); +}; + +// Apply the road length function to Algeria. +var roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa); + +// Print the road statistics for Algeria. +print('Roads statistics in Algeria', roadLengthAlgeria); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13a Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13a Checkpoint.py new file mode 100644 index 0000000..4d9dd12 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13a Checkpoint.py @@ -0,0 +1,132 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.3 Built Environments +# Checkpoint: A13a +# Author: Erin Trochim +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import roads data. +grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe') + +# Check the roads data sizes. +print('Grip4 Africa size', grip4_africa.size()) +print('Grip4 North America size', grip4_north_america.size()) +print('Grip4 Europe size', grip4_europe.size()) + +# Display the roads data. +Map.addLayer(ee.FeatureCollection(grip4_africa).style(**{ + 'color': '413B3A', + 'width': 1 +}), {}, 'Grip4 Africa') +Map.addLayer(ee.FeatureCollection(grip4_north_america).style(**{ + 'color': '413B3A', + 'width': 1 +}), {}, 'Grip4 North America') +Map.addLayer(ee.FeatureCollection(grip4_europe).style(**{ + 'color': '413B3A', + 'width': 1 +}), {}, 'Grip4 Europe') + +# Import simplified countries. +countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + +# Add a function to calculate the feature's geometry area. +# Add the function as a property. +def addArea(feature): + return feature.set({ + 'areaKm': feature.geometry().area().divide(1000 * + 1000) + }); # km2 squared + + +# Map the area getting function over the FeatureCollection. +countriesArea = countries.map(addArea) + +# Filter to the largest country in Africa. +Algeria = countriesArea.filter(ee.Filter.inList('country_na', [ + 'Algeria' +])) + +# Display the selected countries. +Map.addLayer(Algeria.style(**{ + 'fillColor': 'b5ffb4', + 'color': '00909F', + 'width': 1.0 +}), {}, 'Algeria') + +# This function calculates the road length per country for the associated GRIP dataset. +def roadLength4Country(country, grip4): + + # Join roads to countries. + intersectsFilter = ee.Filter.intersects({ + 'leftField': '.geo', + 'rightField': '.geo', + 'maxError': 10 + }) + + grip4Selected = grip4.filterBounds(country) + + countriesWithRds = ee.Join.saveAll('roads').apply({ + 'primary': country, + 'secondary': grip4Selected, + 'condition': intersectsFilter + }).filter(ee.Filter.neq('roads', None)) + + # Return country with calculation of roadLength and roadsPerArea. + +def func_uni(country): + roadsList = ee.List(country.get('roads')) + roadLengths = roadsList.map(function(road) { + return ee.Feature(road).intersection( + country, 10).length(10) + }) + roadLength = ee.Number(roadLengths.reduce(ee \ + .Reducer.sum())) + return country.set({ + 'roadLength': roadLength.divide( + 1000), # Convert to km. + 'roadsPerArea': roadLength.divide(ee \ + .Number(country.get('areaKm')) + ) + }) + + return countriesWithRds.map(func_uni +).select(['country_na', 'areaKm', 'roadLength', + + + + + + + + + + + + + + +).select(['country_na', 'areaKm', 'roadLength', + 'roadsPerArea' + ]) + + +# Apply the road length function to Algeria. +roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa) + +# Print the road statistics for Algeria. +print('Roads statistics in Algeria', roadLengthAlgeria) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13b Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13b Checkpoint.ipynb new file mode 100644 index 0000000..8bc10b4 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13b Checkpoint.ipynb @@ -0,0 +1,271 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.3 Built Environments\n", + "# Checkpoint: A13b\n", + "# Author: Erin Trochim\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import roads data.\n", + "grip4_africa = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Africa'),\n", + " grip4_north_america = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/North-America'),\n", + " grip4_europe = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Europe')\n", + "\n", + "# Check the roads data sizes.\n", + "print('Grip4 Africa size', grip4_africa.size())\n", + "print('Grip4 North America size', grip4_north_america.size())\n", + "print('Grip4 Europe size', grip4_europe.size())\n", + "\n", + "# Display the roads data.\n", + "Map.addLayer(ee.FeatureCollection(grip4_africa).style(**{\n", + " 'color': '413B3A',\n", + " 'width': 1\n", + "}), {}, 'Grip4 Africa')\n", + "Map.addLayer(ee.FeatureCollection(grip4_north_america).style(**{\n", + " 'color': '413B3A',\n", + " 'width': 1\n", + "}), {}, 'Grip4 North America')\n", + "Map.addLayer(ee.FeatureCollection(grip4_europe).style(**{\n", + " 'color': '413B3A',\n", + " 'width': 1\n", + "}), {}, 'Grip4 Europe')\n", + "\n", + "# Import simplified countries.\n", + "countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')\n", + "\n", + "# Add a function to calculate the feature's geometry area.\n", + "# Add the function as a property.\n", + "def addArea(feature):\n", + " return feature.set({\n", + " 'areaKm': feature.geometry().area().divide(1000 *\n", + " 1000)\n", + " }); # km2 squared\n", + "\n", + "\n", + "# Map the area getting function over the FeatureCollection.\n", + "countriesArea = countries.map(addArea)\n", + "\n", + "# Filter to the largest country in Africa.\n", + "Algeria = countriesArea.filter(ee.Filter.inList('country_na', [\n", + " 'Algeria'\n", + "]))\n", + "\n", + "# Display the selected countries.\n", + "Map.addLayer(Algeria.style(**{\n", + " 'fillColor': 'b5ffb4',\n", + " 'color': '00909F',\n", + " 'width': 1.0\n", + "}), {}, 'Algeria')\n", + "\n", + "# This function calculates the road length per country for the associated GRIP dataset.\n", + "def roadLength4Country(country, grip4):\n", + "\n", + " # Join roads to countries.\n", + " intersectsFilter = ee.Filter.intersects({\n", + " 'leftField': '.geo',\n", + " 'rightField': '.geo',\n", + " 'maxError': 10\n", + " })\n", + "\n", + " grip4Selected = grip4.filterBounds(country)\n", + "\n", + " countriesWithRds = ee.Join.saveAll('roads').apply({\n", + " 'primary': country,\n", + " 'secondary': grip4Selected,\n", + " 'condition': intersectsFilter\n", + " }).filter(ee.Filter.neq('roads', None))\n", + "\n", + " # Return country with calculation of roadLength and roadsPerArea.\n", + "\n", + "def func_gfe(country):\n", + " roadsList = ee.List(country.get('roads'))\n", + " roadLengths = roadsList.map(function(road) {\n", + " return ee.Feature(road).intersection(\n", + " country, 10).length(10)\n", + " })\n", + " roadLength = ee.Number(roadLengths.reduce(ee \\\n", + " .Reducer.sum()))\n", + " return country.set({\n", + " 'roadLength': roadLength.divide(\n", + " 1000), # Convert to km.\n", + " 'roadsPerArea': roadLength.divide(ee \\\n", + " .Number(country.get('areaKm'))\n", + " )\n", + " })\n", + "\n", + " return countriesWithRds.map(func_gfe\n", + ").select(['country_na', 'areaKm', 'roadLength',\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").select(['country_na', 'areaKm', 'roadLength',\n", + " 'roadsPerArea'\n", + " ])\n", + "\n", + "\n", + "# Apply the road length function to Algeria.\n", + "roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa)\n", + "\n", + "# Print the road statistics for Algeria.\n", + "print('Roads statistics in Algeria', roadLengthAlgeria)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Export feature collection to drive.\n", + "Export.table.toDrive({\n", + " 'collection': roadLengthAlgeria,\n", + " 'description': 'RoadStatisticsforAlgeria',\n", + " 'selectors': ['country_na', 'roadLength', 'roadsPerArea']\n", + "})\n", + "\n", + "# Print the first feature of the grip4 Africa feature collection.\n", + "print(grip4_africa.limit(1))\n", + "\n", + "Map.setCenter(-0.759, 9.235, 6)\n", + "Map.addLayer(grip4_africa.limit(1),\n", + " {},\n", + " 'Road length comparison')\n", + "\n", + "# This function adds line length in km.\n", + "def addLength(feature):\n", + " return feature.set({\n", + " 'lengthKm': feature.length().divide(1000)\n", + " })\n", + "\n", + "\n", + "# Calculate the line lengths for all roads in Africa.\n", + "grip4_africaLength = grip4_africa.map(addLength)\n", + "\n", + "# Compare with other values.\n", + "print('Calculated road length property', grip4_africaLength.limit(1))\n", + "\n", + "# Repeat the analysis to calculate the length of all roads.\n", + "# Filter the table geographically: only keep roads in Algeria.\n", + "grip4_Algeria = grip4_africaLength.filterBounds(Algeria)\n", + "\n", + "# Visualize the output.\n", + "Map.addLayer(grip4_Algeria.style(**{\n", + " 'color': 'green',\n", + " 'width': 2.0\n", + "}), {}, 'Algeria roads')\n", + "\n", + "# Sum the lengths for roads in Algeria.\n", + "sumLengthKmAlgeria = ee.Number(\n", + " # Reduce to get the sum.\n", + " grip4_Algeria.reduceColumns(ee.Reducer.sum(), ['lengthKm']) \\\n", + " .get('sum')\n", + ")\n", + "\n", + "# Print the result.\n", + "print('Length of all roads in Algeria', sumLengthKmAlgeria)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13b Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13b Checkpoint.js new file mode 100644 index 0000000..272caf2 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13b Checkpoint.js @@ -0,0 +1,160 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.3 Built Environments +// Checkpoint: A13b +// Author: Erin Trochim +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import roads data. +var grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe'); + +// Check the roads data sizes. +print('Grip4 Africa size', grip4_africa.size()); +print('Grip4 North America size', grip4_north_america.size()); +print('Grip4 Europe size', grip4_europe.size()); + +// Display the roads data. +Map.addLayer(ee.FeatureCollection(grip4_africa).style({ + color: '413B3A', + width: 1 +}), {}, 'Grip4 Africa'); +Map.addLayer(ee.FeatureCollection(grip4_north_america).style({ + color: '413B3A', + width: 1 +}), {}, 'Grip4 North America'); +Map.addLayer(ee.FeatureCollection(grip4_europe).style({ + color: '413B3A', + width: 1 +}), {}, 'Grip4 Europe'); + +// Import simplified countries. +var countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017'); + +// Add a function to calculate the feature's geometry area. +// Add the function as a property. +var addArea = function(feature) { + return feature.set({ + areaKm: feature.geometry().area().divide(1000 * + 1000) + }); // km2 squared +}; + +// Map the area getting function over the FeatureCollection. +var countriesArea = countries.map(addArea); + +// Filter to the largest country in Africa. +var Algeria = countriesArea.filter(ee.Filter.inList('country_na', [ + 'Algeria' +])); + +// Display the selected countries. +Map.addLayer(Algeria.style({ + fillColor: 'b5ffb4', + color: '00909F', + width: 1.0 +}), {}, 'Algeria'); + +// This function calculates the road length per country for the associated GRIP dataset. +var roadLength4Country = function(country, grip4) { + + // Join roads to countries. + var intersectsFilter = ee.Filter.intersects({ + leftField: '.geo', + rightField: '.geo', + maxError: 10 + }); + + var grip4Selected = grip4.filterBounds(country); + + var countriesWithRds = ee.Join.saveAll('roads').apply({ + primary: country, + secondary: grip4Selected, + condition: intersectsFilter + }).filter(ee.Filter.neq('roads', null)); + + // Return country with calculation of roadLength and roadsPerArea. + return countriesWithRds.map(function(country) { + var roadsList = ee.List(country.get('roads')); + var roadLengths = roadsList.map(function(road) { + return ee.Feature(road).intersection( + country, 10).length(10); + }); + var roadLength = ee.Number(roadLengths.reduce(ee + .Reducer.sum())); + return country.set({ + roadLength: roadLength.divide( + 1000), // Convert to km. + roadsPerArea: roadLength.divide(ee + .Number(country.get('areaKm')) + ) + }); + }).select(['country_na', 'areaKm', 'roadLength', + 'roadsPerArea' + ]); +}; + +// Apply the road length function to Algeria. +var roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa); + +// Print the road statistics for Algeria. +print('Roads statistics in Algeria', roadLengthAlgeria); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Export feature collection to drive. +Export.table.toDrive({ + collection: roadLengthAlgeria, + description: 'RoadStatisticsforAlgeria', + selectors: ['country_na', 'roadLength', 'roadsPerArea'] +}); + +// Print the first feature of the grip4 Africa feature collection. +print(grip4_africa.limit(1)); + +Map.setCenter(-0.759, 9.235, 6); +Map.addLayer(grip4_africa.limit(1), + {}, + 'Road length comparison'); + +// This function adds line length in km. +var addLength = function(feature) { + return feature.set({ + lengthKm: feature.length().divide(1000) + }); +}; + +// Calculate the line lengths for all roads in Africa. +var grip4_africaLength = grip4_africa.map(addLength); + +// Compare with other values. +print('Calculated road length property', grip4_africaLength.limit(1)); + +// Repeat the analysis to calculate the length of all roads. +// Filter the table geographically: only keep roads in Algeria. +var grip4_Algeria = grip4_africaLength.filterBounds(Algeria); + +// Visualize the output. +Map.addLayer(grip4_Algeria.style({ + color: 'green', + width: 2.0 +}), {}, 'Algeria roads'); + +// Sum the lengths for roads in Algeria. +var sumLengthKmAlgeria = ee.Number( + // Reduce to get the sum. + grip4_Algeria.reduceColumns(ee.Reducer.sum(), ['lengthKm']) + .get('sum') +); + +// Print the result. +print('Length of all roads in Algeria', sumLengthKmAlgeria); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13b Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13b Checkpoint.py new file mode 100644 index 0000000..2ca8dad --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13b Checkpoint.py @@ -0,0 +1,184 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.3 Built Environments +# Checkpoint: A13b +# Author: Erin Trochim +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import roads data. +grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe') + +# Check the roads data sizes. +print('Grip4 Africa size', grip4_africa.size()) +print('Grip4 North America size', grip4_north_america.size()) +print('Grip4 Europe size', grip4_europe.size()) + +# Display the roads data. +Map.addLayer(ee.FeatureCollection(grip4_africa).style(**{ + 'color': '413B3A', + 'width': 1 +}), {}, 'Grip4 Africa') +Map.addLayer(ee.FeatureCollection(grip4_north_america).style(**{ + 'color': '413B3A', + 'width': 1 +}), {}, 'Grip4 North America') +Map.addLayer(ee.FeatureCollection(grip4_europe).style(**{ + 'color': '413B3A', + 'width': 1 +}), {}, 'Grip4 Europe') + +# Import simplified countries. +countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + +# Add a function to calculate the feature's geometry area. +# Add the function as a property. +def addArea(feature): + return feature.set({ + 'areaKm': feature.geometry().area().divide(1000 * + 1000) + }); # km2 squared + + +# Map the area getting function over the FeatureCollection. +countriesArea = countries.map(addArea) + +# Filter to the largest country in Africa. +Algeria = countriesArea.filter(ee.Filter.inList('country_na', [ + 'Algeria' +])) + +# Display the selected countries. +Map.addLayer(Algeria.style(**{ + 'fillColor': 'b5ffb4', + 'color': '00909F', + 'width': 1.0 +}), {}, 'Algeria') + +# This function calculates the road length per country for the associated GRIP dataset. +def roadLength4Country(country, grip4): + + # Join roads to countries. + intersectsFilter = ee.Filter.intersects({ + 'leftField': '.geo', + 'rightField': '.geo', + 'maxError': 10 + }) + + grip4Selected = grip4.filterBounds(country) + + countriesWithRds = ee.Join.saveAll('roads').apply({ + 'primary': country, + 'secondary': grip4Selected, + 'condition': intersectsFilter + }).filter(ee.Filter.neq('roads', None)) + + # Return country with calculation of roadLength and roadsPerArea. + +def func_gfe(country): + roadsList = ee.List(country.get('roads')) + roadLengths = roadsList.map(function(road) { + return ee.Feature(road).intersection( + country, 10).length(10) + }) + roadLength = ee.Number(roadLengths.reduce(ee \ + .Reducer.sum())) + return country.set({ + 'roadLength': roadLength.divide( + 1000), # Convert to km. + 'roadsPerArea': roadLength.divide(ee \ + .Number(country.get('areaKm')) + ) + }) + + return countriesWithRds.map(func_gfe +).select(['country_na', 'areaKm', 'roadLength', + + + + + + + + + + + + + + +).select(['country_na', 'areaKm', 'roadLength', + 'roadsPerArea' + ]) + + +# Apply the road length function to Algeria. +roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa) + +# Print the road statistics for Algeria. +print('Roads statistics in Algeria', roadLengthAlgeria) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Export feature collection to drive. +Export.table.toDrive({ + 'collection': roadLengthAlgeria, + 'description': 'RoadStatisticsforAlgeria', + 'selectors': ['country_na', 'roadLength', 'roadsPerArea'] +}) + +# Print the first feature of the grip4 Africa feature collection. +print(grip4_africa.limit(1)) + +Map.setCenter(-0.759, 9.235, 6) +Map.addLayer(grip4_africa.limit(1), + {}, + 'Road length comparison') + +# This function adds line length in km. +def addLength(feature): + return feature.set({ + 'lengthKm': feature.length().divide(1000) + }) + + +# Calculate the line lengths for all roads in Africa. +grip4_africaLength = grip4_africa.map(addLength) + +# Compare with other values. +print('Calculated road length property', grip4_africaLength.limit(1)) + +# Repeat the analysis to calculate the length of all roads. +# Filter the table geographically: only keep roads in Algeria. +grip4_Algeria = grip4_africaLength.filterBounds(Algeria) + +# Visualize the output. +Map.addLayer(grip4_Algeria.style(**{ + 'color': 'green', + 'width': 2.0 +}), {}, 'Algeria roads') + +# Sum the lengths for roads in Algeria. +sumLengthKmAlgeria = ee.Number( + # Reduce to get the sum. + grip4_Algeria.reduceColumns(ee.Reducer.sum(), ['lengthKm']) \ + .get('sum') +) + +# Print the result. +print('Length of all roads in Algeria', sumLengthKmAlgeria) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13c Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13c Checkpoint.ipynb new file mode 100644 index 0000000..437b112 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13c Checkpoint.ipynb @@ -0,0 +1,365 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.3 Built Environments\n", + "# Checkpoint: A13c\n", + "# Author: Erin Trochim\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import roads data.\n", + "grip4_africa = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Africa'),\n", + " grip4_north_america = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/North-America'),\n", + " grip4_europe = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Europe')\n", + "\n", + "# Check the roads data sizes.\n", + "print('Grip4 Africa size', grip4_africa.size())\n", + "print('Grip4 North America size', grip4_north_america.size())\n", + "print('Grip4 Europe size', grip4_europe.size())\n", + "\n", + "# Display the roads data.\n", + "Map.addLayer(ee.FeatureCollection(grip4_africa).style(**{\n", + " 'color': '413B3A',\n", + " 'width': 1\n", + "}), {}, 'Grip4 Africa')\n", + "Map.addLayer(ee.FeatureCollection(grip4_north_america).style(**{\n", + " 'color': '413B3A',\n", + " 'width': 1\n", + "}), {}, 'Grip4 North America')\n", + "Map.addLayer(ee.FeatureCollection(grip4_europe).style(**{\n", + " 'color': '413B3A',\n", + " 'width': 1\n", + "}), {}, 'Grip4 Europe')\n", + "\n", + "# Import simplified countries.\n", + "countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')\n", + "\n", + "# Add a function to calculate the feature's geometry area.\n", + "# Add the function as a property.\n", + "def addArea(feature):\n", + " return feature.set({\n", + " 'areaKm': feature.geometry().area().divide(1000 *\n", + " 1000)\n", + " }); # km2 squared\n", + "\n", + "\n", + "# Map the area getting function over the FeatureCollection.\n", + "countriesArea = countries.map(addArea)\n", + "\n", + "# Filter to the largest country in Africa.\n", + "Algeria = countriesArea.filter(ee.Filter.inList('country_na', [\n", + " 'Algeria'\n", + "]))\n", + "\n", + "# Display the selected countries.\n", + "Map.addLayer(Algeria.style(**{\n", + " 'fillColor': 'b5ffb4',\n", + " 'color': '00909F',\n", + " 'width': 1.0\n", + "}), {}, 'Algeria')\n", + "\n", + "# This function calculates the road length per country for the associated GRIP dataset.\n", + "def roadLength4Country(country, grip4):\n", + "\n", + " # Join roads to countries.\n", + " intersectsFilter = ee.Filter.intersects({\n", + " 'leftField': '.geo',\n", + " 'rightField': '.geo',\n", + " 'maxError': 10\n", + " })\n", + "\n", + " grip4Selected = grip4.filterBounds(country)\n", + "\n", + " countriesWithRds = ee.Join.saveAll('roads').apply({\n", + " 'primary': country,\n", + " 'secondary': grip4Selected,\n", + " 'condition': intersectsFilter\n", + " }).filter(ee.Filter.neq('roads', None))\n", + "\n", + " # Return country with calculation of roadLength and roadsPerArea.\n", + "\n", + "def func_uge(country):\n", + " roadsList = ee.List(country.get('roads'))\n", + " roadLengths = roadsList.map(function(road) {\n", + " return ee.Feature(road).intersection(\n", + " country, 10).length(10)\n", + " })\n", + " roadLength = ee.Number(roadLengths.reduce(ee \\\n", + " .Reducer.sum()))\n", + " return country.set({\n", + " 'roadLength': roadLength.divide(\n", + " 1000), # Convert to km.\n", + " 'roadsPerArea': roadLength.divide(ee \\\n", + " .Number(country.get('areaKm'))\n", + " )\n", + " })\n", + "\n", + " return countriesWithRds.map(func_uge\n", + ").select(['country_na', 'areaKm', 'roadLength',\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").select(['country_na', 'areaKm', 'roadLength',\n", + " 'roadsPerArea'\n", + " ])\n", + "\n", + "\n", + "# Apply the road length function to Algeria.\n", + "roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa)\n", + "\n", + "# Print the road statistics for Algeria.\n", + "print('Roads statistics in Algeria', roadLengthAlgeria)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Export feature collection to drive.\n", + "Export.table.toDrive({\n", + " 'collection': roadLengthAlgeria,\n", + " 'description': 'RoadStatisticsforAlgeria',\n", + " 'selectors': ['country_na', 'roadLength', 'roadsPerArea']\n", + "})\n", + "\n", + "# Print the first feature of the grip4 Africa feature collection.\n", + "print(grip4_africa.limit(1))\n", + "\n", + "Map.setCenter(-0.759, 9.235, 6)\n", + "Map.addLayer(grip4_africa.limit(1),\n", + " {},\n", + " 'Road length comparison')\n", + "\n", + "# This function adds line length in km.\n", + "def addLength(feature):\n", + " return feature.set({\n", + " 'lengthKm': feature.length().divide(1000)\n", + " })\n", + "\n", + "\n", + "# Calculate the line lengths for all roads in Africa.\n", + "grip4_africaLength = grip4_africa.map(addLength)\n", + "\n", + "# Compare with other values.\n", + "print('Calculated road length property', grip4_africaLength.limit(1))\n", + "\n", + "# Repeat the analysis to calculate the length of all roads.\n", + "# Filter the table geographically: only keep roads in Algeria.\n", + "grip4_Algeria = grip4_africaLength.filterBounds(Algeria)\n", + "\n", + "# Visualize the output.\n", + "Map.addLayer(grip4_Algeria.style(**{\n", + " 'color': 'green',\n", + " 'width': 2.0\n", + "}), {}, 'Algeria roads')\n", + "\n", + "# Sum the lengths for roads in Algeria.\n", + "sumLengthKmAlgeria = ee.Number(\n", + " # Reduce to get the sum.\n", + " grip4_Algeria.reduceColumns(ee.Reducer.sum(), ['lengthKm']) \\\n", + " .get('sum')\n", + ")\n", + "\n", + "# Print the result.\n", + "print('Length of all roads in Algeria', sumLengthKmAlgeria)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Repeat the analysis again to calculate length of all roads using rasters.\n", + "# Convert to raster.\n", + "empty = ee.Image().float()\n", + "\n", + "grip4_africaRaster = empty.paint({\n", + " 'featureCollection': grip4_africaLength,\n", + " 'color': 'lengthKm'\n", + "}).gt(0)\n", + "\n", + "Map.addLayer(grip4_africaRaster, {\n", + " 'palette': ['orange'],\n", + " 'max': 1\n", + "}, 'Rasterized roads')\n", + "\n", + "# Add reducer output to the features in the collection.\n", + "AlgeriaRoadLength = ee.Image.pixelArea() \\\n", + " .addBands(grip4_africaRaster) \\\n", + " .reduceRegions({\n", + " 'collection': Algeria,\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'scale': 100,\n", + "\n", + "def func_ibk(feature):\n", + " num = ee.Number.parse(feature.get('area'))\n", + " return feature.set('length', num.divide(1000).sqrt() \\\n", + " .round())\n", + "\n", + " }).map(func_ibk)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Print the first feature to illustrate the result.\n", + "print('Length of all roads in Algeria calculated via rasters', ee \\\n", + " .Number(AlgeriaRoadLength.first().get('length')))\n", + "\n", + "# Calculate line lengths for all roads in North America and Europe.\n", + "grip4_north_americaLength = grip4_north_america.map(addLength)\n", + "grip4_europeLength = grip4_europe.map(addLength)\n", + "\n", + "# Merge all vectors.\n", + "roadLengthMerge = grip4_africaLength.merge(\n", + " grip4_north_americaLength).merge(grip4_europeLength)\n", + "\n", + "# Convert to raster.\n", + "empty = ee.Image().float()\n", + "\n", + "roadLengthMergeRaster = empty.paint({\n", + " 'featureCollection': roadLengthMerge,\n", + " 'color': 'roadsPerArea'\n", + "}).gt(0)\n", + "\n", + "# Filter to largest countries in Africa, North America and Europe.\n", + "countriesSelected = countries.filter(ee.Filter.inList(\n", + " 'country_na', ['Algeria', 'Canada', 'France']))\n", + "\n", + "# Clip image to only countries of analysis.\n", + "roadLengthMergeRasterClipped = roadLengthMergeRaster \\\n", + " .clipToCollection(countriesSelected)\n", + "\n", + "# Add reducer output to the features in the collection.\n", + "countriesRoadLength = ee.Image.pixelArea() \\\n", + " .addBands(roadLengthMergeRasterClipped) \\\n", + " .reduceRegions({\n", + " 'collection': countriesSelected,\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'scale': 100,\n", + "\n", + "def func_fcu(feature):\n", + " num = ee.Number.parse(feature.get('area'))\n", + " return feature.set('length', num.divide(1000).sqrt() \\\n", + " .round())\n", + "\n", + " }).map(func_fcu)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Compute totaled road lengths in km, grouped by country.\n", + "print('Length of all roads in Canada', countriesRoadLength.filter(ee \\\n", + " .Filter.equals('country_na', 'Canada')).aggregate_sum(\n", + " 'length'))\n", + "print('Length of all roads in France', countriesRoadLength.filter(ee \\\n", + " .Filter.equals('country_na', 'France')).aggregate_sum(\n", + " 'length'))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13c Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13c Checkpoint.js new file mode 100644 index 0000000..5ecd9a5 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13c Checkpoint.js @@ -0,0 +1,240 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.3 Built Environments +// Checkpoint: A13c +// Author: Erin Trochim +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import roads data. +var grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe'); + +// Check the roads data sizes. +print('Grip4 Africa size', grip4_africa.size()); +print('Grip4 North America size', grip4_north_america.size()); +print('Grip4 Europe size', grip4_europe.size()); + +// Display the roads data. +Map.addLayer(ee.FeatureCollection(grip4_africa).style({ + color: '413B3A', + width: 1 +}), {}, 'Grip4 Africa'); +Map.addLayer(ee.FeatureCollection(grip4_north_america).style({ + color: '413B3A', + width: 1 +}), {}, 'Grip4 North America'); +Map.addLayer(ee.FeatureCollection(grip4_europe).style({ + color: '413B3A', + width: 1 +}), {}, 'Grip4 Europe'); + +// Import simplified countries. +var countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017'); + +// Add a function to calculate the feature's geometry area. +// Add the function as a property. +var addArea = function(feature) { + return feature.set({ + areaKm: feature.geometry().area().divide(1000 * + 1000) + }); // km2 squared +}; + +// Map the area getting function over the FeatureCollection. +var countriesArea = countries.map(addArea); + +// Filter to the largest country in Africa. +var Algeria = countriesArea.filter(ee.Filter.inList('country_na', [ + 'Algeria' +])); + +// Display the selected countries. +Map.addLayer(Algeria.style({ + fillColor: 'b5ffb4', + color: '00909F', + width: 1.0 +}), {}, 'Algeria'); + +// This function calculates the road length per country for the associated GRIP dataset. +var roadLength4Country = function(country, grip4) { + + // Join roads to countries. + var intersectsFilter = ee.Filter.intersects({ + leftField: '.geo', + rightField: '.geo', + maxError: 10 + }); + + var grip4Selected = grip4.filterBounds(country); + + var countriesWithRds = ee.Join.saveAll('roads').apply({ + primary: country, + secondary: grip4Selected, + condition: intersectsFilter + }).filter(ee.Filter.neq('roads', null)); + + // Return country with calculation of roadLength and roadsPerArea. + return countriesWithRds.map(function(country) { + var roadsList = ee.List(country.get('roads')); + var roadLengths = roadsList.map(function(road) { + return ee.Feature(road).intersection( + country, 10).length(10); + }); + var roadLength = ee.Number(roadLengths.reduce(ee + .Reducer.sum())); + return country.set({ + roadLength: roadLength.divide( + 1000), // Convert to km. + roadsPerArea: roadLength.divide(ee + .Number(country.get('areaKm')) + ) + }); + }).select(['country_na', 'areaKm', 'roadLength', + 'roadsPerArea' + ]); +}; + +// Apply the road length function to Algeria. +var roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa); + +// Print the road statistics for Algeria. +print('Roads statistics in Algeria', roadLengthAlgeria); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Export feature collection to drive. +Export.table.toDrive({ + collection: roadLengthAlgeria, + description: 'RoadStatisticsforAlgeria', + selectors: ['country_na', 'roadLength', 'roadsPerArea'] +}); + +// Print the first feature of the grip4 Africa feature collection. +print(grip4_africa.limit(1)); + +Map.setCenter(-0.759, 9.235, 6); +Map.addLayer(grip4_africa.limit(1), + {}, + 'Road length comparison'); + +// This function adds line length in km. +var addLength = function(feature) { + return feature.set({ + lengthKm: feature.length().divide(1000) + }); +}; + +// Calculate the line lengths for all roads in Africa. +var grip4_africaLength = grip4_africa.map(addLength); + +// Compare with other values. +print('Calculated road length property', grip4_africaLength.limit(1)); + +// Repeat the analysis to calculate the length of all roads. +// Filter the table geographically: only keep roads in Algeria. +var grip4_Algeria = grip4_africaLength.filterBounds(Algeria); + +// Visualize the output. +Map.addLayer(grip4_Algeria.style({ + color: 'green', + width: 2.0 +}), {}, 'Algeria roads'); + +// Sum the lengths for roads in Algeria. +var sumLengthKmAlgeria = ee.Number( + // Reduce to get the sum. + grip4_Algeria.reduceColumns(ee.Reducer.sum(), ['lengthKm']) + .get('sum') +); + +// Print the result. +print('Length of all roads in Algeria', sumLengthKmAlgeria); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Repeat the analysis again to calculate length of all roads using rasters. +// Convert to raster. +var empty = ee.Image().float(); + +var grip4_africaRaster = empty.paint({ + featureCollection: grip4_africaLength, + color: 'lengthKm' +}).gt(0); + +Map.addLayer(grip4_africaRaster, { + palette: ['orange'], + max: 1 +}, 'Rasterized roads'); + +// Add reducer output to the features in the collection. +var AlgeriaRoadLength = ee.Image.pixelArea() + .addBands(grip4_africaRaster) + .reduceRegions({ + collection: Algeria, + reducer: ee.Reducer.sum(), + scale: 100, + }).map(function(feature) { + var num = ee.Number.parse(feature.get('area')); + return feature.set('length', num.divide(1000).sqrt() + .round()); + }); + +// Print the first feature to illustrate the result. +print('Length of all roads in Algeria calculated via rasters', ee + .Number(AlgeriaRoadLength.first().get('length'))); + +// Calculate line lengths for all roads in North America and Europe. +var grip4_north_americaLength = grip4_north_america.map(addLength); +var grip4_europeLength = grip4_europe.map(addLength); + +// Merge all vectors. +var roadLengthMerge = grip4_africaLength.merge( + grip4_north_americaLength).merge(grip4_europeLength); + +// Convert to raster. +var empty = ee.Image().float(); + +var roadLengthMergeRaster = empty.paint({ + featureCollection: roadLengthMerge, + color: 'roadsPerArea' +}).gt(0); + +// Filter to largest countries in Africa, North America and Europe. +var countriesSelected = countries.filter(ee.Filter.inList( + 'country_na', ['Algeria', 'Canada', 'France'])); + +// Clip image to only countries of analysis. +var roadLengthMergeRasterClipped = roadLengthMergeRaster + .clipToCollection(countriesSelected); + +// Add reducer output to the features in the collection. +var countriesRoadLength = ee.Image.pixelArea() + .addBands(roadLengthMergeRasterClipped) + .reduceRegions({ + collection: countriesSelected, + reducer: ee.Reducer.sum(), + scale: 100, + }).map(function(feature) { + var num = ee.Number.parse(feature.get('area')); + return feature.set('length', num.divide(1000).sqrt() + .round()); + }); + +// Compute totaled road lengths in km, grouped by country. +print('Length of all roads in Canada', countriesRoadLength.filter(ee + .Filter.equals('country_na', 'Canada')).aggregate_sum( + 'length')); +print('Length of all roads in France', countriesRoadLength.filter(ee + .Filter.equals('country_na', 'France')).aggregate_sum( + 'length')); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13c Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13c Checkpoint.py new file mode 100644 index 0000000..1eb3066 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13c Checkpoint.py @@ -0,0 +1,278 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.3 Built Environments +# Checkpoint: A13c +# Author: Erin Trochim +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import roads data. +grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe') + +# Check the roads data sizes. +print('Grip4 Africa size', grip4_africa.size()) +print('Grip4 North America size', grip4_north_america.size()) +print('Grip4 Europe size', grip4_europe.size()) + +# Display the roads data. +Map.addLayer(ee.FeatureCollection(grip4_africa).style(**{ + 'color': '413B3A', + 'width': 1 +}), {}, 'Grip4 Africa') +Map.addLayer(ee.FeatureCollection(grip4_north_america).style(**{ + 'color': '413B3A', + 'width': 1 +}), {}, 'Grip4 North America') +Map.addLayer(ee.FeatureCollection(grip4_europe).style(**{ + 'color': '413B3A', + 'width': 1 +}), {}, 'Grip4 Europe') + +# Import simplified countries. +countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + +# Add a function to calculate the feature's geometry area. +# Add the function as a property. +def addArea(feature): + return feature.set({ + 'areaKm': feature.geometry().area().divide(1000 * + 1000) + }); # km2 squared + + +# Map the area getting function over the FeatureCollection. +countriesArea = countries.map(addArea) + +# Filter to the largest country in Africa. +Algeria = countriesArea.filter(ee.Filter.inList('country_na', [ + 'Algeria' +])) + +# Display the selected countries. +Map.addLayer(Algeria.style(**{ + 'fillColor': 'b5ffb4', + 'color': '00909F', + 'width': 1.0 +}), {}, 'Algeria') + +# This function calculates the road length per country for the associated GRIP dataset. +def roadLength4Country(country, grip4): + + # Join roads to countries. + intersectsFilter = ee.Filter.intersects({ + 'leftField': '.geo', + 'rightField': '.geo', + 'maxError': 10 + }) + + grip4Selected = grip4.filterBounds(country) + + countriesWithRds = ee.Join.saveAll('roads').apply({ + 'primary': country, + 'secondary': grip4Selected, + 'condition': intersectsFilter + }).filter(ee.Filter.neq('roads', None)) + + # Return country with calculation of roadLength and roadsPerArea. + +def func_uge(country): + roadsList = ee.List(country.get('roads')) + roadLengths = roadsList.map(function(road) { + return ee.Feature(road).intersection( + country, 10).length(10) + }) + roadLength = ee.Number(roadLengths.reduce(ee \ + .Reducer.sum())) + return country.set({ + 'roadLength': roadLength.divide( + 1000), # Convert to km. + 'roadsPerArea': roadLength.divide(ee \ + .Number(country.get('areaKm')) + ) + }) + + return countriesWithRds.map(func_uge +).select(['country_na', 'areaKm', 'roadLength', + + + + + + + + + + + + + + +).select(['country_na', 'areaKm', 'roadLength', + 'roadsPerArea' + ]) + + +# Apply the road length function to Algeria. +roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa) + +# Print the road statistics for Algeria. +print('Roads statistics in Algeria', roadLengthAlgeria) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Export feature collection to drive. +Export.table.toDrive({ + 'collection': roadLengthAlgeria, + 'description': 'RoadStatisticsforAlgeria', + 'selectors': ['country_na', 'roadLength', 'roadsPerArea'] +}) + +# Print the first feature of the grip4 Africa feature collection. +print(grip4_africa.limit(1)) + +Map.setCenter(-0.759, 9.235, 6) +Map.addLayer(grip4_africa.limit(1), + {}, + 'Road length comparison') + +# This function adds line length in km. +def addLength(feature): + return feature.set({ + 'lengthKm': feature.length().divide(1000) + }) + + +# Calculate the line lengths for all roads in Africa. +grip4_africaLength = grip4_africa.map(addLength) + +# Compare with other values. +print('Calculated road length property', grip4_africaLength.limit(1)) + +# Repeat the analysis to calculate the length of all roads. +# Filter the table geographically: only keep roads in Algeria. +grip4_Algeria = grip4_africaLength.filterBounds(Algeria) + +# Visualize the output. +Map.addLayer(grip4_Algeria.style(**{ + 'color': 'green', + 'width': 2.0 +}), {}, 'Algeria roads') + +# Sum the lengths for roads in Algeria. +sumLengthKmAlgeria = ee.Number( + # Reduce to get the sum. + grip4_Algeria.reduceColumns(ee.Reducer.sum(), ['lengthKm']) \ + .get('sum') +) + +# Print the result. +print('Length of all roads in Algeria', sumLengthKmAlgeria) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Repeat the analysis again to calculate length of all roads using rasters. +# Convert to raster. +empty = ee.Image().float() + +grip4_africaRaster = empty.paint({ + 'featureCollection': grip4_africaLength, + 'color': 'lengthKm' +}).gt(0) + +Map.addLayer(grip4_africaRaster, { + 'palette': ['orange'], + 'max': 1 +}, 'Rasterized roads') + +# Add reducer output to the features in the collection. +AlgeriaRoadLength = ee.Image.pixelArea() \ + .addBands(grip4_africaRaster) \ + .reduceRegions({ + 'collection': Algeria, + 'reducer': ee.Reducer.sum(), + 'scale': 100, + +def func_ibk(feature): + num = ee.Number.parse(feature.get('area')) + return feature.set('length', num.divide(1000).sqrt() \ + .round()) + + }).map(func_ibk) + + + + + + +# Print the first feature to illustrate the result. +print('Length of all roads in Algeria calculated via rasters', ee \ + .Number(AlgeriaRoadLength.first().get('length'))) + +# Calculate line lengths for all roads in North America and Europe. +grip4_north_americaLength = grip4_north_america.map(addLength) +grip4_europeLength = grip4_europe.map(addLength) + +# Merge all vectors. +roadLengthMerge = grip4_africaLength.merge( + grip4_north_americaLength).merge(grip4_europeLength) + +# Convert to raster. +empty = ee.Image().float() + +roadLengthMergeRaster = empty.paint({ + 'featureCollection': roadLengthMerge, + 'color': 'roadsPerArea' +}).gt(0) + +# Filter to largest countries in Africa, North America and Europe. +countriesSelected = countries.filter(ee.Filter.inList( + 'country_na', ['Algeria', 'Canada', 'France'])) + +# Clip image to only countries of analysis. +roadLengthMergeRasterClipped = roadLengthMergeRaster \ + .clipToCollection(countriesSelected) + +# Add reducer output to the features in the collection. +countriesRoadLength = ee.Image.pixelArea() \ + .addBands(roadLengthMergeRasterClipped) \ + .reduceRegions({ + 'collection': countriesSelected, + 'reducer': ee.Reducer.sum(), + 'scale': 100, + +def func_fcu(feature): + num = ee.Number.parse(feature.get('area')) + return feature.set('length', num.divide(1000).sqrt() \ + .round()) + + }).map(func_fcu) + + + + + + +# Compute totaled road lengths in km, grouped by country. +print('Length of all roads in Canada', countriesRoadLength.filter(ee \ + .Filter.equals('country_na', 'Canada')).aggregate_sum( + 'length')) +print('Length of all roads in France', countriesRoadLength.filter(ee \ + .Filter.equals('country_na', 'France')).aggregate_sum( + 'length')) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13d Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13d Checkpoint.ipynb new file mode 100644 index 0000000..937509b --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13d Checkpoint.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.3 Built Environments\n", + "# Checkpoint: A13d\n", + "# Author: Erin Trochim\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import roads data.\n", + "grip4_africa = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Africa'),\n", + " grip4_europe = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Europe'),\n", + " grip4_north_america = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/North-America')\n", + "\n", + "# Add a function to add line length in km.\n", + "def addLength(feature):\n", + " return feature.set({\n", + " 'lengthKm': feature.length().divide(1000)\n", + " }); # km\n", + "\n", + "\n", + "# Calculate line lengths for all roads in Africa.\n", + "grip4_africaLength = grip4_africa.map(addLength)\n", + "\n", + "# Convert the roads to raster.\n", + "empty = ee.Image().float()\n", + "\n", + "grip4_africaRaster = empty.paint({\n", + " 'featureCollection': grip4_africaLength,\n", + " 'color': 'lengthKm'\n", + "})\n", + "\n", + "# Import simplified countries.\n", + "countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')\n", + "\n", + "# Filter to Africa.\n", + "Africa = countries.filter(ee.Filter.eq('wld_rgn', 'Africa'))\n", + "\n", + "# Import global power transmission lines.\n", + "transmission = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/predictive-global-power-system/distribution-transmission-lines'\n", + ")\n", + "\n", + "# Filter transmission lines to Africa.\n", + "transmissionAfrica = transmission.filterBounds(Africa)\n", + "\n", + "# Calculate line lengths for all transmission lines in Africa.\n", + "transmissionAfricaLength = transmissionAfrica.map(addLength)\n", + "\n", + "# Convert the transmission lines to raster.\n", + "transmissionAfricaRaster = empty.paint({\n", + " 'featureCollection': transmissionAfricaLength,\n", + " 'color': 'lengthKm'\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13d Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13d Checkpoint.js new file mode 100644 index 0000000..00d6b7b --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13d Checkpoint.js @@ -0,0 +1,58 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.3 Built Environments +// Checkpoint: A13d +// Author: Erin Trochim +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import roads data. +var grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'); + +// Add a function to add line length in km. +var addLength = function(feature) { + return feature.set({ + lengthKm: feature.length().divide(1000) + }); // km; +}; + +// Calculate line lengths for all roads in Africa. +var grip4_africaLength = grip4_africa.map(addLength); + +// Convert the roads to raster. +var empty = ee.Image().float(); + +var grip4_africaRaster = empty.paint({ + featureCollection: grip4_africaLength, + color: 'lengthKm' +}); + +// Import simplified countries. +var countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017'); + +// Filter to Africa. +var Africa = countries.filter(ee.Filter.eq('wld_rgn', 'Africa')); + +// Import global power transmission lines. +var transmission = ee.FeatureCollection( + 'projects/sat-io/open-datasets/predictive-global-power-system/distribution-transmission-lines' +); + +// Filter transmission lines to Africa. +var transmissionAfrica = transmission.filterBounds(Africa); + +// Calculate line lengths for all transmission lines in Africa. +var transmissionAfricaLength = transmissionAfrica.map(addLength); + +// Convert the transmission lines to raster. +var transmissionAfricaRaster = empty.paint({ + featureCollection: transmissionAfricaLength, + color: 'lengthKm' +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13d Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13d Checkpoint.py new file mode 100644 index 0000000..4f54319 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13d Checkpoint.py @@ -0,0 +1,64 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.3 Built Environments +# Checkpoint: A13d +# Author: Erin Trochim +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import roads data. +grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America') + +# Add a function to add line length in km. +def addLength(feature): + return feature.set({ + 'lengthKm': feature.length().divide(1000) + }); # km + + +# Calculate line lengths for all roads in Africa. +grip4_africaLength = grip4_africa.map(addLength) + +# Convert the roads to raster. +empty = ee.Image().float() + +grip4_africaRaster = empty.paint({ + 'featureCollection': grip4_africaLength, + 'color': 'lengthKm' +}) + +# Import simplified countries. +countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + +# Filter to Africa. +Africa = countries.filter(ee.Filter.eq('wld_rgn', 'Africa')) + +# Import global power transmission lines. +transmission = ee.FeatureCollection( + 'projects/sat-io/open-datasets/predictive-global-power-system/distribution-transmission-lines' +) + +# Filter transmission lines to Africa. +transmissionAfrica = transmission.filterBounds(Africa) + +# Calculate line lengths for all transmission lines in Africa. +transmissionAfricaLength = transmissionAfrica.map(addLength) + +# Convert the transmission lines to raster. +transmissionAfricaRaster = empty.paint({ + 'featureCollection': transmissionAfricaLength, + 'color': 'lengthKm' +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13e Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13e Checkpoint.ipynb new file mode 100644 index 0000000..b00a8b8 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13e Checkpoint.ipynb @@ -0,0 +1,214 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.3 Built Environments\n", + "# Checkpoint: A13e\n", + "# Author: Erin Trochim\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import roads data.\n", + "grip4_africa = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Africa'),\n", + " grip4_europe = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Europe'),\n", + " grip4_north_america = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/North-America')\n", + "\n", + "# Add a function to add line length in km.\n", + "def addLength(feature):\n", + " return feature.set({\n", + " 'lengthKm': feature.length().divide(1000)\n", + " }); # km\n", + "\n", + "\n", + "# Calculate line lengths for all roads in Africa.\n", + "grip4_africaLength = grip4_africa.map(addLength)\n", + "\n", + "# Convert the roads to raster.\n", + "empty = ee.Image().float()\n", + "\n", + "grip4_africaRaster = empty.paint({\n", + " 'featureCollection': grip4_africaLength,\n", + " 'color': 'lengthKm'\n", + "})\n", + "\n", + "# Import simplified countries.\n", + "countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')\n", + "\n", + "# Filter to Africa.\n", + "Africa = countries.filter(ee.Filter.eq('wld_rgn', 'Africa'))\n", + "\n", + "# Import global power transmission lines.\n", + "transmission = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/predictive-global-power-system/distribution-transmission-lines'\n", + ")\n", + "\n", + "# Filter transmission lines to Africa.\n", + "transmissionAfrica = transmission.filterBounds(Africa)\n", + "\n", + "# Calculate line lengths for all transmission lines in Africa.\n", + "transmissionAfricaLength = transmissionAfrica.map(addLength)\n", + "\n", + "# Convert the transmission lines to raster.\n", + "transmissionAfricaRaster = empty.paint({\n", + " 'featureCollection': transmissionAfricaLength,\n", + " 'color': 'lengthKm'\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Add roads and transmission lines together into one image.\n", + "# Clip to Africa feature collection.\n", + "stack = grip4_africaRaster \\\n", + " .addBands(transmissionAfricaRaster) \\\n", + " .rename(['roads', 'transmission']) \\\n", + " .clipToCollection(Africa)\n", + "\n", + "# Calculate spatial statistics: local Geary's C.\n", + "# Create a list of weights for a 9x9 kernel.\n", + "list = [1, 1, 1, 1, 1, 1, 1, 1, 1]\n", + "\n", + "# The center of the kernel is zero.\n", + "centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1]\n", + "\n", + "# Assemble a list of lists: the 9x9 kernel weights as a 2-D matrix.\n", + "lists = [list, list, list, list, centerList, list, list, list,\n", + " list\n", + "]\n", + "\n", + "# Create the kernel from the weights.\n", + "# Non-zero weights represent the spatial neighborhood.\n", + "kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, False)\n", + "\n", + "# Use the max among bands as the input.\n", + "maxBands = stack.reduce(ee.Reducer.max())\n", + "\n", + "# Convert the neighborhood into multiple bands.\n", + "neighs = maxBands.neighborhoodToBands(kernel)\n", + "\n", + "# Compute local Geary's C, a measure of spatial association\n", + "# - 0 indicates perfect positive autocorrelation/clustered\n", + "# - 1 indicates no autocorrelation/random\n", + "# - 2 indicates perfect negative autocorrelation/dispersed\n", + "gearys = maxBands.subtract(neighs).pow(2).reduce(ee.Reducer.sum()) \\\n", + " .divide(math.pow(9, 2))\n", + "\n", + "# Convert to a -/+1 scale by: calculating C* = 1 - C\n", + "# - 1 indicates perfect positive autocorrelation/clustered\n", + "# - 0 indicates no autocorrelation/random\n", + "# - -1 indicates perfect negative autocorrelation/dispersed\n", + "gearysStar = ee.Image(1).subtract(gearys)\n", + "\n", + "# Import palettes.\n", + "palettes = require('users/gena/packages:palettes')\n", + "\n", + "# Create custom palette, blue is negative while red is positive autocorrelation/clustered.\n", + "palette = palettes.colorbrewer.Spectral[7].reverse()\n", + "\n", + "# Normalize the image and add it to the map.\n", + "visParams = {\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': palette\n", + "}\n", + "\n", + "# Display the image.\n", + "Map.setCenter(19.8638, -34.5705, 10)\n", + "Map.addLayer(gearysStar.focalMax(1), visParams, 'local Gearys C*')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13e Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13e Checkpoint.js new file mode 100644 index 0000000..6cecf30 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13e Checkpoint.js @@ -0,0 +1,121 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.3 Built Environments +// Checkpoint: A13e +// Author: Erin Trochim +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import roads data. +var grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'); + +// Add a function to add line length in km. +var addLength = function(feature) { + return feature.set({ + lengthKm: feature.length().divide(1000) + }); // km; +}; + +// Calculate line lengths for all roads in Africa. +var grip4_africaLength = grip4_africa.map(addLength); + +// Convert the roads to raster. +var empty = ee.Image().float(); + +var grip4_africaRaster = empty.paint({ + featureCollection: grip4_africaLength, + color: 'lengthKm' +}); + +// Import simplified countries. +var countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017'); + +// Filter to Africa. +var Africa = countries.filter(ee.Filter.eq('wld_rgn', 'Africa')); + +// Import global power transmission lines. +var transmission = ee.FeatureCollection( + 'projects/sat-io/open-datasets/predictive-global-power-system/distribution-transmission-lines' +); + +// Filter transmission lines to Africa. +var transmissionAfrica = transmission.filterBounds(Africa); + +// Calculate line lengths for all transmission lines in Africa. +var transmissionAfricaLength = transmissionAfrica.map(addLength); + +// Convert the transmission lines to raster. +var transmissionAfricaRaster = empty.paint({ + featureCollection: transmissionAfricaLength, + color: 'lengthKm' +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Add roads and transmission lines together into one image. +// Clip to Africa feature collection. +var stack = grip4_africaRaster + .addBands(transmissionAfricaRaster) + .rename(['roads', 'transmission']) + .clipToCollection(Africa); + +// Calculate spatial statistics: local Geary's C. +// Create a list of weights for a 9x9 kernel. +var list = [1, 1, 1, 1, 1, 1, 1, 1, 1]; + +// The center of the kernel is zero. +var centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1]; + +// Assemble a list of lists: the 9x9 kernel weights as a 2-D matrix. +var lists = [list, list, list, list, centerList, list, list, list, + list +]; + +// Create the kernel from the weights. +// Non-zero weights represent the spatial neighborhood. +var kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, false); + +// Use the max among bands as the input. +var maxBands = stack.reduce(ee.Reducer.max()); + +// Convert the neighborhood into multiple bands. +var neighs = maxBands.neighborhoodToBands(kernel); + +// Compute local Geary's C, a measure of spatial association +// - 0 indicates perfect positive autocorrelation/clustered +// - 1 indicates no autocorrelation/random +// - 2 indicates perfect negative autocorrelation/dispersed +var gearys = maxBands.subtract(neighs).pow(2).reduce(ee.Reducer.sum()) + .divide(Math.pow(9, 2)); + +// Convert to a -/+1 scale by: calculating C* = 1 - C +// - 1 indicates perfect positive autocorrelation/clustered +// - 0 indicates no autocorrelation/random +// - -1 indicates perfect negative autocorrelation/dispersed +var gearysStar = ee.Image(1).subtract(gearys); + +// Import palettes. +var palettes = require('users/gena/packages:palettes'); + +// Create custom palette, blue is negative while red is positive autocorrelation/clustered. +var palette = palettes.colorbrewer.Spectral[7].reverse(); + +// Normalize the image and add it to the map. +var visParams = { + min: -1, + max: 1, + palette: palette +}; + +// Display the image. +Map.setCenter(19.8638, -34.5705, 10); +Map.addLayer(gearysStar.focalMax(1), visParams, 'local Gearys C*'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13e Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13e Checkpoint.py new file mode 100644 index 0000000..321a950 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13e Checkpoint.py @@ -0,0 +1,128 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.3 Built Environments +# Checkpoint: A13e +# Author: Erin Trochim +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import roads data. +grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'), + grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe'), + grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America') + +# Add a function to add line length in km. +def addLength(feature): + return feature.set({ + 'lengthKm': feature.length().divide(1000) + }); # km + + +# Calculate line lengths for all roads in Africa. +grip4_africaLength = grip4_africa.map(addLength) + +# Convert the roads to raster. +empty = ee.Image().float() + +grip4_africaRaster = empty.paint({ + 'featureCollection': grip4_africaLength, + 'color': 'lengthKm' +}) + +# Import simplified countries. +countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + +# Filter to Africa. +Africa = countries.filter(ee.Filter.eq('wld_rgn', 'Africa')) + +# Import global power transmission lines. +transmission = ee.FeatureCollection( + 'projects/sat-io/open-datasets/predictive-global-power-system/distribution-transmission-lines' +) + +# Filter transmission lines to Africa. +transmissionAfrica = transmission.filterBounds(Africa) + +# Calculate line lengths for all transmission lines in Africa. +transmissionAfricaLength = transmissionAfrica.map(addLength) + +# Convert the transmission lines to raster. +transmissionAfricaRaster = empty.paint({ + 'featureCollection': transmissionAfricaLength, + 'color': 'lengthKm' +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Add roads and transmission lines together into one image. +# Clip to Africa feature collection. +stack = grip4_africaRaster \ + .addBands(transmissionAfricaRaster) \ + .rename(['roads', 'transmission']) \ + .clipToCollection(Africa) + +# Calculate spatial statistics: local Geary's C. +# Create a list of weights for a 9x9 kernel. +list = [1, 1, 1, 1, 1, 1, 1, 1, 1] + +# The center of the kernel is zero. +centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1] + +# Assemble a list of lists: the 9x9 kernel weights as a 2-D matrix. +lists = [list, list, list, list, centerList, list, list, list, + list +] + +# Create the kernel from the weights. +# Non-zero weights represent the spatial neighborhood. +kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, False) + +# Use the max among bands as the input. +maxBands = stack.reduce(ee.Reducer.max()) + +# Convert the neighborhood into multiple bands. +neighs = maxBands.neighborhoodToBands(kernel) + +# Compute local Geary's C, a measure of spatial association +# - 0 indicates perfect positive autocorrelation/clustered +# - 1 indicates no autocorrelation/random +# - 2 indicates perfect negative autocorrelation/dispersed +gearys = maxBands.subtract(neighs).pow(2).reduce(ee.Reducer.sum()) \ + .divide(math.pow(9, 2)) + +# Convert to a -/+1 scale by: calculating C* = 1 - C +# - 1 indicates perfect positive autocorrelation/clustered +# - 0 indicates no autocorrelation/random +# - -1 indicates perfect negative autocorrelation/dispersed +gearysStar = ee.Image(1).subtract(gearys) + +# Import palettes. +palettes = require('users/gena/packages:palettes') + +# Create custom palette, blue is negative while red is positive autocorrelation/clustered. +palette = palettes.colorbrewer.Spectral[7].reverse() + +# Normalize the image and add it to the map. +visParams = { + 'min': -1, + 'max': 1, + 'palette': palette +} + +# Display the image. +Map.setCenter(19.8638, -34.5705, 10) +Map.addLayer(gearysStar.focalMax(1), visParams, 'local Gearys C*') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13f Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13f Checkpoint.ipynb new file mode 100644 index 0000000..3736a8e --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13f Checkpoint.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.3 Built Environments\n", + "# Checkpoint: A13f\n", + "# Author: Erin Trochim\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import Tsinghua FROM-GLC Year of Change to Impervious Surface\n", + "impervious = ee.Image('Tsinghua/FROM-GLC/GAIA/v10')\n", + "\n", + "# Use the change year values found in the band.\n", + "# The change year values is described here:\n", + "# https:#developers.google.com/earth-engine/datasets/catalog/Tsinghua_FROM-GLC_GAIA_v10#bands\n", + "# Select only those areas which were impervious by 2000.\n", + "impervious2000 = impervious.gte(19)\n", + "\n", + "# Select only those areas which were impervious by 2018.\n", + "impervious2018 = impervious.gte(1)\n", + "\n", + "Map.setCenter(-98.688, 39.134, 5)\n", + "\n", + "# Display the images.\n", + "Map.addLayer(\n", + " impervious2000.selfMask(),\n", + " {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['014352', '856F96']\n", + " },\n", + " 'Impervious Surface 2000')\n", + "\n", + "Map.addLayer(\n", + " impervious2018.selfMask(),\n", + " {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['014352', '1A492C']\n", + " },\n", + " 'Impervious Surface 2018')\n", + "\n", + "# Calculate the difference between impervious areas in 2000 and 2018.\n", + "imperviousDiff = impervious2018.subtract(impervious2000)\n", + "\n", + "Map.addLayer(\n", + " imperviousDiff.selfMask(),\n", + " {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['014352', 'FFBF00']\n", + " },\n", + " 'Impervious Surface Diff 2000-18')\n", + "\n", + "# Import the Global Flood Database v1 (2000-2018).\n", + "gfd = ee.ImageCollection('GLOBAL_FLOOD_DB/MODIS_EVENTS/V1')\n", + "\n", + "# Map all floods to generate the satellite-observed historical flood plain.\n", + "gfdFloodedSum = gfd.select('flooded').sum()\n", + "\n", + "# Mask out areas of permanent water.\n", + "gfdFloodedSumNoWater = gfdFloodedSum.updateMask(gfd.select(\n", + " 'jrc_perm_water').sum().lt(1))\n", + "\n", + "durationPalette = ['C3EFFE', '1341E8', '051CB0', '001133']\n", + "\n", + "Map.addLayer(\n", + " gfdFloodedSumNoWater.selfMask(),\n", + " {\n", + " 'min': 0,\n", + " 'max': 10,\n", + " 'palette': durationPalette\n", + " },\n", + " 'GFD Satellite Observed Flood Plain')\n", + "\n", + "# Mask areas in the impervious difference image that are not in flood plains.\n", + "imperviousDiffFloods = imperviousDiff \\\n", + " .updateMask(gfdFloodedSumNoWater.gte(1))\n", + "\n", + "# Which state has built the most area in the flood plains?\n", + "# Import FAO countries with first level administrative units.\n", + "countries = ee.FeatureCollection('FAO/GAUL/2015/level1')\n", + "\n", + "# Filter to the United States.\n", + "unitedStates = countries.filter(ee.Filter.eq('ADM0_NAME',\n", + " 'United States of America'))\n", + "\n", + "# Calculate the image area.\n", + "areaImage = imperviousDiffFloods.multiply(ee.Image.pixelArea())\n", + "\n", + "# Sum the area image for each state.\n", + "unitedStatesImperviousDiffFlood = areaImage.reduceRegions({\n", + " 'collection': unitedStates,\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'scale': 100,\n", + " }) # Sort descending. \\\n", + " .sort('sum', False) \\\n", + " .limit(5)\n", + "\n", + "# Print state statistics for change in impervious area in flood plain.\n", + "print('Impervious-flood change statistics for states in US',\n", + " unitedStatesImperviousDiffFlood)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13f Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13f Checkpoint.js new file mode 100644 index 0000000..f44293a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13f Checkpoint.js @@ -0,0 +1,104 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.3 Built Environments +// Checkpoint: A13f +// Author: Erin Trochim +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import Tsinghua FROM-GLC Year of Change to Impervious Surface +var impervious = ee.Image('Tsinghua/FROM-GLC/GAIA/v10'); + +// Use the change year values found in the band. +// The change year values is described here: +// https://developers.google.com/earth-engine/datasets/catalog/Tsinghua_FROM-GLC_GAIA_v10#bands +// Select only those areas which were impervious by 2000. +var impervious2000 = impervious.gte(19); + +// Select only those areas which were impervious by 2018. +var impervious2018 = impervious.gte(1); + +Map.setCenter(-98.688, 39.134, 5); + +// Display the images. +Map.addLayer( + impervious2000.selfMask(), + { + min: 0, + max: 1, + palette: ['014352', '856F96'] + }, + 'Impervious Surface 2000'); + +Map.addLayer( + impervious2018.selfMask(), + { + min: 0, + max: 1, + palette: ['014352', '1A492C'] + }, + 'Impervious Surface 2018'); + +// Calculate the difference between impervious areas in 2000 and 2018. +var imperviousDiff = impervious2018.subtract(impervious2000); + +Map.addLayer( + imperviousDiff.selfMask(), + { + min: 0, + max: 1, + palette: ['014352', 'FFBF00'] + }, + 'Impervious Surface Diff 2000-18'); + +// Import the Global Flood Database v1 (2000-2018). +var gfd = ee.ImageCollection('GLOBAL_FLOOD_DB/MODIS_EVENTS/V1'); + +// Map all floods to generate the satellite-observed historical flood plain. +var gfdFloodedSum = gfd.select('flooded').sum(); + +// Mask out areas of permanent water. +var gfdFloodedSumNoWater = gfdFloodedSum.updateMask(gfd.select( + 'jrc_perm_water').sum().lt(1)); + +var durationPalette = ['C3EFFE', '1341E8', '051CB0', '001133']; + +Map.addLayer( + gfdFloodedSumNoWater.selfMask(), + { + min: 0, + max: 10, + palette: durationPalette + }, + 'GFD Satellite Observed Flood Plain'); + +// Mask areas in the impervious difference image that are not in flood plains. +var imperviousDiffFloods = imperviousDiff + .updateMask(gfdFloodedSumNoWater.gte(1)); + +// Which state has built the most area in the flood plains? +// Import FAO countries with first level administrative units. +var countries = ee.FeatureCollection('FAO/GAUL/2015/level1'); + +// Filter to the United States. +var unitedStates = countries.filter(ee.Filter.eq('ADM0_NAME', + 'United States of America')); + +// Calculate the image area. +var areaImage = imperviousDiffFloods.multiply(ee.Image.pixelArea()); + +// Sum the area image for each state. +var unitedStatesImperviousDiffFlood = areaImage.reduceRegions({ + collection: unitedStates, + reducer: ee.Reducer.sum(), + scale: 100, + }) // Sort descending. + .sort('sum', false) + // Get only the 5 highest states. + .limit(5); + +// Print state statistics for change in impervious area in flood plain. +print('Impervious-flood change statistics for states in US', + unitedStatesImperviousDiffFlood); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13f Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13f Checkpoint.py new file mode 100644 index 0000000..a457da1 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A13f Checkpoint.py @@ -0,0 +1,109 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.3 Built Environments +# Checkpoint: A13f +# Author: Erin Trochim +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import Tsinghua FROM-GLC Year of Change to Impervious Surface +impervious = ee.Image('Tsinghua/FROM-GLC/GAIA/v10') + +# Use the change year values found in the band. +# The change year values is described here: +# https:#developers.google.com/earth-engine/datasets/catalog/Tsinghua_FROM-GLC_GAIA_v10#bands +# Select only those areas which were impervious by 2000. +impervious2000 = impervious.gte(19) + +# Select only those areas which were impervious by 2018. +impervious2018 = impervious.gte(1) + +Map.setCenter(-98.688, 39.134, 5) + +# Display the images. +Map.addLayer( + impervious2000.selfMask(), + { + 'min': 0, + 'max': 1, + 'palette': ['014352', '856F96'] + }, + 'Impervious Surface 2000') + +Map.addLayer( + impervious2018.selfMask(), + { + 'min': 0, + 'max': 1, + 'palette': ['014352', '1A492C'] + }, + 'Impervious Surface 2018') + +# Calculate the difference between impervious areas in 2000 and 2018. +imperviousDiff = impervious2018.subtract(impervious2000) + +Map.addLayer( + imperviousDiff.selfMask(), + { + 'min': 0, + 'max': 1, + 'palette': ['014352', 'FFBF00'] + }, + 'Impervious Surface Diff 2000-18') + +# Import the Global Flood Database v1 (2000-2018). +gfd = ee.ImageCollection('GLOBAL_FLOOD_DB/MODIS_EVENTS/V1') + +# Map all floods to generate the satellite-observed historical flood plain. +gfdFloodedSum = gfd.select('flooded').sum() + +# Mask out areas of permanent water. +gfdFloodedSumNoWater = gfdFloodedSum.updateMask(gfd.select( + 'jrc_perm_water').sum().lt(1)) + +durationPalette = ['C3EFFE', '1341E8', '051CB0', '001133'] + +Map.addLayer( + gfdFloodedSumNoWater.selfMask(), + { + 'min': 0, + 'max': 10, + 'palette': durationPalette + }, + 'GFD Satellite Observed Flood Plain') + +# Mask areas in the impervious difference image that are not in flood plains. +imperviousDiffFloods = imperviousDiff \ + .updateMask(gfdFloodedSumNoWater.gte(1)) + +# Which state has built the most area in the flood plains? +# Import FAO countries with first level administrative units. +countries = ee.FeatureCollection('FAO/GAUL/2015/level1') + +# Filter to the United States. +unitedStates = countries.filter(ee.Filter.eq('ADM0_NAME', + 'United States of America')) + +# Calculate the image area. +areaImage = imperviousDiffFloods.multiply(ee.Image.pixelArea()) + +# Sum the area image for each state. +unitedStatesImperviousDiffFlood = areaImage.reduceRegions({ + 'collection': unitedStates, + 'reducer': ee.Reducer.sum(), + 'scale': 100, + }) # Sort descending. \ + .sort('sum', False) \ + .limit(5) + +# Print state statistics for change in impervious area in flood plain. +print('Impervious-flood change statistics for states in US', + unitedStatesImperviousDiffFlood) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s1 Exercise 1.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s1 Exercise 1.ipynb new file mode 100644 index 0000000..3c0b48a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s1 Exercise 1.ipynb @@ -0,0 +1,314 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# Import roads.\n", + "grip4_africa = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Africa')\n", + "grip4_europe = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Europe')\n", + "grip4_north_america = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/North-America')\n", + "\n", + "# Check sizes\n", + "print('Grip4 Africa size', grip4_africa.size())\n", + "print('Grip4 North America size', grip4_north_america.size())\n", + "print('Grip4 Europe size', grip4_europe.size())\n", + "\n", + "Map.setCenter(3.6, 32.5, 11)\n", + "\n", + "# Display roads\n", + "Map.addLayer(grip4_africa.style(**{'color': '413B3A', 'width':1}),\n", + " {},\n", + " 'Grip4 Africa')\n", + "Map.addLayer(grip4_north_america.style(**{'color': '413B3A', 'width':1}),\n", + " {},\n", + " 'Grip4 North America')\n", + "Map.addLayer(grip4_europe.style(**{'color': '413B3A', 'width':1}),\n", + " {},\n", + " 'Grip4 Europe')\n", + "\n", + "# Import simplified countries\n", + "countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')\n", + "\n", + "# Function to calculate feature's geometry area and adds it as a property\n", + "def addArea(feature):\n", + " return feature.set({\n", + " 'areaKm': feature.geometry().area().divide(1000 * 1000) # km2 squared\n", + " })\n", + "\n", + "\n", + "# Map the area getting function over the FeatureCollection.\n", + "countriesArea = countries.map(addArea)\n", + "\n", + "# Filter to largest country in Africa\n", + "Algeria = countriesArea.filter(ee.Filter.inList('country_na', ['Algeria']))\n", + "\n", + "# Display selected countries\n", + "Map.addLayer(Algeria.style(**{'fillColor': 'b5ffb4', 'color': '00909F', 'width': 1.0}),\n", + " {},\n", + " 'Algeria')\n", + "\n", + "# Calculate road length per country for the associated GRIP dataset.\n", + "def roadLength4Country(country, grip4):\n", + "\n", + " # Join roads to countries\n", + " interesectsFilter = ee.Filter.intersects({\n", + " 'leftField': '.geo',\n", + " 'rightField': '.geo',\n", + " 'maxError': 10\n", + " })\n", + "\n", + " grip4Selected = grip4.filterBounds(country)\n", + "\n", + " countriesWithRds = ee.Join.saveAll('roads').apply({\n", + " 'primary': country,\n", + " 'secondary': grip4Selected,\n", + " 'condition': interesectsFilter\n", + " }).filter(ee.Filter.neq('roads', None))\n", + "\n", + " # Return country with road length and roads per km square km set\n", + "\n", + "def func_ibq(country):\n", + " roadsList = ee.List(country.get('roads'))\n", + " roadLengths = roadsList.map(function(road) {\n", + " return ee.Feature(road).intersection(country, 10).length(10)\n", + " })\n", + " roadLength = ee.Number(roadLengths.reduce(ee.Reducer.sum()))\n", + " return country.set({\n", + " 'roadLength': roadLength.divide(1000), # Convert to km\n", + " 'roadsPerArea': roadLength.divide(ee.Number(country.get('areaKm')))\n", + " })\n", + "\n", + " return countriesWithRds.map(func_ibq\n", + ").select(['country_na', 'areaKm','roadLength', 'roadsPerArea'])\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").select(['country_na', 'areaKm','roadLength', 'roadsPerArea'])\n", + "\n", + "\n", + "# Apply road length function to Algeria\n", + "roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa)\n", + "\n", + "# Print statics for Algeria for roads per area\n", + "print('Roads statistics in Algeria', roadLengthAlgeria)\n", + "\n", + "# Function to add line length in km\n", + "def addLength(feature):\n", + " return feature.set({\n", + " 'lengthKm': feature.length().divide(1000) # km squared\n", + " })\n", + "\n", + "\n", + "# Calculate line lengths for all roads in Africa\n", + "grip4_africaLength = grip4_africa.map(addLength)\n", + "\n", + "# Compare with other value\n", + "print(grip4_africaLength.limit(1))\n", + "\n", + "# Repeat analysis to calculate length of all roads\n", + "# Filter the table geographically: only keep roads in Algeria\n", + "grip4_Algeria = grip4_africaLength.filterBounds(Algeria)\n", + "\n", + "# Visualize the output\n", + "Map.addLayer(grip4_Algeria.style(**{'color': 'green', 'width': 2.0}),\n", + " {},\n", + " 'Algeria roads')\n", + "\n", + "# Sum the lengths for roads in Algeria\n", + "sumLengthKmAlgeria = ee.Number(\n", + " # Reduce to get the sum\n", + " grip4_Algeria.reduceColumns(ee.Reducer.sum(), ['lengthKm']) \\\n", + " .get('sum')\n", + ")\n", + "\n", + "# Print the result\n", + "print('Length of all roads in Algeria', sumLengthKmAlgeria)\n", + "\n", + "# Repeat analysis again to calculate length of all roads using rasters\n", + "# Convert to raster\n", + "empty = ee.Image().float()\n", + "\n", + "grip4_africaRaster = empty.paint({\n", + " 'featureCollection': grip4_africaLength,\n", + " 'color': 'lengthKm'\n", + "}).gt(0)\n", + "\n", + "Map.addLayer(grip4_africaRaster,\n", + " {'palette': ['orange'], 'max': 1},\n", + " 'Rasterized roads')\n", + "\n", + "# Add reducer output to the Features in the collection.\n", + "AlgeriaRoadLength = ee.Image.pixelArea() \\\n", + " .addBands(grip4_africaRaster) \\\n", + " .reduceRegions({\n", + " 'collection': Algeria,\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'scale': 100,\n", + "\n", + "def func_bks(feature):\n", + " num = ee.Number.parse(feature.get('area'))\n", + " return feature.set('length', num.divide(1000).sqrt().round())\n", + "\n", + "}).map(func_bks)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Print the first feature, to illustrate the result.\n", + "print('Length of all roads in Algeria calculated via rasters',\n", + " ee.Number(AlgeriaRoadLength.first().get('length')))\n", + "\n", + "# Calculate line lengths for all roads in North America and Europe\n", + "grip4_north_americaLength = grip4_north_america.map(addLength)\n", + "grip4_europeLength = grip4_europe.map(addLength)\n", + "\n", + "# Merge vectors\n", + "roadLengthMerge = grip4_africaLength.merge(grip4_north_americaLength) \\\n", + " .merge(grip4_europeLength)\n", + "\n", + "# Convert to raster\n", + "empty = ee.Image().float()\n", + "\n", + "roadLengthMergeRaster = empty.paint({\n", + " 'featureCollection': roadLengthMerge,\n", + " 'color': 'roadsPerArea'\n", + "}).gt(0)\n", + "\n", + "# Filter to largest countries in Africa, North America and Europe\n", + "countriesSelected = countries \\\n", + " .filter(ee.Filter.inList('country_na', ['Algeria', 'Canada', 'France']))\n", + "\n", + "# Clip image to only countries of analysis\n", + "roadLengthMergeRasterClipped = roadLengthMergeRaster \\\n", + " .clipToCollection(countriesSelected)\n", + "\n", + "# Add reducer output to the Features in the collection.\n", + "countriesRoadLength = ee.Image.pixelArea() \\\n", + " .addBands(roadLengthMergeRasterClipped) \\\n", + " .reduceRegions({\n", + " 'collection': countriesSelected,\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'scale': 100,\n", + "\n", + "def func_fgy(feature):\n", + " num = ee.Number.parse(feature.get('area'))\n", + " return feature.set('length', num.divide(1000).sqrt().round())\n", + "\n", + "}).map(func_fgy)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Compute totaled road lengths in km, grouped by country\n", + "print('Length of all roads in Canada',\n", + " countriesRoadLength.filter(ee.Filter.equals('country_na', 'Canada')) \\\n", + " .aggregate_sum('length'))\n", + "print('Length of all roads in France',\n", + " countriesRoadLength.filter(ee.Filter.equals('country_na', 'France')) \\\n", + " .aggregate_sum('length'))\n", + "\n", + "# Examine effect of scale on raster\n", + "Map.addLayer(grip4_africaRaster.reproject({'crs': 'EPSG:4326', 'scale': 100}),\n", + " {'palette': ['orange'], 'max': 1},\n", + " 'Rasterized roads 100 m')\n", + "\n", + "# LGTM (nclinton). Reformatted. Added a setCenter." + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s1 Exercise 1.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s1 Exercise 1.js new file mode 100644 index 0000000..367cf2b --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s1 Exercise 1.js @@ -0,0 +1,196 @@ +// Import roads. +var grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'); +var grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe'); +var grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'); + +// Check sizes +print('Grip4 Africa size', grip4_africa.size()) +print('Grip4 North America size', grip4_north_america.size()) +print('Grip4 Europe size', grip4_europe.size()) + +Map.setCenter(3.6, 32.5, 11) + +// Display roads +Map.addLayer(grip4_africa.style({color: '413B3A',width:1}), + {}, + 'Grip4 Africa') +Map.addLayer(grip4_north_america.style({color: '413B3A',width:1}), + {}, + 'Grip4 North America') +Map.addLayer(grip4_europe.style({color: '413B3A',width:1}), + {}, + 'Grip4 Europe') + +// Import simplified countries +var countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + +// Function to calculate feature's geometry area and adds it as a property +var addArea = function(feature) { + return feature.set({ + areaKm: feature.geometry().area().divide(1000 * 1000) // km2 squared + }) +}; + +// Map the area getting function over the FeatureCollection. +var countriesArea = countries.map(addArea); + +// Filter to largest country in Africa +var Algeria = countriesArea.filter(ee.Filter.inList('country_na', ['Algeria'])) + +// Display selected countries +Map.addLayer(Algeria.style({fillColor: 'b5ffb4', color: '00909F', width: 1.0}), + {}, + 'Algeria') + +// Calculate road length per country for the associated GRIP dataset. +var roadLength4Country = function(country, grip4) { + + // Join roads to countries + var interesectsFilter = ee.Filter.intersects({ + leftField: '.geo', + rightField: '.geo', + maxError: 10 + }); + + var grip4Selected = grip4.filterBounds(country) + + var countriesWithRds = ee.Join.saveAll('roads').apply({ + primary: country, + secondary: grip4Selected, + condition: interesectsFilter + }).filter(ee.Filter.neq('roads', null)); + + // Return country with road length and roads per km square km set + return countriesWithRds.map(function(country) { + var roadsList = ee.List(country.get('roads')); + var roadLengths = roadsList.map(function(road) { + return ee.Feature(road).intersection(country, 10).length(10); + }); + var roadLength = ee.Number(roadLengths.reduce(ee.Reducer.sum())); + return country.set({ + roadLength: roadLength.divide(1000), // Convert to km + roadsPerArea: roadLength.divide(ee.Number(country.get('areaKm'))) + }); + }).select(['country_na', 'areaKm','roadLength', 'roadsPerArea']); +} + +// Apply road length function to Algeria +var roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa) + +// Print statics for Algeria for roads per area +print('Roads statistics in Algeria', roadLengthAlgeria); + +// Function to add line length in km +var addLength = function(feature) { + return feature.set({ + lengthKm: feature.length().divide(1000) // km squared + }) +}; + +// Calculate line lengths for all roads in Africa +var grip4_africaLength = grip4_africa.map(addLength) + +// Compare with other value +print(grip4_africaLength.limit(1)) + +// Repeat analysis to calculate length of all roads +// Filter the table geographically: only keep roads in Algeria +var grip4_Algeria = grip4_africaLength.filterBounds(Algeria); + +// Visualize the output +Map.addLayer(grip4_Algeria.style({color: 'green', width: 2.0}), + {}, + 'Algeria roads') + +// Sum the lengths for roads in Algeria +var sumLengthKmAlgeria = ee.Number( + // Reduce to get the sum + grip4_Algeria.reduceColumns(ee.Reducer.sum(), ['lengthKm']) + .get('sum') +) + +// Print the result +print('Length of all roads in Algeria', sumLengthKmAlgeria); + +// Repeat analysis again to calculate length of all roads using rasters +// Convert to raster +var empty = ee.Image().float(); + +var grip4_africaRaster = empty.paint({ + featureCollection: grip4_africaLength, + color: 'lengthKm' +}).gt(0); + +Map.addLayer(grip4_africaRaster, + {palette: ['orange'], max: 1}, + 'Rasterized roads') + +// Add reducer output to the Features in the collection. +var AlgeriaRoadLength = ee.Image.pixelArea() + .addBands(grip4_africaRaster) + .reduceRegions({ + collection: Algeria, + reducer: ee.Reducer.sum(), + scale: 100, +}).map(function(feature){ + var num = ee.Number.parse(feature.get('area')); + return feature.set('length', num.divide(1000).sqrt().round()); +}); + +// Print the first feature, to illustrate the result. +print('Length of all roads in Algeria calculated via rasters', + ee.Number(AlgeriaRoadLength.first().get('length'))); + +// Calculate line lengths for all roads in North America and Europe +var grip4_north_americaLength = grip4_north_america.map(addLength) +var grip4_europeLength = grip4_europe.map(addLength) + +// Merge vectors +var roadLengthMerge = grip4_africaLength.merge(grip4_north_americaLength) + .merge(grip4_europeLength) + +// Convert to raster +var empty = ee.Image().float(); + +var roadLengthMergeRaster = empty.paint({ + featureCollection: roadLengthMerge, + color: 'roadsPerArea' +}).gt(0); + +// Filter to largest countries in Africa, North America and Europe +var countriesSelected = countries + .filter(ee.Filter.inList('country_na', ['Algeria', 'Canada', 'France'])) + +// Clip image to only countries of analysis +var roadLengthMergeRasterClipped = roadLengthMergeRaster + .clipToCollection(countriesSelected) + +// Add reducer output to the Features in the collection. +var countriesRoadLength = ee.Image.pixelArea() + .addBands(roadLengthMergeRasterClipped) + .reduceRegions({ + collection: countriesSelected, + reducer: ee.Reducer.sum(), + scale: 100, +}).map(function(feature){ + var num = ee.Number.parse(feature.get('area')); + return feature.set('length', num.divide(1000).sqrt().round()); +}); + +// Compute totaled road lengths in km, grouped by country +print('Length of all roads in Canada', + countriesRoadLength.filter(ee.Filter.equals('country_na', 'Canada')) + .aggregate_sum('length')); +print('Length of all roads in France', + countriesRoadLength.filter(ee.Filter.equals('country_na', 'France')) + .aggregate_sum('length')); + +// Examine effect of scale on raster +Map.addLayer(grip4_africaRaster.reproject({crs: 'EPSG:4326', scale: 100}), + {palette: ['orange'], max: 1}, + 'Rasterized roads 100 m') + +// LGTM (nclinton). Reformatted. Added a setCenter. \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s1 Exercise 1.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s1 Exercise 1.py new file mode 100644 index 0000000..8a20e4a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s1 Exercise 1.py @@ -0,0 +1,227 @@ +import ee +import geemap + +Map = geemap.Map() + +# Import roads. +grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa') +grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe') +grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America') + +# Check sizes +print('Grip4 Africa size', grip4_africa.size()) +print('Grip4 North America size', grip4_north_america.size()) +print('Grip4 Europe size', grip4_europe.size()) + +Map.setCenter(3.6, 32.5, 11) + +# Display roads +Map.addLayer(grip4_africa.style(**{'color': '413B3A', 'width':1}), + {}, + 'Grip4 Africa') +Map.addLayer(grip4_north_america.style(**{'color': '413B3A', 'width':1}), + {}, + 'Grip4 North America') +Map.addLayer(grip4_europe.style(**{'color': '413B3A', 'width':1}), + {}, + 'Grip4 Europe') + +# Import simplified countries +countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + +# Function to calculate feature's geometry area and adds it as a property +def addArea(feature): + return feature.set({ + 'areaKm': feature.geometry().area().divide(1000 * 1000) # km2 squared + }) + + +# Map the area getting function over the FeatureCollection. +countriesArea = countries.map(addArea) + +# Filter to largest country in Africa +Algeria = countriesArea.filter(ee.Filter.inList('country_na', ['Algeria'])) + +# Display selected countries +Map.addLayer(Algeria.style(**{'fillColor': 'b5ffb4', 'color': '00909F', 'width': 1.0}), + {}, + 'Algeria') + +# Calculate road length per country for the associated GRIP dataset. +def roadLength4Country(country, grip4): + + # Join roads to countries + interesectsFilter = ee.Filter.intersects({ + 'leftField': '.geo', + 'rightField': '.geo', + 'maxError': 10 + }) + + grip4Selected = grip4.filterBounds(country) + + countriesWithRds = ee.Join.saveAll('roads').apply({ + 'primary': country, + 'secondary': grip4Selected, + 'condition': interesectsFilter + }).filter(ee.Filter.neq('roads', None)) + + # Return country with road length and roads per km square km set + +def func_ibq(country): + roadsList = ee.List(country.get('roads')) + roadLengths = roadsList.map(function(road) { + return ee.Feature(road).intersection(country, 10).length(10) + }) + roadLength = ee.Number(roadLengths.reduce(ee.Reducer.sum())) + return country.set({ + 'roadLength': roadLength.divide(1000), # Convert to km + 'roadsPerArea': roadLength.divide(ee.Number(country.get('areaKm'))) + }) + + return countriesWithRds.map(func_ibq +).select(['country_na', 'areaKm','roadLength', 'roadsPerArea']) + + + + + + + + + +).select(['country_na', 'areaKm','roadLength', 'roadsPerArea']) + + +# Apply road length function to Algeria +roadLengthAlgeria = roadLength4Country(Algeria, grip4_africa) + +# Print statics for Algeria for roads per area +print('Roads statistics in Algeria', roadLengthAlgeria) + +# Function to add line length in km +def addLength(feature): + return feature.set({ + 'lengthKm': feature.length().divide(1000) # km squared + }) + + +# Calculate line lengths for all roads in Africa +grip4_africaLength = grip4_africa.map(addLength) + +# Compare with other value +print(grip4_africaLength.limit(1)) + +# Repeat analysis to calculate length of all roads +# Filter the table geographically: only keep roads in Algeria +grip4_Algeria = grip4_africaLength.filterBounds(Algeria) + +# Visualize the output +Map.addLayer(grip4_Algeria.style(**{'color': 'green', 'width': 2.0}), + {}, + 'Algeria roads') + +# Sum the lengths for roads in Algeria +sumLengthKmAlgeria = ee.Number( + # Reduce to get the sum + grip4_Algeria.reduceColumns(ee.Reducer.sum(), ['lengthKm']) \ + .get('sum') +) + +# Print the result +print('Length of all roads in Algeria', sumLengthKmAlgeria) + +# Repeat analysis again to calculate length of all roads using rasters +# Convert to raster +empty = ee.Image().float() + +grip4_africaRaster = empty.paint({ + 'featureCollection': grip4_africaLength, + 'color': 'lengthKm' +}).gt(0) + +Map.addLayer(grip4_africaRaster, + {'palette': ['orange'], 'max': 1}, + 'Rasterized roads') + +# Add reducer output to the Features in the collection. +AlgeriaRoadLength = ee.Image.pixelArea() \ + .addBands(grip4_africaRaster) \ + .reduceRegions({ + 'collection': Algeria, + 'reducer': ee.Reducer.sum(), + 'scale': 100, + +def func_bks(feature): + num = ee.Number.parse(feature.get('area')) + return feature.set('length', num.divide(1000).sqrt().round()) + +}).map(func_bks) + + + + + +# Print the first feature, to illustrate the result. +print('Length of all roads in Algeria calculated via rasters', + ee.Number(AlgeriaRoadLength.first().get('length'))) + +# Calculate line lengths for all roads in North America and Europe +grip4_north_americaLength = grip4_north_america.map(addLength) +grip4_europeLength = grip4_europe.map(addLength) + +# Merge vectors +roadLengthMerge = grip4_africaLength.merge(grip4_north_americaLength) \ + .merge(grip4_europeLength) + +# Convert to raster +empty = ee.Image().float() + +roadLengthMergeRaster = empty.paint({ + 'featureCollection': roadLengthMerge, + 'color': 'roadsPerArea' +}).gt(0) + +# Filter to largest countries in Africa, North America and Europe +countriesSelected = countries \ + .filter(ee.Filter.inList('country_na', ['Algeria', 'Canada', 'France'])) + +# Clip image to only countries of analysis +roadLengthMergeRasterClipped = roadLengthMergeRaster \ + .clipToCollection(countriesSelected) + +# Add reducer output to the Features in the collection. +countriesRoadLength = ee.Image.pixelArea() \ + .addBands(roadLengthMergeRasterClipped) \ + .reduceRegions({ + 'collection': countriesSelected, + 'reducer': ee.Reducer.sum(), + 'scale': 100, + +def func_fgy(feature): + num = ee.Number.parse(feature.get('area')) + return feature.set('length', num.divide(1000).sqrt().round()) + +}).map(func_fgy) + + + + + +# Compute totaled road lengths in km, grouped by country +print('Length of all roads in Canada', + countriesRoadLength.filter(ee.Filter.equals('country_na', 'Canada')) \ + .aggregate_sum('length')) +print('Length of all roads in France', + countriesRoadLength.filter(ee.Filter.equals('country_na', 'France')) \ + .aggregate_sum('length')) + +# Examine effect of scale on raster +Map.addLayer(grip4_africaRaster.reproject({'crs': 'EPSG:4326', 'scale': 100}), + {'palette': ['orange'], 'max': 1}, + 'Rasterized roads 100 m') + +# LGTM (nclinton). Reformatted. Added a setCenter. +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s2 Exercise 2.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s2 Exercise 2.ipynb new file mode 100644 index 0000000..a7a3f68 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s2 Exercise 2.ipynb @@ -0,0 +1,201 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# Import roads.\n", + "grip4_africa = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Africa')\n", + "grip4_europe = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/Europe')\n", + "grip4_north_america = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/GRIP4/North-America')\n", + "\n", + "# Function to add line length in km\n", + "def addLength(feature):\n", + " return feature.set({'lengthKm': feature.length().divide(1000)}) # km\n", + "\n", + "\n", + "# Calculate line lengths for all roads in Africa\n", + "grip4_africaLength = grip4_africa.map(addLength)\n", + "\n", + "# Convert to roads to raster\n", + "empty = ee.Image().float()\n", + "\n", + "grip4_africaRaster = empty.paint({\n", + " 'featureCollection': grip4_africaLength,\n", + " 'color': 'lengthKm'\n", + "})\n", + "\n", + "# Import simplified countries\n", + "countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')\n", + "\n", + "# Filter to Africa\n", + "Africa = countries.filter(ee.Filter.eq('wld_rgn', 'Africa'))\n", + "\n", + "# Import global power transmission lines\n", + "transmission = ee.FeatureCollection(\n", + " 'projects/sat-io/open-datasets/predictive-global-power-system/distribution-transmission-lines')\n", + "\n", + "# Filter transmission lines to Africa\n", + "transmissionAfrica = transmission.filterBounds(Africa)\n", + "\n", + "# Calculate line lengths for all transmission lines in Africa\n", + "transmissionAfricaLength = transmissionAfrica.map(addLength)\n", + "\n", + "# Convert to transmission lines to raster\n", + "transmissionAfricaRaster = empty.paint({\n", + " 'featureCollection': transmissionAfricaLength,\n", + " 'color': 'lengthKm'\n", + "})\n", + "\n", + "# Add roads and transmission lines together into one image\n", + "# Clip to Africa feature collection\n", + "stack = grip4_africaRaster \\\n", + " .addBands(transmissionAfricaRaster) \\\n", + " .rename(['roads', 'transmission']) \\\n", + " .clipToCollection(Africa)\n", + "\n", + "# Calculate spatial statistics: local Geary's C\n", + "# Create a list of weights for a 9x9 kernel.\n", + "list = [1, 1, 1, 1, 1, 1, 1, 1, 1]\n", + "\n", + "# The center of the kernel is zero.\n", + "centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1]\n", + "\n", + "# Assemble a list of lists: the 9x9 kernel weights as a 2-D matrix.\n", + "lists = [list, list, list, list, centerList, list, list, list, list]\n", + "\n", + "# Create the kernel from the weights.\n", + "# Non-zero weights represent the spatial neighborhood.\n", + "kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, False)\n", + "\n", + "# Use the max among bands as the input.\n", + "maxBands = stack.reduce(ee.Reducer.max())\n", + "\n", + "# Convert the neighborhood into multiple bands.\n", + "neighs = maxBands.neighborhoodToBands(kernel)\n", + "\n", + "# Compute local Geary's C, a measure of spatial association\n", + "# \u2013 0 indicates perfect positive autocorrelation/clustered\n", + "# \u2013 1 indicates no autocorrelation/random\n", + "# \u2013 2 indicates perfect negative autocorrelation/dispersed\n", + "gearys = maxBands.subtract(neighs).pow(2).reduce(ee.Reducer.sum()) \\\n", + " .divide(math.pow(9, 2))\n", + "\n", + "# Convert to a -/+1 scale by: calculating C* = 1 \u2013 C\n", + "# \u2013 1 indicates perfect positive autocorrelation/clustered\n", + "# \u2013 0 indicates no autocorrelation/random\n", + "# \u2013 -1 indicates perfect negative autocorrelation/dispersed\n", + "gearysStar = ee.Image(1).subtract(gearys)\n", + "\n", + "# Import palettes\n", + "palettes = require('users/gena/packages:palettes')\n", + "\n", + "# Create custom palette, blue is negative while red is positive autocorrelation/clustered\n", + "palette = palettes.colorbrewer.Spectral[7].reverse()\n", + "\n", + "# Normalize the image and add it to the map.\n", + "visParams = {'min': -1, 'max': 1, 'palette': palette}\n", + "\n", + "# Import custom basemap\n", + "basemap = require('users/erintrochim/GEE_workshops:backgroundMaps')\n", + "\n", + "# Add basemap\n", + "basemap.addCustomBasemap('BlackAndWhite')\n", + "\n", + "# Display\n", + "Map.setCenter(3.6, 32.5, 11)\n", + "Map.addLayer(gearysStar.focalMax(1),\n", + " visParams,\n", + " 'local Gearys C*')\n", + "\n", + "# LGTM (nclinton)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s2 Exercise 2.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s2 Exercise 2.js new file mode 100644 index 0000000..4b2b6cc --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s2 Exercise 2.js @@ -0,0 +1,108 @@ +// Import roads. +var grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa'); +var grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe'); +var grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America'); + +// Function to add line length in km +var addLength = function(feature) { + return feature.set({lengthKm: feature.length().divide(1000)}) // km; +}; + +// Calculate line lengths for all roads in Africa +var grip4_africaLength = grip4_africa.map(addLength) + +// Convert to roads to raster +var empty = ee.Image().float(); + +var grip4_africaRaster = empty.paint({ + featureCollection: grip4_africaLength, + color: 'lengthKm' +}); + +// Import simplified countries +var countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + +// Filter to Africa +var Africa = countries.filter(ee.Filter.eq('wld_rgn', 'Africa')) + +// Import global power transmission lines +var transmission = ee.FeatureCollection( + 'projects/sat-io/open-datasets/predictive-global-power-system/distribution-transmission-lines'); + +// Filter transmission lines to Africa +var transmissionAfrica = transmission.filterBounds(Africa) + +// Calculate line lengths for all transmission lines in Africa +var transmissionAfricaLength = transmissionAfrica.map(addLength) + +// Convert to transmission lines to raster +var transmissionAfricaRaster = empty.paint({ + featureCollection: transmissionAfricaLength, + color: 'lengthKm' +}); + +// Add roads and transmission lines together into one image +// Clip to Africa feature collection +var stack = grip4_africaRaster + .addBands(transmissionAfricaRaster) + .rename(['roads', 'transmission']) + .clipToCollection(Africa); + +// Calculate spatial statistics: local Geary's C +// Create a list of weights for a 9x9 kernel. +var list = [1, 1, 1, 1, 1, 1, 1, 1, 1]; + +// The center of the kernel is zero. +var centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1]; + +// Assemble a list of lists: the 9x9 kernel weights as a 2-D matrix. +var lists = [list, list, list, list, centerList, list, list, list, list]; + +// Create the kernel from the weights. +// Non-zero weights represent the spatial neighborhood. +var kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, false); + +// Use the max among bands as the input. +var maxBands = stack.reduce(ee.Reducer.max()); + +// Convert the neighborhood into multiple bands. +var neighs = maxBands.neighborhoodToBands(kernel); + +// Compute local Geary's C, a measure of spatial association +// – 0 indicates perfect positive autocorrelation/clustered +// – 1 indicates no autocorrelation/random +// – 2 indicates perfect negative autocorrelation/dispersed +var gearys = maxBands.subtract(neighs).pow(2).reduce(ee.Reducer.sum()) + .divide(Math.pow(9, 2)); + +// Convert to a -/+1 scale by: calculating C* = 1 – C +// – 1 indicates perfect positive autocorrelation/clustered +// – 0 indicates no autocorrelation/random +// – -1 indicates perfect negative autocorrelation/dispersed +var gearysStar = ee.Image(1).subtract(gearys) + +// Import palettes +var palettes = require('users/gena/packages:palettes'); + +// Create custom palette, blue is negative while red is positive autocorrelation/clustered +var palette = palettes.colorbrewer.Spectral[7].reverse(); + +// Normalize the image and add it to the map. +var visParams = {min: -1, max: 1, palette: palette}; + +// Import custom basemap +var basemap = require('users/erintrochim/GEE_workshops:backgroundMaps') + +// Add basemap +basemap.addCustomBasemap('BlackAndWhite') + +// Display +Map.setCenter(3.6, 32.5, 11) +Map.addLayer(gearysStar.focalMax(1), + visParams, + 'local Gearys C*') + +// LGTM (nclinton) diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s2 Exercise 2.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s2 Exercise 2.py new file mode 100644 index 0000000..73c2e3f --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.3 Built Environments/A31s2 Exercise 2.py @@ -0,0 +1,115 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# Import roads. +grip4_africa = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Africa') +grip4_europe = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/Europe') +grip4_north_america = ee.FeatureCollection( + 'projects/sat-io/open-datasets/GRIP4/North-America') + +# Function to add line length in km +def addLength(feature): + return feature.set({'lengthKm': feature.length().divide(1000)}) # km + + +# Calculate line lengths for all roads in Africa +grip4_africaLength = grip4_africa.map(addLength) + +# Convert to roads to raster +empty = ee.Image().float() + +grip4_africaRaster = empty.paint({ + 'featureCollection': grip4_africaLength, + 'color': 'lengthKm' +}) + +# Import simplified countries +countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + +# Filter to Africa +Africa = countries.filter(ee.Filter.eq('wld_rgn', 'Africa')) + +# Import global power transmission lines +transmission = ee.FeatureCollection( + 'projects/sat-io/open-datasets/predictive-global-power-system/distribution-transmission-lines') + +# Filter transmission lines to Africa +transmissionAfrica = transmission.filterBounds(Africa) + +# Calculate line lengths for all transmission lines in Africa +transmissionAfricaLength = transmissionAfrica.map(addLength) + +# Convert to transmission lines to raster +transmissionAfricaRaster = empty.paint({ + 'featureCollection': transmissionAfricaLength, + 'color': 'lengthKm' +}) + +# Add roads and transmission lines together into one image +# Clip to Africa feature collection +stack = grip4_africaRaster \ + .addBands(transmissionAfricaRaster) \ + .rename(['roads', 'transmission']) \ + .clipToCollection(Africa) + +# Calculate spatial statistics: local Geary's C +# Create a list of weights for a 9x9 kernel. +list = [1, 1, 1, 1, 1, 1, 1, 1, 1] + +# The center of the kernel is zero. +centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1] + +# Assemble a list of lists: the 9x9 kernel weights as a 2-D matrix. +lists = [list, list, list, list, centerList, list, list, list, list] + +# Create the kernel from the weights. +# Non-zero weights represent the spatial neighborhood. +kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, False) + +# Use the max among bands as the input. +maxBands = stack.reduce(ee.Reducer.max()) + +# Convert the neighborhood into multiple bands. +neighs = maxBands.neighborhoodToBands(kernel) + +# Compute local Geary's C, a measure of spatial association +# – 0 indicates perfect positive autocorrelation/clustered +# – 1 indicates no autocorrelation/random +# – 2 indicates perfect negative autocorrelation/dispersed +gearys = maxBands.subtract(neighs).pow(2).reduce(ee.Reducer.sum()) \ + .divide(math.pow(9, 2)) + +# Convert to a -/+1 scale by: calculating C* = 1 – C +# – 1 indicates perfect positive autocorrelation/clustered +# – 0 indicates no autocorrelation/random +# – -1 indicates perfect negative autocorrelation/dispersed +gearysStar = ee.Image(1).subtract(gearys) + +# Import palettes +palettes = require('users/gena/packages:palettes') + +# Create custom palette, blue is negative while red is positive autocorrelation/clustered +palette = palettes.colorbrewer.Spectral[7].reverse() + +# Normalize the image and add it to the map. +visParams = {'min': -1, 'max': 1, 'palette': palette} + +# Import custom basemap +basemap = require('users/erintrochim/GEE_workshops:backgroundMaps') + +# Add basemap +basemap.addCustomBasemap('BlackAndWhite') + +# Display +Map.setCenter(3.6, 32.5, 11) +Map.addLayer(gearysStar.focalMax(1), + visParams, + 'local Gearys C*') + +# LGTM (nclinton) +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14a Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14a Checkpoint.ipynb new file mode 100644 index 0000000..ba9fc71 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14a Checkpoint.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometry =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([114.26732477622326, 30.57603159263821])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.4 Air Pollution and Population Exposures\n", + "# Checkpoint: A14a\n", + "# Authors: Zander Venter and Sourangsu Chowdhury\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#\n", + " # Section 1: data import and cleaning\n", + " #\n", + "\n", + "# Import a global dataset of administrative units level 1.\n", + "adminUnits = ee.FeatureCollection(\n", + " 'FAO/GAUL_SIMPLIFIED_500m/2015/level1')\n", + "\n", + "# Filter for the administrative unit that intersects\n", + "# the geometry located at the top of this script.\n", + "adminSelect = adminUnits.filterBounds(geometry)\n", + "\n", + "# Center the map on this area.\n", + "Map.centerObject(adminSelect, 8)\n", + "\n", + "# Make the base map HYBRID.\n", + "Map.setOptions('HYBRID')\n", + "\n", + "# Add it to the map to make sure you have what you want.\n", + "Map.addLayer(adminSelect, {}, 'selected admin unit')\n", + "\n", + "# Import the population count data from Gridded Population of the World Version 4.\n", + "population = ee.ImageCollection(\n", + " 'CIESIN/GPWv411/GPW_Population_Count') \\\n", + " .filter(ee.Filter.calendarRange(2020, 2020, 'year')) \\\n", + " .mean()\n", + "\n", + "# Clip it to your area of interest (only necessary for visualization purposes).\n", + "populationClipped = population.clipToCollection(adminSelect)\n", + "\n", + "# Add it to the map to see the population distribution.\n", + "popVis = {\n", + " 'min': 0,\n", + " 'max': 4000,\n", + " 'palette': ['black', 'yellow', 'white'],\n", + " 'opacity': 0.55\n", + "}\n", + "Map.addLayer(populationClipped, popVis, 'population count')\n", + "\n", + "# Import the Sentinel-5P NO2 offline product.\n", + "no2Raw = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2')\n", + "\n", + "# Define function to exclude cloudy pixels.\n", + "def maskClouds(image):\n", + " # Get the cloud fraction band of the image.\n", + " cf = image.select('cloud_fraction')\n", + " # Create a mask using 0.3 threshold.\n", + " mask = cf.lte(0.3); # You can play around with this value.\n", + " # Return a masked image.\n", + " return image.updateMask(mask).copyProperties(image)\n", + "\n", + "\n", + "# Clean and filter the Sentinel-5P NO2 offline product.\n", + "no2 = no2Raw \\\n", + " .filterBounds(adminSelect) \\\n", + " .map(maskClouds) \\\n", + " .select('tropospheric_NO2_column_number_density')\n", + "\n", + "# Create a median composite for March 2021\n", + "no2Median = no2.filterDate('2021-03-01', '2021-04-01').median()\n", + "\n", + "# Clip it to your area of interest (only necessary for visualization purposes).\n", + "no2MedianClipped = no2Median.clipToCollection(adminSelect)\n", + "\n", + "# Visualize the median NO2.\n", + "no2Viz = {\n", + " 'min': 0,\n", + " 'max': 0.00015,\n", + " 'palette': ['black', 'blue', 'purple', 'cyan', 'green',\n", + " 'yellow', 'red'\n", + " ]\n", + "}\n", + "Map.addLayer(no2MedianClipped, no2Viz, 'median no2 Mar 2021')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14a Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14a Checkpoint.js new file mode 100644 index 0000000..1d29c46 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14a Checkpoint.js @@ -0,0 +1,94 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometry = + /* color: #d63000 */ + /* shown: false */ + ee.Geometry.Point([114.26732477622326, 30.57603159263821]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.4 Air Pollution and Population Exposures +// Checkpoint: A14a +// Authors: Zander Venter and Sourangsu Chowdhury +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +/* + * Section 1: data import and cleaning + */ + +// Import a global dataset of administrative units level 1. +var adminUnits = ee.FeatureCollection( + 'FAO/GAUL_SIMPLIFIED_500m/2015/level1'); + +// Filter for the administrative unit that intersects +// the geometry located at the top of this script. +var adminSelect = adminUnits.filterBounds(geometry); + +// Center the map on this area. +Map.centerObject(adminSelect, 8); + +// Make the base map HYBRID. +Map.setOptions('HYBRID'); + +// Add it to the map to make sure you have what you want. +Map.addLayer(adminSelect, {}, 'selected admin unit'); + +// Import the population count data from Gridded Population of the World Version 4. +var population = ee.ImageCollection( + 'CIESIN/GPWv411/GPW_Population_Count') + // Filter for 2020 using the calendar range function. + .filter(ee.Filter.calendarRange(2020, 2020, 'year')) + // There should be only 1 image, but convert to an image using .mean(). + .mean(); + +// Clip it to your area of interest (only necessary for visualization purposes). +var populationClipped = population.clipToCollection(adminSelect); + +// Add it to the map to see the population distribution. +var popVis = { + min: 0, + max: 4000, + palette: ['black', 'yellow', 'white'], + opacity: 0.55 +}; +Map.addLayer(populationClipped, popVis, 'population count'); + +// Import the Sentinel-5P NO2 offline product. +var no2Raw = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2'); + +// Define function to exclude cloudy pixels. +function maskClouds(image) { + // Get the cloud fraction band of the image. + var cf = image.select('cloud_fraction'); + // Create a mask using 0.3 threshold. + var mask = cf.lte(0.3); // You can play around with this value. + // Return a masked image. + return image.updateMask(mask).copyProperties(image); +} + +// Clean and filter the Sentinel-5P NO2 offline product. +var no2 = no2Raw + // Filter for images intersecting our area of interest. + .filterBounds(adminSelect) + // Map the cloud masking function over the image collection. + .map(maskClouds) + // Select the tropospheric vertical column of NO2 band. + .select('tropospheric_NO2_column_number_density'); + +// Create a median composite for March 2021 +var no2Median = no2.filterDate('2021-03-01', '2021-04-01').median(); + +// Clip it to your area of interest (only necessary for visualization purposes). +var no2MedianClipped = no2Median.clipToCollection(adminSelect); + +// Visualize the median NO2. +var no2Viz = { + min: 0, + max: 0.00015, + palette: ['black', 'blue', 'purple', 'cyan', 'green', + 'yellow', 'red' + ] +}; +Map.addLayer(no2MedianClipped, no2Viz, 'median no2 Mar 2021'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14a Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14a Checkpoint.py new file mode 100644 index 0000000..7708400 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14a Checkpoint.py @@ -0,0 +1,95 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometry = + + # shown: False # + ee.Geometry.Point([114.26732477622326, 30.57603159263821]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.4 Air Pollution and Population Exposures +# Checkpoint: A14a +# Authors: Zander Venter and Sourangsu Chowdhury +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + # Section 1: data import and cleaning + # + +# Import a global dataset of administrative units level 1. +adminUnits = ee.FeatureCollection( + 'FAO/GAUL_SIMPLIFIED_500m/2015/level1') + +# Filter for the administrative unit that intersects +# the geometry located at the top of this script. +adminSelect = adminUnits.filterBounds(geometry) + +# Center the map on this area. +Map.centerObject(adminSelect, 8) + +# Make the base map HYBRID. +Map.setOptions('HYBRID') + +# Add it to the map to make sure you have what you want. +Map.addLayer(adminSelect, {}, 'selected admin unit') + +# Import the population count data from Gridded Population of the World Version 4. +population = ee.ImageCollection( + 'CIESIN/GPWv411/GPW_Population_Count') \ + .filter(ee.Filter.calendarRange(2020, 2020, 'year')) \ + .mean() + +# Clip it to your area of interest (only necessary for visualization purposes). +populationClipped = population.clipToCollection(adminSelect) + +# Add it to the map to see the population distribution. +popVis = { + 'min': 0, + 'max': 4000, + 'palette': ['black', 'yellow', 'white'], + 'opacity': 0.55 +} +Map.addLayer(populationClipped, popVis, 'population count') + +# Import the Sentinel-5P NO2 offline product. +no2Raw = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2') + +# Define function to exclude cloudy pixels. +def maskClouds(image): + # Get the cloud fraction band of the image. + cf = image.select('cloud_fraction') + # Create a mask using 0.3 threshold. + mask = cf.lte(0.3); # You can play around with this value. + # Return a masked image. + return image.updateMask(mask).copyProperties(image) + + +# Clean and filter the Sentinel-5P NO2 offline product. +no2 = no2Raw \ + .filterBounds(adminSelect) \ + .map(maskClouds) \ + .select('tropospheric_NO2_column_number_density') + +# Create a median composite for March 2021 +no2Median = no2.filterDate('2021-03-01', '2021-04-01').median() + +# Clip it to your area of interest (only necessary for visualization purposes). +no2MedianClipped = no2Median.clipToCollection(adminSelect) + +# Visualize the median NO2. +no2Viz = { + 'min': 0, + 'max': 0.00015, + 'palette': ['black', 'blue', 'purple', 'cyan', 'green', + 'yellow', 'red' + ] +} +Map.addLayer(no2MedianClipped, no2Viz, 'median no2 Mar 2021') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14b Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14b Checkpoint.ipynb new file mode 100644 index 0000000..e8536be --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14b Checkpoint.ipynb @@ -0,0 +1,302 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometry =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([114.26732477622326, 30.57603159263821])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.4 Air Pollution and Population Exposures\n", + "# Checkpoint: A14b\n", + "# Authors: Zander Venter and Sourangsu Chowdhury\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#\n", + " # Section 1: data import and cleaning\n", + " #\n", + "\n", + "# Import a global dataset of administrative units level 1.\n", + "adminUnits = ee.FeatureCollection(\n", + " 'FAO/GAUL_SIMPLIFIED_500m/2015/level1')\n", + "\n", + "# Filter for the administrative unit that intersects\n", + "# the geometry located at the top of this script.\n", + "adminSelect = adminUnits.filterBounds(geometry)\n", + "\n", + "# Center the map on this area.\n", + "Map.centerObject(adminSelect, 8)\n", + "\n", + "# Make the base map HYBRID.\n", + "Map.setOptions('HYBRID')\n", + "\n", + "# Add it to the map to make sure you have what you want.\n", + "Map.addLayer(adminSelect, {}, 'selected admin unit')\n", + "\n", + "# Import the population count data from Gridded Population of the World Version 4.\n", + "population = ee.ImageCollection(\n", + " 'CIESIN/GPWv411/GPW_Population_Count') \\\n", + " .filter(ee.Filter.calendarRange(2020, 2020, 'year')) \\\n", + " .mean()\n", + "\n", + "# Clip it to your area of interest (only necessary for visualization purposes).\n", + "populationClipped = population.clipToCollection(adminSelect)\n", + "\n", + "# Add it to the map to see the population distribution.\n", + "popVis = {\n", + " 'min': 0,\n", + " 'max': 4000,\n", + " 'palette': ['black', 'yellow', 'white'],\n", + " 'opacity': 0.55\n", + "}\n", + "Map.addLayer(populationClipped, popVis, 'population count')\n", + "\n", + "# Import the Sentinel-5P NO2 offline product.\n", + "no2Raw = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2')\n", + "\n", + "# Define function to exclude cloudy pixels.\n", + "def maskClouds(image):\n", + " # Get the cloud fraction band of the image.\n", + " cf = image.select('cloud_fraction')\n", + " # Create a mask using 0.3 threshold.\n", + " mask = cf.lte(0.3); # You can play around with this value.\n", + " # Return a masked image.\n", + " return image.updateMask(mask).copyProperties(image)\n", + "\n", + "\n", + "# Clean and filter the Sentinel-5P NO2 offline product.\n", + "no2 = no2Raw \\\n", + " .filterBounds(adminSelect) \\\n", + " .map(maskClouds) \\\n", + " .select('tropospheric_NO2_column_number_density')\n", + "\n", + "# Create a median composite for March 2021\n", + "no2Median = no2.filterDate('2021-03-01', '2021-04-01').median()\n", + "\n", + "# Clip it to your area of interest (only necessary for visualization purposes).\n", + "no2MedianClipped = no2Median.clipToCollection(adminSelect)\n", + "\n", + "# Visualize the median NO2.\n", + "no2Viz = {\n", + " 'min': 0,\n", + " 'max': 0.00015,\n", + " 'palette': ['black', 'blue', 'purple', 'cyan', 'green',\n", + " 'yellow', 'red'\n", + " ]\n", + "}\n", + "Map.addLayer(no2MedianClipped, no2Viz, 'median no2 Mar 2021')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "#\n", + " # Section 2: quantifying and vizualizing change\n", + " #\n", + "\n", + "# Define a lockdown NO2 median composite.\n", + "no2Lockdown = no2.filterDate('2020-03-01', '2020-04-01') \\\n", + " .median().clipToCollection(adminSelect)\n", + "\n", + "# Define a baseline NO2 median using the same month in the previous year.\n", + "no2Baseline = no2.filterDate('2019-03-01', '2019-04-01') \\\n", + " .median().clipToCollection(adminSelect)\n", + "\n", + "# Create a ui map widget to hold the baseline NO2 image.\n", + "leftMap = ui.Map().centerObject(adminSelect, 8).setOptions(\n", + " 'HYBRID')\n", + "\n", + "# Create ta ui map widget to hold the lockdown NO2 image.\n", + "rightMap = ui.Map().setOptions('HYBRID')\n", + "\n", + "# Create a split panel widget to hold the two maps.\n", + "sliderPanel = ui.SplitPanel({\n", + " 'firstPanel': leftMap,\n", + " 'secondPanel': rightMap,\n", + " 'orientation': 'horizontal',\n", + " 'wipe': True,\n", + " 'style': {\n", + " 'stretch': 'both'\n", + " }\n", + "})\n", + "linker = ui.Map.Linker([leftMap, rightMap])\n", + "\n", + "# Make a function to add a label with fancy styling.\n", + "def makeMapLab(lab, position):\n", + " label = ui.Label({\n", + " 'value': lab,\n", + " 'style': {\n", + " 'fontSize': '16px',\n", + " 'color': '#ffffff',\n", + " 'fontWeight': 'bold',\n", + " 'backgroundColor': '#ffffff00',\n", + " 'padding': '0px'\n", + " }\n", + " })\n", + " panel = ui.Panel({\n", + " 'widgets': [label],\n", + " 'layout': ui.Panel.Layout.flow('horizontal'),\n", + " 'style': {\n", + " 'position': position,\n", + " 'backgroundColor': '#00000057',\n", + " 'padding': '0px'\n", + " }\n", + " })\n", + " return panel\n", + "\n", + "\n", + "# Create baseline map layer, add it to the left map, and add the label.\n", + "no2BaselineLayer = ui.Map.Layer(no2Baseline, no2Viz)\n", + "leftMap.layers().reset([no2BaselineLayer])\n", + "leftMap.add(makeMapLab('Baseline 2019', 'top-left'))\n", + "\n", + "# Create lockdown map layer, add it to the right map, and add the label.\n", + "no2LockdownLayer = ui.Map.Layer(no2Lockdown, no2Viz)\n", + "rightMap.layers().reset([no2LockdownLayer])\n", + "rightMap.add(makeMapLab('Lockdown 2020', 'top-right'))\n", + "\n", + "# Reset the map interface (ui.root) with the split panel widget.\n", + "# Note that the Map.addLayer() calls earlier on in Section 1\n", + "# will no longer be shown because we have replaced the Map widget\n", + "# with the sliderPanel widget.\n", + "ui.root.widgets().reset([sliderPanel])\n", + "\n", + "# Create a function to get the mean NO2 for the study region\n", + "# per image in the NO2 collection.\n", + "def getConc(collectionLabel, img):\n", + " return function(img) {\n", + " # Calculate the mean NO2.\n", + " no2Mean = img.reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': adminSelect.geometry(),\n", + " 'scale': 7000\n", + " }).get('tropospheric_NO2_column_number_density')\n", + "\n", + " # Get the day-of-year of the image.\n", + " doy = img.date().getRelative('day', 'year')\n", + "\n", + " # Return a feature with NO2 concentration and day-of-year properties.\n", + " return ee.Feature(None, {\n", + " 'conc': no2Mean,\n", + " 'DOY': doy,\n", + " 'type': collectionLabel\n", + " })\n", + " }\n", + "\n", + "\n", + "# Get the concentrations for a baseline and lockdown collection\n", + "# and merge for plotting.\n", + "no2AggChange_forPlotting = no2 \\\n", + " .filterDate('2020-03-01', '2020-04-01') \\\n", + " .map(getConc('lockdown')) \\\n", + " .merge(no2.filterDate('2019-03-01', '2019-04-01') \\\n", + " .map(getConc('baseline')))\n", + "no2AggChange_forPlotting = no2AggChange_forPlotting \\\n", + " .filter(ee.Filter.NotNull(['conc']))\n", + "\n", + "# Make a chart.\n", + "chart1 = ui.Chart.feature.groups(\n", + " no2AggChange_forPlotting, 'DOY', 'conc', 'type') \\\n", + " .setChartType('LineChart') \\\n", + " .setOptions({\n", + " 'title': 'DOY time series for mean [NO2] during ' + \\\n", + " 'March 2019 (baseline) and 2020 (lockdown)'\n", + " })\n", + "\n", + "# Print it to the console.\n", + "print('Baseline vs lockdown NO2 for the study region by DOY', chart1)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14b Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14b Checkpoint.js new file mode 100644 index 0000000..dcb5248 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14b Checkpoint.js @@ -0,0 +1,214 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometry = + /* color: #d63000 */ + /* shown: false */ + ee.Geometry.Point([114.26732477622326, 30.57603159263821]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.4 Air Pollution and Population Exposures +// Checkpoint: A14b +// Authors: Zander Venter and Sourangsu Chowdhury +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +/* + * Section 1: data import and cleaning + */ + +// Import a global dataset of administrative units level 1. +var adminUnits = ee.FeatureCollection( + 'FAO/GAUL_SIMPLIFIED_500m/2015/level1'); + +// Filter for the administrative unit that intersects +// the geometry located at the top of this script. +var adminSelect = adminUnits.filterBounds(geometry); + +// Center the map on this area. +Map.centerObject(adminSelect, 8); + +// Make the base map HYBRID. +Map.setOptions('HYBRID'); + +// Add it to the map to make sure you have what you want. +Map.addLayer(adminSelect, {}, 'selected admin unit'); + +// Import the population count data from Gridded Population of the World Version 4. +var population = ee.ImageCollection( + 'CIESIN/GPWv411/GPW_Population_Count') + // Filter for 2020 using the calendar range function. + .filter(ee.Filter.calendarRange(2020, 2020, 'year')) + // There should be only 1 image, but convert to an image using .mean(). + .mean(); + +// Clip it to your area of interest (only necessary for visualization purposes). +var populationClipped = population.clipToCollection(adminSelect); + +// Add it to the map to see the population distribution. +var popVis = { + min: 0, + max: 4000, + palette: ['black', 'yellow', 'white'], + opacity: 0.55 +}; +Map.addLayer(populationClipped, popVis, 'population count'); + +// Import the Sentinel-5P NO2 offline product. +var no2Raw = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2'); + +// Define function to exclude cloudy pixels. +function maskClouds(image) { + // Get the cloud fraction band of the image. + var cf = image.select('cloud_fraction'); + // Create a mask using 0.3 threshold. + var mask = cf.lte(0.3); // You can play around with this value. + // Return a masked image. + return image.updateMask(mask).copyProperties(image); +} + +// Clean and filter the Sentinel-5P NO2 offline product. +var no2 = no2Raw + // Filter for images intersecting our area of interest. + .filterBounds(adminSelect) + // Map the cloud masking function over the image collection. + .map(maskClouds) + // Select the tropospheric vertical column of NO2 band. + .select('tropospheric_NO2_column_number_density'); + +// Create a median composite for March 2021 +var no2Median = no2.filterDate('2021-03-01', '2021-04-01').median(); + +// Clip it to your area of interest (only necessary for visualization purposes). +var no2MedianClipped = no2Median.clipToCollection(adminSelect); + +// Visualize the median NO2. +var no2Viz = { + min: 0, + max: 0.00015, + palette: ['black', 'blue', 'purple', 'cyan', 'green', + 'yellow', 'red' + ] +}; +Map.addLayer(no2MedianClipped, no2Viz, 'median no2 Mar 2021'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +/* + * Section 2: quantifying and vizualizing change + */ + +// Define a lockdown NO2 median composite. +var no2Lockdown = no2.filterDate('2020-03-01', '2020-04-01') + .median().clipToCollection(adminSelect); + +// Define a baseline NO2 median using the same month in the previous year. +var no2Baseline = no2.filterDate('2019-03-01', '2019-04-01') + .median().clipToCollection(adminSelect); + +// Create a ui map widget to hold the baseline NO2 image. +var leftMap = ui.Map().centerObject(adminSelect, 8).setOptions( + 'HYBRID'); + +// Create ta ui map widget to hold the lockdown NO2 image. +var rightMap = ui.Map().setOptions('HYBRID'); + +// Create a split panel widget to hold the two maps. +var sliderPanel = ui.SplitPanel({ + firstPanel: leftMap, + secondPanel: rightMap, + orientation: 'horizontal', + wipe: true, + style: { + stretch: 'both' + } +}); +var linker = ui.Map.Linker([leftMap, rightMap]); + +// Make a function to add a label with fancy styling. +function makeMapLab(lab, position) { + var label = ui.Label({ + value: lab, + style: { + fontSize: '16px', + color: '#ffffff', + fontWeight: 'bold', + backgroundColor: '#ffffff00', + padding: '0px' + } + }); + var panel = ui.Panel({ + widgets: [label], + layout: ui.Panel.Layout.flow('horizontal'), + style: { + position: position, + backgroundColor: '#00000057', + padding: '0px' + } + }); + return panel; +} + +// Create baseline map layer, add it to the left map, and add the label. +var no2BaselineLayer = ui.Map.Layer(no2Baseline, no2Viz); +leftMap.layers().reset([no2BaselineLayer]); +leftMap.add(makeMapLab('Baseline 2019', 'top-left')); + +// Create lockdown map layer, add it to the right map, and add the label. +var no2LockdownLayer = ui.Map.Layer(no2Lockdown, no2Viz); +rightMap.layers().reset([no2LockdownLayer]); +rightMap.add(makeMapLab('Lockdown 2020', 'top-right')); + +// Reset the map interface (ui.root) with the split panel widget. +// Note that the Map.addLayer() calls earlier on in Section 1 +// will no longer be shown because we have replaced the Map widget +// with the sliderPanel widget. +ui.root.widgets().reset([sliderPanel]); + +// Create a function to get the mean NO2 for the study region +// per image in the NO2 collection. +function getConc(collectionLabel, img) { + return function(img) { + // Calculate the mean NO2. + var no2Mean = img.reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: adminSelect.geometry(), + scale: 7000 + }).get('tropospheric_NO2_column_number_density'); + + // Get the day-of-year of the image. + var doy = img.date().getRelative('day', 'year'); + + // Return a feature with NO2 concentration and day-of-year properties. + return ee.Feature(null, { + 'conc': no2Mean, + 'DOY': doy, + 'type': collectionLabel + }); + }; +} + +// Get the concentrations for a baseline and lockdown collection +// and merge for plotting. +var no2AggChange_forPlotting = no2 + .filterDate('2020-03-01', '2020-04-01') + .map(getConc('lockdown')) + .merge(no2.filterDate('2019-03-01', '2019-04-01') + .map(getConc('baseline'))); +no2AggChange_forPlotting = no2AggChange_forPlotting + .filter(ee.Filter.notNull(['conc'])); + +// Make a chart. +var chart1 = ui.Chart.feature.groups( + no2AggChange_forPlotting, 'DOY', 'conc', 'type') + .setChartType('LineChart') + .setOptions({ + title: 'DOY time series for mean [NO2] during ' + + 'March 2019 (baseline) and 2020 (lockdown)' + }); + +// Print it to the console. +print('Baseline vs lockdown NO2 for the study region by DOY', chart1); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14b Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14b Checkpoint.py new file mode 100644 index 0000000..f9b0850 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14b Checkpoint.py @@ -0,0 +1,215 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometry = + + # shown: False # + ee.Geometry.Point([114.26732477622326, 30.57603159263821]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.4 Air Pollution and Population Exposures +# Checkpoint: A14b +# Authors: Zander Venter and Sourangsu Chowdhury +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + # Section 1: data import and cleaning + # + +# Import a global dataset of administrative units level 1. +adminUnits = ee.FeatureCollection( + 'FAO/GAUL_SIMPLIFIED_500m/2015/level1') + +# Filter for the administrative unit that intersects +# the geometry located at the top of this script. +adminSelect = adminUnits.filterBounds(geometry) + +# Center the map on this area. +Map.centerObject(adminSelect, 8) + +# Make the base map HYBRID. +Map.setOptions('HYBRID') + +# Add it to the map to make sure you have what you want. +Map.addLayer(adminSelect, {}, 'selected admin unit') + +# Import the population count data from Gridded Population of the World Version 4. +population = ee.ImageCollection( + 'CIESIN/GPWv411/GPW_Population_Count') \ + .filter(ee.Filter.calendarRange(2020, 2020, 'year')) \ + .mean() + +# Clip it to your area of interest (only necessary for visualization purposes). +populationClipped = population.clipToCollection(adminSelect) + +# Add it to the map to see the population distribution. +popVis = { + 'min': 0, + 'max': 4000, + 'palette': ['black', 'yellow', 'white'], + 'opacity': 0.55 +} +Map.addLayer(populationClipped, popVis, 'population count') + +# Import the Sentinel-5P NO2 offline product. +no2Raw = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2') + +# Define function to exclude cloudy pixels. +def maskClouds(image): + # Get the cloud fraction band of the image. + cf = image.select('cloud_fraction') + # Create a mask using 0.3 threshold. + mask = cf.lte(0.3); # You can play around with this value. + # Return a masked image. + return image.updateMask(mask).copyProperties(image) + + +# Clean and filter the Sentinel-5P NO2 offline product. +no2 = no2Raw \ + .filterBounds(adminSelect) \ + .map(maskClouds) \ + .select('tropospheric_NO2_column_number_density') + +# Create a median composite for March 2021 +no2Median = no2.filterDate('2021-03-01', '2021-04-01').median() + +# Clip it to your area of interest (only necessary for visualization purposes). +no2MedianClipped = no2Median.clipToCollection(adminSelect) + +# Visualize the median NO2. +no2Viz = { + 'min': 0, + 'max': 0.00015, + 'palette': ['black', 'blue', 'purple', 'cyan', 'green', + 'yellow', 'red' + ] +} +Map.addLayer(no2MedianClipped, no2Viz, 'median no2 Mar 2021') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# + # Section 2: quantifying and vizualizing change + # + +# Define a lockdown NO2 median composite. +no2Lockdown = no2.filterDate('2020-03-01', '2020-04-01') \ + .median().clipToCollection(adminSelect) + +# Define a baseline NO2 median using the same month in the previous year. +no2Baseline = no2.filterDate('2019-03-01', '2019-04-01') \ + .median().clipToCollection(adminSelect) + +# Create a ui map widget to hold the baseline NO2 image. +leftMap = ui.Map().centerObject(adminSelect, 8).setOptions( + 'HYBRID') + +# Create ta ui map widget to hold the lockdown NO2 image. +rightMap = ui.Map().setOptions('HYBRID') + +# Create a split panel widget to hold the two maps. +sliderPanel = ui.SplitPanel({ + 'firstPanel': leftMap, + 'secondPanel': rightMap, + 'orientation': 'horizontal', + 'wipe': True, + 'style': { + 'stretch': 'both' + } +}) +linker = ui.Map.Linker([leftMap, rightMap]) + +# Make a function to add a label with fancy styling. +def makeMapLab(lab, position): + label = ui.Label({ + 'value': lab, + 'style': { + 'fontSize': '16px', + 'color': '#ffffff', + 'fontWeight': 'bold', + 'backgroundColor': '#ffffff00', + 'padding': '0px' + } + }) + panel = ui.Panel({ + 'widgets': [label], + 'layout': ui.Panel.Layout.flow('horizontal'), + 'style': { + 'position': position, + 'backgroundColor': '#00000057', + 'padding': '0px' + } + }) + return panel + + +# Create baseline map layer, add it to the left map, and add the label. +no2BaselineLayer = ui.Map.Layer(no2Baseline, no2Viz) +leftMap.layers().reset([no2BaselineLayer]) +leftMap.add(makeMapLab('Baseline 2019', 'top-left')) + +# Create lockdown map layer, add it to the right map, and add the label. +no2LockdownLayer = ui.Map.Layer(no2Lockdown, no2Viz) +rightMap.layers().reset([no2LockdownLayer]) +rightMap.add(makeMapLab('Lockdown 2020', 'top-right')) + +# Reset the map interface (ui.root) with the split panel widget. +# Note that the Map.addLayer() calls earlier on in Section 1 +# will no longer be shown because we have replaced the Map widget +# with the sliderPanel widget. +ui.root.widgets().reset([sliderPanel]) + +# Create a function to get the mean NO2 for the study region +# per image in the NO2 collection. +def getConc(collectionLabel, img): + return function(img) { + # Calculate the mean NO2. + no2Mean = img.reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': adminSelect.geometry(), + 'scale': 7000 + }).get('tropospheric_NO2_column_number_density') + + # Get the day-of-year of the image. + doy = img.date().getRelative('day', 'year') + + # Return a feature with NO2 concentration and day-of-year properties. + return ee.Feature(None, { + 'conc': no2Mean, + 'DOY': doy, + 'type': collectionLabel + }) + } + + +# Get the concentrations for a baseline and lockdown collection +# and merge for plotting. +no2AggChange_forPlotting = no2 \ + .filterDate('2020-03-01', '2020-04-01') \ + .map(getConc('lockdown')) \ + .merge(no2.filterDate('2019-03-01', '2019-04-01') \ + .map(getConc('baseline'))) +no2AggChange_forPlotting = no2AggChange_forPlotting \ + .filter(ee.Filter.NotNull(['conc'])) + +# Make a chart. +chart1 = ui.Chart.feature.groups( + no2AggChange_forPlotting, 'DOY', 'conc', 'type') \ + .setChartType('LineChart') \ + .setOptions({ + 'title': 'DOY time series for mean [NO2] during ' + \ + 'March 2019 (baseline) and 2020 (lockdown)' + }) + +# Print it to the console. +print('Baseline vs lockdown NO2 for the study region by DOY', chart1) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14c Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14c Checkpoint.ipynb new file mode 100644 index 0000000..aa1b9d6 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14c Checkpoint.ipynb @@ -0,0 +1,469 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometry =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([114.26732477622326, 30.57603159263821])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.4 Air Pollution and Population Exposures\n", + "# Checkpoint: A14c\n", + "# Authors: Zander Venter and Sourangsu Chowdhury\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#\n", + " # Section 1: data import and cleaning\n", + " #\n", + "\n", + "# Import a global dataset of administrative units level 1.\n", + "adminUnits = ee.FeatureCollection(\n", + " 'FAO/GAUL_SIMPLIFIED_500m/2015/level1')\n", + "\n", + "# Filter for the administrative unit that intersects\n", + "# the geometry located at the top of this script.\n", + "adminSelect = adminUnits.filterBounds(geometry)\n", + "\n", + "# Center the map on this area.\n", + "Map.centerObject(adminSelect, 8)\n", + "\n", + "# Make the base map HYBRID.\n", + "Map.setOptions('HYBRID')\n", + "\n", + "# Add it to the map to make sure you have what you want.\n", + "Map.addLayer(adminSelect, {}, 'selected admin unit')\n", + "\n", + "# Import the population count data from Gridded Population of the World Version 4.\n", + "population = ee.ImageCollection(\n", + " 'CIESIN/GPWv411/GPW_Population_Count') \\\n", + " .filter(ee.Filter.calendarRange(2020, 2020, 'year')) \\\n", + " .mean()\n", + "\n", + "# Clip it to your area of interest (only necessary for visualization purposes).\n", + "populationClipped = population.clipToCollection(adminSelect)\n", + "\n", + "# Add it to the map to see the population distribution.\n", + "popVis = {\n", + " 'min': 0,\n", + " 'max': 4000,\n", + " 'palette': ['black', 'yellow', 'white'],\n", + " 'opacity': 0.55\n", + "}\n", + "Map.addLayer(populationClipped, popVis, 'population count')\n", + "\n", + "# Import the Sentinel-5P NO2 offline product.\n", + "no2Raw = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2')\n", + "\n", + "# Define function to exclude cloudy pixels.\n", + "def maskClouds(image):\n", + " # Get the cloud fraction band of the image.\n", + " cf = image.select('cloud_fraction')\n", + " # Create a mask using 0.3 threshold.\n", + " mask = cf.lte(0.3); # You can play around with this value.\n", + " # Return a masked image.\n", + " return image.updateMask(mask).copyProperties(image)\n", + "\n", + "\n", + "# Clean and filter the Sentinel-5P NO2 offline product.\n", + "no2 = no2Raw \\\n", + " .filterBounds(adminSelect) \\\n", + " .map(maskClouds) \\\n", + " .select('tropospheric_NO2_column_number_density')\n", + "\n", + "# Create a median composite for March 2021\n", + "no2Median = no2.filterDate('2021-03-01', '2021-04-01').median()\n", + "\n", + "# Clip it to your area of interest (only necessary for visualization purposes).\n", + "no2MedianClipped = no2Median.clipToCollection(adminSelect)\n", + "\n", + "# Visualize the median NO2.\n", + "no2Viz = {\n", + " 'min': 0,\n", + " 'max': 0.00015,\n", + " 'palette': ['black', 'blue', 'purple', 'cyan', 'green',\n", + " 'yellow', 'red'\n", + " ]\n", + "}\n", + "Map.addLayer(no2MedianClipped, no2Viz, 'median no2 Mar 2021')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "#\n", + " # Section 2: quantifying and vizualizing change\n", + " #\n", + "\n", + "# Define a lockdown NO2 median composite.\n", + "no2Lockdown = no2.filterDate('2020-03-01', '2020-04-01') \\\n", + " .median().clipToCollection(adminSelect)\n", + "\n", + "# Define a baseline NO2 median using the same month in the previous year.\n", + "no2Baseline = no2.filterDate('2019-03-01', '2019-04-01') \\\n", + " .median().clipToCollection(adminSelect)\n", + "\n", + "# Create a ui map widget to hold the baseline NO2 image.\n", + "leftMap = ui.Map().centerObject(adminSelect, 8).setOptions(\n", + " 'HYBRID')\n", + "\n", + "# Create ta ui map widget to hold the lockdown NO2 image.\n", + "rightMap = ui.Map().setOptions('HYBRID')\n", + "\n", + "# Create a split panel widget to hold the two maps.\n", + "sliderPanel = ui.SplitPanel({\n", + " 'firstPanel': leftMap,\n", + " 'secondPanel': rightMap,\n", + " 'orientation': 'horizontal',\n", + " 'wipe': True,\n", + " 'style': {\n", + " 'stretch': 'both'\n", + " }\n", + "})\n", + "linker = ui.Map.Linker([leftMap, rightMap])\n", + "\n", + "# Make a function to add a label with fancy styling.\n", + "def makeMapLab(lab, position):\n", + " label = ui.Label({\n", + " 'value': lab,\n", + " 'style': {\n", + " 'fontSize': '16px',\n", + " 'color': '#ffffff',\n", + " 'fontWeight': 'bold',\n", + " 'backgroundColor': '#ffffff00',\n", + " 'padding': '0px'\n", + " }\n", + " })\n", + " panel = ui.Panel({\n", + " 'widgets': [label],\n", + " 'layout': ui.Panel.Layout.flow('horizontal'),\n", + " 'style': {\n", + " 'position': position,\n", + " 'backgroundColor': '#00000057',\n", + " 'padding': '0px'\n", + " }\n", + " })\n", + " return panel\n", + "\n", + "\n", + "# Create baseline map layer, add it to the left map, and add the label.\n", + "no2BaselineLayer = ui.Map.Layer(no2Baseline, no2Viz)\n", + "leftMap.layers().reset([no2BaselineLayer])\n", + "leftMap.add(makeMapLab('Baseline 2019', 'top-left'))\n", + "\n", + "# Create lockdown map layer, add it to the right map, and add the label.\n", + "no2LockdownLayer = ui.Map.Layer(no2Lockdown, no2Viz)\n", + "rightMap.layers().reset([no2LockdownLayer])\n", + "rightMap.add(makeMapLab('Lockdown 2020', 'top-right'))\n", + "\n", + "# Reset the map interface (ui.root) with the split panel widget.\n", + "# Note that the Map.addLayer() calls earlier on in Section 1\n", + "# will no longer be shown because we have replaced the Map widget\n", + "# with the sliderPanel widget.\n", + "ui.root.widgets().reset([sliderPanel])\n", + "\n", + "# Create a function to get the mean NO2 for the study region\n", + "# per image in the NO2 collection.\n", + "def getConc(collectionLabel, img):\n", + " return function(img) {\n", + " # Calculate the mean NO2.\n", + " no2Mean = img.reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': adminSelect.geometry(),\n", + " 'scale': 7000\n", + " }).get('tropospheric_NO2_column_number_density')\n", + "\n", + " # Get the day-of-year of the image.\n", + " doy = img.date().getRelative('day', 'year')\n", + "\n", + " # Return a feature with NO2 concentration and day-of-year properties.\n", + " return ee.Feature(None, {\n", + " 'conc': no2Mean,\n", + " 'DOY': doy,\n", + " 'type': collectionLabel\n", + " })\n", + " }\n", + "\n", + "\n", + "# Get the concentrations for a baseline and lockdown collection\n", + "# and merge for plotting.\n", + "no2AggChange_forPlotting = no2 \\\n", + " .filterDate('2020-03-01', '2020-04-01') \\\n", + " .map(getConc('lockdown')) \\\n", + " .merge(no2.filterDate('2019-03-01', '2019-04-01') \\\n", + " .map(getConc('baseline')))\n", + "no2AggChange_forPlotting = no2AggChange_forPlotting \\\n", + " .filter(ee.Filter.NotNull(['conc']))\n", + "\n", + "# Make a chart.\n", + "chart1 = ui.Chart.feature.groups(\n", + " no2AggChange_forPlotting, 'DOY', 'conc', 'type') \\\n", + " .setChartType('LineChart') \\\n", + " .setOptions({\n", + " 'title': 'DOY time series for mean [NO2] during ' + \\\n", + " 'March 2019 (baseline) and 2020 (lockdown)'\n", + " })\n", + "\n", + "# Print it to the console.\n", + "print('Baseline vs lockdown NO2 for the study region by DOY', chart1)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "#\n", + " # Section 3: calculating population-weighted concentrations\n", + " #\n", + "\n", + "# Define the spatial resolution of the population data.\n", + "scalePop = 927.67; # See details in GEE Catalogue.\n", + "\n", + "# Now we define a function that will map over the NO2 collection\n", + "# and calculate population-weighted concentrations.\n", + "# We will use the formula Exp = SUM {(Pi/P)*Ci}.\n", + "# We can calculate P outside of the function\n", + "# so that it is not computed multiple times for each NO2 image.\n", + "P = population.reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': adminSelect.geometry(),\n", + " 'scale': scalePop\n", + "}).get('population_count')\n", + "\n", + "# And here is the function.\n", + "def getPopWeightedConc(P, region, regionName, img):\n", + " return function(img) {\n", + " Ci = img\n", + " Pi = population\n", + " # Calculate the percentage of valid pixels in the region.\n", + " # (masked pixels will not be counted).\n", + " pixelCoverPerc = Ci.gte(0).unmask(0).multiply(100) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': region.geometry(),\n", + " 'scale': scalePop # Add in the scale of the population raster.\n", + " }).get('tropospheric_NO2_column_number_density')\n", + "\n", + " # Calculate the per-pixel EXP (see formula above).\n", + " exp = Pi.divide(ee.Image(ee.Number(P))).multiply(Ci)\n", + "\n", + " # Sum the exp over the region.\n", + " expSum = exp.reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': region.geometry(),\n", + " 'scale': scalePop\n", + " }).get('population_count')\n", + "\n", + " # Calculate the mean NO2 - the approach that would usually\n", + " # be taken without population weighting.\n", + " no2Mean = Ci.reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': region.geometry(),\n", + " 'scale': scalePop\n", + " }).get('tropospheric_NO2_column_number_density')\n", + "\n", + " # Return a feature with properties\n", + " featOut = ee.Feature(None, {\n", + " 'system:time_start': img.get(\n", + " 'system:time_start'),\n", + " 'dateString': img.date().format('YYYY-MM-DD'),\n", + " 'regionName': regionName,\n", + " 'no2ConcPopWeighted': expSum,\n", + " 'no2ConcRaw': no2Mean,\n", + " 'pixelCoverPerc': pixelCoverPerc\n", + " })\n", + "\n", + " return featOut\n", + " }\n", + "\n", + "\n", + "\n", + "# Filter the NO2 collection for March 2020 and map the function over it.\n", + "no2Agg_popWeighted = no2.filterDate('2020-03-01', '2020-04-01') \\\n", + " .map(getPopWeightedConc(P, adminSelect, 'Wuhan'))\n", + "no2Agg_popWeighted = ee.FeatureCollection(no2Agg_popWeighted)\n", + "\n", + "# Define the percentage of valid pixels you want in your region per time point.\n", + "# Here we choose 25; i.e. only images with at least 25% valid NO2 pixels.\n", + "validPixelPerc = 25; # you can play around with this value\n", + "\n", + "# Filter the feature collection based on your pixel criteria.\n", + "no2Agg_popWeighted = no2Agg_popWeighted \\\n", + " .filter(ee.Filter.greaterThanOrEquals('pixelCoverPerc',\n", + " validPixelPerc))\n", + "print('Population weighted no2 feature collection:',\n", + " no2Agg_popWeighted)\n", + "\n", + "# Create a feature collection for plotting the mean [NO2]\n", + "# and the mean pop-weighted [NO2] on the same graph.\n", + "\n", + "def func_grd(ft):\n", + " return ft.set('conc', ft.get('no2ConcPopWeighted'),\n", + " 'type', 'no2ConcPopWeighted')\n", + "\n", + "no2Agg_forPlotting = no2Agg_popWeighted.map(func_grd\n", + ").merge(no2Agg_popWeighted.map(function(ft) {\n", + "\n", + "\n", + "\n", + "def func_rng(ft):\n", + " return ft.set('conc', ft.get('no2ConcRaw'), 'type',\n", + " 'no2ConcRaw')\n", + "\n", + ").merge(no2Agg_popWeighted.map(func_rng\n", + "))\n", + "\n", + "\n", + "))\n", + "\n", + "# Make a chart\n", + "chart2 = ui.Chart.feature.groups(\n", + " no2Agg_forPlotting, 'system:time_start', 'conc', 'type') \\\n", + " .setChartType('LineChart') \\\n", + " .setOptions({\n", + " 'title': 'Time series for mean [NO2] and the pop-weighted [NO2]'\n", + " })\n", + "\n", + "# Print it to the console\n", + "print('Raw vs population-weighted NO2 for the study region', chart2)\n", + "\n", + "# Export population-weighted data for multiple regions.\n", + "# First select the regions. This can also be done with\n", + "# .filterBounds() as in Line 9 above.\n", + "regions = adminUnits \\\n", + " .filter(ee.Filter.inList('ADM1_NAME', ['Chongqing Shi',\n", + " 'Hubei Sheng'\n", + " ]))\n", + "# Map a function over the regions that calculates population-weighted [NO2].\n", + "\n", + "def func_pvo(region):\n", + " P = population.reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': region.geometry(),\n", + " 'scale': scalePop\n", + " }).get('population_count')\n", + " innerTable = no2.filterDate('2020-03-01',\n", + " '2020-04-01') \\\n", + " .map(getPopWeightedConc(P, region, region.get(\n", + " 'ADM1_NAME')))\n", + " return innerTable\n", + "\n", + "No2AggMulti_popWeighted = regions.map(func_pvo\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + "# Remember to filter out readings that have pixel percentage cover\n", + "# below your threshold\n", + "No2AggMulti_popWeighted = No2AggMulti_popWeighted \\\n", + " .filter(ee.Filter.greaterThanOrEquals('pixelCoverPerc',\n", + " validPixelPerc))\n", + "\n", + "# Run the export under the 'Tasks' tab on the right\n", + "# and find your CSV file in Google Drive later on.\n", + "Export.table.toDrive({\n", + " 'collection': No2AggMulti_popWeighted,\n", + " 'description': 'no2_popWeighted',\n", + " 'fileFormat': 'CSV'\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14c Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14c Checkpoint.js new file mode 100644 index 0000000..e1d6132 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14c Checkpoint.js @@ -0,0 +1,355 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometry = + /* color: #d63000 */ + /* shown: false */ + ee.Geometry.Point([114.26732477622326, 30.57603159263821]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.4 Air Pollution and Population Exposures +// Checkpoint: A14c +// Authors: Zander Venter and Sourangsu Chowdhury +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +/* + * Section 1: data import and cleaning + */ + +// Import a global dataset of administrative units level 1. +var adminUnits = ee.FeatureCollection( + 'FAO/GAUL_SIMPLIFIED_500m/2015/level1'); + +// Filter for the administrative unit that intersects +// the geometry located at the top of this script. +var adminSelect = adminUnits.filterBounds(geometry); + +// Center the map on this area. +Map.centerObject(adminSelect, 8); + +// Make the base map HYBRID. +Map.setOptions('HYBRID'); + +// Add it to the map to make sure you have what you want. +Map.addLayer(adminSelect, {}, 'selected admin unit'); + +// Import the population count data from Gridded Population of the World Version 4. +var population = ee.ImageCollection( + 'CIESIN/GPWv411/GPW_Population_Count') + // Filter for 2020 using the calendar range function. + .filter(ee.Filter.calendarRange(2020, 2020, 'year')) + // There should be only 1 image, but convert to an image using .mean(). + .mean(); + +// Clip it to your area of interest (only necessary for visualization purposes). +var populationClipped = population.clipToCollection(adminSelect); + +// Add it to the map to see the population distribution. +var popVis = { + min: 0, + max: 4000, + palette: ['black', 'yellow', 'white'], + opacity: 0.55 +}; +Map.addLayer(populationClipped, popVis, 'population count'); + +// Import the Sentinel-5P NO2 offline product. +var no2Raw = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2'); + +// Define function to exclude cloudy pixels. +function maskClouds(image) { + // Get the cloud fraction band of the image. + var cf = image.select('cloud_fraction'); + // Create a mask using 0.3 threshold. + var mask = cf.lte(0.3); // You can play around with this value. + // Return a masked image. + return image.updateMask(mask).copyProperties(image); +} + +// Clean and filter the Sentinel-5P NO2 offline product. +var no2 = no2Raw + // Filter for images intersecting our area of interest. + .filterBounds(adminSelect) + // Map the cloud masking function over the image collection. + .map(maskClouds) + // Select the tropospheric vertical column of NO2 band. + .select('tropospheric_NO2_column_number_density'); + +// Create a median composite for March 2021 +var no2Median = no2.filterDate('2021-03-01', '2021-04-01').median(); + +// Clip it to your area of interest (only necessary for visualization purposes). +var no2MedianClipped = no2Median.clipToCollection(adminSelect); + +// Visualize the median NO2. +var no2Viz = { + min: 0, + max: 0.00015, + palette: ['black', 'blue', 'purple', 'cyan', 'green', + 'yellow', 'red' + ] +}; +Map.addLayer(no2MedianClipped, no2Viz, 'median no2 Mar 2021'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +/* + * Section 2: quantifying and vizualizing change + */ + +// Define a lockdown NO2 median composite. +var no2Lockdown = no2.filterDate('2020-03-01', '2020-04-01') + .median().clipToCollection(adminSelect); + +// Define a baseline NO2 median using the same month in the previous year. +var no2Baseline = no2.filterDate('2019-03-01', '2019-04-01') + .median().clipToCollection(adminSelect); + +// Create a ui map widget to hold the baseline NO2 image. +var leftMap = ui.Map().centerObject(adminSelect, 8).setOptions( + 'HYBRID'); + +// Create ta ui map widget to hold the lockdown NO2 image. +var rightMap = ui.Map().setOptions('HYBRID'); + +// Create a split panel widget to hold the two maps. +var sliderPanel = ui.SplitPanel({ + firstPanel: leftMap, + secondPanel: rightMap, + orientation: 'horizontal', + wipe: true, + style: { + stretch: 'both' + } +}); +var linker = ui.Map.Linker([leftMap, rightMap]); + +// Make a function to add a label with fancy styling. +function makeMapLab(lab, position) { + var label = ui.Label({ + value: lab, + style: { + fontSize: '16px', + color: '#ffffff', + fontWeight: 'bold', + backgroundColor: '#ffffff00', + padding: '0px' + } + }); + var panel = ui.Panel({ + widgets: [label], + layout: ui.Panel.Layout.flow('horizontal'), + style: { + position: position, + backgroundColor: '#00000057', + padding: '0px' + } + }); + return panel; +} + +// Create baseline map layer, add it to the left map, and add the label. +var no2BaselineLayer = ui.Map.Layer(no2Baseline, no2Viz); +leftMap.layers().reset([no2BaselineLayer]); +leftMap.add(makeMapLab('Baseline 2019', 'top-left')); + +// Create lockdown map layer, add it to the right map, and add the label. +var no2LockdownLayer = ui.Map.Layer(no2Lockdown, no2Viz); +rightMap.layers().reset([no2LockdownLayer]); +rightMap.add(makeMapLab('Lockdown 2020', 'top-right')); + +// Reset the map interface (ui.root) with the split panel widget. +// Note that the Map.addLayer() calls earlier on in Section 1 +// will no longer be shown because we have replaced the Map widget +// with the sliderPanel widget. +ui.root.widgets().reset([sliderPanel]); + +// Create a function to get the mean NO2 for the study region +// per image in the NO2 collection. +function getConc(collectionLabel, img) { + return function(img) { + // Calculate the mean NO2. + var no2Mean = img.reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: adminSelect.geometry(), + scale: 7000 + }).get('tropospheric_NO2_column_number_density'); + + // Get the day-of-year of the image. + var doy = img.date().getRelative('day', 'year'); + + // Return a feature with NO2 concentration and day-of-year properties. + return ee.Feature(null, { + 'conc': no2Mean, + 'DOY': doy, + 'type': collectionLabel + }); + }; +} + +// Get the concentrations for a baseline and lockdown collection +// and merge for plotting. +var no2AggChange_forPlotting = no2 + .filterDate('2020-03-01', '2020-04-01') + .map(getConc('lockdown')) + .merge(no2.filterDate('2019-03-01', '2019-04-01') + .map(getConc('baseline'))); +no2AggChange_forPlotting = no2AggChange_forPlotting + .filter(ee.Filter.notNull(['conc'])); + +// Make a chart. +var chart1 = ui.Chart.feature.groups( + no2AggChange_forPlotting, 'DOY', 'conc', 'type') + .setChartType('LineChart') + .setOptions({ + title: 'DOY time series for mean [NO2] during ' + + 'March 2019 (baseline) and 2020 (lockdown)' + }); + +// Print it to the console. +print('Baseline vs lockdown NO2 for the study region by DOY', chart1); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +/* + * Section 3: calculating population-weighted concentrations + */ + +// Define the spatial resolution of the population data. +var scalePop = 927.67; // See details in GEE Catalogue. + +// Now we define a function that will map over the NO2 collection +// and calculate population-weighted concentrations. +// We will use the formula Exp = SUM {(Pi/P)*Ci}. +// We can calculate P outside of the function +// so that it is not computed multiple times for each NO2 image. +var P = population.reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: adminSelect.geometry(), + scale: scalePop +}).get('population_count'); + +// And here is the function. +function getPopWeightedConc(P, region, regionName, img) { + return function(img) { + var Ci = img; + var Pi = population; + // Calculate the percentage of valid pixels in the region. + // (masked pixels will not be counted). + var pixelCoverPerc = Ci.gte(0).unmask(0).multiply(100) + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: region.geometry(), + scale: scalePop // Add in the scale of the population raster. + }).get('tropospheric_NO2_column_number_density'); + + // Calculate the per-pixel EXP (see formula above). + var exp = Pi.divide(ee.Image(ee.Number(P))).multiply(Ci); + + // Sum the exp over the region. + var expSum = exp.reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: region.geometry(), + scale: scalePop + }).get('population_count'); + + // Calculate the mean NO2 - the approach that would usually + // be taken without population weighting. + var no2Mean = Ci.reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: region.geometry(), + scale: scalePop + }).get('tropospheric_NO2_column_number_density'); + + // Return a feature with properties + var featOut = ee.Feature(null, { + 'system:time_start': img.get( + 'system:time_start'), + 'dateString': img.date().format('YYYY-MM-DD'), + 'regionName': regionName, + 'no2ConcPopWeighted': expSum, + 'no2ConcRaw': no2Mean, + 'pixelCoverPerc': pixelCoverPerc + }); + + return featOut; + }; + +} + +// Filter the NO2 collection for March 2020 and map the function over it. +var no2Agg_popWeighted = no2.filterDate('2020-03-01', '2020-04-01') + .map(getPopWeightedConc(P, adminSelect, 'Wuhan')); +no2Agg_popWeighted = ee.FeatureCollection(no2Agg_popWeighted); + +// Define the percentage of valid pixels you want in your region per time point. +// Here we choose 25; i.e. only images with at least 25% valid NO2 pixels. +var validPixelPerc = 25; // you can play around with this value + +// Filter the feature collection based on your pixel criteria. +no2Agg_popWeighted = no2Agg_popWeighted + .filter(ee.Filter.greaterThanOrEquals('pixelCoverPerc', + validPixelPerc)); +print('Population weighted no2 feature collection:', + no2Agg_popWeighted); + +// Create a feature collection for plotting the mean [NO2] +// and the mean pop-weighted [NO2] on the same graph. +var no2Agg_forPlotting = no2Agg_popWeighted.map(function(ft) { + return ft.set('conc', ft.get('no2ConcPopWeighted'), + 'type', 'no2ConcPopWeighted'); +}).merge(no2Agg_popWeighted.map(function(ft) { + return ft.set('conc', ft.get('no2ConcRaw'), 'type', + 'no2ConcRaw'); +})); + +// Make a chart +var chart2 = ui.Chart.feature.groups( + no2Agg_forPlotting, 'system:time_start', 'conc', 'type') + .setChartType('LineChart') + .setOptions({ + title: 'Time series for mean [NO2] and the pop-weighted [NO2]' + }); + +// Print it to the console +print('Raw vs population-weighted NO2 for the study region', chart2); + +// Export population-weighted data for multiple regions. +// First select the regions. This can also be done with +// .filterBounds() as in Line 9 above. +var regions = adminUnits + .filter(ee.Filter.inList('ADM1_NAME', ['Chongqing Shi', + 'Hubei Sheng' + ])); +// Map a function over the regions that calculates population-weighted [NO2]. +var No2AggMulti_popWeighted = regions.map(function(region) { + var P = population.reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: region.geometry(), + scale: scalePop + }).get('population_count'); + var innerTable = no2.filterDate('2020-03-01', + '2020-04-01') + .map(getPopWeightedConc(P, region, region.get( + 'ADM1_NAME'))); + return innerTable; +}).flatten(); +// Remember to filter out readings that have pixel percentage cover +// below your threshold +No2AggMulti_popWeighted = No2AggMulti_popWeighted + .filter(ee.Filter.greaterThanOrEquals('pixelCoverPerc', + validPixelPerc)); + +// Run the export under the 'Tasks' tab on the right +// and find your CSV file in Google Drive later on. +Export.table.toDrive({ + collection: No2AggMulti_popWeighted, + description: 'no2_popWeighted', + fileFormat: 'CSV' +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14c Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14c Checkpoint.py new file mode 100644 index 0000000..1d81a9a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.4 Air Pollution/A14c Checkpoint.py @@ -0,0 +1,382 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometry = + + # shown: False # + ee.Geometry.Point([114.26732477622326, 30.57603159263821]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.4 Air Pollution and Population Exposures +# Checkpoint: A14c +# Authors: Zander Venter and Sourangsu Chowdhury +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# + # Section 1: data import and cleaning + # + +# Import a global dataset of administrative units level 1. +adminUnits = ee.FeatureCollection( + 'FAO/GAUL_SIMPLIFIED_500m/2015/level1') + +# Filter for the administrative unit that intersects +# the geometry located at the top of this script. +adminSelect = adminUnits.filterBounds(geometry) + +# Center the map on this area. +Map.centerObject(adminSelect, 8) + +# Make the base map HYBRID. +Map.setOptions('HYBRID') + +# Add it to the map to make sure you have what you want. +Map.addLayer(adminSelect, {}, 'selected admin unit') + +# Import the population count data from Gridded Population of the World Version 4. +population = ee.ImageCollection( + 'CIESIN/GPWv411/GPW_Population_Count') \ + .filter(ee.Filter.calendarRange(2020, 2020, 'year')) \ + .mean() + +# Clip it to your area of interest (only necessary for visualization purposes). +populationClipped = population.clipToCollection(adminSelect) + +# Add it to the map to see the population distribution. +popVis = { + 'min': 0, + 'max': 4000, + 'palette': ['black', 'yellow', 'white'], + 'opacity': 0.55 +} +Map.addLayer(populationClipped, popVis, 'population count') + +# Import the Sentinel-5P NO2 offline product. +no2Raw = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2') + +# Define function to exclude cloudy pixels. +def maskClouds(image): + # Get the cloud fraction band of the image. + cf = image.select('cloud_fraction') + # Create a mask using 0.3 threshold. + mask = cf.lte(0.3); # You can play around with this value. + # Return a masked image. + return image.updateMask(mask).copyProperties(image) + + +# Clean and filter the Sentinel-5P NO2 offline product. +no2 = no2Raw \ + .filterBounds(adminSelect) \ + .map(maskClouds) \ + .select('tropospheric_NO2_column_number_density') + +# Create a median composite for March 2021 +no2Median = no2.filterDate('2021-03-01', '2021-04-01').median() + +# Clip it to your area of interest (only necessary for visualization purposes). +no2MedianClipped = no2Median.clipToCollection(adminSelect) + +# Visualize the median NO2. +no2Viz = { + 'min': 0, + 'max': 0.00015, + 'palette': ['black', 'blue', 'purple', 'cyan', 'green', + 'yellow', 'red' + ] +} +Map.addLayer(no2MedianClipped, no2Viz, 'median no2 Mar 2021') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# + # Section 2: quantifying and vizualizing change + # + +# Define a lockdown NO2 median composite. +no2Lockdown = no2.filterDate('2020-03-01', '2020-04-01') \ + .median().clipToCollection(adminSelect) + +# Define a baseline NO2 median using the same month in the previous year. +no2Baseline = no2.filterDate('2019-03-01', '2019-04-01') \ + .median().clipToCollection(adminSelect) + +# Create a ui map widget to hold the baseline NO2 image. +leftMap = ui.Map().centerObject(adminSelect, 8).setOptions( + 'HYBRID') + +# Create ta ui map widget to hold the lockdown NO2 image. +rightMap = ui.Map().setOptions('HYBRID') + +# Create a split panel widget to hold the two maps. +sliderPanel = ui.SplitPanel({ + 'firstPanel': leftMap, + 'secondPanel': rightMap, + 'orientation': 'horizontal', + 'wipe': True, + 'style': { + 'stretch': 'both' + } +}) +linker = ui.Map.Linker([leftMap, rightMap]) + +# Make a function to add a label with fancy styling. +def makeMapLab(lab, position): + label = ui.Label({ + 'value': lab, + 'style': { + 'fontSize': '16px', + 'color': '#ffffff', + 'fontWeight': 'bold', + 'backgroundColor': '#ffffff00', + 'padding': '0px' + } + }) + panel = ui.Panel({ + 'widgets': [label], + 'layout': ui.Panel.Layout.flow('horizontal'), + 'style': { + 'position': position, + 'backgroundColor': '#00000057', + 'padding': '0px' + } + }) + return panel + + +# Create baseline map layer, add it to the left map, and add the label. +no2BaselineLayer = ui.Map.Layer(no2Baseline, no2Viz) +leftMap.layers().reset([no2BaselineLayer]) +leftMap.add(makeMapLab('Baseline 2019', 'top-left')) + +# Create lockdown map layer, add it to the right map, and add the label. +no2LockdownLayer = ui.Map.Layer(no2Lockdown, no2Viz) +rightMap.layers().reset([no2LockdownLayer]) +rightMap.add(makeMapLab('Lockdown 2020', 'top-right')) + +# Reset the map interface (ui.root) with the split panel widget. +# Note that the Map.addLayer() calls earlier on in Section 1 +# will no longer be shown because we have replaced the Map widget +# with the sliderPanel widget. +ui.root.widgets().reset([sliderPanel]) + +# Create a function to get the mean NO2 for the study region +# per image in the NO2 collection. +def getConc(collectionLabel, img): + return function(img) { + # Calculate the mean NO2. + no2Mean = img.reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': adminSelect.geometry(), + 'scale': 7000 + }).get('tropospheric_NO2_column_number_density') + + # Get the day-of-year of the image. + doy = img.date().getRelative('day', 'year') + + # Return a feature with NO2 concentration and day-of-year properties. + return ee.Feature(None, { + 'conc': no2Mean, + 'DOY': doy, + 'type': collectionLabel + }) + } + + +# Get the concentrations for a baseline and lockdown collection +# and merge for plotting. +no2AggChange_forPlotting = no2 \ + .filterDate('2020-03-01', '2020-04-01') \ + .map(getConc('lockdown')) \ + .merge(no2.filterDate('2019-03-01', '2019-04-01') \ + .map(getConc('baseline'))) +no2AggChange_forPlotting = no2AggChange_forPlotting \ + .filter(ee.Filter.NotNull(['conc'])) + +# Make a chart. +chart1 = ui.Chart.feature.groups( + no2AggChange_forPlotting, 'DOY', 'conc', 'type') \ + .setChartType('LineChart') \ + .setOptions({ + 'title': 'DOY time series for mean [NO2] during ' + \ + 'March 2019 (baseline) and 2020 (lockdown)' + }) + +# Print it to the console. +print('Baseline vs lockdown NO2 for the study region by DOY', chart1) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# + # Section 3: calculating population-weighted concentrations + # + +# Define the spatial resolution of the population data. +scalePop = 927.67; # See details in GEE Catalogue. + +# Now we define a function that will map over the NO2 collection +# and calculate population-weighted concentrations. +# We will use the formula Exp = SUM {(Pi/P)*Ci}. +# We can calculate P outside of the function +# so that it is not computed multiple times for each NO2 image. +P = population.reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': adminSelect.geometry(), + 'scale': scalePop +}).get('population_count') + +# And here is the function. +def getPopWeightedConc(P, region, regionName, img): + return function(img) { + Ci = img + Pi = population + # Calculate the percentage of valid pixels in the region. + # (masked pixels will not be counted). + pixelCoverPerc = Ci.gte(0).unmask(0).multiply(100) \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': region.geometry(), + 'scale': scalePop # Add in the scale of the population raster. + }).get('tropospheric_NO2_column_number_density') + + # Calculate the per-pixel EXP (see formula above). + exp = Pi.divide(ee.Image(ee.Number(P))).multiply(Ci) + + # Sum the exp over the region. + expSum = exp.reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': region.geometry(), + 'scale': scalePop + }).get('population_count') + + # Calculate the mean NO2 - the approach that would usually + # be taken without population weighting. + no2Mean = Ci.reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': region.geometry(), + 'scale': scalePop + }).get('tropospheric_NO2_column_number_density') + + # Return a feature with properties + featOut = ee.Feature(None, { + 'system:time_start': img.get( + 'system:time_start'), + 'dateString': img.date().format('YYYY-MM-DD'), + 'regionName': regionName, + 'no2ConcPopWeighted': expSum, + 'no2ConcRaw': no2Mean, + 'pixelCoverPerc': pixelCoverPerc + }) + + return featOut + } + + + +# Filter the NO2 collection for March 2020 and map the function over it. +no2Agg_popWeighted = no2.filterDate('2020-03-01', '2020-04-01') \ + .map(getPopWeightedConc(P, adminSelect, 'Wuhan')) +no2Agg_popWeighted = ee.FeatureCollection(no2Agg_popWeighted) + +# Define the percentage of valid pixels you want in your region per time point. +# Here we choose 25; i.e. only images with at least 25% valid NO2 pixels. +validPixelPerc = 25; # you can play around with this value + +# Filter the feature collection based on your pixel criteria. +no2Agg_popWeighted = no2Agg_popWeighted \ + .filter(ee.Filter.greaterThanOrEquals('pixelCoverPerc', + validPixelPerc)) +print('Population weighted no2 feature collection:', + no2Agg_popWeighted) + +# Create a feature collection for plotting the mean [NO2] +# and the mean pop-weighted [NO2] on the same graph. + +def func_grd(ft): + return ft.set('conc', ft.get('no2ConcPopWeighted'), + 'type', 'no2ConcPopWeighted') + +no2Agg_forPlotting = no2Agg_popWeighted.map(func_grd +).merge(no2Agg_popWeighted.map(function(ft) { + + + +def func_rng(ft): + return ft.set('conc', ft.get('no2ConcRaw'), 'type', + 'no2ConcRaw') + +).merge(no2Agg_popWeighted.map(func_rng +)) + + +)) + +# Make a chart +chart2 = ui.Chart.feature.groups( + no2Agg_forPlotting, 'system:time_start', 'conc', 'type') \ + .setChartType('LineChart') \ + .setOptions({ + 'title': 'Time series for mean [NO2] and the pop-weighted [NO2]' + }) + +# Print it to the console +print('Raw vs population-weighted NO2 for the study region', chart2) + +# Export population-weighted data for multiple regions. +# First select the regions. This can also be done with +# .filterBounds() as in Line 9 above. +regions = adminUnits \ + .filter(ee.Filter.inList('ADM1_NAME', ['Chongqing Shi', + 'Hubei Sheng' + ])) +# Map a function over the regions that calculates population-weighted [NO2]. + +def func_pvo(region): + P = population.reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': region.geometry(), + 'scale': scalePop + }).get('population_count') + innerTable = no2.filterDate('2020-03-01', + '2020-04-01') \ + .map(getPopWeightedConc(P, region, region.get( + 'ADM1_NAME'))) + return innerTable + +No2AggMulti_popWeighted = regions.map(func_pvo +).flatten() + + + + + + + + + + +).flatten() +# Remember to filter out readings that have pixel percentage cover +# below your threshold +No2AggMulti_popWeighted = No2AggMulti_popWeighted \ + .filter(ee.Filter.greaterThanOrEquals('pixelCoverPerc', + validPixelPerc)) + +# Run the export under the 'Tasks' tab on the right +# and find your CSV file in Google Drive later on. +Export.table.toDrive({ + 'collection': No2AggMulti_popWeighted, + 'description': 'no2_popWeighted', + 'fileFormat': 'CSV' +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15a Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15a Checkpoint.ipynb new file mode 100644 index 0000000..1c3f98a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15a Checkpoint.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.5 Heat Islands\n", + "# Checkpoint: A15a\n", + "# Author: TC Chakraborty\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load feature collection of New Haven's census tracts from user assets.\n", + "regionInt = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-5/TC_NewHaven')\n", + "\n", + "# Get dissolved feature collection using an error margin of 50 meters.\n", + "regionInt = regionInt.union(50)\n", + "\n", + "# Set map center and zoom level (Zoom level varies from 1 to 20).\n", + "Map.setCenter(-72.9, 41.3, 12)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(regionInt, {}, 'New Haven boundary')\n", + "\n", + "# Load MODIS image collection from the Earth Engine data catalog.\n", + "modisLst = ee.ImageCollection('MODIS/006/MYD11A2')\n", + "\n", + "# Select the band of interest (in this case: Daytime LST).\n", + "landSurfTemperature = modisLst.select('LST_Day_1km')\n", + "\n", + "# Create a summer filter.\n", + "sumFilter = ee.Filter.dayOfYear(152, 243)\n", + "\n", + "# Filter the date range of interest using a date filter.\n", + "lstDateInt = landSurfTemperature \\\n", + " .filterDate('2014-01-01', '2019-01-01').filter(sumFilter)\n", + "\n", + "# Take pixel-wise mean of all the images in the collection.\n", + "lstMean = lstDateInt.mean()\n", + "\n", + "# Multiply each pixel by scaling factor to get the LST values.\n", + "lstFinal = lstMean.multiply(0.02)\n", + "\n", + "# Generate a water mask.\n", + "water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select(\n", + " 'occurrence')\n", + "notWater = water.mask().Not()\n", + "\n", + "# Clip data to region of interest, convert to degree Celsius, and mask water pixels.\n", + "lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \\\n", + " .updateMask(notWater)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(lstNewHaven, {\n", + " 'palette': ['blue', 'white', 'red'],\n", + " 'min': 25,\n", + " 'max': 38\n", + " },\n", + " 'LST_MODIS')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15a Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15a Checkpoint.js new file mode 100644 index 0000000..9d4511a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15a Checkpoint.js @@ -0,0 +1,58 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.5 Heat Islands +// Checkpoint: A15a +// Author: TC Chakraborty +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load feature collection of New Haven's census tracts from user assets. +var regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven'); + +// Get dissolved feature collection using an error margin of 50 meters. +var regionInt = regionInt.union(50); + +// Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12); + +// Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary'); + +// Load MODIS image collection from the Earth Engine data catalog. +var modisLst = ee.ImageCollection('MODIS/006/MYD11A2'); + +// Select the band of interest (in this case: Daytime LST). +var landSurfTemperature = modisLst.select('LST_Day_1km'); + +// Create a summer filter. +var sumFilter = ee.Filter.dayOfYear(152, 243); + +// Filter the date range of interest using a date filter. +var lstDateInt = landSurfTemperature + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter); + +// Take pixel-wise mean of all the images in the collection. +var lstMean = lstDateInt.mean(); + +// Multiply each pixel by scaling factor to get the LST values. +var lstFinal = lstMean.multiply(0.02); + +// Generate a water mask. +var water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence'); +var notWater = water.mask().not(); + +// Clip data to region of interest, convert to degree Celsius, and mask water pixels. +var lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) + .updateMask(notWater); + +// Add layer to map. +Map.addLayer(lstNewHaven, { + palette: ['blue', 'white', 'red'], + min: 25, + max: 38 + }, + 'LST_MODIS'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15a Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15a Checkpoint.py new file mode 100644 index 0000000..a444e36 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15a Checkpoint.py @@ -0,0 +1,64 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.5 Heat Islands +# Checkpoint: A15a +# Author: TC Chakraborty +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load feature collection of New Haven's census tracts from user assets. +regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven') + +# Get dissolved feature collection using an error margin of 50 meters. +regionInt = regionInt.union(50) + +# Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12) + +# Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary') + +# Load MODIS image collection from the Earth Engine data catalog. +modisLst = ee.ImageCollection('MODIS/006/MYD11A2') + +# Select the band of interest (in this case: Daytime LST). +landSurfTemperature = modisLst.select('LST_Day_1km') + +# Create a summer filter. +sumFilter = ee.Filter.dayOfYear(152, 243) + +# Filter the date range of interest using a date filter. +lstDateInt = landSurfTemperature \ + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter) + +# Take pixel-wise mean of all the images in the collection. +lstMean = lstDateInt.mean() + +# Multiply each pixel by scaling factor to get the LST values. +lstFinal = lstMean.multiply(0.02) + +# Generate a water mask. +water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence') +notWater = water.mask().Not() + +# Clip data to region of interest, convert to degree Celsius, and mask water pixels. +lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \ + .updateMask(notWater) + +# Add layer to map. +Map.addLayer(lstNewHaven, { + 'palette': ['blue', 'white', 'red'], + 'min': 25, + 'max': 38 + }, + 'LST_MODIS') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15b Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15b Checkpoint.ipynb new file mode 100644 index 0000000..42f94ab --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15b Checkpoint.ipynb @@ -0,0 +1,259 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.5 Heat Islands\n", + "# Checkpoint: A15b\n", + "# Author: TC Chakraborty\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load feature collection of New Haven's census tracts from user assets.\n", + "regionInt = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-5/TC_NewHaven')\n", + "\n", + "# Get dissolved feature collection using an error margin of 50 meters.\n", + "regionInt = regionInt.union(50)\n", + "\n", + "# Set map center and zoom level (Zoom level varies from 1 to 20).\n", + "Map.setCenter(-72.9, 41.3, 12)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(regionInt, {}, 'New Haven boundary')\n", + "\n", + "# Load MODIS image collection from the Earth Engine data catalog.\n", + "modisLst = ee.ImageCollection('MODIS/006/MYD11A2')\n", + "\n", + "# Select the band of interest (in this case: Daytime LST).\n", + "landSurfTemperature = modisLst.select('LST_Day_1km')\n", + "\n", + "# Create a summer filter.\n", + "sumFilter = ee.Filter.dayOfYear(152, 243)\n", + "\n", + "# Filter the date range of interest using a date filter.\n", + "lstDateInt = landSurfTemperature \\\n", + " .filterDate('2014-01-01', '2019-01-01').filter(sumFilter)\n", + "\n", + "# Take pixel-wise mean of all the images in the collection.\n", + "lstMean = lstDateInt.mean()\n", + "\n", + "# Multiply each pixel by scaling factor to get the LST values.\n", + "lstFinal = lstMean.multiply(0.02)\n", + "\n", + "# Generate a water mask.\n", + "water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select(\n", + " 'occurrence')\n", + "notWater = water.mask().Not()\n", + "\n", + "# Clip data to region of interest, convert to degree Celsius, and mask water pixels.\n", + "lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \\\n", + " .updateMask(notWater)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(lstNewHaven, {\n", + " 'palette': ['blue', 'white', 'red'],\n", + " 'min': 25,\n", + " 'max': 38\n", + " },\n", + " 'LST_MODIS')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Function to filter out cloudy pixels.\n", + "def cloudMask(cloudyScene):\n", + " # Add a cloud score band to the image.\n", + " scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene)\n", + "\n", + " # Create an image mask from the cloud score band and specify threshold.\n", + " mask = scored.select(['cloud']).lte(10)\n", + "\n", + " # Apply the mask to the original image and return the masked image.\n", + " return cloudyScene.updateMask(mask)\n", + "\n", + "\n", + "# Load the collection, apply cloud mask, and filter to date and region of interest.\n", + "col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterBounds(regionInt) \\\n", + " .filterDate('2014-01-01', '2019-01-01') \\\n", + " .filter(sumFilter) \\\n", + " .map(cloudMask)\n", + "\n", + "print('Landsat collection', col)\n", + "\n", + "# Generate median composite.\n", + "image = col.median()\n", + "\n", + "# Select thermal band 10 (with brightness temperature).\n", + "thermal = image.select('B10') \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater)\n", + "\n", + "Map.addLayer(thermal, {\n", + " 'min': 295,\n", + " 'max': 310,\n", + " 'palette': ['blue', 'white', 'red']\n", + " },\n", + " 'Landsat_BT')\n", + "\n", + "# Calculate Normalized Difference Vegetation Index (NDVI)\n", + "# from Landsat surface reflectance.\n", + "ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(regionInt) \\\n", + " .filterDate('2014-01-01', '2019-01-01') \\\n", + " .filter(sumFilter) \\\n", + " .median() \\\n", + " .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater)\n", + "\n", + "Map.addLayer(ndvi, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + " },\n", + " 'ndvi')\n", + "\n", + "# Find the minimum and maximum of NDVI. Combine the reducers\n", + "# for efficiency (single pass over the data).\n", + "minMax = ndvi.reduceRegion({\n", + " 'reducer': ee.Reducer.min().combine({\n", + " 'reducer2': ee.Reducer.max(),\n", + " 'sharedInputs': True\n", + " }),\n", + " 'geometry': regionInt,\n", + " 'scale': 30,\n", + " 'maxPixels': 1e9\n", + "})\n", + "print('minMax', minMax)\n", + "\n", + "min = ee.Number(minMax.get('NDVI_min'))\n", + "max = ee.Number(minMax.get('NDVI_max'))\n", + "\n", + "# Calculate fractional vegetation.\n", + "fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV')\n", + "Map.addLayer(fv, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + "}, 'fv')\n", + "\n", + "# Emissivity calculations.\n", + "a = ee.Number(0.004)\n", + "b = ee.Number(0.986)\n", + "em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater)\n", + "\n", + "Map.addLayer(em, {\n", + " 'min': 0.98,\n", + " 'max': 0.99,\n", + " 'palette': ['blue', 'white', 'green']\n", + " },\n", + " 'EMM')\n", + "\n", + "# Calculate LST from emissivity and brightness temperature.\n", + "lstLandsat = thermal.expression(\n", + " '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', {\n", + " 'Tb': thermal.select('B10'),\n", + " 'Ep': em.select('EMM')\n", + " }).updateMask(notWater)\n", + "\n", + "Map.addLayer(lstLandsat, {\n", + " 'min': 25,\n", + " 'max': 35,\n", + " 'palette': ['blue', 'white', 'red'],\n", + " },\n", + " 'LST_Landsat')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15b Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15b Checkpoint.js new file mode 100644 index 0000000..6307249 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15b Checkpoint.js @@ -0,0 +1,166 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.5 Heat Islands +// Checkpoint: A15b +// Author: TC Chakraborty +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load feature collection of New Haven's census tracts from user assets. +var regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven'); + +// Get dissolved feature collection using an error margin of 50 meters. +var regionInt = regionInt.union(50); + +// Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12); + +// Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary'); + +// Load MODIS image collection from the Earth Engine data catalog. +var modisLst = ee.ImageCollection('MODIS/006/MYD11A2'); + +// Select the band of interest (in this case: Daytime LST). +var landSurfTemperature = modisLst.select('LST_Day_1km'); + +// Create a summer filter. +var sumFilter = ee.Filter.dayOfYear(152, 243); + +// Filter the date range of interest using a date filter. +var lstDateInt = landSurfTemperature + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter); + +// Take pixel-wise mean of all the images in the collection. +var lstMean = lstDateInt.mean(); + +// Multiply each pixel by scaling factor to get the LST values. +var lstFinal = lstMean.multiply(0.02); + +// Generate a water mask. +var water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence'); +var notWater = water.mask().not(); + +// Clip data to region of interest, convert to degree Celsius, and mask water pixels. +var lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) + .updateMask(notWater); + +// Add layer to map. +Map.addLayer(lstNewHaven, { + palette: ['blue', 'white', 'red'], + min: 25, + max: 38 + }, + 'LST_MODIS'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Function to filter out cloudy pixels. +function cloudMask(cloudyScene) { + // Add a cloud score band to the image. + var scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene); + + // Create an image mask from the cloud score band and specify threshold. + var mask = scored.select(['cloud']).lte(10); + + // Apply the mask to the original image and return the masked image. + return cloudyScene.updateMask(mask); +} + +// Load the collection, apply cloud mask, and filter to date and region of interest. +var col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterBounds(regionInt) + .filterDate('2014-01-01', '2019-01-01') + .filter(sumFilter) + .map(cloudMask); + +print('Landsat collection', col); + +// Generate median composite. +var image = col.median(); + +// Select thermal band 10 (with brightness temperature). +var thermal = image.select('B10') + .clip(regionInt) + .updateMask(notWater); + +Map.addLayer(thermal, { + min: 295, + max: 310, + palette: ['blue', 'white', 'red'] + }, + 'Landsat_BT'); + +// Calculate Normalized Difference Vegetation Index (NDVI) +// from Landsat surface reflectance. +var ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(regionInt) + .filterDate('2014-01-01', '2019-01-01') + .filter(sumFilter) + .median() + .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') + .clip(regionInt) + .updateMask(notWater); + +Map.addLayer(ndvi, { + min: 0, + max: 1, + palette: ['blue', 'white', 'green'] + }, + 'ndvi'); + +// Find the minimum and maximum of NDVI. Combine the reducers +// for efficiency (single pass over the data). +var minMax = ndvi.reduceRegion({ + reducer: ee.Reducer.min().combine({ + reducer2: ee.Reducer.max(), + sharedInputs: true + }), + geometry: regionInt, + scale: 30, + maxPixels: 1e9 +}); +print('minMax', minMax); + +var min = ee.Number(minMax.get('NDVI_min')); +var max = ee.Number(minMax.get('NDVI_max')); + +// Calculate fractional vegetation. +var fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV'); +Map.addLayer(fv, { + min: 0, + max: 1, + palette: ['blue', 'white', 'green'] +}, 'fv'); + +// Emissivity calculations. +var a = ee.Number(0.004); +var b = ee.Number(0.986); +var em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater); + +Map.addLayer(em, { + min: 0.98, + max: 0.99, + palette: ['blue', 'white', 'green'] + }, + 'EMM'); + +// Calculate LST from emissivity and brightness temperature. +var lstLandsat = thermal.expression( + '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', { + 'Tb': thermal.select('B10'), + 'Ep': em.select('EMM') + }).updateMask(notWater); + +Map.addLayer(lstLandsat, { + min: 25, + max: 35, + palette: ['blue', 'white', 'red'], + }, + 'LST_Landsat'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15b Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15b Checkpoint.py new file mode 100644 index 0000000..c30bce5 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15b Checkpoint.py @@ -0,0 +1,172 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.5 Heat Islands +# Checkpoint: A15b +# Author: TC Chakraborty +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load feature collection of New Haven's census tracts from user assets. +regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven') + +# Get dissolved feature collection using an error margin of 50 meters. +regionInt = regionInt.union(50) + +# Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12) + +# Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary') + +# Load MODIS image collection from the Earth Engine data catalog. +modisLst = ee.ImageCollection('MODIS/006/MYD11A2') + +# Select the band of interest (in this case: Daytime LST). +landSurfTemperature = modisLst.select('LST_Day_1km') + +# Create a summer filter. +sumFilter = ee.Filter.dayOfYear(152, 243) + +# Filter the date range of interest using a date filter. +lstDateInt = landSurfTemperature \ + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter) + +# Take pixel-wise mean of all the images in the collection. +lstMean = lstDateInt.mean() + +# Multiply each pixel by scaling factor to get the LST values. +lstFinal = lstMean.multiply(0.02) + +# Generate a water mask. +water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence') +notWater = water.mask().Not() + +# Clip data to region of interest, convert to degree Celsius, and mask water pixels. +lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \ + .updateMask(notWater) + +# Add layer to map. +Map.addLayer(lstNewHaven, { + 'palette': ['blue', 'white', 'red'], + 'min': 25, + 'max': 38 + }, + 'LST_MODIS') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Function to filter out cloudy pixels. +def cloudMask(cloudyScene): + # Add a cloud score band to the image. + scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene) + + # Create an image mask from the cloud score band and specify threshold. + mask = scored.select(['cloud']).lte(10) + + # Apply the mask to the original image and return the masked image. + return cloudyScene.updateMask(mask) + + +# Load the collection, apply cloud mask, and filter to date and region of interest. +col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterBounds(regionInt) \ + .filterDate('2014-01-01', '2019-01-01') \ + .filter(sumFilter) \ + .map(cloudMask) + +print('Landsat collection', col) + +# Generate median composite. +image = col.median() + +# Select thermal band 10 (with brightness temperature). +thermal = image.select('B10') \ + .clip(regionInt) \ + .updateMask(notWater) + +Map.addLayer(thermal, { + 'min': 295, + 'max': 310, + 'palette': ['blue', 'white', 'red'] + }, + 'Landsat_BT') + +# Calculate Normalized Difference Vegetation Index (NDVI) +# from Landsat surface reflectance. +ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(regionInt) \ + .filterDate('2014-01-01', '2019-01-01') \ + .filter(sumFilter) \ + .median() \ + .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') \ + .clip(regionInt) \ + .updateMask(notWater) + +Map.addLayer(ndvi, { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'white', 'green'] + }, + 'ndvi') + +# Find the minimum and maximum of NDVI. Combine the reducers +# for efficiency (single pass over the data). +minMax = ndvi.reduceRegion({ + 'reducer': ee.Reducer.min().combine({ + 'reducer2': ee.Reducer.max(), + 'sharedInputs': True + }), + 'geometry': regionInt, + 'scale': 30, + 'maxPixels': 1e9 +}) +print('minMax', minMax) + +min = ee.Number(minMax.get('NDVI_min')) +max = ee.Number(minMax.get('NDVI_max')) + +# Calculate fractional vegetation. +fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV') +Map.addLayer(fv, { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'white', 'green'] +}, 'fv') + +# Emissivity calculations. +a = ee.Number(0.004) +b = ee.Number(0.986) +em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater) + +Map.addLayer(em, { + 'min': 0.98, + 'max': 0.99, + 'palette': ['blue', 'white', 'green'] + }, + 'EMM') + +# Calculate LST from emissivity and brightness temperature. +lstLandsat = thermal.expression( + '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', { + 'Tb': thermal.select('B10'), + 'Ep': em.select('EMM') + }).updateMask(notWater) + +Map.addLayer(lstLandsat, { + 'min': 25, + 'max': 35, + 'palette': ['blue', 'white', 'red'], + }, + 'LST_Landsat') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15c Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15c Checkpoint.ipynb new file mode 100644 index 0000000..ee78f66 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15c Checkpoint.ipynb @@ -0,0 +1,294 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.5 Heat Islands\n", + "# Checkpoint: A15c\n", + "# Author: TC Chakraborty\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load feature collection of New Haven's census tracts from user assets.\n", + "regionInt = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-5/TC_NewHaven')\n", + "\n", + "# Get dissolved feature collection using an error margin of 50 meters.\n", + "regionInt = regionInt.union(50)\n", + "\n", + "# Set map center and zoom level (Zoom level varies from 1 to 20).\n", + "Map.setCenter(-72.9, 41.3, 12)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(regionInt, {}, 'New Haven boundary')\n", + "\n", + "# Load MODIS image collection from the Earth Engine data catalog.\n", + "modisLst = ee.ImageCollection('MODIS/006/MYD11A2')\n", + "\n", + "# Select the band of interest (in this case: Daytime LST).\n", + "landSurfTemperature = modisLst.select('LST_Day_1km')\n", + "\n", + "# Create a summer filter.\n", + "sumFilter = ee.Filter.dayOfYear(152, 243)\n", + "\n", + "#Filter the date range of interest using a date filter.\n", + "lstDateInt = landSurfTemperature \\\n", + " .filterDate('2014-01-01', '2019-01-01').filter(sumFilter)\n", + "\n", + "# Take pixel-wise mean of all the images in the collection.\n", + "lstMean = lstDateInt.mean()\n", + "\n", + "# Multiply each pixel by scaling factor to get the LST values.\n", + "lstFinal = lstMean.multiply(0.02)\n", + "\n", + "# Generate a water mask.\n", + "water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select(\n", + " 'occurrence')\n", + "notWater = water.mask().Not()\n", + "\n", + "# Clip data to region of interest, convert to degree Celsius, and mask water pixels.\n", + "lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \\\n", + " .updateMask(notWater)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(lstNewHaven, {\n", + " 'palette': ['blue', 'white', 'red'],\n", + " 'min': 25,\n", + " 'max': 38\n", + " },\n", + " 'LST_MODIS')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Function to filter out cloudy pixels.\n", + "def cloudMask(cloudyScene):\n", + " # Add a cloud score band to the image.\n", + " scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene)\n", + "\n", + " # Create an image mask from the cloud score band and specify threshold.\n", + " mask = scored.select(['cloud']).lte(10)\n", + "\n", + " # Apply the mask to the original image and return the masked image.\n", + " return cloudyScene.updateMask(mask)\n", + "\n", + "\n", + "# Load the collection, apply cloud mask, and filter to date and region of interest.\n", + "col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterBounds(regionInt) \\\n", + " .filterDate('2014-01-01', '2019-01-01') \\\n", + " .filter(sumFilter) \\\n", + " .map(cloudMask)\n", + "\n", + "print('Landsat collection', col)\n", + "\n", + "# Generate median composite.\n", + "image = col.median()\n", + "\n", + "# Select thermal band 10 (with brightness temperature).\n", + "thermal = image.select('B10') \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater)\n", + "\n", + "Map.addLayer(thermal, {\n", + " 'min': 295,\n", + " 'max': 310,\n", + " 'palette': ['blue', 'white', 'red']\n", + " },\n", + " 'Landsat_BT')\n", + "\n", + "# Calculate Normalized Difference Vegetation Index (NDVI)\n", + "# from Landsat surface reflectance.\n", + "ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(regionInt) \\\n", + " .filterDate('2014-01-01', '2019-01-01') \\\n", + " .filter(sumFilter) \\\n", + " .median() \\\n", + " .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater)\n", + "\n", + "Map.addLayer(ndvi, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + " },\n", + " 'ndvi')\n", + "\n", + "# Find the minimum and maximum of NDVI. Combine the reducers\n", + "# for efficiency (single pass over the data).\n", + "minMax = ndvi.reduceRegion({\n", + " 'reducer': ee.Reducer.min().combine({\n", + " 'reducer2': ee.Reducer.max(),\n", + " 'sharedInputs': True\n", + " }),\n", + " 'geometry': regionInt,\n", + " 'scale': 30,\n", + " 'maxPixels': 1e9\n", + "})\n", + "print('minMax', minMax)\n", + "\n", + "min = ee.Number(minMax.get('NDVI_min'))\n", + "max = ee.Number(minMax.get('NDVI_max'))\n", + "\n", + "# Calculate fractional vegetation.\n", + "fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV')\n", + "Map.addLayer(fv, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + "}, 'fv')\n", + "\n", + "# Emissivity calculations.\n", + "a = ee.Number(0.004)\n", + "b = ee.Number(0.986)\n", + "em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater)\n", + "\n", + "Map.addLayer(em, {\n", + " 'min': 0.98,\n", + " 'max': 0.99,\n", + " 'palette': ['blue', 'white', 'green']\n", + " },\n", + " 'EMM')\n", + "\n", + "# Calculate LST from emissivity and brightness temperature.\n", + "lstLandsat = thermal.expression(\n", + " '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', {\n", + " 'Tb': thermal.select('B10'),\n", + " 'Ep': em.select('EMM')\n", + " }).updateMask(notWater)\n", + "\n", + "Map.addLayer(lstLandsat, {\n", + " 'min': 25,\n", + " 'max': 35,\n", + " 'palette': ['blue', 'white', 'red'],\n", + " },\n", + " 'LST_Landsat')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Link to the module that computes the Landsat LST.\n", + "landsatLST = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js')\n", + "\n", + "# Select region of interest, date range, and Landsat satellite.\n", + "geometry = regionInt.geometry()\n", + "satellite = 'L8'\n", + "dateStart = '2014-01-01'\n", + "dateEnd = '2019-01-01'\n", + "useNdvi = True\n", + "\n", + "# Get Landsat collection with additional necessary variables.\n", + "landsatColl = landsatLST.collection(satellite, dateStart, dateEnd,\n", + " geometry, useNdvi)\n", + "\n", + "# Create composite, clip, filter to summer, mask, and convert to degree Celsius.\n", + "landsatComp = landsatColl \\\n", + " .select('LST') \\\n", + " .filter(sumFilter) \\\n", + " .median() \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater) \\\n", + " .subtract(273.15)\n", + "\n", + "Map.addLayer(landsatComp, {\n", + " 'min': 25,\n", + " 'max': 38,\n", + " 'palette': ['blue', 'white', 'red']\n", + " },\n", + " 'LST_SMW')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15c Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15c Checkpoint.js new file mode 100644 index 0000000..5998863 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15c Checkpoint.js @@ -0,0 +1,201 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.5 Heat Islands +// Checkpoint: A15c +// Author: TC Chakraborty +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load feature collection of New Haven's census tracts from user assets. +var regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven'); + +// Get dissolved feature collection using an error margin of 50 meters. +var regionInt = regionInt.union(50); + +// Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12); + +// Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary'); + +// Load MODIS image collection from the Earth Engine data catalog. +var modisLst = ee.ImageCollection('MODIS/006/MYD11A2'); + +// Select the band of interest (in this case: Daytime LST). +var landSurfTemperature = modisLst.select('LST_Day_1km'); + +// Create a summer filter. +var sumFilter = ee.Filter.dayOfYear(152, 243); + +//Filter the date range of interest using a date filter. +var lstDateInt = landSurfTemperature + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter); + +// Take pixel-wise mean of all the images in the collection. +var lstMean = lstDateInt.mean(); + +// Multiply each pixel by scaling factor to get the LST values. +var lstFinal = lstMean.multiply(0.02); + +// Generate a water mask. +var water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence'); +var notWater = water.mask().not(); + +// Clip data to region of interest, convert to degree Celsius, and mask water pixels. +var lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) + .updateMask(notWater); + +// Add layer to map. +Map.addLayer(lstNewHaven, { + palette: ['blue', 'white', 'red'], + min: 25, + max: 38 + }, + 'LST_MODIS'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Function to filter out cloudy pixels. +function cloudMask(cloudyScene) { + // Add a cloud score band to the image. + var scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene); + + // Create an image mask from the cloud score band and specify threshold. + var mask = scored.select(['cloud']).lte(10); + + // Apply the mask to the original image and return the masked image. + return cloudyScene.updateMask(mask); +} + +// Load the collection, apply cloud mask, and filter to date and region of interest. +var col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterBounds(regionInt) + .filterDate('2014-01-01', '2019-01-01') + .filter(sumFilter) + .map(cloudMask); + +print('Landsat collection', col); + +// Generate median composite. +var image = col.median(); + +// Select thermal band 10 (with brightness temperature). +var thermal = image.select('B10') + .clip(regionInt) + .updateMask(notWater); + +Map.addLayer(thermal, { + min: 295, + max: 310, + palette: ['blue', 'white', 'red'] + }, + 'Landsat_BT'); + +// Calculate Normalized Difference Vegetation Index (NDVI) +// from Landsat surface reflectance. +var ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(regionInt) + .filterDate('2014-01-01', '2019-01-01') + .filter(sumFilter) + .median() + .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') + .clip(regionInt) + .updateMask(notWater); + +Map.addLayer(ndvi, { + min: 0, + max: 1, + palette: ['blue', 'white', 'green'] + }, + 'ndvi'); + +// Find the minimum and maximum of NDVI. Combine the reducers +// for efficiency (single pass over the data). +var minMax = ndvi.reduceRegion({ + reducer: ee.Reducer.min().combine({ + reducer2: ee.Reducer.max(), + sharedInputs: true + }), + geometry: regionInt, + scale: 30, + maxPixels: 1e9 +}); +print('minMax', minMax); + +var min = ee.Number(minMax.get('NDVI_min')); +var max = ee.Number(minMax.get('NDVI_max')); + +// Calculate fractional vegetation. +var fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV'); +Map.addLayer(fv, { + min: 0, + max: 1, + palette: ['blue', 'white', 'green'] +}, 'fv'); + +// Emissivity calculations. +var a = ee.Number(0.004); +var b = ee.Number(0.986); +var em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater); + +Map.addLayer(em, { + min: 0.98, + max: 0.99, + palette: ['blue', 'white', 'green'] + }, + 'EMM'); + +// Calculate LST from emissivity and brightness temperature. +var lstLandsat = thermal.expression( + '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', { + 'Tb': thermal.select('B10'), + 'Ep': em.select('EMM') + }).updateMask(notWater); + +Map.addLayer(lstLandsat, { + min: 25, + max: 35, + palette: ['blue', 'white', 'red'], + }, + 'LST_Landsat'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Link to the module that computes the Landsat LST. +var landsatLST = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js'); + +// Select region of interest, date range, and Landsat satellite. +var geometry = regionInt.geometry(); +var satellite = 'L8'; +var dateStart = '2014-01-01'; +var dateEnd = '2019-01-01'; +var useNdvi = true; + +// Get Landsat collection with additional necessary variables. +var landsatColl = landsatLST.collection(satellite, dateStart, dateEnd, + geometry, useNdvi); + +// Create composite, clip, filter to summer, mask, and convert to degree Celsius. +var landsatComp = landsatColl + .select('LST') + .filter(sumFilter) + .median() + .clip(regionInt) + .updateMask(notWater) + .subtract(273.15); + +Map.addLayer(landsatComp, { + min: 25, + max: 38, + palette: ['blue', 'white', 'red'] + }, + 'LST_SMW'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15c Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15c Checkpoint.py new file mode 100644 index 0000000..5e857e3 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15c Checkpoint.py @@ -0,0 +1,207 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.5 Heat Islands +# Checkpoint: A15c +# Author: TC Chakraborty +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load feature collection of New Haven's census tracts from user assets. +regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven') + +# Get dissolved feature collection using an error margin of 50 meters. +regionInt = regionInt.union(50) + +# Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12) + +# Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary') + +# Load MODIS image collection from the Earth Engine data catalog. +modisLst = ee.ImageCollection('MODIS/006/MYD11A2') + +# Select the band of interest (in this case: Daytime LST). +landSurfTemperature = modisLst.select('LST_Day_1km') + +# Create a summer filter. +sumFilter = ee.Filter.dayOfYear(152, 243) + +#Filter the date range of interest using a date filter. +lstDateInt = landSurfTemperature \ + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter) + +# Take pixel-wise mean of all the images in the collection. +lstMean = lstDateInt.mean() + +# Multiply each pixel by scaling factor to get the LST values. +lstFinal = lstMean.multiply(0.02) + +# Generate a water mask. +water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence') +notWater = water.mask().Not() + +# Clip data to region of interest, convert to degree Celsius, and mask water pixels. +lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \ + .updateMask(notWater) + +# Add layer to map. +Map.addLayer(lstNewHaven, { + 'palette': ['blue', 'white', 'red'], + 'min': 25, + 'max': 38 + }, + 'LST_MODIS') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Function to filter out cloudy pixels. +def cloudMask(cloudyScene): + # Add a cloud score band to the image. + scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene) + + # Create an image mask from the cloud score band and specify threshold. + mask = scored.select(['cloud']).lte(10) + + # Apply the mask to the original image and return the masked image. + return cloudyScene.updateMask(mask) + + +# Load the collection, apply cloud mask, and filter to date and region of interest. +col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterBounds(regionInt) \ + .filterDate('2014-01-01', '2019-01-01') \ + .filter(sumFilter) \ + .map(cloudMask) + +print('Landsat collection', col) + +# Generate median composite. +image = col.median() + +# Select thermal band 10 (with brightness temperature). +thermal = image.select('B10') \ + .clip(regionInt) \ + .updateMask(notWater) + +Map.addLayer(thermal, { + 'min': 295, + 'max': 310, + 'palette': ['blue', 'white', 'red'] + }, + 'Landsat_BT') + +# Calculate Normalized Difference Vegetation Index (NDVI) +# from Landsat surface reflectance. +ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(regionInt) \ + .filterDate('2014-01-01', '2019-01-01') \ + .filter(sumFilter) \ + .median() \ + .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') \ + .clip(regionInt) \ + .updateMask(notWater) + +Map.addLayer(ndvi, { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'white', 'green'] + }, + 'ndvi') + +# Find the minimum and maximum of NDVI. Combine the reducers +# for efficiency (single pass over the data). +minMax = ndvi.reduceRegion({ + 'reducer': ee.Reducer.min().combine({ + 'reducer2': ee.Reducer.max(), + 'sharedInputs': True + }), + 'geometry': regionInt, + 'scale': 30, + 'maxPixels': 1e9 +}) +print('minMax', minMax) + +min = ee.Number(minMax.get('NDVI_min')) +max = ee.Number(minMax.get('NDVI_max')) + +# Calculate fractional vegetation. +fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV') +Map.addLayer(fv, { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'white', 'green'] +}, 'fv') + +# Emissivity calculations. +a = ee.Number(0.004) +b = ee.Number(0.986) +em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater) + +Map.addLayer(em, { + 'min': 0.98, + 'max': 0.99, + 'palette': ['blue', 'white', 'green'] + }, + 'EMM') + +# Calculate LST from emissivity and brightness temperature. +lstLandsat = thermal.expression( + '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', { + 'Tb': thermal.select('B10'), + 'Ep': em.select('EMM') + }).updateMask(notWater) + +Map.addLayer(lstLandsat, { + 'min': 25, + 'max': 35, + 'palette': ['blue', 'white', 'red'], + }, + 'LST_Landsat') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Link to the module that computes the Landsat LST. +landsatLST = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js') + +# Select region of interest, date range, and Landsat satellite. +geometry = regionInt.geometry() +satellite = 'L8' +dateStart = '2014-01-01' +dateEnd = '2019-01-01' +useNdvi = True + +# Get Landsat collection with additional necessary variables. +landsatColl = landsatLST.collection(satellite, dateStart, dateEnd, + geometry, useNdvi) + +# Create composite, clip, filter to summer, mask, and convert to degree Celsius. +landsatComp = landsatColl \ + .select('LST') \ + .filter(sumFilter) \ + .median() \ + .clip(regionInt) \ + .updateMask(notWater) \ + .subtract(273.15) + +Map.addLayer(landsatComp, { + 'min': 25, + 'max': 38, + 'palette': ['blue', 'white', 'red'] + }, + 'LST_SMW') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15d Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15d Checkpoint.ipynb new file mode 100644 index 0000000..5c4750d --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15d Checkpoint.ipynb @@ -0,0 +1,375 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.5 Heat Islands\n", + "# Checkpoint: A15d\n", + "# Author: TC Chakraborty\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load feature collection of New Haven's census tracts from user assets.\n", + "regionInt = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-5/TC_NewHaven')\n", + "\n", + "# Get dissolved feature collection using an error margin of 50 meters.\n", + "regionInt = regionInt.union(50)\n", + "\n", + "# Set map center and zoom level (Zoom level varies from 1 to 20).\n", + "Map.setCenter(-72.9, 41.3, 12)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(regionInt, {}, 'New Haven boundary')\n", + "\n", + "# Load MODIS image collection from the Earth Engine data catalog.\n", + "modisLst = ee.ImageCollection('MODIS/006/MYD11A2')\n", + "\n", + "# Select the band of interest (in this case: Daytime LST).\n", + "landSurfTemperature = modisLst.select('LST_Day_1km')\n", + "\n", + "# Create a summer filter.\n", + "sumFilter = ee.Filter.dayOfYear(152, 243)\n", + "\n", + "#Filter the date range of interest using a date filter.\n", + "lstDateInt = landSurfTemperature \\\n", + " .filterDate('2014-01-01', '2019-01-01').filter(sumFilter)\n", + "\n", + "# Take pixel-wise mean of all the images in the collection.\n", + "lstMean = lstDateInt.mean()\n", + "\n", + "# Multiply each pixel by scaling factor to get the LST values.\n", + "lstFinal = lstMean.multiply(0.02)\n", + "\n", + "# Generate a water mask.\n", + "water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select(\n", + " 'occurrence')\n", + "notWater = water.mask().Not()\n", + "\n", + "# Clip data to region of interest, convert to degree Celsius, and mask water pixels.\n", + "lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \\\n", + " .updateMask(notWater)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(lstNewHaven, {\n", + " 'palette': ['blue', 'white', 'red'],\n", + " 'min': 25,\n", + " 'max': 38\n", + " },\n", + " 'LST_MODIS')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Function to filter out cloudy pixels.\n", + "def cloudMask(cloudyScene):\n", + " # Add a cloud score band to the image.\n", + " scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene)\n", + "\n", + " # Create an image mask from the cloud score band and specify threshold.\n", + " mask = scored.select(['cloud']).lte(10)\n", + "\n", + " # Apply the mask to the original image and return the masked image.\n", + " return cloudyScene.updateMask(mask)\n", + "\n", + "\n", + "# Load the collection, apply cloud mask, and filter to date and region of interest.\n", + "col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterBounds(regionInt) \\\n", + " .filterDate('2014-01-01', '2019-01-01') \\\n", + " .filter(sumFilter) \\\n", + " .map(cloudMask)\n", + "\n", + "print('Landsat collection', col)\n", + "\n", + "# Generate median composite.\n", + "image = col.median()\n", + "\n", + "# Select thermal band 10 (with brightness temperature).\n", + "thermal = image.select('B10') \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater)\n", + "\n", + "Map.addLayer(thermal, {\n", + " 'min': 295,\n", + " 'max': 310,\n", + " 'palette': ['blue', 'white', 'red']\n", + " },\n", + " 'Landsat_BT')\n", + "\n", + "# Calculate Normalized Difference Vegetation Index (NDVI)\n", + "# from Landsat surface reflectance.\n", + "ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(regionInt) \\\n", + " .filterDate('2014-01-01', '2019-01-01') \\\n", + " .filter(sumFilter) \\\n", + " .median() \\\n", + " .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater)\n", + "\n", + "Map.addLayer(ndvi, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + " },\n", + " 'ndvi')\n", + "\n", + "# Find the minimum and maximum of NDVI. Combine the reducers\n", + "# for efficiency (single pass over the data).\n", + "minMax = ndvi.reduceRegion({\n", + " 'reducer': ee.Reducer.min().combine({\n", + " 'reducer2': ee.Reducer.max(),\n", + " 'sharedInputs': True\n", + " }),\n", + " 'geometry': regionInt,\n", + " 'scale': 30,\n", + " 'maxPixels': 1e9\n", + "})\n", + "print('minMax', minMax)\n", + "\n", + "min = ee.Number(minMax.get('NDVI_min'))\n", + "max = ee.Number(minMax.get('NDVI_max'))\n", + "\n", + "# Calculate fractional vegetation.\n", + "fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV')\n", + "Map.addLayer(fv, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + "}, 'fv')\n", + "\n", + "# Emissivity calculations.\n", + "a = ee.Number(0.004)\n", + "b = ee.Number(0.986)\n", + "em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater)\n", + "\n", + "Map.addLayer(em, {\n", + " 'min': 0.98,\n", + " 'max': 0.99,\n", + " 'palette': ['blue', 'white', 'green']\n", + " },\n", + " 'EMM')\n", + "\n", + "# Calculate LST from emissivity and brightness temperature.\n", + "lstLandsat = thermal.expression(\n", + " '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', {\n", + " 'Tb': thermal.select('B10'),\n", + " 'Ep': em.select('EMM')\n", + " }).updateMask(notWater)\n", + "\n", + "Map.addLayer(lstLandsat, {\n", + " 'min': 25,\n", + " 'max': 35,\n", + " 'palette': ['blue', 'white', 'red'],\n", + " },\n", + " 'LST_Landsat')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Link to the module that computes the Landsat LST.\n", + "landsatLST = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js')\n", + "\n", + "# Select region of interest, date range, and Landsat satellite.\n", + "geometry = regionInt.geometry()\n", + "satellite = 'L8'\n", + "dateStart = '2014-01-01'\n", + "dateEnd = '2019-01-01'\n", + "useNdvi = True\n", + "\n", + "# Get Landsat collection with additional necessary variables.\n", + "landsatColl = landsatLST.collection(satellite, dateStart, dateEnd,\n", + " geometry, useNdvi)\n", + "\n", + "# Create composite, clip, filter to summer, mask, and convert to degree Celsius.\n", + "landsatComp = landsatColl \\\n", + " .select('LST') \\\n", + " .filter(sumFilter) \\\n", + " .median() \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater) \\\n", + " .subtract(273.15)\n", + "\n", + "Map.addLayer(landsatComp, {\n", + " 'min': 25,\n", + " 'max': 38,\n", + " 'palette': ['blue', 'white', 'red']\n", + " },\n", + " 'LST_SMW')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Function to subtract the original urban cluster from the buffered cluster\n", + "# to generate rural references.\n", + "def bufferSubtract(feature):\n", + " return ee.Feature(feature.geometry() \\\n", + " .buffer(2000) \\\n", + " .difference(feature.geometry()))\n", + "\n", + "\n", + "ruralRef = regionInt.map(bufferSubtract)\n", + "\n", + "Map.addLayer(ruralRef, {\n", + " 'color': 'green'\n", + "}, 'Buffer_ref')\n", + "\n", + "# Define sequence of buffer widths to be tested.\n", + "buffWidths = ee.List.sequence(30, 3000, 30)\n", + "\n", + "# Function to generate standardized buffers (approximately comparable to area of urban cluster).\n", + "def bufferOptimize(feature):\n", + " def buff(buffLength):\n", + " buffedPolygon = ee.Feature(feature.geometry() \\\n", + " .buffer(ee.Number(buffLength))) \\\n", + " .set({\n", + " 'Buffer_width': ee.Number(buffLength)\n", + " })\n", + " area = buffedPolygon.geometry().difference(feature \\\n", + " .geometry()).area()\n", + " diffFeature = ee.Feature(\n", + " buffedPolygon.geometry().difference(feature \\\n", + " .geometry()))\n", + " return diffFeature.set({\n", + " 'Buffer_diff': area.subtract(feature.geometry() \\\n", + " .area()).abs(),\n", + " 'Buffer_area': area,\n", + " 'Buffer_width': buffedPolygon.get('Buffer_width')\n", + " })\n", + "\n", + "\n", + " buffed = ee.FeatureCollection(buffWidths.map(buff))\n", + " sortedByBuffer = buffed.sort({\n", + " 'property': 'Buffer_diff'\n", + " })\n", + " firstFeature = ee.Feature(sortedByBuffer.first())\n", + " return firstFeature.set({\n", + " 'Urban_Area': feature.get('Area'),\n", + " 'Buffer_width': firstFeature.get('Buffer_width')\n", + " })\n", + "\n", + "\n", + "# Map function over urban feature collection.\n", + "ruralRefStd = regionInt.map(bufferOptimize)\n", + "\n", + "Map.addLayer(ruralRefStd, {\n", + " 'color': 'brown'\n", + "}, 'Buffer_ref_std')\n", + "\n", + "print('ruralRefStd', ruralRefStd)\n", + "\n", + "# Select the NLCD land cover data.\n", + "landCover = ee.Image('USGS/NLCD/NLCD2016').select('landcover')\n", + "urban = landCover\n", + "\n", + "# Select urban pixels in image.\n", + "urbanUrban = urban.updateMask(urban.eq(23).Or(urban.eq(24)))\n", + "\n", + "# Select background reference pixels in the image.\n", + "nonUrbanVals = [41, 42, 43, 51, 52, 71, 72, 73, 74, 81, 82]\n", + "nonUrbanPixels = urban.eq(ee.Image(nonUrbanVals)).reduce('max')\n", + "urbanNonUrban = urban.updateMask(nonUrbanPixels)\n", + "\n", + "Map.addLayer(urbanUrban.clip(regionInt), {\n", + " 'palette': 'red'\n", + "}, 'Urban pixels')\n", + "Map.addLayer(urbanNonUrban.clip(regionInt), {\n", + " 'palette': 'blue'\n", + "}, 'Non-urban pixels')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15d Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15d Checkpoint.js new file mode 100644 index 0000000..0a2ca94 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15d Checkpoint.js @@ -0,0 +1,282 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.5 Heat Islands +// Checkpoint: A15d +// Author: TC Chakraborty +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load feature collection of New Haven's census tracts from user assets. +var regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven'); + +// Get dissolved feature collection using an error margin of 50 meters. +var regionInt = regionInt.union(50); + +// Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12); + +// Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary'); + +// Load MODIS image collection from the Earth Engine data catalog. +var modisLst = ee.ImageCollection('MODIS/006/MYD11A2'); + +// Select the band of interest (in this case: Daytime LST). +var landSurfTemperature = modisLst.select('LST_Day_1km'); + +// Create a summer filter. +var sumFilter = ee.Filter.dayOfYear(152, 243); + +//Filter the date range of interest using a date filter. +var lstDateInt = landSurfTemperature + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter); + +// Take pixel-wise mean of all the images in the collection. +var lstMean = lstDateInt.mean(); + +// Multiply each pixel by scaling factor to get the LST values. +var lstFinal = lstMean.multiply(0.02); + +// Generate a water mask. +var water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence'); +var notWater = water.mask().not(); + +// Clip data to region of interest, convert to degree Celsius, and mask water pixels. +var lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) + .updateMask(notWater); + +// Add layer to map. +Map.addLayer(lstNewHaven, { + palette: ['blue', 'white', 'red'], + min: 25, + max: 38 + }, + 'LST_MODIS'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Function to filter out cloudy pixels. +function cloudMask(cloudyScene) { + // Add a cloud score band to the image. + var scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene); + + // Create an image mask from the cloud score band and specify threshold. + var mask = scored.select(['cloud']).lte(10); + + // Apply the mask to the original image and return the masked image. + return cloudyScene.updateMask(mask); +} + +// Load the collection, apply cloud mask, and filter to date and region of interest. +var col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterBounds(regionInt) + .filterDate('2014-01-01', '2019-01-01') + .filter(sumFilter) + .map(cloudMask); + +print('Landsat collection', col); + +// Generate median composite. +var image = col.median(); + +// Select thermal band 10 (with brightness temperature). +var thermal = image.select('B10') + .clip(regionInt) + .updateMask(notWater); + +Map.addLayer(thermal, { + min: 295, + max: 310, + palette: ['blue', 'white', 'red'] + }, + 'Landsat_BT'); + +// Calculate Normalized Difference Vegetation Index (NDVI) +// from Landsat surface reflectance. +var ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(regionInt) + .filterDate('2014-01-01', '2019-01-01') + .filter(sumFilter) + .median() + .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') + .clip(regionInt) + .updateMask(notWater); + +Map.addLayer(ndvi, { + min: 0, + max: 1, + palette: ['blue', 'white', 'green'] + }, + 'ndvi'); + +// Find the minimum and maximum of NDVI. Combine the reducers +// for efficiency (single pass over the data). +var minMax = ndvi.reduceRegion({ + reducer: ee.Reducer.min().combine({ + reducer2: ee.Reducer.max(), + sharedInputs: true + }), + geometry: regionInt, + scale: 30, + maxPixels: 1e9 +}); +print('minMax', minMax); + +var min = ee.Number(minMax.get('NDVI_min')); +var max = ee.Number(minMax.get('NDVI_max')); + +// Calculate fractional vegetation. +var fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV'); +Map.addLayer(fv, { + min: 0, + max: 1, + palette: ['blue', 'white', 'green'] +}, 'fv'); + +// Emissivity calculations. +var a = ee.Number(0.004); +var b = ee.Number(0.986); +var em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater); + +Map.addLayer(em, { + min: 0.98, + max: 0.99, + palette: ['blue', 'white', 'green'] + }, + 'EMM'); + +// Calculate LST from emissivity and brightness temperature. +var lstLandsat = thermal.expression( + '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', { + 'Tb': thermal.select('B10'), + 'Ep': em.select('EMM') + }).updateMask(notWater); + +Map.addLayer(lstLandsat, { + min: 25, + max: 35, + palette: ['blue', 'white', 'red'], + }, + 'LST_Landsat'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Link to the module that computes the Landsat LST. +var landsatLST = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js'); + +// Select region of interest, date range, and Landsat satellite. +var geometry = regionInt.geometry(); +var satellite = 'L8'; +var dateStart = '2014-01-01'; +var dateEnd = '2019-01-01'; +var useNdvi = true; + +// Get Landsat collection with additional necessary variables. +var landsatColl = landsatLST.collection(satellite, dateStart, dateEnd, + geometry, useNdvi); + +// Create composite, clip, filter to summer, mask, and convert to degree Celsius. +var landsatComp = landsatColl + .select('LST') + .filter(sumFilter) + .median() + .clip(regionInt) + .updateMask(notWater) + .subtract(273.15); + +Map.addLayer(landsatComp, { + min: 25, + max: 38, + palette: ['blue', 'white', 'red'] + }, + 'LST_SMW'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Function to subtract the original urban cluster from the buffered cluster +// to generate rural references. +function bufferSubtract(feature) { + return ee.Feature(feature.geometry() + .buffer(2000) + .difference(feature.geometry())); +} + +var ruralRef = regionInt.map(bufferSubtract); + +Map.addLayer(ruralRef, { + color: 'green' +}, 'Buffer_ref'); + +// Define sequence of buffer widths to be tested. +var buffWidths = ee.List.sequence(30, 3000, 30); + +// Function to generate standardized buffers (approximately comparable to area of urban cluster). +function bufferOptimize(feature) { + function buff(buffLength) { + var buffedPolygon = ee.Feature(feature.geometry() + .buffer(ee.Number(buffLength))) + .set({ + 'Buffer_width': ee.Number(buffLength) + }); + var area = buffedPolygon.geometry().difference(feature + .geometry()).area(); + var diffFeature = ee.Feature( + buffedPolygon.geometry().difference(feature + .geometry())); + return diffFeature.set({ + 'Buffer_diff': area.subtract(feature.geometry() + .area()).abs(), + 'Buffer_area': area, + 'Buffer_width': buffedPolygon.get('Buffer_width') + }); + } + + var buffed = ee.FeatureCollection(buffWidths.map(buff)); + var sortedByBuffer = buffed.sort({ + property: 'Buffer_diff' + }); + var firstFeature = ee.Feature(sortedByBuffer.first()); + return firstFeature.set({ + 'Urban_Area': feature.get('Area'), + 'Buffer_width': firstFeature.get('Buffer_width') + }); +} + +// Map function over urban feature collection. +var ruralRefStd = regionInt.map(bufferOptimize); + +Map.addLayer(ruralRefStd, { + color: 'brown' +}, 'Buffer_ref_std'); + +print('ruralRefStd', ruralRefStd); + +// Select the NLCD land cover data. +var landCover = ee.Image('USGS/NLCD/NLCD2016').select('landcover'); +var urban = landCover; + +// Select urban pixels in image. +var urbanUrban = urban.updateMask(urban.eq(23).or(urban.eq(24))); + +// Select background reference pixels in the image. +var nonUrbanVals = [41, 42, 43, 51, 52, 71, 72, 73, 74, 81, 82]; +var nonUrbanPixels = urban.eq(ee.Image(nonUrbanVals)).reduce('max'); +var urbanNonUrban = urban.updateMask(nonUrbanPixels); + +Map.addLayer(urbanUrban.clip(regionInt), { + palette: 'red' +}, 'Urban pixels'); +Map.addLayer(urbanNonUrban.clip(regionInt), { + palette: 'blue' +}, 'Non-urban pixels'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15d Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15d Checkpoint.py new file mode 100644 index 0000000..c070570 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15d Checkpoint.py @@ -0,0 +1,288 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.5 Heat Islands +# Checkpoint: A15d +# Author: TC Chakraborty +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load feature collection of New Haven's census tracts from user assets. +regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven') + +# Get dissolved feature collection using an error margin of 50 meters. +regionInt = regionInt.union(50) + +# Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12) + +# Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary') + +# Load MODIS image collection from the Earth Engine data catalog. +modisLst = ee.ImageCollection('MODIS/006/MYD11A2') + +# Select the band of interest (in this case: Daytime LST). +landSurfTemperature = modisLst.select('LST_Day_1km') + +# Create a summer filter. +sumFilter = ee.Filter.dayOfYear(152, 243) + +#Filter the date range of interest using a date filter. +lstDateInt = landSurfTemperature \ + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter) + +# Take pixel-wise mean of all the images in the collection. +lstMean = lstDateInt.mean() + +# Multiply each pixel by scaling factor to get the LST values. +lstFinal = lstMean.multiply(0.02) + +# Generate a water mask. +water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence') +notWater = water.mask().Not() + +# Clip data to region of interest, convert to degree Celsius, and mask water pixels. +lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \ + .updateMask(notWater) + +# Add layer to map. +Map.addLayer(lstNewHaven, { + 'palette': ['blue', 'white', 'red'], + 'min': 25, + 'max': 38 + }, + 'LST_MODIS') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Function to filter out cloudy pixels. +def cloudMask(cloudyScene): + # Add a cloud score band to the image. + scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene) + + # Create an image mask from the cloud score band and specify threshold. + mask = scored.select(['cloud']).lte(10) + + # Apply the mask to the original image and return the masked image. + return cloudyScene.updateMask(mask) + + +# Load the collection, apply cloud mask, and filter to date and region of interest. +col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterBounds(regionInt) \ + .filterDate('2014-01-01', '2019-01-01') \ + .filter(sumFilter) \ + .map(cloudMask) + +print('Landsat collection', col) + +# Generate median composite. +image = col.median() + +# Select thermal band 10 (with brightness temperature). +thermal = image.select('B10') \ + .clip(regionInt) \ + .updateMask(notWater) + +Map.addLayer(thermal, { + 'min': 295, + 'max': 310, + 'palette': ['blue', 'white', 'red'] + }, + 'Landsat_BT') + +# Calculate Normalized Difference Vegetation Index (NDVI) +# from Landsat surface reflectance. +ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(regionInt) \ + .filterDate('2014-01-01', '2019-01-01') \ + .filter(sumFilter) \ + .median() \ + .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') \ + .clip(regionInt) \ + .updateMask(notWater) + +Map.addLayer(ndvi, { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'white', 'green'] + }, + 'ndvi') + +# Find the minimum and maximum of NDVI. Combine the reducers +# for efficiency (single pass over the data). +minMax = ndvi.reduceRegion({ + 'reducer': ee.Reducer.min().combine({ + 'reducer2': ee.Reducer.max(), + 'sharedInputs': True + }), + 'geometry': regionInt, + 'scale': 30, + 'maxPixels': 1e9 +}) +print('minMax', minMax) + +min = ee.Number(minMax.get('NDVI_min')) +max = ee.Number(minMax.get('NDVI_max')) + +# Calculate fractional vegetation. +fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV') +Map.addLayer(fv, { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'white', 'green'] +}, 'fv') + +# Emissivity calculations. +a = ee.Number(0.004) +b = ee.Number(0.986) +em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater) + +Map.addLayer(em, { + 'min': 0.98, + 'max': 0.99, + 'palette': ['blue', 'white', 'green'] + }, + 'EMM') + +# Calculate LST from emissivity and brightness temperature. +lstLandsat = thermal.expression( + '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', { + 'Tb': thermal.select('B10'), + 'Ep': em.select('EMM') + }).updateMask(notWater) + +Map.addLayer(lstLandsat, { + 'min': 25, + 'max': 35, + 'palette': ['blue', 'white', 'red'], + }, + 'LST_Landsat') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Link to the module that computes the Landsat LST. +landsatLST = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js') + +# Select region of interest, date range, and Landsat satellite. +geometry = regionInt.geometry() +satellite = 'L8' +dateStart = '2014-01-01' +dateEnd = '2019-01-01' +useNdvi = True + +# Get Landsat collection with additional necessary variables. +landsatColl = landsatLST.collection(satellite, dateStart, dateEnd, + geometry, useNdvi) + +# Create composite, clip, filter to summer, mask, and convert to degree Celsius. +landsatComp = landsatColl \ + .select('LST') \ + .filter(sumFilter) \ + .median() \ + .clip(regionInt) \ + .updateMask(notWater) \ + .subtract(273.15) + +Map.addLayer(landsatComp, { + 'min': 25, + 'max': 38, + 'palette': ['blue', 'white', 'red'] + }, + 'LST_SMW') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Function to subtract the original urban cluster from the buffered cluster +# to generate rural references. +def bufferSubtract(feature): + return ee.Feature(feature.geometry() \ + .buffer(2000) \ + .difference(feature.geometry())) + + +ruralRef = regionInt.map(bufferSubtract) + +Map.addLayer(ruralRef, { + 'color': 'green' +}, 'Buffer_ref') + +# Define sequence of buffer widths to be tested. +buffWidths = ee.List.sequence(30, 3000, 30) + +# Function to generate standardized buffers (approximately comparable to area of urban cluster). +def bufferOptimize(feature): + def buff(buffLength): + buffedPolygon = ee.Feature(feature.geometry() \ + .buffer(ee.Number(buffLength))) \ + .set({ + 'Buffer_width': ee.Number(buffLength) + }) + area = buffedPolygon.geometry().difference(feature \ + .geometry()).area() + diffFeature = ee.Feature( + buffedPolygon.geometry().difference(feature \ + .geometry())) + return diffFeature.set({ + 'Buffer_diff': area.subtract(feature.geometry() \ + .area()).abs(), + 'Buffer_area': area, + 'Buffer_width': buffedPolygon.get('Buffer_width') + }) + + + buffed = ee.FeatureCollection(buffWidths.map(buff)) + sortedByBuffer = buffed.sort({ + 'property': 'Buffer_diff' + }) + firstFeature = ee.Feature(sortedByBuffer.first()) + return firstFeature.set({ + 'Urban_Area': feature.get('Area'), + 'Buffer_width': firstFeature.get('Buffer_width') + }) + + +# Map function over urban feature collection. +ruralRefStd = regionInt.map(bufferOptimize) + +Map.addLayer(ruralRefStd, { + 'color': 'brown' +}, 'Buffer_ref_std') + +print('ruralRefStd', ruralRefStd) + +# Select the NLCD land cover data. +landCover = ee.Image('USGS/NLCD/NLCD2016').select('landcover') +urban = landCover + +# Select urban pixels in image. +urbanUrban = urban.updateMask(urban.eq(23).Or(urban.eq(24))) + +# Select background reference pixels in the image. +nonUrbanVals = [41, 42, 43, 51, 52, 71, 72, 73, 74, 81, 82] +nonUrbanPixels = urban.eq(ee.Image(nonUrbanVals)).reduce('max') +urbanNonUrban = urban.updateMask(nonUrbanPixels) + +Map.addLayer(urbanUrban.clip(regionInt), { + 'palette': 'red' +}, 'Urban pixels') +Map.addLayer(urbanNonUrban.clip(regionInt), { + 'palette': 'blue' +}, 'Non-urban pixels') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15e Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15e Checkpoint.ipynb new file mode 100644 index 0000000..a1d5eb4 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15e Checkpoint.ipynb @@ -0,0 +1,498 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.5 Heat Islands\n", + "# Checkpoint: A15e\n", + "# Author: TC Chakraborty\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load feature collection of New Haven's census tracts from user assets.\n", + "regionInt = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-5/TC_NewHaven')\n", + "\n", + "# Get dissolved feature collection using an error margin of 50 meters.\n", + "regionInt = regionInt.union(50)\n", + "\n", + "# Set map center and zoom level (Zoom level varies from 1 to 20).\n", + "Map.setCenter(-72.9, 41.3, 12)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(regionInt, {}, 'New Haven boundary')\n", + "\n", + "# Load MODIS image collection from the Earth Engine data catalog.\n", + "modisLst = ee.ImageCollection('MODIS/006/MYD11A2')\n", + "\n", + "# Select the band of interest (in this case: Daytime LST).\n", + "landSurfTemperature = modisLst.select('LST_Day_1km')\n", + "\n", + "# Create a summer filter.\n", + "sumFilter = ee.Filter.dayOfYear(152, 243)\n", + "\n", + "#Filter the date range of interest using a date filter.\n", + "lstDateInt = landSurfTemperature \\\n", + " .filterDate('2014-01-01', '2019-01-01').filter(sumFilter)\n", + "\n", + "# Take pixel-wise mean of all the images in the collection.\n", + "lstMean = lstDateInt.mean()\n", + "\n", + "# Multiply each pixel by scaling factor to get the LST values.\n", + "lstFinal = lstMean.multiply(0.02)\n", + "\n", + "# Generate a water mask.\n", + "water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select(\n", + " 'occurrence')\n", + "notWater = water.mask().Not()\n", + "\n", + "# Clip data to region of interest, convert to degree Celsius, and mask water pixels.\n", + "lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \\\n", + " .updateMask(notWater)\n", + "\n", + "# Add layer to map.\n", + "Map.addLayer(lstNewHaven, {\n", + " 'palette': ['blue', 'white', 'red'],\n", + " 'min': 25,\n", + " 'max': 38\n", + " },\n", + " 'LST_MODIS')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Function to filter out cloudy pixels.\n", + "def cloudMask(cloudyScene):\n", + " # Add a cloud score band to the image.\n", + " scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene)\n", + "\n", + " # Create an image mask from the cloud score band and specify threshold.\n", + " mask = scored.select(['cloud']).lte(10)\n", + "\n", + " # Apply the mask to the original image and return the masked image.\n", + " return cloudyScene.updateMask(mask)\n", + "\n", + "\n", + "# Load the collection, apply cloud mask, and filter to date and region of interest.\n", + "col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterBounds(regionInt) \\\n", + " .filterDate('2014-01-01', '2019-01-01') \\\n", + " .filter(sumFilter) \\\n", + " .map(cloudMask)\n", + "\n", + "print('Landsat collection', col)\n", + "\n", + "# Generate median composite.\n", + "image = col.median()\n", + "\n", + "# Select thermal band 10 (with brightness temperature).\n", + "thermal = image.select('B10') \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater)\n", + "\n", + "Map.addLayer(thermal, {\n", + " 'min': 295,\n", + " 'max': 310,\n", + " 'palette': ['blue', 'white', 'red']\n", + " },\n", + " 'Landsat_BT')\n", + "\n", + "# Calculate Normalized Difference Vegetation Index (NDVI)\n", + "# from Landsat surface reflectance.\n", + "ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(regionInt) \\\n", + " .filterDate('2014-01-01', '2019-01-01') \\\n", + " .filter(sumFilter) \\\n", + " .median() \\\n", + " .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater)\n", + "\n", + "Map.addLayer(ndvi, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + " },\n", + " 'ndvi')\n", + "\n", + "# Find the minimum and maximum of NDVI. Combine the reducers\n", + "# for efficiency (single pass over the data).\n", + "minMax = ndvi.reduceRegion({\n", + " 'reducer': ee.Reducer.min().combine({\n", + " 'reducer2': ee.Reducer.max(),\n", + " 'sharedInputs': True\n", + " }),\n", + " 'geometry': regionInt,\n", + " 'scale': 30,\n", + " 'maxPixels': 1e9\n", + "})\n", + "print('minMax', minMax)\n", + "\n", + "min = ee.Number(minMax.get('NDVI_min'))\n", + "max = ee.Number(minMax.get('NDVI_max'))\n", + "\n", + "# Calculate fractional vegetation.\n", + "fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV')\n", + "Map.addLayer(fv, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + "}, 'fv')\n", + "\n", + "# Emissivity calculations.\n", + "a = ee.Number(0.004)\n", + "b = ee.Number(0.986)\n", + "em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater)\n", + "\n", + "Map.addLayer(em, {\n", + " 'min': 0.98,\n", + " 'max': 0.99,\n", + " 'palette': ['blue', 'white', 'green']\n", + " },\n", + " 'EMM')\n", + "\n", + "# Calculate LST from emissivity and brightness temperature.\n", + "lstLandsat = thermal.expression(\n", + " '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', {\n", + " 'Tb': thermal.select('B10'),\n", + " 'Ep': em.select('EMM')\n", + " }).updateMask(notWater)\n", + "\n", + "Map.addLayer(lstLandsat, {\n", + " 'min': 25,\n", + " 'max': 35,\n", + " 'palette': ['blue', 'white', 'red'],\n", + " },\n", + " 'LST_Landsat')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Link to the module that computes the Landsat LST.\n", + "landsatLST = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js')\n", + "\n", + "# Select region of interest, date range, and Landsat satellite.\n", + "geometry = regionInt.geometry()\n", + "satellite = 'L8'\n", + "dateStart = '2014-01-01'\n", + "dateEnd = '2019-01-01'\n", + "useNdvi = True\n", + "\n", + "# Get Landsat collection with additional necessary variables.\n", + "landsatColl = landsatLST.collection(satellite, dateStart, dateEnd,\n", + " geometry, useNdvi)\n", + "\n", + "# Create composite, clip, filter to summer, mask, and convert to degree Celsius.\n", + "landsatComp = landsatColl \\\n", + " .select('LST') \\\n", + " .filter(sumFilter) \\\n", + " .median() \\\n", + " .clip(regionInt) \\\n", + " .updateMask(notWater) \\\n", + " .subtract(273.15)\n", + "\n", + "Map.addLayer(landsatComp, {\n", + " 'min': 25,\n", + " 'max': 38,\n", + " 'palette': ['blue', 'white', 'red']\n", + " },\n", + " 'LST_SMW')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Function to subtract the original urban cluster from the buffered cluster\n", + "# to generate rural references.\n", + "def bufferSubtract(feature):\n", + " return ee.Feature(feature.geometry() \\\n", + " .buffer(2000) \\\n", + " .difference(feature.geometry()))\n", + "\n", + "\n", + "ruralRef = regionInt.map(bufferSubtract)\n", + "\n", + "Map.addLayer(ruralRef, {\n", + " 'color': 'green'\n", + "}, 'Buffer_ref')\n", + "\n", + "# Define sequence of buffer widths to be tested.\n", + "buffWidths = ee.List.sequence(30, 3000, 30)\n", + "\n", + "# Function to generate standardized buffers (approximately comparable to area of urban cluster).\n", + "def bufferOptimize(feature):\n", + " def buff(buffLength):\n", + " buffedPolygon = ee.Feature(feature.geometry() \\\n", + " .buffer(ee.Number(buffLength))) \\\n", + " .set({\n", + " 'Buffer_width': ee.Number(buffLength)\n", + " })\n", + " area = buffedPolygon.geometry().difference(feature \\\n", + " .geometry()).area()\n", + " diffFeature = ee.Feature(\n", + " buffedPolygon.geometry().difference(feature \\\n", + " .geometry()))\n", + " return diffFeature.set({\n", + " 'Buffer_diff': area.subtract(feature.geometry() \\\n", + " .area()).abs(),\n", + " 'Buffer_area': area,\n", + " 'Buffer_width': buffedPolygon.get('Buffer_width')\n", + " })\n", + "\n", + "\n", + " buffed = ee.FeatureCollection(buffWidths.map(buff))\n", + " sortedByBuffer = buffed.sort({\n", + " 'property': 'Buffer_diff'\n", + " })\n", + " firstFeature = ee.Feature(sortedByBuffer.first())\n", + " return firstFeature.set({\n", + " 'Urban_Area': feature.get('Area'),\n", + " 'Buffer_width': firstFeature.get('Buffer_width')\n", + " })\n", + "\n", + "\n", + "# Map function over urban feature collection.\n", + "ruralRefStd = regionInt.map(bufferOptimize)\n", + "\n", + "Map.addLayer(ruralRefStd, {\n", + " 'color': 'brown'\n", + "}, 'Buffer_ref_std')\n", + "\n", + "print('ruralRefStd', ruralRefStd)\n", + "\n", + "# Select the NLCD land cover data.\n", + "landCover = ee.Image('USGS/NLCD/NLCD2016').select('landcover')\n", + "urban = landCover\n", + "\n", + "# Select urban pixels in image.\n", + "urbanUrban = urban.updateMask(urban.eq(23).Or(urban.eq(24)))\n", + "\n", + "# Select background reference pixels in the image.\n", + "nonUrbanVals = [41, 42, 43, 51, 52, 71, 72, 73, 74, 81, 82]\n", + "nonUrbanPixels = urban.eq(ee.Image(nonUrbanVals)).reduce('max')\n", + "urbanNonUrban = urban.updateMask(nonUrbanPixels)\n", + "\n", + "Map.addLayer(urbanUrban.clip(regionInt), {\n", + " 'palette': 'red'\n", + "}, 'Urban pixels')\n", + "Map.addLayer(urbanNonUrban.clip(regionInt), {\n", + " 'palette': 'blue'\n", + "}, 'Non-urban pixels')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Define function to reduce regions and summarize pixel values\n", + "# to get mean LST for different cases.\n", + "def polygonMean(feature):\n", + "\n", + " # Calculate spatial mean value of LST for each case\n", + " # making sure the pixel values are converted to \u00b0C from Kelvin.\n", + " reducedLstUrb = lstFinal.subtract(273.15).updateMask(notWater) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': feature.geometry(),\n", + " 'scale': 30\n", + " })\n", + " reducedLstUrbMask = lstFinal.subtract(273.15).updateMask(\n", + " notWater) \\\n", + " .updateMask(urbanUrban) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': feature.geometry(),\n", + " 'scale': 30\n", + " })\n", + " reducedLstUrbPix = lstFinal.subtract(273.15).updateMask(\n", + " notWater) \\\n", + " .updateMask(urbanUrban) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': feature.geometry(),\n", + " 'scale': 500\n", + " })\n", + " reducedLstLandsatUrbPix = landsatComp.updateMask(notWater) \\\n", + " .updateMask(urbanUrban) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': feature.geometry(),\n", + " 'scale': 30\n", + " })\n", + " reducedLstRurPix = lstFinal.subtract(273.15).updateMask(\n", + " notWater) \\\n", + " .updateMask(urbanNonUrban) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': feature.geometry(),\n", + " 'scale': 500\n", + " })\n", + " reducedLstLandsatRurPix = landsatComp.updateMask(notWater) \\\n", + " .updateMask(urbanNonUrban) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': feature.geometry(),\n", + " 'scale': 30\n", + " })\n", + "\n", + " # Return each feature with the summarized LSY values as properties.\n", + " return feature.set({\n", + " 'MODIS_LST_urb': reducedLstUrb.get('LST_Day_1km'),\n", + " 'MODIS_LST_urb_mask': reducedLstUrbMask.get(\n", + " 'LST_Day_1km'),\n", + " 'MODIS_LST_urb_pix': reducedLstUrbPix.get(\n", + " 'LST_Day_1km'),\n", + " 'MODIS_LST_rur_pix': reducedLstRurPix.get(\n", + " 'LST_Day_1km'),\n", + " 'Landsat_LST_urb_pix': reducedLstLandsatUrbPix.get(\n", + " 'LST'),\n", + " 'Landsat_LST_rur_pix': reducedLstLandsatRurPix.get(\n", + " 'LST')\n", + " })\n", + "\n", + "\n", + "# Map the function over the urban boundary to get mean urban and rural LST\n", + "# for cases without any explicit buffer-based boundaries.\n", + "reduced = regionInt.map(polygonMean)\n", + "\n", + "# Define a function to reduce region and summarize pixel values\n", + "# to get mean LST for different cases.\n", + "def refMean(feature):\n", + " # Calculate spatial mean value of LST for each case\n", + " # making sure the pixel values are converted to \u00b0C from Kelvin.\n", + " reducedLstRur = lstFinal.subtract(273.15).updateMask(notWater) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': feature.geometry(),\n", + " 'scale': 30\n", + " })\n", + " reducedLstRurMask = lstFinal.subtract(273.15).updateMask(\n", + " notWater) \\\n", + " .updateMask(urbanNonUrban) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': feature.geometry(),\n", + " 'scale': 30\n", + " })\n", + " return feature.set({\n", + " 'MODIS_LST_rur': reducedLstRur.get('LST_Day_1km'),\n", + " 'MODIS_LST_rur_mask': reducedLstRurMask.get(\n", + " 'LST_Day_1km'),\n", + " })\n", + "\n", + "\n", + "# Map the function over the constant buffer rural reference boundary one.\n", + "reducedRural = ee.FeatureCollection(ruralRef).map(refMean)\n", + "\n", + "# Map the function over the standardized rural reference boundary.\n", + "reducedRuralStd = ruralRefStd.map(refMean)\n", + "\n", + "print('reduced', reduced)\n", + "print('reducedRural', reducedRural)\n", + "print('reducedRuralStd', reducedRuralStd)\n", + "\n", + "# Display SUHI variability within the city.\n", + "suhi = landsatComp \\\n", + " .updateMask(urbanUrban) \\\n", + " .subtract(ee.Number(ee.Feature(reduced.first()) \\\n", + " .get('Landsat_LST_rur_pix')))\n", + "\n", + "Map.addLayer(suhi, {\n", + " 'palette': ['blue', 'white', 'red'],\n", + " 'min': 2,\n", + " 'max': 8\n", + "}, 'SUHI')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15e Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15e Checkpoint.js new file mode 100644 index 0000000..46e420b --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15e Checkpoint.js @@ -0,0 +1,405 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.5 Heat Islands +// Checkpoint: A15e +// Author: TC Chakraborty +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load feature collection of New Haven's census tracts from user assets. +var regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven'); + +// Get dissolved feature collection using an error margin of 50 meters. +var regionInt = regionInt.union(50); + +// Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12); + +// Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary'); + +// Load MODIS image collection from the Earth Engine data catalog. +var modisLst = ee.ImageCollection('MODIS/006/MYD11A2'); + +// Select the band of interest (in this case: Daytime LST). +var landSurfTemperature = modisLst.select('LST_Day_1km'); + +// Create a summer filter. +var sumFilter = ee.Filter.dayOfYear(152, 243); + +//Filter the date range of interest using a date filter. +var lstDateInt = landSurfTemperature + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter); + +// Take pixel-wise mean of all the images in the collection. +var lstMean = lstDateInt.mean(); + +// Multiply each pixel by scaling factor to get the LST values. +var lstFinal = lstMean.multiply(0.02); + +// Generate a water mask. +var water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence'); +var notWater = water.mask().not(); + +// Clip data to region of interest, convert to degree Celsius, and mask water pixels. +var lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) + .updateMask(notWater); + +// Add layer to map. +Map.addLayer(lstNewHaven, { + palette: ['blue', 'white', 'red'], + min: 25, + max: 38 + }, + 'LST_MODIS'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Function to filter out cloudy pixels. +function cloudMask(cloudyScene) { + // Add a cloud score band to the image. + var scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene); + + // Create an image mask from the cloud score band and specify threshold. + var mask = scored.select(['cloud']).lte(10); + + // Apply the mask to the original image and return the masked image. + return cloudyScene.updateMask(mask); +} + +// Load the collection, apply cloud mask, and filter to date and region of interest. +var col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterBounds(regionInt) + .filterDate('2014-01-01', '2019-01-01') + .filter(sumFilter) + .map(cloudMask); + +print('Landsat collection', col); + +// Generate median composite. +var image = col.median(); + +// Select thermal band 10 (with brightness temperature). +var thermal = image.select('B10') + .clip(regionInt) + .updateMask(notWater); + +Map.addLayer(thermal, { + min: 295, + max: 310, + palette: ['blue', 'white', 'red'] + }, + 'Landsat_BT'); + +// Calculate Normalized Difference Vegetation Index (NDVI) +// from Landsat surface reflectance. +var ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(regionInt) + .filterDate('2014-01-01', '2019-01-01') + .filter(sumFilter) + .median() + .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') + .clip(regionInt) + .updateMask(notWater); + +Map.addLayer(ndvi, { + min: 0, + max: 1, + palette: ['blue', 'white', 'green'] + }, + 'ndvi'); + +// Find the minimum and maximum of NDVI. Combine the reducers +// for efficiency (single pass over the data). +var minMax = ndvi.reduceRegion({ + reducer: ee.Reducer.min().combine({ + reducer2: ee.Reducer.max(), + sharedInputs: true + }), + geometry: regionInt, + scale: 30, + maxPixels: 1e9 +}); +print('minMax', minMax); + +var min = ee.Number(minMax.get('NDVI_min')); +var max = ee.Number(minMax.get('NDVI_max')); + +// Calculate fractional vegetation. +var fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV'); +Map.addLayer(fv, { + min: 0, + max: 1, + palette: ['blue', 'white', 'green'] +}, 'fv'); + +// Emissivity calculations. +var a = ee.Number(0.004); +var b = ee.Number(0.986); +var em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater); + +Map.addLayer(em, { + min: 0.98, + max: 0.99, + palette: ['blue', 'white', 'green'] + }, + 'EMM'); + +// Calculate LST from emissivity and brightness temperature. +var lstLandsat = thermal.expression( + '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', { + 'Tb': thermal.select('B10'), + 'Ep': em.select('EMM') + }).updateMask(notWater); + +Map.addLayer(lstLandsat, { + min: 25, + max: 35, + palette: ['blue', 'white', 'red'], + }, + 'LST_Landsat'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Link to the module that computes the Landsat LST. +var landsatLST = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js'); + +// Select region of interest, date range, and Landsat satellite. +var geometry = regionInt.geometry(); +var satellite = 'L8'; +var dateStart = '2014-01-01'; +var dateEnd = '2019-01-01'; +var useNdvi = true; + +// Get Landsat collection with additional necessary variables. +var landsatColl = landsatLST.collection(satellite, dateStart, dateEnd, + geometry, useNdvi); + +// Create composite, clip, filter to summer, mask, and convert to degree Celsius. +var landsatComp = landsatColl + .select('LST') + .filter(sumFilter) + .median() + .clip(regionInt) + .updateMask(notWater) + .subtract(273.15); + +Map.addLayer(landsatComp, { + min: 25, + max: 38, + palette: ['blue', 'white', 'red'] + }, + 'LST_SMW'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Function to subtract the original urban cluster from the buffered cluster +// to generate rural references. +function bufferSubtract(feature) { + return ee.Feature(feature.geometry() + .buffer(2000) + .difference(feature.geometry())); +} + +var ruralRef = regionInt.map(bufferSubtract); + +Map.addLayer(ruralRef, { + color: 'green' +}, 'Buffer_ref'); + +// Define sequence of buffer widths to be tested. +var buffWidths = ee.List.sequence(30, 3000, 30); + +// Function to generate standardized buffers (approximately comparable to area of urban cluster). +function bufferOptimize(feature) { + function buff(buffLength) { + var buffedPolygon = ee.Feature(feature.geometry() + .buffer(ee.Number(buffLength))) + .set({ + 'Buffer_width': ee.Number(buffLength) + }); + var area = buffedPolygon.geometry().difference(feature + .geometry()).area(); + var diffFeature = ee.Feature( + buffedPolygon.geometry().difference(feature + .geometry())); + return diffFeature.set({ + 'Buffer_diff': area.subtract(feature.geometry() + .area()).abs(), + 'Buffer_area': area, + 'Buffer_width': buffedPolygon.get('Buffer_width') + }); + } + + var buffed = ee.FeatureCollection(buffWidths.map(buff)); + var sortedByBuffer = buffed.sort({ + property: 'Buffer_diff' + }); + var firstFeature = ee.Feature(sortedByBuffer.first()); + return firstFeature.set({ + 'Urban_Area': feature.get('Area'), + 'Buffer_width': firstFeature.get('Buffer_width') + }); +} + +// Map function over urban feature collection. +var ruralRefStd = regionInt.map(bufferOptimize); + +Map.addLayer(ruralRefStd, { + color: 'brown' +}, 'Buffer_ref_std'); + +print('ruralRefStd', ruralRefStd); + +// Select the NLCD land cover data. +var landCover = ee.Image('USGS/NLCD/NLCD2016').select('landcover'); +var urban = landCover; + +// Select urban pixels in image. +var urbanUrban = urban.updateMask(urban.eq(23).or(urban.eq(24))); + +// Select background reference pixels in the image. +var nonUrbanVals = [41, 42, 43, 51, 52, 71, 72, 73, 74, 81, 82]; +var nonUrbanPixels = urban.eq(ee.Image(nonUrbanVals)).reduce('max'); +var urbanNonUrban = urban.updateMask(nonUrbanPixels); + +Map.addLayer(urbanUrban.clip(regionInt), { + palette: 'red' +}, 'Urban pixels'); +Map.addLayer(urbanNonUrban.clip(regionInt), { + palette: 'blue' +}, 'Non-urban pixels'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Define function to reduce regions and summarize pixel values +// to get mean LST for different cases. +function polygonMean(feature) { + + // Calculate spatial mean value of LST for each case + // making sure the pixel values are converted to °C from Kelvin. + var reducedLstUrb = lstFinal.subtract(273.15).updateMask(notWater) + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: feature.geometry(), + scale: 30 + }); + var reducedLstUrbMask = lstFinal.subtract(273.15).updateMask( + notWater) + .updateMask(urbanUrban) + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: feature.geometry(), + scale: 30 + }); + var reducedLstUrbPix = lstFinal.subtract(273.15).updateMask( + notWater) + .updateMask(urbanUrban) + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: feature.geometry(), + scale: 500 + }); + var reducedLstLandsatUrbPix = landsatComp.updateMask(notWater) + .updateMask(urbanUrban) + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: feature.geometry(), + scale: 30 + }); + var reducedLstRurPix = lstFinal.subtract(273.15).updateMask( + notWater) + .updateMask(urbanNonUrban) + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: feature.geometry(), + scale: 500 + }); + var reducedLstLandsatRurPix = landsatComp.updateMask(notWater) + .updateMask(urbanNonUrban) + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: feature.geometry(), + scale: 30 + }); + + // Return each feature with the summarized LSY values as properties. + return feature.set({ + 'MODIS_LST_urb': reducedLstUrb.get('LST_Day_1km'), + 'MODIS_LST_urb_mask': reducedLstUrbMask.get( + 'LST_Day_1km'), + 'MODIS_LST_urb_pix': reducedLstUrbPix.get( + 'LST_Day_1km'), + 'MODIS_LST_rur_pix': reducedLstRurPix.get( + 'LST_Day_1km'), + 'Landsat_LST_urb_pix': reducedLstLandsatUrbPix.get( + 'LST'), + 'Landsat_LST_rur_pix': reducedLstLandsatRurPix.get( + 'LST') + }); +} + +// Map the function over the urban boundary to get mean urban and rural LST +// for cases without any explicit buffer-based boundaries. +var reduced = regionInt.map(polygonMean); + +// Define a function to reduce region and summarize pixel values +// to get mean LST for different cases. +function refMean(feature) { + // Calculate spatial mean value of LST for each case + // making sure the pixel values are converted to °C from Kelvin. + var reducedLstRur = lstFinal.subtract(273.15).updateMask(notWater) + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: feature.geometry(), + scale: 30 + }); + var reducedLstRurMask = lstFinal.subtract(273.15).updateMask( + notWater) + .updateMask(urbanNonUrban) + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: feature.geometry(), + scale: 30 + }); + return feature.set({ + 'MODIS_LST_rur': reducedLstRur.get('LST_Day_1km'), + 'MODIS_LST_rur_mask': reducedLstRurMask.get( + 'LST_Day_1km'), + }); +} + +// Map the function over the constant buffer rural reference boundary one. +var reducedRural = ee.FeatureCollection(ruralRef).map(refMean); + +// Map the function over the standardized rural reference boundary. +var reducedRuralStd = ruralRefStd.map(refMean); + +print('reduced', reduced); +print('reducedRural', reducedRural); +print('reducedRuralStd', reducedRuralStd); + +// Display SUHI variability within the city. +var suhi = landsatComp + .updateMask(urbanUrban) + .subtract(ee.Number(ee.Feature(reduced.first()) + .get('Landsat_LST_rur_pix'))); + +Map.addLayer(suhi, { + palette: ['blue', 'white', 'red'], + min: 2, + max: 8 +}, 'SUHI'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15e Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15e Checkpoint.py new file mode 100644 index 0000000..637c784 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/A15e Checkpoint.py @@ -0,0 +1,411 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.5 Heat Islands +# Checkpoint: A15e +# Author: TC Chakraborty +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load feature collection of New Haven's census tracts from user assets. +regionInt = ee.FeatureCollection( + 'projects/gee-book/assets/A1-5/TC_NewHaven') + +# Get dissolved feature collection using an error margin of 50 meters. +regionInt = regionInt.union(50) + +# Set map center and zoom level (Zoom level varies from 1 to 20). +Map.setCenter(-72.9, 41.3, 12) + +# Add layer to map. +Map.addLayer(regionInt, {}, 'New Haven boundary') + +# Load MODIS image collection from the Earth Engine data catalog. +modisLst = ee.ImageCollection('MODIS/006/MYD11A2') + +# Select the band of interest (in this case: Daytime LST). +landSurfTemperature = modisLst.select('LST_Day_1km') + +# Create a summer filter. +sumFilter = ee.Filter.dayOfYear(152, 243) + +#Filter the date range of interest using a date filter. +lstDateInt = landSurfTemperature \ + .filterDate('2014-01-01', '2019-01-01').filter(sumFilter) + +# Take pixel-wise mean of all the images in the collection. +lstMean = lstDateInt.mean() + +# Multiply each pixel by scaling factor to get the LST values. +lstFinal = lstMean.multiply(0.02) + +# Generate a water mask. +water = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select( + 'occurrence') +notWater = water.mask().Not() + +# Clip data to region of interest, convert to degree Celsius, and mask water pixels. +lstNewHaven = lstFinal.clip(regionInt).subtract(273.15) \ + .updateMask(notWater) + +# Add layer to map. +Map.addLayer(lstNewHaven, { + 'palette': ['blue', 'white', 'red'], + 'min': 25, + 'max': 38 + }, + 'LST_MODIS') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Function to filter out cloudy pixels. +def cloudMask(cloudyScene): + # Add a cloud score band to the image. + scored = ee.Algorithms.Landsat.simpleCloudScore(cloudyScene) + + # Create an image mask from the cloud score band and specify threshold. + mask = scored.select(['cloud']).lte(10) + + # Apply the mask to the original image and return the masked image. + return cloudyScene.updateMask(mask) + + +# Load the collection, apply cloud mask, and filter to date and region of interest. +col = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterBounds(regionInt) \ + .filterDate('2014-01-01', '2019-01-01') \ + .filter(sumFilter) \ + .map(cloudMask) + +print('Landsat collection', col) + +# Generate median composite. +image = col.median() + +# Select thermal band 10 (with brightness temperature). +thermal = image.select('B10') \ + .clip(regionInt) \ + .updateMask(notWater) + +Map.addLayer(thermal, { + 'min': 295, + 'max': 310, + 'palette': ['blue', 'white', 'red'] + }, + 'Landsat_BT') + +# Calculate Normalized Difference Vegetation Index (NDVI) +# from Landsat surface reflectance. +ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(regionInt) \ + .filterDate('2014-01-01', '2019-01-01') \ + .filter(sumFilter) \ + .median() \ + .normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI') \ + .clip(regionInt) \ + .updateMask(notWater) + +Map.addLayer(ndvi, { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'white', 'green'] + }, + 'ndvi') + +# Find the minimum and maximum of NDVI. Combine the reducers +# for efficiency (single pass over the data). +minMax = ndvi.reduceRegion({ + 'reducer': ee.Reducer.min().combine({ + 'reducer2': ee.Reducer.max(), + 'sharedInputs': True + }), + 'geometry': regionInt, + 'scale': 30, + 'maxPixels': 1e9 +}) +print('minMax', minMax) + +min = ee.Number(minMax.get('NDVI_min')) +max = ee.Number(minMax.get('NDVI_max')) + +# Calculate fractional vegetation. +fv = ndvi.subtract(min).divide(max.subtract(min)).rename('FV') +Map.addLayer(fv, { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'white', 'green'] +}, 'fv') + +# Emissivity calculations. +a = ee.Number(0.004) +b = ee.Number(0.986) +em = fv.multiply(a).add(b).rename('EMM').updateMask(notWater) + +Map.addLayer(em, { + 'min': 0.98, + 'max': 0.99, + 'palette': ['blue', 'white', 'green'] + }, + 'EMM') + +# Calculate LST from emissivity and brightness temperature. +lstLandsat = thermal.expression( + '(Tb/(1 + (0.001145* (Tb / 1.438))*log(Ep)))-273.15', { + 'Tb': thermal.select('B10'), + 'Ep': em.select('EMM') + }).updateMask(notWater) + +Map.addLayer(lstLandsat, { + 'min': 25, + 'max': 35, + 'palette': ['blue', 'white', 'red'], + }, + 'LST_Landsat') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Link to the module that computes the Landsat LST. +landsatLST = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js') + +# Select region of interest, date range, and Landsat satellite. +geometry = regionInt.geometry() +satellite = 'L8' +dateStart = '2014-01-01' +dateEnd = '2019-01-01' +useNdvi = True + +# Get Landsat collection with additional necessary variables. +landsatColl = landsatLST.collection(satellite, dateStart, dateEnd, + geometry, useNdvi) + +# Create composite, clip, filter to summer, mask, and convert to degree Celsius. +landsatComp = landsatColl \ + .select('LST') \ + .filter(sumFilter) \ + .median() \ + .clip(regionInt) \ + .updateMask(notWater) \ + .subtract(273.15) + +Map.addLayer(landsatComp, { + 'min': 25, + 'max': 38, + 'palette': ['blue', 'white', 'red'] + }, + 'LST_SMW') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Function to subtract the original urban cluster from the buffered cluster +# to generate rural references. +def bufferSubtract(feature): + return ee.Feature(feature.geometry() \ + .buffer(2000) \ + .difference(feature.geometry())) + + +ruralRef = regionInt.map(bufferSubtract) + +Map.addLayer(ruralRef, { + 'color': 'green' +}, 'Buffer_ref') + +# Define sequence of buffer widths to be tested. +buffWidths = ee.List.sequence(30, 3000, 30) + +# Function to generate standardized buffers (approximately comparable to area of urban cluster). +def bufferOptimize(feature): + def buff(buffLength): + buffedPolygon = ee.Feature(feature.geometry() \ + .buffer(ee.Number(buffLength))) \ + .set({ + 'Buffer_width': ee.Number(buffLength) + }) + area = buffedPolygon.geometry().difference(feature \ + .geometry()).area() + diffFeature = ee.Feature( + buffedPolygon.geometry().difference(feature \ + .geometry())) + return diffFeature.set({ + 'Buffer_diff': area.subtract(feature.geometry() \ + .area()).abs(), + 'Buffer_area': area, + 'Buffer_width': buffedPolygon.get('Buffer_width') + }) + + + buffed = ee.FeatureCollection(buffWidths.map(buff)) + sortedByBuffer = buffed.sort({ + 'property': 'Buffer_diff' + }) + firstFeature = ee.Feature(sortedByBuffer.first()) + return firstFeature.set({ + 'Urban_Area': feature.get('Area'), + 'Buffer_width': firstFeature.get('Buffer_width') + }) + + +# Map function over urban feature collection. +ruralRefStd = regionInt.map(bufferOptimize) + +Map.addLayer(ruralRefStd, { + 'color': 'brown' +}, 'Buffer_ref_std') + +print('ruralRefStd', ruralRefStd) + +# Select the NLCD land cover data. +landCover = ee.Image('USGS/NLCD/NLCD2016').select('landcover') +urban = landCover + +# Select urban pixels in image. +urbanUrban = urban.updateMask(urban.eq(23).Or(urban.eq(24))) + +# Select background reference pixels in the image. +nonUrbanVals = [41, 42, 43, 51, 52, 71, 72, 73, 74, 81, 82] +nonUrbanPixels = urban.eq(ee.Image(nonUrbanVals)).reduce('max') +urbanNonUrban = urban.updateMask(nonUrbanPixels) + +Map.addLayer(urbanUrban.clip(regionInt), { + 'palette': 'red' +}, 'Urban pixels') +Map.addLayer(urbanNonUrban.clip(regionInt), { + 'palette': 'blue' +}, 'Non-urban pixels') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Define function to reduce regions and summarize pixel values +# to get mean LST for different cases. +def polygonMean(feature): + + # Calculate spatial mean value of LST for each case + # making sure the pixel values are converted to °C from Kelvin. + reducedLstUrb = lstFinal.subtract(273.15).updateMask(notWater) \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': feature.geometry(), + 'scale': 30 + }) + reducedLstUrbMask = lstFinal.subtract(273.15).updateMask( + notWater) \ + .updateMask(urbanUrban) \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': feature.geometry(), + 'scale': 30 + }) + reducedLstUrbPix = lstFinal.subtract(273.15).updateMask( + notWater) \ + .updateMask(urbanUrban) \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': feature.geometry(), + 'scale': 500 + }) + reducedLstLandsatUrbPix = landsatComp.updateMask(notWater) \ + .updateMask(urbanUrban) \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': feature.geometry(), + 'scale': 30 + }) + reducedLstRurPix = lstFinal.subtract(273.15).updateMask( + notWater) \ + .updateMask(urbanNonUrban) \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': feature.geometry(), + 'scale': 500 + }) + reducedLstLandsatRurPix = landsatComp.updateMask(notWater) \ + .updateMask(urbanNonUrban) \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': feature.geometry(), + 'scale': 30 + }) + + # Return each feature with the summarized LSY values as properties. + return feature.set({ + 'MODIS_LST_urb': reducedLstUrb.get('LST_Day_1km'), + 'MODIS_LST_urb_mask': reducedLstUrbMask.get( + 'LST_Day_1km'), + 'MODIS_LST_urb_pix': reducedLstUrbPix.get( + 'LST_Day_1km'), + 'MODIS_LST_rur_pix': reducedLstRurPix.get( + 'LST_Day_1km'), + 'Landsat_LST_urb_pix': reducedLstLandsatUrbPix.get( + 'LST'), + 'Landsat_LST_rur_pix': reducedLstLandsatRurPix.get( + 'LST') + }) + + +# Map the function over the urban boundary to get mean urban and rural LST +# for cases without any explicit buffer-based boundaries. +reduced = regionInt.map(polygonMean) + +# Define a function to reduce region and summarize pixel values +# to get mean LST for different cases. +def refMean(feature): + # Calculate spatial mean value of LST for each case + # making sure the pixel values are converted to °C from Kelvin. + reducedLstRur = lstFinal.subtract(273.15).updateMask(notWater) \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': feature.geometry(), + 'scale': 30 + }) + reducedLstRurMask = lstFinal.subtract(273.15).updateMask( + notWater) \ + .updateMask(urbanNonUrban) \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': feature.geometry(), + 'scale': 30 + }) + return feature.set({ + 'MODIS_LST_rur': reducedLstRur.get('LST_Day_1km'), + 'MODIS_LST_rur_mask': reducedLstRurMask.get( + 'LST_Day_1km'), + }) + + +# Map the function over the constant buffer rural reference boundary one. +reducedRural = ee.FeatureCollection(ruralRef).map(refMean) + +# Map the function over the standardized rural reference boundary. +reducedRuralStd = ruralRefStd.map(refMean) + +print('reduced', reduced) +print('reducedRural', reducedRural) +print('reducedRuralStd', reducedRuralStd) + +# Display SUHI variability within the city. +suhi = landsatComp \ + .updateMask(urbanUrban) \ + .subtract(ee.Number(ee.Feature(reduced.first()) \ + .get('Landsat_LST_rur_pix'))) + +Map.addLayer(suhi, { + 'palette': ['blue', 'white', 'red'], + 'min': 2, + 'max': 8 +}, 'SUHI') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/ASTER_bare_emiss.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/ASTER_bare_emiss.ipynb new file mode 100644 index 0000000..6d71ad5 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/ASTER_bare_emiss.ipynb @@ -0,0 +1,172 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "This code is free and open.\n", + "By using this code and any data derived with it,\n", + "you agree to cite the following reference\n", + "'in any publications derived from them':\n", + "Ermida, S.L., Soares, P., Mantas, V., G\u00f6ttsche, F.-M., Trigo, I.F., 2020.\n", + " Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.\n", + " 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471\n", + "\n", + "This function applies a vegetation cover correction to ASTER emissivity\n", + "in order to obtain a bare ground emissivity component at each pixel\n", + "\n", + "'to call this function use':\n", + "\n", + "ASTERGED = require('users/sofiaermida/landsat_smw_lst:modules/ASTER_bare_emiss.js')\n", + "bare_ground_emiss = ASTERGED.emiss_bare_bandXX(image)\n", + "or\n", + "ImageCollectionwithASTER = ImageCollection.map(ASTERGED.emiss_bare_bandXX)\n", + "\n", + "with XX = band number\n", + "\n", + "'INPUTS':\n", + " '- image': \n", + " an image is required to clip the ASTER data\n", + " to the image geometry; using the full ASTER image\n", + " compromises the performance\n", + "'OUTPUTS':\n", + " - \n", + " bare ground emissivity of band XX\n", + "#\n", + "\n", + "\n", + "# get ASTER emissivity\n", + "aster = ee.Image(\"NASA/ASTER_GED/AG100_003\")\n", + "\n", + "#get ASTER FVC from NDVI\n", + "aster_ndvi = aster.select('ndvi').multiply(0.01)\n", + "\n", + "aster_fvc = aster_ndvi.expression('((ndvi-ndvi_bg)/(ndvi_vg - ndvi_bg))**2',\n", + " {'ndvi':aster_ndvi,'ndvi_bg':0.2,'ndvi_vg':0.86})\n", + "aster_fvc = aster_fvc.where(aster_fvc.lt(0.0),0.0)\n", + "aster_fvc = aster_fvc.where(aster_fvc.gt(1.0),1.0)\n", + "\n", + "# bare ground emissivity functions for each band\n", + "def exports.emiss_bare_band10(image):\n", + " return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{\n", + " 'EM':aster.select('emissivity_band10').multiply(0.001),\n", + " 'fvc':aster_fvc}) \\\n", + " .clip(image.geometry())\n", + "\n", + "\n", + "def exports.emiss_bare_band11(image):\n", + " return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{\n", + " 'EM':aster.select('emissivity_band11').multiply(0.001),\n", + " 'fvc':aster_fvc}) \\\n", + " .clip(image.geometry())\n", + "\n", + "\n", + "def exports.emiss_bare_band12(image):\n", + " return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{\n", + " 'EM':aster.select('emissivity_band12').multiply(0.001),\n", + " 'fvc':aster_fvc}) \\\n", + " .clip(image.geometry())\n", + "\n", + "\n", + "def exports.emiss_bare_band13(image):\n", + " return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{\n", + " 'EM':aster.select('emissivity_band13').multiply(0.001),\n", + " 'fvc':aster_fvc}) \\\n", + " .clip(image.geometry())\n", + "\n", + "\n", + "def exports.emiss_bare_band14(image):\n", + " return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{\n", + " 'EM':aster.select('emissivity_band14').multiply(0.001),\n", + " 'fvc':aster_fvc}) \\\n", + " .clip(image.geometry())\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/ASTER_bare_emiss.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/ASTER_bare_emiss.js new file mode 100644 index 0000000..a8bacbf --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/ASTER_bare_emiss.js @@ -0,0 +1,80 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +in any publications derived from them: +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471 + +This function applies a vegetation cover correction to ASTER emissivity +in order to obtain a bare ground emissivity component at each pixel + +to call this function use: + +var ASTERGED = require('users/sofiaermida/landsat_smw_lst:modules/ASTER_bare_emiss.js') +var bare_ground_emiss = ASTERGED.emiss_bare_bandXX(image) +or +var ImageCollectionwithASTER = ImageCollection.map(ASTERGED.emiss_bare_bandXX) + +with XX = band number + +INPUTS: + - image: + an image is required to clip the ASTER data + to the image geometry; using the full ASTER image + compromises the performance +OUTPUTS: + - + bare ground emissivity of band XX +*/ + + +// get ASTER emissivity +var aster = ee.Image("NASA/ASTER_GED/AG100_003") + +//get ASTER FVC from NDVI +var aster_ndvi = aster.select('ndvi').multiply(0.01); + +var aster_fvc = aster_ndvi.expression('((ndvi-ndvi_bg)/(ndvi_vg - ndvi_bg))**2', + {'ndvi':aster_ndvi,'ndvi_bg':0.2,'ndvi_vg':0.86}); +aster_fvc = aster_fvc.where(aster_fvc.lt(0.0),0.0); +aster_fvc = aster_fvc.where(aster_fvc.gt(1.0),1.0); + +// bare ground emissivity functions for each band +exports.emiss_bare_band10 = function(image){ + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band10').multiply(0.001), + 'fvc':aster_fvc}) + .clip(image.geometry()) +}; + +exports.emiss_bare_band11 = function(image){ + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band11').multiply(0.001), + 'fvc':aster_fvc}) + .clip(image.geometry()) +}; + +exports.emiss_bare_band12 = function(image){ + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band12').multiply(0.001), + 'fvc':aster_fvc}) + .clip(image.geometry()) +}; + +exports.emiss_bare_band13 = function(image){ + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band13').multiply(0.001), + 'fvc':aster_fvc}) + .clip(image.geometry()) +}; + +exports.emiss_bare_band14 = function(image){ + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band14').multiply(0.001), + 'fvc':aster_fvc}) + .clip(image.geometry()) +}; \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/ASTER_bare_emiss.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/ASTER_bare_emiss.py new file mode 100644 index 0000000..61735c9 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/ASTER_bare_emiss.py @@ -0,0 +1,86 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +'in any publications derived from them': +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471 + +This function applies a vegetation cover correction to ASTER emissivity +in order to obtain a bare ground emissivity component at each pixel + +'to call this function use': + +ASTERGED = require('users/sofiaermida/landsat_smw_lst:modules/ASTER_bare_emiss.js') +bare_ground_emiss = ASTERGED.emiss_bare_bandXX(image) +or +ImageCollectionwithASTER = ImageCollection.map(ASTERGED.emiss_bare_bandXX) + +with XX = band number + +'INPUTS': + '- image': + an image is required to clip the ASTER data + to the image geometry; using the full ASTER image + compromises the performance +'OUTPUTS': + - + bare ground emissivity of band XX +# + + +# get ASTER emissivity +aster = ee.Image("NASA/ASTER_GED/AG100_003") + +#get ASTER FVC from NDVI +aster_ndvi = aster.select('ndvi').multiply(0.01) + +aster_fvc = aster_ndvi.expression('((ndvi-ndvi_bg)/(ndvi_vg - ndvi_bg))**2', + {'ndvi':aster_ndvi,'ndvi_bg':0.2,'ndvi_vg':0.86}) +aster_fvc = aster_fvc.where(aster_fvc.lt(0.0),0.0) +aster_fvc = aster_fvc.where(aster_fvc.gt(1.0),1.0) + +# bare ground emissivity functions for each band +def exports.emiss_bare_band10(image): + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band10').multiply(0.001), + 'fvc':aster_fvc}) \ + .clip(image.geometry()) + + +def exports.emiss_bare_band11(image): + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band11').multiply(0.001), + 'fvc':aster_fvc}) \ + .clip(image.geometry()) + + +def exports.emiss_bare_band12(image): + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band12').multiply(0.001), + 'fvc':aster_fvc}) \ + .clip(image.geometry()) + + +def exports.emiss_bare_band13(image): + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band13').multiply(0.001), + 'fvc':aster_fvc}) \ + .clip(image.geometry()) + + +def exports.emiss_bare_band14(image): + return image.expression('(EM - 0.99*fvc)/(1.0-fvc)',{ + 'EM':aster.select('emissivity_band14').multiply(0.001), + 'fvc':aster_fvc}) \ + .clip(image.geometry()) + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.ipynb new file mode 100644 index 0000000..e8d6c8c --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.ipynb @@ -0,0 +1,271 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "This code is free and open.\n", + "By using this code and any data derived with it,\n", + "you agree to cite the following reference\n", + "'in any publications derived from them':\n", + "Ermida, S.L., Soares, P., Mantas, V., G\u00f6ttsche, F.-M., Trigo, I.F., 2020.\n", + " Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.\n", + " 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471\n", + "\n", + "This function selects the Landsat data based on user inputs\n", + "and performes the LST computation\n", + "\n", + "'to call this function use':\n", + "\n", + "LandsatLST = require('users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js')\n", + "LandsatCollection = LandsatLST.collection(landsat, date_start, date_end, geometry)\n", + "\n", + "'USES':\n", + " - NCEP_TPW.js\n", + " - cloudmask.js\n", + " - compute_NDVI.js\n", + " - compute_FVC.js\n", + " - compute_emissivity.js\n", + " - SMWalgorithm.js\n", + "\n", + "'INPUTS':\n", + " '- landsat': \n", + " the Landsat satellite id\n", + " 'valid inputs': 'L4', 'L5', 'L7' and 'L8'\n", + " '- date_start': \n", + " start date of the Landsat collection\n", + " format: YYYY-MM-DD\n", + " '- date_end': \n", + " end date of the Landsat collection\n", + " format: YYYY-MM-DD\n", + " '- geometry': \n", + " region of interest\n", + " '- use_ndvi': \n", + " if True, NDVI values are used to obtain a\n", + " dynamic emissivity; if False, emissivity is\n", + " obtained directly from ASTER\n", + "'OUTPUTS':\n", + " - \n", + " 'image collection with bands':\n", + " '- landsat original bands': all from SR excpet the TIR bands (from TOA)\n", + " - cloud masked\n", + " - 'NDVI': normalized vegetation index\n", + " - 'FVC': fraction of vegetation cover [0-1]\n", + " - 'TPW': total precipitable water [mm]\n", + " - 'EM': surface emissvity for TIR band\n", + " - 'LST': land surface temperature\n", + "\n", + " '14-08-2020': update to avoid using the getInfo() and if()\n", + " (Thanks Tyler Erickson for the suggestion)\n", + "\n", + " '11-07-2022': update to use collection 2\n", + "#\n", + "\n", + "##############/ ATTENTION ###################\n", + "######################################/\n", + "#\n", + "# As off 11.07.2022 a new version of the code is released:\n", + "# - update to use collection 2 data\n", + "# - emissivities of water and snow surfaces are now prescribed\n", + "#\n", + "# the previous version of the code will still be available; the replaced code\n", + "# is commented\n", + "#\n", + "#######################################\n", + "#######################################\n", + "\n", + "# MODULES DECLARATION -----------------------------------------------------------\n", + "# Total Precipitable Water\n", + "NCEP_TPW = require('users/sofiaermida/landsat_smw_lst:modules/NCEP_TPW.js')\n", + "#cloud mask\n", + "cloudmask = require('users/sofiaermida/landsat_smw_lst:modules/cloudmask.js')\n", + "#Normalized Difference Vegetation Index\n", + "NDVI = require('users/sofiaermida/landsat_smw_lst:modules/compute_NDVI.js')\n", + "#Fraction of Vegetation cover\n", + "FVC = require('users/sofiaermida/landsat_smw_lst:modules/compute_FVC.js')\n", + "#surface emissivity\n", + "EM = require('users/sofiaermida/landsat_smw_lst:modules/compute_emissivity.js')\n", + "# land surface temperature\n", + "LST = require('users/sofiaermida/landsat_smw_lst:modules/SMWalgorithm.js')\n", + "# --------------------------------------------------------------------------------\n", + "\n", + "COLLECTION = ee.Dictionary({\n", + " 'L4': {\n", + " 'TOA': ee.ImageCollection('LANDSAT/LT04/C02/T1_TOA'),\n", + " 'SR': ee.ImageCollection('LANDSAT/LT04/C02/T1_L2'),\n", + " 'TIR': ['B6',],\n", + " 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7','QA_PIXEL']\n", + " },\n", + " 'L5': {\n", + " 'TOA': ee.ImageCollection('LANDSAT/LT05/C02/T1_TOA'),\n", + " 'SR': ee.ImageCollection('LANDSAT/LT05/C02/T1_L2'),\n", + " 'TIR': ['B6',],\n", + " 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7','QA_PIXEL']\n", + " },\n", + " 'L7': {\n", + " 'TOA': ee.ImageCollection('LANDSAT/LE07/C02/T1_TOA'),\n", + " 'SR': ee.ImageCollection('LANDSAT/LE07/C02/T1_L2'),\n", + " 'TIR': ['B6_VCID_1','B6_VCID_2'],\n", + " 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7','QA_PIXEL']\n", + " },\n", + " 'L8': {\n", + " 'TOA': ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA'),\n", + " 'SR': ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'),\n", + " 'TIR': ['B10','B11'],\n", + " 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B6','SR_B7','QA_PIXEL']\n", + " }\n", + "})\n", + "\n", + "# COLLECTION 1\n", + "COLLECTION = ee.Dictionary({\n", + " 'L4': {\n", + " 'TOA': ee.ImageCollection('LANDSAT/LT04/C01/T1_TOA'),\n", + " 'SR': ee.ImageCollection('LANDSAT/LT04/C01/T1_SR'),\n", + " 'TIR': ['B6',]\n", + " },\n", + " 'L5': {\n", + " 'TOA': ee.ImageCollection('LANDSAT/LT05/C01/T1_TOA'),\n", + " 'SR': ee.ImageCollection('LANDSAT/LT05/C01/T1_SR'),\n", + " 'TIR': ['B6',]\n", + " },\n", + " 'L7': {\n", + " 'TOA': ee.ImageCollection('LANDSAT/LE07/C01/T1_TOA'),\n", + " 'SR': ee.ImageCollection('LANDSAT/LE07/C01/T1_SR'),\n", + " 'TIR': ['B6_VCID_1','B6_VCID_2'],\n", + " },\n", + " 'L8': {\n", + " 'TOA': ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA'),\n", + " 'SR': ee.ImageCollection('LANDSAT/LC08/C01/T1_SR'),\n", + " 'TIR': ['B10','B11']\n", + " }\n", + "})\n", + "#\n", + "\n", + "def exports.collection(landsat, date_start, date_end, geometry, use_ndvi):\n", + "\n", + " print('!!!!! On 11-07-2022 this code has been updated to run with landsat collection 2 data !!!!!')\n", + " # load TOA Radiance/Reflectance\n", + " collection_dict = ee.Dictionary(COLLECTION.get(landsat))\n", + "\n", + " landsatTOA = ee.ImageCollection(collection_dict.get('TOA')) \\\n", + " .filter(ee.Filter.date(date_start, date_end)) \\\n", + " .filterBounds(geometry)\n", + " #.map(cloudmask.toa)\n", + "\n", + " # load Surface Reflectance collection for NDVI\n", + " landsatSR = ee.ImageCollection(collection_dict.get('SR')) \\\n", + " .filter(ee.Filter.date(date_start, date_end)) \\\n", + " .filterBounds(geometry) \\\n", + " .map(cloudmask.sr) \\\n", + " .map(NDVI.addBand(landsat)) \\\n", + " .map(FVC.addBand(landsat)) \\\n", + " .map(NCEP_TPW.addBand) \\\n", + " .map(EM.addBand(landsat,use_ndvi))\n", + "\n", + " # combine collections\n", + " # all channels from surface reflectance collection\n", + " # except tir channels: from TOA collection\n", + " # select TIR bands\n", + " tir = ee.List(collection_dict.get('TIR'))\n", + " visw = ee.List(collection_dict.get('VISW')) \\\n", + " .add('NDVI') \\\n", + " .add('FVC') \\\n", + " .add('TPW') \\\n", + " .add('TPWpos') \\\n", + " .add('EM')\n", + " landsatALL = (landsatSR.select(visw).combine(landsatTOA.select(tir), True))\n", + "\n", + " # compute the LST\n", + " landsatLST = landsatALL.map(LST.addBand(landsat))\n", + "\n", + " return landsatLST\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js new file mode 100644 index 0000000..089ccb0 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.js @@ -0,0 +1,179 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +in any publications derived from them: +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471 + +This function selects the Landsat data based on user inputs +and performes the LST computation + +to call this function use: + +var LandsatLST = require('users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js') +var LandsatCollection = LandsatLST.collection(landsat, date_start, date_end, geometry) + +USES: + - NCEP_TPW.js + - cloudmask.js + - compute_NDVI.js + - compute_FVC.js + - compute_emissivity.js + - SMWalgorithm.js + +INPUTS: + - landsat: + the Landsat satellite id + valid inputs: 'L4', 'L5', 'L7' and 'L8' + - date_start: + start date of the Landsat collection + format: YYYY-MM-DD + - date_end: + end date of the Landsat collection + format: YYYY-MM-DD + - geometry: + region of interest + - use_ndvi: + if true, NDVI values are used to obtain a + dynamic emissivity; if false, emissivity is + obtained directly from ASTER +OUTPUTS: + - + image collection with bands: + - landsat original bands: all from SR excpet the TIR bands (from TOA) + - cloud masked + - 'NDVI': normalized vegetation index + - 'FVC': fraction of vegetation cover [0-1] + - 'TPW': total precipitable water [mm] + - 'EM': surface emissvity for TIR band + - 'LST': land surface temperature + + 14-08-2020: update to avoid using the getInfo() and if() + (Thanks Tyler Erickson for the suggestion) + + 11-07-2022: update to use collection 2 +*/ + +///////////////////////////// ATTENTION ////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// +// As off 11.07.2022 a new version of the code is released: +// - update to use collection 2 data +// - emissivities of water and snow surfaces are now prescribed +// +// the previous version of the code will still be available; the replaced code +// is commented +// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// MODULES DECLARATION ----------------------------------------------------------- +// Total Precipitable Water +var NCEP_TPW = require('users/sofiaermida/landsat_smw_lst:modules/NCEP_TPW.js') +//cloud mask +var cloudmask = require('users/sofiaermida/landsat_smw_lst:modules/cloudmask.js') +//Normalized Difference Vegetation Index +var NDVI = require('users/sofiaermida/landsat_smw_lst:modules/compute_NDVI.js') +//Fraction of Vegetation cover +var FVC = require('users/sofiaermida/landsat_smw_lst:modules/compute_FVC.js') +//surface emissivity +var EM = require('users/sofiaermida/landsat_smw_lst:modules/compute_emissivity.js') +// land surface temperature +var LST = require('users/sofiaermida/landsat_smw_lst:modules/SMWalgorithm.js') +// -------------------------------------------------------------------------------- + +var COLLECTION = ee.Dictionary({ + 'L4': { + 'TOA': ee.ImageCollection('LANDSAT/LT04/C02/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LT04/C02/T1_L2'), + 'TIR': ['B6',], + 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7','QA_PIXEL'] + }, + 'L5': { + 'TOA': ee.ImageCollection('LANDSAT/LT05/C02/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LT05/C02/T1_L2'), + 'TIR': ['B6',], + 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7','QA_PIXEL'] + }, + 'L7': { + 'TOA': ee.ImageCollection('LANDSAT/LE07/C02/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LE07/C02/T1_L2'), + 'TIR': ['B6_VCID_1','B6_VCID_2'], + 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7','QA_PIXEL'] + }, + 'L8': { + 'TOA': ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'), + 'TIR': ['B10','B11'], + 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B6','SR_B7','QA_PIXEL'] + } +}); + +/* COLLECTION 1 +var COLLECTION = ee.Dictionary({ + 'L4': { + 'TOA': ee.ImageCollection('LANDSAT/LT04/C01/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LT04/C01/T1_SR'), + 'TIR': ['B6',] + }, + 'L5': { + 'TOA': ee.ImageCollection('LANDSAT/LT05/C01/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LT05/C01/T1_SR'), + 'TIR': ['B6',] + }, + 'L7': { + 'TOA': ee.ImageCollection('LANDSAT/LE07/C01/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LE07/C01/T1_SR'), + 'TIR': ['B6_VCID_1','B6_VCID_2'], + }, + 'L8': { + 'TOA': ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LC08/C01/T1_SR'), + 'TIR': ['B10','B11'] + } +}); +*/ + +exports.collection = function(landsat, date_start, date_end, geometry, use_ndvi) { + + print('!!!!! On 11-07-2022 this code has been updated to run with landsat collection 2 data !!!!!') + // load TOA Radiance/Reflectance + var collection_dict = ee.Dictionary(COLLECTION.get(landsat)); + + var landsatTOA = ee.ImageCollection(collection_dict.get('TOA')) + .filter(ee.Filter.date(date_start, date_end)) + .filterBounds(geometry) + //.map(cloudmask.toa); + + // load Surface Reflectance collection for NDVI + var landsatSR = ee.ImageCollection(collection_dict.get('SR')) + .filter(ee.Filter.date(date_start, date_end)) + .filterBounds(geometry) + .map(cloudmask.sr) + .map(NDVI.addBand(landsat)) + .map(FVC.addBand(landsat)) + .map(NCEP_TPW.addBand) + .map(EM.addBand(landsat,use_ndvi)); + + // combine collections + // all channels from surface reflectance collection + // except tir channels: from TOA collection + // select TIR bands + var tir = ee.List(collection_dict.get('TIR')); + var visw = ee.List(collection_dict.get('VISW')) + .add('NDVI') + .add('FVC') + .add('TPW') + .add('TPWpos') + .add('EM'); + var landsatALL = (landsatSR.select(visw).combine(landsatTOA.select(tir), true)); + + // compute the LST + var landsatLST = landsatALL.map(LST.addBand(landsat)); + + return landsatLST; +}; \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.py new file mode 100644 index 0000000..0f01463 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/Landsat_LST.py @@ -0,0 +1,185 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +'in any publications derived from them': +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471 + +This function selects the Landsat data based on user inputs +and performes the LST computation + +'to call this function use': + +LandsatLST = require('users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js') +LandsatCollection = LandsatLST.collection(landsat, date_start, date_end, geometry) + +'USES': + - NCEP_TPW.js + - cloudmask.js + - compute_NDVI.js + - compute_FVC.js + - compute_emissivity.js + - SMWalgorithm.js + +'INPUTS': + '- landsat': + the Landsat satellite id + 'valid inputs': 'L4', 'L5', 'L7' and 'L8' + '- date_start': + start date of the Landsat collection + format: YYYY-MM-DD + '- date_end': + end date of the Landsat collection + format: YYYY-MM-DD + '- geometry': + region of interest + '- use_ndvi': + if True, NDVI values are used to obtain a + dynamic emissivity; if False, emissivity is + obtained directly from ASTER +'OUTPUTS': + - + 'image collection with bands': + '- landsat original bands': all from SR excpet the TIR bands (from TOA) + - cloud masked + - 'NDVI': normalized vegetation index + - 'FVC': fraction of vegetation cover [0-1] + - 'TPW': total precipitable water [mm] + - 'EM': surface emissvity for TIR band + - 'LST': land surface temperature + + '14-08-2020': update to avoid using the getInfo() and if() + (Thanks Tyler Erickson for the suggestion) + + '11-07-2022': update to use collection 2 +# + +##############/ ATTENTION ################### +######################################/ +# +# As off 11.07.2022 a new version of the code is released: +# - update to use collection 2 data +# - emissivities of water and snow surfaces are now prescribed +# +# the previous version of the code will still be available; the replaced code +# is commented +# +####################################### +####################################### + +# MODULES DECLARATION ----------------------------------------------------------- +# Total Precipitable Water +NCEP_TPW = require('users/sofiaermida/landsat_smw_lst:modules/NCEP_TPW.js') +#cloud mask +cloudmask = require('users/sofiaermida/landsat_smw_lst:modules/cloudmask.js') +#Normalized Difference Vegetation Index +NDVI = require('users/sofiaermida/landsat_smw_lst:modules/compute_NDVI.js') +#Fraction of Vegetation cover +FVC = require('users/sofiaermida/landsat_smw_lst:modules/compute_FVC.js') +#surface emissivity +EM = require('users/sofiaermida/landsat_smw_lst:modules/compute_emissivity.js') +# land surface temperature +LST = require('users/sofiaermida/landsat_smw_lst:modules/SMWalgorithm.js') +# -------------------------------------------------------------------------------- + +COLLECTION = ee.Dictionary({ + 'L4': { + 'TOA': ee.ImageCollection('LANDSAT/LT04/C02/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LT04/C02/T1_L2'), + 'TIR': ['B6',], + 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7','QA_PIXEL'] + }, + 'L5': { + 'TOA': ee.ImageCollection('LANDSAT/LT05/C02/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LT05/C02/T1_L2'), + 'TIR': ['B6',], + 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7','QA_PIXEL'] + }, + 'L7': { + 'TOA': ee.ImageCollection('LANDSAT/LE07/C02/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LE07/C02/T1_L2'), + 'TIR': ['B6_VCID_1','B6_VCID_2'], + 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7','QA_PIXEL'] + }, + 'L8': { + 'TOA': ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'), + 'TIR': ['B10','B11'], + 'VISW': ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B6','SR_B7','QA_PIXEL'] + } +}) + +# COLLECTION 1 +COLLECTION = ee.Dictionary({ + 'L4': { + 'TOA': ee.ImageCollection('LANDSAT/LT04/C01/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LT04/C01/T1_SR'), + 'TIR': ['B6',] + }, + 'L5': { + 'TOA': ee.ImageCollection('LANDSAT/LT05/C01/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LT05/C01/T1_SR'), + 'TIR': ['B6',] + }, + 'L7': { + 'TOA': ee.ImageCollection('LANDSAT/LE07/C01/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LE07/C01/T1_SR'), + 'TIR': ['B6_VCID_1','B6_VCID_2'], + }, + 'L8': { + 'TOA': ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA'), + 'SR': ee.ImageCollection('LANDSAT/LC08/C01/T1_SR'), + 'TIR': ['B10','B11'] + } +}) +# + +def exports.collection(landsat, date_start, date_end, geometry, use_ndvi): + + print('!!!!! On 11-07-2022 this code has been updated to run with landsat collection 2 data !!!!!') + # load TOA Radiance/Reflectance + collection_dict = ee.Dictionary(COLLECTION.get(landsat)) + + landsatTOA = ee.ImageCollection(collection_dict.get('TOA')) \ + .filter(ee.Filter.date(date_start, date_end)) \ + .filterBounds(geometry) + #.map(cloudmask.toa) + + # load Surface Reflectance collection for NDVI + landsatSR = ee.ImageCollection(collection_dict.get('SR')) \ + .filter(ee.Filter.date(date_start, date_end)) \ + .filterBounds(geometry) \ + .map(cloudmask.sr) \ + .map(NDVI.addBand(landsat)) \ + .map(FVC.addBand(landsat)) \ + .map(NCEP_TPW.addBand) \ + .map(EM.addBand(landsat,use_ndvi)) + + # combine collections + # all channels from surface reflectance collection + # except tir channels: from TOA collection + # select TIR bands + tir = ee.List(collection_dict.get('TIR')) + visw = ee.List(collection_dict.get('VISW')) \ + .add('NDVI') \ + .add('FVC') \ + .add('TPW') \ + .add('TPWpos') \ + .add('EM') + landsatALL = (landsatSR.select(visw).combine(landsatTOA.select(tir), True)) + + # compute the LST + landsatLST = landsatALL.map(LST.addBand(landsat)) + + return landsatLST + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/NCEP_TPW.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/NCEP_TPW.ipynb new file mode 100644 index 0000000..26ad7dd --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/NCEP_TPW.ipynb @@ -0,0 +1,195 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "This code is free and open.\n", + "By using this code and any data derived with it,\n", + "you agree to cite the following reference\n", + "'in any publications derived from them':\n", + "Ermida, S.L., Soares, P., Mantas, V., G\u00f6ttsche, F.-M., Trigo, I.F., 2020.\n", + " Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.\n", + " 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471\n", + "\n", + "this function matches the atmospheric water vapour data\n", + "from NCEP reanalysis to each Landsat image\n", + "tpw values are interpolated from the 6-hourly model times to the image time\n", + "\n", + "'to call this function use':\n", + "\n", + "NCEP_TPW = require('users/sofiaermida/landsat_smw_lst:modules/NCEP_TPW.js')\n", + "ImagewithTPW = NCEP_TPW.addBand(image)\n", + "or\n", + "collectionwithPTW = ImageCollection.map(NCEP_TPW.addBand)\n", + "\n", + "'INPUTS':\n", + " '- image': \n", + " image for which to interpolate the TPW data\n", + " needs the 'system:time_start' image property\n", + "'OUTPUTS':\n", + " - \n", + " 'the input image with 3 new bands':\n", + " 'TPW': total precipitable water values\n", + " 'TPWpos': index for the LUT of SMW algorithm coefficients\n", + "\n", + " '10.12.2020': typo correction in the tpw inperpolation expression\n", + " (thanks to Jiacheng Zhao for reporting this issue)\n", + "#\n", + "\n", + "def exports.addBand(image):\n", + "\n", + " # first select the day of interest\n", + " date = ee.Date(image.get('system:time_start'))\n", + " year = ee.Number.parse(date.format('yyyy'))\n", + " month = ee.Number.parse(date.format('MM'))\n", + " day = ee.Number.parse(date.format('dd'))\n", + " date1 = ee.Date.fromYMD(year,month,day)\n", + " date2 = date1.advance(1,'days')\n", + "\n", + " # function compute the time difference from landsat image\n", + " def datedist(image):\n", + " return image.set('DateDist',\n", + " ee.Number(image.get('system:time_start')) \\\n", + " .subtract(date.millis()).abs())\n", + " \n", + "\n", + " # load atmospheric data collection\n", + " TPWcollection = ee.ImageCollection('NCEP_RE/surface_wv') \\\n", + " .filter(ee.Filter.date(date1.format('yyyy-MM-dd'), date2.format('yyyy-MM-dd'))) \\\n", + " .map(datedist)\n", + "\n", + " # select the two closest model times\n", + " closest = (TPWcollection.sort('DateDist')).toList(2)\n", + "\n", + " # check if there is atmospheric data in the wanted day\n", + " # if not creates a TPW image with non-realistic values\n", + " # these are then masked in the SMWalgorithm function (prevents errors)\n", + " tpw1 = ee.Image(ee.Algorithms.If(closest.size().eq(0), ee.Image.constant(-999.0),\n", + " ee.Image(closest.get(0)).select('pr_wtr') ))\n", + " tpw2 = ee.Image(ee.Algorithms.If(closest.size().eq(0), ee.Image.constant(-999.0),\n", + " ee.Algorithms.If(closest.size().eq(1), tpw1,\n", + " ee.Image(closest.get(1)).select('pr_wtr') )))\n", + "\n", + " time1 = ee.Number(ee.Algorithms.If(closest.size().eq(0), 1.0,\n", + " ee.Number(tpw1.get('DateDist')).divide(ee.Number(21600000)) ))\n", + " time2 = ee.Number(ee.Algorithms.If(closest.size().lt(2), 0.0,\n", + " ee.Number(tpw2.get('DateDist')).divide(ee.Number(21600000)) ))\n", + "\n", + " tpw = tpw1.expression('tpw1*time2+tpw2*time1',\n", + " {'tpw1':tpw1,\n", + " 'time1':time1,\n", + " 'tpw2':tpw2,\n", + " 'time2':time2\n", + " }).clip(image.geometry())\n", + "\n", + " # SMW coefficients are binned by TPW values\n", + " # find the bin of each TPW value\n", + " pos = tpw.expression(\n", + " \"value = (TPW>0 && TPW<=6) ? 0\" + \\\n", + " \": (TPW>6 && TPW<=12) ? 1\" + \\\n", + " \": (TPW>12 && TPW<=18) ? 2\" + \\\n", + " \": (TPW>18 && TPW<=24) ? 3\" + \\\n", + " \": (TPW>24 && TPW<=30) ? 4\" + \\\n", + " \": (TPW>30 && TPW<=36) ? 5\" + \\\n", + " \": (TPW>36 && TPW<=42) ? 6\" + \\\n", + " \": (TPW>42 && TPW<=48) ? 7\" + \\\n", + " \": (TPW>48 && TPW<=54) ? 8\" + \\\n", + " \": (TPW>54) ? 9\" + \\\n", + " \": 0\",{'TPW': tpw}) \\\n", + " .clip(image.geometry())\n", + "\n", + " # add tpw to image as a band\n", + " withTPW = (image.addBands(tpw.rename('TPW'),['TPW'])).addBands(pos.rename('TPWpos'),['TPWpos'])\n", + "\n", + " return withTPW\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/NCEP_TPW.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/NCEP_TPW.js new file mode 100644 index 0000000..2e717c6 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/NCEP_TPW.js @@ -0,0 +1,103 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +in any publications derived from them: +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471 + +this function matches the atmospheric water vapour data +from NCEP reanalysis to each Landsat image +tpw values are interpolated from the 6-hourly model times to the image time + +to call this function use: + +var NCEP_TPW = require('users/sofiaermida/landsat_smw_lst:modules/NCEP_TPW.js') +var ImagewithTPW = NCEP_TPW.addBand(image) +or +var collectionwithPTW = ImageCollection.map(NCEP_TPW.addBand) + +INPUTS: + - image: + image for which to interpolate the TPW data + needs the 'system:time_start' image property +OUTPUTS: + - + the input image with 3 new bands: + 'TPW': total precipitable water values + 'TPWpos': index for the LUT of SMW algorithm coefficients + + 10.12.2020: typo correction in the tpw inperpolation expression + (thanks to Jiacheng Zhao for reporting this issue) +*/ + +exports.addBand = function(image){ + + // first select the day of interest + var date = ee.Date(image.get('system:time_start')) + var year = ee.Number.parse(date.format('yyyy')) + var month = ee.Number.parse(date.format('MM')) + var day = ee.Number.parse(date.format('dd')) + var date1 = ee.Date.fromYMD(year,month,day) + var date2 = date1.advance(1,'days') + + // function compute the time difference from landsat image + var datedist = function(image){ + return image.set('DateDist', + ee.Number(image.get('system:time_start')) + .subtract(date.millis()).abs()) + }; + + // load atmospheric data collection + var TPWcollection = ee.ImageCollection('NCEP_RE/surface_wv') + .filter(ee.Filter.date(date1.format('yyyy-MM-dd'), date2.format('yyyy-MM-dd'))) + .map(datedist) + + // select the two closest model times + var closest = (TPWcollection.sort('DateDist')).toList(2); + + // check if there is atmospheric data in the wanted day + // if not creates a TPW image with non-realistic values + // these are then masked in the SMWalgorithm function (prevents errors) + var tpw1 = ee.Image(ee.Algorithms.If(closest.size().eq(0), ee.Image.constant(-999.0), + ee.Image(closest.get(0)).select('pr_wtr') )); + var tpw2 = ee.Image(ee.Algorithms.If(closest.size().eq(0), ee.Image.constant(-999.0), + ee.Algorithms.If(closest.size().eq(1), tpw1, + ee.Image(closest.get(1)).select('pr_wtr') ))); + + var time1 = ee.Number(ee.Algorithms.If(closest.size().eq(0), 1.0, + ee.Number(tpw1.get('DateDist')).divide(ee.Number(21600000)) )); + var time2 = ee.Number(ee.Algorithms.If(closest.size().lt(2), 0.0, + ee.Number(tpw2.get('DateDist')).divide(ee.Number(21600000)) )); + + var tpw = tpw1.expression('tpw1*time2+tpw2*time1', + {'tpw1':tpw1, + 'time1':time1, + 'tpw2':tpw2, + 'time2':time2 + }).clip(image.geometry()); + + // SMW coefficients are binned by TPW values + // find the bin of each TPW value + var pos = tpw.expression( + "value = (TPW>0 && TPW<=6) ? 0" + + ": (TPW>6 && TPW<=12) ? 1" + + ": (TPW>12 && TPW<=18) ? 2" + + ": (TPW>18 && TPW<=24) ? 3" + + ": (TPW>24 && TPW<=30) ? 4" + + ": (TPW>30 && TPW<=36) ? 5" + + ": (TPW>36 && TPW<=42) ? 6" + + ": (TPW>42 && TPW<=48) ? 7" + + ": (TPW>48 && TPW<=54) ? 8" + + ": (TPW>54) ? 9" + + ": 0",{'TPW': tpw}) + .clip(image.geometry()); + + // add tpw to image as a band + var withTPW = (image.addBands(tpw.rename('TPW'),['TPW'])).addBands(pos.rename('TPWpos'),['TPWpos']); + + return withTPW +}; \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/NCEP_TPW.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/NCEP_TPW.py new file mode 100644 index 0000000..a81783a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/NCEP_TPW.py @@ -0,0 +1,109 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +'in any publications derived from them': +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471 + +this function matches the atmospheric water vapour data +from NCEP reanalysis to each Landsat image +tpw values are interpolated from the 6-hourly model times to the image time + +'to call this function use': + +NCEP_TPW = require('users/sofiaermida/landsat_smw_lst:modules/NCEP_TPW.js') +ImagewithTPW = NCEP_TPW.addBand(image) +or +collectionwithPTW = ImageCollection.map(NCEP_TPW.addBand) + +'INPUTS': + '- image': + image for which to interpolate the TPW data + needs the 'system:time_start' image property +'OUTPUTS': + - + 'the input image with 3 new bands': + 'TPW': total precipitable water values + 'TPWpos': index for the LUT of SMW algorithm coefficients + + '10.12.2020': typo correction in the tpw inperpolation expression + (thanks to Jiacheng Zhao for reporting this issue) +# + +def exports.addBand(image): + + # first select the day of interest + date = ee.Date(image.get('system:time_start')) + year = ee.Number.parse(date.format('yyyy')) + month = ee.Number.parse(date.format('MM')) + day = ee.Number.parse(date.format('dd')) + date1 = ee.Date.fromYMD(year,month,day) + date2 = date1.advance(1,'days') + + # function compute the time difference from landsat image + def datedist(image): + return image.set('DateDist', + ee.Number(image.get('system:time_start')) \ + .subtract(date.millis()).abs()) + + + # load atmospheric data collection + TPWcollection = ee.ImageCollection('NCEP_RE/surface_wv') \ + .filter(ee.Filter.date(date1.format('yyyy-MM-dd'), date2.format('yyyy-MM-dd'))) \ + .map(datedist) + + # select the two closest model times + closest = (TPWcollection.sort('DateDist')).toList(2) + + # check if there is atmospheric data in the wanted day + # if not creates a TPW image with non-realistic values + # these are then masked in the SMWalgorithm function (prevents errors) + tpw1 = ee.Image(ee.Algorithms.If(closest.size().eq(0), ee.Image.constant(-999.0), + ee.Image(closest.get(0)).select('pr_wtr') )) + tpw2 = ee.Image(ee.Algorithms.If(closest.size().eq(0), ee.Image.constant(-999.0), + ee.Algorithms.If(closest.size().eq(1), tpw1, + ee.Image(closest.get(1)).select('pr_wtr') ))) + + time1 = ee.Number(ee.Algorithms.If(closest.size().eq(0), 1.0, + ee.Number(tpw1.get('DateDist')).divide(ee.Number(21600000)) )) + time2 = ee.Number(ee.Algorithms.If(closest.size().lt(2), 0.0, + ee.Number(tpw2.get('DateDist')).divide(ee.Number(21600000)) )) + + tpw = tpw1.expression('tpw1*time2+tpw2*time1', + {'tpw1':tpw1, + 'time1':time1, + 'tpw2':tpw2, + 'time2':time2 + }).clip(image.geometry()) + + # SMW coefficients are binned by TPW values + # find the bin of each TPW value + pos = tpw.expression( + "value = (TPW>0 && TPW<=6) ? 0" + \ + ": (TPW>6 && TPW<=12) ? 1" + \ + ": (TPW>12 && TPW<=18) ? 2" + \ + ": (TPW>18 && TPW<=24) ? 3" + \ + ": (TPW>24 && TPW<=30) ? 4" + \ + ": (TPW>30 && TPW<=36) ? 5" + \ + ": (TPW>36 && TPW<=42) ? 6" + \ + ": (TPW>42 && TPW<=48) ? 7" + \ + ": (TPW>48 && TPW<=54) ? 8" + \ + ": (TPW>54) ? 9" + \ + ": 0",{'TPW': tpw}) \ + .clip(image.geometry()) + + # add tpw to image as a band + withTPW = (image.addBands(tpw.rename('TPW'),['TPW'])).addBands(pos.rename('TPWpos'),['TPWpos']) + + return withTPW + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMW_coefficients.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMW_coefficients.ipynb new file mode 100644 index 0000000..901e714 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMW_coefficients.ipynb @@ -0,0 +1,156 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "This code is free and open.\n", + "By using this code and any data derived with it,\n", + "you agree to cite the following reference\n", + "'in any publications derived from them':\n", + "Ermida, S.L., Soares, P., Mantas, V., G\u00f6ttsche, F.-M., Trigo, I.F., 2020.\n", + " Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.\n", + " 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471\n", + "#\n", + "# coefficients for the Statistical Mono-Window Algorithm\n", + "exports.coeff_SMW_L4 = ee.FeatureCollection([\n", + " ee.Feature(None, {'TPWpos': 0, 'A': 0.9755, 'B': -205.2767, 'C': 212.0051}),\n", + " ee.Feature(None, {'TPWpos': 1, 'A': 1.0155, 'B': -233.8902, 'C': 230.4049}),\n", + " ee.Feature(None, {'TPWpos': 2, 'A': 1.0672, 'B': -257.1884, 'C': 239.3072}),\n", + " ee.Feature(None, {'TPWpos': 3, 'A': 1.1499, 'B': -286.2166, 'C': 244.8497}),\n", + " ee.Feature(None, {'TPWpos': 4, 'A': 1.2277, 'B': -316.7643, 'C': 253.0033}),\n", + " ee.Feature(None, {'TPWpos': 5, 'A': 1.3649, 'B': -361.8276, 'C': 258.5471}),\n", + " ee.Feature(None, {'TPWpos': 6, 'A': 1.5085, 'B': -410.1157, 'C': 265.1131}),\n", + " ee.Feature(None, {'TPWpos': 7, 'A': 1.7045, 'B': -472.4909, 'C': 270.7000}),\n", + " ee.Feature(None, {'TPWpos': 8, 'A': 1.5886, 'B': -442.9489, 'C': 277.1511}),\n", + " ee.Feature(None, {'TPWpos': 9, 'A': 2.0215, 'B': -571.8563, 'C': 279.9854})\n", + "])\n", + "\n", + "exports.coeff_SMW_L5 = ee.FeatureCollection([\n", + " ee.Feature(None, {'TPWpos': 0, 'A': 0.9765, 'B': -204.6584, 'C': 211.1321}),\n", + " ee.Feature(None, {'TPWpos': 1, 'A': 1.0229, 'B': -235.5384, 'C': 230.0619}),\n", + " ee.Feature(None, {'TPWpos': 2, 'A': 1.0817, 'B': -261.3886, 'C': 239.5256}),\n", + " ee.Feature(None, {'TPWpos': 3, 'A': 1.1738, 'B': -293.6128, 'C': 245.6042}),\n", + " ee.Feature(None, {'TPWpos': 4, 'A': 1.2605, 'B': -327.1417, 'C': 254.2301}),\n", + " ee.Feature(None, {'TPWpos': 5, 'A': 1.4166, 'B': -377.7741, 'C': 259.9711}),\n", + " ee.Feature(None, {'TPWpos': 6, 'A': 1.5727, 'B': -430.0388, 'C': 266.9520}),\n", + " ee.Feature(None, {'TPWpos': 7, 'A': 1.7879, 'B': -498.1947, 'C': 272.8413}),\n", + " ee.Feature(None, {'TPWpos': 8, 'A': 1.6347, 'B': -457.8183, 'C': 279.6160}),\n", + " ee.Feature(None, {'TPWpos': 9, 'A': 2.1168, 'B': -600.7079, 'C': 282.4583})\n", + "])\n", + "\n", + "exports.coeff_SMW_L7 = ee.FeatureCollection([\n", + " ee.Feature(None, {'TPWpos': 0, 'A': 0.9764, 'B': -205.3511, 'C': 211.8507}),\n", + " ee.Feature(None, {'TPWpos': 1, 'A': 1.0201, 'B': -235.2416, 'C': 230.5468}),\n", + " ee.Feature(None, {'TPWpos': 2, 'A': 1.0750, 'B': -259.6560, 'C': 239.6619}),\n", + " ee.Feature(None, {'TPWpos': 3, 'A': 1.1612, 'B': -289.8190, 'C': 245.3286}),\n", + " ee.Feature(None, {'TPWpos': 4, 'A': 1.2425, 'B': -321.4658, 'C': 253.6144}),\n", + " ee.Feature(None, {'TPWpos': 5, 'A': 1.3864, 'B': -368.4078, 'C': 259.1390}),\n", + " ee.Feature(None, {'TPWpos': 6, 'A': 1.5336, 'B': -417.7796, 'C': 265.7486}),\n", + " ee.Feature(None, {'TPWpos': 7, 'A': 1.7345, 'B': -481.5714, 'C': 271.3659}),\n", + " ee.Feature(None, {'TPWpos': 8, 'A': 1.6066, 'B': -448.5071, 'C': 277.9058}),\n", + " ee.Feature(None, {'TPWpos': 9, 'A': 2.0533, 'B': -581.2619, 'C': 280.6800})\n", + "])\n", + "\n", + "exports.coeff_SMW_L8 = ee.FeatureCollection([\n", + " ee.Feature(None, {'TPWpos': 0, 'A': 0.9751, 'B': -205.8929, 'C': 212.7173}),\n", + " ee.Feature(None, {'TPWpos': 1, 'A': 1.0090, 'B': -232.2750, 'C': 230.5698}),\n", + " ee.Feature(None, {'TPWpos': 2, 'A': 1.0541, 'B': -253.1943, 'C': 238.9548}),\n", + " ee.Feature(None, {'TPWpos': 3, 'A': 1.1282, 'B': -279.4212, 'C': 244.0772}),\n", + " ee.Feature(None, {'TPWpos': 4, 'A': 1.1987, 'B': -307.4497, 'C': 251.8341}),\n", + " ee.Feature(None, {'TPWpos': 5, 'A': 1.3205, 'B': -348.0228, 'C': 257.2740}),\n", + " ee.Feature(None, {'TPWpos': 6, 'A': 1.4540, 'B': -393.1718, 'C': 263.5599}),\n", + " ee.Feature(None, {'TPWpos': 7, 'A': 1.6350, 'B': -451.0790, 'C': 268.9405}),\n", + " ee.Feature(None, {'TPWpos': 8, 'A': 1.5468, 'B': -429.5095, 'C': 275.0895}),\n", + " ee.Feature(None, {'TPWpos': 9, 'A': 1.9403, 'B': -547.2681, 'C': 277.9953})\n", + "])" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMW_coefficients.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMW_coefficients.js new file mode 100644 index 0000000..90597c8 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMW_coefficients.js @@ -0,0 +1,63 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +in any publications derived from them: +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471 +*/ +// coefficients for the Statistical Mono-Window Algorithm +exports.coeff_SMW_L4 = ee.FeatureCollection([ + ee.Feature(null, {'TPWpos': 0, 'A': 0.9755, 'B': -205.2767, 'C': 212.0051}), + ee.Feature(null, {'TPWpos': 1, 'A': 1.0155, 'B': -233.8902, 'C': 230.4049}), + ee.Feature(null, {'TPWpos': 2, 'A': 1.0672, 'B': -257.1884, 'C': 239.3072}), + ee.Feature(null, {'TPWpos': 3, 'A': 1.1499, 'B': -286.2166, 'C': 244.8497}), + ee.Feature(null, {'TPWpos': 4, 'A': 1.2277, 'B': -316.7643, 'C': 253.0033}), + ee.Feature(null, {'TPWpos': 5, 'A': 1.3649, 'B': -361.8276, 'C': 258.5471}), + ee.Feature(null, {'TPWpos': 6, 'A': 1.5085, 'B': -410.1157, 'C': 265.1131}), + ee.Feature(null, {'TPWpos': 7, 'A': 1.7045, 'B': -472.4909, 'C': 270.7000}), + ee.Feature(null, {'TPWpos': 8, 'A': 1.5886, 'B': -442.9489, 'C': 277.1511}), + ee.Feature(null, {'TPWpos': 9, 'A': 2.0215, 'B': -571.8563, 'C': 279.9854}) +]); + +exports.coeff_SMW_L5 = ee.FeatureCollection([ + ee.Feature(null, {'TPWpos': 0, 'A': 0.9765, 'B': -204.6584, 'C': 211.1321}), + ee.Feature(null, {'TPWpos': 1, 'A': 1.0229, 'B': -235.5384, 'C': 230.0619}), + ee.Feature(null, {'TPWpos': 2, 'A': 1.0817, 'B': -261.3886, 'C': 239.5256}), + ee.Feature(null, {'TPWpos': 3, 'A': 1.1738, 'B': -293.6128, 'C': 245.6042}), + ee.Feature(null, {'TPWpos': 4, 'A': 1.2605, 'B': -327.1417, 'C': 254.2301}), + ee.Feature(null, {'TPWpos': 5, 'A': 1.4166, 'B': -377.7741, 'C': 259.9711}), + ee.Feature(null, {'TPWpos': 6, 'A': 1.5727, 'B': -430.0388, 'C': 266.9520}), + ee.Feature(null, {'TPWpos': 7, 'A': 1.7879, 'B': -498.1947, 'C': 272.8413}), + ee.Feature(null, {'TPWpos': 8, 'A': 1.6347, 'B': -457.8183, 'C': 279.6160}), + ee.Feature(null, {'TPWpos': 9, 'A': 2.1168, 'B': -600.7079, 'C': 282.4583}) +]); + +exports.coeff_SMW_L7 = ee.FeatureCollection([ + ee.Feature(null, {'TPWpos': 0, 'A': 0.9764, 'B': -205.3511, 'C': 211.8507}), + ee.Feature(null, {'TPWpos': 1, 'A': 1.0201, 'B': -235.2416, 'C': 230.5468}), + ee.Feature(null, {'TPWpos': 2, 'A': 1.0750, 'B': -259.6560, 'C': 239.6619}), + ee.Feature(null, {'TPWpos': 3, 'A': 1.1612, 'B': -289.8190, 'C': 245.3286}), + ee.Feature(null, {'TPWpos': 4, 'A': 1.2425, 'B': -321.4658, 'C': 253.6144}), + ee.Feature(null, {'TPWpos': 5, 'A': 1.3864, 'B': -368.4078, 'C': 259.1390}), + ee.Feature(null, {'TPWpos': 6, 'A': 1.5336, 'B': -417.7796, 'C': 265.7486}), + ee.Feature(null, {'TPWpos': 7, 'A': 1.7345, 'B': -481.5714, 'C': 271.3659}), + ee.Feature(null, {'TPWpos': 8, 'A': 1.6066, 'B': -448.5071, 'C': 277.9058}), + ee.Feature(null, {'TPWpos': 9, 'A': 2.0533, 'B': -581.2619, 'C': 280.6800}) +]); + +exports.coeff_SMW_L8 = ee.FeatureCollection([ + ee.Feature(null, {'TPWpos': 0, 'A': 0.9751, 'B': -205.8929, 'C': 212.7173}), + ee.Feature(null, {'TPWpos': 1, 'A': 1.0090, 'B': -232.2750, 'C': 230.5698}), + ee.Feature(null, {'TPWpos': 2, 'A': 1.0541, 'B': -253.1943, 'C': 238.9548}), + ee.Feature(null, {'TPWpos': 3, 'A': 1.1282, 'B': -279.4212, 'C': 244.0772}), + ee.Feature(null, {'TPWpos': 4, 'A': 1.1987, 'B': -307.4497, 'C': 251.8341}), + ee.Feature(null, {'TPWpos': 5, 'A': 1.3205, 'B': -348.0228, 'C': 257.2740}), + ee.Feature(null, {'TPWpos': 6, 'A': 1.4540, 'B': -393.1718, 'C': 263.5599}), + ee.Feature(null, {'TPWpos': 7, 'A': 1.6350, 'B': -451.0790, 'C': 268.9405}), + ee.Feature(null, {'TPWpos': 8, 'A': 1.5468, 'B': -429.5095, 'C': 275.0895}), + ee.Feature(null, {'TPWpos': 9, 'A': 1.9403, 'B': -547.2681, 'C': 277.9953}) +]); \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMW_coefficients.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMW_coefficients.py new file mode 100644 index 0000000..f2157e9 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMW_coefficients.py @@ -0,0 +1,69 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +'in any publications derived from them': +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471 +# +# coefficients for the Statistical Mono-Window Algorithm +exports.coeff_SMW_L4 = ee.FeatureCollection([ + ee.Feature(None, {'TPWpos': 0, 'A': 0.9755, 'B': -205.2767, 'C': 212.0051}), + ee.Feature(None, {'TPWpos': 1, 'A': 1.0155, 'B': -233.8902, 'C': 230.4049}), + ee.Feature(None, {'TPWpos': 2, 'A': 1.0672, 'B': -257.1884, 'C': 239.3072}), + ee.Feature(None, {'TPWpos': 3, 'A': 1.1499, 'B': -286.2166, 'C': 244.8497}), + ee.Feature(None, {'TPWpos': 4, 'A': 1.2277, 'B': -316.7643, 'C': 253.0033}), + ee.Feature(None, {'TPWpos': 5, 'A': 1.3649, 'B': -361.8276, 'C': 258.5471}), + ee.Feature(None, {'TPWpos': 6, 'A': 1.5085, 'B': -410.1157, 'C': 265.1131}), + ee.Feature(None, {'TPWpos': 7, 'A': 1.7045, 'B': -472.4909, 'C': 270.7000}), + ee.Feature(None, {'TPWpos': 8, 'A': 1.5886, 'B': -442.9489, 'C': 277.1511}), + ee.Feature(None, {'TPWpos': 9, 'A': 2.0215, 'B': -571.8563, 'C': 279.9854}) +]) + +exports.coeff_SMW_L5 = ee.FeatureCollection([ + ee.Feature(None, {'TPWpos': 0, 'A': 0.9765, 'B': -204.6584, 'C': 211.1321}), + ee.Feature(None, {'TPWpos': 1, 'A': 1.0229, 'B': -235.5384, 'C': 230.0619}), + ee.Feature(None, {'TPWpos': 2, 'A': 1.0817, 'B': -261.3886, 'C': 239.5256}), + ee.Feature(None, {'TPWpos': 3, 'A': 1.1738, 'B': -293.6128, 'C': 245.6042}), + ee.Feature(None, {'TPWpos': 4, 'A': 1.2605, 'B': -327.1417, 'C': 254.2301}), + ee.Feature(None, {'TPWpos': 5, 'A': 1.4166, 'B': -377.7741, 'C': 259.9711}), + ee.Feature(None, {'TPWpos': 6, 'A': 1.5727, 'B': -430.0388, 'C': 266.9520}), + ee.Feature(None, {'TPWpos': 7, 'A': 1.7879, 'B': -498.1947, 'C': 272.8413}), + ee.Feature(None, {'TPWpos': 8, 'A': 1.6347, 'B': -457.8183, 'C': 279.6160}), + ee.Feature(None, {'TPWpos': 9, 'A': 2.1168, 'B': -600.7079, 'C': 282.4583}) +]) + +exports.coeff_SMW_L7 = ee.FeatureCollection([ + ee.Feature(None, {'TPWpos': 0, 'A': 0.9764, 'B': -205.3511, 'C': 211.8507}), + ee.Feature(None, {'TPWpos': 1, 'A': 1.0201, 'B': -235.2416, 'C': 230.5468}), + ee.Feature(None, {'TPWpos': 2, 'A': 1.0750, 'B': -259.6560, 'C': 239.6619}), + ee.Feature(None, {'TPWpos': 3, 'A': 1.1612, 'B': -289.8190, 'C': 245.3286}), + ee.Feature(None, {'TPWpos': 4, 'A': 1.2425, 'B': -321.4658, 'C': 253.6144}), + ee.Feature(None, {'TPWpos': 5, 'A': 1.3864, 'B': -368.4078, 'C': 259.1390}), + ee.Feature(None, {'TPWpos': 6, 'A': 1.5336, 'B': -417.7796, 'C': 265.7486}), + ee.Feature(None, {'TPWpos': 7, 'A': 1.7345, 'B': -481.5714, 'C': 271.3659}), + ee.Feature(None, {'TPWpos': 8, 'A': 1.6066, 'B': -448.5071, 'C': 277.9058}), + ee.Feature(None, {'TPWpos': 9, 'A': 2.0533, 'B': -581.2619, 'C': 280.6800}) +]) + +exports.coeff_SMW_L8 = ee.FeatureCollection([ + ee.Feature(None, {'TPWpos': 0, 'A': 0.9751, 'B': -205.8929, 'C': 212.7173}), + ee.Feature(None, {'TPWpos': 1, 'A': 1.0090, 'B': -232.2750, 'C': 230.5698}), + ee.Feature(None, {'TPWpos': 2, 'A': 1.0541, 'B': -253.1943, 'C': 238.9548}), + ee.Feature(None, {'TPWpos': 3, 'A': 1.1282, 'B': -279.4212, 'C': 244.0772}), + ee.Feature(None, {'TPWpos': 4, 'A': 1.1987, 'B': -307.4497, 'C': 251.8341}), + ee.Feature(None, {'TPWpos': 5, 'A': 1.3205, 'B': -348.0228, 'C': 257.2740}), + ee.Feature(None, {'TPWpos': 6, 'A': 1.4540, 'B': -393.1718, 'C': 263.5599}), + ee.Feature(None, {'TPWpos': 7, 'A': 1.6350, 'B': -451.0790, 'C': 268.9405}), + ee.Feature(None, {'TPWpos': 8, 'A': 1.5468, 'B': -429.5095, 'C': 275.0895}), + ee.Feature(None, {'TPWpos': 9, 'A': 1.9403, 'B': -547.2681, 'C': 277.9953}) +]) +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMWalgorithm.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMWalgorithm.ipynb new file mode 100644 index 0000000..97240e0 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMWalgorithm.ipynb @@ -0,0 +1,179 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "This code is free and open.\n", + "By using this code and any data derived with it,\n", + "you agree to cite the following reference\n", + "'in any publications derived from them':\n", + "Ermida, S.L., Soares, P., Mantas, V., G\u00f6ttsche, F.-M., Trigo, I.F., 2020.\n", + " Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.\n", + " 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471\n", + "\n", + "This function applies the Stastical Mono-Window algorithm to compute the LST\n", + "\n", + "'to call this function use':\n", + "\n", + "LSTfun = require('users/sofiaermida/landsat_smw_lst:modules/SMWalgorithm.js')\n", + "ImagewithLST = LSTfun.addBand(landsat)(image)\n", + "or\n", + "collectionwithLST = ImageCollection.map(LSTfun.addBand(landsat))\n", + "\n", + "'USES':\n", + " - SMW_coefficients.js\n", + "\n", + "'INPUTS':\n", + " '- landsat': \n", + " the Landsat satellite id\n", + " 'valid inputs': 'L4', 'L5', 'L7' and 'L8'\n", + " '- image': \n", + " image for which to calculate the LSTy\n", + "'OUTPUTS':\n", + " - \n", + " 'the input image with 1 new band':\n", + " 'LST': land surface temperature\n", + "#\n", + "\n", + "\n", + "# coefficients for the Statistical Mono-Window Algorithm\n", + "SMWcoef = require('users/sofiaermida/landsat_smw_lst:modules/SMW_coefficients.js')\n", + "\n", + "# Function to create a lookup between two columns in a\n", + "# feature collection\n", + "def get_lookup_table(fc, prop_1, prop_2):\n", + " reducer = ee.Reducer.toList().repeat(2)\n", + " lookup = fc.reduceColumns(reducer, [prop_1, prop_2])\n", + " return ee.List(lookup.get('list'))\n", + "\n", + "\n", + "\n", + "def exports.addBand(landsat):\n", + "\n", + " def wrap(image):\n", + "\n", + " # Select algorithm coefficients\n", + " coeff_SMW = ee.FeatureCollection(ee.Algorithms.If(landsat==='L4',SMWcoef.coeff_SMW_L4,\n", + " ee.Algorithms.If(landsat==='L5',SMWcoef.coeff_SMW_L5,\n", + " ee.Algorithms.If(landsat==='L7',SMWcoef.coeff_SMW_L7,\n", + " SMWcoef.coeff_SMW_L8))))\n", + "\n", + " # Create lookups for the algorithm coefficients\n", + " A_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'A')\n", + " B_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'B')\n", + " C_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'C')\n", + "\n", + " # Map coefficients to the image using the TPW bin position\n", + " A_img = image.remap(A_lookup.get(0), A_lookup.get(1),0.0,'TPWpos').resample('bilinear')\n", + " B_img = image.remap(B_lookup.get(0), B_lookup.get(1),0.0,'TPWpos').resample('bilinear')\n", + " C_img = image.remap(C_lookup.get(0), C_lookup.get(1),0.0,'TPWpos').resample('bilinear')\n", + "\n", + " # select TIR band\n", + " tir = ee.String(ee.Algorithms.If(landsat==='L8','B10',\n", + " ee.Algorithms.If(landsat==='L7','B6_VCID_1',\n", + " 'B6')))\n", + " # compute the LST\n", + " lst = image.expression(\n", + " 'A*Tb1/em1 + B/em1 + C',\n", + " {'A': A_img,\n", + " 'B': B_img,\n", + " 'C': C_img,\n", + " 'em1': image.select('EM'),\n", + " 'Tb1': image.select(tir)\n", + " }).updateMask(image.select('TPW').lt(0).Not())\n", + "\n", + "\n", + " return image.addBands(lst.rename('LST'))\n", + " \n", + " return wrap\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMWalgorithm.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMWalgorithm.js new file mode 100644 index 0000000..65e28e6 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMWalgorithm.js @@ -0,0 +1,87 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +in any publications derived from them: +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471 + +This function applies the Stastical Mono-Window algorithm to compute the LST + +to call this function use: + +var LSTfun = require('users/sofiaermida/landsat_smw_lst:modules/SMWalgorithm.js') +var ImagewithLST = LSTfun.addBand(landsat)(image) +or +var collectionwithLST = ImageCollection.map(LSTfun.addBand(landsat)) + +USES: + - SMW_coefficients.js + +INPUTS: + - landsat: + the Landsat satellite id + valid inputs: 'L4', 'L5', 'L7' and 'L8' + - image: + image for which to calculate the LSTy +OUTPUTS: + - + the input image with 1 new band: + 'LST': land surface temperature +*/ + + +// coefficients for the Statistical Mono-Window Algorithm +var SMWcoef = require('users/sofiaermida/landsat_smw_lst:modules/SMW_coefficients.js'); + +// Function to create a lookup between two columns in a +// feature collection +var get_lookup_table = function(fc, prop_1, prop_2) { + var reducer = ee.Reducer.toList().repeat(2); + var lookup = fc.reduceColumns(reducer, [prop_1, prop_2]); + return ee.List(lookup.get('list')); +}; + + +exports.addBand = function(landsat){ + + var wrap = function(image){ + + // Select algorithm coefficients + var coeff_SMW = ee.FeatureCollection(ee.Algorithms.If(landsat==='L4',SMWcoef.coeff_SMW_L4, + ee.Algorithms.If(landsat==='L5',SMWcoef.coeff_SMW_L5, + ee.Algorithms.If(landsat==='L7',SMWcoef.coeff_SMW_L7, + SMWcoef.coeff_SMW_L8)))); + + // Create lookups for the algorithm coefficients + var A_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'A'); + var B_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'B'); + var C_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'C'); + + // Map coefficients to the image using the TPW bin position + var A_img = image.remap(A_lookup.get(0), A_lookup.get(1),0.0,'TPWpos').resample('bilinear'); + var B_img = image.remap(B_lookup.get(0), B_lookup.get(1),0.0,'TPWpos').resample('bilinear'); + var C_img = image.remap(C_lookup.get(0), C_lookup.get(1),0.0,'TPWpos').resample('bilinear'); + + // select TIR band + var tir = ee.String(ee.Algorithms.If(landsat==='L8','B10', + ee.Algorithms.If(landsat==='L7','B6_VCID_1', + 'B6'))); + // compute the LST + var lst = image.expression( + 'A*Tb1/em1 + B/em1 + C', + {'A': A_img, + 'B': B_img, + 'C': C_img, + 'em1': image.select('EM'), + 'Tb1': image.select(tir) + }).updateMask(image.select('TPW').lt(0).not()); + + + return image.addBands(lst.rename('LST')) + }; + return wrap +} diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMWalgorithm.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMWalgorithm.py new file mode 100644 index 0000000..b6ccf08 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/SMWalgorithm.py @@ -0,0 +1,93 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +'in any publications derived from them': +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471 + +This function applies the Stastical Mono-Window algorithm to compute the LST + +'to call this function use': + +LSTfun = require('users/sofiaermida/landsat_smw_lst:modules/SMWalgorithm.js') +ImagewithLST = LSTfun.addBand(landsat)(image) +or +collectionwithLST = ImageCollection.map(LSTfun.addBand(landsat)) + +'USES': + - SMW_coefficients.js + +'INPUTS': + '- landsat': + the Landsat satellite id + 'valid inputs': 'L4', 'L5', 'L7' and 'L8' + '- image': + image for which to calculate the LSTy +'OUTPUTS': + - + 'the input image with 1 new band': + 'LST': land surface temperature +# + + +# coefficients for the Statistical Mono-Window Algorithm +SMWcoef = require('users/sofiaermida/landsat_smw_lst:modules/SMW_coefficients.js') + +# Function to create a lookup between two columns in a +# feature collection +def get_lookup_table(fc, prop_1, prop_2): + reducer = ee.Reducer.toList().repeat(2) + lookup = fc.reduceColumns(reducer, [prop_1, prop_2]) + return ee.List(lookup.get('list')) + + + +def exports.addBand(landsat): + + def wrap(image): + + # Select algorithm coefficients + coeff_SMW = ee.FeatureCollection(ee.Algorithms.If(landsat==='L4',SMWcoef.coeff_SMW_L4, + ee.Algorithms.If(landsat==='L5',SMWcoef.coeff_SMW_L5, + ee.Algorithms.If(landsat==='L7',SMWcoef.coeff_SMW_L7, + SMWcoef.coeff_SMW_L8)))) + + # Create lookups for the algorithm coefficients + A_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'A') + B_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'B') + C_lookup = get_lookup_table(coeff_SMW, 'TPWpos', 'C') + + # Map coefficients to the image using the TPW bin position + A_img = image.remap(A_lookup.get(0), A_lookup.get(1),0.0,'TPWpos').resample('bilinear') + B_img = image.remap(B_lookup.get(0), B_lookup.get(1),0.0,'TPWpos').resample('bilinear') + C_img = image.remap(C_lookup.get(0), C_lookup.get(1),0.0,'TPWpos').resample('bilinear') + + # select TIR band + tir = ee.String(ee.Algorithms.If(landsat==='L8','B10', + ee.Algorithms.If(landsat==='L7','B6_VCID_1', + 'B6'))) + # compute the LST + lst = image.expression( + 'A*Tb1/em1 + B/em1 + C', + {'A': A_img, + 'B': B_img, + 'C': C_img, + 'em1': image.select('EM'), + 'Tb1': image.select(tir) + }).updateMask(image.select('TPW').lt(0).Not()) + + + return image.addBands(lst.rename('LST')) + + return wrap + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/broadband_emiss.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/broadband_emiss.ipynb new file mode 100644 index 0000000..03a5d49 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/broadband_emiss.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "This code is free and open.\n", + "By using this code and any data derived with it,\n", + "you agree to cite the following reference\n", + "'in any publications derived from them':\n", + "Ermida, S.L., Soares, P., Mantas, V., G\u00f6ttsche, F.-M., Trigo, I.F., 2020.\n", + " Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.\n", + " 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471\n", + "Malakar, N.K., Hulley, G.C., Hook, S.J., Laraby, K., Cook, M., Schott, J.R., 2018.\n", + " 'An Operational Land Surface Temperature Product for Landsat Thermal Data': Methodology\n", + " and Validation. IEEE Trans. Geosci. Remote Sens. 56, 5717\u20135735.\n", + " 'https':#doi.Org/10.1109/TGRS.2018.2824828\n", + "\n", + "This function computes broad-band emissivity from ASTER GED\n", + "\n", + "'to call this function use':\n", + "\n", + "BBEfun = require('users/sofiaermida/landsat_smw_lst:modules/broadband_emiss.js')\n", + "ImagewithBBE = BBEfun.addBand(dynamic)(image)\n", + "or\n", + "collectionwithBBE = ImageCollection.map(BBEfun.addBand(dynamic))\n", + "\n", + "'USES':\n", + " - ASTER_bare_emiss.js\n", + "\n", + "'INPUTS':\n", + " '- dynamic': \n", + " 'True': use vegetation cover correction\n", + " 'False': use original ASTER GED emissivity\n", + " '- image': \n", + " an image is required to clip the ASTER data\n", + " to the image geometry; using the full ASTER image\n", + " compromises the performance\n", + "'OUTPUTS':\n", + " - \n", + " 'the input image with 1 new band':\n", + " 'BBE': broad-band emissivity\n", + "#\n", + "\n", + "\n", + "\n", + "ASTERGED = require('users/sofiaermida/landsat_smw_lst:modules/ASTER_bare_emiss.js')\n", + "\n", + "def exports.addBand(dynamic):\n", + " def wrap(image):\n", + "\n", + " # get ASTER emissivity\n", + " aster = ee.Image(\"NASA/ASTER_GED/AG100_003\") \\\n", + " .clip(image.geometry())\n", + "\n", + " orig = aster.select('emissivity_band10').multiply(0.001)\n", + " dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{\n", + " 'fvc':image.select('FVC'),\n", + " 'em_bare':ASTERGED.emiss_bare_band10(image)})\n", + " em10 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig))\n", + "\n", + " orig = aster.select('emissivity_band11').multiply(0.001)\n", + " dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{\n", + " 'fvc':image.select('FVC'),\n", + " 'em_bare':ASTERGED.emiss_bare_band11(image)})\n", + " em11 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig))\n", + "\n", + " orig = aster.select('emissivity_band12').multiply(0.001)\n", + " dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{\n", + " 'fvc':image.select('FVC'),\n", + " 'em_bare':ASTERGED.emiss_bare_band12(image)})\n", + " em12 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig))\n", + "\n", + " orig = aster.select('emissivity_band13').multiply(0.001)\n", + " dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{\n", + " 'fvc':image.select('FVC'),\n", + " 'em_bare':ASTERGED.emiss_bare_band13(image)})\n", + " em13 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig))\n", + "\n", + " orig = aster.select('emissivity_band14').multiply(0.001)\n", + " dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{\n", + " 'fvc':image.select('FVC'),\n", + " 'em_bare':ASTERGED.emiss_bare_band14(image)})\n", + " em14 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig))\n", + "\n", + "\n", + " bbe = image.expression('0.128 + 0.014*em10 + 0.145*em11 + 0.241*em12 + 0.467*em13 + 0.004*em14',\n", + " {'em10':em10,'em11':em11,'em12':em12,'em13':em13,'em14':em14})\n", + "\n", + " return image.addBands(bbe.rename('BBE'))\n", + "\n", + " return wrap\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/broadband_emiss.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/broadband_emiss.js new file mode 100644 index 0000000..f805ca5 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/broadband_emiss.js @@ -0,0 +1,90 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +in any publications derived from them: +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471 +Malakar, N.K., Hulley, G.C., Hook, S.J., Laraby, K., Cook, M., Schott, J.R., 2018. + An Operational Land Surface Temperature Product for Landsat Thermal Data: Methodology + and Validation. IEEE Trans. Geosci. Remote Sens. 56, 5717–5735. + https://doi.org/10.1109/TGRS.2018.2824828 + +This function computes broad-band emissivity from ASTER GED + +to call this function use: + +var BBEfun = require('users/sofiaermida/landsat_smw_lst:modules/broadband_emiss.js') +var ImagewithBBE = BBEfun.addBand(dynamic)(image) +or +var collectionwithBBE = ImageCollection.map(BBEfun.addBand(dynamic)) + +USES: + - ASTER_bare_emiss.js + +INPUTS: + - dynamic: + 'true': use vegetation cover correction + 'false': use original ASTER GED emissivity + - image: + an image is required to clip the ASTER data + to the image geometry; using the full ASTER image + compromises the performance +OUTPUTS: + - + the input image with 1 new band: + 'BBE': broad-band emissivity +*/ + + + +var ASTERGED = require('users/sofiaermida/landsat_smw_lst:modules/ASTER_bare_emiss.js') + +exports.addBand = function(dynamic){ + var wrap = function(image){ + + // get ASTER emissivity + var aster = ee.Image("NASA/ASTER_GED/AG100_003") + .clip(image.geometry()); + + var orig = aster.select('emissivity_band10').multiply(0.001); + var dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band10(image)}); + var em10 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)); + + orig = aster.select('emissivity_band11').multiply(0.001); + dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band11(image)}); + var em11 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)); + + orig = aster.select('emissivity_band12').multiply(0.001); + dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band12(image)}); + var em12 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)); + + orig = aster.select('emissivity_band13').multiply(0.001); + dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band13(image)}); + var em13 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)); + + orig = aster.select('emissivity_band14').multiply(0.001); + dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band14(image)}); + var em14 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)); + + + var bbe = image.expression('0.128 + 0.014*em10 + 0.145*em11 + 0.241*em12 + 0.467*em13 + 0.004*em14', + {'em10':em10,'em11':em11,'em12':em12,'em13':em13,'em14':em14}); + + return image.addBands(bbe.rename('BBE')) + } + return wrap +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/broadband_emiss.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/broadband_emiss.py new file mode 100644 index 0000000..bdfd8b5 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/broadband_emiss.py @@ -0,0 +1,96 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +'in any publications derived from them': +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471 +Malakar, N.K., Hulley, G.C., Hook, S.J., Laraby, K., Cook, M., Schott, J.R., 2018. + 'An Operational Land Surface Temperature Product for Landsat Thermal Data': Methodology + and Validation. IEEE Trans. Geosci. Remote Sens. 56, 5717–5735. + 'https':#doi.Org/10.1109/TGRS.2018.2824828 + +This function computes broad-band emissivity from ASTER GED + +'to call this function use': + +BBEfun = require('users/sofiaermida/landsat_smw_lst:modules/broadband_emiss.js') +ImagewithBBE = BBEfun.addBand(dynamic)(image) +or +collectionwithBBE = ImageCollection.map(BBEfun.addBand(dynamic)) + +'USES': + - ASTER_bare_emiss.js + +'INPUTS': + '- dynamic': + 'True': use vegetation cover correction + 'False': use original ASTER GED emissivity + '- image': + an image is required to clip the ASTER data + to the image geometry; using the full ASTER image + compromises the performance +'OUTPUTS': + - + 'the input image with 1 new band': + 'BBE': broad-band emissivity +# + + + +ASTERGED = require('users/sofiaermida/landsat_smw_lst:modules/ASTER_bare_emiss.js') + +def exports.addBand(dynamic): + def wrap(image): + + # get ASTER emissivity + aster = ee.Image("NASA/ASTER_GED/AG100_003") \ + .clip(image.geometry()) + + orig = aster.select('emissivity_band10').multiply(0.001) + dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band10(image)}) + em10 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)) + + orig = aster.select('emissivity_band11').multiply(0.001) + dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band11(image)}) + em11 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)) + + orig = aster.select('emissivity_band12').multiply(0.001) + dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band12(image)}) + em12 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)) + + orig = aster.select('emissivity_band13').multiply(0.001) + dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band13(image)}) + em13 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)) + + orig = aster.select('emissivity_band14').multiply(0.001) + dynam = image.expression('fvc*0.99+(1-fvc)*em_bare',{ + 'fvc':image.select('FVC'), + 'em_bare':ASTERGED.emiss_bare_band14(image)}) + em14 = ee.Image(ee.Algorithms.If(dynamic,dynam,orig)) + + + bbe = image.expression('0.128 + 0.014*em10 + 0.145*em11 + 0.241*em12 + 0.467*em13 + 0.004*em14', + {'em10':em10,'em11':em11,'em12':em12,'em13':em13,'em14':em14}) + + return image.addBands(bbe.rename('BBE')) + + return wrap + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/cloudmask.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/cloudmask.ipynb new file mode 100644 index 0000000..dedf913 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/cloudmask.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "this function mask clouds and cloud shadow using the Quality band\n", + "\n", + "'to call this function use':\n", + "\n", + "cloudmask = require('users/sofiaermida/landsat_smw_lst:modules/cloudmask.js')\n", + "TOAImageMasked = cloudmask.toa(image)\n", + "SRImageMasked = cloudmask.sr(image)\n", + "or\n", + "TOAcollectionMasked = ImageCollection.map(cloudmask.toa)\n", + "SRcollectionMasked = ImageCollection.map(cloudmask.sr)\n", + "\n", + "\n", + "'INPUTS':\n", + " '- image': \n", + " image for which clouds are masked\n", + "'OUTPUTS':\n", + " - \n", + " the input image with updated mask\n", + "\n", + " '11-07-2022': update to use collection 2\n", + "#\n", + "\n", + "# cloudmask for TOA data\n", + "def exports.toa(image):\n", + " qa = image.select('QA_PIXEL')\n", + " mask = qa.bitwiseAnd(1 << 3)\n", + " return image.updateMask(mask.Not())\n", + "\n", + "\n", + "# cloudmask for SR data\n", + "def exports.sr(image):\n", + " qa = image.select('QA_PIXEL')\n", + " mask = qa.bitwiseAnd(1 << 3) \\\n", + " .Or(qa.bitwiseAnd(1 << 4))\n", + " return image.updateMask(mask.Not())\n", + "\n", + "\n", + "# COLLECTION 1\n", + "# cloudmask for TOA data\n", + "def exports.toa(image):\n", + " qa = image.select('BQA')\n", + " mask = qa.bitwiseAnd(1 << 4).eq(0)\n", + " return image.updateMask(mask)\n", + "\n", + "\n", + "# cloudmask for SR data\n", + "def exports.sr(image):\n", + " qa = image.select('pixel_qa')\n", + " mask = qa.bitwiseAnd(1 << 3) \\\n", + " .Or(qa.bitwiseAnd(1 << 5))\n", + " return image.updateMask(mask.Not())\n", + "\n", + "#" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/cloudmask.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/cloudmask.js new file mode 100644 index 0000000..d9c06e1 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/cloudmask.js @@ -0,0 +1,56 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +this function mask clouds and cloud shadow using the Quality band + +to call this function use: + +var cloudmask = require('users/sofiaermida/landsat_smw_lst:modules/cloudmask.js') +var TOAImageMasked = cloudmask.toa(image) +var SRImageMasked = cloudmask.sr(image) +or +var TOAcollectionMasked = ImageCollection.map(cloudmask.toa) +var SRcollectionMasked = ImageCollection.map(cloudmask.sr) + + +INPUTS: + - image: + image for which clouds are masked +OUTPUTS: + - + the input image with updated mask + + 11-07-2022: update to use collection 2 +*/ + +// cloudmask for TOA data +exports.toa = function(image) { + var qa = image.select('QA_PIXEL'); + var mask = qa.bitwiseAnd(1 << 3); + return image.updateMask(mask.not()); +}; + +// cloudmask for SR data +exports.sr = function(image) { + var qa = image.select('QA_PIXEL'); + var mask = qa.bitwiseAnd(1 << 3) + .or(qa.bitwiseAnd(1 << 4)) + return image.updateMask(mask.not()); +}; + +/* COLLECTION 1 +// cloudmask for TOA data +exports.toa = function(image) { + var qa = image.select('BQA'); + var mask = qa.bitwiseAnd(1 << 4).eq(0); + return image.updateMask(mask); +}; + +// cloudmask for SR data +exports.sr = function(image) { + var qa = image.select('pixel_qa'); + var mask = qa.bitwiseAnd(1 << 3) + .or(qa.bitwiseAnd(1 << 5)) + return image.updateMask(mask.not()); +}; +*/ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/cloudmask.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/cloudmask.py new file mode 100644 index 0000000..e6485ff --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/cloudmask.py @@ -0,0 +1,62 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +this function mask clouds and cloud shadow using the Quality band + +'to call this function use': + +cloudmask = require('users/sofiaermida/landsat_smw_lst:modules/cloudmask.js') +TOAImageMasked = cloudmask.toa(image) +SRImageMasked = cloudmask.sr(image) +or +TOAcollectionMasked = ImageCollection.map(cloudmask.toa) +SRcollectionMasked = ImageCollection.map(cloudmask.sr) + + +'INPUTS': + '- image': + image for which clouds are masked +'OUTPUTS': + - + the input image with updated mask + + '11-07-2022': update to use collection 2 +# + +# cloudmask for TOA data +def exports.toa(image): + qa = image.select('QA_PIXEL') + mask = qa.bitwiseAnd(1 << 3) + return image.updateMask(mask.Not()) + + +# cloudmask for SR data +def exports.sr(image): + qa = image.select('QA_PIXEL') + mask = qa.bitwiseAnd(1 << 3) \ + .Or(qa.bitwiseAnd(1 << 4)) + return image.updateMask(mask.Not()) + + +# COLLECTION 1 +# cloudmask for TOA data +def exports.toa(image): + qa = image.select('BQA') + mask = qa.bitwiseAnd(1 << 4).eq(0) + return image.updateMask(mask) + + +# cloudmask for SR data +def exports.sr(image): + qa = image.select('pixel_qa') + mask = qa.bitwiseAnd(1 << 3) \ + .Or(qa.bitwiseAnd(1 << 5)) + return image.updateMask(mask.Not()) + +# +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_FVC.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_FVC.ipynb new file mode 100644 index 0000000..49cff92 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_FVC.ipynb @@ -0,0 +1,142 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "This code is free and open.\n", + "By using this code and any data derived with it,\n", + "you agree to cite the following reference\n", + "'in any publications derived from them':\n", + "Ermida, S.L., Soares, P., Mantas, V., G\u00f6ttsche, F.-M., Trigo, I.F., 2020.\n", + " Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.\n", + " 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471\n", + "\n", + "this function computes the Fraction of Vegetation Cover from NDVI\n", + "the compute_NDVI.js function must be called before this one\n", + "\n", + "'to call this function use':\n", + "\n", + "FVCfun = require('users/sofiaermida/landsat_smw_lst:modules/compute_FVC.js')\n", + "ImagewithFVC = FVCfun.addBand(landsat)(image)\n", + "or\n", + "collectionwithFVC = ImageCollection.map(FVCfun.addBand(landsat))\n", + "\n", + "'USES':\n", + " - SMW_coefficients.js\n", + "\n", + "'INPUTS':\n", + " '- landsat': \n", + " the Landsat satellite id\n", + " 'valid inputs': 'L4', 'L5', 'L7' and 'L8'\n", + " '- image': \n", + " image for which to calculate the FVC\n", + "'OUTPUTS':\n", + " - \n", + " 'the input image with 1 new band':\n", + " 'FVC': fraction of vegetation cover\n", + "#\n", + "def exports.addBand(landsat):\n", + " def wrap(image):\n", + "\n", + " ndvi = image.select('NDVI')\n", + "\n", + " # Compute FVC\n", + " fvc = image.expression('((ndvi-ndvi_bg)/(ndvi_vg - ndvi_bg))**2',\n", + " {'ndvi':ndvi,'ndvi_bg':0.2,'ndvi_vg':0.86})\n", + " fvc = fvc.where(fvc.lt(0.0),0.0)\n", + " fvc = fvc.where(fvc.gt(1.0),1.0)\n", + "\n", + " return image.addBands(fvc.rename('FVC'))\n", + "\n", + " return wrap\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_FVC.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_FVC.js new file mode 100644 index 0000000..ee1e363 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_FVC.js @@ -0,0 +1,50 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +in any publications derived from them: +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471 + +this function computes the Fraction of Vegetation Cover from NDVI +the compute_NDVI.js function must be called before this one + +to call this function use: + +var FVCfun = require('users/sofiaermida/landsat_smw_lst:modules/compute_FVC.js') +var ImagewithFVC = FVCfun.addBand(landsat)(image) +or +var collectionwithFVC = ImageCollection.map(FVCfun.addBand(landsat)) + +USES: + - SMW_coefficients.js + +INPUTS: + - landsat: + the Landsat satellite id + valid inputs: 'L4', 'L5', 'L7' and 'L8' + - image: + image for which to calculate the FVC +OUTPUTS: + - + the input image with 1 new band: + 'FVC': fraction of vegetation cover +*/ +exports.addBand = function(landsat){ + var wrap = function(image){ + + var ndvi = image.select('NDVI') + + // Compute FVC + var fvc = image.expression('((ndvi-ndvi_bg)/(ndvi_vg - ndvi_bg))**2', + {'ndvi':ndvi,'ndvi_bg':0.2,'ndvi_vg':0.86}); + fvc = fvc.where(fvc.lt(0.0),0.0); + fvc = fvc.where(fvc.gt(1.0),1.0); + + return image.addBands(fvc.rename('FVC')); + } + return wrap +}; \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_FVC.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_FVC.py new file mode 100644 index 0000000..45ea466 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_FVC.py @@ -0,0 +1,56 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +'in any publications derived from them': +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471 + +this function computes the Fraction of Vegetation Cover from NDVI +the compute_NDVI.js function must be called before this one + +'to call this function use': + +FVCfun = require('users/sofiaermida/landsat_smw_lst:modules/compute_FVC.js') +ImagewithFVC = FVCfun.addBand(landsat)(image) +or +collectionwithFVC = ImageCollection.map(FVCfun.addBand(landsat)) + +'USES': + - SMW_coefficients.js + +'INPUTS': + '- landsat': + the Landsat satellite id + 'valid inputs': 'L4', 'L5', 'L7' and 'L8' + '- image': + image for which to calculate the FVC +'OUTPUTS': + - + 'the input image with 1 new band': + 'FVC': fraction of vegetation cover +# +def exports.addBand(landsat): + def wrap(image): + + ndvi = image.select('NDVI') + + # Compute FVC + fvc = image.expression('((ndvi-ndvi_bg)/(ndvi_vg - ndvi_bg))**2', + {'ndvi':ndvi,'ndvi_bg':0.2,'ndvi_vg':0.86}) + fvc = fvc.where(fvc.lt(0.0),0.0) + fvc = fvc.where(fvc.gt(1.0),1.0) + + return image.addBands(fvc.rename('FVC')) + + return wrap + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_NDVI.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_NDVI.ipynb new file mode 100644 index 0000000..e85aa52 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_NDVI.ipynb @@ -0,0 +1,153 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "this function computes NDVI values for Landsat\n", + "\n", + "\n", + "'to call this function use':\n", + "\n", + "NDVIfun = require('users/sofiaermida/landsat_smw_lst:modules/compute_NDVI.js')\n", + "ImagewithNDVI = NDVIfun.addBand(landsat)(image)\n", + "or\n", + "collectionwithNDVI = ImageCollection.map(NDVIfun.addBand(landsat))\n", + "\n", + "'INPUTS':\n", + " '- landsat': \n", + " the Landsat satellite id\n", + " 'valid inputs': 'L4', 'L5', 'L7' and 'L8'\n", + " '- image': \n", + " image for which to calculate the NDVI\n", + "'OUTPUTS':\n", + " - \n", + " 'the input image with 1 new band':\n", + " 'NDVI': normalized difference vegetation index\n", + "\n", + " '11-07-2022': update to use Collection 2 Level 2 Surface Reflectance data\n", + "#\n", + "\n", + "def exports.addBand(landsat):\n", + " def wrap(image):\n", + "\n", + " # choose bands\n", + " nir = ee.String(ee.Algorithms.If(landsat==='L8','SR_B5','SR_B4'))\n", + " red = ee.String(ee.Algorithms.If(landsat==='L8','SR_B4','SR_B3'))\n", + "\n", + " # compute NDVI\n", + " return image.addBands(image.expression('(nir-red)/(nir+red)',{\n", + " 'nir':image.select(nir).multiply(0.0000275).add(-0.2),\n", + " 'red':image.select(red).multiply(0.0000275).add(-0.2)\n", + " }).rename('NDVI'))\n", + "\n", + " return wrap\n", + "\n", + "\n", + "# COLLECTION 1\n", + "def exports.addBand(landsat):\n", + " def wrap(image):\n", + "\n", + " # choose bands\n", + " nir = ee.String(ee.Algorithms.If(landsat==='L8','B5','B4'))\n", + " red = ee.String(ee.Algorithms.If(landsat==='L8','B4','B3'))\n", + "\n", + " # compute NDVI\n", + " return image.addBands(image.expression('(nir-red)/(nir+red)',{\n", + " 'nir':image.select(nir).multiply(0.0001),\n", + " 'red':image.select(red).multiply(0.0001)\n", + " }).rename('NDVI'))\n", + "\n", + " return wrap\n", + "\n", + "#" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_NDVI.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_NDVI.js new file mode 100644 index 0000000..6ec8e0b --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_NDVI.js @@ -0,0 +1,60 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +this function computes NDVI values for Landsat + + +to call this function use: + +var NDVIfun = require('users/sofiaermida/landsat_smw_lst:modules/compute_NDVI.js') +var ImagewithNDVI = NDVIfun.addBand(landsat)(image) +or +var collectionwithNDVI = ImageCollection.map(NDVIfun.addBand(landsat)) + +INPUTS: + - landsat: + the Landsat satellite id + valid inputs: 'L4', 'L5', 'L7' and 'L8' + - image: + image for which to calculate the NDVI +OUTPUTS: + - + the input image with 1 new band: + 'NDVI': normalized difference vegetation index + + 11-07-2022: update to use Collection 2 Level 2 Surface Reflectance data +*/ + +exports.addBand = function(landsat){ + var wrap = function(image){ + + // choose bands + var nir = ee.String(ee.Algorithms.If(landsat==='L8','SR_B5','SR_B4')) + var red = ee.String(ee.Algorithms.If(landsat==='L8','SR_B4','SR_B3')) + + // compute NDVI + return image.addBands(image.expression('(nir-red)/(nir+red)',{ + 'nir':image.select(nir).multiply(0.0000275).add(-0.2), + 'red':image.select(red).multiply(0.0000275).add(-0.2) + }).rename('NDVI')) + } + return wrap +}; + +/* COLLECTION 1 +exports.addBand = function(landsat){ + var wrap = function(image){ + + // choose bands + var nir = ee.String(ee.Algorithms.If(landsat==='L8','B5','B4')) + var red = ee.String(ee.Algorithms.If(landsat==='L8','B4','B3')) + + // compute NDVI + return image.addBands(image.expression('(nir-red)/(nir+red)',{ + 'nir':image.select(nir).multiply(0.0001), + 'red':image.select(red).multiply(0.0001) + }).rename('NDVI')) + } + return wrap +}; +*/ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_NDVI.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_NDVI.py new file mode 100644 index 0000000..8ccc456 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_NDVI.py @@ -0,0 +1,66 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +this function computes NDVI values for Landsat + + +'to call this function use': + +NDVIfun = require('users/sofiaermida/landsat_smw_lst:modules/compute_NDVI.js') +ImagewithNDVI = NDVIfun.addBand(landsat)(image) +or +collectionwithNDVI = ImageCollection.map(NDVIfun.addBand(landsat)) + +'INPUTS': + '- landsat': + the Landsat satellite id + 'valid inputs': 'L4', 'L5', 'L7' and 'L8' + '- image': + image for which to calculate the NDVI +'OUTPUTS': + - + 'the input image with 1 new band': + 'NDVI': normalized difference vegetation index + + '11-07-2022': update to use Collection 2 Level 2 Surface Reflectance data +# + +def exports.addBand(landsat): + def wrap(image): + + # choose bands + nir = ee.String(ee.Algorithms.If(landsat==='L8','SR_B5','SR_B4')) + red = ee.String(ee.Algorithms.If(landsat==='L8','SR_B4','SR_B3')) + + # compute NDVI + return image.addBands(image.expression('(nir-red)/(nir+red)',{ + 'nir':image.select(nir).multiply(0.0000275).add(-0.2), + 'red':image.select(red).multiply(0.0000275).add(-0.2) + }).rename('NDVI')) + + return wrap + + +# COLLECTION 1 +def exports.addBand(landsat): + def wrap(image): + + # choose bands + nir = ee.String(ee.Algorithms.If(landsat==='L8','B5','B4')) + red = ee.String(ee.Algorithms.If(landsat==='L8','B4','B3')) + + # compute NDVI + return image.addBands(image.expression('(nir-red)/(nir+red)',{ + 'nir':image.select(nir).multiply(0.0001), + 'red':image.select(red).multiply(0.0001) + }).rename('NDVI')) + + return wrap + +# +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_emissivity.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_emissivity.ipynb new file mode 100644 index 0000000..5794f7c --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_emissivity.ipynb @@ -0,0 +1,199 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#\n", + "'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)\n", + "\n", + "This code is free and open.\n", + "By using this code and any data derived with it,\n", + "you agree to cite the following reference\n", + "'in any publications derived from them':\n", + "Ermida, S.L., Soares, P., Mantas, V., G\u00f6ttsche, F.-M., Trigo, I.F., 2020.\n", + " Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.\n", + " 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471\n", + "\n", + "this function computes surface emissivity for Landsat\n", + "'requires values of FVC': compute_FVC.js\n", + "\n", + "'ref': Malakar, N.K., Hulley, G.C., Hook, S.J., Laraby, K., Cook, M., Schott, J.R., 2018.\n", + " 'An Operational Land Surface Temperature Product for Landsat Thermal Data': Methodology\n", + " and Validation. IEEE Trans. Geosci. Remote Sens. 56, 5717\u20135735.\n", + " 'https':#doi.Org/10.1109/TGRS.2018.2824828\n", + "\n", + "'to call this function use':\n", + "\n", + "EMfun = require('users/sofiaermida/landsat_smw_lst:modules/compute_emissivity.js')\n", + "ImagewithEM = EMfun.addBand(landsat)(image)\n", + "or\n", + "collectionwithEM = ImageCollection.map(EMfun.addBand(landsat))\n", + "\n", + "'USES':\n", + " - ASTER_bare_emiss.js\n", + "\n", + "'INPUTS':\n", + " '- landsat': \n", + " the Landsat satellite id\n", + " 'valid inputs': 'L4', 'L5', 'L7' and 'L8'\n", + " '- use_ndvi': \n", + " if True, NDVI values are used to obtain a\n", + " dynamic emissivity; if False, emissivity is\n", + " obtained directly from ASTER\n", + " '- image': \n", + " image for which to calculate the emissivity\n", + "'OUTPUTS':\n", + " - \n", + " 'the input image with 1 new band':\n", + " 'EM': surface emissivity of TIR band\n", + "\n", + " '11-07-2022': update to prescribe emissivity of snow and water surfaces\n", + "#\n", + "\n", + "ASTERGED = require('users/sofiaermida/landsat_smw_lst:modules/ASTER_bare_emiss.js')\n", + "\n", + "# this function computes the emissivity of the\n", + "# Landsat TIR band using ASTER and FVC\n", + "def exports.addBand(landsat, use_ndvi):\n", + " def wrap(image):\n", + "\n", + " c13 = ee.Number(ee.Algorithms.If(landsat==='L4',0.3222,\n", + " ee.Algorithms.If(landsat==='L5',-0.0723,\n", + " ee.Algorithms.If(landsat==='L7',0.2147,\n", + " 0.6820))))\n", + " c14 = ee.Number(ee.Algorithms.If(landsat==='L4',0.6498,\n", + " ee.Algorithms.If(landsat==='L5',1.0521,\n", + " ee.Algorithms.If(landsat==='L7',0.7789,\n", + " 0.2578))))\n", + " c = ee.Number(ee.Algorithms.If(landsat==='L4',0.0272,\n", + " ee.Algorithms.If(landsat==='L5',0.0195,\n", + " ee.Algorithms.If(landsat==='L7',0.0059,\n", + " 0.0584))))\n", + "\n", + " # get ASTER emissivity\n", + " # convolve to Landsat band\n", + " emiss_bare = image.expression('c13*EM13 + c14*EM14 + c',{\n", + " 'EM13':ASTERGED.emiss_bare_band13(image),\n", + " 'EM14':ASTERGED.emiss_bare_band14(image),\n", + " 'c13':ee.Image(c13),\n", + " 'c14':ee.Image(c14),\n", + " 'c':ee.Image(c)\n", + " })\n", + "\n", + " # compute the dynamic emissivity for Landsat\n", + " EMd = image.expression('fvc*0.99+(1-fvc)*em_bare',\n", + " {'fvc':image.select('FVC'),'em_bare':emiss_bare})\n", + "\n", + " # compute emissivity directly from ASTER\n", + " # without vegetation correction\n", + " # get ASTER emissivity\n", + " aster = ee.Image(\"NASA/ASTER_GED/AG100_003\") \\\n", + " .clip(image.geometry())\n", + " EM0 = image.expression('c13*EM13 + c14*EM14 + c',{\n", + " 'EM13':aster.select('emissivity_band13').multiply(0.001),\n", + " 'EM14':aster.select('emissivity_band14').multiply(0.001),\n", + " 'c13':ee.Image(c13),\n", + " 'c14':ee.Image(c14),\n", + " 'c':ee.Image(c)\n", + " })\n", + "\n", + " # select which emissivity to output based on user selection\n", + " EM = ee.Image(ee.Algorithms.If(use_ndvi,EMd,EM0))\n", + "\n", + " # prescribe emissivity of water bodies\n", + " qa = image.select('QA_PIXEL')\n", + " EM = EM.where(qa.bitwiseAnd(1 << 7),0.99)\n", + " # prescribe emissivity of snow/ice bodies\n", + " EM = EM.where(qa.bitwiseAnd(1 << 5),0.989)\n", + "\n", + " return image.addBands(EM.rename('EM'))\n", + "\n", + " return wrap\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_emissivity.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_emissivity.js new file mode 100644 index 0000000..fcdb4b6 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_emissivity.js @@ -0,0 +1,107 @@ +/* +Author: Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +in any publications derived from them: +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471 + +this function computes surface emissivity for Landsat +requires values of FVC: compute_FVC.js + +ref: Malakar, N.K., Hulley, G.C., Hook, S.J., Laraby, K., Cook, M., Schott, J.R., 2018. + An Operational Land Surface Temperature Product for Landsat Thermal Data: Methodology + and Validation. IEEE Trans. Geosci. Remote Sens. 56, 5717–5735. + https://doi.org/10.1109/TGRS.2018.2824828 + +to call this function use: + +var EMfun = require('users/sofiaermida/landsat_smw_lst:modules/compute_emissivity.js') +var ImagewithEM = EMfun.addBand(landsat)(image) +or +var collectionwithEM = ImageCollection.map(EMfun.addBand(landsat)) + +USES: + - ASTER_bare_emiss.js + +INPUTS: + - landsat: + the Landsat satellite id + valid inputs: 'L4', 'L5', 'L7' and 'L8' + - use_ndvi: + if true, NDVI values are used to obtain a + dynamic emissivity; if false, emissivity is + obtained directly from ASTER + - image: + image for which to calculate the emissivity +OUTPUTS: + - + the input image with 1 new band: + 'EM': surface emissivity of TIR band + + 11-07-2022: update to prescribe emissivity of snow and water surfaces +*/ + +var ASTERGED = require('users/sofiaermida/landsat_smw_lst:modules/ASTER_bare_emiss.js') + +// this function computes the emissivity of the +// Landsat TIR band using ASTER and FVC +exports.addBand = function(landsat, use_ndvi){ + var wrap = function(image){ + + var c13 = ee.Number(ee.Algorithms.If(landsat==='L4',0.3222, + ee.Algorithms.If(landsat==='L5',-0.0723, + ee.Algorithms.If(landsat==='L7',0.2147, + 0.6820)))); + var c14 = ee.Number(ee.Algorithms.If(landsat==='L4',0.6498, + ee.Algorithms.If(landsat==='L5',1.0521, + ee.Algorithms.If(landsat==='L7',0.7789, + 0.2578)))); + var c = ee.Number(ee.Algorithms.If(landsat==='L4',0.0272, + ee.Algorithms.If(landsat==='L5',0.0195, + ee.Algorithms.If(landsat==='L7',0.0059, + 0.0584)))); + + // get ASTER emissivity + // convolve to Landsat band + var emiss_bare = image.expression('c13*EM13 + c14*EM14 + c',{ + 'EM13':ASTERGED.emiss_bare_band13(image), + 'EM14':ASTERGED.emiss_bare_band14(image), + 'c13':ee.Image(c13), + 'c14':ee.Image(c14), + 'c':ee.Image(c) + }); + + // compute the dynamic emissivity for Landsat + var EMd = image.expression('fvc*0.99+(1-fvc)*em_bare', + {'fvc':image.select('FVC'),'em_bare':emiss_bare}); + + // compute emissivity directly from ASTER + // without vegetation correction + // get ASTER emissivity + var aster = ee.Image("NASA/ASTER_GED/AG100_003") + .clip(image.geometry()); + var EM0 = image.expression('c13*EM13 + c14*EM14 + c',{ + 'EM13':aster.select('emissivity_band13').multiply(0.001), + 'EM14':aster.select('emissivity_band14').multiply(0.001), + 'c13':ee.Image(c13), + 'c14':ee.Image(c14), + 'c':ee.Image(c) + }); + + // select which emissivity to output based on user selection + var EM = ee.Image(ee.Algorithms.If(use_ndvi,EMd,EM0)); + + // prescribe emissivity of water bodies + var qa = image.select('QA_PIXEL'); + EM = EM.where(qa.bitwiseAnd(1 << 7),0.99); + // prescribe emissivity of snow/ice bodies + EM = EM.where(qa.bitwiseAnd(1 << 5),0.989); + + return image.addBands(EM.rename('EM')); + } + return wrap +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_emissivity.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_emissivity.py new file mode 100644 index 0000000..b26d0e5 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.5 Heat Islands/modules/compute_emissivity.py @@ -0,0 +1,113 @@ +import ee +import geemap + +Map = geemap.Map() + +# +'Author': Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia) + +This code is free and open. +By using this code and any data derived with it, +you agree to cite the following reference +'in any publications derived from them': +Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020. + Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series. + 'Remote Sensing, 12 (9), 1471; https':#doi.Org/10.3390/rs12091471 + +this function computes surface emissivity for Landsat +'requires values of FVC': compute_FVC.js + +'ref': Malakar, N.K., Hulley, G.C., Hook, S.J., Laraby, K., Cook, M., Schott, J.R., 2018. + 'An Operational Land Surface Temperature Product for Landsat Thermal Data': Methodology + and Validation. IEEE Trans. Geosci. Remote Sens. 56, 5717–5735. + 'https':#doi.Org/10.1109/TGRS.2018.2824828 + +'to call this function use': + +EMfun = require('users/sofiaermida/landsat_smw_lst:modules/compute_emissivity.js') +ImagewithEM = EMfun.addBand(landsat)(image) +or +collectionwithEM = ImageCollection.map(EMfun.addBand(landsat)) + +'USES': + - ASTER_bare_emiss.js + +'INPUTS': + '- landsat': + the Landsat satellite id + 'valid inputs': 'L4', 'L5', 'L7' and 'L8' + '- use_ndvi': + if True, NDVI values are used to obtain a + dynamic emissivity; if False, emissivity is + obtained directly from ASTER + '- image': + image for which to calculate the emissivity +'OUTPUTS': + - + 'the input image with 1 new band': + 'EM': surface emissivity of TIR band + + '11-07-2022': update to prescribe emissivity of snow and water surfaces +# + +ASTERGED = require('users/sofiaermida/landsat_smw_lst:modules/ASTER_bare_emiss.js') + +# this function computes the emissivity of the +# Landsat TIR band using ASTER and FVC +def exports.addBand(landsat, use_ndvi): + def wrap(image): + + c13 = ee.Number(ee.Algorithms.If(landsat==='L4',0.3222, + ee.Algorithms.If(landsat==='L5',-0.0723, + ee.Algorithms.If(landsat==='L7',0.2147, + 0.6820)))) + c14 = ee.Number(ee.Algorithms.If(landsat==='L4',0.6498, + ee.Algorithms.If(landsat==='L5',1.0521, + ee.Algorithms.If(landsat==='L7',0.7789, + 0.2578)))) + c = ee.Number(ee.Algorithms.If(landsat==='L4',0.0272, + ee.Algorithms.If(landsat==='L5',0.0195, + ee.Algorithms.If(landsat==='L7',0.0059, + 0.0584)))) + + # get ASTER emissivity + # convolve to Landsat band + emiss_bare = image.expression('c13*EM13 + c14*EM14 + c',{ + 'EM13':ASTERGED.emiss_bare_band13(image), + 'EM14':ASTERGED.emiss_bare_band14(image), + 'c13':ee.Image(c13), + 'c14':ee.Image(c14), + 'c':ee.Image(c) + }) + + # compute the dynamic emissivity for Landsat + EMd = image.expression('fvc*0.99+(1-fvc)*em_bare', + {'fvc':image.select('FVC'),'em_bare':emiss_bare}) + + # compute emissivity directly from ASTER + # without vegetation correction + # get ASTER emissivity + aster = ee.Image("NASA/ASTER_GED/AG100_003") \ + .clip(image.geometry()) + EM0 = image.expression('c13*EM13 + c14*EM14 + c',{ + 'EM13':aster.select('emissivity_band13').multiply(0.001), + 'EM14':aster.select('emissivity_band14').multiply(0.001), + 'c13':ee.Image(c13), + 'c14':ee.Image(c14), + 'c':ee.Image(c) + }) + + # select which emissivity to output based on user selection + EM = ee.Image(ee.Algorithms.If(use_ndvi,EMd,EM0)) + + # prescribe emissivity of water bodies + qa = image.select('QA_PIXEL') + EM = EM.where(qa.bitwiseAnd(1 << 7),0.99) + # prescribe emissivity of snow/ice bodies + EM = EM.where(qa.bitwiseAnd(1 << 5),0.989) + + return image.addBands(EM.rename('EM')) + + return wrap + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16a Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16a Checkpoint.ipynb new file mode 100644 index 0000000..4bd2dff --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16a Checkpoint.ipynb @@ -0,0 +1,128 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.6 Health Applications\n", + "# Checkpoint: A16a\n", + "# Author: Dawn Nekorchuk\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1: Data Import\n", + "woredas = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-6/amhara_woreda_20170207')\n", + "# Create region outer boundary to filter products on.\n", + "amhara = woredas.geometry().bounds()\n", + "gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06')\n", + "LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \\\n", + " .filterDate('2001-06-26', Date.now())\n", + "brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4')\n", + "brdfQa = ee.ImageCollection('MODIS/006/MCD43A2')\n", + "\n", + "# Visualize woredas with black borders and no fill.\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "# Paint all the polygon edges with the same number and width.\n", + "outline = empty.paint({\n", + " 'featureCollection': woredas,\n", + " 'color': 1,\n", + " 'width': 1\n", + "})\n", + "# Add woreda boundaries to the map.\n", + "Map.setCenter(38, 11.5, 7)\n", + "Map.addLayer(outline, {\n", + " 'palette': '000000'\n", + "}, 'Woredas')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16a Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16a Checkpoint.js new file mode 100644 index 0000000..821824e --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16a Checkpoint.js @@ -0,0 +1,36 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.6 Health Applications +// Checkpoint: A16a +// Author: Dawn Nekorchuk +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1: Data Import +var woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207'); +// Create region outer boundary to filter products on. +var amhara = woredas.geometry().bounds(); +var gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06'); +var LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') + // Due to MCST outage, only use dates after this for this script. + .filterDate('2001-06-26', Date.now()); +var brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4'); +var brdfQa = ee.ImageCollection('MODIS/006/MCD43A2'); + +// Visualize woredas with black borders and no fill. +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); +// Paint all the polygon edges with the same number and width. +var outline = empty.paint({ + featureCollection: woredas, + color: 1, + width: 1 +}); +// Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7); +Map.addLayer(outline, { + palette: '000000' +}, 'Woredas'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16a Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16a Checkpoint.py new file mode 100644 index 0000000..49914f5 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16a Checkpoint.py @@ -0,0 +1,41 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.6 Health Applications +# Checkpoint: A16a +# Author: Dawn Nekorchuk +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1: Data Import +woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207') +# Create region outer boundary to filter products on. +amhara = woredas.geometry().bounds() +gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06') +LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \ + .filterDate('2001-06-26', Date.now()) +brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4') +brdfQa = ee.ImageCollection('MODIS/006/MCD43A2') + +# Visualize woredas with black borders and no fill. +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() +# Paint all the polygon edges with the same number and width. +outline = empty.paint({ + 'featureCollection': woredas, + 'color': 1, + 'width': 1 +}) +# Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7) +Map.addLayer(outline, { + 'palette': '000000' +}, 'Woredas') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16b Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16b Checkpoint.ipynb new file mode 100644 index 0000000..c504c0b --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16b Checkpoint.ipynb @@ -0,0 +1,195 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.6 Health Applications\n", + "# Checkpoint: A16b\n", + "# Author: Dawn Nekorchuk\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1: Data Import\n", + "woredas = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-6/amhara_woreda_20170207')\n", + "# Create region outer boundary to filter products on.\n", + "amhara = woredas.geometry().bounds()\n", + "gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06')\n", + "LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \\\n", + " .filterDate('2001-06-26', Date.now())\n", + "brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4')\n", + "brdfQa = ee.ImageCollection('MODIS/006/MCD43A2')\n", + "\n", + "# Visualize woredas with black borders and no fill.\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "# Paint all the polygon edges with the same number and width.\n", + "outline = empty.paint({\n", + " 'featureCollection': woredas,\n", + " 'color': 1,\n", + " 'width': 1\n", + "})\n", + "# Add woreda boundaries to the map.\n", + "Map.setCenter(38, 11.5, 7)\n", + "Map.addLayer(outline, {\n", + " 'palette': '000000'\n", + "}, 'Woredas')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 2: Handling of dates\n", + "\n", + "# 2.1 Requested start and end dates.\n", + "reqStartDate = ee.Date('2021-10-01')\n", + "reqEndDate = ee.Date('2021-11-30')\n", + "\n", + "# 2.2 LST Dates\n", + "# LST MODIS is every 8 days, and a user-requested date will likely not match.\n", + "# We want to get the latest previous image date,\n", + "# i.e. the date the closest, but prior to, the requested date.\n", + "# We will filter later.\n", + "# Get date of first image.\n", + "LSTEarliestDate = LSTTerra8.first().date()\n", + "# Filter collection to dates from beginning to requested start date.\n", + "priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate,\n", + " reqStartDate)\n", + "# Get the latest (max) date of this collection of earlier images.\n", + "LSTPrevMax = priorLstImgCol.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTStartDate = ee.Date(LSTPrevMax.get('max'))\n", + "print('LSTStartDate', LSTStartDate)\n", + "\n", + "# 2.3 Last available data dates\n", + "# Different variables have different data lags.\n", + "# Data may not be available in user range.\n", + "# To prevent errors from stopping script,\n", + "# grab last available (if relevant) & filter at end.\n", + "\n", + "# 2.3.1 Precipitation\n", + "# Calculate date of most recent measurement for gpm (of all time).\n", + "gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [\n", + " 'system:time_start'\n", + "])\n", + "gpmAllEndDateTime = ee.Date(gpmAllMax.get('max'))\n", + "# GPM every 30 minutes, so get just date part.\n", + "gpmAllEndDate = ee.Date.fromYMD({\n", + " 'year': gpmAllEndDateTime.get('year'),\n", + " 'month': gpmAllEndDateTime.get('month'),\n", + " 'day': gpmAllEndDateTime.get('day')\n", + "})\n", + "\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use requested date.\n", + "precipStartDate = ee.Date(gpmAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('precipStartDate', precipStartDate)\n", + "\n", + "# 2.3.2 BRDF\n", + "# Calculate date of most recent measurement for brdf (of all time).\n", + "brdfAllMax = brdfReflect.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "brdfAllEndDate = ee.Date(brdfAllMax.get('max'))\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use the requested date.\n", + "brdfStartDate = ee.Date(brdfAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('brdfStartDate', brdfStartDate)\n", + "print('brdfEndDate', brdfAllEndDate)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16b Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16b Checkpoint.js new file mode 100644 index 0000000..6364137 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16b Checkpoint.js @@ -0,0 +1,103 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.6 Health Applications +// Checkpoint: A16b +// Author: Dawn Nekorchuk +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1: Data Import +var woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207'); +// Create region outer boundary to filter products on. +var amhara = woredas.geometry().bounds(); +var gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06'); +var LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') + // Due to MCST outage, only use dates after this for this script. + .filterDate('2001-06-26', Date.now()); +var brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4'); +var brdfQa = ee.ImageCollection('MODIS/006/MCD43A2'); + +// Visualize woredas with black borders and no fill. +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); +// Paint all the polygon edges with the same number and width. +var outline = empty.paint({ + featureCollection: woredas, + color: 1, + width: 1 +}); +// Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7); +Map.addLayer(outline, { + palette: '000000' +}, 'Woredas'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 2: Handling of dates + +// 2.1 Requested start and end dates. +var reqStartDate = ee.Date('2021-10-01'); +var reqEndDate = ee.Date('2021-11-30'); + +// 2.2 LST Dates +// LST MODIS is every 8 days, and a user-requested date will likely not match. +// We want to get the latest previous image date, +// i.e. the date the closest, but prior to, the requested date. +// We will filter later. +// Get date of first image. +var LSTEarliestDate = LSTTerra8.first().date(); +// Filter collection to dates from beginning to requested start date. +var priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate); +// Get the latest (max) date of this collection of earlier images. +var LSTPrevMax = priorLstImgCol.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTStartDate = ee.Date(LSTPrevMax.get('max')); +print('LSTStartDate', LSTStartDate); + +// 2.3 Last available data dates +// Different variables have different data lags. +// Data may not be available in user range. +// To prevent errors from stopping script, +// grab last available (if relevant) & filter at end. + +// 2.3.1 Precipitation +// Calculate date of most recent measurement for gpm (of all time). +var gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]); +var gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')); +// GPM every 30 minutes, so get just date part. +var gpmAllEndDate = ee.Date.fromYMD({ + year: gpmAllEndDateTime.get('year'), + month: gpmAllEndDateTime.get('month'), + day: gpmAllEndDateTime.get('day') +}); + +// If data ends before requested start, take last data date, +// otherwise use requested date. +var precipStartDate = ee.Date(gpmAllEndDate.millis() + .min(reqStartDate.millis())); +print('precipStartDate', precipStartDate); + +// 2.3.2 BRDF +// Calculate date of most recent measurement for brdf (of all time). +var brdfAllMax = brdfReflect.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var brdfAllEndDate = ee.Date(brdfAllMax.get('max')); +// If data ends before requested start, take last data date, +// otherwise use the requested date. +var brdfStartDate = ee.Date(brdfAllEndDate.millis() + .min(reqStartDate.millis())); +print('brdfStartDate', brdfStartDate); +print('brdfEndDate', brdfAllEndDate); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16b Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16b Checkpoint.py new file mode 100644 index 0000000..38dab1a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16b Checkpoint.py @@ -0,0 +1,108 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.6 Health Applications +# Checkpoint: A16b +# Author: Dawn Nekorchuk +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1: Data Import +woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207') +# Create region outer boundary to filter products on. +amhara = woredas.geometry().bounds() +gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06') +LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \ + .filterDate('2001-06-26', Date.now()) +brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4') +brdfQa = ee.ImageCollection('MODIS/006/MCD43A2') + +# Visualize woredas with black borders and no fill. +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() +# Paint all the polygon edges with the same number and width. +outline = empty.paint({ + 'featureCollection': woredas, + 'color': 1, + 'width': 1 +}) +# Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7) +Map.addLayer(outline, { + 'palette': '000000' +}, 'Woredas') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 2: Handling of dates + +# 2.1 Requested start and end dates. +reqStartDate = ee.Date('2021-10-01') +reqEndDate = ee.Date('2021-11-30') + +# 2.2 LST Dates +# LST MODIS is every 8 days, and a user-requested date will likely not match. +# We want to get the latest previous image date, +# i.e. the date the closest, but prior to, the requested date. +# We will filter later. +# Get date of first image. +LSTEarliestDate = LSTTerra8.first().date() +# Filter collection to dates from beginning to requested start date. +priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate) +# Get the latest (max) date of this collection of earlier images. +LSTPrevMax = priorLstImgCol.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTStartDate = ee.Date(LSTPrevMax.get('max')) +print('LSTStartDate', LSTStartDate) + +# 2.3 Last available data dates +# Different variables have different data lags. +# Data may not be available in user range. +# To prevent errors from stopping script, +# grab last available (if relevant) & filter at end. + +# 2.3.1 Precipitation +# Calculate date of most recent measurement for gpm (of all time). +gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]) +gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')) +# GPM every 30 minutes, so get just date part. +gpmAllEndDate = ee.Date.fromYMD({ + 'year': gpmAllEndDateTime.get('year'), + 'month': gpmAllEndDateTime.get('month'), + 'day': gpmAllEndDateTime.get('day') +}) + +# If data ends before requested start, take last data date, +# otherwise use requested date. +precipStartDate = ee.Date(gpmAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('precipStartDate', precipStartDate) + +# 2.3.2 BRDF +# Calculate date of most recent measurement for brdf (of all time). +brdfAllMax = brdfReflect.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +brdfAllEndDate = ee.Date(brdfAllMax.get('max')) +# If data ends before requested start, take last data date, +# otherwise use the requested date. +brdfStartDate = ee.Date(brdfAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('brdfStartDate', brdfStartDate) +print('brdfEndDate', brdfAllEndDate) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16c Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16c Checkpoint.ipynb new file mode 100644 index 0000000..04df7ab --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16c Checkpoint.ipynb @@ -0,0 +1,283 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.6 Health Applications\n", + "# Checkpoint: A16c\n", + "# Author: Dawn Nekorchuk\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1: Data Import\n", + "woredas = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-6/amhara_woreda_20170207')\n", + "# Create region outer boundary to filter products on.\n", + "amhara = woredas.geometry().bounds()\n", + "gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06')\n", + "LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \\\n", + " .filterDate('2001-06-26', Date.now())\n", + "brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4')\n", + "brdfQa = ee.ImageCollection('MODIS/006/MCD43A2')\n", + "\n", + "# Visualize woredas with black borders and no fill.\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "# Paint all the polygon edges with the same number and width.\n", + "outline = empty.paint({\n", + " 'featureCollection': woredas,\n", + " 'color': 1,\n", + " 'width': 1\n", + "})\n", + "# Add woreda boundaries to the map.\n", + "Map.setCenter(38, 11.5, 7)\n", + "Map.addLayer(outline, {\n", + " 'palette': '000000'\n", + "}, 'Woredas')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 2: Handling of dates\n", + "\n", + "# 2.1 Requested start and end dates.\n", + "reqStartDate = ee.Date('2021-10-01')\n", + "reqEndDate = ee.Date('2021-11-30')\n", + "\n", + "# 2.2 LST Dates\n", + "# LST MODIS is every 8 days, and a user-requested date will likely not match.\n", + "# We want to get the latest previous image date,\n", + "# i.e. the date the closest, but prior to, the requested date.\n", + "# We will filter later.\n", + "# Get date of first image.\n", + "LSTEarliestDate = LSTTerra8.first().date()\n", + "# Filter collection to dates from beginning to requested start date.\n", + "priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate,\n", + " reqStartDate)\n", + "# Get the latest (max) date of this collection of earlier images.\n", + "LSTPrevMax = priorLstImgCol.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTStartDate = ee.Date(LSTPrevMax.get('max'))\n", + "print('LSTStartDate', LSTStartDate)\n", + "\n", + "# 2.3 Last available data dates\n", + "# Different variables have different data lags.\n", + "# Data may not be available in user range.\n", + "# To prevent errors from stopping script,\n", + "# grab last available (if relevant) & filter at end.\n", + "\n", + "# 2.3.1 Precipitation\n", + "# Calculate date of most recent measurement for gpm (of all time).\n", + "gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [\n", + " 'system:time_start'\n", + "])\n", + "gpmAllEndDateTime = ee.Date(gpmAllMax.get('max'))\n", + "# GPM every 30 minutes, so get just date part.\n", + "gpmAllEndDate = ee.Date.fromYMD({\n", + " 'year': gpmAllEndDateTime.get('year'),\n", + " 'month': gpmAllEndDateTime.get('month'),\n", + " 'day': gpmAllEndDateTime.get('day')\n", + "})\n", + "\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use requested date.\n", + "precipStartDate = ee.Date(gpmAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('precipStartDate', precipStartDate)\n", + "\n", + "# 2.3.2 BRDF\n", + "# Calculate date of most recent measurement for brdf (of all time).\n", + "brdfAllMax = brdfReflect.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "brdfAllEndDate = ee.Date(brdfAllMax.get('max'))\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use the requested date.\n", + "brdfStartDate = ee.Date(brdfAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('brdfStartDate', brdfStartDate)\n", + "print('brdfEndDate', brdfAllEndDate)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 3: Precipitation\n", + "\n", + "# Section 3.1: Precipitation filtering and dates\n", + "\n", + "# Filter gpm by date, using modified start if necessary.\n", + "gpmFiltered = gpm \\\n", + " .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select('precipitationCal')\n", + "\n", + "# Calculate date of most recent measurement for gpm\n", + "# (in the modified requested window).\n", + "gpmMax = gpmFiltered.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "gpmEndDate = ee.Date(gpmMax.get('max'))\n", + "precipEndDate = gpmEndDate\n", + "print('precipEndDate ', precipEndDate)\n", + "\n", + "# Create a list of dates for the precipitation time series.\n", + "precipDays = precipEndDate.difference(precipStartDate, 'day')\n", + "precipDatesPrep = ee.List.sequence(0, precipDays, 1)\n", + "\n", + "def makePrecipDates(n):\n", + " return precipStartDate.advance(n, 'day')\n", + "\n", + "precipDates = precipDatesPrep.map(makePrecipDates)\n", + "\n", + "# Section 3.2: Calculate daily precipitation\n", + "\n", + "# Function to calculate daily precipitation:\n", + "def calcDailyPrecip(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " totprec = gpmFiltered \\\n", + " .filterDate(curdate, curdate.advance(1, 'day')) \\\n", + " .select('precipitationCal') \\\n", + " .sum() \\\n", + " .multiply(0.5) \\\n", + " .rename('totprec')\n", + "\n", + " return totprec \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate)\n", + "\n", + "# Map function over list of dates.\n", + "dailyPrecipExtended =\n", + " ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip))\n", + "\n", + "# Filter back to the original user requested start date.\n", + "dailyPrecip = dailyPrecipExtended \\\n", + " .filterDate(reqStartDate, precipEndDate.advance(1, 'day'))\n", + "\n", + "# Section 3.3: Summarize daily precipitation by woreda\n", + "\n", + "# Filter precip data for zonal summaries.\n", + "precipSummary = dailyPrecip \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "\n", + "# Function to calculate zonal statistics for precipitation by woreda.\n", + "def sumZonalPrecip(image):\n", + " # To get the doy and year,\n", + " # convert the metadata to grids and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each county.\n", + " output = image2.select(['year', 'doy', 'totprec']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "# Map the zonal statistics function over the filtered precip data.\n", + "precipWoreda = precipSummary.map(sumZonalPrecip)\n", + "# Flatten the results for export.\n", + "precipFlat = precipWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16c Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16c Checkpoint.js new file mode 100644 index 0000000..17e61f3 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16c Checkpoint.js @@ -0,0 +1,192 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.6 Health Applications +// Checkpoint: A16c +// Author: Dawn Nekorchuk +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1: Data Import +var woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207'); +// Create region outer boundary to filter products on. +var amhara = woredas.geometry().bounds(); +var gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06'); +var LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') + // Due to MCST outage, only use dates after this for this script. + .filterDate('2001-06-26', Date.now()); +var brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4'); +var brdfQa = ee.ImageCollection('MODIS/006/MCD43A2'); + +// Visualize woredas with black borders and no fill. +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); +// Paint all the polygon edges with the same number and width. +var outline = empty.paint({ + featureCollection: woredas, + color: 1, + width: 1 +}); +// Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7); +Map.addLayer(outline, { + palette: '000000' +}, 'Woredas'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 2: Handling of dates + +// 2.1 Requested start and end dates. +var reqStartDate = ee.Date('2021-10-01'); +var reqEndDate = ee.Date('2021-11-30'); + +// 2.2 LST Dates +// LST MODIS is every 8 days, and a user-requested date will likely not match. +// We want to get the latest previous image date, +// i.e. the date the closest, but prior to, the requested date. +// We will filter later. +// Get date of first image. +var LSTEarliestDate = LSTTerra8.first().date(); +// Filter collection to dates from beginning to requested start date. +var priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate); +// Get the latest (max) date of this collection of earlier images. +var LSTPrevMax = priorLstImgCol.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTStartDate = ee.Date(LSTPrevMax.get('max')); +print('LSTStartDate', LSTStartDate); + +// 2.3 Last available data dates +// Different variables have different data lags. +// Data may not be available in user range. +// To prevent errors from stopping script, +// grab last available (if relevant) & filter at end. + +// 2.3.1 Precipitation +// Calculate date of most recent measurement for gpm (of all time). +var gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]); +var gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')); +// GPM every 30 minutes, so get just date part. +var gpmAllEndDate = ee.Date.fromYMD({ + year: gpmAllEndDateTime.get('year'), + month: gpmAllEndDateTime.get('month'), + day: gpmAllEndDateTime.get('day') +}); + +// If data ends before requested start, take last data date, +// otherwise use requested date. +var precipStartDate = ee.Date(gpmAllEndDate.millis() + .min(reqStartDate.millis())); +print('precipStartDate', precipStartDate); + +// 2.3.2 BRDF +// Calculate date of most recent measurement for brdf (of all time). +var brdfAllMax = brdfReflect.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var brdfAllEndDate = ee.Date(brdfAllMax.get('max')); +// If data ends before requested start, take last data date, +// otherwise use the requested date. +var brdfStartDate = ee.Date(brdfAllEndDate.millis() + .min(reqStartDate.millis())); +print('brdfStartDate', brdfStartDate); +print('brdfEndDate', brdfAllEndDate); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 3: Precipitation + +// Section 3.1: Precipitation filtering and dates + +// Filter gpm by date, using modified start if necessary. +var gpmFiltered = gpm + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select('precipitationCal'); + +// Calculate date of most recent measurement for gpm +// (in the modified requested window). +var gpmMax = gpmFiltered.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var gpmEndDate = ee.Date(gpmMax.get('max')); +var precipEndDate = gpmEndDate; +print('precipEndDate ', precipEndDate); + +// Create a list of dates for the precipitation time series. +var precipDays = precipEndDate.difference(precipStartDate, 'day'); +var precipDatesPrep = ee.List.sequence(0, precipDays, 1); + +function makePrecipDates(n) { + return precipStartDate.advance(n, 'day'); +} +var precipDates = precipDatesPrep.map(makePrecipDates); + +// Section 3.2: Calculate daily precipitation + +// Function to calculate daily precipitation: +function calcDailyPrecip(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var totprec = gpmFiltered + .filterDate(curdate, curdate.advance(1, 'day')) + .select('precipitationCal') + .sum() + //every half-hour + .multiply(0.5) + .rename('totprec'); + + return totprec + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate); +} +// Map function over list of dates. +var dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)); + +// Filter back to the original user requested start date. +var dailyPrecip = dailyPrecipExtended + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')); + +// Section 3.3: Summarize daily precipitation by woreda + +// Filter precip data for zonal summaries. +var precipSummary = dailyPrecip + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); + +// Function to calculate zonal statistics for precipitation by woreda. +function sumZonalPrecip(image) { + // To get the doy and year, + // convert the metadata to grids and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each county. + var output = image2.select(['year', 'doy', 'totprec']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} +// Map the zonal statistics function over the filtered precip data. +var precipWoreda = precipSummary.map(sumZonalPrecip); +// Flatten the results for export. +var precipFlat = precipWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16c Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16c Checkpoint.py new file mode 100644 index 0000000..54769ef --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16c Checkpoint.py @@ -0,0 +1,196 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.6 Health Applications +# Checkpoint: A16c +# Author: Dawn Nekorchuk +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1: Data Import +woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207') +# Create region outer boundary to filter products on. +amhara = woredas.geometry().bounds() +gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06') +LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \ + .filterDate('2001-06-26', Date.now()) +brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4') +brdfQa = ee.ImageCollection('MODIS/006/MCD43A2') + +# Visualize woredas with black borders and no fill. +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() +# Paint all the polygon edges with the same number and width. +outline = empty.paint({ + 'featureCollection': woredas, + 'color': 1, + 'width': 1 +}) +# Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7) +Map.addLayer(outline, { + 'palette': '000000' +}, 'Woredas') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 2: Handling of dates + +# 2.1 Requested start and end dates. +reqStartDate = ee.Date('2021-10-01') +reqEndDate = ee.Date('2021-11-30') + +# 2.2 LST Dates +# LST MODIS is every 8 days, and a user-requested date will likely not match. +# We want to get the latest previous image date, +# i.e. the date the closest, but prior to, the requested date. +# We will filter later. +# Get date of first image. +LSTEarliestDate = LSTTerra8.first().date() +# Filter collection to dates from beginning to requested start date. +priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate) +# Get the latest (max) date of this collection of earlier images. +LSTPrevMax = priorLstImgCol.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTStartDate = ee.Date(LSTPrevMax.get('max')) +print('LSTStartDate', LSTStartDate) + +# 2.3 Last available data dates +# Different variables have different data lags. +# Data may not be available in user range. +# To prevent errors from stopping script, +# grab last available (if relevant) & filter at end. + +# 2.3.1 Precipitation +# Calculate date of most recent measurement for gpm (of all time). +gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]) +gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')) +# GPM every 30 minutes, so get just date part. +gpmAllEndDate = ee.Date.fromYMD({ + 'year': gpmAllEndDateTime.get('year'), + 'month': gpmAllEndDateTime.get('month'), + 'day': gpmAllEndDateTime.get('day') +}) + +# If data ends before requested start, take last data date, +# otherwise use requested date. +precipStartDate = ee.Date(gpmAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('precipStartDate', precipStartDate) + +# 2.3.2 BRDF +# Calculate date of most recent measurement for brdf (of all time). +brdfAllMax = brdfReflect.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +brdfAllEndDate = ee.Date(brdfAllMax.get('max')) +# If data ends before requested start, take last data date, +# otherwise use the requested date. +brdfStartDate = ee.Date(brdfAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('brdfStartDate', brdfStartDate) +print('brdfEndDate', brdfAllEndDate) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 3: Precipitation + +# Section 3.1: Precipitation filtering and dates + +# Filter gpm by date, using modified start if necessary. +gpmFiltered = gpm \ + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select('precipitationCal') + +# Calculate date of most recent measurement for gpm +# (in the modified requested window). +gpmMax = gpmFiltered.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +gpmEndDate = ee.Date(gpmMax.get('max')) +precipEndDate = gpmEndDate +print('precipEndDate ', precipEndDate) + +# Create a list of dates for the precipitation time series. +precipDays = precipEndDate.difference(precipStartDate, 'day') +precipDatesPrep = ee.List.sequence(0, precipDays, 1) + +def makePrecipDates(n): + return precipStartDate.advance(n, 'day') + +precipDates = precipDatesPrep.map(makePrecipDates) + +# Section 3.2: Calculate daily precipitation + +# Function to calculate daily precipitation: +def calcDailyPrecip(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + totprec = gpmFiltered \ + .filterDate(curdate, curdate.advance(1, 'day')) \ + .select('precipitationCal') \ + .sum() \ + .multiply(0.5) \ + .rename('totprec') + + return totprec \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) + +# Map function over list of dates. +dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)) + +# Filter back to the original user requested start date. +dailyPrecip = dailyPrecipExtended \ + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')) + +# Section 3.3: Summarize daily precipitation by woreda + +# Filter precip data for zonal summaries. +precipSummary = dailyPrecip \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) + +# Function to calculate zonal statistics for precipitation by woreda. +def sumZonalPrecip(image): + # To get the doy and year, + # convert the metadata to grids and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each county. + output = image2.select(['year', 'doy', 'totprec']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + +# Map the zonal statistics function over the filtered precip data. +precipWoreda = precipSummary.map(sumZonalPrecip) +# Flatten the results for export. +precipFlat = precipWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16d Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16d Checkpoint.ipynb new file mode 100644 index 0000000..e06bfbe --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16d Checkpoint.ipynb @@ -0,0 +1,422 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.6 Health Applications\n", + "# Checkpoint: A16d\n", + "# Author: Dawn Nekorchuk\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1: Data Import\n", + "woredas = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-6/amhara_woreda_20170207')\n", + "# Create region outer boundary to filter products on.\n", + "amhara = woredas.geometry().bounds()\n", + "gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06')\n", + "LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \\\n", + " .filterDate('2001-06-26', Date.now())\n", + "brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4')\n", + "brdfQa = ee.ImageCollection('MODIS/006/MCD43A2')\n", + "\n", + "# Visualize woredas with black borders and no fill.\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "# Paint all the polygon edges with the same number and width.\n", + "outline = empty.paint({\n", + " 'featureCollection': woredas,\n", + " 'color': 1,\n", + " 'width': 1\n", + "})\n", + "# Add woreda boundaries to the map.\n", + "Map.setCenter(38, 11.5, 7)\n", + "Map.addLayer(outline, {\n", + " 'palette': '000000'\n", + "}, 'Woredas')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 2: Handling of dates\n", + "\n", + "# 2.1 Requested start and end dates.\n", + "reqStartDate = ee.Date('2021-10-01')\n", + "reqEndDate = ee.Date('2021-11-30')\n", + "\n", + "# 2.2 LST Dates\n", + "# LST MODIS is every 8 days, and a user-requested date will likely not match.\n", + "# We want to get the latest previous image date,\n", + "# i.e. the date the closest, but prior to, the requested date.\n", + "# We will filter later.\n", + "# Get date of first image.\n", + "LSTEarliestDate = LSTTerra8.first().date()\n", + "# Filter collection to dates from beginning to requested start date.\n", + "priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate,\n", + " reqStartDate)\n", + "# Get the latest (max) date of this collection of earlier images.\n", + "LSTPrevMax = priorLstImgCol.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTStartDate = ee.Date(LSTPrevMax.get('max'))\n", + "print('LSTStartDate', LSTStartDate)\n", + "\n", + "# 2.3 Last available data dates\n", + "# Different variables have different data lags.\n", + "# Data may not be available in user range.\n", + "# To prevent errors from stopping script,\n", + "# grab last available (if relevant) & filter at end.\n", + "\n", + "# 2.3.1 Precipitation\n", + "# Calculate date of most recent measurement for gpm (of all time).\n", + "gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [\n", + " 'system:time_start'\n", + "])\n", + "gpmAllEndDateTime = ee.Date(gpmAllMax.get('max'))\n", + "# GPM every 30 minutes, so get just date part.\n", + "gpmAllEndDate = ee.Date.fromYMD({\n", + " 'year': gpmAllEndDateTime.get('year'),\n", + " 'month': gpmAllEndDateTime.get('month'),\n", + " 'day': gpmAllEndDateTime.get('day')\n", + "})\n", + "\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use requested date.\n", + "precipStartDate = ee.Date(gpmAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('precipStartDate', precipStartDate)\n", + "\n", + "# 2.3.2 BRDF\n", + "# Calculate date of most recent measurement for brdf (of all time).\n", + "brdfAllMax = brdfReflect.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "brdfAllEndDate = ee.Date(brdfAllMax.get('max'))\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use the requested date.\n", + "brdfStartDate = ee.Date(brdfAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('brdfStartDate', brdfStartDate)\n", + "print('brdfEndDate', brdfAllEndDate)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 3: Precipitation\n", + "\n", + "# Section 3.1: Precipitation filtering and dates\n", + "\n", + "# Filter gpm by date, using modified start if necessary.\n", + "gpmFiltered = gpm \\\n", + " .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select('precipitationCal')\n", + "\n", + "# Calculate date of most recent measurement for gpm\n", + "# (in the modified requested window).\n", + "gpmMax = gpmFiltered.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "gpmEndDate = ee.Date(gpmMax.get('max'))\n", + "precipEndDate = gpmEndDate\n", + "print('precipEndDate ', precipEndDate)\n", + "\n", + "# Create a list of dates for the precipitation time series.\n", + "precipDays = precipEndDate.difference(precipStartDate, 'day')\n", + "precipDatesPrep = ee.List.sequence(0, precipDays, 1)\n", + "\n", + "def makePrecipDates(n):\n", + " return precipStartDate.advance(n, 'day')\n", + "\n", + "precipDates = precipDatesPrep.map(makePrecipDates)\n", + "\n", + "# Section 3.2: Calculate daily precipitation\n", + "\n", + "# Function to calculate daily precipitation:\n", + "def calcDailyPrecip(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " totprec = gpmFiltered \\\n", + " .filterDate(curdate, curdate.advance(1, 'day')) \\\n", + " .select('precipitationCal') \\\n", + " .sum() \\\n", + " .multiply(0.5) \\\n", + " .rename('totprec')\n", + "\n", + " return totprec \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate)\n", + "\n", + "# Map function over list of dates.\n", + "dailyPrecipExtended =\n", + " ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip))\n", + "\n", + "# Filter back to the original user requested start date.\n", + "dailyPrecip = dailyPrecipExtended \\\n", + " .filterDate(reqStartDate, precipEndDate.advance(1, 'day'))\n", + "\n", + "# Section 3.3: Summarize daily precipitation by woreda\n", + "\n", + "# Filter precip data for zonal summaries.\n", + "precipSummary = dailyPrecip \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "\n", + "# Function to calculate zonal statistics for precipitation by woreda.\n", + "def sumZonalPrecip(image):\n", + " # To get the doy and year,\n", + " # convert the metadata to grids and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each county.\n", + " output = image2.select(['year', 'doy', 'totprec']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "# Map the zonal statistics function over the filtered precip data.\n", + "precipWoreda = precipSummary.map(sumZonalPrecip)\n", + "# Flatten the results for export.\n", + "precipFlat = precipWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 4: Land surface temperature\n", + "\n", + "# Section 4.1: Calculate LST variables\n", + "\n", + "# Filter Terra LST by altered LST start date.\n", + "# Rarely, but at the end of the year if the last image is late in the year\n", + "# with only a few days in its period, it will sometimes not grab\n", + "# the next image. Add extra padding to reqEndDate and\n", + "# it will be trimmed at the end.\n", + "LSTFiltered = LSTTerra8 \\\n", + " .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night')\n", + "\n", + "# Filter Terra LST by QA information.\n", + "def filterLstQa(image):\n", + " qaday = image.select(['QC_Day'])\n", + " qanight = image.select(['QC_Night'])\n", + " dayshift = qaday.rightShift(6)\n", + " nightshift = qanight.rightShift(6)\n", + " daymask = dayshift.lte(2)\n", + " nightmask = nightshift.lte(2)\n", + " outimage = ee.Image(image.select(['LST_Day_1km',\n", + " 'LST_Night_1km'\n", + " ]))\n", + " outmask = ee.Image([daymask, nightmask])\n", + " return outimage.updateMask(outmask)\n", + "\n", + "LSTFilteredQa = LSTFiltered.map(filterLstQa)\n", + "\n", + "# Rescale temperature data and convert to degrees Celsius (C).\n", + "def rescaleLst(image):\n", + " LST_day = image.select('LST_Day_1km') \\\n", + " .multiply(0.02) \\\n", + " .subtract(273.15) \\\n", + " .rename('LST_day')\n", + " LST_night = image.select('LST_Night_1km') \\\n", + " .multiply(0.02) \\\n", + " .subtract(273.15) \\\n", + " .rename('LST_night')\n", + " LST_mean = image.expression(\n", + " '(day + night) / 2', {\n", + " 'day': LST_day.select('LST_day'),\n", + " 'night': LST_night.select('LST_night')\n", + " }\n", + " ).rename('LST_mean')\n", + " return image.addBands(LST_day) \\\n", + " .addBands(LST_night) \\\n", + " .addBands(LST_mean)\n", + "\n", + "LSTVars = LSTFilteredQa.map(rescaleLst)\n", + "\n", + "# Section 4.2: Calculate daily LST\n", + "\n", + "# Create list of dates for time series.\n", + "LSTRange = LSTVars.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day')\n", + "LSTDays = LSTEndDate.difference(LSTStartDate, 'day')\n", + "LSTDatesPrep = ee.List.sequence(0, LSTDays, 1)\n", + "\n", + "def makeLstDates(n):\n", + " return LSTStartDate.advance(n, 'day')\n", + "\n", + "LSTDates = LSTDatesPrep.map(makeLstDates)\n", + "\n", + "# Function to calculate daily LST by assigning the 8-day composite summary\n", + "# to each day in the composite period:\n", + "def calcDailyLst(curdate):\n", + " curyear = ee.Date(curdate).get('year')\n", + " curdoy = ee.Date(curdate).getRelative('day', 'year').add(1)\n", + " moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add(\n", + " 1)\n", + " basedate = ee.Date.fromYMD(curyear, 1, 1)\n", + " moddate = basedate.advance(moddoy.subtract(1), 'day')\n", + " LST_day = LSTVars \\\n", + " .select('LST_day') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_day')\n", + " LST_night = LSTVars \\\n", + " .select('LST_night') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_night')\n", + " LST_mean = LSTVars \\\n", + " .select('LST_mean') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_mean')\n", + " return LST_day \\\n", + " .addBands(LST_night) \\\n", + " .addBands(LST_mean) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate)\n", + "\n", + "# Map the function over the image collection\n", + "dailyLstExtended =\n", + " ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst))\n", + "\n", + "# Filter back to original user requested start date\n", + "dailyLst = dailyLstExtended \\\n", + " .filterDate(reqStartDate, LSTEndDate.advance(1, 'day'))\n", + "\n", + "# Section 4.3: Summarize daily LST by woreda\n", + "\n", + "# Filter LST data for zonal summaries.\n", + "LSTSummary = dailyLst \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "# Function to calculate zonal statistics for LST by woreda:\n", + "def sumZonalLst(image):\n", + " # To get the doy and year, we convert the metadata to grids\n", + " # and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each county.\n", + " output = image2 \\\n", + " .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "# Map the zonal statistics function over the filtered LST data.\n", + "LSTWoreda = LSTSummary.map(sumZonalLst)\n", + "# Flatten the results for export.\n", + "LSTFlat = LSTWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16d Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16d Checkpoint.js new file mode 100644 index 0000000..d7049b8 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16d Checkpoint.js @@ -0,0 +1,331 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.6 Health Applications +// Checkpoint: A16d +// Author: Dawn Nekorchuk +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1: Data Import +var woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207'); +// Create region outer boundary to filter products on. +var amhara = woredas.geometry().bounds(); +var gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06'); +var LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') + // Due to MCST outage, only use dates after this for this script. + .filterDate('2001-06-26', Date.now()); +var brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4'); +var brdfQa = ee.ImageCollection('MODIS/006/MCD43A2'); + +// Visualize woredas with black borders and no fill. +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); +// Paint all the polygon edges with the same number and width. +var outline = empty.paint({ + featureCollection: woredas, + color: 1, + width: 1 +}); +// Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7); +Map.addLayer(outline, { + palette: '000000' +}, 'Woredas'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 2: Handling of dates + +// 2.1 Requested start and end dates. +var reqStartDate = ee.Date('2021-10-01'); +var reqEndDate = ee.Date('2021-11-30'); + +// 2.2 LST Dates +// LST MODIS is every 8 days, and a user-requested date will likely not match. +// We want to get the latest previous image date, +// i.e. the date the closest, but prior to, the requested date. +// We will filter later. +// Get date of first image. +var LSTEarliestDate = LSTTerra8.first().date(); +// Filter collection to dates from beginning to requested start date. +var priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate); +// Get the latest (max) date of this collection of earlier images. +var LSTPrevMax = priorLstImgCol.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTStartDate = ee.Date(LSTPrevMax.get('max')); +print('LSTStartDate', LSTStartDate); + +// 2.3 Last available data dates +// Different variables have different data lags. +// Data may not be available in user range. +// To prevent errors from stopping script, +// grab last available (if relevant) & filter at end. + +// 2.3.1 Precipitation +// Calculate date of most recent measurement for gpm (of all time). +var gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]); +var gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')); +// GPM every 30 minutes, so get just date part. +var gpmAllEndDate = ee.Date.fromYMD({ + year: gpmAllEndDateTime.get('year'), + month: gpmAllEndDateTime.get('month'), + day: gpmAllEndDateTime.get('day') +}); + +// If data ends before requested start, take last data date, +// otherwise use requested date. +var precipStartDate = ee.Date(gpmAllEndDate.millis() + .min(reqStartDate.millis())); +print('precipStartDate', precipStartDate); + +// 2.3.2 BRDF +// Calculate date of most recent measurement for brdf (of all time). +var brdfAllMax = brdfReflect.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var brdfAllEndDate = ee.Date(brdfAllMax.get('max')); +// If data ends before requested start, take last data date, +// otherwise use the requested date. +var brdfStartDate = ee.Date(brdfAllEndDate.millis() + .min(reqStartDate.millis())); +print('brdfStartDate', brdfStartDate); +print('brdfEndDate', brdfAllEndDate); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 3: Precipitation + +// Section 3.1: Precipitation filtering and dates + +// Filter gpm by date, using modified start if necessary. +var gpmFiltered = gpm + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select('precipitationCal'); + +// Calculate date of most recent measurement for gpm +// (in the modified requested window). +var gpmMax = gpmFiltered.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var gpmEndDate = ee.Date(gpmMax.get('max')); +var precipEndDate = gpmEndDate; +print('precipEndDate ', precipEndDate); + +// Create a list of dates for the precipitation time series. +var precipDays = precipEndDate.difference(precipStartDate, 'day'); +var precipDatesPrep = ee.List.sequence(0, precipDays, 1); + +function makePrecipDates(n) { + return precipStartDate.advance(n, 'day'); +} +var precipDates = precipDatesPrep.map(makePrecipDates); + +// Section 3.2: Calculate daily precipitation + +// Function to calculate daily precipitation: +function calcDailyPrecip(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var totprec = gpmFiltered + .filterDate(curdate, curdate.advance(1, 'day')) + .select('precipitationCal') + .sum() + //every half-hour + .multiply(0.5) + .rename('totprec'); + + return totprec + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate); +} +// Map function over list of dates. +var dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)); + +// Filter back to the original user requested start date. +var dailyPrecip = dailyPrecipExtended + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')); + +// Section 3.3: Summarize daily precipitation by woreda + +// Filter precip data for zonal summaries. +var precipSummary = dailyPrecip + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); + +// Function to calculate zonal statistics for precipitation by woreda. +function sumZonalPrecip(image) { + // To get the doy and year, + // convert the metadata to grids and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each county. + var output = image2.select(['year', 'doy', 'totprec']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} +// Map the zonal statistics function over the filtered precip data. +var precipWoreda = precipSummary.map(sumZonalPrecip); +// Flatten the results for export. +var precipFlat = precipWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 4: Land surface temperature + +// Section 4.1: Calculate LST variables + +// Filter Terra LST by altered LST start date. +// Rarely, but at the end of the year if the last image is late in the year +// with only a few days in its period, it will sometimes not grab +// the next image. Add extra padding to reqEndDate and +// it will be trimmed at the end. +var LSTFiltered = LSTTerra8 + .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) + .filterBounds(amhara) + .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night'); + +// Filter Terra LST by QA information. +function filterLstQa(image) { + var qaday = image.select(['QC_Day']); + var qanight = image.select(['QC_Night']); + var dayshift = qaday.rightShift(6); + var nightshift = qanight.rightShift(6); + var daymask = dayshift.lte(2); + var nightmask = nightshift.lte(2); + var outimage = ee.Image(image.select(['LST_Day_1km', + 'LST_Night_1km' + ])); + var outmask = ee.Image([daymask, nightmask]); + return outimage.updateMask(outmask); +} +var LSTFilteredQa = LSTFiltered.map(filterLstQa); + +// Rescale temperature data and convert to degrees Celsius (C). +function rescaleLst(image) { + var LST_day = image.select('LST_Day_1km') + .multiply(0.02) + .subtract(273.15) + .rename('LST_day'); + var LST_night = image.select('LST_Night_1km') + .multiply(0.02) + .subtract(273.15) + .rename('LST_night'); + var LST_mean = image.expression( + '(day + night) / 2', { + 'day': LST_day.select('LST_day'), + 'night': LST_night.select('LST_night') + } + ).rename('LST_mean'); + return image.addBands(LST_day) + .addBands(LST_night) + .addBands(LST_mean); +} +var LSTVars = LSTFilteredQa.map(rescaleLst); + +// Section 4.2: Calculate daily LST + +// Create list of dates for time series. +var LSTRange = LSTVars.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day'); +var LSTDays = LSTEndDate.difference(LSTStartDate, 'day'); +var LSTDatesPrep = ee.List.sequence(0, LSTDays, 1); + +function makeLstDates(n) { + return LSTStartDate.advance(n, 'day'); +} +var LSTDates = LSTDatesPrep.map(makeLstDates); + +// Function to calculate daily LST by assigning the 8-day composite summary +// to each day in the composite period: +function calcDailyLst(curdate) { + var curyear = ee.Date(curdate).get('year'); + var curdoy = ee.Date(curdate).getRelative('day', 'year').add(1); + var moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add( + 1); + var basedate = ee.Date.fromYMD(curyear, 1, 1); + var moddate = basedate.advance(moddoy.subtract(1), 'day'); + var LST_day = LSTVars + .select('LST_day') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_day'); + var LST_night = LSTVars + .select('LST_night') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_night'); + var LST_mean = LSTVars + .select('LST_mean') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_mean'); + return LST_day + .addBands(LST_night) + .addBands(LST_mean) + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate); +} +// Map the function over the image collection +var dailyLstExtended = + ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst)); + +// Filter back to original user requested start date +var dailyLst = dailyLstExtended + .filterDate(reqStartDate, LSTEndDate.advance(1, 'day')); + +// Section 4.3: Summarize daily LST by woreda + +// Filter LST data for zonal summaries. +var LSTSummary = dailyLst + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); +// Function to calculate zonal statistics for LST by woreda: +function sumZonalLst(image) { + // To get the doy and year, we convert the metadata to grids + // and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each county. + var output = image2 + .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} +// Map the zonal statistics function over the filtered LST data. +var LSTWoreda = LSTSummary.map(sumZonalLst); +// Flatten the results for export. +var LSTFlat = LSTWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16d Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16d Checkpoint.py new file mode 100644 index 0000000..44a8db3 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16d Checkpoint.py @@ -0,0 +1,335 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.6 Health Applications +# Checkpoint: A16d +# Author: Dawn Nekorchuk +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1: Data Import +woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207') +# Create region outer boundary to filter products on. +amhara = woredas.geometry().bounds() +gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06') +LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \ + .filterDate('2001-06-26', Date.now()) +brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4') +brdfQa = ee.ImageCollection('MODIS/006/MCD43A2') + +# Visualize woredas with black borders and no fill. +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() +# Paint all the polygon edges with the same number and width. +outline = empty.paint({ + 'featureCollection': woredas, + 'color': 1, + 'width': 1 +}) +# Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7) +Map.addLayer(outline, { + 'palette': '000000' +}, 'Woredas') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 2: Handling of dates + +# 2.1 Requested start and end dates. +reqStartDate = ee.Date('2021-10-01') +reqEndDate = ee.Date('2021-11-30') + +# 2.2 LST Dates +# LST MODIS is every 8 days, and a user-requested date will likely not match. +# We want to get the latest previous image date, +# i.e. the date the closest, but prior to, the requested date. +# We will filter later. +# Get date of first image. +LSTEarliestDate = LSTTerra8.first().date() +# Filter collection to dates from beginning to requested start date. +priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate) +# Get the latest (max) date of this collection of earlier images. +LSTPrevMax = priorLstImgCol.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTStartDate = ee.Date(LSTPrevMax.get('max')) +print('LSTStartDate', LSTStartDate) + +# 2.3 Last available data dates +# Different variables have different data lags. +# Data may not be available in user range. +# To prevent errors from stopping script, +# grab last available (if relevant) & filter at end. + +# 2.3.1 Precipitation +# Calculate date of most recent measurement for gpm (of all time). +gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]) +gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')) +# GPM every 30 minutes, so get just date part. +gpmAllEndDate = ee.Date.fromYMD({ + 'year': gpmAllEndDateTime.get('year'), + 'month': gpmAllEndDateTime.get('month'), + 'day': gpmAllEndDateTime.get('day') +}) + +# If data ends before requested start, take last data date, +# otherwise use requested date. +precipStartDate = ee.Date(gpmAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('precipStartDate', precipStartDate) + +# 2.3.2 BRDF +# Calculate date of most recent measurement for brdf (of all time). +brdfAllMax = brdfReflect.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +brdfAllEndDate = ee.Date(brdfAllMax.get('max')) +# If data ends before requested start, take last data date, +# otherwise use the requested date. +brdfStartDate = ee.Date(brdfAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('brdfStartDate', brdfStartDate) +print('brdfEndDate', brdfAllEndDate) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 3: Precipitation + +# Section 3.1: Precipitation filtering and dates + +# Filter gpm by date, using modified start if necessary. +gpmFiltered = gpm \ + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select('precipitationCal') + +# Calculate date of most recent measurement for gpm +# (in the modified requested window). +gpmMax = gpmFiltered.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +gpmEndDate = ee.Date(gpmMax.get('max')) +precipEndDate = gpmEndDate +print('precipEndDate ', precipEndDate) + +# Create a list of dates for the precipitation time series. +precipDays = precipEndDate.difference(precipStartDate, 'day') +precipDatesPrep = ee.List.sequence(0, precipDays, 1) + +def makePrecipDates(n): + return precipStartDate.advance(n, 'day') + +precipDates = precipDatesPrep.map(makePrecipDates) + +# Section 3.2: Calculate daily precipitation + +# Function to calculate daily precipitation: +def calcDailyPrecip(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + totprec = gpmFiltered \ + .filterDate(curdate, curdate.advance(1, 'day')) \ + .select('precipitationCal') \ + .sum() \ + .multiply(0.5) \ + .rename('totprec') + + return totprec \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) + +# Map function over list of dates. +dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)) + +# Filter back to the original user requested start date. +dailyPrecip = dailyPrecipExtended \ + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')) + +# Section 3.3: Summarize daily precipitation by woreda + +# Filter precip data for zonal summaries. +precipSummary = dailyPrecip \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) + +# Function to calculate zonal statistics for precipitation by woreda. +def sumZonalPrecip(image): + # To get the doy and year, + # convert the metadata to grids and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each county. + output = image2.select(['year', 'doy', 'totprec']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + +# Map the zonal statistics function over the filtered precip data. +precipWoreda = precipSummary.map(sumZonalPrecip) +# Flatten the results for export. +precipFlat = precipWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 4: Land surface temperature + +# Section 4.1: Calculate LST variables + +# Filter Terra LST by altered LST start date. +# Rarely, but at the end of the year if the last image is late in the year +# with only a few days in its period, it will sometimes not grab +# the next image. Add extra padding to reqEndDate and +# it will be trimmed at the end. +LSTFiltered = LSTTerra8 \ + .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) \ + .filterBounds(amhara) \ + .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night') + +# Filter Terra LST by QA information. +def filterLstQa(image): + qaday = image.select(['QC_Day']) + qanight = image.select(['QC_Night']) + dayshift = qaday.rightShift(6) + nightshift = qanight.rightShift(6) + daymask = dayshift.lte(2) + nightmask = nightshift.lte(2) + outimage = ee.Image(image.select(['LST_Day_1km', + 'LST_Night_1km' + ])) + outmask = ee.Image([daymask, nightmask]) + return outimage.updateMask(outmask) + +LSTFilteredQa = LSTFiltered.map(filterLstQa) + +# Rescale temperature data and convert to degrees Celsius (C). +def rescaleLst(image): + LST_day = image.select('LST_Day_1km') \ + .multiply(0.02) \ + .subtract(273.15) \ + .rename('LST_day') + LST_night = image.select('LST_Night_1km') \ + .multiply(0.02) \ + .subtract(273.15) \ + .rename('LST_night') + LST_mean = image.expression( + '(day + night) / 2', { + 'day': LST_day.select('LST_day'), + 'night': LST_night.select('LST_night') + } + ).rename('LST_mean') + return image.addBands(LST_day) \ + .addBands(LST_night) \ + .addBands(LST_mean) + +LSTVars = LSTFilteredQa.map(rescaleLst) + +# Section 4.2: Calculate daily LST + +# Create list of dates for time series. +LSTRange = LSTVars.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day') +LSTDays = LSTEndDate.difference(LSTStartDate, 'day') +LSTDatesPrep = ee.List.sequence(0, LSTDays, 1) + +def makeLstDates(n): + return LSTStartDate.advance(n, 'day') + +LSTDates = LSTDatesPrep.map(makeLstDates) + +# Function to calculate daily LST by assigning the 8-day composite summary +# to each day in the composite period: +def calcDailyLst(curdate): + curyear = ee.Date(curdate).get('year') + curdoy = ee.Date(curdate).getRelative('day', 'year').add(1) + moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add( + 1) + basedate = ee.Date.fromYMD(curyear, 1, 1) + moddate = basedate.advance(moddoy.subtract(1), 'day') + LST_day = LSTVars \ + .select('LST_day') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_day') + LST_night = LSTVars \ + .select('LST_night') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_night') + LST_mean = LSTVars \ + .select('LST_mean') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_mean') + return LST_day \ + .addBands(LST_night) \ + .addBands(LST_mean) \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) + +# Map the function over the image collection +dailyLstExtended = + ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst)) + +# Filter back to original user requested start date +dailyLst = dailyLstExtended \ + .filterDate(reqStartDate, LSTEndDate.advance(1, 'day')) + +# Section 4.3: Summarize daily LST by woreda + +# Filter LST data for zonal summaries. +LSTSummary = dailyLst \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) +# Function to calculate zonal statistics for LST by woreda: +def sumZonalLst(image): + # To get the doy and year, we convert the metadata to grids + # and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each county. + output = image2 \ + .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + +# Map the zonal statistics function over the filtered LST data. +LSTWoreda = LSTSummary.map(sumZonalLst) +# Flatten the results for export. +LSTFlat = LSTWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16e Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16e Checkpoint.ipynb new file mode 100644 index 0000000..addba45 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16e Checkpoint.ipynb @@ -0,0 +1,604 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.6 Health Applications\n", + "# Checkpoint: A16e\n", + "# Author: Dawn Nekorchuk\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1: Data Import\n", + "woredas = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-6/amhara_woreda_20170207')\n", + "# Create region outer boundary to filter products on.\n", + "amhara = woredas.geometry().bounds()\n", + "gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06')\n", + "LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \\\n", + " .filterDate('2001-06-26', Date.now())\n", + "brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4')\n", + "brdfQa = ee.ImageCollection('MODIS/006/MCD43A2')\n", + "\n", + "# Visualize woredas with black borders and no fill.\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "# Paint all the polygon edges with the same number and width.\n", + "outline = empty.paint({\n", + " 'featureCollection': woredas,\n", + " 'color': 1,\n", + " 'width': 1\n", + "})\n", + "# Add woreda boundaries to the map.\n", + "Map.setCenter(38, 11.5, 7)\n", + "Map.addLayer(outline, {\n", + " 'palette': '000000'\n", + "}, 'Woredas')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 2: Handling of dates\n", + "\n", + "# 2.1 Requested start and end dates.\n", + "reqStartDate = ee.Date('2021-10-01')\n", + "reqEndDate = ee.Date('2021-11-30')\n", + "\n", + "# 2.2 LST Dates\n", + "# LST MODIS is every 8 days, and a user-requested date will likely not match.\n", + "# We want to get the latest previous image date,\n", + "# i.e. the date the closest, but prior to, the requested date.\n", + "# We will filter later.\n", + "# Get date of first image.\n", + "LSTEarliestDate = LSTTerra8.first().date()\n", + "# Filter collection to dates from beginning to requested start date.\n", + "priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate,\n", + " reqStartDate)\n", + "# Get the latest (max) date of this collection of earlier images.\n", + "LSTPrevMax = priorLstImgCol.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTStartDate = ee.Date(LSTPrevMax.get('max'))\n", + "print('LSTStartDate', LSTStartDate)\n", + "\n", + "# 2.3 Last available data dates\n", + "# Different variables have different data lags.\n", + "# Data may not be available in user range.\n", + "# To prevent errors from stopping script,\n", + "# grab last available (if relevant) & filter at end.\n", + "\n", + "# 2.3.1 Precipitation\n", + "# Calculate date of most recent measurement for gpm (of all time).\n", + "gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [\n", + " 'system:time_start'\n", + "])\n", + "gpmAllEndDateTime = ee.Date(gpmAllMax.get('max'))\n", + "# GPM every 30 minutes, so get just date part.\n", + "gpmAllEndDate = ee.Date.fromYMD({\n", + " 'year': gpmAllEndDateTime.get('year'),\n", + " 'month': gpmAllEndDateTime.get('month'),\n", + " 'day': gpmAllEndDateTime.get('day')\n", + "})\n", + "\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use requested date.\n", + "precipStartDate = ee.Date(gpmAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('precipStartDate', precipStartDate)\n", + "\n", + "# 2.3.2 BRDF\n", + "# Calculate date of most recent measurement for brdf (of all time).\n", + "brdfAllMax = brdfReflect.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "brdfAllEndDate = ee.Date(brdfAllMax.get('max'))\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use the requested date.\n", + "brdfStartDate = ee.Date(brdfAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('brdfStartDate', brdfStartDate)\n", + "print('brdfEndDate', brdfAllEndDate)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 3: Precipitation\n", + "\n", + "# Section 3.1: Precipitation filtering and dates\n", + "\n", + "# Filter gpm by date, using modified start if necessary.\n", + "gpmFiltered = gpm \\\n", + " .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select('precipitationCal')\n", + "\n", + "# Calculate date of most recent measurement for gpm\n", + "# (in the modified requested window).\n", + "gpmMax = gpmFiltered.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "gpmEndDate = ee.Date(gpmMax.get('max'))\n", + "precipEndDate = gpmEndDate\n", + "print('precipEndDate ', precipEndDate)\n", + "\n", + "# Create a list of dates for the precipitation time series.\n", + "precipDays = precipEndDate.difference(precipStartDate, 'day')\n", + "precipDatesPrep = ee.List.sequence(0, precipDays, 1)\n", + "\n", + "def makePrecipDates(n):\n", + " return precipStartDate.advance(n, 'day')\n", + "\n", + "precipDates = precipDatesPrep.map(makePrecipDates)\n", + "\n", + "# Section 3.2: Calculate daily precipitation\n", + "\n", + "# Function to calculate daily precipitation:\n", + "def calcDailyPrecip(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " totprec = gpmFiltered \\\n", + " .filterDate(curdate, curdate.advance(1, 'day')) \\\n", + " .select('precipitationCal') \\\n", + " .sum() \\\n", + " .multiply(0.5) \\\n", + " .rename('totprec')\n", + "\n", + " return totprec \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate)\n", + "\n", + "# Map function over list of dates.\n", + "dailyPrecipExtended =\n", + " ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip))\n", + "\n", + "# Filter back to the original user requested start date.\n", + "dailyPrecip = dailyPrecipExtended \\\n", + " .filterDate(reqStartDate, precipEndDate.advance(1, 'day'))\n", + "\n", + "# Section 3.3: Summarize daily precipitation by woreda\n", + "\n", + "# Filter precip data for zonal summaries.\n", + "precipSummary = dailyPrecip \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "\n", + "# Function to calculate zonal statistics for precipitation by woreda.\n", + "def sumZonalPrecip(image):\n", + " # To get the doy and year,\n", + " # convert the metadata to grids and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each county.\n", + " output = image2.select(['year', 'doy', 'totprec']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "# Map the zonal statistics function over the filtered precip data.\n", + "precipWoreda = precipSummary.map(sumZonalPrecip)\n", + "# Flatten the results for export.\n", + "precipFlat = precipWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 4: Land surface temperature\n", + "\n", + "# Section 4.1: Calculate LST variables\n", + "\n", + "# Filter Terra LST by altered LST start date.\n", + "# Rarely, but at the end of the year if the last image is late in the year\n", + "# with only a few days in its period, it will sometimes not grab\n", + "# the next image. Add extra padding to reqEndDate and\n", + "# it will be trimmed at the end.\n", + "LSTFiltered = LSTTerra8 \\\n", + " .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night')\n", + "\n", + "# Filter Terra LST by QA information.\n", + "def filterLstQa(image):\n", + " qaday = image.select(['QC_Day'])\n", + " qanight = image.select(['QC_Night'])\n", + " dayshift = qaday.rightShift(6)\n", + " nightshift = qanight.rightShift(6)\n", + " daymask = dayshift.lte(2)\n", + " nightmask = nightshift.lte(2)\n", + " outimage = ee.Image(image.select(['LST_Day_1km',\n", + " 'LST_Night_1km'\n", + " ]))\n", + " outmask = ee.Image([daymask, nightmask])\n", + " return outimage.updateMask(outmask)\n", + "\n", + "LSTFilteredQa = LSTFiltered.map(filterLstQa)\n", + "\n", + "# Rescale temperature data and convert to degrees Celsius (C).\n", + "def rescaleLst(image):\n", + " LST_day = image.select('LST_Day_1km') \\\n", + " .multiply(0.02) \\\n", + " .subtract(273.15) \\\n", + " .rename('LST_day')\n", + " LST_night = image.select('LST_Night_1km') \\\n", + " .multiply(0.02) \\\n", + " .subtract(273.15) \\\n", + " .rename('LST_night')\n", + " LST_mean = image.expression(\n", + " '(day + night) / 2', {\n", + " 'day': LST_day.select('LST_day'),\n", + " 'night': LST_night.select('LST_night')\n", + " }\n", + " ).rename('LST_mean')\n", + " return image.addBands(LST_day) \\\n", + " .addBands(LST_night) \\\n", + " .addBands(LST_mean)\n", + "\n", + "LSTVars = LSTFilteredQa.map(rescaleLst)\n", + "\n", + "# Section 4.2: Calculate daily LST\n", + "\n", + "# Create list of dates for time series.\n", + "LSTRange = LSTVars.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day')\n", + "LSTDays = LSTEndDate.difference(LSTStartDate, 'day')\n", + "LSTDatesPrep = ee.List.sequence(0, LSTDays, 1)\n", + "\n", + "def makeLstDates(n):\n", + " return LSTStartDate.advance(n, 'day')\n", + "\n", + "LSTDates = LSTDatesPrep.map(makeLstDates)\n", + "\n", + "# Function to calculate daily LST by assigning the 8-day composite summary\n", + "# to each day in the composite period:\n", + "def calcDailyLst(curdate):\n", + " curyear = ee.Date(curdate).get('year')\n", + " curdoy = ee.Date(curdate).getRelative('day', 'year').add(1)\n", + " moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add(\n", + " 1)\n", + " basedate = ee.Date.fromYMD(curyear, 1, 1)\n", + " moddate = basedate.advance(moddoy.subtract(1), 'day')\n", + " LST_day = LSTVars \\\n", + " .select('LST_day') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_day')\n", + " LST_night = LSTVars \\\n", + " .select('LST_night') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_night')\n", + " LST_mean = LSTVars \\\n", + " .select('LST_mean') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_mean')\n", + " return LST_day \\\n", + " .addBands(LST_night) \\\n", + " .addBands(LST_mean) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate)\n", + "\n", + "# Map the function over the image collection\n", + "dailyLstExtended =\n", + " ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst))\n", + "\n", + "# Filter back to original user requested start date\n", + "dailyLst = dailyLstExtended \\\n", + " .filterDate(reqStartDate, LSTEndDate.advance(1, 'day'))\n", + "\n", + "# Section 4.3: Summarize daily LST by woreda\n", + "\n", + "# Filter LST data for zonal summaries.\n", + "LSTSummary = dailyLst \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "# Function to calculate zonal statistics for LST by woreda:\n", + "def sumZonalLst(image):\n", + " # To get the doy and year, we convert the metadata to grids\n", + " # and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each county.\n", + " output = image2 \\\n", + " .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "# Map the zonal statistics function over the filtered LST data.\n", + "LSTWoreda = LSTSummary.map(sumZonalLst)\n", + "# Flatten the results for export.\n", + "LSTFlat = LSTWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 5: Spectral index NDWI\n", + "\n", + "# Section 5.1: Calculate NDWI\n", + "\n", + "# Filter BRDF-Adjusted Reflectance by date.\n", + "brdfReflectVars = brdfReflect \\\n", + " .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select([\n", + " 'Nadir_Reflectance_Band1', 'Nadir_Reflectance_Band2',\n", + " 'Nadir_Reflectance_Band3', 'Nadir_Reflectance_Band4',\n", + " 'Nadir_Reflectance_Band5', 'Nadir_Reflectance_Band6',\n", + " 'Nadir_Reflectance_Band7'\n", + " ],\n", + " ['red', 'nir', 'blue', 'green', 'swir1', 'swir2', 'swir3'])\n", + "\n", + "# Filter BRDF QA by date.\n", + "brdfReflectQa = brdfQa \\\n", + " .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select([\n", + " 'BRDF_Albedo_Band_Quality_Band1',\n", + " 'BRDF_Albedo_Band_Quality_Band2',\n", + " 'BRDF_Albedo_Band_Quality_Band3',\n", + " 'BRDF_Albedo_Band_Quality_Band4',\n", + " 'BRDF_Albedo_Band_Quality_Band5',\n", + " 'BRDF_Albedo_Band_Quality_Band6',\n", + " 'BRDF_Albedo_Band_Quality_Band7',\n", + " 'BRDF_Albedo_LandWaterType'\n", + " ],\n", + " ['qa1', 'qa2', 'qa3', 'qa4', 'qa5', 'qa6', 'qa7', 'water'])\n", + "\n", + "# Join the 2 collections.\n", + "idJoin = ee.Filter.equals({\n", + " 'leftField': 'system:time_end',\n", + " 'rightField': 'system:time_end'\n", + "})\n", + "# Define the join.\n", + "innerJoin = ee.Join.inner('NBAR', 'QA')\n", + "# Apply the join.\n", + "brdfJoined = innerJoin.apply(brdfReflectVars, brdfReflectQa,\n", + " idJoin)\n", + "\n", + "# Add QA bands to the NBAR collection.\n", + "def addQaBands(image):\n", + " nbar = ee.Image(image.get('NBAR'))\n", + " qa = ee.Image(image.get('QA')).select(['qa2'])\n", + " water = ee.Image(image.get('QA')).select(['water'])\n", + " return nbar.addBands([qa, water])\n", + "\n", + "brdfMerged = ee.ImageCollection(brdfJoined.map(addQaBands))\n", + "\n", + "# Function to mask out pixels based on QA and water/land flags.\n", + "def filterBrdf(image):\n", + " # Using QA info for the NIR band.\n", + " qaband = image.select(['qa2'])\n", + " wband = image.select(['water'])\n", + " qamask = qaband.lte(2).And(wband.eq(1))\n", + " nir_r = image.select('nir').multiply(0.0001).rename('nir_r')\n", + " swir2_r = image.select('swir2').multiply(0.0001).rename(\n", + " 'swir2_r')\n", + " return image.addBands(nir_r) \\\n", + " .addBands(swir2_r) \\\n", + " .updateMask(qamask)\n", + "\n", + "brdfFilteredVars = brdfMerged.map(filterBrdf)\n", + "\n", + "# Function to calculate spectral indices:\n", + "def calcBrdfIndices(image):\n", + " curyear = ee.Date(image.get('system:time_start')).get('year')\n", + " curdoy = ee.Date(image.get('system:time_start')) \\\n", + " .getRelative('day', 'year').add(1)\n", + " ndwi6 = image.normalizedDifference(['nir_r', 'swir2_r']) \\\n", + " .rename('ndwi6')\n", + " return image.addBands(ndwi6) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear)\n", + "\n", + "# Map function over image collection.\n", + "brdfFilteredVars = brdfFilteredVars.map(calcBrdfIndices)\n", + "\n", + "# Section 5.2: Calculate daily NDWI\n", + "\n", + "# Create list of dates for full time series.\n", + "brdfRange = brdfFilteredVars.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "brdfEndDate = ee.Date(brdfRange.get('max'))\n", + "brdfDays = brdfEndDate.difference(brdfStartDate, 'day')\n", + "brdfDatesPrep = ee.List.sequence(0, brdfDays, 1)\n", + "\n", + "def makeBrdfDates(n):\n", + " return brdfStartDate.advance(n, 'day')\n", + "\n", + "brdfDates = brdfDatesPrep.map(makeBrdfDates)\n", + "\n", + "# List of dates that exist in BRDF data.\n", + "brdfDatesExist = brdfFilteredVars \\\n", + " .aggregate_array('system:time_start')\n", + "\n", + "# Get daily brdf values.\n", + "def calcDailyBrdfExists(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " brdfTemp = brdfFilteredVars \\\n", + " .filterDate(curdate, curdate.advance(1, 'day'))\n", + " outImg = brdfTemp.first()\n", + " return outImg\n", + "\n", + "dailyBrdfExtExists =\n", + " ee.ImageCollection.fromImages(brdfDatesExist.map(\n", + " calcDailyBrdfExists))\n", + "\n", + "# Create empty results, to fill in dates when BRDF data does not exist.\n", + "def calcDailyBrdfFiller(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " brdfTemp = brdfFilteredVars \\\n", + " .filterDate(curdate, curdate.advance(1, 'day'))\n", + " brdfSize = brdfTemp.size()\n", + " outImg = ee.Image.constant(0).selfMask() \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .rename(['ndvi', 'evi', 'savi', 'ndwi5', 'ndwi6']) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate) \\\n", + " .set('brdfSize', brdfSize)\n", + " return outImg\n", + "\n", + "# Create filler for all dates.\n", + "dailyBrdfExtendedFiller =\n", + " ee.ImageCollection.fromImages(brdfDates.map(calcDailyBrdfFiller))\n", + "# But only used if and when size was 0.\n", + "dailyBrdfExtFillFilt = dailyBrdfExtendedFiller \\\n", + " .filter(ee.Filter.eq('brdfSize', 0))\n", + "# Merge the two collections.\n", + "dailyBrdfExtended = dailyBrdfExtExists \\\n", + " .merge(dailyBrdfExtFillFilt)\n", + "\n", + "# Filter back to original user requested start date.\n", + "dailyBrdf = dailyBrdfExtended \\\n", + " .filterDate(reqStartDate, brdfEndDate.advance(1, 'day'))\n", + "\n", + "# Section 5.3: Summarize daily spectral indices by woreda\n", + "\n", + "# Filter spectral indices for zonal summaries.\n", + "brdfSummary = dailyBrdf \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "\n", + "# Function to calculate zonal statistics for spectral indices by woreda:\n", + "def sumZonalBrdf(image):\n", + " # To get the doy and year, we convert the metadata to grids\n", + " # and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each woreda.\n", + " output = image2.select(['doy', 'year', 'ndwi6']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "\n", + "# Map the zonal statistics function over the filtered spectral index data.\n", + "brdfWoreda = brdfSummary.map(sumZonalBrdf)\n", + "# Flatten the results for export.\n", + "brdfFlat = brdfWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16e Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16e Checkpoint.js new file mode 100644 index 0000000..5359694 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16e Checkpoint.js @@ -0,0 +1,513 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.6 Health Applications +// Checkpoint: A16e +// Author: Dawn Nekorchuk +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1: Data Import +var woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207'); +// Create region outer boundary to filter products on. +var amhara = woredas.geometry().bounds(); +var gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06'); +var LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') + // Due to MCST outage, only use dates after this for this script. + .filterDate('2001-06-26', Date.now()); +var brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4'); +var brdfQa = ee.ImageCollection('MODIS/006/MCD43A2'); + +// Visualize woredas with black borders and no fill. +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); +// Paint all the polygon edges with the same number and width. +var outline = empty.paint({ + featureCollection: woredas, + color: 1, + width: 1 +}); +// Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7); +Map.addLayer(outline, { + palette: '000000' +}, 'Woredas'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 2: Handling of dates + +// 2.1 Requested start and end dates. +var reqStartDate = ee.Date('2021-10-01'); +var reqEndDate = ee.Date('2021-11-30'); + +// 2.2 LST Dates +// LST MODIS is every 8 days, and a user-requested date will likely not match. +// We want to get the latest previous image date, +// i.e. the date the closest, but prior to, the requested date. +// We will filter later. +// Get date of first image. +var LSTEarliestDate = LSTTerra8.first().date(); +// Filter collection to dates from beginning to requested start date. +var priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate); +// Get the latest (max) date of this collection of earlier images. +var LSTPrevMax = priorLstImgCol.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTStartDate = ee.Date(LSTPrevMax.get('max')); +print('LSTStartDate', LSTStartDate); + +// 2.3 Last available data dates +// Different variables have different data lags. +// Data may not be available in user range. +// To prevent errors from stopping script, +// grab last available (if relevant) & filter at end. + +// 2.3.1 Precipitation +// Calculate date of most recent measurement for gpm (of all time). +var gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]); +var gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')); +// GPM every 30 minutes, so get just date part. +var gpmAllEndDate = ee.Date.fromYMD({ + year: gpmAllEndDateTime.get('year'), + month: gpmAllEndDateTime.get('month'), + day: gpmAllEndDateTime.get('day') +}); + +// If data ends before requested start, take last data date, +// otherwise use requested date. +var precipStartDate = ee.Date(gpmAllEndDate.millis() + .min(reqStartDate.millis())); +print('precipStartDate', precipStartDate); + +// 2.3.2 BRDF +// Calculate date of most recent measurement for brdf (of all time). +var brdfAllMax = brdfReflect.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var brdfAllEndDate = ee.Date(brdfAllMax.get('max')); +// If data ends before requested start, take last data date, +// otherwise use the requested date. +var brdfStartDate = ee.Date(brdfAllEndDate.millis() + .min(reqStartDate.millis())); +print('brdfStartDate', brdfStartDate); +print('brdfEndDate', brdfAllEndDate); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 3: Precipitation + +// Section 3.1: Precipitation filtering and dates + +// Filter gpm by date, using modified start if necessary. +var gpmFiltered = gpm + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select('precipitationCal'); + +// Calculate date of most recent measurement for gpm +// (in the modified requested window). +var gpmMax = gpmFiltered.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var gpmEndDate = ee.Date(gpmMax.get('max')); +var precipEndDate = gpmEndDate; +print('precipEndDate ', precipEndDate); + +// Create a list of dates for the precipitation time series. +var precipDays = precipEndDate.difference(precipStartDate, 'day'); +var precipDatesPrep = ee.List.sequence(0, precipDays, 1); + +function makePrecipDates(n) { + return precipStartDate.advance(n, 'day'); +} +var precipDates = precipDatesPrep.map(makePrecipDates); + +// Section 3.2: Calculate daily precipitation + +// Function to calculate daily precipitation: +function calcDailyPrecip(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var totprec = gpmFiltered + .filterDate(curdate, curdate.advance(1, 'day')) + .select('precipitationCal') + .sum() + //every half-hour + .multiply(0.5) + .rename('totprec'); + + return totprec + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate); +} +// Map function over list of dates. +var dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)); + +// Filter back to the original user requested start date. +var dailyPrecip = dailyPrecipExtended + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')); + +// Section 3.3: Summarize daily precipitation by woreda + +// Filter precip data for zonal summaries. +var precipSummary = dailyPrecip + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); + +// Function to calculate zonal statistics for precipitation by woreda. +function sumZonalPrecip(image) { + // To get the doy and year, + // convert the metadata to grids and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each county. + var output = image2.select(['year', 'doy', 'totprec']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} +// Map the zonal statistics function over the filtered precip data. +var precipWoreda = precipSummary.map(sumZonalPrecip); +// Flatten the results for export. +var precipFlat = precipWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 4: Land surface temperature + +// Section 4.1: Calculate LST variables + +// Filter Terra LST by altered LST start date. +// Rarely, but at the end of the year if the last image is late in the year +// with only a few days in its period, it will sometimes not grab +// the next image. Add extra padding to reqEndDate and +// it will be trimmed at the end. +var LSTFiltered = LSTTerra8 + .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) + .filterBounds(amhara) + .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night'); + +// Filter Terra LST by QA information. +function filterLstQa(image) { + var qaday = image.select(['QC_Day']); + var qanight = image.select(['QC_Night']); + var dayshift = qaday.rightShift(6); + var nightshift = qanight.rightShift(6); + var daymask = dayshift.lte(2); + var nightmask = nightshift.lte(2); + var outimage = ee.Image(image.select(['LST_Day_1km', + 'LST_Night_1km' + ])); + var outmask = ee.Image([daymask, nightmask]); + return outimage.updateMask(outmask); +} +var LSTFilteredQa = LSTFiltered.map(filterLstQa); + +// Rescale temperature data and convert to degrees Celsius (C). +function rescaleLst(image) { + var LST_day = image.select('LST_Day_1km') + .multiply(0.02) + .subtract(273.15) + .rename('LST_day'); + var LST_night = image.select('LST_Night_1km') + .multiply(0.02) + .subtract(273.15) + .rename('LST_night'); + var LST_mean = image.expression( + '(day + night) / 2', { + 'day': LST_day.select('LST_day'), + 'night': LST_night.select('LST_night') + } + ).rename('LST_mean'); + return image.addBands(LST_day) + .addBands(LST_night) + .addBands(LST_mean); +} +var LSTVars = LSTFilteredQa.map(rescaleLst); + +// Section 4.2: Calculate daily LST + +// Create list of dates for time series. +var LSTRange = LSTVars.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day'); +var LSTDays = LSTEndDate.difference(LSTStartDate, 'day'); +var LSTDatesPrep = ee.List.sequence(0, LSTDays, 1); + +function makeLstDates(n) { + return LSTStartDate.advance(n, 'day'); +} +var LSTDates = LSTDatesPrep.map(makeLstDates); + +// Function to calculate daily LST by assigning the 8-day composite summary +// to each day in the composite period: +function calcDailyLst(curdate) { + var curyear = ee.Date(curdate).get('year'); + var curdoy = ee.Date(curdate).getRelative('day', 'year').add(1); + var moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add( + 1); + var basedate = ee.Date.fromYMD(curyear, 1, 1); + var moddate = basedate.advance(moddoy.subtract(1), 'day'); + var LST_day = LSTVars + .select('LST_day') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_day'); + var LST_night = LSTVars + .select('LST_night') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_night'); + var LST_mean = LSTVars + .select('LST_mean') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_mean'); + return LST_day + .addBands(LST_night) + .addBands(LST_mean) + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate); +} +// Map the function over the image collection +var dailyLstExtended = + ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst)); + +// Filter back to original user requested start date +var dailyLst = dailyLstExtended + .filterDate(reqStartDate, LSTEndDate.advance(1, 'day')); + +// Section 4.3: Summarize daily LST by woreda + +// Filter LST data for zonal summaries. +var LSTSummary = dailyLst + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); +// Function to calculate zonal statistics for LST by woreda: +function sumZonalLst(image) { + // To get the doy and year, we convert the metadata to grids + // and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each county. + var output = image2 + .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} +// Map the zonal statistics function over the filtered LST data. +var LSTWoreda = LSTSummary.map(sumZonalLst); +// Flatten the results for export. +var LSTFlat = LSTWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 5: Spectral index NDWI + +// Section 5.1: Calculate NDWI + +// Filter BRDF-Adjusted Reflectance by date. +var brdfReflectVars = brdfReflect + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select([ + 'Nadir_Reflectance_Band1', 'Nadir_Reflectance_Band2', + 'Nadir_Reflectance_Band3', 'Nadir_Reflectance_Band4', + 'Nadir_Reflectance_Band5', 'Nadir_Reflectance_Band6', + 'Nadir_Reflectance_Band7' + ], + ['red', 'nir', 'blue', 'green', 'swir1', 'swir2', 'swir3']); + +// Filter BRDF QA by date. +var brdfReflectQa = brdfQa + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select([ + 'BRDF_Albedo_Band_Quality_Band1', + 'BRDF_Albedo_Band_Quality_Band2', + 'BRDF_Albedo_Band_Quality_Band3', + 'BRDF_Albedo_Band_Quality_Band4', + 'BRDF_Albedo_Band_Quality_Band5', + 'BRDF_Albedo_Band_Quality_Band6', + 'BRDF_Albedo_Band_Quality_Band7', + 'BRDF_Albedo_LandWaterType' + ], + ['qa1', 'qa2', 'qa3', 'qa4', 'qa5', 'qa6', 'qa7', 'water']); + +// Join the 2 collections. +var idJoin = ee.Filter.equals({ + leftField: 'system:time_end', + rightField: 'system:time_end' +}); +// Define the join. +var innerJoin = ee.Join.inner('NBAR', 'QA'); +// Apply the join. +var brdfJoined = innerJoin.apply(brdfReflectVars, brdfReflectQa, + idJoin); + +// Add QA bands to the NBAR collection. +function addQaBands(image) { + var nbar = ee.Image(image.get('NBAR')); + var qa = ee.Image(image.get('QA')).select(['qa2']); + var water = ee.Image(image.get('QA')).select(['water']); + return nbar.addBands([qa, water]); +} +var brdfMerged = ee.ImageCollection(brdfJoined.map(addQaBands)); + +// Function to mask out pixels based on QA and water/land flags. +function filterBrdf(image) { + // Using QA info for the NIR band. + var qaband = image.select(['qa2']); + var wband = image.select(['water']); + var qamask = qaband.lte(2).and(wband.eq(1)); + var nir_r = image.select('nir').multiply(0.0001).rename('nir_r'); + var swir2_r = image.select('swir2').multiply(0.0001).rename( + 'swir2_r'); + return image.addBands(nir_r) + .addBands(swir2_r) + .updateMask(qamask); +} +var brdfFilteredVars = brdfMerged.map(filterBrdf); + +// Function to calculate spectral indices: +function calcBrdfIndices(image) { + var curyear = ee.Date(image.get('system:time_start')).get('year'); + var curdoy = ee.Date(image.get('system:time_start')) + .getRelative('day', 'year').add(1); + var ndwi6 = image.normalizedDifference(['nir_r', 'swir2_r']) + .rename('ndwi6'); + return image.addBands(ndwi6) + .set('doy', curdoy) + .set('year', curyear); +} +// Map function over image collection. +brdfFilteredVars = brdfFilteredVars.map(calcBrdfIndices); + +// Section 5.2: Calculate daily NDWI + +// Create list of dates for full time series. +var brdfRange = brdfFilteredVars.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var brdfEndDate = ee.Date(brdfRange.get('max')); +var brdfDays = brdfEndDate.difference(brdfStartDate, 'day'); +var brdfDatesPrep = ee.List.sequence(0, brdfDays, 1); + +function makeBrdfDates(n) { + return brdfStartDate.advance(n, 'day'); +} +var brdfDates = brdfDatesPrep.map(makeBrdfDates); + +// List of dates that exist in BRDF data. +var brdfDatesExist = brdfFilteredVars + .aggregate_array('system:time_start'); + +// Get daily brdf values. +function calcDailyBrdfExists(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var brdfTemp = brdfFilteredVars + .filterDate(curdate, curdate.advance(1, 'day')); + var outImg = brdfTemp.first(); + return outImg; +} +var dailyBrdfExtExists = + ee.ImageCollection.fromImages(brdfDatesExist.map( + calcDailyBrdfExists)); + +// Create empty results, to fill in dates when BRDF data does not exist. +function calcDailyBrdfFiller(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var brdfTemp = brdfFilteredVars + .filterDate(curdate, curdate.advance(1, 'day')); + var brdfSize = brdfTemp.size(); + var outImg = ee.Image.constant(0).selfMask() + .addBands(ee.Image.constant(0).selfMask()) + .addBands(ee.Image.constant(0).selfMask()) + .addBands(ee.Image.constant(0).selfMask()) + .addBands(ee.Image.constant(0).selfMask()) + .rename(['ndvi', 'evi', 'savi', 'ndwi5', 'ndwi6']) + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate) + .set('brdfSize', brdfSize); + return outImg; +} +// Create filler for all dates. +var dailyBrdfExtendedFiller = + ee.ImageCollection.fromImages(brdfDates.map(calcDailyBrdfFiller)); +// But only used if and when size was 0. +var dailyBrdfExtFillFilt = dailyBrdfExtendedFiller + .filter(ee.Filter.eq('brdfSize', 0)); +// Merge the two collections. +var dailyBrdfExtended = dailyBrdfExtExists + .merge(dailyBrdfExtFillFilt); + +// Filter back to original user requested start date. +var dailyBrdf = dailyBrdfExtended + .filterDate(reqStartDate, brdfEndDate.advance(1, 'day')); + +// Section 5.3: Summarize daily spectral indices by woreda + +// Filter spectral indices for zonal summaries. +var brdfSummary = dailyBrdf + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); + +// Function to calculate zonal statistics for spectral indices by woreda: +function sumZonalBrdf(image) { + // To get the doy and year, we convert the metadata to grids + // and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each woreda. + var output = image2.select(['doy', 'year', 'ndwi6']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} + +// Map the zonal statistics function over the filtered spectral index data. +var brdfWoreda = brdfSummary.map(sumZonalBrdf); +// Flatten the results for export. +var brdfFlat = brdfWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16e Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16e Checkpoint.py new file mode 100644 index 0000000..167831f --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16e Checkpoint.py @@ -0,0 +1,517 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.6 Health Applications +# Checkpoint: A16e +# Author: Dawn Nekorchuk +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1: Data Import +woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207') +# Create region outer boundary to filter products on. +amhara = woredas.geometry().bounds() +gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06') +LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \ + .filterDate('2001-06-26', Date.now()) +brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4') +brdfQa = ee.ImageCollection('MODIS/006/MCD43A2') + +# Visualize woredas with black borders and no fill. +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() +# Paint all the polygon edges with the same number and width. +outline = empty.paint({ + 'featureCollection': woredas, + 'color': 1, + 'width': 1 +}) +# Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7) +Map.addLayer(outline, { + 'palette': '000000' +}, 'Woredas') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 2: Handling of dates + +# 2.1 Requested start and end dates. +reqStartDate = ee.Date('2021-10-01') +reqEndDate = ee.Date('2021-11-30') + +# 2.2 LST Dates +# LST MODIS is every 8 days, and a user-requested date will likely not match. +# We want to get the latest previous image date, +# i.e. the date the closest, but prior to, the requested date. +# We will filter later. +# Get date of first image. +LSTEarliestDate = LSTTerra8.first().date() +# Filter collection to dates from beginning to requested start date. +priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate) +# Get the latest (max) date of this collection of earlier images. +LSTPrevMax = priorLstImgCol.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTStartDate = ee.Date(LSTPrevMax.get('max')) +print('LSTStartDate', LSTStartDate) + +# 2.3 Last available data dates +# Different variables have different data lags. +# Data may not be available in user range. +# To prevent errors from stopping script, +# grab last available (if relevant) & filter at end. + +# 2.3.1 Precipitation +# Calculate date of most recent measurement for gpm (of all time). +gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]) +gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')) +# GPM every 30 minutes, so get just date part. +gpmAllEndDate = ee.Date.fromYMD({ + 'year': gpmAllEndDateTime.get('year'), + 'month': gpmAllEndDateTime.get('month'), + 'day': gpmAllEndDateTime.get('day') +}) + +# If data ends before requested start, take last data date, +# otherwise use requested date. +precipStartDate = ee.Date(gpmAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('precipStartDate', precipStartDate) + +# 2.3.2 BRDF +# Calculate date of most recent measurement for brdf (of all time). +brdfAllMax = brdfReflect.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +brdfAllEndDate = ee.Date(brdfAllMax.get('max')) +# If data ends before requested start, take last data date, +# otherwise use the requested date. +brdfStartDate = ee.Date(brdfAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('brdfStartDate', brdfStartDate) +print('brdfEndDate', brdfAllEndDate) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 3: Precipitation + +# Section 3.1: Precipitation filtering and dates + +# Filter gpm by date, using modified start if necessary. +gpmFiltered = gpm \ + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select('precipitationCal') + +# Calculate date of most recent measurement for gpm +# (in the modified requested window). +gpmMax = gpmFiltered.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +gpmEndDate = ee.Date(gpmMax.get('max')) +precipEndDate = gpmEndDate +print('precipEndDate ', precipEndDate) + +# Create a list of dates for the precipitation time series. +precipDays = precipEndDate.difference(precipStartDate, 'day') +precipDatesPrep = ee.List.sequence(0, precipDays, 1) + +def makePrecipDates(n): + return precipStartDate.advance(n, 'day') + +precipDates = precipDatesPrep.map(makePrecipDates) + +# Section 3.2: Calculate daily precipitation + +# Function to calculate daily precipitation: +def calcDailyPrecip(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + totprec = gpmFiltered \ + .filterDate(curdate, curdate.advance(1, 'day')) \ + .select('precipitationCal') \ + .sum() \ + .multiply(0.5) \ + .rename('totprec') + + return totprec \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) + +# Map function over list of dates. +dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)) + +# Filter back to the original user requested start date. +dailyPrecip = dailyPrecipExtended \ + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')) + +# Section 3.3: Summarize daily precipitation by woreda + +# Filter precip data for zonal summaries. +precipSummary = dailyPrecip \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) + +# Function to calculate zonal statistics for precipitation by woreda. +def sumZonalPrecip(image): + # To get the doy and year, + # convert the metadata to grids and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each county. + output = image2.select(['year', 'doy', 'totprec']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + +# Map the zonal statistics function over the filtered precip data. +precipWoreda = precipSummary.map(sumZonalPrecip) +# Flatten the results for export. +precipFlat = precipWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 4: Land surface temperature + +# Section 4.1: Calculate LST variables + +# Filter Terra LST by altered LST start date. +# Rarely, but at the end of the year if the last image is late in the year +# with only a few days in its period, it will sometimes not grab +# the next image. Add extra padding to reqEndDate and +# it will be trimmed at the end. +LSTFiltered = LSTTerra8 \ + .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) \ + .filterBounds(amhara) \ + .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night') + +# Filter Terra LST by QA information. +def filterLstQa(image): + qaday = image.select(['QC_Day']) + qanight = image.select(['QC_Night']) + dayshift = qaday.rightShift(6) + nightshift = qanight.rightShift(6) + daymask = dayshift.lte(2) + nightmask = nightshift.lte(2) + outimage = ee.Image(image.select(['LST_Day_1km', + 'LST_Night_1km' + ])) + outmask = ee.Image([daymask, nightmask]) + return outimage.updateMask(outmask) + +LSTFilteredQa = LSTFiltered.map(filterLstQa) + +# Rescale temperature data and convert to degrees Celsius (C). +def rescaleLst(image): + LST_day = image.select('LST_Day_1km') \ + .multiply(0.02) \ + .subtract(273.15) \ + .rename('LST_day') + LST_night = image.select('LST_Night_1km') \ + .multiply(0.02) \ + .subtract(273.15) \ + .rename('LST_night') + LST_mean = image.expression( + '(day + night) / 2', { + 'day': LST_day.select('LST_day'), + 'night': LST_night.select('LST_night') + } + ).rename('LST_mean') + return image.addBands(LST_day) \ + .addBands(LST_night) \ + .addBands(LST_mean) + +LSTVars = LSTFilteredQa.map(rescaleLst) + +# Section 4.2: Calculate daily LST + +# Create list of dates for time series. +LSTRange = LSTVars.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day') +LSTDays = LSTEndDate.difference(LSTStartDate, 'day') +LSTDatesPrep = ee.List.sequence(0, LSTDays, 1) + +def makeLstDates(n): + return LSTStartDate.advance(n, 'day') + +LSTDates = LSTDatesPrep.map(makeLstDates) + +# Function to calculate daily LST by assigning the 8-day composite summary +# to each day in the composite period: +def calcDailyLst(curdate): + curyear = ee.Date(curdate).get('year') + curdoy = ee.Date(curdate).getRelative('day', 'year').add(1) + moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add( + 1) + basedate = ee.Date.fromYMD(curyear, 1, 1) + moddate = basedate.advance(moddoy.subtract(1), 'day') + LST_day = LSTVars \ + .select('LST_day') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_day') + LST_night = LSTVars \ + .select('LST_night') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_night') + LST_mean = LSTVars \ + .select('LST_mean') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_mean') + return LST_day \ + .addBands(LST_night) \ + .addBands(LST_mean) \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) + +# Map the function over the image collection +dailyLstExtended = + ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst)) + +# Filter back to original user requested start date +dailyLst = dailyLstExtended \ + .filterDate(reqStartDate, LSTEndDate.advance(1, 'day')) + +# Section 4.3: Summarize daily LST by woreda + +# Filter LST data for zonal summaries. +LSTSummary = dailyLst \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) +# Function to calculate zonal statistics for LST by woreda: +def sumZonalLst(image): + # To get the doy and year, we convert the metadata to grids + # and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each county. + output = image2 \ + .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + +# Map the zonal statistics function over the filtered LST data. +LSTWoreda = LSTSummary.map(sumZonalLst) +# Flatten the results for export. +LSTFlat = LSTWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 5: Spectral index NDWI + +# Section 5.1: Calculate NDWI + +# Filter BRDF-Adjusted Reflectance by date. +brdfReflectVars = brdfReflect \ + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select([ + 'Nadir_Reflectance_Band1', 'Nadir_Reflectance_Band2', + 'Nadir_Reflectance_Band3', 'Nadir_Reflectance_Band4', + 'Nadir_Reflectance_Band5', 'Nadir_Reflectance_Band6', + 'Nadir_Reflectance_Band7' + ], + ['red', 'nir', 'blue', 'green', 'swir1', 'swir2', 'swir3']) + +# Filter BRDF QA by date. +brdfReflectQa = brdfQa \ + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select([ + 'BRDF_Albedo_Band_Quality_Band1', + 'BRDF_Albedo_Band_Quality_Band2', + 'BRDF_Albedo_Band_Quality_Band3', + 'BRDF_Albedo_Band_Quality_Band4', + 'BRDF_Albedo_Band_Quality_Band5', + 'BRDF_Albedo_Band_Quality_Band6', + 'BRDF_Albedo_Band_Quality_Band7', + 'BRDF_Albedo_LandWaterType' + ], + ['qa1', 'qa2', 'qa3', 'qa4', 'qa5', 'qa6', 'qa7', 'water']) + +# Join the 2 collections. +idJoin = ee.Filter.equals({ + 'leftField': 'system:time_end', + 'rightField': 'system:time_end' +}) +# Define the join. +innerJoin = ee.Join.inner('NBAR', 'QA') +# Apply the join. +brdfJoined = innerJoin.apply(brdfReflectVars, brdfReflectQa, + idJoin) + +# Add QA bands to the NBAR collection. +def addQaBands(image): + nbar = ee.Image(image.get('NBAR')) + qa = ee.Image(image.get('QA')).select(['qa2']) + water = ee.Image(image.get('QA')).select(['water']) + return nbar.addBands([qa, water]) + +brdfMerged = ee.ImageCollection(brdfJoined.map(addQaBands)) + +# Function to mask out pixels based on QA and water/land flags. +def filterBrdf(image): + # Using QA info for the NIR band. + qaband = image.select(['qa2']) + wband = image.select(['water']) + qamask = qaband.lte(2).And(wband.eq(1)) + nir_r = image.select('nir').multiply(0.0001).rename('nir_r') + swir2_r = image.select('swir2').multiply(0.0001).rename( + 'swir2_r') + return image.addBands(nir_r) \ + .addBands(swir2_r) \ + .updateMask(qamask) + +brdfFilteredVars = brdfMerged.map(filterBrdf) + +# Function to calculate spectral indices: +def calcBrdfIndices(image): + curyear = ee.Date(image.get('system:time_start')).get('year') + curdoy = ee.Date(image.get('system:time_start')) \ + .getRelative('day', 'year').add(1) + ndwi6 = image.normalizedDifference(['nir_r', 'swir2_r']) \ + .rename('ndwi6') + return image.addBands(ndwi6) \ + .set('doy', curdoy) \ + .set('year', curyear) + +# Map function over image collection. +brdfFilteredVars = brdfFilteredVars.map(calcBrdfIndices) + +# Section 5.2: Calculate daily NDWI + +# Create list of dates for full time series. +brdfRange = brdfFilteredVars.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +brdfEndDate = ee.Date(brdfRange.get('max')) +brdfDays = brdfEndDate.difference(brdfStartDate, 'day') +brdfDatesPrep = ee.List.sequence(0, brdfDays, 1) + +def makeBrdfDates(n): + return brdfStartDate.advance(n, 'day') + +brdfDates = brdfDatesPrep.map(makeBrdfDates) + +# List of dates that exist in BRDF data. +brdfDatesExist = brdfFilteredVars \ + .aggregate_array('system:time_start') + +# Get daily brdf values. +def calcDailyBrdfExists(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + brdfTemp = brdfFilteredVars \ + .filterDate(curdate, curdate.advance(1, 'day')) + outImg = brdfTemp.first() + return outImg + +dailyBrdfExtExists = + ee.ImageCollection.fromImages(brdfDatesExist.map( + calcDailyBrdfExists)) + +# Create empty results, to fill in dates when BRDF data does not exist. +def calcDailyBrdfFiller(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + brdfTemp = brdfFilteredVars \ + .filterDate(curdate, curdate.advance(1, 'day')) + brdfSize = brdfTemp.size() + outImg = ee.Image.constant(0).selfMask() \ + .addBands(ee.Image.constant(0).selfMask()) \ + .addBands(ee.Image.constant(0).selfMask()) \ + .addBands(ee.Image.constant(0).selfMask()) \ + .addBands(ee.Image.constant(0).selfMask()) \ + .rename(['ndvi', 'evi', 'savi', 'ndwi5', 'ndwi6']) \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) \ + .set('brdfSize', brdfSize) + return outImg + +# Create filler for all dates. +dailyBrdfExtendedFiller = + ee.ImageCollection.fromImages(brdfDates.map(calcDailyBrdfFiller)) +# But only used if and when size was 0. +dailyBrdfExtFillFilt = dailyBrdfExtendedFiller \ + .filter(ee.Filter.eq('brdfSize', 0)) +# Merge the two collections. +dailyBrdfExtended = dailyBrdfExtExists \ + .merge(dailyBrdfExtFillFilt) + +# Filter back to original user requested start date. +dailyBrdf = dailyBrdfExtended \ + .filterDate(reqStartDate, brdfEndDate.advance(1, 'day')) + +# Section 5.3: Summarize daily spectral indices by woreda + +# Filter spectral indices for zonal summaries. +brdfSummary = dailyBrdf \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) + +# Function to calculate zonal statistics for spectral indices by woreda: +def sumZonalBrdf(image): + # To get the doy and year, we convert the metadata to grids + # and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each woreda. + output = image2.select(['doy', 'year', 'ndwi6']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + + +# Map the zonal statistics function over the filtered spectral index data. +brdfWoreda = brdfSummary.map(sumZonalBrdf) +# Flatten the results for export. +brdfFlat = brdfWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16f Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16f Checkpoint.ipynb new file mode 100644 index 0000000..982a46b --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16f Checkpoint.ipynb @@ -0,0 +1,665 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.6 Health Applications\n", + "# Checkpoint: A16f\n", + "# Author: Dawn Nekorchuk\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1: Data Import\n", + "woredas = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-6/amhara_woreda_20170207')\n", + "# Create region outer boundary to filter products on.\n", + "amhara = woredas.geometry().bounds()\n", + "gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06')\n", + "LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \\\n", + " .filterDate('2001-06-26', Date.now())\n", + "brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4')\n", + "brdfQa = ee.ImageCollection('MODIS/006/MCD43A2')\n", + "\n", + "# Visualize woredas with black borders and no fill.\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "# Paint all the polygon edges with the same number and width.\n", + "outline = empty.paint({\n", + " 'featureCollection': woredas,\n", + " 'color': 1,\n", + " 'width': 1\n", + "})\n", + "# Add woreda boundaries to the map.\n", + "Map.setCenter(38, 11.5, 7)\n", + "Map.addLayer(outline, {\n", + " 'palette': '000000'\n", + "}, 'Woredas')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 2: Handling of dates\n", + "\n", + "# 2.1 Requested start and end dates.\n", + "reqStartDate = ee.Date('2021-10-01')\n", + "reqEndDate = ee.Date('2021-11-30')\n", + "\n", + "# 2.2 LST Dates\n", + "# LST MODIS is every 8 days, and a user-requested date will likely not match.\n", + "# We want to get the latest previous image date,\n", + "# i.e. the date the closest, but prior to, the requested date.\n", + "# We will filter later.\n", + "# Get date of first image.\n", + "LSTEarliestDate = LSTTerra8.first().date()\n", + "# Filter collection to dates from beginning to requested start date.\n", + "priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate,\n", + " reqStartDate)\n", + "# Get the latest (max) date of this collection of earlier images.\n", + "LSTPrevMax = priorLstImgCol.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTStartDate = ee.Date(LSTPrevMax.get('max'))\n", + "print('LSTStartDate', LSTStartDate)\n", + "\n", + "# 2.3 Last available data dates\n", + "# Different variables have different data lags.\n", + "# Data may not be available in user range.\n", + "# To prevent errors from stopping script,\n", + "# grab last available (if relevant) & filter at end.\n", + "\n", + "# 2.3.1 Precipitation\n", + "# Calculate date of most recent measurement for gpm (of all time).\n", + "gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [\n", + " 'system:time_start'\n", + "])\n", + "gpmAllEndDateTime = ee.Date(gpmAllMax.get('max'))\n", + "# GPM every 30 minutes, so get just date part.\n", + "gpmAllEndDate = ee.Date.fromYMD({\n", + " 'year': gpmAllEndDateTime.get('year'),\n", + " 'month': gpmAllEndDateTime.get('month'),\n", + " 'day': gpmAllEndDateTime.get('day')\n", + "})\n", + "\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use requested date.\n", + "precipStartDate = ee.Date(gpmAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('precipStartDate', precipStartDate)\n", + "\n", + "# 2.3.2 BRDF\n", + "# Calculate date of most recent measurement for brdf (of all time).\n", + "brdfAllMax = brdfReflect.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "brdfAllEndDate = ee.Date(brdfAllMax.get('max'))\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use the requested date.\n", + "brdfStartDate = ee.Date(brdfAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('brdfStartDate', brdfStartDate)\n", + "print('brdfEndDate', brdfAllEndDate)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 3: Precipitation\n", + "\n", + "# Section 3.1: Precipitation filtering and dates\n", + "\n", + "# Filter gpm by date, using modified start if necessary.\n", + "gpmFiltered = gpm \\\n", + " .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select('precipitationCal')\n", + "\n", + "# Calculate date of most recent measurement for gpm\n", + "# (in the modified requested window).\n", + "gpmMax = gpmFiltered.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "gpmEndDate = ee.Date(gpmMax.get('max'))\n", + "precipEndDate = gpmEndDate\n", + "print('precipEndDate ', precipEndDate)\n", + "\n", + "# Create a list of dates for the precipitation time series.\n", + "precipDays = precipEndDate.difference(precipStartDate, 'day')\n", + "precipDatesPrep = ee.List.sequence(0, precipDays, 1)\n", + "\n", + "def makePrecipDates(n):\n", + " return precipStartDate.advance(n, 'day')\n", + "\n", + "precipDates = precipDatesPrep.map(makePrecipDates)\n", + "\n", + "# Section 3.2: Calculate daily precipitation\n", + "\n", + "# Function to calculate daily precipitation:\n", + "def calcDailyPrecip(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " totprec = gpmFiltered \\\n", + " .filterDate(curdate, curdate.advance(1, 'day')) \\\n", + " .select('precipitationCal') \\\n", + " .sum() \\\n", + " .multiply(0.5) \\\n", + " .rename('totprec')\n", + "\n", + " return totprec \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate)\n", + "\n", + "# Map function over list of dates.\n", + "dailyPrecipExtended =\n", + " ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip))\n", + "\n", + "# Filter back to the original user requested start date.\n", + "dailyPrecip = dailyPrecipExtended \\\n", + " .filterDate(reqStartDate, precipEndDate.advance(1, 'day'))\n", + "\n", + "# Section 3.3: Summarize daily precipitation by woreda\n", + "\n", + "# Filter precip data for zonal summaries.\n", + "precipSummary = dailyPrecip \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "\n", + "# Function to calculate zonal statistics for precipitation by woreda.\n", + "def sumZonalPrecip(image):\n", + " # To get the doy and year,\n", + " # convert the metadata to grids and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each county.\n", + " output = image2.select(['year', 'doy', 'totprec']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "# Map the zonal statistics function over the filtered precip data.\n", + "precipWoreda = precipSummary.map(sumZonalPrecip)\n", + "# Flatten the results for export.\n", + "precipFlat = precipWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 4: Land surface temperature\n", + "\n", + "# Section 4.1: Calculate LST variables\n", + "\n", + "# Filter Terra LST by altered LST start date.\n", + "# Rarely, but at the end of the year if the last image is late in the year\n", + "# with only a few days in its period, it will sometimes not grab\n", + "# the next image. Add extra padding to reqEndDate and\n", + "# it will be trimmed at the end.\n", + "LSTFiltered = LSTTerra8 \\\n", + " .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night')\n", + "\n", + "# Filter Terra LST by QA information.\n", + "def filterLstQa(image):\n", + " qaday = image.select(['QC_Day'])\n", + " qanight = image.select(['QC_Night'])\n", + " dayshift = qaday.rightShift(6)\n", + " nightshift = qanight.rightShift(6)\n", + " daymask = dayshift.lte(2)\n", + " nightmask = nightshift.lte(2)\n", + " outimage = ee.Image(image.select(['LST_Day_1km',\n", + " 'LST_Night_1km'\n", + " ]))\n", + " outmask = ee.Image([daymask, nightmask])\n", + " return outimage.updateMask(outmask)\n", + "\n", + "LSTFilteredQa = LSTFiltered.map(filterLstQa)\n", + "\n", + "# Rescale temperature data and convert to degrees Celsius (C).\n", + "def rescaleLst(image):\n", + " LST_day = image.select('LST_Day_1km') \\\n", + " .multiply(0.02) \\\n", + " .subtract(273.15) \\\n", + " .rename('LST_day')\n", + " LST_night = image.select('LST_Night_1km') \\\n", + " .multiply(0.02) \\\n", + " .subtract(273.15) \\\n", + " .rename('LST_night')\n", + " LST_mean = image.expression(\n", + " '(day + night) / 2', {\n", + " 'day': LST_day.select('LST_day'),\n", + " 'night': LST_night.select('LST_night')\n", + " }\n", + " ).rename('LST_mean')\n", + " return image.addBands(LST_day) \\\n", + " .addBands(LST_night) \\\n", + " .addBands(LST_mean)\n", + "\n", + "LSTVars = LSTFilteredQa.map(rescaleLst)\n", + "\n", + "# Section 4.2: Calculate daily LST\n", + "\n", + "# Create list of dates for time series.\n", + "LSTRange = LSTVars.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day')\n", + "LSTDays = LSTEndDate.difference(LSTStartDate, 'day')\n", + "LSTDatesPrep = ee.List.sequence(0, LSTDays, 1)\n", + "\n", + "def makeLstDates(n):\n", + " return LSTStartDate.advance(n, 'day')\n", + "\n", + "LSTDates = LSTDatesPrep.map(makeLstDates)\n", + "\n", + "# Function to calculate daily LST by assigning the 8-day composite summary\n", + "# to each day in the composite period:\n", + "def calcDailyLst(curdate):\n", + " curyear = ee.Date(curdate).get('year')\n", + " curdoy = ee.Date(curdate).getRelative('day', 'year').add(1)\n", + " moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add(\n", + " 1)\n", + " basedate = ee.Date.fromYMD(curyear, 1, 1)\n", + " moddate = basedate.advance(moddoy.subtract(1), 'day')\n", + " LST_day = LSTVars \\\n", + " .select('LST_day') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_day')\n", + " LST_night = LSTVars \\\n", + " .select('LST_night') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_night')\n", + " LST_mean = LSTVars \\\n", + " .select('LST_mean') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_mean')\n", + " return LST_day \\\n", + " .addBands(LST_night) \\\n", + " .addBands(LST_mean) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate)\n", + "\n", + "# Map the function over the image collection\n", + "dailyLstExtended =\n", + " ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst))\n", + "\n", + "# Filter back to original user requested start date\n", + "dailyLst = dailyLstExtended \\\n", + " .filterDate(reqStartDate, LSTEndDate.advance(1, 'day'))\n", + "\n", + "# Section 4.3: Summarize daily LST by woreda\n", + "\n", + "# Filter LST data for zonal summaries.\n", + "LSTSummary = dailyLst \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "# Function to calculate zonal statistics for LST by woreda:\n", + "def sumZonalLst(image):\n", + " # To get the doy and year, we convert the metadata to grids\n", + " # and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each county.\n", + " output = image2 \\\n", + " .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "# Map the zonal statistics function over the filtered LST data.\n", + "LSTWoreda = LSTSummary.map(sumZonalLst)\n", + "# Flatten the results for export.\n", + "LSTFlat = LSTWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 5: Spectral index NDWI\n", + "\n", + "# Section 5.1: Calculate NDWI\n", + "\n", + "# Filter BRDF-Adjusted Reflectance by date.\n", + "brdfReflectVars = brdfReflect \\\n", + " .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select([\n", + " 'Nadir_Reflectance_Band1', 'Nadir_Reflectance_Band2',\n", + " 'Nadir_Reflectance_Band3', 'Nadir_Reflectance_Band4',\n", + " 'Nadir_Reflectance_Band5', 'Nadir_Reflectance_Band6',\n", + " 'Nadir_Reflectance_Band7'\n", + " ],\n", + " ['red', 'nir', 'blue', 'green', 'swir1', 'swir2', 'swir3'])\n", + "\n", + "# Filter BRDF QA by date.\n", + "brdfReflectQa = brdfQa \\\n", + " .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select([\n", + " 'BRDF_Albedo_Band_Quality_Band1',\n", + " 'BRDF_Albedo_Band_Quality_Band2',\n", + " 'BRDF_Albedo_Band_Quality_Band3',\n", + " 'BRDF_Albedo_Band_Quality_Band4',\n", + " 'BRDF_Albedo_Band_Quality_Band5',\n", + " 'BRDF_Albedo_Band_Quality_Band6',\n", + " 'BRDF_Albedo_Band_Quality_Band7',\n", + " 'BRDF_Albedo_LandWaterType'\n", + " ],\n", + " ['qa1', 'qa2', 'qa3', 'qa4', 'qa5', 'qa6', 'qa7', 'water'])\n", + "\n", + "# Join the 2 collections.\n", + "idJoin = ee.Filter.equals({\n", + " 'leftField': 'system:time_end',\n", + " 'rightField': 'system:time_end'\n", + "})\n", + "# Define the join.\n", + "innerJoin = ee.Join.inner('NBAR', 'QA')\n", + "# Apply the join.\n", + "brdfJoined = innerJoin.apply(brdfReflectVars, brdfReflectQa,\n", + " idJoin)\n", + "\n", + "# Add QA bands to the NBAR collection.\n", + "def addQaBands(image):\n", + " nbar = ee.Image(image.get('NBAR'))\n", + " qa = ee.Image(image.get('QA')).select(['qa2'])\n", + " water = ee.Image(image.get('QA')).select(['water'])\n", + " return nbar.addBands([qa, water])\n", + "\n", + "brdfMerged = ee.ImageCollection(brdfJoined.map(addQaBands))\n", + "\n", + "# Function to mask out pixels based on QA and water/land flags.\n", + "def filterBrdf(image):\n", + " # Using QA info for the NIR band.\n", + " qaband = image.select(['qa2'])\n", + " wband = image.select(['water'])\n", + " qamask = qaband.lte(2).And(wband.eq(1))\n", + " nir_r = image.select('nir').multiply(0.0001).rename('nir_r')\n", + " swir2_r = image.select('swir2').multiply(0.0001).rename(\n", + " 'swir2_r')\n", + " return image.addBands(nir_r) \\\n", + " .addBands(swir2_r) \\\n", + " .updateMask(qamask)\n", + "\n", + "brdfFilteredVars = brdfMerged.map(filterBrdf)\n", + "\n", + "# Function to calculate spectral indices:\n", + "def calcBrdfIndices(image):\n", + " curyear = ee.Date(image.get('system:time_start')).get('year')\n", + " curdoy = ee.Date(image.get('system:time_start')) \\\n", + " .getRelative('day', 'year').add(1)\n", + " ndwi6 = image.normalizedDifference(['nir_r', 'swir2_r']) \\\n", + " .rename('ndwi6')\n", + " return image.addBands(ndwi6) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear)\n", + "\n", + "# Map function over image collection.\n", + "brdfFilteredVars = brdfFilteredVars.map(calcBrdfIndices)\n", + "\n", + "# Section 5.2: Calculate daily NDWI\n", + "\n", + "# Create list of dates for full time series.\n", + "brdfRange = brdfFilteredVars.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "brdfEndDate = ee.Date(brdfRange.get('max'))\n", + "brdfDays = brdfEndDate.difference(brdfStartDate, 'day')\n", + "brdfDatesPrep = ee.List.sequence(0, brdfDays, 1)\n", + "\n", + "def makeBrdfDates(n):\n", + " return brdfStartDate.advance(n, 'day')\n", + "\n", + "brdfDates = brdfDatesPrep.map(makeBrdfDates)\n", + "\n", + "# List of dates that exist in BRDF data.\n", + "brdfDatesExist = brdfFilteredVars \\\n", + " .aggregate_array('system:time_start')\n", + "\n", + "# Get daily brdf values.\n", + "def calcDailyBrdfExists(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " brdfTemp = brdfFilteredVars \\\n", + " .filterDate(curdate, curdate.advance(1, 'day'))\n", + " outImg = brdfTemp.first()\n", + " return outImg\n", + "\n", + "dailyBrdfExtExists =\n", + " ee.ImageCollection.fromImages(brdfDatesExist.map(\n", + " calcDailyBrdfExists))\n", + "\n", + "# Create empty results, to fill in dates when BRDF data does not exist.\n", + "def calcDailyBrdfFiller(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " brdfTemp = brdfFilteredVars \\\n", + " .filterDate(curdate, curdate.advance(1, 'day'))\n", + " brdfSize = brdfTemp.size()\n", + " outImg = ee.Image.constant(0).selfMask() \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .rename(['ndvi', 'evi', 'savi', 'ndwi5', 'ndwi6']) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate) \\\n", + " .set('brdfSize', brdfSize)\n", + " return outImg\n", + "\n", + "# Create filler for all dates.\n", + "dailyBrdfExtendedFiller =\n", + " ee.ImageCollection.fromImages(brdfDates.map(calcDailyBrdfFiller))\n", + "# But only used if and when size was 0.\n", + "dailyBrdfExtFillFilt = dailyBrdfExtendedFiller \\\n", + " .filter(ee.Filter.eq('brdfSize', 0))\n", + "# Merge the two collections.\n", + "dailyBrdfExtended = dailyBrdfExtExists \\\n", + " .merge(dailyBrdfExtFillFilt)\n", + "\n", + "# Filter back to original user requested start date.\n", + "dailyBrdf = dailyBrdfExtended \\\n", + " .filterDate(reqStartDate, brdfEndDate.advance(1, 'day'))\n", + "\n", + "# Section 5.3: Summarize daily spectral indices by woreda\n", + "\n", + "# Filter spectral indices for zonal summaries.\n", + "brdfSummary = dailyBrdf \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "\n", + "# Function to calculate zonal statistics for spectral indices by woreda:\n", + "def sumZonalBrdf(image):\n", + " # To get the doy and year, we convert the metadata to grids\n", + " # and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each woreda.\n", + " output = image2.select(['doy', 'year', 'ndwi6']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "\n", + "# Map the zonal statistics function over the filtered spectral index data.\n", + "brdfWoreda = brdfSummary.map(sumZonalBrdf)\n", + "# Flatten the results for export.\n", + "brdfFlat = brdfWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 6: Map display of calculated environmental variables\n", + "displayDate = ee.Date('2021-10-01')\n", + "\n", + "precipDisp = dailyPrecip \\\n", + " .filterDate(displayDate, displayDate.advance(1, 'day'))\n", + "brdfDisp = dailyBrdf \\\n", + " .filterDate(displayDate, displayDate.advance(1, 'day'))\n", + "LSTDisp = dailyLst \\\n", + " .filterDate(displayDate, displayDate.advance(1, 'day'))\n", + "\n", + "# Select the image (should be only one) from each collection.\n", + "precipImage = precipDisp.first().select('totprec')\n", + "LSTmImage = LSTDisp.first().select('LST_mean')\n", + "ndwi6Image = brdfDisp.first().select('ndwi6')\n", + "\n", + "# Palettes for environmental variable maps:\n", + "palettePrecip = ['f7fbff', '08306b']\n", + "paletteLst = ['fff5f0', '67000d']\n", + "paletteSpectral = ['ffffe5', '004529']\n", + "\n", + "# Add layers to the map.\n", + "# Show precipitation by default,\n", + "# others hidden until users picks them from layers drop down.\n", + "Map.addLayer({\n", + " 'eeObject': precipImage,\n", + " 'visParams': {\n", + " 'min': 0,\n", + " 'max': 20,\n", + " 'palette': palettePrecip\n", + " },\n", + " 'name': 'Precipitation',\n", + " 'shown': True,\n", + " 'opacity': 0.75\n", + "})\n", + "Map.addLayer({\n", + " 'eeObject': LSTmImage,\n", + " 'visParams': {\n", + " 'min': 0,\n", + " 'max': 40,\n", + " 'palette': paletteLst\n", + " },\n", + " 'name': 'LST Mean',\n", + " 'shown': False,\n", + " 'opacity': 0.75\n", + "})\n", + "Map.addLayer({\n", + " 'eeObject': ndwi6Image,\n", + " 'visParams': {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': paletteSpectral\n", + " },\n", + " 'name': 'NDWI6',\n", + " 'shown': False,\n", + " 'opacity': 0.75\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16f Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16f Checkpoint.js new file mode 100644 index 0000000..f8e7568 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16f Checkpoint.js @@ -0,0 +1,574 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.6 Health Applications +// Checkpoint: A16f +// Author: Dawn Nekorchuk +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1: Data Import +var woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207'); +// Create region outer boundary to filter products on. +var amhara = woredas.geometry().bounds(); +var gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06'); +var LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') + // Due to MCST outage, only use dates after this for this script. + .filterDate('2001-06-26', Date.now()); +var brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4'); +var brdfQa = ee.ImageCollection('MODIS/006/MCD43A2'); + +// Visualize woredas with black borders and no fill. +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); +// Paint all the polygon edges with the same number and width. +var outline = empty.paint({ + featureCollection: woredas, + color: 1, + width: 1 +}); +// Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7); +Map.addLayer(outline, { + palette: '000000' +}, 'Woredas'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 2: Handling of dates + +// 2.1 Requested start and end dates. +var reqStartDate = ee.Date('2021-10-01'); +var reqEndDate = ee.Date('2021-11-30'); + +// 2.2 LST Dates +// LST MODIS is every 8 days, and a user-requested date will likely not match. +// We want to get the latest previous image date, +// i.e. the date the closest, but prior to, the requested date. +// We will filter later. +// Get date of first image. +var LSTEarliestDate = LSTTerra8.first().date(); +// Filter collection to dates from beginning to requested start date. +var priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate); +// Get the latest (max) date of this collection of earlier images. +var LSTPrevMax = priorLstImgCol.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTStartDate = ee.Date(LSTPrevMax.get('max')); +print('LSTStartDate', LSTStartDate); + +// 2.3 Last available data dates +// Different variables have different data lags. +// Data may not be available in user range. +// To prevent errors from stopping script, +// grab last available (if relevant) & filter at end. + +// 2.3.1 Precipitation +// Calculate date of most recent measurement for gpm (of all time). +var gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]); +var gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')); +// GPM every 30 minutes, so get just date part. +var gpmAllEndDate = ee.Date.fromYMD({ + year: gpmAllEndDateTime.get('year'), + month: gpmAllEndDateTime.get('month'), + day: gpmAllEndDateTime.get('day') +}); + +// If data ends before requested start, take last data date, +// otherwise use requested date. +var precipStartDate = ee.Date(gpmAllEndDate.millis() + .min(reqStartDate.millis())); +print('precipStartDate', precipStartDate); + +// 2.3.2 BRDF +// Calculate date of most recent measurement for brdf (of all time). +var brdfAllMax = brdfReflect.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var brdfAllEndDate = ee.Date(brdfAllMax.get('max')); +// If data ends before requested start, take last data date, +// otherwise use the requested date. +var brdfStartDate = ee.Date(brdfAllEndDate.millis() + .min(reqStartDate.millis())); +print('brdfStartDate', brdfStartDate); +print('brdfEndDate', brdfAllEndDate); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 3: Precipitation + +// Section 3.1: Precipitation filtering and dates + +// Filter gpm by date, using modified start if necessary. +var gpmFiltered = gpm + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select('precipitationCal'); + +// Calculate date of most recent measurement for gpm +// (in the modified requested window). +var gpmMax = gpmFiltered.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var gpmEndDate = ee.Date(gpmMax.get('max')); +var precipEndDate = gpmEndDate; +print('precipEndDate ', precipEndDate); + +// Create a list of dates for the precipitation time series. +var precipDays = precipEndDate.difference(precipStartDate, 'day'); +var precipDatesPrep = ee.List.sequence(0, precipDays, 1); + +function makePrecipDates(n) { + return precipStartDate.advance(n, 'day'); +} +var precipDates = precipDatesPrep.map(makePrecipDates); + +// Section 3.2: Calculate daily precipitation + +// Function to calculate daily precipitation: +function calcDailyPrecip(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var totprec = gpmFiltered + .filterDate(curdate, curdate.advance(1, 'day')) + .select('precipitationCal') + .sum() + //every half-hour + .multiply(0.5) + .rename('totprec'); + + return totprec + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate); +} +// Map function over list of dates. +var dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)); + +// Filter back to the original user requested start date. +var dailyPrecip = dailyPrecipExtended + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')); + +// Section 3.3: Summarize daily precipitation by woreda + +// Filter precip data for zonal summaries. +var precipSummary = dailyPrecip + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); + +// Function to calculate zonal statistics for precipitation by woreda. +function sumZonalPrecip(image) { + // To get the doy and year, + // convert the metadata to grids and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each county. + var output = image2.select(['year', 'doy', 'totprec']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} +// Map the zonal statistics function over the filtered precip data. +var precipWoreda = precipSummary.map(sumZonalPrecip); +// Flatten the results for export. +var precipFlat = precipWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 4: Land surface temperature + +// Section 4.1: Calculate LST variables + +// Filter Terra LST by altered LST start date. +// Rarely, but at the end of the year if the last image is late in the year +// with only a few days in its period, it will sometimes not grab +// the next image. Add extra padding to reqEndDate and +// it will be trimmed at the end. +var LSTFiltered = LSTTerra8 + .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) + .filterBounds(amhara) + .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night'); + +// Filter Terra LST by QA information. +function filterLstQa(image) { + var qaday = image.select(['QC_Day']); + var qanight = image.select(['QC_Night']); + var dayshift = qaday.rightShift(6); + var nightshift = qanight.rightShift(6); + var daymask = dayshift.lte(2); + var nightmask = nightshift.lte(2); + var outimage = ee.Image(image.select(['LST_Day_1km', + 'LST_Night_1km' + ])); + var outmask = ee.Image([daymask, nightmask]); + return outimage.updateMask(outmask); +} +var LSTFilteredQa = LSTFiltered.map(filterLstQa); + +// Rescale temperature data and convert to degrees Celsius (C). +function rescaleLst(image) { + var LST_day = image.select('LST_Day_1km') + .multiply(0.02) + .subtract(273.15) + .rename('LST_day'); + var LST_night = image.select('LST_Night_1km') + .multiply(0.02) + .subtract(273.15) + .rename('LST_night'); + var LST_mean = image.expression( + '(day + night) / 2', { + 'day': LST_day.select('LST_day'), + 'night': LST_night.select('LST_night') + } + ).rename('LST_mean'); + return image.addBands(LST_day) + .addBands(LST_night) + .addBands(LST_mean); +} +var LSTVars = LSTFilteredQa.map(rescaleLst); + +// Section 4.2: Calculate daily LST + +// Create list of dates for time series. +var LSTRange = LSTVars.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day'); +var LSTDays = LSTEndDate.difference(LSTStartDate, 'day'); +var LSTDatesPrep = ee.List.sequence(0, LSTDays, 1); + +function makeLstDates(n) { + return LSTStartDate.advance(n, 'day'); +} +var LSTDates = LSTDatesPrep.map(makeLstDates); + +// Function to calculate daily LST by assigning the 8-day composite summary +// to each day in the composite period: +function calcDailyLst(curdate) { + var curyear = ee.Date(curdate).get('year'); + var curdoy = ee.Date(curdate).getRelative('day', 'year').add(1); + var moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add( + 1); + var basedate = ee.Date.fromYMD(curyear, 1, 1); + var moddate = basedate.advance(moddoy.subtract(1), 'day'); + var LST_day = LSTVars + .select('LST_day') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_day'); + var LST_night = LSTVars + .select('LST_night') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_night'); + var LST_mean = LSTVars + .select('LST_mean') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_mean'); + return LST_day + .addBands(LST_night) + .addBands(LST_mean) + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate); +} +// Map the function over the image collection +var dailyLstExtended = + ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst)); + +// Filter back to original user requested start date +var dailyLst = dailyLstExtended + .filterDate(reqStartDate, LSTEndDate.advance(1, 'day')); + +// Section 4.3: Summarize daily LST by woreda + +// Filter LST data for zonal summaries. +var LSTSummary = dailyLst + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); +// Function to calculate zonal statistics for LST by woreda: +function sumZonalLst(image) { + // To get the doy and year, we convert the metadata to grids + // and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each county. + var output = image2 + .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} +// Map the zonal statistics function over the filtered LST data. +var LSTWoreda = LSTSummary.map(sumZonalLst); +// Flatten the results for export. +var LSTFlat = LSTWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 5: Spectral index NDWI + +// Section 5.1: Calculate NDWI + +// Filter BRDF-Adjusted Reflectance by date. +var brdfReflectVars = brdfReflect + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select([ + 'Nadir_Reflectance_Band1', 'Nadir_Reflectance_Band2', + 'Nadir_Reflectance_Band3', 'Nadir_Reflectance_Band4', + 'Nadir_Reflectance_Band5', 'Nadir_Reflectance_Band6', + 'Nadir_Reflectance_Band7' + ], + ['red', 'nir', 'blue', 'green', 'swir1', 'swir2', 'swir3']); + +// Filter BRDF QA by date. +var brdfReflectQa = brdfQa + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select([ + 'BRDF_Albedo_Band_Quality_Band1', + 'BRDF_Albedo_Band_Quality_Band2', + 'BRDF_Albedo_Band_Quality_Band3', + 'BRDF_Albedo_Band_Quality_Band4', + 'BRDF_Albedo_Band_Quality_Band5', + 'BRDF_Albedo_Band_Quality_Band6', + 'BRDF_Albedo_Band_Quality_Band7', + 'BRDF_Albedo_LandWaterType' + ], + ['qa1', 'qa2', 'qa3', 'qa4', 'qa5', 'qa6', 'qa7', 'water']); + +// Join the 2 collections. +var idJoin = ee.Filter.equals({ + leftField: 'system:time_end', + rightField: 'system:time_end' +}); +// Define the join. +var innerJoin = ee.Join.inner('NBAR', 'QA'); +// Apply the join. +var brdfJoined = innerJoin.apply(brdfReflectVars, brdfReflectQa, + idJoin); + +// Add QA bands to the NBAR collection. +function addQaBands(image) { + var nbar = ee.Image(image.get('NBAR')); + var qa = ee.Image(image.get('QA')).select(['qa2']); + var water = ee.Image(image.get('QA')).select(['water']); + return nbar.addBands([qa, water]); +} +var brdfMerged = ee.ImageCollection(brdfJoined.map(addQaBands)); + +// Function to mask out pixels based on QA and water/land flags. +function filterBrdf(image) { + // Using QA info for the NIR band. + var qaband = image.select(['qa2']); + var wband = image.select(['water']); + var qamask = qaband.lte(2).and(wband.eq(1)); + var nir_r = image.select('nir').multiply(0.0001).rename('nir_r'); + var swir2_r = image.select('swir2').multiply(0.0001).rename( + 'swir2_r'); + return image.addBands(nir_r) + .addBands(swir2_r) + .updateMask(qamask); +} +var brdfFilteredVars = brdfMerged.map(filterBrdf); + +// Function to calculate spectral indices: +function calcBrdfIndices(image) { + var curyear = ee.Date(image.get('system:time_start')).get('year'); + var curdoy = ee.Date(image.get('system:time_start')) + .getRelative('day', 'year').add(1); + var ndwi6 = image.normalizedDifference(['nir_r', 'swir2_r']) + .rename('ndwi6'); + return image.addBands(ndwi6) + .set('doy', curdoy) + .set('year', curyear); +} +// Map function over image collection. +brdfFilteredVars = brdfFilteredVars.map(calcBrdfIndices); + +// Section 5.2: Calculate daily NDWI + +// Create list of dates for full time series. +var brdfRange = brdfFilteredVars.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var brdfEndDate = ee.Date(brdfRange.get('max')); +var brdfDays = brdfEndDate.difference(brdfStartDate, 'day'); +var brdfDatesPrep = ee.List.sequence(0, brdfDays, 1); + +function makeBrdfDates(n) { + return brdfStartDate.advance(n, 'day'); +} +var brdfDates = brdfDatesPrep.map(makeBrdfDates); + +// List of dates that exist in BRDF data. +var brdfDatesExist = brdfFilteredVars + .aggregate_array('system:time_start'); + +// Get daily brdf values. +function calcDailyBrdfExists(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var brdfTemp = brdfFilteredVars + .filterDate(curdate, curdate.advance(1, 'day')); + var outImg = brdfTemp.first(); + return outImg; +} +var dailyBrdfExtExists = + ee.ImageCollection.fromImages(brdfDatesExist.map( + calcDailyBrdfExists)); + +// Create empty results, to fill in dates when BRDF data does not exist. +function calcDailyBrdfFiller(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var brdfTemp = brdfFilteredVars + .filterDate(curdate, curdate.advance(1, 'day')); + var brdfSize = brdfTemp.size(); + var outImg = ee.Image.constant(0).selfMask() + .addBands(ee.Image.constant(0).selfMask()) + .addBands(ee.Image.constant(0).selfMask()) + .addBands(ee.Image.constant(0).selfMask()) + .addBands(ee.Image.constant(0).selfMask()) + .rename(['ndvi', 'evi', 'savi', 'ndwi5', 'ndwi6']) + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate) + .set('brdfSize', brdfSize); + return outImg; +} +// Create filler for all dates. +var dailyBrdfExtendedFiller = + ee.ImageCollection.fromImages(brdfDates.map(calcDailyBrdfFiller)); +// But only used if and when size was 0. +var dailyBrdfExtFillFilt = dailyBrdfExtendedFiller + .filter(ee.Filter.eq('brdfSize', 0)); +// Merge the two collections. +var dailyBrdfExtended = dailyBrdfExtExists + .merge(dailyBrdfExtFillFilt); + +// Filter back to original user requested start date. +var dailyBrdf = dailyBrdfExtended + .filterDate(reqStartDate, brdfEndDate.advance(1, 'day')); + +// Section 5.3: Summarize daily spectral indices by woreda + +// Filter spectral indices for zonal summaries. +var brdfSummary = dailyBrdf + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); + +// Function to calculate zonal statistics for spectral indices by woreda: +function sumZonalBrdf(image) { + // To get the doy and year, we convert the metadata to grids + // and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each woreda. + var output = image2.select(['doy', 'year', 'ndwi6']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} + +// Map the zonal statistics function over the filtered spectral index data. +var brdfWoreda = brdfSummary.map(sumZonalBrdf); +// Flatten the results for export. +var brdfFlat = brdfWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 6: Map display of calculated environmental variables +var displayDate = ee.Date('2021-10-01'); + +var precipDisp = dailyPrecip + .filterDate(displayDate, displayDate.advance(1, 'day')); +var brdfDisp = dailyBrdf + .filterDate(displayDate, displayDate.advance(1, 'day')); +var LSTDisp = dailyLst + .filterDate(displayDate, displayDate.advance(1, 'day')); + +// Select the image (should be only one) from each collection. +var precipImage = precipDisp.first().select('totprec'); +var LSTmImage = LSTDisp.first().select('LST_mean'); +var ndwi6Image = brdfDisp.first().select('ndwi6'); + +// Palettes for environmental variable maps: +var palettePrecip = ['f7fbff', '08306b']; +var paletteLst = ['fff5f0', '67000d']; +var paletteSpectral = ['ffffe5', '004529']; + +// Add layers to the map. +// Show precipitation by default, +// others hidden until users picks them from layers drop down. +Map.addLayer({ + eeObject: precipImage, + visParams: { + min: 0, + max: 20, + palette: palettePrecip + }, + name: 'Precipitation', + shown: true, + opacity: 0.75 +}); +Map.addLayer({ + eeObject: LSTmImage, + visParams: { + min: 0, + max: 40, + palette: paletteLst + }, + name: 'LST Mean', + shown: false, + opacity: 0.75 +}); +Map.addLayer({ + eeObject: ndwi6Image, + visParams: { + min: 0, + max: 1, + palette: paletteSpectral + }, + name: 'NDWI6', + shown: false, + opacity: 0.75 +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16f Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16f Checkpoint.py new file mode 100644 index 0000000..47252ab --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16f Checkpoint.py @@ -0,0 +1,578 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.6 Health Applications +# Checkpoint: A16f +# Author: Dawn Nekorchuk +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1: Data Import +woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207') +# Create region outer boundary to filter products on. +amhara = woredas.geometry().bounds() +gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06') +LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \ + .filterDate('2001-06-26', Date.now()) +brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4') +brdfQa = ee.ImageCollection('MODIS/006/MCD43A2') + +# Visualize woredas with black borders and no fill. +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() +# Paint all the polygon edges with the same number and width. +outline = empty.paint({ + 'featureCollection': woredas, + 'color': 1, + 'width': 1 +}) +# Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7) +Map.addLayer(outline, { + 'palette': '000000' +}, 'Woredas') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 2: Handling of dates + +# 2.1 Requested start and end dates. +reqStartDate = ee.Date('2021-10-01') +reqEndDate = ee.Date('2021-11-30') + +# 2.2 LST Dates +# LST MODIS is every 8 days, and a user-requested date will likely not match. +# We want to get the latest previous image date, +# i.e. the date the closest, but prior to, the requested date. +# We will filter later. +# Get date of first image. +LSTEarliestDate = LSTTerra8.first().date() +# Filter collection to dates from beginning to requested start date. +priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate) +# Get the latest (max) date of this collection of earlier images. +LSTPrevMax = priorLstImgCol.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTStartDate = ee.Date(LSTPrevMax.get('max')) +print('LSTStartDate', LSTStartDate) + +# 2.3 Last available data dates +# Different variables have different data lags. +# Data may not be available in user range. +# To prevent errors from stopping script, +# grab last available (if relevant) & filter at end. + +# 2.3.1 Precipitation +# Calculate date of most recent measurement for gpm (of all time). +gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]) +gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')) +# GPM every 30 minutes, so get just date part. +gpmAllEndDate = ee.Date.fromYMD({ + 'year': gpmAllEndDateTime.get('year'), + 'month': gpmAllEndDateTime.get('month'), + 'day': gpmAllEndDateTime.get('day') +}) + +# If data ends before requested start, take last data date, +# otherwise use requested date. +precipStartDate = ee.Date(gpmAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('precipStartDate', precipStartDate) + +# 2.3.2 BRDF +# Calculate date of most recent measurement for brdf (of all time). +brdfAllMax = brdfReflect.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +brdfAllEndDate = ee.Date(brdfAllMax.get('max')) +# If data ends before requested start, take last data date, +# otherwise use the requested date. +brdfStartDate = ee.Date(brdfAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('brdfStartDate', brdfStartDate) +print('brdfEndDate', brdfAllEndDate) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 3: Precipitation + +# Section 3.1: Precipitation filtering and dates + +# Filter gpm by date, using modified start if necessary. +gpmFiltered = gpm \ + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select('precipitationCal') + +# Calculate date of most recent measurement for gpm +# (in the modified requested window). +gpmMax = gpmFiltered.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +gpmEndDate = ee.Date(gpmMax.get('max')) +precipEndDate = gpmEndDate +print('precipEndDate ', precipEndDate) + +# Create a list of dates for the precipitation time series. +precipDays = precipEndDate.difference(precipStartDate, 'day') +precipDatesPrep = ee.List.sequence(0, precipDays, 1) + +def makePrecipDates(n): + return precipStartDate.advance(n, 'day') + +precipDates = precipDatesPrep.map(makePrecipDates) + +# Section 3.2: Calculate daily precipitation + +# Function to calculate daily precipitation: +def calcDailyPrecip(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + totprec = gpmFiltered \ + .filterDate(curdate, curdate.advance(1, 'day')) \ + .select('precipitationCal') \ + .sum() \ + .multiply(0.5) \ + .rename('totprec') + + return totprec \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) + +# Map function over list of dates. +dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)) + +# Filter back to the original user requested start date. +dailyPrecip = dailyPrecipExtended \ + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')) + +# Section 3.3: Summarize daily precipitation by woreda + +# Filter precip data for zonal summaries. +precipSummary = dailyPrecip \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) + +# Function to calculate zonal statistics for precipitation by woreda. +def sumZonalPrecip(image): + # To get the doy and year, + # convert the metadata to grids and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each county. + output = image2.select(['year', 'doy', 'totprec']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + +# Map the zonal statistics function over the filtered precip data. +precipWoreda = precipSummary.map(sumZonalPrecip) +# Flatten the results for export. +precipFlat = precipWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 4: Land surface temperature + +# Section 4.1: Calculate LST variables + +# Filter Terra LST by altered LST start date. +# Rarely, but at the end of the year if the last image is late in the year +# with only a few days in its period, it will sometimes not grab +# the next image. Add extra padding to reqEndDate and +# it will be trimmed at the end. +LSTFiltered = LSTTerra8 \ + .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) \ + .filterBounds(amhara) \ + .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night') + +# Filter Terra LST by QA information. +def filterLstQa(image): + qaday = image.select(['QC_Day']) + qanight = image.select(['QC_Night']) + dayshift = qaday.rightShift(6) + nightshift = qanight.rightShift(6) + daymask = dayshift.lte(2) + nightmask = nightshift.lte(2) + outimage = ee.Image(image.select(['LST_Day_1km', + 'LST_Night_1km' + ])) + outmask = ee.Image([daymask, nightmask]) + return outimage.updateMask(outmask) + +LSTFilteredQa = LSTFiltered.map(filterLstQa) + +# Rescale temperature data and convert to degrees Celsius (C). +def rescaleLst(image): + LST_day = image.select('LST_Day_1km') \ + .multiply(0.02) \ + .subtract(273.15) \ + .rename('LST_day') + LST_night = image.select('LST_Night_1km') \ + .multiply(0.02) \ + .subtract(273.15) \ + .rename('LST_night') + LST_mean = image.expression( + '(day + night) / 2', { + 'day': LST_day.select('LST_day'), + 'night': LST_night.select('LST_night') + } + ).rename('LST_mean') + return image.addBands(LST_day) \ + .addBands(LST_night) \ + .addBands(LST_mean) + +LSTVars = LSTFilteredQa.map(rescaleLst) + +# Section 4.2: Calculate daily LST + +# Create list of dates for time series. +LSTRange = LSTVars.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day') +LSTDays = LSTEndDate.difference(LSTStartDate, 'day') +LSTDatesPrep = ee.List.sequence(0, LSTDays, 1) + +def makeLstDates(n): + return LSTStartDate.advance(n, 'day') + +LSTDates = LSTDatesPrep.map(makeLstDates) + +# Function to calculate daily LST by assigning the 8-day composite summary +# to each day in the composite period: +def calcDailyLst(curdate): + curyear = ee.Date(curdate).get('year') + curdoy = ee.Date(curdate).getRelative('day', 'year').add(1) + moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add( + 1) + basedate = ee.Date.fromYMD(curyear, 1, 1) + moddate = basedate.advance(moddoy.subtract(1), 'day') + LST_day = LSTVars \ + .select('LST_day') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_day') + LST_night = LSTVars \ + .select('LST_night') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_night') + LST_mean = LSTVars \ + .select('LST_mean') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_mean') + return LST_day \ + .addBands(LST_night) \ + .addBands(LST_mean) \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) + +# Map the function over the image collection +dailyLstExtended = + ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst)) + +# Filter back to original user requested start date +dailyLst = dailyLstExtended \ + .filterDate(reqStartDate, LSTEndDate.advance(1, 'day')) + +# Section 4.3: Summarize daily LST by woreda + +# Filter LST data for zonal summaries. +LSTSummary = dailyLst \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) +# Function to calculate zonal statistics for LST by woreda: +def sumZonalLst(image): + # To get the doy and year, we convert the metadata to grids + # and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each county. + output = image2 \ + .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + +# Map the zonal statistics function over the filtered LST data. +LSTWoreda = LSTSummary.map(sumZonalLst) +# Flatten the results for export. +LSTFlat = LSTWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 5: Spectral index NDWI + +# Section 5.1: Calculate NDWI + +# Filter BRDF-Adjusted Reflectance by date. +brdfReflectVars = brdfReflect \ + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select([ + 'Nadir_Reflectance_Band1', 'Nadir_Reflectance_Band2', + 'Nadir_Reflectance_Band3', 'Nadir_Reflectance_Band4', + 'Nadir_Reflectance_Band5', 'Nadir_Reflectance_Band6', + 'Nadir_Reflectance_Band7' + ], + ['red', 'nir', 'blue', 'green', 'swir1', 'swir2', 'swir3']) + +# Filter BRDF QA by date. +brdfReflectQa = brdfQa \ + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select([ + 'BRDF_Albedo_Band_Quality_Band1', + 'BRDF_Albedo_Band_Quality_Band2', + 'BRDF_Albedo_Band_Quality_Band3', + 'BRDF_Albedo_Band_Quality_Band4', + 'BRDF_Albedo_Band_Quality_Band5', + 'BRDF_Albedo_Band_Quality_Band6', + 'BRDF_Albedo_Band_Quality_Band7', + 'BRDF_Albedo_LandWaterType' + ], + ['qa1', 'qa2', 'qa3', 'qa4', 'qa5', 'qa6', 'qa7', 'water']) + +# Join the 2 collections. +idJoin = ee.Filter.equals({ + 'leftField': 'system:time_end', + 'rightField': 'system:time_end' +}) +# Define the join. +innerJoin = ee.Join.inner('NBAR', 'QA') +# Apply the join. +brdfJoined = innerJoin.apply(brdfReflectVars, brdfReflectQa, + idJoin) + +# Add QA bands to the NBAR collection. +def addQaBands(image): + nbar = ee.Image(image.get('NBAR')) + qa = ee.Image(image.get('QA')).select(['qa2']) + water = ee.Image(image.get('QA')).select(['water']) + return nbar.addBands([qa, water]) + +brdfMerged = ee.ImageCollection(brdfJoined.map(addQaBands)) + +# Function to mask out pixels based on QA and water/land flags. +def filterBrdf(image): + # Using QA info for the NIR band. + qaband = image.select(['qa2']) + wband = image.select(['water']) + qamask = qaband.lte(2).And(wband.eq(1)) + nir_r = image.select('nir').multiply(0.0001).rename('nir_r') + swir2_r = image.select('swir2').multiply(0.0001).rename( + 'swir2_r') + return image.addBands(nir_r) \ + .addBands(swir2_r) \ + .updateMask(qamask) + +brdfFilteredVars = brdfMerged.map(filterBrdf) + +# Function to calculate spectral indices: +def calcBrdfIndices(image): + curyear = ee.Date(image.get('system:time_start')).get('year') + curdoy = ee.Date(image.get('system:time_start')) \ + .getRelative('day', 'year').add(1) + ndwi6 = image.normalizedDifference(['nir_r', 'swir2_r']) \ + .rename('ndwi6') + return image.addBands(ndwi6) \ + .set('doy', curdoy) \ + .set('year', curyear) + +# Map function over image collection. +brdfFilteredVars = brdfFilteredVars.map(calcBrdfIndices) + +# Section 5.2: Calculate daily NDWI + +# Create list of dates for full time series. +brdfRange = brdfFilteredVars.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +brdfEndDate = ee.Date(brdfRange.get('max')) +brdfDays = brdfEndDate.difference(brdfStartDate, 'day') +brdfDatesPrep = ee.List.sequence(0, brdfDays, 1) + +def makeBrdfDates(n): + return brdfStartDate.advance(n, 'day') + +brdfDates = brdfDatesPrep.map(makeBrdfDates) + +# List of dates that exist in BRDF data. +brdfDatesExist = brdfFilteredVars \ + .aggregate_array('system:time_start') + +# Get daily brdf values. +def calcDailyBrdfExists(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + brdfTemp = brdfFilteredVars \ + .filterDate(curdate, curdate.advance(1, 'day')) + outImg = brdfTemp.first() + return outImg + +dailyBrdfExtExists = + ee.ImageCollection.fromImages(brdfDatesExist.map( + calcDailyBrdfExists)) + +# Create empty results, to fill in dates when BRDF data does not exist. +def calcDailyBrdfFiller(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + brdfTemp = brdfFilteredVars \ + .filterDate(curdate, curdate.advance(1, 'day')) + brdfSize = brdfTemp.size() + outImg = ee.Image.constant(0).selfMask() \ + .addBands(ee.Image.constant(0).selfMask()) \ + .addBands(ee.Image.constant(0).selfMask()) \ + .addBands(ee.Image.constant(0).selfMask()) \ + .addBands(ee.Image.constant(0).selfMask()) \ + .rename(['ndvi', 'evi', 'savi', 'ndwi5', 'ndwi6']) \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) \ + .set('brdfSize', brdfSize) + return outImg + +# Create filler for all dates. +dailyBrdfExtendedFiller = + ee.ImageCollection.fromImages(brdfDates.map(calcDailyBrdfFiller)) +# But only used if and when size was 0. +dailyBrdfExtFillFilt = dailyBrdfExtendedFiller \ + .filter(ee.Filter.eq('brdfSize', 0)) +# Merge the two collections. +dailyBrdfExtended = dailyBrdfExtExists \ + .merge(dailyBrdfExtFillFilt) + +# Filter back to original user requested start date. +dailyBrdf = dailyBrdfExtended \ + .filterDate(reqStartDate, brdfEndDate.advance(1, 'day')) + +# Section 5.3: Summarize daily spectral indices by woreda + +# Filter spectral indices for zonal summaries. +brdfSummary = dailyBrdf \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) + +# Function to calculate zonal statistics for spectral indices by woreda: +def sumZonalBrdf(image): + # To get the doy and year, we convert the metadata to grids + # and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each woreda. + output = image2.select(['doy', 'year', 'ndwi6']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + + +# Map the zonal statistics function over the filtered spectral index data. +brdfWoreda = brdfSummary.map(sumZonalBrdf) +# Flatten the results for export. +brdfFlat = brdfWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 6: Map display of calculated environmental variables +displayDate = ee.Date('2021-10-01') + +precipDisp = dailyPrecip \ + .filterDate(displayDate, displayDate.advance(1, 'day')) +brdfDisp = dailyBrdf \ + .filterDate(displayDate, displayDate.advance(1, 'day')) +LSTDisp = dailyLst \ + .filterDate(displayDate, displayDate.advance(1, 'day')) + +# Select the image (should be only one) from each collection. +precipImage = precipDisp.first().select('totprec') +LSTmImage = LSTDisp.first().select('LST_mean') +ndwi6Image = brdfDisp.first().select('ndwi6') + +# Palettes for environmental variable maps: +palettePrecip = ['f7fbff', '08306b'] +paletteLst = ['fff5f0', '67000d'] +paletteSpectral = ['ffffe5', '004529'] + +# Add layers to the map. +# Show precipitation by default, +# others hidden until users picks them from layers drop down. +Map.addLayer({ + 'eeObject': precipImage, + 'visParams': { + 'min': 0, + 'max': 20, + 'palette': palettePrecip + }, + 'name': 'Precipitation', + 'shown': True, + 'opacity': 0.75 +}) +Map.addLayer({ + 'eeObject': LSTmImage, + 'visParams': { + 'min': 0, + 'max': 40, + 'palette': paletteLst + }, + 'name': 'LST Mean', + 'shown': False, + 'opacity': 0.75 +}) +Map.addLayer({ + 'eeObject': ndwi6Image, + 'visParams': { + 'min': 0, + 'max': 1, + 'palette': paletteSpectral + }, + 'name': 'NDWI6', + 'shown': False, + 'opacity': 0.75 +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16g Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16g Checkpoint.ipynb new file mode 100644 index 0000000..3d0fc79 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16g Checkpoint.ipynb @@ -0,0 +1,722 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.6 Health Applications\n", + "# Checkpoint: A16g\n", + "# Author: Dawn Nekorchuk\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1: Data Import\n", + "woredas = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-6/amhara_woreda_20170207')\n", + "# Create region outer boundary to filter products on.\n", + "amhara = woredas.geometry().bounds()\n", + "gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06')\n", + "LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \\\n", + " .filterDate('2001-06-26', Date.now())\n", + "brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4')\n", + "brdfQa = ee.ImageCollection('MODIS/006/MCD43A2')\n", + "\n", + "# Visualize woredas with black borders and no fill.\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "# Paint all the polygon edges with the same number and width.\n", + "outline = empty.paint({\n", + " 'featureCollection': woredas,\n", + " 'color': 1,\n", + " 'width': 1\n", + "})\n", + "# Add woreda boundaries to the map.\n", + "Map.setCenter(38, 11.5, 7)\n", + "Map.addLayer(outline, {\n", + " 'palette': '000000'\n", + "}, 'Woredas')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 2: Handling of dates\n", + "\n", + "# 2.1 Requested start and end dates.\n", + "reqStartDate = ee.Date('2021-10-01')\n", + "reqEndDate = ee.Date('2021-11-30')\n", + "\n", + "# 2.2 LST Dates\n", + "# LST MODIS is every 8 days, and a user-requested date will likely not match.\n", + "# We want to get the latest previous image date,\n", + "# i.e. the date the closest, but prior to, the requested date.\n", + "# We will filter later.\n", + "# Get date of first image.\n", + "LSTEarliestDate = LSTTerra8.first().date()\n", + "# Filter collection to dates from beginning to requested start date.\n", + "priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate,\n", + " reqStartDate)\n", + "# Get the latest (max) date of this collection of earlier images.\n", + "LSTPrevMax = priorLstImgCol.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTStartDate = ee.Date(LSTPrevMax.get('max'))\n", + "print('LSTStartDate', LSTStartDate)\n", + "\n", + "# 2.3 Last available data dates\n", + "# Different variables have different data lags.\n", + "# Data may not be available in user range.\n", + "# To prevent errors from stopping script,\n", + "# grab last available (if relevant) & filter at end.\n", + "\n", + "# 2.3.1 Precipitation\n", + "# Calculate date of most recent measurement for gpm (of all time).\n", + "gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [\n", + " 'system:time_start'\n", + "])\n", + "gpmAllEndDateTime = ee.Date(gpmAllMax.get('max'))\n", + "# GPM every 30 minutes, so get just date part.\n", + "gpmAllEndDate = ee.Date.fromYMD({\n", + " 'year': gpmAllEndDateTime.get('year'),\n", + " 'month': gpmAllEndDateTime.get('month'),\n", + " 'day': gpmAllEndDateTime.get('day')\n", + "})\n", + "\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use requested date.\n", + "precipStartDate = ee.Date(gpmAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('precipStartDate', precipStartDate)\n", + "\n", + "# 2.3.2 BRDF\n", + "# Calculate date of most recent measurement for brdf (of all time).\n", + "brdfAllMax = brdfReflect.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "brdfAllEndDate = ee.Date(brdfAllMax.get('max'))\n", + "# If data ends before requested start, take last data date,\n", + "# otherwise use the requested date.\n", + "brdfStartDate = ee.Date(brdfAllEndDate.millis() \\\n", + " .min(reqStartDate.millis()))\n", + "print('brdfStartDate', brdfStartDate)\n", + "print('brdfEndDate', brdfAllEndDate)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 3: Precipitation\n", + "\n", + "# Section 3.1: Precipitation filtering and dates\n", + "\n", + "# Filter gpm by date, using modified start if necessary.\n", + "gpmFiltered = gpm \\\n", + " .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select('precipitationCal')\n", + "\n", + "# Calculate date of most recent measurement for gpm\n", + "# (in the modified requested window).\n", + "gpmMax = gpmFiltered.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "gpmEndDate = ee.Date(gpmMax.get('max'))\n", + "precipEndDate = gpmEndDate\n", + "print('precipEndDate ', precipEndDate)\n", + "\n", + "# Create a list of dates for the precipitation time series.\n", + "precipDays = precipEndDate.difference(precipStartDate, 'day')\n", + "precipDatesPrep = ee.List.sequence(0, precipDays, 1)\n", + "\n", + "def makePrecipDates(n):\n", + " return precipStartDate.advance(n, 'day')\n", + "\n", + "precipDates = precipDatesPrep.map(makePrecipDates)\n", + "\n", + "# Section 3.2: Calculate daily precipitation\n", + "\n", + "# Function to calculate daily precipitation:\n", + "def calcDailyPrecip(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " totprec = gpmFiltered \\\n", + " .filterDate(curdate, curdate.advance(1, 'day')) \\\n", + " .select('precipitationCal') \\\n", + " .sum() \\\n", + " .multiply(0.5) \\\n", + " .rename('totprec')\n", + "\n", + " return totprec \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate)\n", + "\n", + "# Map function over list of dates.\n", + "dailyPrecipExtended =\n", + " ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip))\n", + "\n", + "# Filter back to the original user requested start date.\n", + "dailyPrecip = dailyPrecipExtended \\\n", + " .filterDate(reqStartDate, precipEndDate.advance(1, 'day'))\n", + "\n", + "# Section 3.3: Summarize daily precipitation by woreda\n", + "\n", + "# Filter precip data for zonal summaries.\n", + "precipSummary = dailyPrecip \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "\n", + "# Function to calculate zonal statistics for precipitation by woreda.\n", + "def sumZonalPrecip(image):\n", + " # To get the doy and year,\n", + " # convert the metadata to grids and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each county.\n", + " output = image2.select(['year', 'doy', 'totprec']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "# Map the zonal statistics function over the filtered precip data.\n", + "precipWoreda = precipSummary.map(sumZonalPrecip)\n", + "# Flatten the results for export.\n", + "precipFlat = precipWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 4: Land surface temperature\n", + "\n", + "# Section 4.1: Calculate LST variables\n", + "\n", + "# Filter Terra LST by altered LST start date.\n", + "# Rarely, but at the end of the year if the last image is late in the year\n", + "# with only a few days in its period, it will sometimes not grab\n", + "# the next image. Add extra padding to reqEndDate and\n", + "# it will be trimmed at the end.\n", + "LSTFiltered = LSTTerra8 \\\n", + " .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night')\n", + "\n", + "# Filter Terra LST by QA information.\n", + "def filterLstQa(image):\n", + " qaday = image.select(['QC_Day'])\n", + " qanight = image.select(['QC_Night'])\n", + " dayshift = qaday.rightShift(6)\n", + " nightshift = qanight.rightShift(6)\n", + " daymask = dayshift.lte(2)\n", + " nightmask = nightshift.lte(2)\n", + " outimage = ee.Image(image.select(['LST_Day_1km',\n", + " 'LST_Night_1km'\n", + " ]))\n", + " outmask = ee.Image([daymask, nightmask])\n", + " return outimage.updateMask(outmask)\n", + "\n", + "LSTFilteredQa = LSTFiltered.map(filterLstQa)\n", + "\n", + "# Rescale temperature data and convert to degrees Celsius (C).\n", + "def rescaleLst(image):\n", + " LST_day = image.select('LST_Day_1km') \\\n", + " .multiply(0.02) \\\n", + " .subtract(273.15) \\\n", + " .rename('LST_day')\n", + " LST_night = image.select('LST_Night_1km') \\\n", + " .multiply(0.02) \\\n", + " .subtract(273.15) \\\n", + " .rename('LST_night')\n", + " LST_mean = image.expression(\n", + " '(day + night) / 2', {\n", + " 'day': LST_day.select('LST_day'),\n", + " 'night': LST_night.select('LST_night')\n", + " }\n", + " ).rename('LST_mean')\n", + " return image.addBands(LST_day) \\\n", + " .addBands(LST_night) \\\n", + " .addBands(LST_mean)\n", + "\n", + "LSTVars = LSTFilteredQa.map(rescaleLst)\n", + "\n", + "# Section 4.2: Calculate daily LST\n", + "\n", + "# Create list of dates for time series.\n", + "LSTRange = LSTVars.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day')\n", + "LSTDays = LSTEndDate.difference(LSTStartDate, 'day')\n", + "LSTDatesPrep = ee.List.sequence(0, LSTDays, 1)\n", + "\n", + "def makeLstDates(n):\n", + " return LSTStartDate.advance(n, 'day')\n", + "\n", + "LSTDates = LSTDatesPrep.map(makeLstDates)\n", + "\n", + "# Function to calculate daily LST by assigning the 8-day composite summary\n", + "# to each day in the composite period:\n", + "def calcDailyLst(curdate):\n", + " curyear = ee.Date(curdate).get('year')\n", + " curdoy = ee.Date(curdate).getRelative('day', 'year').add(1)\n", + " moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add(\n", + " 1)\n", + " basedate = ee.Date.fromYMD(curyear, 1, 1)\n", + " moddate = basedate.advance(moddoy.subtract(1), 'day')\n", + " LST_day = LSTVars \\\n", + " .select('LST_day') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_day')\n", + " LST_night = LSTVars \\\n", + " .select('LST_night') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_night')\n", + " LST_mean = LSTVars \\\n", + " .select('LST_mean') \\\n", + " .filterDate(moddate, moddate.advance(1, 'day')) \\\n", + " .first() \\\n", + " .rename('LST_mean')\n", + " return LST_day \\\n", + " .addBands(LST_night) \\\n", + " .addBands(LST_mean) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate)\n", + "\n", + "# Map the function over the image collection\n", + "dailyLstExtended =\n", + " ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst))\n", + "\n", + "# Filter back to original user requested start date\n", + "dailyLst = dailyLstExtended \\\n", + " .filterDate(reqStartDate, LSTEndDate.advance(1, 'day'))\n", + "\n", + "# Section 4.3: Summarize daily LST by woreda\n", + "\n", + "# Filter LST data for zonal summaries.\n", + "LSTSummary = dailyLst \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "# Function to calculate zonal statistics for LST by woreda:\n", + "def sumZonalLst(image):\n", + " # To get the doy and year, we convert the metadata to grids\n", + " # and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each county.\n", + " output = image2 \\\n", + " .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "# Map the zonal statistics function over the filtered LST data.\n", + "LSTWoreda = LSTSummary.map(sumZonalLst)\n", + "# Flatten the results for export.\n", + "LSTFlat = LSTWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 5: Spectral index NDWI\n", + "\n", + "# Section 5.1: Calculate NDWI\n", + "\n", + "# Filter BRDF-Adjusted Reflectance by date.\n", + "brdfReflectVars = brdfReflect \\\n", + " .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select([\n", + " 'Nadir_Reflectance_Band1', 'Nadir_Reflectance_Band2',\n", + " 'Nadir_Reflectance_Band3', 'Nadir_Reflectance_Band4',\n", + " 'Nadir_Reflectance_Band5', 'Nadir_Reflectance_Band6',\n", + " 'Nadir_Reflectance_Band7'\n", + " ],\n", + " ['red', 'nir', 'blue', 'green', 'swir1', 'swir2', 'swir3'])\n", + "\n", + "# Filter BRDF QA by date.\n", + "brdfReflectQa = brdfQa \\\n", + " .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \\\n", + " .filterBounds(amhara) \\\n", + " .select([\n", + " 'BRDF_Albedo_Band_Quality_Band1',\n", + " 'BRDF_Albedo_Band_Quality_Band2',\n", + " 'BRDF_Albedo_Band_Quality_Band3',\n", + " 'BRDF_Albedo_Band_Quality_Band4',\n", + " 'BRDF_Albedo_Band_Quality_Band5',\n", + " 'BRDF_Albedo_Band_Quality_Band6',\n", + " 'BRDF_Albedo_Band_Quality_Band7',\n", + " 'BRDF_Albedo_LandWaterType'\n", + " ],\n", + " ['qa1', 'qa2', 'qa3', 'qa4', 'qa5', 'qa6', 'qa7', 'water'])\n", + "\n", + "# Join the 2 collections.\n", + "idJoin = ee.Filter.equals({\n", + " 'leftField': 'system:time_end',\n", + " 'rightField': 'system:time_end'\n", + "})\n", + "# Define the join.\n", + "innerJoin = ee.Join.inner('NBAR', 'QA')\n", + "# Apply the join.\n", + "brdfJoined = innerJoin.apply(brdfReflectVars, brdfReflectQa,\n", + " idJoin)\n", + "\n", + "# Add QA bands to the NBAR collection.\n", + "def addQaBands(image):\n", + " nbar = ee.Image(image.get('NBAR'))\n", + " qa = ee.Image(image.get('QA')).select(['qa2'])\n", + " water = ee.Image(image.get('QA')).select(['water'])\n", + " return nbar.addBands([qa, water])\n", + "\n", + "brdfMerged = ee.ImageCollection(brdfJoined.map(addQaBands))\n", + "\n", + "# Function to mask out pixels based on QA and water/land flags.\n", + "def filterBrdf(image):\n", + " # Using QA info for the NIR band.\n", + " qaband = image.select(['qa2'])\n", + " wband = image.select(['water'])\n", + " qamask = qaband.lte(2).And(wband.eq(1))\n", + " nir_r = image.select('nir').multiply(0.0001).rename('nir_r')\n", + " swir2_r = image.select('swir2').multiply(0.0001).rename(\n", + " 'swir2_r')\n", + " return image.addBands(nir_r) \\\n", + " .addBands(swir2_r) \\\n", + " .updateMask(qamask)\n", + "\n", + "brdfFilteredVars = brdfMerged.map(filterBrdf)\n", + "\n", + "# Function to calculate spectral indices:\n", + "def calcBrdfIndices(image):\n", + " curyear = ee.Date(image.get('system:time_start')).get('year')\n", + " curdoy = ee.Date(image.get('system:time_start')) \\\n", + " .getRelative('day', 'year').add(1)\n", + " ndwi6 = image.normalizedDifference(['nir_r', 'swir2_r']) \\\n", + " .rename('ndwi6')\n", + " return image.addBands(ndwi6) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear)\n", + "\n", + "# Map function over image collection.\n", + "brdfFilteredVars = brdfFilteredVars.map(calcBrdfIndices)\n", + "\n", + "# Section 5.2: Calculate daily NDWI\n", + "\n", + "# Create list of dates for full time series.\n", + "brdfRange = brdfFilteredVars.reduceColumns({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'selectors': ['system:time_start']\n", + "})\n", + "brdfEndDate = ee.Date(brdfRange.get('max'))\n", + "brdfDays = brdfEndDate.difference(brdfStartDate, 'day')\n", + "brdfDatesPrep = ee.List.sequence(0, brdfDays, 1)\n", + "\n", + "def makeBrdfDates(n):\n", + " return brdfStartDate.advance(n, 'day')\n", + "\n", + "brdfDates = brdfDatesPrep.map(makeBrdfDates)\n", + "\n", + "# List of dates that exist in BRDF data.\n", + "brdfDatesExist = brdfFilteredVars \\\n", + " .aggregate_array('system:time_start')\n", + "\n", + "# Get daily brdf values.\n", + "def calcDailyBrdfExists(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " brdfTemp = brdfFilteredVars \\\n", + " .filterDate(curdate, curdate.advance(1, 'day'))\n", + " outImg = brdfTemp.first()\n", + " return outImg\n", + "\n", + "dailyBrdfExtExists =\n", + " ee.ImageCollection.fromImages(brdfDatesExist.map(\n", + " calcDailyBrdfExists))\n", + "\n", + "# Create empty results, to fill in dates when BRDF data does not exist.\n", + "def calcDailyBrdfFiller(curdate):\n", + " curdate = ee.Date(curdate)\n", + " curyear = curdate.get('year')\n", + " curdoy = curdate.getRelative('day', 'year').add(1)\n", + " brdfTemp = brdfFilteredVars \\\n", + " .filterDate(curdate, curdate.advance(1, 'day'))\n", + " brdfSize = brdfTemp.size()\n", + " outImg = ee.Image.constant(0).selfMask() \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .addBands(ee.Image.constant(0).selfMask()) \\\n", + " .rename(['ndvi', 'evi', 'savi', 'ndwi5', 'ndwi6']) \\\n", + " .set('doy', curdoy) \\\n", + " .set('year', curyear) \\\n", + " .set('system:time_start', curdate) \\\n", + " .set('brdfSize', brdfSize)\n", + " return outImg\n", + "\n", + "# Create filler for all dates.\n", + "dailyBrdfExtendedFiller =\n", + " ee.ImageCollection.fromImages(brdfDates.map(calcDailyBrdfFiller))\n", + "# But only used if and when size was 0.\n", + "dailyBrdfExtFillFilt = dailyBrdfExtendedFiller \\\n", + " .filter(ee.Filter.eq('brdfSize', 0))\n", + "# Merge the two collections.\n", + "dailyBrdfExtended = dailyBrdfExtExists \\\n", + " .merge(dailyBrdfExtFillFilt)\n", + "\n", + "# Filter back to original user requested start date.\n", + "dailyBrdf = dailyBrdfExtended \\\n", + " .filterDate(reqStartDate, brdfEndDate.advance(1, 'day'))\n", + "\n", + "# Section 5.3: Summarize daily spectral indices by woreda\n", + "\n", + "# Filter spectral indices for zonal summaries.\n", + "brdfSummary = dailyBrdf \\\n", + " .filterDate(reqStartDate, reqEndDate.advance(1, 'day'))\n", + "\n", + "# Function to calculate zonal statistics for spectral indices by woreda:\n", + "def sumZonalBrdf(image):\n", + " # To get the doy and year, we convert the metadata to grids\n", + " # and then summarize.\n", + " image2 = image.addBands([\n", + " image.metadata('doy').int(),\n", + " image.metadata('year').int()\n", + " ])\n", + " # Reduce by regions to get zonal means for each woreda.\n", + " output = image2.select(['doy', 'year', 'ndwi6']) \\\n", + " .reduceRegions({\n", + " 'collection': woredas,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000\n", + " })\n", + " return output\n", + "\n", + "\n", + "# Map the zonal statistics function over the filtered spectral index data.\n", + "brdfWoreda = brdfSummary.map(sumZonalBrdf)\n", + "# Flatten the results for export.\n", + "brdfFlat = brdfWoreda.flatten()\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 6: Map display of calculated environmental variables\n", + "displayDate = ee.Date('2021-10-01')\n", + "\n", + "precipDisp = dailyPrecip \\\n", + " .filterDate(displayDate, displayDate.advance(1, 'day'))\n", + "brdfDisp = dailyBrdf \\\n", + " .filterDate(displayDate, displayDate.advance(1, 'day'))\n", + "LSTDisp = dailyLst \\\n", + " .filterDate(displayDate, displayDate.advance(1, 'day'))\n", + "\n", + "# Select the image (should be only one) from each collection.\n", + "precipImage = precipDisp.first().select('totprec')\n", + "LSTmImage = LSTDisp.first().select('LST_mean')\n", + "ndwi6Image = brdfDisp.first().select('ndwi6')\n", + "\n", + "# Palettes for environmental variable maps:\n", + "palettePrecip = ['f7fbff', '08306b']\n", + "paletteLst = ['fff5f0', '67000d']\n", + "paletteSpectral = ['ffffe5', '004529']\n", + "\n", + "# Add layers to the map.\n", + "# Show precipitation by default,\n", + "# others hidden until users picks them from layers drop down.\n", + "Map.addLayer({\n", + " 'eeObject': precipImage,\n", + " 'visParams': {\n", + " 'min': 0,\n", + " 'max': 20,\n", + " 'palette': palettePrecip\n", + " },\n", + " 'name': 'Precipitation',\n", + " 'shown': True,\n", + " 'opacity': 0.75\n", + "})\n", + "Map.addLayer({\n", + " 'eeObject': LSTmImage,\n", + " 'visParams': {\n", + " 'min': 0,\n", + " 'max': 40,\n", + " 'palette': paletteLst\n", + " },\n", + " 'name': 'LST Mean',\n", + " 'shown': False,\n", + " 'opacity': 0.75\n", + "})\n", + "Map.addLayer({\n", + " 'eeObject': ndwi6Image,\n", + " 'visParams': {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': paletteSpectral\n", + " },\n", + " 'name': 'NDWI6',\n", + " 'shown': False,\n", + " 'opacity': 0.75\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Section 7: Exporting\n", + "\n", + "# 7.1 Export naming\n", + "reqStartDateText = reqStartDate.format('yyyy-MM-dd').getInfo()\n", + "\n", + "# Precipitation\n", + "precipPrefix = 'Export_Precip_Data'\n", + "precipLastDate = ee.Date(reqEndDate.millis() \\\n", + " .min(precipEndDate.millis()))\n", + "precipSummaryEndDate = precipLastDate \\\n", + " .format('yyyy-MM-dd').getInfo()\n", + "precipFilename = precipPrefix \\\n", + " .concat('_', reqStartDateText,\n", + " '_', precipSummaryEndDate)\n", + "# LST\n", + "LSTPrefix = 'Export_LST_Data'\n", + "LSTLastDate = ee.Date(reqEndDate.millis() \\\n", + " .min(LSTEndDate.millis()))\n", + "LSTSummaryEndDate = LSTLastDate \\\n", + " .format('yyyy-MM-dd').getInfo()\n", + "LSTFilename = LSTPrefix \\\n", + " .concat('_', reqStartDateText,\n", + " '_', LSTSummaryEndDate)\n", + "# BRDF\n", + "brdfPrefix = 'Export_Spectral_Data'\n", + "brdfLastDate = ee.Date(reqEndDate.millis() \\\n", + " .min(brdfEndDate.millis()))\n", + "brdfSummaryEndDate = brdfLastDate \\\n", + " .format('yyyy-MM-dd').getInfo()\n", + "brdfFilename = brdfPrefix \\\n", + " .concat('_', reqStartDateText,\n", + " '_', brdfSummaryEndDate)\n", + "\n", + "# 7.2 Export flattened tables to Google Drive\n", + "# Need to click 'RUN in the Tasks tab to configure and start each export.\n", + "Export.table.toDrive({\n", + " 'collection': precipFlat,\n", + " 'description': precipFilename,\n", + " 'selectors': ['wid', 'woreda', 'doy', 'year', 'totprec']\n", + "})\n", + "Export.table.toDrive({\n", + " 'collection': LSTFlat,\n", + " 'description': LSTFilename,\n", + " 'selectors': ['wid', 'woreda', 'doy', 'year',\n", + " 'LST_day', 'LST_night', 'LST_mean'\n", + " ]\n", + "})\n", + "Export.table.toDrive({\n", + " 'collection': brdfFlat,\n", + " 'description': brdfFilename,\n", + " 'selectors': ['wid', 'woreda', 'doy', 'year', 'ndwi6']\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16g Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16g Checkpoint.js new file mode 100644 index 0000000..caeb694 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16g Checkpoint.js @@ -0,0 +1,631 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.6 Health Applications +// Checkpoint: A16g +// Author: Dawn Nekorchuk +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1: Data Import +var woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207'); +// Create region outer boundary to filter products on. +var amhara = woredas.geometry().bounds(); +var gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06'); +var LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') + // Due to MCST outage, only use dates after this for this script. + .filterDate('2001-06-26', Date.now()); +var brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4'); +var brdfQa = ee.ImageCollection('MODIS/006/MCD43A2'); + +// Visualize woredas with black borders and no fill. +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); +// Paint all the polygon edges with the same number and width. +var outline = empty.paint({ + featureCollection: woredas, + color: 1, + width: 1 +}); +// Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7); +Map.addLayer(outline, { + palette: '000000' +}, 'Woredas'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 2: Handling of dates + +// 2.1 Requested start and end dates. +var reqStartDate = ee.Date('2021-10-01'); +var reqEndDate = ee.Date('2021-11-30'); + +// 2.2 LST Dates +// LST MODIS is every 8 days, and a user-requested date will likely not match. +// We want to get the latest previous image date, +// i.e. the date the closest, but prior to, the requested date. +// We will filter later. +// Get date of first image. +var LSTEarliestDate = LSTTerra8.first().date(); +// Filter collection to dates from beginning to requested start date. +var priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate); +// Get the latest (max) date of this collection of earlier images. +var LSTPrevMax = priorLstImgCol.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTStartDate = ee.Date(LSTPrevMax.get('max')); +print('LSTStartDate', LSTStartDate); + +// 2.3 Last available data dates +// Different variables have different data lags. +// Data may not be available in user range. +// To prevent errors from stopping script, +// grab last available (if relevant) & filter at end. + +// 2.3.1 Precipitation +// Calculate date of most recent measurement for gpm (of all time). +var gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]); +var gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')); +// GPM every 30 minutes, so get just date part. +var gpmAllEndDate = ee.Date.fromYMD({ + year: gpmAllEndDateTime.get('year'), + month: gpmAllEndDateTime.get('month'), + day: gpmAllEndDateTime.get('day') +}); + +// If data ends before requested start, take last data date, +// otherwise use requested date. +var precipStartDate = ee.Date(gpmAllEndDate.millis() + .min(reqStartDate.millis())); +print('precipStartDate', precipStartDate); + +// 2.3.2 BRDF +// Calculate date of most recent measurement for brdf (of all time). +var brdfAllMax = brdfReflect.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var brdfAllEndDate = ee.Date(brdfAllMax.get('max')); +// If data ends before requested start, take last data date, +// otherwise use the requested date. +var brdfStartDate = ee.Date(brdfAllEndDate.millis() + .min(reqStartDate.millis())); +print('brdfStartDate', brdfStartDate); +print('brdfEndDate', brdfAllEndDate); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 3: Precipitation + +// Section 3.1: Precipitation filtering and dates + +// Filter gpm by date, using modified start if necessary. +var gpmFiltered = gpm + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select('precipitationCal'); + +// Calculate date of most recent measurement for gpm +// (in the modified requested window). +var gpmMax = gpmFiltered.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var gpmEndDate = ee.Date(gpmMax.get('max')); +var precipEndDate = gpmEndDate; +print('precipEndDate ', precipEndDate); + +// Create a list of dates for the precipitation time series. +var precipDays = precipEndDate.difference(precipStartDate, 'day'); +var precipDatesPrep = ee.List.sequence(0, precipDays, 1); + +function makePrecipDates(n) { + return precipStartDate.advance(n, 'day'); +} +var precipDates = precipDatesPrep.map(makePrecipDates); + +// Section 3.2: Calculate daily precipitation + +// Function to calculate daily precipitation: +function calcDailyPrecip(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var totprec = gpmFiltered + .filterDate(curdate, curdate.advance(1, 'day')) + .select('precipitationCal') + .sum() + //every half-hour + .multiply(0.5) + .rename('totprec'); + + return totprec + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate); +} +// Map function over list of dates. +var dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)); + +// Filter back to the original user requested start date. +var dailyPrecip = dailyPrecipExtended + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')); + +// Section 3.3: Summarize daily precipitation by woreda + +// Filter precip data for zonal summaries. +var precipSummary = dailyPrecip + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); + +// Function to calculate zonal statistics for precipitation by woreda. +function sumZonalPrecip(image) { + // To get the doy and year, + // convert the metadata to grids and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each county. + var output = image2.select(['year', 'doy', 'totprec']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} +// Map the zonal statistics function over the filtered precip data. +var precipWoreda = precipSummary.map(sumZonalPrecip); +// Flatten the results for export. +var precipFlat = precipWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 4: Land surface temperature + +// Section 4.1: Calculate LST variables + +// Filter Terra LST by altered LST start date. +// Rarely, but at the end of the year if the last image is late in the year +// with only a few days in its period, it will sometimes not grab +// the next image. Add extra padding to reqEndDate and +// it will be trimmed at the end. +var LSTFiltered = LSTTerra8 + .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) + .filterBounds(amhara) + .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night'); + +// Filter Terra LST by QA information. +function filterLstQa(image) { + var qaday = image.select(['QC_Day']); + var qanight = image.select(['QC_Night']); + var dayshift = qaday.rightShift(6); + var nightshift = qanight.rightShift(6); + var daymask = dayshift.lte(2); + var nightmask = nightshift.lte(2); + var outimage = ee.Image(image.select(['LST_Day_1km', + 'LST_Night_1km' + ])); + var outmask = ee.Image([daymask, nightmask]); + return outimage.updateMask(outmask); +} +var LSTFilteredQa = LSTFiltered.map(filterLstQa); + +// Rescale temperature data and convert to degrees Celsius (C). +function rescaleLst(image) { + var LST_day = image.select('LST_Day_1km') + .multiply(0.02) + .subtract(273.15) + .rename('LST_day'); + var LST_night = image.select('LST_Night_1km') + .multiply(0.02) + .subtract(273.15) + .rename('LST_night'); + var LST_mean = image.expression( + '(day + night) / 2', { + 'day': LST_day.select('LST_day'), + 'night': LST_night.select('LST_night') + } + ).rename('LST_mean'); + return image.addBands(LST_day) + .addBands(LST_night) + .addBands(LST_mean); +} +var LSTVars = LSTFilteredQa.map(rescaleLst); + +// Section 4.2: Calculate daily LST + +// Create list of dates for time series. +var LSTRange = LSTVars.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day'); +var LSTDays = LSTEndDate.difference(LSTStartDate, 'day'); +var LSTDatesPrep = ee.List.sequence(0, LSTDays, 1); + +function makeLstDates(n) { + return LSTStartDate.advance(n, 'day'); +} +var LSTDates = LSTDatesPrep.map(makeLstDates); + +// Function to calculate daily LST by assigning the 8-day composite summary +// to each day in the composite period: +function calcDailyLst(curdate) { + var curyear = ee.Date(curdate).get('year'); + var curdoy = ee.Date(curdate).getRelative('day', 'year').add(1); + var moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add( + 1); + var basedate = ee.Date.fromYMD(curyear, 1, 1); + var moddate = basedate.advance(moddoy.subtract(1), 'day'); + var LST_day = LSTVars + .select('LST_day') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_day'); + var LST_night = LSTVars + .select('LST_night') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_night'); + var LST_mean = LSTVars + .select('LST_mean') + .filterDate(moddate, moddate.advance(1, 'day')) + .first() + .rename('LST_mean'); + return LST_day + .addBands(LST_night) + .addBands(LST_mean) + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate); +} +// Map the function over the image collection +var dailyLstExtended = + ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst)); + +// Filter back to original user requested start date +var dailyLst = dailyLstExtended + .filterDate(reqStartDate, LSTEndDate.advance(1, 'day')); + +// Section 4.3: Summarize daily LST by woreda + +// Filter LST data for zonal summaries. +var LSTSummary = dailyLst + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); +// Function to calculate zonal statistics for LST by woreda: +function sumZonalLst(image) { + // To get the doy and year, we convert the metadata to grids + // and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each county. + var output = image2 + .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} +// Map the zonal statistics function over the filtered LST data. +var LSTWoreda = LSTSummary.map(sumZonalLst); +// Flatten the results for export. +var LSTFlat = LSTWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 5: Spectral index NDWI + +// Section 5.1: Calculate NDWI + +// Filter BRDF-Adjusted Reflectance by date. +var brdfReflectVars = brdfReflect + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select([ + 'Nadir_Reflectance_Band1', 'Nadir_Reflectance_Band2', + 'Nadir_Reflectance_Band3', 'Nadir_Reflectance_Band4', + 'Nadir_Reflectance_Band5', 'Nadir_Reflectance_Band6', + 'Nadir_Reflectance_Band7' + ], + ['red', 'nir', 'blue', 'green', 'swir1', 'swir2', 'swir3']); + +// Filter BRDF QA by date. +var brdfReflectQa = brdfQa + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) + .filterBounds(amhara) + .select([ + 'BRDF_Albedo_Band_Quality_Band1', + 'BRDF_Albedo_Band_Quality_Band2', + 'BRDF_Albedo_Band_Quality_Band3', + 'BRDF_Albedo_Band_Quality_Band4', + 'BRDF_Albedo_Band_Quality_Band5', + 'BRDF_Albedo_Band_Quality_Band6', + 'BRDF_Albedo_Band_Quality_Band7', + 'BRDF_Albedo_LandWaterType' + ], + ['qa1', 'qa2', 'qa3', 'qa4', 'qa5', 'qa6', 'qa7', 'water']); + +// Join the 2 collections. +var idJoin = ee.Filter.equals({ + leftField: 'system:time_end', + rightField: 'system:time_end' +}); +// Define the join. +var innerJoin = ee.Join.inner('NBAR', 'QA'); +// Apply the join. +var brdfJoined = innerJoin.apply(brdfReflectVars, brdfReflectQa, + idJoin); + +// Add QA bands to the NBAR collection. +function addQaBands(image) { + var nbar = ee.Image(image.get('NBAR')); + var qa = ee.Image(image.get('QA')).select(['qa2']); + var water = ee.Image(image.get('QA')).select(['water']); + return nbar.addBands([qa, water]); +} +var brdfMerged = ee.ImageCollection(brdfJoined.map(addQaBands)); + +// Function to mask out pixels based on QA and water/land flags. +function filterBrdf(image) { + // Using QA info for the NIR band. + var qaband = image.select(['qa2']); + var wband = image.select(['water']); + var qamask = qaband.lte(2).and(wband.eq(1)); + var nir_r = image.select('nir').multiply(0.0001).rename('nir_r'); + var swir2_r = image.select('swir2').multiply(0.0001).rename( + 'swir2_r'); + return image.addBands(nir_r) + .addBands(swir2_r) + .updateMask(qamask); +} +var brdfFilteredVars = brdfMerged.map(filterBrdf); + +// Function to calculate spectral indices: +function calcBrdfIndices(image) { + var curyear = ee.Date(image.get('system:time_start')).get('year'); + var curdoy = ee.Date(image.get('system:time_start')) + .getRelative('day', 'year').add(1); + var ndwi6 = image.normalizedDifference(['nir_r', 'swir2_r']) + .rename('ndwi6'); + return image.addBands(ndwi6) + .set('doy', curdoy) + .set('year', curyear); +} +// Map function over image collection. +brdfFilteredVars = brdfFilteredVars.map(calcBrdfIndices); + +// Section 5.2: Calculate daily NDWI + +// Create list of dates for full time series. +var brdfRange = brdfFilteredVars.reduceColumns({ + reducer: ee.Reducer.max(), + selectors: ['system:time_start'] +}); +var brdfEndDate = ee.Date(brdfRange.get('max')); +var brdfDays = brdfEndDate.difference(brdfStartDate, 'day'); +var brdfDatesPrep = ee.List.sequence(0, brdfDays, 1); + +function makeBrdfDates(n) { + return brdfStartDate.advance(n, 'day'); +} +var brdfDates = brdfDatesPrep.map(makeBrdfDates); + +// List of dates that exist in BRDF data. +var brdfDatesExist = brdfFilteredVars + .aggregate_array('system:time_start'); + +// Get daily brdf values. +function calcDailyBrdfExists(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var brdfTemp = brdfFilteredVars + .filterDate(curdate, curdate.advance(1, 'day')); + var outImg = brdfTemp.first(); + return outImg; +} +var dailyBrdfExtExists = + ee.ImageCollection.fromImages(brdfDatesExist.map( + calcDailyBrdfExists)); + +// Create empty results, to fill in dates when BRDF data does not exist. +function calcDailyBrdfFiller(curdate) { + curdate = ee.Date(curdate); + var curyear = curdate.get('year'); + var curdoy = curdate.getRelative('day', 'year').add(1); + var brdfTemp = brdfFilteredVars + .filterDate(curdate, curdate.advance(1, 'day')); + var brdfSize = brdfTemp.size(); + var outImg = ee.Image.constant(0).selfMask() + .addBands(ee.Image.constant(0).selfMask()) + .addBands(ee.Image.constant(0).selfMask()) + .addBands(ee.Image.constant(0).selfMask()) + .addBands(ee.Image.constant(0).selfMask()) + .rename(['ndvi', 'evi', 'savi', 'ndwi5', 'ndwi6']) + .set('doy', curdoy) + .set('year', curyear) + .set('system:time_start', curdate) + .set('brdfSize', brdfSize); + return outImg; +} +// Create filler for all dates. +var dailyBrdfExtendedFiller = + ee.ImageCollection.fromImages(brdfDates.map(calcDailyBrdfFiller)); +// But only used if and when size was 0. +var dailyBrdfExtFillFilt = dailyBrdfExtendedFiller + .filter(ee.Filter.eq('brdfSize', 0)); +// Merge the two collections. +var dailyBrdfExtended = dailyBrdfExtExists + .merge(dailyBrdfExtFillFilt); + +// Filter back to original user requested start date. +var dailyBrdf = dailyBrdfExtended + .filterDate(reqStartDate, brdfEndDate.advance(1, 'day')); + +// Section 5.3: Summarize daily spectral indices by woreda + +// Filter spectral indices for zonal summaries. +var brdfSummary = dailyBrdf + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')); + +// Function to calculate zonal statistics for spectral indices by woreda: +function sumZonalBrdf(image) { + // To get the doy and year, we convert the metadata to grids + // and then summarize. + var image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]); + // Reduce by regions to get zonal means for each woreda. + var output = image2.select(['doy', 'year', 'ndwi6']) + .reduceRegions({ + collection: woredas, + reducer: ee.Reducer.mean(), + scale: 1000 + }); + return output; +} + +// Map the zonal statistics function over the filtered spectral index data. +var brdfWoreda = brdfSummary.map(sumZonalBrdf); +// Flatten the results for export. +var brdfFlat = brdfWoreda.flatten(); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 6: Map display of calculated environmental variables +var displayDate = ee.Date('2021-10-01'); + +var precipDisp = dailyPrecip + .filterDate(displayDate, displayDate.advance(1, 'day')); +var brdfDisp = dailyBrdf + .filterDate(displayDate, displayDate.advance(1, 'day')); +var LSTDisp = dailyLst + .filterDate(displayDate, displayDate.advance(1, 'day')); + +// Select the image (should be only one) from each collection. +var precipImage = precipDisp.first().select('totprec'); +var LSTmImage = LSTDisp.first().select('LST_mean'); +var ndwi6Image = brdfDisp.first().select('ndwi6'); + +// Palettes for environmental variable maps: +var palettePrecip = ['f7fbff', '08306b']; +var paletteLst = ['fff5f0', '67000d']; +var paletteSpectral = ['ffffe5', '004529']; + +// Add layers to the map. +// Show precipitation by default, +// others hidden until users picks them from layers drop down. +Map.addLayer({ + eeObject: precipImage, + visParams: { + min: 0, + max: 20, + palette: palettePrecip + }, + name: 'Precipitation', + shown: true, + opacity: 0.75 +}); +Map.addLayer({ + eeObject: LSTmImage, + visParams: { + min: 0, + max: 40, + palette: paletteLst + }, + name: 'LST Mean', + shown: false, + opacity: 0.75 +}); +Map.addLayer({ + eeObject: ndwi6Image, + visParams: { + min: 0, + max: 1, + palette: paletteSpectral + }, + name: 'NDWI6', + shown: false, + opacity: 0.75 +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Section 7: Exporting + +// 7.1 Export naming +var reqStartDateText = reqStartDate.format('yyyy-MM-dd').getInfo(); + +// Precipitation +var precipPrefix = 'Export_Precip_Data'; +var precipLastDate = ee.Date(reqEndDate.millis() + .min(precipEndDate.millis())); +var precipSummaryEndDate = precipLastDate + .format('yyyy-MM-dd').getInfo(); +var precipFilename = precipPrefix + .concat('_', reqStartDateText, + '_', precipSummaryEndDate); +// LST +var LSTPrefix = 'Export_LST_Data'; +var LSTLastDate = ee.Date(reqEndDate.millis() + .min(LSTEndDate.millis())); +var LSTSummaryEndDate = LSTLastDate + .format('yyyy-MM-dd').getInfo(); +var LSTFilename = LSTPrefix + .concat('_', reqStartDateText, + '_', LSTSummaryEndDate); +// BRDF +var brdfPrefix = 'Export_Spectral_Data'; +var brdfLastDate = ee.Date(reqEndDate.millis() + .min(brdfEndDate.millis())); +var brdfSummaryEndDate = brdfLastDate + .format('yyyy-MM-dd').getInfo(); +var brdfFilename = brdfPrefix + .concat('_', reqStartDateText, + '_', brdfSummaryEndDate); + +// 7.2 Export flattened tables to Google Drive +// Need to click 'RUN in the Tasks tab to configure and start each export. +Export.table.toDrive({ + collection: precipFlat, + description: precipFilename, + selectors: ['wid', 'woreda', 'doy', 'year', 'totprec'] +}); +Export.table.toDrive({ + collection: LSTFlat, + description: LSTFilename, + selectors: ['wid', 'woreda', 'doy', 'year', + 'LST_day', 'LST_night', 'LST_mean' + ] +}); +Export.table.toDrive({ + collection: brdfFlat, + description: brdfFilename, + selectors: ['wid', 'woreda', 'doy', 'year', 'ndwi6'] +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16g Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16g Checkpoint.py new file mode 100644 index 0000000..27c47d9 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16g Checkpoint.py @@ -0,0 +1,635 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.6 Health Applications +# Checkpoint: A16g +# Author: Dawn Nekorchuk +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1: Data Import +woredas = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_woreda_20170207') +# Create region outer boundary to filter products on. +amhara = woredas.geometry().bounds() +gpm = ee.ImageCollection('NASA/GPM_L3/IMERG_V06') +LSTTerra8 = ee.ImageCollection('MODIS/061/MOD11A2') \ + .filterDate('2001-06-26', Date.now()) +brdfReflect = ee.ImageCollection('MODIS/006/MCD43A4') +brdfQa = ee.ImageCollection('MODIS/006/MCD43A2') + +# Visualize woredas with black borders and no fill. +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() +# Paint all the polygon edges with the same number and width. +outline = empty.paint({ + 'featureCollection': woredas, + 'color': 1, + 'width': 1 +}) +# Add woreda boundaries to the map. +Map.setCenter(38, 11.5, 7) +Map.addLayer(outline, { + 'palette': '000000' +}, 'Woredas') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 2: Handling of dates + +# 2.1 Requested start and end dates. +reqStartDate = ee.Date('2021-10-01') +reqEndDate = ee.Date('2021-11-30') + +# 2.2 LST Dates +# LST MODIS is every 8 days, and a user-requested date will likely not match. +# We want to get the latest previous image date, +# i.e. the date the closest, but prior to, the requested date. +# We will filter later. +# Get date of first image. +LSTEarliestDate = LSTTerra8.first().date() +# Filter collection to dates from beginning to requested start date. +priorLstImgCol = LSTTerra8.filterDate(LSTEarliestDate, + reqStartDate) +# Get the latest (max) date of this collection of earlier images. +LSTPrevMax = priorLstImgCol.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTStartDate = ee.Date(LSTPrevMax.get('max')) +print('LSTStartDate', LSTStartDate) + +# 2.3 Last available data dates +# Different variables have different data lags. +# Data may not be available in user range. +# To prevent errors from stopping script, +# grab last available (if relevant) & filter at end. + +# 2.3.1 Precipitation +# Calculate date of most recent measurement for gpm (of all time). +gpmAllMax = gpm.reduceColumns(ee.Reducer.max(), [ + 'system:time_start' +]) +gpmAllEndDateTime = ee.Date(gpmAllMax.get('max')) +# GPM every 30 minutes, so get just date part. +gpmAllEndDate = ee.Date.fromYMD({ + 'year': gpmAllEndDateTime.get('year'), + 'month': gpmAllEndDateTime.get('month'), + 'day': gpmAllEndDateTime.get('day') +}) + +# If data ends before requested start, take last data date, +# otherwise use requested date. +precipStartDate = ee.Date(gpmAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('precipStartDate', precipStartDate) + +# 2.3.2 BRDF +# Calculate date of most recent measurement for brdf (of all time). +brdfAllMax = brdfReflect.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +brdfAllEndDate = ee.Date(brdfAllMax.get('max')) +# If data ends before requested start, take last data date, +# otherwise use the requested date. +brdfStartDate = ee.Date(brdfAllEndDate.millis() \ + .min(reqStartDate.millis())) +print('brdfStartDate', brdfStartDate) +print('brdfEndDate', brdfAllEndDate) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 3: Precipitation + +# Section 3.1: Precipitation filtering and dates + +# Filter gpm by date, using modified start if necessary. +gpmFiltered = gpm \ + .filterDate(precipStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select('precipitationCal') + +# Calculate date of most recent measurement for gpm +# (in the modified requested window). +gpmMax = gpmFiltered.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +gpmEndDate = ee.Date(gpmMax.get('max')) +precipEndDate = gpmEndDate +print('precipEndDate ', precipEndDate) + +# Create a list of dates for the precipitation time series. +precipDays = precipEndDate.difference(precipStartDate, 'day') +precipDatesPrep = ee.List.sequence(0, precipDays, 1) + +def makePrecipDates(n): + return precipStartDate.advance(n, 'day') + +precipDates = precipDatesPrep.map(makePrecipDates) + +# Section 3.2: Calculate daily precipitation + +# Function to calculate daily precipitation: +def calcDailyPrecip(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + totprec = gpmFiltered \ + .filterDate(curdate, curdate.advance(1, 'day')) \ + .select('precipitationCal') \ + .sum() \ + .multiply(0.5) \ + .rename('totprec') + + return totprec \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) + +# Map function over list of dates. +dailyPrecipExtended = + ee.ImageCollection.fromImages(precipDates.map(calcDailyPrecip)) + +# Filter back to the original user requested start date. +dailyPrecip = dailyPrecipExtended \ + .filterDate(reqStartDate, precipEndDate.advance(1, 'day')) + +# Section 3.3: Summarize daily precipitation by woreda + +# Filter precip data for zonal summaries. +precipSummary = dailyPrecip \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) + +# Function to calculate zonal statistics for precipitation by woreda. +def sumZonalPrecip(image): + # To get the doy and year, + # convert the metadata to grids and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each county. + output = image2.select(['year', 'doy', 'totprec']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + +# Map the zonal statistics function over the filtered precip data. +precipWoreda = precipSummary.map(sumZonalPrecip) +# Flatten the results for export. +precipFlat = precipWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 4: Land surface temperature + +# Section 4.1: Calculate LST variables + +# Filter Terra LST by altered LST start date. +# Rarely, but at the end of the year if the last image is late in the year +# with only a few days in its period, it will sometimes not grab +# the next image. Add extra padding to reqEndDate and +# it will be trimmed at the end. +LSTFiltered = LSTTerra8 \ + .filterDate(LSTStartDate, reqEndDate.advance(8, 'day')) \ + .filterBounds(amhara) \ + .select('LST_Day_1km', 'QC_Day', 'LST_Night_1km', 'QC_Night') + +# Filter Terra LST by QA information. +def filterLstQa(image): + qaday = image.select(['QC_Day']) + qanight = image.select(['QC_Night']) + dayshift = qaday.rightShift(6) + nightshift = qanight.rightShift(6) + daymask = dayshift.lte(2) + nightmask = nightshift.lte(2) + outimage = ee.Image(image.select(['LST_Day_1km', + 'LST_Night_1km' + ])) + outmask = ee.Image([daymask, nightmask]) + return outimage.updateMask(outmask) + +LSTFilteredQa = LSTFiltered.map(filterLstQa) + +# Rescale temperature data and convert to degrees Celsius (C). +def rescaleLst(image): + LST_day = image.select('LST_Day_1km') \ + .multiply(0.02) \ + .subtract(273.15) \ + .rename('LST_day') + LST_night = image.select('LST_Night_1km') \ + .multiply(0.02) \ + .subtract(273.15) \ + .rename('LST_night') + LST_mean = image.expression( + '(day + night) / 2', { + 'day': LST_day.select('LST_day'), + 'night': LST_night.select('LST_night') + } + ).rename('LST_mean') + return image.addBands(LST_day) \ + .addBands(LST_night) \ + .addBands(LST_mean) + +LSTVars = LSTFilteredQa.map(rescaleLst) + +# Section 4.2: Calculate daily LST + +# Create list of dates for time series. +LSTRange = LSTVars.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +LSTEndDate = ee.Date(LSTRange.get('max')).advance(7, 'day') +LSTDays = LSTEndDate.difference(LSTStartDate, 'day') +LSTDatesPrep = ee.List.sequence(0, LSTDays, 1) + +def makeLstDates(n): + return LSTStartDate.advance(n, 'day') + +LSTDates = LSTDatesPrep.map(makeLstDates) + +# Function to calculate daily LST by assigning the 8-day composite summary +# to each day in the composite period: +def calcDailyLst(curdate): + curyear = ee.Date(curdate).get('year') + curdoy = ee.Date(curdate).getRelative('day', 'year').add(1) + moddoy = curdoy.divide(8).ceil().subtract(1).multiply(8).add( + 1) + basedate = ee.Date.fromYMD(curyear, 1, 1) + moddate = basedate.advance(moddoy.subtract(1), 'day') + LST_day = LSTVars \ + .select('LST_day') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_day') + LST_night = LSTVars \ + .select('LST_night') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_night') + LST_mean = LSTVars \ + .select('LST_mean') \ + .filterDate(moddate, moddate.advance(1, 'day')) \ + .first() \ + .rename('LST_mean') + return LST_day \ + .addBands(LST_night) \ + .addBands(LST_mean) \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) + +# Map the function over the image collection +dailyLstExtended = + ee.ImageCollection.fromImages(LSTDates.map(calcDailyLst)) + +# Filter back to original user requested start date +dailyLst = dailyLstExtended \ + .filterDate(reqStartDate, LSTEndDate.advance(1, 'day')) + +# Section 4.3: Summarize daily LST by woreda + +# Filter LST data for zonal summaries. +LSTSummary = dailyLst \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) +# Function to calculate zonal statistics for LST by woreda: +def sumZonalLst(image): + # To get the doy and year, we convert the metadata to grids + # and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each county. + output = image2 \ + .select(['doy', 'year', 'LST_day', 'LST_night', 'LST_mean']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + +# Map the zonal statistics function over the filtered LST data. +LSTWoreda = LSTSummary.map(sumZonalLst) +# Flatten the results for export. +LSTFlat = LSTWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 5: Spectral index NDWI + +# Section 5.1: Calculate NDWI + +# Filter BRDF-Adjusted Reflectance by date. +brdfReflectVars = brdfReflect \ + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select([ + 'Nadir_Reflectance_Band1', 'Nadir_Reflectance_Band2', + 'Nadir_Reflectance_Band3', 'Nadir_Reflectance_Band4', + 'Nadir_Reflectance_Band5', 'Nadir_Reflectance_Band6', + 'Nadir_Reflectance_Band7' + ], + ['red', 'nir', 'blue', 'green', 'swir1', 'swir2', 'swir3']) + +# Filter BRDF QA by date. +brdfReflectQa = brdfQa \ + .filterDate(brdfStartDate, reqEndDate.advance(1, 'day')) \ + .filterBounds(amhara) \ + .select([ + 'BRDF_Albedo_Band_Quality_Band1', + 'BRDF_Albedo_Band_Quality_Band2', + 'BRDF_Albedo_Band_Quality_Band3', + 'BRDF_Albedo_Band_Quality_Band4', + 'BRDF_Albedo_Band_Quality_Band5', + 'BRDF_Albedo_Band_Quality_Band6', + 'BRDF_Albedo_Band_Quality_Band7', + 'BRDF_Albedo_LandWaterType' + ], + ['qa1', 'qa2', 'qa3', 'qa4', 'qa5', 'qa6', 'qa7', 'water']) + +# Join the 2 collections. +idJoin = ee.Filter.equals({ + 'leftField': 'system:time_end', + 'rightField': 'system:time_end' +}) +# Define the join. +innerJoin = ee.Join.inner('NBAR', 'QA') +# Apply the join. +brdfJoined = innerJoin.apply(brdfReflectVars, brdfReflectQa, + idJoin) + +# Add QA bands to the NBAR collection. +def addQaBands(image): + nbar = ee.Image(image.get('NBAR')) + qa = ee.Image(image.get('QA')).select(['qa2']) + water = ee.Image(image.get('QA')).select(['water']) + return nbar.addBands([qa, water]) + +brdfMerged = ee.ImageCollection(brdfJoined.map(addQaBands)) + +# Function to mask out pixels based on QA and water/land flags. +def filterBrdf(image): + # Using QA info for the NIR band. + qaband = image.select(['qa2']) + wband = image.select(['water']) + qamask = qaband.lte(2).And(wband.eq(1)) + nir_r = image.select('nir').multiply(0.0001).rename('nir_r') + swir2_r = image.select('swir2').multiply(0.0001).rename( + 'swir2_r') + return image.addBands(nir_r) \ + .addBands(swir2_r) \ + .updateMask(qamask) + +brdfFilteredVars = brdfMerged.map(filterBrdf) + +# Function to calculate spectral indices: +def calcBrdfIndices(image): + curyear = ee.Date(image.get('system:time_start')).get('year') + curdoy = ee.Date(image.get('system:time_start')) \ + .getRelative('day', 'year').add(1) + ndwi6 = image.normalizedDifference(['nir_r', 'swir2_r']) \ + .rename('ndwi6') + return image.addBands(ndwi6) \ + .set('doy', curdoy) \ + .set('year', curyear) + +# Map function over image collection. +brdfFilteredVars = brdfFilteredVars.map(calcBrdfIndices) + +# Section 5.2: Calculate daily NDWI + +# Create list of dates for full time series. +brdfRange = brdfFilteredVars.reduceColumns({ + 'reducer': ee.Reducer.max(), + 'selectors': ['system:time_start'] +}) +brdfEndDate = ee.Date(brdfRange.get('max')) +brdfDays = brdfEndDate.difference(brdfStartDate, 'day') +brdfDatesPrep = ee.List.sequence(0, brdfDays, 1) + +def makeBrdfDates(n): + return brdfStartDate.advance(n, 'day') + +brdfDates = brdfDatesPrep.map(makeBrdfDates) + +# List of dates that exist in BRDF data. +brdfDatesExist = brdfFilteredVars \ + .aggregate_array('system:time_start') + +# Get daily brdf values. +def calcDailyBrdfExists(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + brdfTemp = brdfFilteredVars \ + .filterDate(curdate, curdate.advance(1, 'day')) + outImg = brdfTemp.first() + return outImg + +dailyBrdfExtExists = + ee.ImageCollection.fromImages(brdfDatesExist.map( + calcDailyBrdfExists)) + +# Create empty results, to fill in dates when BRDF data does not exist. +def calcDailyBrdfFiller(curdate): + curdate = ee.Date(curdate) + curyear = curdate.get('year') + curdoy = curdate.getRelative('day', 'year').add(1) + brdfTemp = brdfFilteredVars \ + .filterDate(curdate, curdate.advance(1, 'day')) + brdfSize = brdfTemp.size() + outImg = ee.Image.constant(0).selfMask() \ + .addBands(ee.Image.constant(0).selfMask()) \ + .addBands(ee.Image.constant(0).selfMask()) \ + .addBands(ee.Image.constant(0).selfMask()) \ + .addBands(ee.Image.constant(0).selfMask()) \ + .rename(['ndvi', 'evi', 'savi', 'ndwi5', 'ndwi6']) \ + .set('doy', curdoy) \ + .set('year', curyear) \ + .set('system:time_start', curdate) \ + .set('brdfSize', brdfSize) + return outImg + +# Create filler for all dates. +dailyBrdfExtendedFiller = + ee.ImageCollection.fromImages(brdfDates.map(calcDailyBrdfFiller)) +# But only used if and when size was 0. +dailyBrdfExtFillFilt = dailyBrdfExtendedFiller \ + .filter(ee.Filter.eq('brdfSize', 0)) +# Merge the two collections. +dailyBrdfExtended = dailyBrdfExtExists \ + .merge(dailyBrdfExtFillFilt) + +# Filter back to original user requested start date. +dailyBrdf = dailyBrdfExtended \ + .filterDate(reqStartDate, brdfEndDate.advance(1, 'day')) + +# Section 5.3: Summarize daily spectral indices by woreda + +# Filter spectral indices for zonal summaries. +brdfSummary = dailyBrdf \ + .filterDate(reqStartDate, reqEndDate.advance(1, 'day')) + +# Function to calculate zonal statistics for spectral indices by woreda: +def sumZonalBrdf(image): + # To get the doy and year, we convert the metadata to grids + # and then summarize. + image2 = image.addBands([ + image.metadata('doy').int(), + image.metadata('year').int() + ]) + # Reduce by regions to get zonal means for each woreda. + output = image2.select(['doy', 'year', 'ndwi6']) \ + .reduceRegions({ + 'collection': woredas, + 'reducer': ee.Reducer.mean(), + 'scale': 1000 + }) + return output + + +# Map the zonal statistics function over the filtered spectral index data. +brdfWoreda = brdfSummary.map(sumZonalBrdf) +# Flatten the results for export. +brdfFlat = brdfWoreda.flatten() + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 6: Map display of calculated environmental variables +displayDate = ee.Date('2021-10-01') + +precipDisp = dailyPrecip \ + .filterDate(displayDate, displayDate.advance(1, 'day')) +brdfDisp = dailyBrdf \ + .filterDate(displayDate, displayDate.advance(1, 'day')) +LSTDisp = dailyLst \ + .filterDate(displayDate, displayDate.advance(1, 'day')) + +# Select the image (should be only one) from each collection. +precipImage = precipDisp.first().select('totprec') +LSTmImage = LSTDisp.first().select('LST_mean') +ndwi6Image = brdfDisp.first().select('ndwi6') + +# Palettes for environmental variable maps: +palettePrecip = ['f7fbff', '08306b'] +paletteLst = ['fff5f0', '67000d'] +paletteSpectral = ['ffffe5', '004529'] + +# Add layers to the map. +# Show precipitation by default, +# others hidden until users picks them from layers drop down. +Map.addLayer({ + 'eeObject': precipImage, + 'visParams': { + 'min': 0, + 'max': 20, + 'palette': palettePrecip + }, + 'name': 'Precipitation', + 'shown': True, + 'opacity': 0.75 +}) +Map.addLayer({ + 'eeObject': LSTmImage, + 'visParams': { + 'min': 0, + 'max': 40, + 'palette': paletteLst + }, + 'name': 'LST Mean', + 'shown': False, + 'opacity': 0.75 +}) +Map.addLayer({ + 'eeObject': ndwi6Image, + 'visParams': { + 'min': 0, + 'max': 1, + 'palette': paletteSpectral + }, + 'name': 'NDWI6', + 'shown': False, + 'opacity': 0.75 +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Section 7: Exporting + +# 7.1 Export naming +reqStartDateText = reqStartDate.format('yyyy-MM-dd').getInfo() + +# Precipitation +precipPrefix = 'Export_Precip_Data' +precipLastDate = ee.Date(reqEndDate.millis() \ + .min(precipEndDate.millis())) +precipSummaryEndDate = precipLastDate \ + .format('yyyy-MM-dd').getInfo() +precipFilename = precipPrefix \ + .concat('_', reqStartDateText, + '_', precipSummaryEndDate) +# LST +LSTPrefix = 'Export_LST_Data' +LSTLastDate = ee.Date(reqEndDate.millis() \ + .min(LSTEndDate.millis())) +LSTSummaryEndDate = LSTLastDate \ + .format('yyyy-MM-dd').getInfo() +LSTFilename = LSTPrefix \ + .concat('_', reqStartDateText, + '_', LSTSummaryEndDate) +# BRDF +brdfPrefix = 'Export_Spectral_Data' +brdfLastDate = ee.Date(reqEndDate.millis() \ + .min(brdfEndDate.millis())) +brdfSummaryEndDate = brdfLastDate \ + .format('yyyy-MM-dd').getInfo() +brdfFilename = brdfPrefix \ + .concat('_', reqStartDateText, + '_', brdfSummaryEndDate) + +# 7.2 Export flattened tables to Google Drive +# Need to click 'RUN in the Tasks tab to configure and start each export. +Export.table.toDrive({ + 'collection': precipFlat, + 'description': precipFilename, + 'selectors': ['wid', 'woreda', 'doy', 'year', 'totprec'] +}) +Export.table.toDrive({ + 'collection': LSTFlat, + 'description': LSTFilename, + 'selectors': ['wid', 'woreda', 'doy', 'year', + 'LST_day', 'LST_night', 'LST_mean' + ] +}) +Export.table.toDrive({ + 'collection': brdfFlat, + 'description': brdfFilename, + 'selectors': ['wid', 'woreda', 'doy', 'year', 'ndwi6'] +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16h Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16h Checkpoint.ipynb new file mode 100644 index 0000000..3eb7d3e --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16h Checkpoint.ipynb @@ -0,0 +1,186 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.6 Health Applications\n", + "# Checkpoint: A16h\n", + "# Author: Dawn Nekorchuk\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 8: Viewing external analyses results\n", + "\n", + "# This is using *synthetic* malaria data.\n", + "# For demonstration only, not to be used for epidemiological purposes.\n", + "epidemiaResults = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-6/amhara_pilot_synthetic_2018W32'\n", + ")\n", + "# Filter to only keep pilot woredas with forecasted values.\n", + "pilot = epidemiaResults \\\n", + " .filter(ee.Filter.neq('inc_n_fc', None))\n", + "nonpilot = epidemiaResults \\\n", + " .filter(ee.Filter.eq('inc_n_fc', None))\n", + "\n", + "Map.setCenter(38, 11.5, 7)\n", + "\n", + "# Paint the pilot woredas with different colors for forecasted* incidence\n", + "# fc_n_inc here is the forecasted incidence (cut into factors)\n", + "# made on (historical) 2018W24 (i.e. 8 weeks in advance).\n", + "# * based on synthetic data for demonstration only.\n", + "# Incidence per 1000\n", + "# 1 : [0 - 0.25)\n", + "# 2 : [0.25 - 0.5)\n", + "# 3 : [0.5 - 0.75)\n", + "# 4 : [0.75 - 1)\n", + "# 5 : > 1\n", + "\n", + "empty = ee.Image().byte()\n", + "fill_fc = empty.paint({\n", + " 'featureCollection': pilot,\n", + " 'color': 'inc_n_fc',\n", + "})\n", + "palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15']\n", + "Map.addLayer(\n", + " fill_fc, {\n", + " 'palette': palette,\n", + " 'min': 1,\n", + " 'max': 5\n", + " },\n", + " 'Forecasted Incidence'\n", + ")\n", + "\n", + "# Paint the woredas with different colors for the observed* incidence.\n", + "# * based on synthetic data for demonstration only\n", + "fill_obs = empty.paint({\n", + " 'featureCollection': pilot,\n", + " 'color': 'inc_n_obs',\n", + "})\n", + "palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15']\n", + "# Layer is off by default, users change between the two in the map viewer.\n", + "Map.addLayer(\n", + " fill_obs, {\n", + " 'palette': palette,\n", + " 'min': 1,\n", + " 'max': 5\n", + " },\n", + " 'Observed Incidence',\n", + " False\n", + ")\n", + "\n", + "# Add gray fill for nonpilot woredas (not included in study).\n", + "fill_na = empty.paint({\n", + " 'featureCollection': nonpilot\n", + "})\n", + "Map.addLayer(\n", + " fill_na, {\n", + " 'palette': 'a1a9a8'\n", + " },\n", + " 'Non-study woredas'\n", + ")\n", + "\n", + "# Draw borders for ALL Amhara region woredas.\n", + "outline = empty.paint({\n", + " 'featureCollection': epidemiaResults,\n", + " 'color': 1,\n", + " 'width': 1\n", + "})\n", + "# Add woreda boundaries to map.\n", + "Map.addLayer(\n", + " outline, {\n", + " 'palette': '000000'\n", + " },\n", + " 'Woredas'\n", + ")\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16h Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16h Checkpoint.js new file mode 100644 index 0000000..c2acae4 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16h Checkpoint.js @@ -0,0 +1,93 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.6 Health Applications +// Checkpoint: A16h +// Author: Dawn Nekorchuk +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 8: Viewing external analyses results + +// This is using *synthetic* malaria data. +// For demonstration only, not to be used for epidemiological purposes. +var epidemiaResults = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_pilot_synthetic_2018W32' +); +// Filter to only keep pilot woredas with forecasted values. +var pilot = epidemiaResults + .filter(ee.Filter.neq('inc_n_fc', null)); +var nonpilot = epidemiaResults + .filter(ee.Filter.eq('inc_n_fc', null)); + +Map.setCenter(38, 11.5, 7); + +// Paint the pilot woredas with different colors for forecasted* incidence +// fc_n_inc here is the forecasted incidence (cut into factors) +// made on (historical) 2018W24 (i.e. 8 weeks in advance). +// * based on synthetic data for demonstration only. +// Incidence per 1000 +// 1 : [0 - 0.25) +// 2 : [0.25 - 0.5) +// 3 : [0.5 - 0.75) +// 4 : [0.75 - 1) +// 5 : > 1 + +var empty = ee.Image().byte(); +var fill_fc = empty.paint({ + featureCollection: pilot, + color: 'inc_n_fc', +}); +var palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15']; +Map.addLayer( + fill_fc, { + palette: palette, + min: 1, + max: 5 + }, + 'Forecasted Incidence' +); + +// Paint the woredas with different colors for the observed* incidence. +// * based on synthetic data for demonstration only +var fill_obs = empty.paint({ + featureCollection: pilot, + color: 'inc_n_obs', +}); +var palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15']; +// Layer is off by default, users change between the two in the map viewer. +Map.addLayer( + fill_obs, { + palette: palette, + min: 1, + max: 5 + }, + 'Observed Incidence', + false +); + +// Add gray fill for nonpilot woredas (not included in study). +var fill_na = empty.paint({ + featureCollection: nonpilot +}); +Map.addLayer( + fill_na, { + palette: 'a1a9a8' + }, + 'Non-study woredas' +); + +// Draw borders for ALL Amhara region woredas. +var outline = empty.paint({ + featureCollection: epidemiaResults, + color: 1, + width: 1 +}); +// Add woreda boundaries to map. +Map.addLayer( + outline, { + palette: '000000' + }, + 'Woredas' +); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16h Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16h Checkpoint.py new file mode 100644 index 0000000..5379c0a --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.6 Health Applications/A16h Checkpoint.py @@ -0,0 +1,99 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.6 Health Applications +# Checkpoint: A16h +# Author: Dawn Nekorchuk +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 8: Viewing external analyses results + +# This is using *synthetic* malaria data. +# For demonstration only, not to be used for epidemiological purposes. +epidemiaResults = ee.FeatureCollection( + 'projects/gee-book/assets/A1-6/amhara_pilot_synthetic_2018W32' +) +# Filter to only keep pilot woredas with forecasted values. +pilot = epidemiaResults \ + .filter(ee.Filter.neq('inc_n_fc', None)) +nonpilot = epidemiaResults \ + .filter(ee.Filter.eq('inc_n_fc', None)) + +Map.setCenter(38, 11.5, 7) + +# Paint the pilot woredas with different colors for forecasted* incidence +# fc_n_inc here is the forecasted incidence (cut into factors) +# made on (historical) 2018W24 (i.e. 8 weeks in advance). +# * based on synthetic data for demonstration only. +# Incidence per 1000 +# 1 : [0 - 0.25) +# 2 : [0.25 - 0.5) +# 3 : [0.5 - 0.75) +# 4 : [0.75 - 1) +# 5 : > 1 + +empty = ee.Image().byte() +fill_fc = empty.paint({ + 'featureCollection': pilot, + 'color': 'inc_n_fc', +}) +palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15'] +Map.addLayer( + fill_fc, { + 'palette': palette, + 'min': 1, + 'max': 5 + }, + 'Forecasted Incidence' +) + +# Paint the woredas with different colors for the observed* incidence. +# * based on synthetic data for demonstration only +fill_obs = empty.paint({ + 'featureCollection': pilot, + 'color': 'inc_n_obs', +}) +palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15'] +# Layer is off by default, users change between the two in the map viewer. +Map.addLayer( + fill_obs, { + 'palette': palette, + 'min': 1, + 'max': 5 + }, + 'Observed Incidence', + False +) + +# Add gray fill for nonpilot woredas (not included in study). +fill_na = empty.paint({ + 'featureCollection': nonpilot +}) +Map.addLayer( + fill_na, { + 'palette': 'a1a9a8' + }, + 'Non-study woredas' +) + +# Draw borders for ALL Amhara region woredas. +outline = empty.paint({ + 'featureCollection': epidemiaResults, + 'color': 1, + 'width': 1 +}) +# Add woreda boundaries to map. +Map.addLayer( + outline, { + 'palette': '000000' + }, + 'Woredas' +) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17a Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17a Checkpoint.ipynb new file mode 100644 index 0000000..d5a2f6f --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17a Checkpoint.ipynb @@ -0,0 +1,309 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.7 Humanitarian Applications\n", + "# Checkpoint: A17a\n", + "# Authors: Jamon Van Den Hoek, Hannah K. Friedrich\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "###########################\n", + "#/ Section One: Seeing refugee settlements from above\n", + "###########################\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Load UNHCR settlement boundary for Pagirinya Refugee Settlement.\n", + "pagirinya = ee.Feature(ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary'\n", + ").first())\n", + "\n", + "Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement')\n", + "Map.centerObject(pagirinya, 14)\n", + "\n", + "# Create buffered settlement boundary geometry.\n", + "# 500 meter buffer size is arbitrary but large enough\n", + "# to capture area outside of the study settlement.\n", + "bufferSize = 500; # (in meters)\n", + "\n", + "# Buffer and convert to Geometry for spatial filtering and clipping.\n", + "bufferedBounds = pagirinya.buffer(bufferSize) \\\n", + " .bounds().geometry()\n", + "\n", + "def addIndices(img):\n", + " ndvi = img.normalizedDifference(['nir', 'red']) \\\n", + " .rename('NDVI'); \n", + " ndbi = img.normalizedDifference(['swir1', 'nir']) \\\n", + " .rename(['NDBI']); \n", + " nbr = img.normalizedDifference(['nir', 'swir2']) \\\n", + " .rename(['NBR']); \n", + " imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr)\n", + " return imgIndices\n", + "\n", + "\n", + "# Create L8 SR Collection 2 band names and new names.\n", + "landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6',\n", + " 'SR_B7'\n", + "]\n", + "landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']\n", + "\n", + "# Create image collection.\n", + "landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01',\n", + " '2020-12-31') \\\n", + " .filterBounds(bufferedBounds) \\\n", + " .filter(ee.Filter.lt('CLOUD_COVER', 40)) \\\n", + " .select(landsat8BandNames, landsat8BandRename) \\\n", + " .map(addIndices))\n", + "\n", + "# Make annual pre- and post-establishment composites.\n", + "preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() \\\n", + " .clip(bufferedBounds)\n", + "postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() \\\n", + " .clip(bufferedBounds)\n", + "\n", + "# Import visualization palettes https:#github.com/gee-community/ee-palettes.\n", + "palettes = require('users/gena/packages:palettes')\n", + "greenPalette = palettes.colorbrewer.Greens[9]\n", + "prGreenPalette = palettes.colorbrewer.PRGn[9]\n", + "\n", + "# Set-up \"True color\" visualization parameters.\n", + "TCImageVisParam = {\n", + " 'bands': ['red', 'green', 'blue'],\n", + " 'gamma': 1,\n", + " 'max': 13600,\n", + " 'min': 8400,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Set-up \"False color\" visualization parameters.\n", + "FCImageVisParam = {\n", + " 'bands': ['nir', 'red', 'green'],\n", + " 'gamma': 1,\n", + " 'min': 9000,\n", + " 'max': 20000,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Display True-color composites.\n", + "Map.addLayer(preMedian, TCImageVisParam,\n", + " 'Pre-Establishment Median TC')\n", + "Map.addLayer(postMedian, TCImageVisParam,\n", + " 'Post-Establishment Median TC')\n", + "\n", + "# Display False-color composites.\n", + "Map.addLayer(preMedian, FCImageVisParam,\n", + " 'Pre-Establishment Median FC')\n", + "Map.addLayer(postMedian, FCImageVisParam,\n", + " 'Post-Establishment Median FC')\n", + "\n", + "# Display median NDVI composites.\n", + "Map.addLayer(preMedian, {\n", + " 'min': 0,\n", + " 'max': 0.7,\n", + " 'bands': ['NDVI'],\n", + " 'palette': greenPalette\n", + "}, 'Pre-Establishment Median NDVI')\n", + "Map.addLayer(postMedian, {\n", + " 'min': 0,\n", + " 'max': 0.7,\n", + " 'bands': ['NDVI'],\n", + " 'palette': greenPalette\n", + "}, 'Post-Establishment Median NDVI')\n", + "\n", + "# Create an empty byte Image into which we\u2019ll paint the settlement boundary.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Convert settlement boundary\u2019s geometry to an Image for overlay.\n", + "pagirinyaOutline = empty.paint({\n", + " 'featureCollection': pagirinya,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Display Pagirinya boundary in blue.\n", + "Map.addLayer(pagirinyaOutline,\n", + " {\n", + " 'palette': '0000FF'\n", + " },\n", + " 'Pagirinya Refugee Settlement boundary')\n", + "\n", + "# Compare pre- and post-establishment differences in NDVI.\n", + "diffMedian = postMedian.subtract(preMedian)\n", + "Map.addLayer(diffMedian,\n", + " {\n", + " 'min': -0.1,\n", + " 'max': 0.1,\n", + " 'bands': ['NDVI'],\n", + " 'palette': prGreenPalette\n", + " },\n", + " 'Difference Median NDVI')\n", + "\n", + "# Chart the NDVI distributions for pre- and post-establishment.\n", + "combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) \\\n", + " .addBands(postMedian.select(['NDVI'], ['post-NDVI']))\n", + "\n", + "prePostNDVIFrequencyChart =\n", + " ui.Chart.image.histogram({\n", + " 'image': combinedNDVI,\n", + " 'region': bufferedBounds,\n", + " 'scale': 30\n", + " }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) \\\n", + " .setOptions({\n", + " 'title': 'NDVI Frequency Histogram',\n", + " 'hAxis': {\n", + " 'title': 'NDVI',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " },\n", + " },\n", + " 'vAxis':\n", + " {\n", + " 'title': 'Count',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'colors': ['cf513e', '1d6b99']\n", + " })\n", + "print(prePostNDVIFrequencyChart)\n", + "\n", + "# Import package to support text annotation.\n", + "text = require('users/gena/packages:text')\n", + "rgbVisParam = {\n", + " 'bands': ['red', 'green', 'blue'],\n", + " 'gamma': 1,\n", + " 'max': 12011,\n", + " 'min': 8114,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Define arguments for animation function parameters.\n", + "videoArgs = {\n", + " 'region': bufferedBounds,\n", + " 'framesPerSecond': 3,\n", + " 'scale': 10\n", + "}\n", + "\n", + "annotations = [{\n", + " 'position': 'left',\n", + " 'offset': '5%',\n", + " 'margin': '5%',\n", + " 'property': 'label',\n", + " 'scale': 30\n", + "}]\n", + "\n", + "def addText(image):\n", + " date = ee.String(ee.Date(image.get('system:time_start')) \\\n", + " .format(' YYYY-MM-dd'))\n", + " # Set a property called label for each image.\n", + " image = image.clip(bufferedBounds).visualize(rgbVisParam) \\\n", + " .set({\n", + " 'label': date\n", + " })\n", + " # Create a new image with the label overlaid using gena's package.\n", + " annotated = text.annotateImage(image, {}, bufferedBounds,\n", + " annotations)\n", + " return annotated\n", + "\n", + "\n", + "# Add timestamp annotation to all images in video.\n", + "tempCol = ic.map(addText)\n", + "\n", + "# Click the URL to watch the time series video.\n", + "print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17a Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17a Checkpoint.js new file mode 100644 index 0000000..05d05a3 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17a Checkpoint.js @@ -0,0 +1,216 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.7 Humanitarian Applications +// Checkpoint: A17a +// Authors: Jamon Van Den Hoek, Hannah K. Friedrich +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +////////////////////////////////////////////////////// +/// Section One: Seeing refugee settlements from above +////////////////////////////////////////////////////// +Map.setOptions('SATELLITE'); + +// Load UNHCR settlement boundary for Pagirinya Refugee Settlement. +var pagirinya = ee.Feature(ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary' +).first()); + +Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement'); +Map.centerObject(pagirinya, 14); + +// Create buffered settlement boundary geometry. +// 500 meter buffer size is arbitrary but large enough +// to capture area outside of the study settlement. +var bufferSize = 500; // (in meters) + +// Buffer and convert to Geometry for spatial filtering and clipping. +var bufferedBounds = pagirinya.buffer(bufferSize) + .bounds().geometry(); + +function addIndices(img) { + var ndvi = img.normalizedDifference(['nir', 'red']) + .rename('NDVI'); // NDVI = (nir-red)/(nir+red) + var ndbi = img.normalizedDifference(['swir1', 'nir']) + .rename(['NDBI']); // NDBI = (swir1-nir)/(swir1+nir) + var nbr = img.normalizedDifference(['nir', 'swir2']) + .rename(['NBR']); // NBR = (nir-swir2)/(nir+swir2) + var imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr); + return imgIndices; +} + +// Create L8 SR Collection 2 band names and new names. +var landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', + 'SR_B7' +]; +var landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']; + +// Create image collection. +var landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); +var ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01', + '2020-12-31') + .filterBounds(bufferedBounds) + .filter(ee.Filter.lt('CLOUD_COVER', 40)) + .select(landsat8BandNames, landsat8BandRename) + .map(addIndices)); + +// Make annual pre- and post-establishment composites. +var preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() + .clip(bufferedBounds); +var postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() + .clip(bufferedBounds); + +// Import visualization palettes https://github.com/gee-community/ee-palettes. +var palettes = require('users/gena/packages:palettes'); +var greenPalette = palettes.colorbrewer.Greens[9]; +var prGreenPalette = palettes.colorbrewer.PRGn[9]; + +// Set-up "true color" visualization parameters. +var TCImageVisParam = { + bands: ['red', 'green', 'blue'], + gamma: 1, + max: 13600, + min: 8400, + opacity: 1 +}; + +// Set-up "false color" visualization parameters. +var FCImageVisParam = { + bands: ['nir', 'red', 'green'], + gamma: 1, + min: 9000, + max: 20000, + opacity: 1 +}; + +// Display true-color composites. +Map.addLayer(preMedian, TCImageVisParam, + 'Pre-Establishment Median TC'); +Map.addLayer(postMedian, TCImageVisParam, + 'Post-Establishment Median TC'); + +// Display false-color composites. +Map.addLayer(preMedian, FCImageVisParam, + 'Pre-Establishment Median FC'); +Map.addLayer(postMedian, FCImageVisParam, + 'Post-Establishment Median FC'); + +// Display median NDVI composites. +Map.addLayer(preMedian, { + min: 0, + max: 0.7, + bands: ['NDVI'], + palette: greenPalette +}, 'Pre-Establishment Median NDVI'); +Map.addLayer(postMedian, { + min: 0, + max: 0.7, + bands: ['NDVI'], + palette: greenPalette +}, 'Post-Establishment Median NDVI'); + +// Create an empty byte Image into which we’ll paint the settlement boundary. +var empty = ee.Image().byte(); + +// Convert settlement boundary’s geometry to an Image for overlay. +var pagirinyaOutline = empty.paint({ + featureCollection: pagirinya, + color: 1, + width: 2 +}); + +// Display Pagirinya boundary in blue. +Map.addLayer(pagirinyaOutline, + { + palette: '0000FF' + }, + 'Pagirinya Refugee Settlement boundary'); + +// Compare pre- and post-establishment differences in NDVI. +var diffMedian = postMedian.subtract(preMedian); +Map.addLayer(diffMedian, + { + min: -0.1, + max: 0.1, + bands: ['NDVI'], + palette: prGreenPalette + }, + 'Difference Median NDVI'); + +// Chart the NDVI distributions for pre- and post-establishment. +var combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) + .addBands(postMedian.select(['NDVI'], ['post-NDVI'])); + +var prePostNDVIFrequencyChart = + ui.Chart.image.histogram({ + image: combinedNDVI, + region: bufferedBounds, + scale: 30 + }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) + .setOptions({ + title: 'NDVI Frequency Histogram', + hAxis: { + title: 'NDVI', + titleTextStyle: { + italic: false, + bold: true + }, + }, + vAxis: + { + title: 'Count', + titleTextStyle: { + italic: false, + bold: true + } + }, + colors: ['cf513e', '1d6b99'] + }); +print(prePostNDVIFrequencyChart); + +// Import package to support text annotation. +var text = require('users/gena/packages:text'); +var rgbVisParam = { + bands: ['red', 'green', 'blue'], + gamma: 1, + max: 12011, + min: 8114, + opacity: 1 +}; + +// Define arguments for animation function parameters. +var videoArgs = { + region: bufferedBounds, + framesPerSecond: 3, + scale: 10 +}; + +var annotations = [{ + position: 'left', + offset: '5%', + margin: '5%', + property: 'label', + scale: 30 +}]; + +function addText(image) { + var date = ee.String(ee.Date(image.get('system:time_start')) + .format(' YYYY-MM-dd')); + // Set a property called label for each image. + var image = image.clip(bufferedBounds).visualize(rgbVisParam) + .set({ + 'label': date + }); + // Create a new image with the label overlaid using gena's package. + var annotated = text.annotateImage(image, {}, bufferedBounds, + annotations); + return annotated; +} + +// Add timestamp annotation to all images in video. +var tempCol = ic.map(addText); + +// Click the URL to watch the time series video. +print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs)); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17a Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17a Checkpoint.py new file mode 100644 index 0000000..bccf7f9 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17a Checkpoint.py @@ -0,0 +1,222 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.7 Humanitarian Applications +# Checkpoint: A17a +# Authors: Jamon Van Den Hoek, Hannah K. Friedrich +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +########################### +#/ Section One: Seeing refugee settlements from above +########################### +Map.setOptions('SATELLITE') + +# Load UNHCR settlement boundary for Pagirinya Refugee Settlement. +pagirinya = ee.Feature(ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary' +).first()) + +Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement') +Map.centerObject(pagirinya, 14) + +# Create buffered settlement boundary geometry. +# 500 meter buffer size is arbitrary but large enough +# to capture area outside of the study settlement. +bufferSize = 500; # (in meters) + +# Buffer and convert to Geometry for spatial filtering and clipping. +bufferedBounds = pagirinya.buffer(bufferSize) \ + .bounds().geometry() + +def addIndices(img): + ndvi = img.normalizedDifference(['nir', 'red']) \ + .rename('NDVI'); + ndbi = img.normalizedDifference(['swir1', 'nir']) \ + .rename(['NDBI']); + nbr = img.normalizedDifference(['nir', 'swir2']) \ + .rename(['NBR']); + imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr) + return imgIndices + + +# Create L8 SR Collection 2 band names and new names. +landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', + 'SR_B7' +] +landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'] + +# Create image collection. +landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') +ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01', + '2020-12-31') \ + .filterBounds(bufferedBounds) \ + .filter(ee.Filter.lt('CLOUD_COVER', 40)) \ + .select(landsat8BandNames, landsat8BandRename) \ + .map(addIndices)) + +# Make annual pre- and post-establishment composites. +preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() \ + .clip(bufferedBounds) +postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() \ + .clip(bufferedBounds) + +# Import visualization palettes https:#github.com/gee-community/ee-palettes. +palettes = require('users/gena/packages:palettes') +greenPalette = palettes.colorbrewer.Greens[9] +prGreenPalette = palettes.colorbrewer.PRGn[9] + +# Set-up "True color" visualization parameters. +TCImageVisParam = { + 'bands': ['red', 'green', 'blue'], + 'gamma': 1, + 'max': 13600, + 'min': 8400, + 'opacity': 1 +} + +# Set-up "False color" visualization parameters. +FCImageVisParam = { + 'bands': ['nir', 'red', 'green'], + 'gamma': 1, + 'min': 9000, + 'max': 20000, + 'opacity': 1 +} + +# Display True-color composites. +Map.addLayer(preMedian, TCImageVisParam, + 'Pre-Establishment Median TC') +Map.addLayer(postMedian, TCImageVisParam, + 'Post-Establishment Median TC') + +# Display False-color composites. +Map.addLayer(preMedian, FCImageVisParam, + 'Pre-Establishment Median FC') +Map.addLayer(postMedian, FCImageVisParam, + 'Post-Establishment Median FC') + +# Display median NDVI composites. +Map.addLayer(preMedian, { + 'min': 0, + 'max': 0.7, + 'bands': ['NDVI'], + 'palette': greenPalette +}, 'Pre-Establishment Median NDVI') +Map.addLayer(postMedian, { + 'min': 0, + 'max': 0.7, + 'bands': ['NDVI'], + 'palette': greenPalette +}, 'Post-Establishment Median NDVI') + +# Create an empty byte Image into which we’ll paint the settlement boundary. +empty = ee.Image().byte() + +# Convert settlement boundary’s geometry to an Image for overlay. +pagirinyaOutline = empty.paint({ + 'featureCollection': pagirinya, + 'color': 1, + 'width': 2 +}) + +# Display Pagirinya boundary in blue. +Map.addLayer(pagirinyaOutline, + { + 'palette': '0000FF' + }, + 'Pagirinya Refugee Settlement boundary') + +# Compare pre- and post-establishment differences in NDVI. +diffMedian = postMedian.subtract(preMedian) +Map.addLayer(diffMedian, + { + 'min': -0.1, + 'max': 0.1, + 'bands': ['NDVI'], + 'palette': prGreenPalette + }, + 'Difference Median NDVI') + +# Chart the NDVI distributions for pre- and post-establishment. +combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) \ + .addBands(postMedian.select(['NDVI'], ['post-NDVI'])) + +prePostNDVIFrequencyChart = + ui.Chart.image.histogram({ + 'image': combinedNDVI, + 'region': bufferedBounds, + 'scale': 30 + }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) \ + .setOptions({ + 'title': 'NDVI Frequency Histogram', + 'hAxis': { + 'title': 'NDVI', + 'titleTextStyle': { + 'italic': False, + 'bold': True + }, + }, + 'vAxis': + { + 'title': 'Count', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'colors': ['cf513e', '1d6b99'] + }) +print(prePostNDVIFrequencyChart) + +# Import package to support text annotation. +text = require('users/gena/packages:text') +rgbVisParam = { + 'bands': ['red', 'green', 'blue'], + 'gamma': 1, + 'max': 12011, + 'min': 8114, + 'opacity': 1 +} + +# Define arguments for animation function parameters. +videoArgs = { + 'region': bufferedBounds, + 'framesPerSecond': 3, + 'scale': 10 +} + +annotations = [{ + 'position': 'left', + 'offset': '5%', + 'margin': '5%', + 'property': 'label', + 'scale': 30 +}] + +def addText(image): + date = ee.String(ee.Date(image.get('system:time_start')) \ + .format(' YYYY-MM-dd')) + # Set a property called label for each image. + image = image.clip(bufferedBounds).visualize(rgbVisParam) \ + .set({ + 'label': date + }) + # Create a new image with the label overlaid using gena's package. + annotated = text.annotateImage(image, {}, bufferedBounds, + annotations) + return annotated + + +# Add timestamp annotation to all images in video. +tempCol = ic.map(addText) + +# Click the URL to watch the time series video. +print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs)) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17b Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17b Checkpoint.ipynb new file mode 100644 index 0000000..5b3aead --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17b Checkpoint.ipynb @@ -0,0 +1,455 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.7 Humanitarian Applications\n", + "# Checkpoint: A17b\n", + "# Authors: Jamon Van Den Hoek, Hannah K. Friedrich\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "###########################\n", + "#/ Section One: Seeing refugee settlements from above\n", + "###########################\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Load UNHCR settlement boundary for Pagirinya Refugee Settlement.\n", + "pagirinya = ee.Feature(ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary'\n", + ").first())\n", + "\n", + "Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement')\n", + "Map.centerObject(pagirinya, 14)\n", + "\n", + "# Create buffered settlement boundary geometry.\n", + "# 500 meter buffer size is arbitrary but large enough\n", + "# to capture area outside of the study settlement.\n", + "bufferSize = 500; # (in meters)\n", + "\n", + "# Buffer and convert to Geometry for spatial filtering and clipping.\n", + "bufferedBounds = pagirinya.buffer(bufferSize) \\\n", + " .bounds().geometry()\n", + "\n", + "def addIndices(img):\n", + " ndvi = img.normalizedDifference(['nir', 'red']) \\\n", + " .rename('NDVI'); \n", + " ndbi = img.normalizedDifference(['swir1', 'nir']) \\\n", + " .rename(['NDBI']); \n", + " nbr = img.normalizedDifference(['nir', 'swir2']) \\\n", + " .rename(['NBR']); \n", + " imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr)\n", + " return imgIndices\n", + "\n", + "\n", + "# Create L8 SR Collection 2 band names and new names.\n", + "landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6',\n", + " 'SR_B7'\n", + "]\n", + "landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']\n", + "\n", + "# Create image collection.\n", + "landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01',\n", + " '2020-12-31') \\\n", + " .filterBounds(bufferedBounds) \\\n", + " .filter(ee.Filter.lt('CLOUD_COVER', 40)) \\\n", + " .select(landsat8BandNames, landsat8BandRename) \\\n", + " .map(addIndices))\n", + "\n", + "# Make annual pre- and post-establishment composites.\n", + "preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() \\\n", + " .clip(bufferedBounds)\n", + "postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() \\\n", + " .clip(bufferedBounds)\n", + "\n", + "# Import visualization palettes https:#github.com/gee-community/ee-palettes.\n", + "palettes = require('users/gena/packages:palettes')\n", + "greenPalette = palettes.colorbrewer.Greens[9]\n", + "prGreenPalette = palettes.colorbrewer.PRGn[9]\n", + "\n", + "# Set-up \"True color\" visualization parameters.\n", + "TCImageVisParam = {\n", + " 'bands': ['red', 'green', 'blue'],\n", + " 'gamma': 1,\n", + " 'max': 13600,\n", + " 'min': 8400,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Set-up \"False color\" visualization parameters.\n", + "FCImageVisParam = {\n", + " 'bands': ['nir', 'red', 'green'],\n", + " 'gamma': 1,\n", + " 'min': 9000,\n", + " 'max': 20000,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Display True-color composites.\n", + "Map.addLayer(preMedian, TCImageVisParam,\n", + " 'Pre-Establishment Median TC')\n", + "Map.addLayer(postMedian, TCImageVisParam,\n", + " 'Post-Establishment Median TC')\n", + "\n", + "# Display False-color composites.\n", + "Map.addLayer(preMedian, FCImageVisParam,\n", + " 'Pre-Establishment Median FC')\n", + "Map.addLayer(postMedian, FCImageVisParam,\n", + " 'Post-Establishment Median FC')\n", + "\n", + "# Display median NDVI composites.\n", + "Map.addLayer(preMedian, {\n", + " 'min': 0,\n", + " 'max': 0.7,\n", + " 'bands': ['NDVI'],\n", + " 'palette': greenPalette\n", + "}, 'Pre-Establishment Median NDVI')\n", + "Map.addLayer(postMedian, {\n", + " 'min': 0,\n", + " 'max': 0.7,\n", + " 'bands': ['NDVI'],\n", + " 'palette': greenPalette\n", + "}, 'Post-Establishment Median NDVI')\n", + "\n", + "# Create an empty byte Image into which we\u2019ll paint the settlement boundary.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Convert settlement boundary\u2019s geometry to an Image for overlay.\n", + "pagirinyaOutline = empty.paint({\n", + " 'featureCollection': pagirinya,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Display Pagirinya boundary in blue.\n", + "Map.addLayer(pagirinyaOutline,\n", + " {\n", + " 'palette': '0000FF'\n", + " },\n", + " 'Pagirinya Refugee Settlement boundary')\n", + "\n", + "# Compare pre- and post-establishment differences in NDVI.\n", + "diffMedian = postMedian.subtract(preMedian)\n", + "Map.addLayer(diffMedian,\n", + " {\n", + " 'min': -0.1,\n", + " 'max': 0.1,\n", + " 'bands': ['NDVI'],\n", + " 'palette': prGreenPalette\n", + " },\n", + " 'Difference Median NDVI')\n", + "\n", + "# Chart the NDVI distributions for pre- and post-establishment.\n", + "combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) \\\n", + " .addBands(postMedian.select(['NDVI'], ['post-NDVI']))\n", + "\n", + "prePostNDVIFrequencyChart =\n", + " ui.Chart.image.histogram({\n", + " 'image': combinedNDVI,\n", + " 'region': bufferedBounds,\n", + " 'scale': 30\n", + " }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) \\\n", + " .setOptions({\n", + " 'title': 'NDVI Frequency Histogram',\n", + " 'hAxis': {\n", + " 'title': 'NDVI',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " },\n", + " },\n", + " 'vAxis':\n", + " {\n", + " 'title': 'Count',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'colors': ['cf513e', '1d6b99']\n", + " })\n", + "print(prePostNDVIFrequencyChart)\n", + "\n", + "# Import package to support text annotation.\n", + "text = require('users/gena/packages:text')\n", + "rgbVisParam = {\n", + " 'bands': ['red', 'green', 'blue'],\n", + " 'gamma': 1,\n", + " 'max': 12011,\n", + " 'min': 8114,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Define arguments for animation function parameters.\n", + "videoArgs = {\n", + " 'region': bufferedBounds,\n", + " 'framesPerSecond': 3,\n", + " 'scale': 10\n", + "}\n", + "\n", + "annotations = [{\n", + " 'position': 'left',\n", + " 'offset': '5%',\n", + " 'margin': '5%',\n", + " 'property': 'label',\n", + " 'scale': 30\n", + "}]\n", + "\n", + "def addText(image):\n", + " date = ee.String(ee.Date(image.get('system:time_start')) \\\n", + " .format(' YYYY-MM-dd'))\n", + " # Set a property called label for each image.\n", + " image = image.clip(bufferedBounds).visualize(rgbVisParam) \\\n", + " .set({\n", + " 'label': date\n", + " })\n", + " # Create a new image with the label overlaid using gena's package.\n", + " annotated = text.annotateImage(image, {}, bufferedBounds,\n", + " annotations)\n", + " return annotated\n", + "\n", + "\n", + "# Add timestamp annotation to all images in video.\n", + "tempCol = ic.map(addText)\n", + "\n", + "# Click the URL to watch the time series video.\n", + "print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "###############################/\n", + "#/ Section Two: Mapping features within the refugee settlement\n", + "###############################/\n", + "\n", + "# Visualize Open Buildings dataset.\n", + "footprints = ee.FeatureCollection(\n", + " 'GOOGLE/Research/open-buildings/v1/polygons')\n", + "footprintsHigh = footprints.filter('confidence > 0.75')\n", + "footprintsLow = footprints.filter('confidence <= 0.75')\n", + "\n", + "Map.addLayer(footprintsHigh, {\n", + " 'color': 'FFA500'\n", + "}, 'Buildings high confidence')\n", + "Map.addLayer(footprintsLow, {\n", + " 'color': '800080'\n", + "}, 'Buildings low confidence')\n", + "\n", + "# Load land cover samples.\n", + "lcPts = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-7/lcPts')\n", + "print('lcPts', lcPts)\n", + "\n", + "# Create a function to set Feature properties based on value.\n", + "def setColor(f):\n", + " value = f.get('class')\n", + " mapDisplayColors = ee.List(['#13a1ed', '#7d02bf',\n", + " '#f0940a', '#d60909'\n", + " ])\n", + " # Use the class as an index to lookup the corresponding display color.\n", + " return f.set({\n", + " 'style': {\n", + " 'color': mapDisplayColors.get(value)\n", + " }\n", + " })\n", + "\n", + "\n", + "# Apply the function and view the results.\n", + "styled = lcPts.map(setColor)\n", + "Map.addLayer(styled.style(**{\n", + " 'styleProperty': 'style'\n", + "}), {}, 'Land cover samples')\n", + "\n", + "# Convert land cover sample FeatureCollection to an Image.\n", + "lcBand = lcPts.reduceToImage({\n", + " 'properties': ['class'],\n", + " 'reducer': ee.Reducer.first()\n", + "}).rename('class')\n", + "\n", + "# Add lcBand to the post-establishment composite.\n", + "postMedian = postMedian.addBands(lcBand)\n", + "\n", + "# Define bands that will be visualized in chart.\n", + "chartBands = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'class']\n", + "\n", + "print(postMedian, 'postMedian')\n", + "\n", + "# Plot median band value for each land cover type.\n", + "postBandsChart = ui.Chart.image \\\n", + " .byClass({\n", + " 'image': postMedian.select(chartBands),\n", + " 'classBand': 'class',\n", + " 'region': lcPts,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'scale': 30,\n", + " 'classLabels': ['Settlement', 'Road', 'Forest', 'Agriculture'],\n", + " 'xLabels': chartBands\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Band Values',\n", + " 'hAxis': {\n", + " 'title': 'Band Name',\n", + " 'titleTextStyle': '{italic': False, 'bold': True},\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Reflectance (x1e4)',\n", + " 'titleTextStyle': '{italic': False, 'bold': True}\n", + " },\n", + " 'colors': ['#13a1ed', '#7d02bf', '#f0940a','#d60909'],\n", + " 'pointSize': 0,\n", + " 'lineSize': 5,\n", + " 'curveType': 'function'\n", + " })\n", + "print(postBandsChart)\n", + "\n", + "# Define spectral indices that will be visualized in the chart.\n", + "indexBands = ['NDVI', 'NDBI', 'NBR', 'class']\n", + "\n", + "# Plot median index value for each land cover type.\n", + "postIndicesChart = ui.Chart.image \\\n", + " .byClass({\n", + " 'image': postMedian.select(indexBands),\n", + " 'classBand': 'class',\n", + " 'region': lcPts,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'scale': 30,\n", + " 'classLabels': ['Settlement', 'Road', 'Forest',\n", + " 'Agriculture'\n", + " ],\n", + " 'xLabels': indexBands\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Index Values',\n", + " 'hAxis': {\n", + " 'title': 'Index Name',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " },\n", + " #viewWindow: {min: wavelengths[0], max: wavelengths[2]}\n", + " 'scaleType': 'string'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Value',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'colors': ['#13a1ed', '#7d02bf', '#f0940a', '#d60909'],\n", + " 'pointSize': 5\n", + " })\n", + "print(postIndicesChart)\n", + "\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Paint all the polygon edges with the same number and width, display.\n", + "pagirinyaOutline = empty.paint({\n", + " 'featureCollection': pagirinya,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Map outline of Pagirinya in blue.\n", + "Map.addLayer(pagirinyaOutline,\n", + " {\n", + " 'palette': '0000FF'\n", + " },\n", + " 'Pagirinya Refugee Settlement boundary')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17b Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17b Checkpoint.js new file mode 100644 index 0000000..bfdd580 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17b Checkpoint.js @@ -0,0 +1,362 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.7 Humanitarian Applications +// Checkpoint: A17b +// Authors: Jamon Van Den Hoek, Hannah K. Friedrich +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +////////////////////////////////////////////////////// +/// Section One: Seeing refugee settlements from above +////////////////////////////////////////////////////// +Map.setOptions('SATELLITE'); + +// Load UNHCR settlement boundary for Pagirinya Refugee Settlement. +var pagirinya = ee.Feature(ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary' +).first()); + +Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement'); +Map.centerObject(pagirinya, 14); + +// Create buffered settlement boundary geometry. +// 500 meter buffer size is arbitrary but large enough +// to capture area outside of the study settlement. +var bufferSize = 500; // (in meters) + +// Buffer and convert to Geometry for spatial filtering and clipping. +var bufferedBounds = pagirinya.buffer(bufferSize) + .bounds().geometry(); + +function addIndices(img) { + var ndvi = img.normalizedDifference(['nir', 'red']) + .rename('NDVI'); // NDVI = (nir-red)/(nir+red) + var ndbi = img.normalizedDifference(['swir1', 'nir']) + .rename(['NDBI']); // NDBI = (swir1-nir)/(swir1+nir) + var nbr = img.normalizedDifference(['nir', 'swir2']) + .rename(['NBR']); // NBR = (nir-swir2)/(nir+swir2) + var imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr); + return imgIndices; +} + +// Create L8 SR Collection 2 band names and new names. +var landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', + 'SR_B7' +]; +var landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']; + +// Create image collection. +var landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); +var ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01', + '2020-12-31') + .filterBounds(bufferedBounds) + .filter(ee.Filter.lt('CLOUD_COVER', 40)) + .select(landsat8BandNames, landsat8BandRename) + .map(addIndices)); + +// Make annual pre- and post-establishment composites. +var preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() + .clip(bufferedBounds); +var postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() + .clip(bufferedBounds); + +// Import visualization palettes https://github.com/gee-community/ee-palettes. +var palettes = require('users/gena/packages:palettes'); +var greenPalette = palettes.colorbrewer.Greens[9]; +var prGreenPalette = palettes.colorbrewer.PRGn[9]; + +// Set-up "true color" visualization parameters. +var TCImageVisParam = { + bands: ['red', 'green', 'blue'], + gamma: 1, + max: 13600, + min: 8400, + opacity: 1 +}; + +// Set-up "false color" visualization parameters. +var FCImageVisParam = { + bands: ['nir', 'red', 'green'], + gamma: 1, + min: 9000, + max: 20000, + opacity: 1 +}; + +// Display true-color composites. +Map.addLayer(preMedian, TCImageVisParam, + 'Pre-Establishment Median TC'); +Map.addLayer(postMedian, TCImageVisParam, + 'Post-Establishment Median TC'); + +// Display false-color composites. +Map.addLayer(preMedian, FCImageVisParam, + 'Pre-Establishment Median FC'); +Map.addLayer(postMedian, FCImageVisParam, + 'Post-Establishment Median FC'); + +// Display median NDVI composites. +Map.addLayer(preMedian, { + min: 0, + max: 0.7, + bands: ['NDVI'], + palette: greenPalette +}, 'Pre-Establishment Median NDVI'); +Map.addLayer(postMedian, { + min: 0, + max: 0.7, + bands: ['NDVI'], + palette: greenPalette +}, 'Post-Establishment Median NDVI'); + +// Create an empty byte Image into which we’ll paint the settlement boundary. +var empty = ee.Image().byte(); + +// Convert settlement boundary’s geometry to an Image for overlay. +var pagirinyaOutline = empty.paint({ + featureCollection: pagirinya, + color: 1, + width: 2 +}); + +// Display Pagirinya boundary in blue. +Map.addLayer(pagirinyaOutline, + { + palette: '0000FF' + }, + 'Pagirinya Refugee Settlement boundary'); + +// Compare pre- and post-establishment differences in NDVI. +var diffMedian = postMedian.subtract(preMedian); +Map.addLayer(diffMedian, + { + min: -0.1, + max: 0.1, + bands: ['NDVI'], + palette: prGreenPalette + }, + 'Difference Median NDVI'); + +// Chart the NDVI distributions for pre- and post-establishment. +var combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) + .addBands(postMedian.select(['NDVI'], ['post-NDVI'])); + +var prePostNDVIFrequencyChart = + ui.Chart.image.histogram({ + image: combinedNDVI, + region: bufferedBounds, + scale: 30 + }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) + .setOptions({ + title: 'NDVI Frequency Histogram', + hAxis: { + title: 'NDVI', + titleTextStyle: { + italic: false, + bold: true + }, + }, + vAxis: + { + title: 'Count', + titleTextStyle: { + italic: false, + bold: true + } + }, + colors: ['cf513e', '1d6b99'] + }); +print(prePostNDVIFrequencyChart); + +// Import package to support text annotation. +var text = require('users/gena/packages:text'); +var rgbVisParam = { + bands: ['red', 'green', 'blue'], + gamma: 1, + max: 12011, + min: 8114, + opacity: 1 +}; + +// Define arguments for animation function parameters. +var videoArgs = { + region: bufferedBounds, + framesPerSecond: 3, + scale: 10 +}; + +var annotations = [{ + position: 'left', + offset: '5%', + margin: '5%', + property: 'label', + scale: 30 +}]; + +function addText(image) { + var date = ee.String(ee.Date(image.get('system:time_start')) + .format(' YYYY-MM-dd')); + // Set a property called label for each image. + var image = image.clip(bufferedBounds).visualize(rgbVisParam) + .set({ + 'label': date + }); + // Create a new image with the label overlaid using gena's package. + var annotated = text.annotateImage(image, {}, bufferedBounds, + annotations); + return annotated; +} + +// Add timestamp annotation to all images in video. +var tempCol = ic.map(addText); + +// Click the URL to watch the time series video. +print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs)); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +/////////////////////////////////////////////////////////////// +/// Section Two: Mapping features within the refugee settlement +/////////////////////////////////////////////////////////////// + +// Visualize Open Buildings dataset. +var footprints = ee.FeatureCollection( + 'GOOGLE/Research/open-buildings/v1/polygons'); +var footprintsHigh = footprints.filter('confidence > 0.75'); +var footprintsLow = footprints.filter('confidence <= 0.75'); + +Map.addLayer(footprintsHigh, { + color: 'FFA500' +}, 'Buildings high confidence'); +Map.addLayer(footprintsLow, { + color: '800080' +}, 'Buildings low confidence'); + +// Load land cover samples. +var lcPts = ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/lcPts'); +print('lcPts', lcPts); + +// Create a function to set Feature properties based on value. +var setColor = function(f) { + var value = f.get('class'); + var mapDisplayColors = ee.List(['#13a1ed', '#7d02bf', + '#f0940a', '#d60909' + ]); + // Use the class as an index to lookup the corresponding display color. + return f.set({ + style: { + color: mapDisplayColors.get(value) + } + }); +}; + +// Apply the function and view the results. +var styled = lcPts.map(setColor); +Map.addLayer(styled.style({ + styleProperty: 'style' +}), {}, 'Land cover samples'); + +// Convert land cover sample FeatureCollection to an Image. +var lcBand = lcPts.reduceToImage({ + properties: ['class'], + reducer: ee.Reducer.first() +}).rename('class'); + +// Add lcBand to the post-establishment composite. +postMedian = postMedian.addBands(lcBand); + +// Define bands that will be visualized in chart. +var chartBands = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'class']; + +print(postMedian, 'postMedian'); + +// Plot median band value for each land cover type. +var postBandsChart = ui.Chart.image + .byClass({ + image: postMedian.select(chartBands), + classBand: 'class', + region: lcPts, + reducer: ee.Reducer.median(), + scale: 30, + classLabels: ['Settlement', 'Road', 'Forest', 'Agriculture'], + xLabels: chartBands + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Band Values', + hAxis: { + title: 'Band Name', + titleTextStyle: {italic: false, bold: true}, + }, + vAxis: { + title: 'Reflectance (x1e4)', + titleTextStyle: {italic: false, bold: true} + }, + colors: ['#13a1ed', '#7d02bf', '#f0940a','#d60909'], + pointSize: 0, + lineSize: 5, + curveType: 'function' + }); +print(postBandsChart); + +// Define spectral indices that will be visualized in the chart. +var indexBands = ['NDVI', 'NDBI', 'NBR', 'class']; + +// Plot median index value for each land cover type. +var postIndicesChart = ui.Chart.image + .byClass({ + image: postMedian.select(indexBands), + classBand: 'class', + region: lcPts, + reducer: ee.Reducer.median(), + scale: 30, + classLabels: ['Settlement', 'Road', 'Forest', + 'Agriculture' + ], + xLabels: indexBands + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Index Values', + hAxis: { + title: 'Index Name', + titleTextStyle: { + italic: false, + bold: true + }, + //viewWindow: {min: wavelengths[0], max: wavelengths[2]} + scaleType: 'string' + }, + vAxis: { + title: 'Value', + titleTextStyle: { + italic: false, + bold: true + } + }, + colors: ['#13a1ed', '#7d02bf', '#f0940a', '#d60909'], + pointSize: 5 + }); +print(postIndicesChart); + +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); + +// Paint all the polygon edges with the same number and width, display. +var pagirinyaOutline = empty.paint({ + featureCollection: pagirinya, + color: 1, + width: 2 +}); + +// Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + palette: '0000FF' + }, + 'Pagirinya Refugee Settlement boundary'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17b Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17b Checkpoint.py new file mode 100644 index 0000000..8bd2f9e --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17b Checkpoint.py @@ -0,0 +1,368 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.7 Humanitarian Applications +# Checkpoint: A17b +# Authors: Jamon Van Den Hoek, Hannah K. Friedrich +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +########################### +#/ Section One: Seeing refugee settlements from above +########################### +Map.setOptions('SATELLITE') + +# Load UNHCR settlement boundary for Pagirinya Refugee Settlement. +pagirinya = ee.Feature(ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary' +).first()) + +Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement') +Map.centerObject(pagirinya, 14) + +# Create buffered settlement boundary geometry. +# 500 meter buffer size is arbitrary but large enough +# to capture area outside of the study settlement. +bufferSize = 500; # (in meters) + +# Buffer and convert to Geometry for spatial filtering and clipping. +bufferedBounds = pagirinya.buffer(bufferSize) \ + .bounds().geometry() + +def addIndices(img): + ndvi = img.normalizedDifference(['nir', 'red']) \ + .rename('NDVI'); + ndbi = img.normalizedDifference(['swir1', 'nir']) \ + .rename(['NDBI']); + nbr = img.normalizedDifference(['nir', 'swir2']) \ + .rename(['NBR']); + imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr) + return imgIndices + + +# Create L8 SR Collection 2 band names and new names. +landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', + 'SR_B7' +] +landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'] + +# Create image collection. +landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') +ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01', + '2020-12-31') \ + .filterBounds(bufferedBounds) \ + .filter(ee.Filter.lt('CLOUD_COVER', 40)) \ + .select(landsat8BandNames, landsat8BandRename) \ + .map(addIndices)) + +# Make annual pre- and post-establishment composites. +preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() \ + .clip(bufferedBounds) +postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() \ + .clip(bufferedBounds) + +# Import visualization palettes https:#github.com/gee-community/ee-palettes. +palettes = require('users/gena/packages:palettes') +greenPalette = palettes.colorbrewer.Greens[9] +prGreenPalette = palettes.colorbrewer.PRGn[9] + +# Set-up "True color" visualization parameters. +TCImageVisParam = { + 'bands': ['red', 'green', 'blue'], + 'gamma': 1, + 'max': 13600, + 'min': 8400, + 'opacity': 1 +} + +# Set-up "False color" visualization parameters. +FCImageVisParam = { + 'bands': ['nir', 'red', 'green'], + 'gamma': 1, + 'min': 9000, + 'max': 20000, + 'opacity': 1 +} + +# Display True-color composites. +Map.addLayer(preMedian, TCImageVisParam, + 'Pre-Establishment Median TC') +Map.addLayer(postMedian, TCImageVisParam, + 'Post-Establishment Median TC') + +# Display False-color composites. +Map.addLayer(preMedian, FCImageVisParam, + 'Pre-Establishment Median FC') +Map.addLayer(postMedian, FCImageVisParam, + 'Post-Establishment Median FC') + +# Display median NDVI composites. +Map.addLayer(preMedian, { + 'min': 0, + 'max': 0.7, + 'bands': ['NDVI'], + 'palette': greenPalette +}, 'Pre-Establishment Median NDVI') +Map.addLayer(postMedian, { + 'min': 0, + 'max': 0.7, + 'bands': ['NDVI'], + 'palette': greenPalette +}, 'Post-Establishment Median NDVI') + +# Create an empty byte Image into which we’ll paint the settlement boundary. +empty = ee.Image().byte() + +# Convert settlement boundary’s geometry to an Image for overlay. +pagirinyaOutline = empty.paint({ + 'featureCollection': pagirinya, + 'color': 1, + 'width': 2 +}) + +# Display Pagirinya boundary in blue. +Map.addLayer(pagirinyaOutline, + { + 'palette': '0000FF' + }, + 'Pagirinya Refugee Settlement boundary') + +# Compare pre- and post-establishment differences in NDVI. +diffMedian = postMedian.subtract(preMedian) +Map.addLayer(diffMedian, + { + 'min': -0.1, + 'max': 0.1, + 'bands': ['NDVI'], + 'palette': prGreenPalette + }, + 'Difference Median NDVI') + +# Chart the NDVI distributions for pre- and post-establishment. +combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) \ + .addBands(postMedian.select(['NDVI'], ['post-NDVI'])) + +prePostNDVIFrequencyChart = + ui.Chart.image.histogram({ + 'image': combinedNDVI, + 'region': bufferedBounds, + 'scale': 30 + }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) \ + .setOptions({ + 'title': 'NDVI Frequency Histogram', + 'hAxis': { + 'title': 'NDVI', + 'titleTextStyle': { + 'italic': False, + 'bold': True + }, + }, + 'vAxis': + { + 'title': 'Count', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'colors': ['cf513e', '1d6b99'] + }) +print(prePostNDVIFrequencyChart) + +# Import package to support text annotation. +text = require('users/gena/packages:text') +rgbVisParam = { + 'bands': ['red', 'green', 'blue'], + 'gamma': 1, + 'max': 12011, + 'min': 8114, + 'opacity': 1 +} + +# Define arguments for animation function parameters. +videoArgs = { + 'region': bufferedBounds, + 'framesPerSecond': 3, + 'scale': 10 +} + +annotations = [{ + 'position': 'left', + 'offset': '5%', + 'margin': '5%', + 'property': 'label', + 'scale': 30 +}] + +def addText(image): + date = ee.String(ee.Date(image.get('system:time_start')) \ + .format(' YYYY-MM-dd')) + # Set a property called label for each image. + image = image.clip(bufferedBounds).visualize(rgbVisParam) \ + .set({ + 'label': date + }) + # Create a new image with the label overlaid using gena's package. + annotated = text.annotateImage(image, {}, bufferedBounds, + annotations) + return annotated + + +# Add timestamp annotation to all images in video. +tempCol = ic.map(addText) + +# Click the URL to watch the time series video. +print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs)) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +###############################/ +#/ Section Two: Mapping features within the refugee settlement +###############################/ + +# Visualize Open Buildings dataset. +footprints = ee.FeatureCollection( + 'GOOGLE/Research/open-buildings/v1/polygons') +footprintsHigh = footprints.filter('confidence > 0.75') +footprintsLow = footprints.filter('confidence <= 0.75') + +Map.addLayer(footprintsHigh, { + 'color': 'FFA500' +}, 'Buildings high confidence') +Map.addLayer(footprintsLow, { + 'color': '800080' +}, 'Buildings low confidence') + +# Load land cover samples. +lcPts = ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/lcPts') +print('lcPts', lcPts) + +# Create a function to set Feature properties based on value. +def setColor(f): + value = f.get('class') + mapDisplayColors = ee.List(['#13a1ed', '#7d02bf', + '#f0940a', '#d60909' + ]) + # Use the class as an index to lookup the corresponding display color. + return f.set({ + 'style': { + 'color': mapDisplayColors.get(value) + } + }) + + +# Apply the function and view the results. +styled = lcPts.map(setColor) +Map.addLayer(styled.style(**{ + 'styleProperty': 'style' +}), {}, 'Land cover samples') + +# Convert land cover sample FeatureCollection to an Image. +lcBand = lcPts.reduceToImage({ + 'properties': ['class'], + 'reducer': ee.Reducer.first() +}).rename('class') + +# Add lcBand to the post-establishment composite. +postMedian = postMedian.addBands(lcBand) + +# Define bands that will be visualized in chart. +chartBands = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'class'] + +print(postMedian, 'postMedian') + +# Plot median band value for each land cover type. +postBandsChart = ui.Chart.image \ + .byClass({ + 'image': postMedian.select(chartBands), + 'classBand': 'class', + 'region': lcPts, + 'reducer': ee.Reducer.median(), + 'scale': 30, + 'classLabels': ['Settlement', 'Road', 'Forest', 'Agriculture'], + 'xLabels': chartBands + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Band Values', + 'hAxis': { + 'title': 'Band Name', + 'titleTextStyle': '{italic': False, 'bold': True}, + }, + 'vAxis': { + 'title': 'Reflectance (x1e4)', + 'titleTextStyle': '{italic': False, 'bold': True} + }, + 'colors': ['#13a1ed', '#7d02bf', '#f0940a','#d60909'], + 'pointSize': 0, + 'lineSize': 5, + 'curveType': 'function' + }) +print(postBandsChart) + +# Define spectral indices that will be visualized in the chart. +indexBands = ['NDVI', 'NDBI', 'NBR', 'class'] + +# Plot median index value for each land cover type. +postIndicesChart = ui.Chart.image \ + .byClass({ + 'image': postMedian.select(indexBands), + 'classBand': 'class', + 'region': lcPts, + 'reducer': ee.Reducer.median(), + 'scale': 30, + 'classLabels': ['Settlement', 'Road', 'Forest', + 'Agriculture' + ], + 'xLabels': indexBands + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Index Values', + 'hAxis': { + 'title': 'Index Name', + 'titleTextStyle': { + 'italic': False, + 'bold': True + }, + #viewWindow: {min: wavelengths[0], max: wavelengths[2]} + 'scaleType': 'string' + }, + 'vAxis': { + 'title': 'Value', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'colors': ['#13a1ed', '#7d02bf', '#f0940a', '#d60909'], + 'pointSize': 5 + }) +print(postIndicesChart) + +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() + +# Paint all the polygon edges with the same number and width, display. +pagirinyaOutline = empty.paint({ + 'featureCollection': pagirinya, + 'color': 1, + 'width': 2 +}) + +# Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + 'palette': '0000FF' + }, + 'Pagirinya Refugee Settlement boundary') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17c Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17c Checkpoint.ipynb new file mode 100644 index 0000000..5963ba1 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17c Checkpoint.ipynb @@ -0,0 +1,553 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.7 Humanitarian Applications\n", + "# Checkpoint: A17c\n", + "# Authors: Jamon Van Den Hoek, Hannah K. Friedrich\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "###########################\n", + "#/ Section One: Seeing refugee settlements from above\n", + "###########################\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Load UNHCR settlement boundary for Pagirinya Refugee Settlement.\n", + "pagirinya = ee.Feature(ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary'\n", + ").first())\n", + "\n", + "Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement')\n", + "Map.centerObject(pagirinya, 14)\n", + "\n", + "# Create buffered settlement boundary geometry.\n", + "# 500 meter buffer size is arbitrary but large enough\n", + "# to capture area outside of the study settlement.\n", + "bufferSize = 500; # (in meters)\n", + "\n", + "# Buffer and convert to Geometry for spatial filtering and clipping.\n", + "bufferedBounds = pagirinya.buffer(bufferSize) \\\n", + " .bounds().geometry()\n", + "\n", + "def addIndices(img):\n", + " ndvi = img.normalizedDifference(['nir', 'red']) \\\n", + " .rename('NDVI'); \n", + " ndbi = img.normalizedDifference(['swir1', 'nir']) \\\n", + " .rename(['NDBI']); \n", + " nbr = img.normalizedDifference(['nir', 'swir2']) \\\n", + " .rename(['NBR']); \n", + " imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr)\n", + " return imgIndices\n", + "\n", + "\n", + "# Create L8 SR Collection 2 band names and new names.\n", + "landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6',\n", + " 'SR_B7'\n", + "]\n", + "landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']\n", + "\n", + "# Create image collection.\n", + "landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01',\n", + " '2020-12-31') \\\n", + " .filterBounds(bufferedBounds) \\\n", + " .filter(ee.Filter.lt('CLOUD_COVER', 40)) \\\n", + " .select(landsat8BandNames, landsat8BandRename) \\\n", + " .map(addIndices))\n", + "\n", + "# Make annual pre- and post-establishment composites.\n", + "preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() \\\n", + " .clip(bufferedBounds)\n", + "postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() \\\n", + " .clip(bufferedBounds)\n", + "\n", + "# Import visualization palettes https:#github.com/gee-community/ee-palettes.\n", + "palettes = require('users/gena/packages:palettes')\n", + "greenPalette = palettes.colorbrewer.Greens[9]\n", + "prGreenPalette = palettes.colorbrewer.PRGn[9]\n", + "\n", + "# Set-up \"True color\" visualization parameters.\n", + "TCImageVisParam = {\n", + " 'bands': ['red', 'green', 'blue'],\n", + " 'gamma': 1,\n", + " 'max': 13600,\n", + " 'min': 8400,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Set-up \"False color\" visualization parameters.\n", + "FCImageVisParam = {\n", + " 'bands': ['nir', 'red', 'green'],\n", + " 'gamma': 1,\n", + " 'min': 9000,\n", + " 'max': 20000,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Display True-color composites.\n", + "Map.addLayer(preMedian, TCImageVisParam,\n", + " 'Pre-Establishment Median TC')\n", + "Map.addLayer(postMedian, TCImageVisParam,\n", + " 'Post-Establishment Median TC')\n", + "\n", + "# Display False-color composites.\n", + "Map.addLayer(preMedian, FCImageVisParam,\n", + " 'Pre-Establishment Median FC')\n", + "Map.addLayer(postMedian, FCImageVisParam,\n", + " 'Post-Establishment Median FC')\n", + "\n", + "# Display median NDVI composites.\n", + "Map.addLayer(preMedian, {\n", + " 'min': 0,\n", + " 'max': 0.7,\n", + " 'bands': ['NDVI'],\n", + " 'palette': greenPalette\n", + "}, 'Pre-Establishment Median NDVI')\n", + "Map.addLayer(postMedian, {\n", + " 'min': 0,\n", + " 'max': 0.7,\n", + " 'bands': ['NDVI'],\n", + " 'palette': greenPalette\n", + "}, 'Post-Establishment Median NDVI')\n", + "\n", + "# Create an empty byte Image into which we\u2019ll paint the settlement boundary.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Convert settlement boundary\u2019s geometry to an Image for overlay.\n", + "pagirinyaOutline = empty.paint({\n", + " 'featureCollection': pagirinya,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Display Pagirinya boundary in blue.\n", + "Map.addLayer(pagirinyaOutline,\n", + " {\n", + " 'palette': '0000FF'\n", + " },\n", + " 'Pagirinya Refugee Settlement boundary')\n", + "\n", + "# Compare pre- and post-establishment differences in NDVI.\n", + "diffMedian = postMedian.subtract(preMedian)\n", + "Map.addLayer(diffMedian,\n", + " {\n", + " 'min': -0.1,\n", + " 'max': 0.1,\n", + " 'bands': ['NDVI'],\n", + " 'palette': prGreenPalette\n", + " },\n", + " 'Difference Median NDVI')\n", + "\n", + "# Chart the NDVI distributions for pre- and post-establishment.\n", + "combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) \\\n", + " .addBands(postMedian.select(['NDVI'], ['post-NDVI']))\n", + "\n", + "prePostNDVIFrequencyChart =\n", + " ui.Chart.image.histogram({\n", + " 'image': combinedNDVI,\n", + " 'region': bufferedBounds,\n", + " 'scale': 30\n", + " }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) \\\n", + " .setOptions({\n", + " 'title': 'NDVI Frequency Histogram',\n", + " 'hAxis': {\n", + " 'title': 'NDVI',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " },\n", + " },\n", + " 'vAxis':\n", + " {\n", + " 'title': 'Count',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'colors': ['cf513e', '1d6b99']\n", + " })\n", + "print(prePostNDVIFrequencyChart)\n", + "\n", + "# Import package to support text annotation.\n", + "text = require('users/gena/packages:text')\n", + "rgbVisParam = {\n", + " 'bands': ['red', 'green', 'blue'],\n", + " 'gamma': 1,\n", + " 'max': 12011,\n", + " 'min': 8114,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Define arguments for animation function parameters.\n", + "videoArgs = {\n", + " 'region': bufferedBounds,\n", + " 'framesPerSecond': 3,\n", + " 'scale': 10\n", + "}\n", + "\n", + "annotations = [{\n", + " 'position': 'left',\n", + " 'offset': '5%',\n", + " 'margin': '5%',\n", + " 'property': 'label',\n", + " 'scale': 30\n", + "}]\n", + "\n", + "def addText(image):\n", + " date = ee.String(ee.Date(image.get('system:time_start')) \\\n", + " .format(' YYYY-MM-dd'))\n", + " # Set a property called label for each image.\n", + " image = image.clip(bufferedBounds).visualize(rgbVisParam) \\\n", + " .set({\n", + " 'label': date\n", + " })\n", + " # Create a new image with the label overlaid using gena's package.\n", + " annotated = text.annotateImage(image, {}, bufferedBounds,\n", + " annotations)\n", + " return annotated\n", + "\n", + "\n", + "# Add timestamp annotation to all images in video.\n", + "tempCol = ic.map(addText)\n", + "\n", + "# Click the URL to watch the time series video.\n", + "print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "###############################/\n", + "#/ Section Two: Mapping features within the refugee settlement\n", + "###############################/\n", + "\n", + "# Visualize Open Buildings dataset.\n", + "footprints = ee.FeatureCollection(\n", + " 'GOOGLE/Research/open-buildings/v1/polygons')\n", + "footprintsHigh = footprints.filter('confidence > 0.75')\n", + "footprintsLow = footprints.filter('confidence <= 0.75')\n", + "\n", + "Map.addLayer(footprintsHigh, {\n", + " 'color': 'FFA500'\n", + "}, 'Buildings high confidence')\n", + "Map.addLayer(footprintsLow, {\n", + " 'color': '800080'\n", + "}, 'Buildings low confidence')\n", + "\n", + "# Load land cover samples.\n", + "lcPts = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-7/lcPts')\n", + "print('lcPts', lcPts)\n", + "\n", + "# Create a function to set Feature properties based on value.\n", + "def setColor(f):\n", + " value = f.get('class')\n", + " mapDisplayColors = ee.List(['#13a1ed', '#7d02bf',\n", + " '#f0940a', '#d60909'\n", + " ])\n", + " # Use the class as an index to lookup the corresponding display color.\n", + " return f.set({\n", + " 'style': {\n", + " 'color': mapDisplayColors.get(value)\n", + " }\n", + " })\n", + "\n", + "\n", + "# Apply the function and view the results.\n", + "styled = lcPts.map(setColor)\n", + "Map.addLayer(styled.style(**{\n", + " 'styleProperty': 'style'\n", + "}), {}, 'Land cover samples')\n", + "\n", + "# Convert land cover sample FeatureCollection to an Image.\n", + "lcBand = lcPts.reduceToImage({\n", + " 'properties': ['class'],\n", + " 'reducer': ee.Reducer.first()\n", + "}).rename('class')\n", + "\n", + "# Add lcBand to the post-establishment composite.\n", + "postMedian = postMedian.addBands(lcBand)\n", + "\n", + "# Define bands that will be visualized in chart.\n", + "chartBands = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'class']\n", + "\n", + "print(postMedian, 'postMedian')\n", + "\n", + "# Plot median band value for each land cover type.\n", + "postBandsChart = ui.Chart.image \\\n", + " .byClass({\n", + " 'image': postMedian.select(chartBands),\n", + " 'classBand': 'class',\n", + " 'region': lcPts,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'scale': 30,\n", + " 'classLabels': ['Settlement', 'Road', 'Forest', 'Agriculture'],\n", + " 'xLabels': chartBands\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Band Values',\n", + " 'hAxis': {\n", + " 'title': 'Band Name',\n", + " 'titleTextStyle': '{italic': False, 'bold': True},\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Reflectance (x1e4)',\n", + " 'titleTextStyle': '{italic': False, 'bold': True}\n", + " },\n", + " 'colors': ['#13a1ed', '#7d02bf', '#f0940a','#d60909'],\n", + " 'pointSize': 0,\n", + " 'lineSize': 5,\n", + " 'curveType': 'function'\n", + " })\n", + "print(postBandsChart)\n", + "\n", + "# Define spectral indices that will be visualized in the chart.\n", + "indexBands = ['NDVI', 'NDBI', 'NBR', 'class']\n", + "\n", + "# Plot median index value for each land cover type.\n", + "postIndicesChart = ui.Chart.image \\\n", + " .byClass({\n", + " 'image': postMedian.select(indexBands),\n", + " 'classBand': 'class',\n", + " 'region': lcPts,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'scale': 30,\n", + " 'classLabels': ['Settlement', 'Road', 'Forest',\n", + " 'Agriculture'\n", + " ],\n", + " 'xLabels': indexBands\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Index Values',\n", + " 'hAxis': {\n", + " 'title': 'Index Name',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " },\n", + " #viewWindow: {min: wavelengths[0], max: wavelengths[2]}\n", + " 'scaleType': 'string'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Value',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'colors': ['#13a1ed', '#7d02bf', '#f0940a', '#d60909'],\n", + " 'pointSize': 5\n", + " })\n", + "print(postIndicesChart)\n", + "\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Paint all the polygon edges with the same number and width, display.\n", + "pagirinyaOutline = empty.paint({\n", + " 'featureCollection': pagirinya,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Map outline of Pagirinya in blue.\n", + "Map.addLayer(pagirinyaOutline,\n", + " {\n", + " 'palette': '0000FF'\n", + " },\n", + " 'Pagirinya Refugee Settlement boundary')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##############################\n", + "#/ Section Three: Delineating refugee settlement boundaries\n", + "##############################\n", + "\n", + "# Create samples to input to a K-means classifier.\n", + "numPx = 500\n", + "samples = postMedian.select('NDVI').sample({\n", + " 'scale': 30, # Landsat resolution\n", + " 'numPixels': numPx,\n", + " 'geometries': True\n", + "})\n", + "\n", + "Map.addLayer(samples, {}, 'K-means samples')\n", + "\n", + "# Set-up the parameters for K-means.\n", + "numClusters = 2\n", + "maxIter = 5\n", + "seedValue = 21\n", + "\n", + "# Seed the classifier using land cover samples.\n", + "clusterer = ee.Clusterer.wekaKMeans({\n", + " 'nClusters': numClusters,\n", + " 'maxIterations': maxIter,\n", + " 'seed': seedValue\n", + "}).train(samples)\n", + "\n", + "# Apply the K-means classifier.\n", + "kmeansResult = postMedian.cluster(clusterer)\n", + "Map.addLayer(kmeansResult, {\n", + " 'bands': ['cluster'],\n", + " 'max': 1,\n", + " 'min': 0\n", + "}, 'K-means output')\n", + "\n", + "# Define the kernel used for morphological operations.\n", + "kernel = ee.Kernel.square({\n", + " 'radius': 3\n", + "})\n", + "\n", + "# Perform a dilation followed by an erosion.\n", + "kMeansCleaned = kmeansResult \\\n", + " .focal_max({\n", + " 'kernel': kernel,\n", + " 'iterations': 1\n", + " }) # Dilation \\\n", + " .focal_min({\n", + " 'kernel': kernel,\n", + " 'iterations': 1\n", + " }); # Erosion\n", + "Map.addLayer(kMeansCleaned, {\n", + " 'bands': ['cluster'],\n", + " 'max': 1,\n", + " 'min': 0\n", + "}, 'K-means cleaned')\n", + "\n", + "# Convert cleaned K-means settlement and non-settlement coverages to polygons.\n", + "kMeansCleanedPolygon = kMeansCleaned.reduceToVectors({\n", + " 'scale': 30,\n", + " 'eightConnected': True\n", + "})\n", + "\n", + "Map.addLayer(kMeansCleanedPolygon, {}, 'K-Means cleaned polygon')\n", + "\n", + "# Map outline of Pagirinya in blue.\n", + "Map.addLayer(pagirinyaOutline,\n", + " {\n", + " 'palette': '0000FF'\n", + " },\n", + " 'Pagirinya Refugee Settlement boundary')\n", + "\n", + "# Intersect K-means polygons with UNHCR settlement boundary and\n", + "# return intersection area as a feature property.\n", + "\n", + "def func_aha(feat):\n", + " boundaryIsect = pagirinya.intersection(feat, ee \\\n", + " .ErrorMargin(1))\n", + " return ee.Feature(feat).set({\n", + " 'isectArea': boundaryIsect.area()\n", + " })\n", + "\n", + "kMeansIntersect = kMeansCleanedPolygon.map(func_aha)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Sort to select the polygon with largest overlap with the UNHCR settlement boundary.\n", + "kMeansBoundary = ee.Feature(kMeansIntersect.sort('isectArea',\n", + " False).first())\n", + "Map.addLayer(kMeansBoundary, {}, 'K-Means Settlement Boundary')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17c Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17c Checkpoint.js new file mode 100644 index 0000000..3ca39ed --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17c Checkpoint.js @@ -0,0 +1,451 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.7 Humanitarian Applications +// Checkpoint: A17c +// Authors: Jamon Van Den Hoek, Hannah K. Friedrich +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +////////////////////////////////////////////////////// +/// Section One: Seeing refugee settlements from above +////////////////////////////////////////////////////// +Map.setOptions('SATELLITE'); + +// Load UNHCR settlement boundary for Pagirinya Refugee Settlement. +var pagirinya = ee.Feature(ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary' +).first()); + +Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement'); +Map.centerObject(pagirinya, 14); + +// Create buffered settlement boundary geometry. +// 500 meter buffer size is arbitrary but large enough +// to capture area outside of the study settlement. +var bufferSize = 500; // (in meters) + +// Buffer and convert to Geometry for spatial filtering and clipping. +var bufferedBounds = pagirinya.buffer(bufferSize) + .bounds().geometry(); + +function addIndices(img) { + var ndvi = img.normalizedDifference(['nir', 'red']) + .rename('NDVI'); // NDVI = (nir-red)/(nir+red) + var ndbi = img.normalizedDifference(['swir1', 'nir']) + .rename(['NDBI']); // NDBI = (swir1-nir)/(swir1+nir) + var nbr = img.normalizedDifference(['nir', 'swir2']) + .rename(['NBR']); // NBR = (nir-swir2)/(nir+swir2) + var imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr); + return imgIndices; +} + +// Create L8 SR Collection 2 band names and new names. +var landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', + 'SR_B7' +]; +var landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']; + +// Create image collection. +var landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); +var ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01', + '2020-12-31') + .filterBounds(bufferedBounds) + .filter(ee.Filter.lt('CLOUD_COVER', 40)) + .select(landsat8BandNames, landsat8BandRename) + .map(addIndices)); + +// Make annual pre- and post-establishment composites. +var preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() + .clip(bufferedBounds); +var postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() + .clip(bufferedBounds); + +// Import visualization palettes https://github.com/gee-community/ee-palettes. +var palettes = require('users/gena/packages:palettes'); +var greenPalette = palettes.colorbrewer.Greens[9]; +var prGreenPalette = palettes.colorbrewer.PRGn[9]; + +// Set-up "true color" visualization parameters. +var TCImageVisParam = { + bands: ['red', 'green', 'blue'], + gamma: 1, + max: 13600, + min: 8400, + opacity: 1 +}; + +// Set-up "false color" visualization parameters. +var FCImageVisParam = { + bands: ['nir', 'red', 'green'], + gamma: 1, + min: 9000, + max: 20000, + opacity: 1 +}; + +// Display true-color composites. +Map.addLayer(preMedian, TCImageVisParam, + 'Pre-Establishment Median TC'); +Map.addLayer(postMedian, TCImageVisParam, + 'Post-Establishment Median TC'); + +// Display false-color composites. +Map.addLayer(preMedian, FCImageVisParam, + 'Pre-Establishment Median FC'); +Map.addLayer(postMedian, FCImageVisParam, + 'Post-Establishment Median FC'); + +// Display median NDVI composites. +Map.addLayer(preMedian, { + min: 0, + max: 0.7, + bands: ['NDVI'], + palette: greenPalette +}, 'Pre-Establishment Median NDVI'); +Map.addLayer(postMedian, { + min: 0, + max: 0.7, + bands: ['NDVI'], + palette: greenPalette +}, 'Post-Establishment Median NDVI'); + +// Create an empty byte Image into which we’ll paint the settlement boundary. +var empty = ee.Image().byte(); + +// Convert settlement boundary’s geometry to an Image for overlay. +var pagirinyaOutline = empty.paint({ + featureCollection: pagirinya, + color: 1, + width: 2 +}); + +// Display Pagirinya boundary in blue. +Map.addLayer(pagirinyaOutline, + { + palette: '0000FF' + }, + 'Pagirinya Refugee Settlement boundary'); + +// Compare pre- and post-establishment differences in NDVI. +var diffMedian = postMedian.subtract(preMedian); +Map.addLayer(diffMedian, + { + min: -0.1, + max: 0.1, + bands: ['NDVI'], + palette: prGreenPalette + }, + 'Difference Median NDVI'); + +// Chart the NDVI distributions for pre- and post-establishment. +var combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) + .addBands(postMedian.select(['NDVI'], ['post-NDVI'])); + +var prePostNDVIFrequencyChart = + ui.Chart.image.histogram({ + image: combinedNDVI, + region: bufferedBounds, + scale: 30 + }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) + .setOptions({ + title: 'NDVI Frequency Histogram', + hAxis: { + title: 'NDVI', + titleTextStyle: { + italic: false, + bold: true + }, + }, + vAxis: + { + title: 'Count', + titleTextStyle: { + italic: false, + bold: true + } + }, + colors: ['cf513e', '1d6b99'] + }); +print(prePostNDVIFrequencyChart); + +// Import package to support text annotation. +var text = require('users/gena/packages:text'); +var rgbVisParam = { + bands: ['red', 'green', 'blue'], + gamma: 1, + max: 12011, + min: 8114, + opacity: 1 +}; + +// Define arguments for animation function parameters. +var videoArgs = { + region: bufferedBounds, + framesPerSecond: 3, + scale: 10 +}; + +var annotations = [{ + position: 'left', + offset: '5%', + margin: '5%', + property: 'label', + scale: 30 +}]; + +function addText(image) { + var date = ee.String(ee.Date(image.get('system:time_start')) + .format(' YYYY-MM-dd')); + // Set a property called label for each image. + var image = image.clip(bufferedBounds).visualize(rgbVisParam) + .set({ + 'label': date + }); + // Create a new image with the label overlaid using gena's package. + var annotated = text.annotateImage(image, {}, bufferedBounds, + annotations); + return annotated; +} + +// Add timestamp annotation to all images in video. +var tempCol = ic.map(addText); + +// Click the URL to watch the time series video. +print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs)); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +/////////////////////////////////////////////////////////////// +/// Section Two: Mapping features within the refugee settlement +/////////////////////////////////////////////////////////////// + +// Visualize Open Buildings dataset. +var footprints = ee.FeatureCollection( + 'GOOGLE/Research/open-buildings/v1/polygons'); +var footprintsHigh = footprints.filter('confidence > 0.75'); +var footprintsLow = footprints.filter('confidence <= 0.75'); + +Map.addLayer(footprintsHigh, { + color: 'FFA500' +}, 'Buildings high confidence'); +Map.addLayer(footprintsLow, { + color: '800080' +}, 'Buildings low confidence'); + +// Load land cover samples. +var lcPts = ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/lcPts'); +print('lcPts', lcPts); + +// Create a function to set Feature properties based on value. +var setColor = function(f) { + var value = f.get('class'); + var mapDisplayColors = ee.List(['#13a1ed', '#7d02bf', + '#f0940a', '#d60909' + ]); + // Use the class as an index to lookup the corresponding display color. + return f.set({ + style: { + color: mapDisplayColors.get(value) + } + }); +}; + +// Apply the function and view the results. +var styled = lcPts.map(setColor); +Map.addLayer(styled.style({ + styleProperty: 'style' +}), {}, 'Land cover samples'); + +// Convert land cover sample FeatureCollection to an Image. +var lcBand = lcPts.reduceToImage({ + properties: ['class'], + reducer: ee.Reducer.first() +}).rename('class'); + +// Add lcBand to the post-establishment composite. +postMedian = postMedian.addBands(lcBand); + +// Define bands that will be visualized in chart. +var chartBands = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'class']; + +print(postMedian, 'postMedian'); + +// Plot median band value for each land cover type. +var postBandsChart = ui.Chart.image + .byClass({ + image: postMedian.select(chartBands), + classBand: 'class', + region: lcPts, + reducer: ee.Reducer.median(), + scale: 30, + classLabels: ['Settlement', 'Road', 'Forest', 'Agriculture'], + xLabels: chartBands + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Band Values', + hAxis: { + title: 'Band Name', + titleTextStyle: {italic: false, bold: true}, + }, + vAxis: { + title: 'Reflectance (x1e4)', + titleTextStyle: {italic: false, bold: true} + }, + colors: ['#13a1ed', '#7d02bf', '#f0940a','#d60909'], + pointSize: 0, + lineSize: 5, + curveType: 'function' + }); +print(postBandsChart); + +// Define spectral indices that will be visualized in the chart. +var indexBands = ['NDVI', 'NDBI', 'NBR', 'class']; + +// Plot median index value for each land cover type. +var postIndicesChart = ui.Chart.image + .byClass({ + image: postMedian.select(indexBands), + classBand: 'class', + region: lcPts, + reducer: ee.Reducer.median(), + scale: 30, + classLabels: ['Settlement', 'Road', 'Forest', + 'Agriculture' + ], + xLabels: indexBands + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Index Values', + hAxis: { + title: 'Index Name', + titleTextStyle: { + italic: false, + bold: true + }, + //viewWindow: {min: wavelengths[0], max: wavelengths[2]} + scaleType: 'string' + }, + vAxis: { + title: 'Value', + titleTextStyle: { + italic: false, + bold: true + } + }, + colors: ['#13a1ed', '#7d02bf', '#f0940a', '#d60909'], + pointSize: 5 + }); +print(postIndicesChart); + +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); + +// Paint all the polygon edges with the same number and width, display. +var pagirinyaOutline = empty.paint({ + featureCollection: pagirinya, + color: 1, + width: 2 +}); + +// Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + palette: '0000FF' + }, + 'Pagirinya Refugee Settlement boundary'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//////////////////////////////////////////////////////////// +/// Section Three: Delineating refugee settlement boundaries +//////////////////////////////////////////////////////////// + +// Create samples to input to a K-means classifier. +var numPx = 500; +var samples = postMedian.select('NDVI').sample({ + scale: 30, // Landsat resolution + numPixels: numPx, + geometries: true +}); + +Map.addLayer(samples, {}, 'K-means samples'); + +// Set-up the parameters for K-means. +var numClusters = 2; +var maxIter = 5; +var seedValue = 21; + +// Seed the classifier using land cover samples. +var clusterer = ee.Clusterer.wekaKMeans({ + nClusters: numClusters, + maxIterations: maxIter, + seed: seedValue +}).train(samples); + +// Apply the K-means classifier. +var kmeansResult = postMedian.cluster(clusterer); +Map.addLayer(kmeansResult, { + bands: ['cluster'], + max: 1, + min: 0 +}, 'K-means output'); + +// Define the kernel used for morphological operations. +var kernel = ee.Kernel.square({ + radius: 3 +}); + +// Perform a dilation followed by an erosion. +var kMeansCleaned = kmeansResult + .focal_max({ + kernel: kernel, + iterations: 1 + }) // Dilation + .focal_min({ + kernel: kernel, + iterations: 1 + }); // Erosion +Map.addLayer(kMeansCleaned, { + bands: ['cluster'], + max: 1, + min: 0 +}, 'K-means cleaned'); + +// Convert cleaned K-means settlement and non-settlement coverages to polygons. +var kMeansCleanedPolygon = kMeansCleaned.reduceToVectors({ + scale: 30, + eightConnected: true +}); + +Map.addLayer(kMeansCleanedPolygon, {}, 'K-Means cleaned polygon'); + +// Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + palette: '0000FF' + }, + 'Pagirinya Refugee Settlement boundary'); + +// Intersect K-means polygons with UNHCR settlement boundary and +// return intersection area as a feature property. +var kMeansIntersect = kMeansCleanedPolygon.map(function(feat) { + var boundaryIsect = pagirinya.intersection(feat, ee + .ErrorMargin(1)); + return ee.Feature(feat).set({ + 'isectArea': boundaryIsect.area() + }); +}); + +// Sort to select the polygon with largest overlap with the UNHCR settlement boundary. +var kMeansBoundary = ee.Feature(kMeansIntersect.sort('isectArea', + false).first()); +Map.addLayer(kMeansBoundary, {}, 'K-Means Settlement Boundary'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17c Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17c Checkpoint.py new file mode 100644 index 0000000..54ef092 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17c Checkpoint.py @@ -0,0 +1,466 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.7 Humanitarian Applications +# Checkpoint: A17c +# Authors: Jamon Van Den Hoek, Hannah K. Friedrich +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +########################### +#/ Section One: Seeing refugee settlements from above +########################### +Map.setOptions('SATELLITE') + +# Load UNHCR settlement boundary for Pagirinya Refugee Settlement. +pagirinya = ee.Feature(ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary' +).first()) + +Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement') +Map.centerObject(pagirinya, 14) + +# Create buffered settlement boundary geometry. +# 500 meter buffer size is arbitrary but large enough +# to capture area outside of the study settlement. +bufferSize = 500; # (in meters) + +# Buffer and convert to Geometry for spatial filtering and clipping. +bufferedBounds = pagirinya.buffer(bufferSize) \ + .bounds().geometry() + +def addIndices(img): + ndvi = img.normalizedDifference(['nir', 'red']) \ + .rename('NDVI'); + ndbi = img.normalizedDifference(['swir1', 'nir']) \ + .rename(['NDBI']); + nbr = img.normalizedDifference(['nir', 'swir2']) \ + .rename(['NBR']); + imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr) + return imgIndices + + +# Create L8 SR Collection 2 band names and new names. +landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', + 'SR_B7' +] +landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'] + +# Create image collection. +landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') +ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01', + '2020-12-31') \ + .filterBounds(bufferedBounds) \ + .filter(ee.Filter.lt('CLOUD_COVER', 40)) \ + .select(landsat8BandNames, landsat8BandRename) \ + .map(addIndices)) + +# Make annual pre- and post-establishment composites. +preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() \ + .clip(bufferedBounds) +postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() \ + .clip(bufferedBounds) + +# Import visualization palettes https:#github.com/gee-community/ee-palettes. +palettes = require('users/gena/packages:palettes') +greenPalette = palettes.colorbrewer.Greens[9] +prGreenPalette = palettes.colorbrewer.PRGn[9] + +# Set-up "True color" visualization parameters. +TCImageVisParam = { + 'bands': ['red', 'green', 'blue'], + 'gamma': 1, + 'max': 13600, + 'min': 8400, + 'opacity': 1 +} + +# Set-up "False color" visualization parameters. +FCImageVisParam = { + 'bands': ['nir', 'red', 'green'], + 'gamma': 1, + 'min': 9000, + 'max': 20000, + 'opacity': 1 +} + +# Display True-color composites. +Map.addLayer(preMedian, TCImageVisParam, + 'Pre-Establishment Median TC') +Map.addLayer(postMedian, TCImageVisParam, + 'Post-Establishment Median TC') + +# Display False-color composites. +Map.addLayer(preMedian, FCImageVisParam, + 'Pre-Establishment Median FC') +Map.addLayer(postMedian, FCImageVisParam, + 'Post-Establishment Median FC') + +# Display median NDVI composites. +Map.addLayer(preMedian, { + 'min': 0, + 'max': 0.7, + 'bands': ['NDVI'], + 'palette': greenPalette +}, 'Pre-Establishment Median NDVI') +Map.addLayer(postMedian, { + 'min': 0, + 'max': 0.7, + 'bands': ['NDVI'], + 'palette': greenPalette +}, 'Post-Establishment Median NDVI') + +# Create an empty byte Image into which we’ll paint the settlement boundary. +empty = ee.Image().byte() + +# Convert settlement boundary’s geometry to an Image for overlay. +pagirinyaOutline = empty.paint({ + 'featureCollection': pagirinya, + 'color': 1, + 'width': 2 +}) + +# Display Pagirinya boundary in blue. +Map.addLayer(pagirinyaOutline, + { + 'palette': '0000FF' + }, + 'Pagirinya Refugee Settlement boundary') + +# Compare pre- and post-establishment differences in NDVI. +diffMedian = postMedian.subtract(preMedian) +Map.addLayer(diffMedian, + { + 'min': -0.1, + 'max': 0.1, + 'bands': ['NDVI'], + 'palette': prGreenPalette + }, + 'Difference Median NDVI') + +# Chart the NDVI distributions for pre- and post-establishment. +combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) \ + .addBands(postMedian.select(['NDVI'], ['post-NDVI'])) + +prePostNDVIFrequencyChart = + ui.Chart.image.histogram({ + 'image': combinedNDVI, + 'region': bufferedBounds, + 'scale': 30 + }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) \ + .setOptions({ + 'title': 'NDVI Frequency Histogram', + 'hAxis': { + 'title': 'NDVI', + 'titleTextStyle': { + 'italic': False, + 'bold': True + }, + }, + 'vAxis': + { + 'title': 'Count', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'colors': ['cf513e', '1d6b99'] + }) +print(prePostNDVIFrequencyChart) + +# Import package to support text annotation. +text = require('users/gena/packages:text') +rgbVisParam = { + 'bands': ['red', 'green', 'blue'], + 'gamma': 1, + 'max': 12011, + 'min': 8114, + 'opacity': 1 +} + +# Define arguments for animation function parameters. +videoArgs = { + 'region': bufferedBounds, + 'framesPerSecond': 3, + 'scale': 10 +} + +annotations = [{ + 'position': 'left', + 'offset': '5%', + 'margin': '5%', + 'property': 'label', + 'scale': 30 +}] + +def addText(image): + date = ee.String(ee.Date(image.get('system:time_start')) \ + .format(' YYYY-MM-dd')) + # Set a property called label for each image. + image = image.clip(bufferedBounds).visualize(rgbVisParam) \ + .set({ + 'label': date + }) + # Create a new image with the label overlaid using gena's package. + annotated = text.annotateImage(image, {}, bufferedBounds, + annotations) + return annotated + + +# Add timestamp annotation to all images in video. +tempCol = ic.map(addText) + +# Click the URL to watch the time series video. +print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs)) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +###############################/ +#/ Section Two: Mapping features within the refugee settlement +###############################/ + +# Visualize Open Buildings dataset. +footprints = ee.FeatureCollection( + 'GOOGLE/Research/open-buildings/v1/polygons') +footprintsHigh = footprints.filter('confidence > 0.75') +footprintsLow = footprints.filter('confidence <= 0.75') + +Map.addLayer(footprintsHigh, { + 'color': 'FFA500' +}, 'Buildings high confidence') +Map.addLayer(footprintsLow, { + 'color': '800080' +}, 'Buildings low confidence') + +# Load land cover samples. +lcPts = ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/lcPts') +print('lcPts', lcPts) + +# Create a function to set Feature properties based on value. +def setColor(f): + value = f.get('class') + mapDisplayColors = ee.List(['#13a1ed', '#7d02bf', + '#f0940a', '#d60909' + ]) + # Use the class as an index to lookup the corresponding display color. + return f.set({ + 'style': { + 'color': mapDisplayColors.get(value) + } + }) + + +# Apply the function and view the results. +styled = lcPts.map(setColor) +Map.addLayer(styled.style(**{ + 'styleProperty': 'style' +}), {}, 'Land cover samples') + +# Convert land cover sample FeatureCollection to an Image. +lcBand = lcPts.reduceToImage({ + 'properties': ['class'], + 'reducer': ee.Reducer.first() +}).rename('class') + +# Add lcBand to the post-establishment composite. +postMedian = postMedian.addBands(lcBand) + +# Define bands that will be visualized in chart. +chartBands = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'class'] + +print(postMedian, 'postMedian') + +# Plot median band value for each land cover type. +postBandsChart = ui.Chart.image \ + .byClass({ + 'image': postMedian.select(chartBands), + 'classBand': 'class', + 'region': lcPts, + 'reducer': ee.Reducer.median(), + 'scale': 30, + 'classLabels': ['Settlement', 'Road', 'Forest', 'Agriculture'], + 'xLabels': chartBands + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Band Values', + 'hAxis': { + 'title': 'Band Name', + 'titleTextStyle': '{italic': False, 'bold': True}, + }, + 'vAxis': { + 'title': 'Reflectance (x1e4)', + 'titleTextStyle': '{italic': False, 'bold': True} + }, + 'colors': ['#13a1ed', '#7d02bf', '#f0940a','#d60909'], + 'pointSize': 0, + 'lineSize': 5, + 'curveType': 'function' + }) +print(postBandsChart) + +# Define spectral indices that will be visualized in the chart. +indexBands = ['NDVI', 'NDBI', 'NBR', 'class'] + +# Plot median index value for each land cover type. +postIndicesChart = ui.Chart.image \ + .byClass({ + 'image': postMedian.select(indexBands), + 'classBand': 'class', + 'region': lcPts, + 'reducer': ee.Reducer.median(), + 'scale': 30, + 'classLabels': ['Settlement', 'Road', 'Forest', + 'Agriculture' + ], + 'xLabels': indexBands + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Index Values', + 'hAxis': { + 'title': 'Index Name', + 'titleTextStyle': { + 'italic': False, + 'bold': True + }, + #viewWindow: {min: wavelengths[0], max: wavelengths[2]} + 'scaleType': 'string' + }, + 'vAxis': { + 'title': 'Value', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'colors': ['#13a1ed', '#7d02bf', '#f0940a', '#d60909'], + 'pointSize': 5 + }) +print(postIndicesChart) + +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() + +# Paint all the polygon edges with the same number and width, display. +pagirinyaOutline = empty.paint({ + 'featureCollection': pagirinya, + 'color': 1, + 'width': 2 +}) + +# Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + 'palette': '0000FF' + }, + 'Pagirinya Refugee Settlement boundary') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +############################## +#/ Section Three: Delineating refugee settlement boundaries +############################## + +# Create samples to input to a K-means classifier. +numPx = 500 +samples = postMedian.select('NDVI').sample({ + 'scale': 30, # Landsat resolution + 'numPixels': numPx, + 'geometries': True +}) + +Map.addLayer(samples, {}, 'K-means samples') + +# Set-up the parameters for K-means. +numClusters = 2 +maxIter = 5 +seedValue = 21 + +# Seed the classifier using land cover samples. +clusterer = ee.Clusterer.wekaKMeans({ + 'nClusters': numClusters, + 'maxIterations': maxIter, + 'seed': seedValue +}).train(samples) + +# Apply the K-means classifier. +kmeansResult = postMedian.cluster(clusterer) +Map.addLayer(kmeansResult, { + 'bands': ['cluster'], + 'max': 1, + 'min': 0 +}, 'K-means output') + +# Define the kernel used for morphological operations. +kernel = ee.Kernel.square({ + 'radius': 3 +}) + +# Perform a dilation followed by an erosion. +kMeansCleaned = kmeansResult \ + .focal_max({ + 'kernel': kernel, + 'iterations': 1 + }) # Dilation \ + .focal_min({ + 'kernel': kernel, + 'iterations': 1 + }); # Erosion +Map.addLayer(kMeansCleaned, { + 'bands': ['cluster'], + 'max': 1, + 'min': 0 +}, 'K-means cleaned') + +# Convert cleaned K-means settlement and non-settlement coverages to polygons. +kMeansCleanedPolygon = kMeansCleaned.reduceToVectors({ + 'scale': 30, + 'eightConnected': True +}) + +Map.addLayer(kMeansCleanedPolygon, {}, 'K-Means cleaned polygon') + +# Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + 'palette': '0000FF' + }, + 'Pagirinya Refugee Settlement boundary') + +# Intersect K-means polygons with UNHCR settlement boundary and +# return intersection area as a feature property. + +def func_aha(feat): + boundaryIsect = pagirinya.intersection(feat, ee \ + .ErrorMargin(1)) + return ee.Feature(feat).set({ + 'isectArea': boundaryIsect.area() + }) + +kMeansIntersect = kMeansCleanedPolygon.map(func_aha) + + + + + + + + +# Sort to select the polygon with largest overlap with the UNHCR settlement boundary. +kMeansBoundary = ee.Feature(kMeansIntersect.sort('isectArea', + False).first()) +Map.addLayer(kMeansBoundary, {}, 'K-Means Settlement Boundary') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17d Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17d Checkpoint.ipynb new file mode 100644 index 0000000..8537579 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17d Checkpoint.ipynb @@ -0,0 +1,646 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.7 Humanitarian Applications\n", + "# Checkpoint: A17d\n", + "# Authors: Jamon Van Den Hoek, Hannah K. Friedrich\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "###########################\n", + "#/ Section One: Seeing refugee settlements from above\n", + "###########################\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Load UNHCR settlement boundary for Pagirinya Refugee Settlement.\n", + "pagirinya = ee.Feature(ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary'\n", + ").first())\n", + "\n", + "Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement')\n", + "Map.centerObject(pagirinya, 14)\n", + "\n", + "# Create buffered settlement boundary geometry.\n", + "# 500 meter buffer size is arbitrary but large enough\n", + "# to capture area outside of the study settlement.\n", + "bufferSize = 500; # (in meters)\n", + "\n", + "# Buffer and convert to Geometry for spatial filtering and clipping.\n", + "bufferedBounds = pagirinya.buffer(bufferSize) \\\n", + " .bounds().geometry()\n", + "\n", + "def addIndices(img):\n", + " ndvi = img.normalizedDifference(['nir', 'red']) \\\n", + " .rename('NDVI'); \n", + " ndbi = img.normalizedDifference(['swir1', 'nir']) \\\n", + " .rename(['NDBI']); \n", + " nbr = img.normalizedDifference(['nir', 'swir2']) \\\n", + " .rename(['NBR']); \n", + " imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr)\n", + " return imgIndices\n", + "\n", + "\n", + "# Create L8 SR Collection 2 band names and new names.\n", + "landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6',\n", + " 'SR_B7'\n", + "]\n", + "landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']\n", + "\n", + "# Create image collection.\n", + "landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01',\n", + " '2020-12-31') \\\n", + " .filterBounds(bufferedBounds) \\\n", + " .filter(ee.Filter.lt('CLOUD_COVER', 40)) \\\n", + " .select(landsat8BandNames, landsat8BandRename) \\\n", + " .map(addIndices))\n", + "\n", + "# Make annual pre- and post-establishment composites.\n", + "preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() \\\n", + " .clip(bufferedBounds)\n", + "postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() \\\n", + " .clip(bufferedBounds)\n", + "\n", + "# Import visualization palettes https:#github.com/gee-community/ee-palettes.\n", + "palettes = require('users/gena/packages:palettes')\n", + "greenPalette = palettes.colorbrewer.Greens[9]\n", + "prGreenPalette = palettes.colorbrewer.PRGn[9]\n", + "\n", + "# Set-up \"True color\" visualization parameters.\n", + "TCImageVisParam = {\n", + " 'bands': ['red', 'green', 'blue'],\n", + " 'gamma': 1,\n", + " 'max': 13600,\n", + " 'min': 8400,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Set-up \"False color\" visualization parameters.\n", + "FCImageVisParam = {\n", + " 'bands': ['nir', 'red', 'green'],\n", + " 'gamma': 1,\n", + " 'min': 9000,\n", + " 'max': 20000,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Display True-color composites.\n", + "Map.addLayer(preMedian, TCImageVisParam,\n", + " 'Pre-Establishment Median TC')\n", + "Map.addLayer(postMedian, TCImageVisParam,\n", + " 'Post-Establishment Median TC')\n", + "\n", + "# Display False-color composites.\n", + "Map.addLayer(preMedian, FCImageVisParam,\n", + " 'Pre-Establishment Median FC')\n", + "Map.addLayer(postMedian, FCImageVisParam,\n", + " 'Post-Establishment Median FC')\n", + "\n", + "# Display median NDVI composites.\n", + "Map.addLayer(preMedian, {\n", + " 'min': 0,\n", + " 'max': 0.7,\n", + " 'bands': ['NDVI'],\n", + " 'palette': greenPalette\n", + "}, 'Pre-Establishment Median NDVI')\n", + "Map.addLayer(postMedian, {\n", + " 'min': 0,\n", + " 'max': 0.7,\n", + " 'bands': ['NDVI'],\n", + " 'palette': greenPalette\n", + "}, 'Post-Establishment Median NDVI')\n", + "\n", + "# Create an empty byte Image into which we\u2019ll paint the settlement boundary.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Convert settlement boundary\u2019s geometry to an Image for overlay.\n", + "pagirinyaOutline = empty.paint({\n", + " 'featureCollection': pagirinya,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Display Pagirinya boundary in blue.\n", + "Map.addLayer(pagirinyaOutline,\n", + " {\n", + " 'palette': '0000FF'\n", + " },\n", + " 'Pagirinya Refugee Settlement boundary')\n", + "\n", + "# Compare pre- and post-establishment differences in NDVI.\n", + "diffMedian = postMedian.subtract(preMedian)\n", + "Map.addLayer(diffMedian,\n", + " {\n", + " 'min': -0.1,\n", + " 'max': 0.1,\n", + " 'bands': ['NDVI'],\n", + " 'palette': prGreenPalette\n", + " },\n", + " 'Difference Median NDVI')\n", + "\n", + "# Chart the NDVI distributions for pre- and post-establishment.\n", + "combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) \\\n", + " .addBands(postMedian.select(['NDVI'], ['post-NDVI']))\n", + "\n", + "prePostNDVIFrequencyChart =\n", + " ui.Chart.image.histogram({\n", + " 'image': combinedNDVI,\n", + " 'region': bufferedBounds,\n", + " 'scale': 30\n", + " }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) \\\n", + " .setOptions({\n", + " 'title': 'NDVI Frequency Histogram',\n", + " 'hAxis': {\n", + " 'title': 'NDVI',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " },\n", + " },\n", + " 'vAxis':\n", + " {\n", + " 'title': 'Count',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'colors': ['cf513e', '1d6b99']\n", + " })\n", + "print(prePostNDVIFrequencyChart)\n", + "\n", + "# Import package to support text annotation.\n", + "text = require('users/gena/packages:text')\n", + "rgbVisParam = {\n", + " 'bands': ['red', 'green', 'blue'],\n", + " 'gamma': 1,\n", + " 'max': 12011,\n", + " 'min': 8114,\n", + " 'opacity': 1\n", + "}\n", + "\n", + "# Define arguments for animation function parameters.\n", + "videoArgs = {\n", + " 'region': bufferedBounds,\n", + " 'framesPerSecond': 3,\n", + " 'scale': 10\n", + "}\n", + "\n", + "annotations = [{\n", + " 'position': 'left',\n", + " 'offset': '5%',\n", + " 'margin': '5%',\n", + " 'property': 'label',\n", + " 'scale': 30\n", + "}]\n", + "\n", + "def addText(image):\n", + " date = ee.String(ee.Date(image.get('system:time_start')) \\\n", + " .format(' YYYY-MM-dd'))\n", + " # Set a property called label for each image.\n", + " image = image.clip(bufferedBounds).visualize(rgbVisParam) \\\n", + " .set({\n", + " 'label': date\n", + " })\n", + " # Create a new image with the label overlaid using gena's package.\n", + " annotated = text.annotateImage(image, {}, bufferedBounds,\n", + " annotations)\n", + " return annotated\n", + "\n", + "\n", + "# Add timestamp annotation to all images in video.\n", + "tempCol = ic.map(addText)\n", + "\n", + "# Click the URL to watch the time series video.\n", + "print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "###############################/\n", + "#/ Section Two: Mapping features within the refugee settlement\n", + "###############################/\n", + "\n", + "# Visualize Open Buildings dataset.\n", + "footprints = ee.FeatureCollection(\n", + " 'GOOGLE/Research/open-buildings/v1/polygons')\n", + "footprintsHigh = footprints.filter('confidence > 0.75')\n", + "footprintsLow = footprints.filter('confidence <= 0.75')\n", + "\n", + "Map.addLayer(footprintsHigh, {\n", + " 'color': 'FFA500'\n", + "}, 'Buildings high confidence')\n", + "Map.addLayer(footprintsLow, {\n", + " 'color': '800080'\n", + "}, 'Buildings low confidence')\n", + "\n", + "# Load land cover samples.\n", + "lcPts = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A1-7/lcPts')\n", + "print('lcPts', lcPts)\n", + "\n", + "# Create a function to set Feature properties based on value.\n", + "def setColor(f):\n", + " value = f.get('class')\n", + " mapDisplayColors = ee.List(['#13a1ed', '#7d02bf',\n", + " '#f0940a', '#d60909'\n", + " ])\n", + " # Use the class as an index to lookup the corresponding display color.\n", + " return f.set({\n", + " 'style': {\n", + " 'color': mapDisplayColors.get(value)\n", + " }\n", + " })\n", + "\n", + "\n", + "# Apply the function and view the results.\n", + "styled = lcPts.map(setColor)\n", + "Map.addLayer(styled.style(**{\n", + " 'styleProperty': 'style'\n", + "}), {}, 'Land cover samples')\n", + "\n", + "# Convert land cover sample FeatureCollection to an Image.\n", + "lcBand = lcPts.reduceToImage({\n", + " 'properties': ['class'],\n", + " 'reducer': ee.Reducer.first()\n", + "}).rename('class')\n", + "\n", + "# Add lcBand to the post-establishment composite.\n", + "postMedian = postMedian.addBands(lcBand)\n", + "\n", + "# Define bands that will be visualized in chart.\n", + "chartBands = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'class']\n", + "\n", + "print(postMedian, 'postMedian')\n", + "\n", + "# Plot median band value for each land cover type.\n", + "postBandsChart = ui.Chart.image \\\n", + " .byClass({\n", + " 'image': postMedian.select(chartBands),\n", + " 'classBand': 'class',\n", + " 'region': lcPts,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'scale': 30,\n", + " 'classLabels': ['Settlement', 'Road', 'Forest', 'Agriculture'],\n", + " 'xLabels': chartBands\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Band Values',\n", + " 'hAxis': {\n", + " 'title': 'Band Name',\n", + " 'titleTextStyle': '{italic': False, 'bold': True},\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Reflectance (x1e4)',\n", + " 'titleTextStyle': '{italic': False, 'bold': True}\n", + " },\n", + " 'colors': ['#13a1ed', '#7d02bf', '#f0940a','#d60909'],\n", + " 'pointSize': 0,\n", + " 'lineSize': 5,\n", + " 'curveType': 'function'\n", + " })\n", + "print(postBandsChart)\n", + "\n", + "# Define spectral indices that will be visualized in the chart.\n", + "indexBands = ['NDVI', 'NDBI', 'NBR', 'class']\n", + "\n", + "# Plot median index value for each land cover type.\n", + "postIndicesChart = ui.Chart.image \\\n", + " .byClass({\n", + " 'image': postMedian.select(indexBands),\n", + " 'classBand': 'class',\n", + " 'region': lcPts,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'scale': 30,\n", + " 'classLabels': ['Settlement', 'Road', 'Forest',\n", + " 'Agriculture'\n", + " ],\n", + " 'xLabels': indexBands\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Index Values',\n", + " 'hAxis': {\n", + " 'title': 'Index Name',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " },\n", + " #viewWindow: {min: wavelengths[0], max: wavelengths[2]}\n", + " 'scaleType': 'string'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Value',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'colors': ['#13a1ed', '#7d02bf', '#f0940a', '#d60909'],\n", + " 'pointSize': 5\n", + " })\n", + "print(postIndicesChart)\n", + "\n", + "# Create an empty image into which to paint the features, cast to byte.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Paint all the polygon edges with the same number and width, display.\n", + "pagirinyaOutline = empty.paint({\n", + " 'featureCollection': pagirinya,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Map outline of Pagirinya in blue.\n", + "Map.addLayer(pagirinyaOutline,\n", + " {\n", + " 'palette': '0000FF'\n", + " },\n", + " 'Pagirinya Refugee Settlement boundary')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##############################\n", + "#/ Section Three: Delineating refugee settlement boundaries\n", + "##############################\n", + "\n", + "# Create samples to input to a K-means classifier.\n", + "numPx = 500\n", + "samples = postMedian.select('NDVI').sample({\n", + " 'scale': 30, # Landsat resolution\n", + " 'numPixels': numPx,\n", + " 'geometries': True\n", + "})\n", + "\n", + "Map.addLayer(samples, {}, 'K-means samples')\n", + "\n", + "# Set-up the parameters for K-means.\n", + "numClusters = 2\n", + "maxIter = 5\n", + "seedValue = 21\n", + "\n", + "# Seed the classifier using land cover samples.\n", + "clusterer = ee.Clusterer.wekaKMeans({\n", + " 'nClusters': numClusters,\n", + " 'maxIterations': maxIter,\n", + " 'seed': seedValue\n", + "}).train(samples)\n", + "\n", + "# Apply the K-means classifier.\n", + "kmeansResult = postMedian.cluster(clusterer)\n", + "Map.addLayer(kmeansResult, {\n", + " 'bands': ['cluster'],\n", + " 'max': 1,\n", + " 'min': 0\n", + "}, 'K-means output')\n", + "\n", + "# Define the kernel used for morphological operations.\n", + "kernel = ee.Kernel.square({\n", + " 'radius': 3\n", + "})\n", + "\n", + "# Perform a dilation followed by an erosion.\n", + "kMeansCleaned = kmeansResult \\\n", + " .focal_max({\n", + " 'kernel': kernel,\n", + " 'iterations': 1\n", + " }) # Dilation \\\n", + " .focal_min({\n", + " 'kernel': kernel,\n", + " 'iterations': 1\n", + " }); # Erosion\n", + "Map.addLayer(kMeansCleaned, {\n", + " 'bands': ['cluster'],\n", + " 'max': 1,\n", + " 'min': 0\n", + "}, 'K-means cleaned')\n", + "\n", + "# Convert cleaned K-means settlement and non-settlement coverages to polygons.\n", + "kMeansCleanedPolygon = kMeansCleaned.reduceToVectors({\n", + " 'scale': 30,\n", + " 'eightConnected': True\n", + "})\n", + "\n", + "Map.addLayer(kMeansCleanedPolygon, {}, 'K-Means cleaned polygon')\n", + "\n", + "# Map outline of Pagirinya in blue.\n", + "Map.addLayer(pagirinyaOutline,\n", + " {\n", + " 'palette': '0000FF'\n", + " },\n", + " 'Pagirinya Refugee Settlement boundary')\n", + "\n", + "# Intersect K-means polygons with UNHCR settlement boundary and\n", + "# return intersection area as a feature property.\n", + "\n", + "def func_mbh(feat):\n", + " boundaryIsect = pagirinya.intersection(feat, ee \\\n", + " .ErrorMargin(1))\n", + " return ee.Feature(feat).set({\n", + " 'isectArea': boundaryIsect.area()\n", + " })\n", + "\n", + "kMeansIntersect = kMeansCleanedPolygon.map(func_mbh)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Sort to select the polygon with largest overlap with the UNHCR settlement boundary.\n", + "kMeansBoundary = ee.Feature(kMeansIntersect.sort('isectArea',\n", + " False).first())\n", + "Map.addLayer(kMeansBoundary, {}, 'K-Means Settlement Boundary')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##################################/\n", + "#/ Section Four: Estimating refugee population within the settlement\n", + "##################################/\n", + "\n", + "Map.centerObject(pagirinya, 14)\n", + "\n", + "ghslPop = ee.ImageCollection('JRC/GHSL/P2016/POP_GPW_GLOBE_V1') \\\n", + " .filter(ee.Filter.date('2015-01-01', '2016-01-01')).first() \\\n", + " .select(['population_count'], ['population'])\n", + "hrslPop = ee.Image('projects/gee-book/assets/A1-7/HRSL') \\\n", + " .select(['b1'], ['population'])\n", + "worldPop = ee.ImageCollection(\n", + " 'WorldPop/GP/100m/pop_age_sex_cons_unadj') \\\n", + " .filterMetadata('country', 'equals', 'UGA') \\\n", + " .first() \\\n", + " .select(['population'])\n", + "\n", + "# Set-up visualization to be shared by all population datasets.\n", + "visualization = {\n", + " 'bands': ['population'],\n", + " 'min': 0.0,\n", + " 'max': 50.0,\n", + " 'palette': ['24126c', '1fff4f', 'd4ff50']\n", + "}\n", + "\n", + "# Map population datasets.\n", + "Map.addLayer(ghslPop, visualization, 'GHSL Pop')\n", + "Map.addLayer(hrslPop, visualization, 'HRSL Pop')\n", + "Map.addLayer(worldPop, visualization, 'WorldPop')\n", + "\n", + "# Collect spatial resolution of each dataset.\n", + "ghslPopProjection = ghslPop.projection()\n", + "ghslPopScale = ghslPopProjection.nominalScale()\n", + "print(ghslPopScale, 'GHSL scale')\n", + "\n", + "hrslPopProjection = hrslPop.projection()\n", + "hrslPopScale = hrslPopProjection.nominalScale()\n", + "print(hrslPopScale, 'HRSL scale')\n", + "\n", + "worldPopProjection = worldPop.projection()\n", + "worldPopScale = worldPopProjection.nominalScale()\n", + "print(worldPopScale, 'WorldPop scale')\n", + "\n", + "# Summarize population totals for each population product at each settlement and\n", + "# assign as new properties to the UNHCR boundary Feature.\n", + "pagirinya = pagirinya.set(ghslPop.select(['population'], ['GHSL']) \\\n", + " .reduceRegion({\n", + " 'reducer': 'sum',\n", + " 'scale': ghslPopScale,\n", + " 'geometry': pagirinya.geometry(),\n", + " 'maxPixels': 1e9,\n", + " }))\n", + "\n", + "pagirinya = pagirinya.set(hrslPop.select(['population'], ['HRSL']) \\\n", + " .reduceRegion({\n", + " 'reducer': 'sum',\n", + " 'scale': hrslPopScale,\n", + " 'geometry': pagirinya.geometry(),\n", + " 'maxPixels': 1e9,\n", + " }))\n", + "\n", + "pagirinya = pagirinya.set(worldPop.select(['population'], [\n", + " 'WorldPop']) \\\n", + " .reduceRegion({\n", + " 'reducer': 'sum',\n", + " 'scale': worldPopScale,\n", + " 'geometry': pagirinya.geometry(),\n", + " 'maxPixels': 1e9,\n", + " }))\n", + "\n", + "print(pagirinya, 'Pagirinya with population estimates')\n", + "\n", + "# Measure difference between settlement product and UNHCR-recorded population values.\n", + "unhcrPopulation = ee.Number(pagirinya.get('UNHCR_Pop'))\n", + "ghslDiff = ee.Number(pagirinya.get('GHSL')).subtract(\n", + " unhcrPopulation)\n", + "hrslDiff = ee.Number(pagirinya.get('HRSL')).subtract(\n", + " unhcrPopulation)\n", + "worldPopDiff = ee.Number(pagirinya.get('WorldPop')).subtract(\n", + " unhcrPopulation)\n", + "\n", + "# Update UNHCR boundary Feature with population difference properties.\n", + "pagirinya = pagirinya.set(ee.Dictionary.fromLists(['GHSL_diff',\n", + " 'HRSL_diff', 'WorldPop_diff'\n", + " ],\n", + " [ghslDiff, hrslDiff, worldPopDiff]))\n", + "\n", + "print('Pagirinya Population Estimations', pagirinya)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17d Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17d Checkpoint.js new file mode 100644 index 0000000..96a1db3 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17d Checkpoint.js @@ -0,0 +1,544 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.7 Humanitarian Applications +// Checkpoint: A17d +// Authors: Jamon Van Den Hoek, Hannah K. Friedrich +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +////////////////////////////////////////////////////// +/// Section One: Seeing refugee settlements from above +////////////////////////////////////////////////////// +Map.setOptions('SATELLITE'); + +// Load UNHCR settlement boundary for Pagirinya Refugee Settlement. +var pagirinya = ee.Feature(ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary' +).first()); + +Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement'); +Map.centerObject(pagirinya, 14); + +// Create buffered settlement boundary geometry. +// 500 meter buffer size is arbitrary but large enough +// to capture area outside of the study settlement. +var bufferSize = 500; // (in meters) + +// Buffer and convert to Geometry for spatial filtering and clipping. +var bufferedBounds = pagirinya.buffer(bufferSize) + .bounds().geometry(); + +function addIndices(img) { + var ndvi = img.normalizedDifference(['nir', 'red']) + .rename('NDVI'); // NDVI = (nir-red)/(nir+red) + var ndbi = img.normalizedDifference(['swir1', 'nir']) + .rename(['NDBI']); // NDBI = (swir1-nir)/(swir1+nir) + var nbr = img.normalizedDifference(['nir', 'swir2']) + .rename(['NBR']); // NBR = (nir-swir2)/(nir+swir2) + var imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr); + return imgIndices; +} + +// Create L8 SR Collection 2 band names and new names. +var landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', + 'SR_B7' +]; +var landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']; + +// Create image collection. +var landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); +var ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01', + '2020-12-31') + .filterBounds(bufferedBounds) + .filter(ee.Filter.lt('CLOUD_COVER', 40)) + .select(landsat8BandNames, landsat8BandRename) + .map(addIndices)); + +// Make annual pre- and post-establishment composites. +var preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() + .clip(bufferedBounds); +var postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() + .clip(bufferedBounds); + +// Import visualization palettes https://github.com/gee-community/ee-palettes. +var palettes = require('users/gena/packages:palettes'); +var greenPalette = palettes.colorbrewer.Greens[9]; +var prGreenPalette = palettes.colorbrewer.PRGn[9]; + +// Set-up "true color" visualization parameters. +var TCImageVisParam = { + bands: ['red', 'green', 'blue'], + gamma: 1, + max: 13600, + min: 8400, + opacity: 1 +}; + +// Set-up "false color" visualization parameters. +var FCImageVisParam = { + bands: ['nir', 'red', 'green'], + gamma: 1, + min: 9000, + max: 20000, + opacity: 1 +}; + +// Display true-color composites. +Map.addLayer(preMedian, TCImageVisParam, + 'Pre-Establishment Median TC'); +Map.addLayer(postMedian, TCImageVisParam, + 'Post-Establishment Median TC'); + +// Display false-color composites. +Map.addLayer(preMedian, FCImageVisParam, + 'Pre-Establishment Median FC'); +Map.addLayer(postMedian, FCImageVisParam, + 'Post-Establishment Median FC'); + +// Display median NDVI composites. +Map.addLayer(preMedian, { + min: 0, + max: 0.7, + bands: ['NDVI'], + palette: greenPalette +}, 'Pre-Establishment Median NDVI'); +Map.addLayer(postMedian, { + min: 0, + max: 0.7, + bands: ['NDVI'], + palette: greenPalette +}, 'Post-Establishment Median NDVI'); + +// Create an empty byte Image into which we’ll paint the settlement boundary. +var empty = ee.Image().byte(); + +// Convert settlement boundary’s geometry to an Image for overlay. +var pagirinyaOutline = empty.paint({ + featureCollection: pagirinya, + color: 1, + width: 2 +}); + +// Display Pagirinya boundary in blue. +Map.addLayer(pagirinyaOutline, + { + palette: '0000FF' + }, + 'Pagirinya Refugee Settlement boundary'); + +// Compare pre- and post-establishment differences in NDVI. +var diffMedian = postMedian.subtract(preMedian); +Map.addLayer(diffMedian, + { + min: -0.1, + max: 0.1, + bands: ['NDVI'], + palette: prGreenPalette + }, + 'Difference Median NDVI'); + +// Chart the NDVI distributions for pre- and post-establishment. +var combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) + .addBands(postMedian.select(['NDVI'], ['post-NDVI'])); + +var prePostNDVIFrequencyChart = + ui.Chart.image.histogram({ + image: combinedNDVI, + region: bufferedBounds, + scale: 30 + }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) + .setOptions({ + title: 'NDVI Frequency Histogram', + hAxis: { + title: 'NDVI', + titleTextStyle: { + italic: false, + bold: true + }, + }, + vAxis: + { + title: 'Count', + titleTextStyle: { + italic: false, + bold: true + } + }, + colors: ['cf513e', '1d6b99'] + }); +print(prePostNDVIFrequencyChart); + +// Import package to support text annotation. +var text = require('users/gena/packages:text'); +var rgbVisParam = { + bands: ['red', 'green', 'blue'], + gamma: 1, + max: 12011, + min: 8114, + opacity: 1 +}; + +// Define arguments for animation function parameters. +var videoArgs = { + region: bufferedBounds, + framesPerSecond: 3, + scale: 10 +}; + +var annotations = [{ + position: 'left', + offset: '5%', + margin: '5%', + property: 'label', + scale: 30 +}]; + +function addText(image) { + var date = ee.String(ee.Date(image.get('system:time_start')) + .format(' YYYY-MM-dd')); + // Set a property called label for each image. + var image = image.clip(bufferedBounds).visualize(rgbVisParam) + .set({ + 'label': date + }); + // Create a new image with the label overlaid using gena's package. + var annotated = text.annotateImage(image, {}, bufferedBounds, + annotations); + return annotated; +} + +// Add timestamp annotation to all images in video. +var tempCol = ic.map(addText); + +// Click the URL to watch the time series video. +print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs)); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +/////////////////////////////////////////////////////////////// +/// Section Two: Mapping features within the refugee settlement +/////////////////////////////////////////////////////////////// + +// Visualize Open Buildings dataset. +var footprints = ee.FeatureCollection( + 'GOOGLE/Research/open-buildings/v1/polygons'); +var footprintsHigh = footprints.filter('confidence > 0.75'); +var footprintsLow = footprints.filter('confidence <= 0.75'); + +Map.addLayer(footprintsHigh, { + color: 'FFA500' +}, 'Buildings high confidence'); +Map.addLayer(footprintsLow, { + color: '800080' +}, 'Buildings low confidence'); + +// Load land cover samples. +var lcPts = ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/lcPts'); +print('lcPts', lcPts); + +// Create a function to set Feature properties based on value. +var setColor = function(f) { + var value = f.get('class'); + var mapDisplayColors = ee.List(['#13a1ed', '#7d02bf', + '#f0940a', '#d60909' + ]); + // Use the class as an index to lookup the corresponding display color. + return f.set({ + style: { + color: mapDisplayColors.get(value) + } + }); +}; + +// Apply the function and view the results. +var styled = lcPts.map(setColor); +Map.addLayer(styled.style({ + styleProperty: 'style' +}), {}, 'Land cover samples'); + +// Convert land cover sample FeatureCollection to an Image. +var lcBand = lcPts.reduceToImage({ + properties: ['class'], + reducer: ee.Reducer.first() +}).rename('class'); + +// Add lcBand to the post-establishment composite. +postMedian = postMedian.addBands(lcBand); + +// Define bands that will be visualized in chart. +var chartBands = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'class']; + +print(postMedian, 'postMedian'); + +// Plot median band value for each land cover type. +var postBandsChart = ui.Chart.image + .byClass({ + image: postMedian.select(chartBands), + classBand: 'class', + region: lcPts, + reducer: ee.Reducer.median(), + scale: 30, + classLabels: ['Settlement', 'Road', 'Forest', 'Agriculture'], + xLabels: chartBands + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Band Values', + hAxis: { + title: 'Band Name', + titleTextStyle: {italic: false, bold: true}, + }, + vAxis: { + title: 'Reflectance (x1e4)', + titleTextStyle: {italic: false, bold: true} + }, + colors: ['#13a1ed', '#7d02bf', '#f0940a','#d60909'], + pointSize: 0, + lineSize: 5, + curveType: 'function' + }); +print(postBandsChart); + +// Define spectral indices that will be visualized in the chart. +var indexBands = ['NDVI', 'NDBI', 'NBR', 'class']; + +// Plot median index value for each land cover type. +var postIndicesChart = ui.Chart.image + .byClass({ + image: postMedian.select(indexBands), + classBand: 'class', + region: lcPts, + reducer: ee.Reducer.median(), + scale: 30, + classLabels: ['Settlement', 'Road', 'Forest', + 'Agriculture' + ], + xLabels: indexBands + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Index Values', + hAxis: { + title: 'Index Name', + titleTextStyle: { + italic: false, + bold: true + }, + //viewWindow: {min: wavelengths[0], max: wavelengths[2]} + scaleType: 'string' + }, + vAxis: { + title: 'Value', + titleTextStyle: { + italic: false, + bold: true + } + }, + colors: ['#13a1ed', '#7d02bf', '#f0940a', '#d60909'], + pointSize: 5 + }); +print(postIndicesChart); + +// Create an empty image into which to paint the features, cast to byte. +var empty = ee.Image().byte(); + +// Paint all the polygon edges with the same number and width, display. +var pagirinyaOutline = empty.paint({ + featureCollection: pagirinya, + color: 1, + width: 2 +}); + +// Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + palette: '0000FF' + }, + 'Pagirinya Refugee Settlement boundary'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//////////////////////////////////////////////////////////// +/// Section Three: Delineating refugee settlement boundaries +//////////////////////////////////////////////////////////// + +// Create samples to input to a K-means classifier. +var numPx = 500; +var samples = postMedian.select('NDVI').sample({ + scale: 30, // Landsat resolution + numPixels: numPx, + geometries: true +}); + +Map.addLayer(samples, {}, 'K-means samples'); + +// Set-up the parameters for K-means. +var numClusters = 2; +var maxIter = 5; +var seedValue = 21; + +// Seed the classifier using land cover samples. +var clusterer = ee.Clusterer.wekaKMeans({ + nClusters: numClusters, + maxIterations: maxIter, + seed: seedValue +}).train(samples); + +// Apply the K-means classifier. +var kmeansResult = postMedian.cluster(clusterer); +Map.addLayer(kmeansResult, { + bands: ['cluster'], + max: 1, + min: 0 +}, 'K-means output'); + +// Define the kernel used for morphological operations. +var kernel = ee.Kernel.square({ + radius: 3 +}); + +// Perform a dilation followed by an erosion. +var kMeansCleaned = kmeansResult + .focal_max({ + kernel: kernel, + iterations: 1 + }) // Dilation + .focal_min({ + kernel: kernel, + iterations: 1 + }); // Erosion +Map.addLayer(kMeansCleaned, { + bands: ['cluster'], + max: 1, + min: 0 +}, 'K-means cleaned'); + +// Convert cleaned K-means settlement and non-settlement coverages to polygons. +var kMeansCleanedPolygon = kMeansCleaned.reduceToVectors({ + scale: 30, + eightConnected: true +}); + +Map.addLayer(kMeansCleanedPolygon, {}, 'K-Means cleaned polygon'); + +// Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + palette: '0000FF' + }, + 'Pagirinya Refugee Settlement boundary'); + +// Intersect K-means polygons with UNHCR settlement boundary and +// return intersection area as a feature property. +var kMeansIntersect = kMeansCleanedPolygon.map(function(feat) { + var boundaryIsect = pagirinya.intersection(feat, ee + .ErrorMargin(1)); + return ee.Feature(feat).set({ + 'isectArea': boundaryIsect.area() + }); +}); + +// Sort to select the polygon with largest overlap with the UNHCR settlement boundary. +var kMeansBoundary = ee.Feature(kMeansIntersect.sort('isectArea', + false).first()); +Map.addLayer(kMeansBoundary, {}, 'K-Means Settlement Boundary'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///////////////////////////////////////////////////////////////////// +/// Section Four: Estimating refugee population within the settlement +///////////////////////////////////////////////////////////////////// + +Map.centerObject(pagirinya, 14); + +var ghslPop = ee.ImageCollection('JRC/GHSL/P2016/POP_GPW_GLOBE_V1') + .filter(ee.Filter.date('2015-01-01', '2016-01-01')).first() + .select(['population_count'], ['population']); +var hrslPop = ee.Image('projects/gee-book/assets/A1-7/HRSL') + .select(['b1'], ['population']); +var worldPop = ee.ImageCollection( + 'WorldPop/GP/100m/pop_age_sex_cons_unadj') + .filterMetadata('country', 'equals', 'UGA') + .first() + .select(['population']); + +// Set-up visualization to be shared by all population datasets. +var visualization = { + bands: ['population'], + min: 0.0, + max: 50.0, + palette: ['24126c', '1fff4f', 'd4ff50'] +}; + +// Map population datasets. +Map.addLayer(ghslPop, visualization, 'GHSL Pop'); +Map.addLayer(hrslPop, visualization, 'HRSL Pop'); +Map.addLayer(worldPop, visualization, 'WorldPop'); + +// Collect spatial resolution of each dataset. +var ghslPopProjection = ghslPop.projection(); +var ghslPopScale = ghslPopProjection.nominalScale(); +print(ghslPopScale, 'GHSL scale'); + +var hrslPopProjection = hrslPop.projection(); +var hrslPopScale = hrslPopProjection.nominalScale(); +print(hrslPopScale, 'HRSL scale'); + +var worldPopProjection = worldPop.projection(); +var worldPopScale = worldPopProjection.nominalScale(); +print(worldPopScale, 'WorldPop scale'); + +// Summarize population totals for each population product at each settlement and +// assign as new properties to the UNHCR boundary Feature. +pagirinya = pagirinya.set(ghslPop.select(['population'], ['GHSL']) + .reduceRegion({ + reducer: 'sum', + scale: ghslPopScale, + geometry: pagirinya.geometry(), + maxPixels: 1e9, + })); + +pagirinya = pagirinya.set(hrslPop.select(['population'], ['HRSL']) + .reduceRegion({ + reducer: 'sum', + scale: hrslPopScale, + geometry: pagirinya.geometry(), + maxPixels: 1e9, + })); + +pagirinya = pagirinya.set(worldPop.select(['population'], [ + 'WorldPop']) + .reduceRegion({ + reducer: 'sum', + scale: worldPopScale, + geometry: pagirinya.geometry(), + maxPixels: 1e9, + })); + +print(pagirinya, 'Pagirinya with population estimates'); + +// Measure difference between settlement product and UNHCR-recorded population values. +var unhcrPopulation = ee.Number(pagirinya.get('UNHCR_Pop')); +var ghslDiff = ee.Number(pagirinya.get('GHSL')).subtract( + unhcrPopulation); +var hrslDiff = ee.Number(pagirinya.get('HRSL')).subtract( + unhcrPopulation); +var worldPopDiff = ee.Number(pagirinya.get('WorldPop')).subtract( + unhcrPopulation); + +// Update UNHCR boundary Feature with population difference properties. +pagirinya = pagirinya.set(ee.Dictionary.fromLists(['GHSL_diff', + 'HRSL_diff', 'WorldPop_diff' + ], + [ghslDiff, hrslDiff, worldPopDiff])); + +print('Pagirinya Population Estimations', pagirinya); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17d Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17d Checkpoint.py new file mode 100644 index 0000000..b7a9882 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.7 Humanitarian Applications/A17d Checkpoint.py @@ -0,0 +1,559 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.7 Humanitarian Applications +# Checkpoint: A17d +# Authors: Jamon Van Den Hoek, Hannah K. Friedrich +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +########################### +#/ Section One: Seeing refugee settlements from above +########################### +Map.setOptions('SATELLITE') + +# Load UNHCR settlement boundary for Pagirinya Refugee Settlement. +pagirinya = ee.Feature(ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/pagirinya_settlement_boundary' +).first()) + +Map.addLayer(pagirinya, {}, 'Pagirinya Refugee Settlement') +Map.centerObject(pagirinya, 14) + +# Create buffered settlement boundary geometry. +# 500 meter buffer size is arbitrary but large enough +# to capture area outside of the study settlement. +bufferSize = 500; # (in meters) + +# Buffer and convert to Geometry for spatial filtering and clipping. +bufferedBounds = pagirinya.buffer(bufferSize) \ + .bounds().geometry() + +def addIndices(img): + ndvi = img.normalizedDifference(['nir', 'red']) \ + .rename('NDVI'); + ndbi = img.normalizedDifference(['swir1', 'nir']) \ + .rename(['NDBI']); + nbr = img.normalizedDifference(['nir', 'swir2']) \ + .rename(['NBR']); + imgIndices = img.addBands(ndvi).addBands(ndbi).addBands(nbr) + return imgIndices + + +# Create L8 SR Collection 2 band names and new names. +landsat8BandNames = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', + 'SR_B7' +] +landsat8BandRename = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'] + +# Create image collection. +landsat8Sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') +ic = ee.ImageCollection(landsat8Sr.filterDate('2015-01-01', + '2020-12-31') \ + .filterBounds(bufferedBounds) \ + .filter(ee.Filter.lt('CLOUD_COVER', 40)) \ + .select(landsat8BandNames, landsat8BandRename) \ + .map(addIndices)) + +# Make annual pre- and post-establishment composites. +preMedian = ic.filterDate('2015-01-01', '2015-12-31').median() \ + .clip(bufferedBounds) +postMedian = ic.filterDate('2017-01-01', '2017-12-31').median() \ + .clip(bufferedBounds) + +# Import visualization palettes https:#github.com/gee-community/ee-palettes. +palettes = require('users/gena/packages:palettes') +greenPalette = palettes.colorbrewer.Greens[9] +prGreenPalette = palettes.colorbrewer.PRGn[9] + +# Set-up "True color" visualization parameters. +TCImageVisParam = { + 'bands': ['red', 'green', 'blue'], + 'gamma': 1, + 'max': 13600, + 'min': 8400, + 'opacity': 1 +} + +# Set-up "False color" visualization parameters. +FCImageVisParam = { + 'bands': ['nir', 'red', 'green'], + 'gamma': 1, + 'min': 9000, + 'max': 20000, + 'opacity': 1 +} + +# Display True-color composites. +Map.addLayer(preMedian, TCImageVisParam, + 'Pre-Establishment Median TC') +Map.addLayer(postMedian, TCImageVisParam, + 'Post-Establishment Median TC') + +# Display False-color composites. +Map.addLayer(preMedian, FCImageVisParam, + 'Pre-Establishment Median FC') +Map.addLayer(postMedian, FCImageVisParam, + 'Post-Establishment Median FC') + +# Display median NDVI composites. +Map.addLayer(preMedian, { + 'min': 0, + 'max': 0.7, + 'bands': ['NDVI'], + 'palette': greenPalette +}, 'Pre-Establishment Median NDVI') +Map.addLayer(postMedian, { + 'min': 0, + 'max': 0.7, + 'bands': ['NDVI'], + 'palette': greenPalette +}, 'Post-Establishment Median NDVI') + +# Create an empty byte Image into which we’ll paint the settlement boundary. +empty = ee.Image().byte() + +# Convert settlement boundary’s geometry to an Image for overlay. +pagirinyaOutline = empty.paint({ + 'featureCollection': pagirinya, + 'color': 1, + 'width': 2 +}) + +# Display Pagirinya boundary in blue. +Map.addLayer(pagirinyaOutline, + { + 'palette': '0000FF' + }, + 'Pagirinya Refugee Settlement boundary') + +# Compare pre- and post-establishment differences in NDVI. +diffMedian = postMedian.subtract(preMedian) +Map.addLayer(diffMedian, + { + 'min': -0.1, + 'max': 0.1, + 'bands': ['NDVI'], + 'palette': prGreenPalette + }, + 'Difference Median NDVI') + +# Chart the NDVI distributions for pre- and post-establishment. +combinedNDVI = preMedian.select(['NDVI'], ['pre-NDVI']) \ + .addBands(postMedian.select(['NDVI'], ['post-NDVI'])) + +prePostNDVIFrequencyChart = + ui.Chart.image.histogram({ + 'image': combinedNDVI, + 'region': bufferedBounds, + 'scale': 30 + }).setSeriesNames(['Pre-Establishment', 'Post-Establishment']) \ + .setOptions({ + 'title': 'NDVI Frequency Histogram', + 'hAxis': { + 'title': 'NDVI', + 'titleTextStyle': { + 'italic': False, + 'bold': True + }, + }, + 'vAxis': + { + 'title': 'Count', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'colors': ['cf513e', '1d6b99'] + }) +print(prePostNDVIFrequencyChart) + +# Import package to support text annotation. +text = require('users/gena/packages:text') +rgbVisParam = { + 'bands': ['red', 'green', 'blue'], + 'gamma': 1, + 'max': 12011, + 'min': 8114, + 'opacity': 1 +} + +# Define arguments for animation function parameters. +videoArgs = { + 'region': bufferedBounds, + 'framesPerSecond': 3, + 'scale': 10 +} + +annotations = [{ + 'position': 'left', + 'offset': '5%', + 'margin': '5%', + 'property': 'label', + 'scale': 30 +}] + +def addText(image): + date = ee.String(ee.Date(image.get('system:time_start')) \ + .format(' YYYY-MM-dd')) + # Set a property called label for each image. + image = image.clip(bufferedBounds).visualize(rgbVisParam) \ + .set({ + 'label': date + }) + # Create a new image with the label overlaid using gena's package. + annotated = text.annotateImage(image, {}, bufferedBounds, + annotations) + return annotated + + +# Add timestamp annotation to all images in video. +tempCol = ic.map(addText) + +# Click the URL to watch the time series video. +print('L8 Time Series Video', tempCol.getVideoThumbURL(videoArgs)) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +###############################/ +#/ Section Two: Mapping features within the refugee settlement +###############################/ + +# Visualize Open Buildings dataset. +footprints = ee.FeatureCollection( + 'GOOGLE/Research/open-buildings/v1/polygons') +footprintsHigh = footprints.filter('confidence > 0.75') +footprintsLow = footprints.filter('confidence <= 0.75') + +Map.addLayer(footprintsHigh, { + 'color': 'FFA500' +}, 'Buildings high confidence') +Map.addLayer(footprintsLow, { + 'color': '800080' +}, 'Buildings low confidence') + +# Load land cover samples. +lcPts = ee.FeatureCollection( + 'projects/gee-book/assets/A1-7/lcPts') +print('lcPts', lcPts) + +# Create a function to set Feature properties based on value. +def setColor(f): + value = f.get('class') + mapDisplayColors = ee.List(['#13a1ed', '#7d02bf', + '#f0940a', '#d60909' + ]) + # Use the class as an index to lookup the corresponding display color. + return f.set({ + 'style': { + 'color': mapDisplayColors.get(value) + } + }) + + +# Apply the function and view the results. +styled = lcPts.map(setColor) +Map.addLayer(styled.style(**{ + 'styleProperty': 'style' +}), {}, 'Land cover samples') + +# Convert land cover sample FeatureCollection to an Image. +lcBand = lcPts.reduceToImage({ + 'properties': ['class'], + 'reducer': ee.Reducer.first() +}).rename('class') + +# Add lcBand to the post-establishment composite. +postMedian = postMedian.addBands(lcBand) + +# Define bands that will be visualized in chart. +chartBands = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'class'] + +print(postMedian, 'postMedian') + +# Plot median band value for each land cover type. +postBandsChart = ui.Chart.image \ + .byClass({ + 'image': postMedian.select(chartBands), + 'classBand': 'class', + 'region': lcPts, + 'reducer': ee.Reducer.median(), + 'scale': 30, + 'classLabels': ['Settlement', 'Road', 'Forest', 'Agriculture'], + 'xLabels': chartBands + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Band Values', + 'hAxis': { + 'title': 'Band Name', + 'titleTextStyle': '{italic': False, 'bold': True}, + }, + 'vAxis': { + 'title': 'Reflectance (x1e4)', + 'titleTextStyle': '{italic': False, 'bold': True} + }, + 'colors': ['#13a1ed', '#7d02bf', '#f0940a','#d60909'], + 'pointSize': 0, + 'lineSize': 5, + 'curveType': 'function' + }) +print(postBandsChart) + +# Define spectral indices that will be visualized in the chart. +indexBands = ['NDVI', 'NDBI', 'NBR', 'class'] + +# Plot median index value for each land cover type. +postIndicesChart = ui.Chart.image \ + .byClass({ + 'image': postMedian.select(indexBands), + 'classBand': 'class', + 'region': lcPts, + 'reducer': ee.Reducer.median(), + 'scale': 30, + 'classLabels': ['Settlement', 'Road', 'Forest', + 'Agriculture' + ], + 'xLabels': indexBands + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Index Values', + 'hAxis': { + 'title': 'Index Name', + 'titleTextStyle': { + 'italic': False, + 'bold': True + }, + #viewWindow: {min: wavelengths[0], max: wavelengths[2]} + 'scaleType': 'string' + }, + 'vAxis': { + 'title': 'Value', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'colors': ['#13a1ed', '#7d02bf', '#f0940a', '#d60909'], + 'pointSize': 5 + }) +print(postIndicesChart) + +# Create an empty image into which to paint the features, cast to byte. +empty = ee.Image().byte() + +# Paint all the polygon edges with the same number and width, display. +pagirinyaOutline = empty.paint({ + 'featureCollection': pagirinya, + 'color': 1, + 'width': 2 +}) + +# Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + 'palette': '0000FF' + }, + 'Pagirinya Refugee Settlement boundary') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +############################## +#/ Section Three: Delineating refugee settlement boundaries +############################## + +# Create samples to input to a K-means classifier. +numPx = 500 +samples = postMedian.select('NDVI').sample({ + 'scale': 30, # Landsat resolution + 'numPixels': numPx, + 'geometries': True +}) + +Map.addLayer(samples, {}, 'K-means samples') + +# Set-up the parameters for K-means. +numClusters = 2 +maxIter = 5 +seedValue = 21 + +# Seed the classifier using land cover samples. +clusterer = ee.Clusterer.wekaKMeans({ + 'nClusters': numClusters, + 'maxIterations': maxIter, + 'seed': seedValue +}).train(samples) + +# Apply the K-means classifier. +kmeansResult = postMedian.cluster(clusterer) +Map.addLayer(kmeansResult, { + 'bands': ['cluster'], + 'max': 1, + 'min': 0 +}, 'K-means output') + +# Define the kernel used for morphological operations. +kernel = ee.Kernel.square({ + 'radius': 3 +}) + +# Perform a dilation followed by an erosion. +kMeansCleaned = kmeansResult \ + .focal_max({ + 'kernel': kernel, + 'iterations': 1 + }) # Dilation \ + .focal_min({ + 'kernel': kernel, + 'iterations': 1 + }); # Erosion +Map.addLayer(kMeansCleaned, { + 'bands': ['cluster'], + 'max': 1, + 'min': 0 +}, 'K-means cleaned') + +# Convert cleaned K-means settlement and non-settlement coverages to polygons. +kMeansCleanedPolygon = kMeansCleaned.reduceToVectors({ + 'scale': 30, + 'eightConnected': True +}) + +Map.addLayer(kMeansCleanedPolygon, {}, 'K-Means cleaned polygon') + +# Map outline of Pagirinya in blue. +Map.addLayer(pagirinyaOutline, + { + 'palette': '0000FF' + }, + 'Pagirinya Refugee Settlement boundary') + +# Intersect K-means polygons with UNHCR settlement boundary and +# return intersection area as a feature property. + +def func_mbh(feat): + boundaryIsect = pagirinya.intersection(feat, ee \ + .ErrorMargin(1)) + return ee.Feature(feat).set({ + 'isectArea': boundaryIsect.area() + }) + +kMeansIntersect = kMeansCleanedPolygon.map(func_mbh) + + + + + + + + +# Sort to select the polygon with largest overlap with the UNHCR settlement boundary. +kMeansBoundary = ee.Feature(kMeansIntersect.sort('isectArea', + False).first()) +Map.addLayer(kMeansBoundary, {}, 'K-Means Settlement Boundary') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##################################/ +#/ Section Four: Estimating refugee population within the settlement +##################################/ + +Map.centerObject(pagirinya, 14) + +ghslPop = ee.ImageCollection('JRC/GHSL/P2016/POP_GPW_GLOBE_V1') \ + .filter(ee.Filter.date('2015-01-01', '2016-01-01')).first() \ + .select(['population_count'], ['population']) +hrslPop = ee.Image('projects/gee-book/assets/A1-7/HRSL') \ + .select(['b1'], ['population']) +worldPop = ee.ImageCollection( + 'WorldPop/GP/100m/pop_age_sex_cons_unadj') \ + .filterMetadata('country', 'equals', 'UGA') \ + .first() \ + .select(['population']) + +# Set-up visualization to be shared by all population datasets. +visualization = { + 'bands': ['population'], + 'min': 0.0, + 'max': 50.0, + 'palette': ['24126c', '1fff4f', 'd4ff50'] +} + +# Map population datasets. +Map.addLayer(ghslPop, visualization, 'GHSL Pop') +Map.addLayer(hrslPop, visualization, 'HRSL Pop') +Map.addLayer(worldPop, visualization, 'WorldPop') + +# Collect spatial resolution of each dataset. +ghslPopProjection = ghslPop.projection() +ghslPopScale = ghslPopProjection.nominalScale() +print(ghslPopScale, 'GHSL scale') + +hrslPopProjection = hrslPop.projection() +hrslPopScale = hrslPopProjection.nominalScale() +print(hrslPopScale, 'HRSL scale') + +worldPopProjection = worldPop.projection() +worldPopScale = worldPopProjection.nominalScale() +print(worldPopScale, 'WorldPop scale') + +# Summarize population totals for each population product at each settlement and +# assign as new properties to the UNHCR boundary Feature. +pagirinya = pagirinya.set(ghslPop.select(['population'], ['GHSL']) \ + .reduceRegion({ + 'reducer': 'sum', + 'scale': ghslPopScale, + 'geometry': pagirinya.geometry(), + 'maxPixels': 1e9, + })) + +pagirinya = pagirinya.set(hrslPop.select(['population'], ['HRSL']) \ + .reduceRegion({ + 'reducer': 'sum', + 'scale': hrslPopScale, + 'geometry': pagirinya.geometry(), + 'maxPixels': 1e9, + })) + +pagirinya = pagirinya.set(worldPop.select(['population'], [ + 'WorldPop']) \ + .reduceRegion({ + 'reducer': 'sum', + 'scale': worldPopScale, + 'geometry': pagirinya.geometry(), + 'maxPixels': 1e9, + })) + +print(pagirinya, 'Pagirinya with population estimates') + +# Measure difference between settlement product and UNHCR-recorded population values. +unhcrPopulation = ee.Number(pagirinya.get('UNHCR_Pop')) +ghslDiff = ee.Number(pagirinya.get('GHSL')).subtract( + unhcrPopulation) +hrslDiff = ee.Number(pagirinya.get('HRSL')).subtract( + unhcrPopulation) +worldPopDiff = ee.Number(pagirinya.get('WorldPop')).subtract( + unhcrPopulation) + +# Update UNHCR boundary Feature with population difference properties. +pagirinya = pagirinya.set(ee.Dictionary.fromLists(['GHSL_diff', + 'HRSL_diff', 'WorldPop_diff' + ], + [ghslDiff, hrslDiff, worldPopDiff])) + +print('Pagirinya Population Estimations', pagirinya) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18a Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18a Checkpoint.ipynb new file mode 100644 index 0000000..20652fb --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18a Checkpoint.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.8 Monitoring Gold Mining Activity using SAR\n", + "# Checkpoint: A18a\n", + "# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra,\n", + "# Andr\u00e9a Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "###########################\n", + "#/ Section One\n", + "###########################\n", + "\n", + "# Define the area of study.\n", + "aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd')\n", + "\n", + "# Center the map at the aoi.\n", + "Map.centerObject(aoi, 9)\n", + "\n", + "# Create an empty image.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Convert the area of study to an EE image object\n", + "# so we can visualize only the boundary.\n", + "aoiOutline = empty.paint({\n", + " 'featureCollection': aoi,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Select the satellite basemap view.\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Add the area of study boundary to the map.\n", + "Map.addLayer(aoiOutline, {\n", + " 'palette': 'red'\n", + "}, 'Area of Study')\n", + "\n", + "# Function to mask the SAR images acquired with an incidence angle\n", + "# lower or equal to 31 and greater or equal to 45 degrees.\n", + "def maskAngle(image):\n", + " angleMask = image.select('angle')\n", + " return image.updateMask(angleMask.gte(31).And(angleMask.lte(45)))\n", + "\n", + "\n", + "# Function to get the SAR Collection.\n", + "def getCollection(dates, roi, orbitPass0):\n", + " sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate(dates[0], dates[1]) \\\n", + " .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0))\n", + " return sarCollFloat.map(maskAngle).select(['VV', 'VH'])\n", + "\n", + "\n", + "# Define variables: the period of time and the orbitpass.\n", + "listOfDates = ['2021-08-01', '2021-08-12']\n", + "orbitPass = 'DESCENDING'\n", + "\n", + "# Apply the function to get the SAR mosaic.\n", + "sarImageColl = getCollection(listOfDates, aoi, orbitPass) \\\n", + " .mosaic() \\\n", + " .clip(aoi)\n", + "print('SAR Image Mosaic', sarImageColl)\n", + "\n", + "# Apply logarithmic scale.\n", + "sarImageScaled = sarImageColl.log10().multiply(10.0)\n", + "\n", + "# Visualize results.\n", + "sarVis = {\n", + " 'bands': ['VV', 'VH', 'VV'],\n", + " 'min': [-18, -23, 3],\n", + " 'max': [-4, -11, 15]\n", + "}\n", + "Map.addLayer(sarImageScaled, sarVis, 'Sentinel-1 / SAR Mosaic')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18a Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18a Checkpoint.js new file mode 100644 index 0000000..4410de5 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18a Checkpoint.js @@ -0,0 +1,76 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.8 Monitoring Gold Mining Activity using SAR +// Checkpoint: A18a +// Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +// Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +////////////////////////////////////////////////////// +/// Section One +////////////////////////////////////////////////////// + +// Define the area of study. +var aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd'); + +// Center the map at the aoi. +Map.centerObject(aoi, 9); + +// Create an empty image. +var empty = ee.Image().byte(); + +// Convert the area of study to an EE image object +// so we can visualize only the boundary. +var aoiOutline = empty.paint({ + featureCollection: aoi, + color: 1, + width: 2 +}); + +// Select the satellite basemap view. +Map.setOptions('SATELLITE'); + +// Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + palette: 'red' +}, 'Area of Study'); + +// Function to mask the SAR images acquired with an incidence angle +// lower or equal to 31 and greater or equal to 45 degrees. +function maskAngle(image) { + var angleMask = image.select('angle'); + return image.updateMask(angleMask.gte(31).and(angleMask.lte(45))); +} + +// Function to get the SAR Collection. +function getCollection(dates, roi, orbitPass0) { + var sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') + .filterBounds(roi) + .filterDate(dates[0], dates[1]) + .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0)); + return sarCollFloat.map(maskAngle).select(['VV', 'VH']); +} + +// Define variables: the period of time and the orbitpass. +var listOfDates = ['2021-08-01', '2021-08-12']; +var orbitPass = 'DESCENDING'; + +// Apply the function to get the SAR mosaic. +var sarImageColl = getCollection(listOfDates, aoi, orbitPass) + .mosaic() + .clip(aoi); +print('SAR Image Mosaic', sarImageColl); + +// Apply logarithmic scale. +var sarImageScaled = sarImageColl.log10().multiply(10.0); + +// Visualize results. +var sarVis = { + bands: ['VV', 'VH', 'VV'], + min: [-18, -23, 3], + max: [-4, -11, 15] +}; +Map.addLayer(sarImageScaled, sarVis, 'Sentinel-1 / SAR Mosaic'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18a Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18a Checkpoint.py new file mode 100644 index 0000000..1961193 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18a Checkpoint.py @@ -0,0 +1,82 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.8 Monitoring Gold Mining Activity using SAR +# Checkpoint: A18a +# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +# Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +########################### +#/ Section One +########################### + +# Define the area of study. +aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd') + +# Center the map at the aoi. +Map.centerObject(aoi, 9) + +# Create an empty image. +empty = ee.Image().byte() + +# Convert the area of study to an EE image object +# so we can visualize only the boundary. +aoiOutline = empty.paint({ + 'featureCollection': aoi, + 'color': 1, + 'width': 2 +}) + +# Select the satellite basemap view. +Map.setOptions('SATELLITE') + +# Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + 'palette': 'red' +}, 'Area of Study') + +# Function to mask the SAR images acquired with an incidence angle +# lower or equal to 31 and greater or equal to 45 degrees. +def maskAngle(image): + angleMask = image.select('angle') + return image.updateMask(angleMask.gte(31).And(angleMask.lte(45))) + + +# Function to get the SAR Collection. +def getCollection(dates, roi, orbitPass0): + sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') \ + .filterBounds(roi) \ + .filterDate(dates[0], dates[1]) \ + .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0)) + return sarCollFloat.map(maskAngle).select(['VV', 'VH']) + + +# Define variables: the period of time and the orbitpass. +listOfDates = ['2021-08-01', '2021-08-12'] +orbitPass = 'DESCENDING' + +# Apply the function to get the SAR mosaic. +sarImageColl = getCollection(listOfDates, aoi, orbitPass) \ + .mosaic() \ + .clip(aoi) +print('SAR Image Mosaic', sarImageColl) + +# Apply logarithmic scale. +sarImageScaled = sarImageColl.log10().multiply(10.0) + +# Visualize results. +sarVis = { + 'bands': ['VV', 'VH', 'VV'], + 'min': [-18, -23, 3], + 'max': [-4, -11, 15] +} +Map.addLayer(sarImageScaled, sarVis, 'Sentinel-1 / SAR Mosaic') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18b Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18b Checkpoint.ipynb new file mode 100644 index 0000000..768fbe7 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18b Checkpoint.ipynb @@ -0,0 +1,156 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.8 Monitoring Gold Mining Activity using SAR\n", + "# Checkpoint: A18b\n", + "# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra,\n", + "# Andr\u00e9a Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "###########################\n", + "#/ Section Two\n", + "###########################\n", + "\n", + "# Define the area of study.\n", + "aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd')\n", + "\n", + "# Center the map at the aoi.\n", + "Map.centerObject(aoi, 9)\n", + "\n", + "# Create an empty image.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Convert the area of study to an EE image object\n", + "# so we can visualize only the boundary.\n", + "aoiOutline = empty.paint({\n", + " 'featureCollection': aoi,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Select the satellite basemap view.\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Add the area of study boundary to the map.\n", + "Map.addLayer(aoiOutline, {\n", + " 'palette': 'red'\n", + "}, 'Area of Study')\n", + "\n", + "# Function to mask the SAR images acquired with an incidence angle\n", + "# lower equal than 31 and greater equal than 45 degrees.\n", + "def maskAngle(image):\n", + " angleMask = image.select('angle')\n", + " return image.updateMask(angleMask.gte(31).And(angleMask.lte(45)))\n", + "\n", + "\n", + "# Function to get the SAR Collection.\n", + "def getCollection(dates, roi, orbitPass0):\n", + " sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate(dates[0], dates[1]) \\\n", + " .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0))\n", + " return sarCollFloat.map(maskAngle).select(['VV', 'VH'])\n", + "\n", + "\n", + "# Define variables: the period of time and the orbitpass.\n", + "listOfDates = ['2021-01-01', '2022-01-01']\n", + "orbitPass = 'DESCENDING'\n", + "\n", + "# Apply the function to get the SAR Collection.\n", + "sarImageColl = getCollection(listOfDates, aoi, orbitPass)\n", + "print('SAR Image Collection', sarImageColl)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18b Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18b Checkpoint.js new file mode 100644 index 0000000..4caee06 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18b Checkpoint.js @@ -0,0 +1,63 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.8 Monitoring Gold Mining Activity using SAR +// Checkpoint: A18b +// Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +// Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +////////////////////////////////////////////////////// +/// Section Two +////////////////////////////////////////////////////// + +// Define the area of study. +var aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd'); + +// Center the map at the aoi. +Map.centerObject(aoi, 9); + +// Create an empty image. +var empty = ee.Image().byte(); + +// Convert the area of study to an EE image object +// so we can visualize only the boundary. +var aoiOutline = empty.paint({ + featureCollection: aoi, + color: 1, + width: 2 +}); + +// Select the satellite basemap view. +Map.setOptions('SATELLITE'); + +// Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + palette: 'red' +}, 'Area of Study'); + +// Function to mask the SAR images acquired with an incidence angle +// lower equal than 31 and greater equal than 45 degrees. +function maskAngle(image) { + var angleMask = image.select('angle'); + return image.updateMask(angleMask.gte(31).and(angleMask.lte(45))); +} + +// Function to get the SAR Collection. +function getCollection(dates, roi, orbitPass0) { + var sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') + .filterBounds(roi) + .filterDate(dates[0], dates[1]) + .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0)); + return sarCollFloat.map(maskAngle).select(['VV', 'VH']); +} + +// Define variables: the period of time and the orbitpass. +var listOfDates = ['2021-01-01', '2022-01-01']; +var orbitPass = 'DESCENDING'; + +// Apply the function to get the SAR Collection. +var sarImageColl = getCollection(listOfDates, aoi, orbitPass); +print('SAR Image Collection', sarImageColl); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18b Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18b Checkpoint.py new file mode 100644 index 0000000..031872d --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18b Checkpoint.py @@ -0,0 +1,69 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.8 Monitoring Gold Mining Activity using SAR +# Checkpoint: A18b +# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +# Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +########################### +#/ Section Two +########################### + +# Define the area of study. +aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd') + +# Center the map at the aoi. +Map.centerObject(aoi, 9) + +# Create an empty image. +empty = ee.Image().byte() + +# Convert the area of study to an EE image object +# so we can visualize only the boundary. +aoiOutline = empty.paint({ + 'featureCollection': aoi, + 'color': 1, + 'width': 2 +}) + +# Select the satellite basemap view. +Map.setOptions('SATELLITE') + +# Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + 'palette': 'red' +}, 'Area of Study') + +# Function to mask the SAR images acquired with an incidence angle +# lower equal than 31 and greater equal than 45 degrees. +def maskAngle(image): + angleMask = image.select('angle') + return image.updateMask(angleMask.gte(31).And(angleMask.lte(45))) + + +# Function to get the SAR Collection. +def getCollection(dates, roi, orbitPass0): + sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') \ + .filterBounds(roi) \ + .filterDate(dates[0], dates[1]) \ + .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0)) + return sarCollFloat.map(maskAngle).select(['VV', 'VH']) + + +# Define variables: the period of time and the orbitpass. +listOfDates = ['2021-01-01', '2022-01-01'] +orbitPass = 'DESCENDING' + +# Apply the function to get the SAR Collection. +sarImageColl = getCollection(listOfDates, aoi, orbitPass) +print('SAR Image Collection', sarImageColl) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18c Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18c Checkpoint.ipynb new file mode 100644 index 0000000..45b1afe --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18c Checkpoint.ipynb @@ -0,0 +1,206 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.8 Monitoring Gold Mining Activity using SAR\n", + "# Checkpoint: A18c\n", + "# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra,\n", + "# Andr\u00e9a Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "###########################\n", + "#/ Section Two\n", + "###########################\n", + "\n", + "# Define the area of study.\n", + "aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd')\n", + "\n", + "# Center the map at the aoi.\n", + "Map.centerObject(aoi, 9)\n", + "\n", + "# Create an empty image.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Convert the area of study to an EE image object\n", + "# so we can visualize only the boundary.\n", + "aoiOutline = empty.paint({\n", + " 'featureCollection': aoi,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Select the satellite basemap view.\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Add the area of study boundary to the map.\n", + "Map.addLayer(aoiOutline, {\n", + " 'palette': 'red'\n", + "}, 'Area of Study')\n", + "\n", + "# Function to mask the SAR images acquired with an incidence angle\n", + "# lower equal than 31 and greater equal than 45 degrees.\n", + "def maskAngle(image):\n", + " angleMask = image.select('angle')\n", + " return image.updateMask(angleMask.gte(31).And(angleMask.lte(45)))\n", + "\n", + "\n", + "# Function to get the SAR Collection.\n", + "def getCollection(dates, roi, orbitPass0):\n", + " sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate(dates[0], dates[1]) \\\n", + " .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0))\n", + " return sarCollFloat.map(maskAngle).select(['VV', 'VH'])\n", + "\n", + "\n", + "# Define variables: the period of time and the orbitpass.\n", + "listOfDates = ['2021-01-01', '2022-01-01']\n", + "orbitPass = 'DESCENDING'\n", + "\n", + "# Apply the function to get the SAR Collection.\n", + "sarImageColl = getCollection(listOfDates, aoi, orbitPass)\n", + "print('SAR Image Collection', sarImageColl)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Function to get dates in 'YYYY-MM-dd' format.\n", + "def getDates(dd):\n", + " return ee.Date(dd).format('YYYY-MM-dd')\n", + "\n", + "\n", + "# Function to get a SAR Mosaic clipped to the study area.\n", + "def mosaicSAR(dates1):\n", + " dates1 = ee.Date(dates1)\n", + " imageFilt = sarImageColl \\\n", + " .filterDate(dates1, dates1.advance(1, 'day'))\n", + " return imageFilt.mosaic() \\\n", + " .clip(aoi) \\\n", + " .set({\n", + " 'system:time_start': dates1.millis(),\n", + " 'dateYMD': dates1.format('YYYY-MM-dd')\n", + " })\n", + "\n", + "\n", + "# Function to get a SAR Collection of mosaics by date.\n", + "datesMosaic = ee.List(sarImageColl \\\n", + " .aggregate_array('system:time_start')) \\\n", + " .map(getDates) \\\n", + " .distinct()\n", + "\n", + "# Get a SAR List and Image Collection of mosaics by date.\n", + "getMosaicList = datesMosaic.map(mosaicSAR)\n", + "getMosaicColl = ee.ImageCollection(getMosaicList)\n", + "print('get Mosaic Collection', getMosaicColl)\n", + "\n", + "# Visualize results.\n", + "sarVis = {\n", + " 'bands': ['VV', 'VH', 'VV'],\n", + " 'min': [-18, -23, 3],\n", + " 'max': [-4, -11, 15]\n", + "}\n", + "\n", + "image1 = getMosaicColl \\\n", + " .filter(ee.Filter.eq('dateYMD', '2021-01-04')) \\\n", + " .first().log10().multiply(10.0)\n", + "image2 = getMosaicColl \\\n", + " .filter(ee.Filter.eq('dateYMD', '2021-12-18')) \\\n", + " .first().log10().multiply(10.0)\n", + "\n", + "Map.addLayer(image1, sarVis, 'Sentinel-1 | 2021-01-04')\n", + "Map.addLayer(image2, sarVis, 'Sentinel-1 | 2021-12-18')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18c Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18c Checkpoint.js new file mode 100644 index 0000000..1ba0b25 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18c Checkpoint.js @@ -0,0 +1,113 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.8 Monitoring Gold Mining Activity using SAR +// Checkpoint: A18c +// Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +// Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +////////////////////////////////////////////////////// +/// Section Two +////////////////////////////////////////////////////// + +// Define the area of study. +var aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd'); + +// Center the map at the aoi. +Map.centerObject(aoi, 9); + +// Create an empty image. +var empty = ee.Image().byte(); + +// Convert the area of study to an EE image object +// so we can visualize only the boundary. +var aoiOutline = empty.paint({ + featureCollection: aoi, + color: 1, + width: 2 +}); + +// Select the satellite basemap view. +Map.setOptions('SATELLITE'); + +// Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + palette: 'red' +}, 'Area of Study'); + +// Function to mask the SAR images acquired with an incidence angle +// lower equal than 31 and greater equal than 45 degrees. +function maskAngle(image) { + var angleMask = image.select('angle'); + return image.updateMask(angleMask.gte(31).and(angleMask.lte(45))); +} + +// Function to get the SAR Collection. +function getCollection(dates, roi, orbitPass0) { + var sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') + .filterBounds(roi) + .filterDate(dates[0], dates[1]) + .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0)); + return sarCollFloat.map(maskAngle).select(['VV', 'VH']); +} + +// Define variables: the period of time and the orbitpass. +var listOfDates = ['2021-01-01', '2022-01-01']; +var orbitPass = 'DESCENDING'; + +// Apply the function to get the SAR Collection. +var sarImageColl = getCollection(listOfDates, aoi, orbitPass); +print('SAR Image Collection', sarImageColl); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Function to get dates in 'YYYY-MM-dd' format. +function getDates(dd) { + return ee.Date(dd).format('YYYY-MM-dd'); +} + +// Function to get a SAR Mosaic clipped to the study area. +function mosaicSAR(dates1) { + dates1 = ee.Date(dates1); + var imageFilt = sarImageColl + .filterDate(dates1, dates1.advance(1, 'day')); + return imageFilt.mosaic() + .clip(aoi) + .set({ + 'system:time_start': dates1.millis(), + 'dateYMD': dates1.format('YYYY-MM-dd') + }); +} + +// Function to get a SAR Collection of mosaics by date. +var datesMosaic = ee.List(sarImageColl + .aggregate_array('system:time_start')) + .map(getDates) + .distinct(); + +// Get a SAR List and Image Collection of mosaics by date. +var getMosaicList = datesMosaic.map(mosaicSAR); +var getMosaicColl = ee.ImageCollection(getMosaicList); +print('get Mosaic Collection', getMosaicColl); + +// Visualize results. +var sarVis = { + bands: ['VV', 'VH', 'VV'], + min: [-18, -23, 3], + max: [-4, -11, 15] +}; + +var image1 = getMosaicColl + .filter(ee.Filter.eq('dateYMD', '2021-01-04')) + .first().log10().multiply(10.0); +var image2 = getMosaicColl + .filter(ee.Filter.eq('dateYMD', '2021-12-18')) + .first().log10().multiply(10.0); + +Map.addLayer(image1, sarVis, 'Sentinel-1 | 2021-01-04'); +Map.addLayer(image2, sarVis, 'Sentinel-1 | 2021-12-18'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18c Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18c Checkpoint.py new file mode 100644 index 0000000..15e8eb5 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18c Checkpoint.py @@ -0,0 +1,119 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.8 Monitoring Gold Mining Activity using SAR +# Checkpoint: A18c +# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +# Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +########################### +#/ Section Two +########################### + +# Define the area of study. +aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd') + +# Center the map at the aoi. +Map.centerObject(aoi, 9) + +# Create an empty image. +empty = ee.Image().byte() + +# Convert the area of study to an EE image object +# so we can visualize only the boundary. +aoiOutline = empty.paint({ + 'featureCollection': aoi, + 'color': 1, + 'width': 2 +}) + +# Select the satellite basemap view. +Map.setOptions('SATELLITE') + +# Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + 'palette': 'red' +}, 'Area of Study') + +# Function to mask the SAR images acquired with an incidence angle +# lower equal than 31 and greater equal than 45 degrees. +def maskAngle(image): + angleMask = image.select('angle') + return image.updateMask(angleMask.gte(31).And(angleMask.lte(45))) + + +# Function to get the SAR Collection. +def getCollection(dates, roi, orbitPass0): + sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') \ + .filterBounds(roi) \ + .filterDate(dates[0], dates[1]) \ + .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0)) + return sarCollFloat.map(maskAngle).select(['VV', 'VH']) + + +# Define variables: the period of time and the orbitpass. +listOfDates = ['2021-01-01', '2022-01-01'] +orbitPass = 'DESCENDING' + +# Apply the function to get the SAR Collection. +sarImageColl = getCollection(listOfDates, aoi, orbitPass) +print('SAR Image Collection', sarImageColl) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Function to get dates in 'YYYY-MM-dd' format. +def getDates(dd): + return ee.Date(dd).format('YYYY-MM-dd') + + +# Function to get a SAR Mosaic clipped to the study area. +def mosaicSAR(dates1): + dates1 = ee.Date(dates1) + imageFilt = sarImageColl \ + .filterDate(dates1, dates1.advance(1, 'day')) + return imageFilt.mosaic() \ + .clip(aoi) \ + .set({ + 'system:time_start': dates1.millis(), + 'dateYMD': dates1.format('YYYY-MM-dd') + }) + + +# Function to get a SAR Collection of mosaics by date. +datesMosaic = ee.List(sarImageColl \ + .aggregate_array('system:time_start')) \ + .map(getDates) \ + .distinct() + +# Get a SAR List and Image Collection of mosaics by date. +getMosaicList = datesMosaic.map(mosaicSAR) +getMosaicColl = ee.ImageCollection(getMosaicList) +print('get Mosaic Collection', getMosaicColl) + +# Visualize results. +sarVis = { + 'bands': ['VV', 'VH', 'VV'], + 'min': [-18, -23, 3], + 'max': [-4, -11, 15] +} + +image1 = getMosaicColl \ + .filter(ee.Filter.eq('dateYMD', '2021-01-04')) \ + .first().log10().multiply(10.0) +image2 = getMosaicColl \ + .filter(ee.Filter.eq('dateYMD', '2021-12-18')) \ + .first().log10().multiply(10.0) + +Map.addLayer(image1, sarVis, 'Sentinel-1 | 2021-01-04') +Map.addLayer(image2, sarVis, 'Sentinel-1 | 2021-12-18') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18d Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18d Checkpoint.ipynb new file mode 100644 index 0000000..a920e00 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18d Checkpoint.ipynb @@ -0,0 +1,295 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.8 Monitoring Gold Mining Activity using SAR\n", + "# Checkpoint: A18d\n", + "# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra,\n", + "# Andr\u00e9a Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "###########################\n", + "#/ Section Two\n", + "###########################\n", + "\n", + "# Define the area of study.\n", + "aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd')\n", + "\n", + "# Center the map at the aoi.\n", + "Map.centerObject(aoi, 9)\n", + "\n", + "# Create an empty image.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Convert the area of study to an EE image object\n", + "# so we can visualize only the boundary.\n", + "aoiOutline = empty.paint({\n", + " 'featureCollection': aoi,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Select the satellite basemap view.\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Add the area of study boundary to the map.\n", + "Map.addLayer(aoiOutline, {\n", + " 'palette': 'red'\n", + "}, 'Area of Study')\n", + "\n", + "# Function to mask the SAR images acquired with an incidence angle\n", + "# lower equal than 31 and greater equal than 45 degrees.\n", + "def maskAngle(image):\n", + " angleMask = image.select('angle')\n", + " return image.updateMask(angleMask.gte(31).And(angleMask.lte(45)))\n", + "\n", + "\n", + "# Function to get the SAR Collection.\n", + "def getCollection(dates, roi, orbitPass0):\n", + " sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate(dates[0], dates[1]) \\\n", + " .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0))\n", + " return sarCollFloat.map(maskAngle).select(['VV', 'VH'])\n", + "\n", + "\n", + "# Define variables: the period of time and the orbitpass.\n", + "listOfDates = ['2021-01-01', '2022-01-01']\n", + "orbitPass = 'DESCENDING'\n", + "\n", + "# Apply the function to get the SAR Collection.\n", + "sarImageColl = getCollection(listOfDates, aoi, orbitPass)\n", + "print('SAR Image Collection', sarImageColl)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Function to get dates in 'YYYY-MM-dd' format.\n", + "def getDates(dd):\n", + " return ee.Date(dd).format('YYYY-MM-dd')\n", + "\n", + "\n", + "# Function to get a SAR Mosaic clipped to the study area.\n", + "def mosaicSAR(dates1):\n", + " dates1 = ee.Date(dates1)\n", + " imageFilt = sarImageColl \\\n", + " .filterDate(dates1, dates1.advance(1, 'day'))\n", + " return imageFilt.mosaic() \\\n", + " .clip(aoi) \\\n", + " .set({\n", + " 'system:time_start': dates1.millis(),\n", + " 'dateYMD': dates1.format('YYYY-MM-dd')\n", + " })\n", + "\n", + "\n", + "# Function to get a SAR Collection of mosaics by date.\n", + "datesMosaic = ee.List(sarImageColl \\\n", + " .aggregate_array('system:time_start')) \\\n", + " .map(getDates) \\\n", + " .distinct()\n", + "\n", + "# Get a SAR List and Image Collection of mosaics by date.\n", + "getMosaicList = datesMosaic.map(mosaicSAR)\n", + "getMosaicColl = ee.ImageCollection(getMosaicList)\n", + "print('get Mosaic Collection', getMosaicColl)\n", + "\n", + "# Visualize results.\n", + "sarVis = {\n", + " 'bands': ['VV', 'VH', 'VV'],\n", + " 'min': [-18, -23, 3],\n", + " 'max': [-4, -11, 15]\n", + "}\n", + "\n", + "image1 = getMosaicColl \\\n", + " .filter(ee.Filter.eq('dateYMD', '2021-01-04')) \\\n", + " .first().log10().multiply(10.0)\n", + "image2 = getMosaicColl \\\n", + " .filter(ee.Filter.eq('dateYMD', '2021-12-18')) \\\n", + " .first().log10().multiply(10.0)\n", + "\n", + "Map.addLayer(image1, sarVis, 'Sentinel-1 | 2021-01-04')\n", + "Map.addLayer(image2, sarVis, 'Sentinel-1 | 2021-12-18')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "###########################\n", + "#/ Section Three\n", + "###########################\n", + "\n", + "# Libraries of SAR Change Detection (version modified).\n", + "# The original version can be found in:\n", + "# users/mortcanty/changedetection\n", + "omb = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/omnibusTest_v1.1'\n", + " )\n", + "util = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/utilities_v1.1'\n", + " )\n", + "\n", + "# Count the length of the list of dates of the time-series.\n", + "countDates = datesMosaic.size().getInfo()\n", + "\n", + "# Run the algorithm and print the results.\n", + "significance = 0.0001\n", + "median = True\n", + "result = ee.Dictionary(omb.omnibus(getMosaicList, significance,\n", + " median))\n", + "print('result', result)\n", + "\n", + "# Change maps generated (cmap, smap, fmap and bmap)\n", + "# are detailed in the next commented lines.\n", + "\n", + "# cmap: the interval in which the most recent significant change occurred (single-band).\n", + "# smap: the interval in which the first significant change occurred (single-band).\n", + "# fmap: the frequency of significant changes (single-band).\n", + "# bmap: the interval in which each significant change occurred ((k \u2212 1)-band).\n", + "\n", + "# Extract and print the images result\n", + "# (cmap, smap, fmap and bmap) from the ee.Dictionary.\n", + "cmap = ee.Image(result.get('cmap')).byte()\n", + "smap = ee.Image(result.get('smap')).byte()\n", + "fmap = ee.Image(result.get('fmap')).byte()\n", + "bmap = ee.Image(result.get('bmap')).byte()\n", + "\n", + "# Build a Feature Collection from Dates.\n", + "fCollectionDates = ee.FeatureCollection(datesMosaic\n", + "\n", + "def func_qpl(element):\n", + " return ee.Feature(None, {\n", + " 'prop': element\n", + " }) \\\n", + " .map(func_qpl\n", + "))\n", + "\n", + "\n", + "\n", + "))\n", + "print('Dates', datesMosaic)\n", + "\n", + "# Visualization parameters.\n", + "jet = ['black', 'blue', 'cyan', 'yellow', 'red']\n", + "vis = {\n", + " 'min': 0,\n", + " 'max': countDates,\n", + " 'palette': jet\n", + "}\n", + "\n", + "# Add resulting images and legend to the map.\n", + "Map.add(util.makeLegend(vis))\n", + "Map.addLayer(cmap, vis, 'cmap - recent change (unfiltered)')\n", + "Map.addLayer(smap, vis, 'smap - first change (unfiltered)')\n", + "Map.addLayer(fmap.multiply(2), vis, 'fmap*2 - frequency of changes')\n", + "\n", + "# Export the Feature Collection with the dates of change.\n", + "exportDates = Export.table.toDrive({\n", + " 'collection': fCollectionDates,\n", + " 'folder': 'datesChangesDN',\n", + " 'description': 'dates',\n", + " 'fileFormat': 'CSV'\n", + "})\n", + "# Export the image of the first significant changes.\n", + "exportImgChanges = Export.image.toAsset({\n", + " 'image': smap,\n", + " 'description': 'smap',\n", + " 'assetId': 'your_asset_path_here/' + 'smap',\n", + " 'region': aoi,\n", + " 'scale': 10,\n", + " 'maxPixels': 1e13\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18d Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18d Checkpoint.js new file mode 100644 index 0000000..a5adec9 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18d Checkpoint.js @@ -0,0 +1,196 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.8 Monitoring Gold Mining Activity using SAR +// Checkpoint: A18d +// Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +// Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +////////////////////////////////////////////////////// +/// Section Two +////////////////////////////////////////////////////// + +// Define the area of study. +var aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd'); + +// Center the map at the aoi. +Map.centerObject(aoi, 9); + +// Create an empty image. +var empty = ee.Image().byte(); + +// Convert the area of study to an EE image object +// so we can visualize only the boundary. +var aoiOutline = empty.paint({ + featureCollection: aoi, + color: 1, + width: 2 +}); + +// Select the satellite basemap view. +Map.setOptions('SATELLITE'); + +// Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + palette: 'red' +}, 'Area of Study'); + +// Function to mask the SAR images acquired with an incidence angle +// lower equal than 31 and greater equal than 45 degrees. +function maskAngle(image) { + var angleMask = image.select('angle'); + return image.updateMask(angleMask.gte(31).and(angleMask.lte(45))); +} + +// Function to get the SAR Collection. +function getCollection(dates, roi, orbitPass0) { + var sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') + .filterBounds(roi) + .filterDate(dates[0], dates[1]) + .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0)); + return sarCollFloat.map(maskAngle).select(['VV', 'VH']); +} + +// Define variables: the period of time and the orbitpass. +var listOfDates = ['2021-01-01', '2022-01-01']; +var orbitPass = 'DESCENDING'; + +// Apply the function to get the SAR Collection. +var sarImageColl = getCollection(listOfDates, aoi, orbitPass); +print('SAR Image Collection', sarImageColl); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Function to get dates in 'YYYY-MM-dd' format. +function getDates(dd) { + return ee.Date(dd).format('YYYY-MM-dd'); +} + +// Function to get a SAR Mosaic clipped to the study area. +function mosaicSAR(dates1) { + dates1 = ee.Date(dates1); + var imageFilt = sarImageColl + .filterDate(dates1, dates1.advance(1, 'day')); + return imageFilt.mosaic() + .clip(aoi) + .set({ + 'system:time_start': dates1.millis(), + 'dateYMD': dates1.format('YYYY-MM-dd') + }); +} + +// Function to get a SAR Collection of mosaics by date. +var datesMosaic = ee.List(sarImageColl + .aggregate_array('system:time_start')) + .map(getDates) + .distinct(); + +// Get a SAR List and Image Collection of mosaics by date. +var getMosaicList = datesMosaic.map(mosaicSAR); +var getMosaicColl = ee.ImageCollection(getMosaicList); +print('get Mosaic Collection', getMosaicColl); + +// Visualize results. +var sarVis = { + bands: ['VV', 'VH', 'VV'], + min: [-18, -23, 3], + max: [-4, -11, 15] +}; + +var image1 = getMosaicColl + .filter(ee.Filter.eq('dateYMD', '2021-01-04')) + .first().log10().multiply(10.0); +var image2 = getMosaicColl + .filter(ee.Filter.eq('dateYMD', '2021-12-18')) + .first().log10().multiply(10.0); + +Map.addLayer(image1, sarVis, 'Sentinel-1 | 2021-01-04'); +Map.addLayer(image2, sarVis, 'Sentinel-1 | 2021-12-18'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +////////////////////////////////////////////////////// +/// Section Three +////////////////////////////////////////////////////// + +// Libraries of SAR Change Detection (version modified). +// The original version can be found in: +// users/mortcanty/changedetection +var omb = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/omnibusTest_v1.1' + ); +var util = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/utilities_v1.1' + ); + +// Count the length of the list of dates of the time-series. +var countDates = datesMosaic.size().getInfo(); + +// Run the algorithm and print the results. +var significance = 0.0001; +var median = true; +var result = ee.Dictionary(omb.omnibus(getMosaicList, significance, + median)); +print('result', result); + +// Change maps generated (cmap, smap, fmap and bmap) +// are detailed in the next commented lines. + +// cmap: the interval in which the most recent significant change occurred (single-band). +// smap: the interval in which the first significant change occurred (single-band). +// fmap: the frequency of significant changes (single-band). +// bmap: the interval in which each significant change occurred ((k − 1)-band). + +// Extract and print the images result +// (cmap, smap, fmap and bmap) from the ee.Dictionary. +var cmap = ee.Image(result.get('cmap')).byte(); +var smap = ee.Image(result.get('smap')).byte(); +var fmap = ee.Image(result.get('fmap')).byte(); +var bmap = ee.Image(result.get('bmap')).byte(); + +// Build a Feature Collection from Dates. +var fCollectionDates = ee.FeatureCollection(datesMosaic + .map(function(element) { + return ee.Feature(null, { + prop: element + }); + })); +print('Dates', datesMosaic); + +// Visualization parameters. +var jet = ['black', 'blue', 'cyan', 'yellow', 'red']; +var vis = { + min: 0, + max: countDates, + palette: jet +}; + +// Add resulting images and legend to the map. +Map.add(util.makeLegend(vis)); +Map.addLayer(cmap, vis, 'cmap - recent change (unfiltered)'); +Map.addLayer(smap, vis, 'smap - first change (unfiltered)'); +Map.addLayer(fmap.multiply(2), vis, 'fmap*2 - frequency of changes'); + +// Export the Feature Collection with the dates of change. +var exportDates = Export.table.toDrive({ + collection: fCollectionDates, + folder: 'datesChangesDN', + description: 'dates', + fileFormat: 'CSV' +}); +// Export the image of the first significant changes. +var exportImgChanges = Export.image.toAsset({ + image: smap, + description: 'smap', + assetId: 'your_asset_path_here/' + 'smap', + region: aoi, + scale: 10, + maxPixels: 1e13 +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18d Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18d Checkpoint.py new file mode 100644 index 0000000..f416ecc --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18d Checkpoint.py @@ -0,0 +1,208 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.8 Monitoring Gold Mining Activity using SAR +# Checkpoint: A18d +# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +# Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +########################### +#/ Section Two +########################### + +# Define the area of study. +aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd') + +# Center the map at the aoi. +Map.centerObject(aoi, 9) + +# Create an empty image. +empty = ee.Image().byte() + +# Convert the area of study to an EE image object +# so we can visualize only the boundary. +aoiOutline = empty.paint({ + 'featureCollection': aoi, + 'color': 1, + 'width': 2 +}) + +# Select the satellite basemap view. +Map.setOptions('SATELLITE') + +# Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + 'palette': 'red' +}, 'Area of Study') + +# Function to mask the SAR images acquired with an incidence angle +# lower equal than 31 and greater equal than 45 degrees. +def maskAngle(image): + angleMask = image.select('angle') + return image.updateMask(angleMask.gte(31).And(angleMask.lte(45))) + + +# Function to get the SAR Collection. +def getCollection(dates, roi, orbitPass0): + sarCollFloat = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT') \ + .filterBounds(roi) \ + .filterDate(dates[0], dates[1]) \ + .filter(ee.Filter.eq('orbitProperties_pass', orbitPass0)) + return sarCollFloat.map(maskAngle).select(['VV', 'VH']) + + +# Define variables: the period of time and the orbitpass. +listOfDates = ['2021-01-01', '2022-01-01'] +orbitPass = 'DESCENDING' + +# Apply the function to get the SAR Collection. +sarImageColl = getCollection(listOfDates, aoi, orbitPass) +print('SAR Image Collection', sarImageColl) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Function to get dates in 'YYYY-MM-dd' format. +def getDates(dd): + return ee.Date(dd).format('YYYY-MM-dd') + + +# Function to get a SAR Mosaic clipped to the study area. +def mosaicSAR(dates1): + dates1 = ee.Date(dates1) + imageFilt = sarImageColl \ + .filterDate(dates1, dates1.advance(1, 'day')) + return imageFilt.mosaic() \ + .clip(aoi) \ + .set({ + 'system:time_start': dates1.millis(), + 'dateYMD': dates1.format('YYYY-MM-dd') + }) + + +# Function to get a SAR Collection of mosaics by date. +datesMosaic = ee.List(sarImageColl \ + .aggregate_array('system:time_start')) \ + .map(getDates) \ + .distinct() + +# Get a SAR List and Image Collection of mosaics by date. +getMosaicList = datesMosaic.map(mosaicSAR) +getMosaicColl = ee.ImageCollection(getMosaicList) +print('get Mosaic Collection', getMosaicColl) + +# Visualize results. +sarVis = { + 'bands': ['VV', 'VH', 'VV'], + 'min': [-18, -23, 3], + 'max': [-4, -11, 15] +} + +image1 = getMosaicColl \ + .filter(ee.Filter.eq('dateYMD', '2021-01-04')) \ + .first().log10().multiply(10.0) +image2 = getMosaicColl \ + .filter(ee.Filter.eq('dateYMD', '2021-12-18')) \ + .first().log10().multiply(10.0) + +Map.addLayer(image1, sarVis, 'Sentinel-1 | 2021-01-04') +Map.addLayer(image2, sarVis, 'Sentinel-1 | 2021-12-18') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +########################### +#/ Section Three +########################### + +# Libraries of SAR Change Detection (version modified). +# The original version can be found in: +# users/mortcanty/changedetection +omb = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/omnibusTest_v1.1' + ) +util = require( + 'projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/utilities_v1.1' + ) + +# Count the length of the list of dates of the time-series. +countDates = datesMosaic.size().getInfo() + +# Run the algorithm and print the results. +significance = 0.0001 +median = True +result = ee.Dictionary(omb.omnibus(getMosaicList, significance, + median)) +print('result', result) + +# Change maps generated (cmap, smap, fmap and bmap) +# are detailed in the next commented lines. + +# cmap: the interval in which the most recent significant change occurred (single-band). +# smap: the interval in which the first significant change occurred (single-band). +# fmap: the frequency of significant changes (single-band). +# bmap: the interval in which each significant change occurred ((k − 1)-band). + +# Extract and print the images result +# (cmap, smap, fmap and bmap) from the ee.Dictionary. +cmap = ee.Image(result.get('cmap')).byte() +smap = ee.Image(result.get('smap')).byte() +fmap = ee.Image(result.get('fmap')).byte() +bmap = ee.Image(result.get('bmap')).byte() + +# Build a Feature Collection from Dates. +fCollectionDates = ee.FeatureCollection(datesMosaic + +def func_qpl(element): + return ee.Feature(None, { + 'prop': element + }) \ + .map(func_qpl +)) + + + +)) +print('Dates', datesMosaic) + +# Visualization parameters. +jet = ['black', 'blue', 'cyan', 'yellow', 'red'] +vis = { + 'min': 0, + 'max': countDates, + 'palette': jet +} + +# Add resulting images and legend to the map. +Map.add(util.makeLegend(vis)) +Map.addLayer(cmap, vis, 'cmap - recent change (unfiltered)') +Map.addLayer(smap, vis, 'smap - first change (unfiltered)') +Map.addLayer(fmap.multiply(2), vis, 'fmap*2 - frequency of changes') + +# Export the Feature Collection with the dates of change. +exportDates = Export.table.toDrive({ + 'collection': fCollectionDates, + 'folder': 'datesChangesDN', + 'description': 'dates', + 'fileFormat': 'CSV' +}) +# Export the image of the first significant changes. +exportImgChanges = Export.image.toAsset({ + 'image': smap, + 'description': 'smap', + 'assetId': 'your_asset_path_here/' + 'smap', + 'region': aoi, + 'scale': 10, + 'maxPixels': 1e13 +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18e Checkpoint.ipynb b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18e Checkpoint.ipynb new file mode 100644 index 0000000..01d3f18 --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18e Checkpoint.ipynb @@ -0,0 +1,233 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A1.6 Monitoring Gold Mining Activity using SAR\n", + "# Checkpoint: A16e\n", + "# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra,\n", + "# Andr\u00e9a Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "###########################\n", + "#/ Section Four\n", + "###########################\n", + "\n", + "# Define the area of study.\n", + "aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd')\n", + "\n", + "# Center the map.\n", + "Map.centerObject(aoi, 10)\n", + "\n", + "# Create an empty image.\n", + "empty = ee.Image().byte()\n", + "\n", + "# Convert the area of study to an EE image object so we can visualize\n", + "# only the boundary.\n", + "aoiOutline = empty.paint({\n", + " 'featureCollection': aoi,\n", + " 'color': 1,\n", + " 'width': 2\n", + "})\n", + "\n", + "# Select the satellite basemap view.\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Add the area of study boundary to the map.\n", + "Map.addLayer(aoiOutline, {\n", + " 'palette': 'red'\n", + "}, 'Area of Study')\n", + "\n", + "# Import the smap result from section 3.\n", + "changeDetect = ee.Image('projects/gee-book/assets/A1-8/smap')\n", + "\n", + "# Visualization parameters.\n", + "countDates = 30\n", + "jet = ['black', 'blue', 'cyan', 'yellow', 'red']\n", + "vis = {\n", + " 'min': 0,\n", + " 'max': countDates,\n", + " 'palette': jet\n", + "}\n", + "\n", + "# Add results to the map.\n", + "Map.addLayer(changeDetect, vis, 'Change Map Unfiltered')\n", + "\n", + "# Digital Elevation Model SRTM.\n", + "# https:#developers.google.com/earth-engine/datasets/catalog/USGS_SRTMGL1_003\n", + "srtm = ee.Image('USGS/SRTMGL1_003').clip(aoi)\n", + "slope = ee.Terrain.slope(srtm)\n", + "srtmVis = {\n", + " 'min': 0,\n", + " 'max': 1000,\n", + " 'palette': ['black', 'blue', 'cyan', 'yellow', 'red']\n", + "}\n", + "Map.addLayer(srtm, srtmVis, 'SRTM Elevation')\n", + "slopeVis = {\n", + " 'min': 0,\n", + " 'max': 15,\n", + " 'palette': ['black', 'blue', 'cyan', 'yellow', 'red']\n", + "}\n", + "Map.addLayer(slope, slopeVis, 'SRTM Slope')\n", + "\n", + "# Hansen Global Forest Change v1.8 (2000-2020)\n", + "# https:#developers.google.com/earth-engine/datasets/catalog/UMD_hansen_global_forest_change_2020_v1_8\n", + "gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8').clip(\n", + " aoi)\n", + "forest2020 = gfc.select('treecover2000') \\\n", + " .gt(0) \\\n", + " .updateMask(gfc.select('loss') \\\n", + " .neq(1)) \\\n", + " .selfMask()\n", + "Map.addLayer(forest2020,\n", + " {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['black', 'green']\n", + " },\n", + " 'Forest cover 2020')\n", + "\n", + "# JRC Yearly Water Classification History, v1.3 (Updated until Dec 2020).\n", + "# https:#developers.google.com/earth-engine/datasets/catalog/JRC_GSW1_3_GlobalSurfaceWater\n", + "waterJRC = ee.Image('JRC/GSW1_3/GlobalSurfaceWater').select(\n", + " 'max_extent')\n", + "waterVis = {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'black']\n", + "}\n", + "Map.addLayer(waterJRC.eq(0), waterVis, 'Water Bodies until 2020')\n", + "\n", + "# Apply filters through masks.\n", + "alertsFiltered = changeDetect \\\n", + " .updateMask(srtm.lt(1000)) \\\n", + " .updateMask(slope.lt(15)) \\\n", + " .updateMask(forest2020.eq(1)) \\\n", + " .updateMask(waterJRC.eq(0)) \\\n", + " .selfMask()\n", + "\n", + "# Add filtered results to the map.\n", + "Map.addLayer(alertsFiltered,\n", + " {\n", + " 'min': 0,\n", + " 'max': countDates,\n", + " 'palette': jet\n", + " },\n", + " 'Change Map Filtered',\n", + " 1)\n", + "\n", + "# Function to filter small patches and isolated pixels.\n", + "def filterMinPatchs(alerts0, minArea0, maxSize0):\n", + " pixelCount = alerts0.gt(0).connectedPixelCount(maxSize0)\n", + " minPixelCount = ee.Image(minArea0).divide(ee.Image \\\n", + " .pixelArea())\n", + " return alerts0.updateMask(pixelCount.gte(minPixelCount))\n", + "\n", + "\n", + "# Apply the function and visualize the filtered results.\n", + "alertsFiltMinPatchs = filterMinPatchs(alertsFiltered, 10000, 200)\n", + "\n", + "Map.addLayer(alertsFiltMinPatchs, vis,\n", + " 'Alerts Filtered - Minimum Patches')\n", + "\n", + "# Export filtered results to the Drive.\n", + "Export.image.toDrive({\n", + " 'image': alertsFiltMinPatchs,\n", + " 'description': 'alertsFiltered',\n", + " 'folder': 'alertsFiltered',\n", + " 'region': aoi,\n", + " 'scale': 10,\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18e Checkpoint.js b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18e Checkpoint.js new file mode 100644 index 0000000..69b2f6f --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18e Checkpoint.js @@ -0,0 +1,140 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A1.6 Monitoring Gold Mining Activity using SAR +// Checkpoint: A16e +// Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +// Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +////////////////////////////////////////////////////// +/// Section Four +////////////////////////////////////////////////////// + +// Define the area of study. +var aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd'); + +// Center the map. +Map.centerObject(aoi, 10); + +// Create an empty image. +var empty = ee.Image().byte(); + +// Convert the area of study to an EE image object so we can visualize +// only the boundary. +var aoiOutline = empty.paint({ + featureCollection: aoi, + color: 1, + width: 2 +}); + +// Select the satellite basemap view. +Map.setOptions('SATELLITE'); + +// Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + palette: 'red' +}, 'Area of Study'); + +// Import the smap result from section 3. +var changeDetect = ee.Image('projects/gee-book/assets/A1-8/smap'); + +// Visualization parameters. +var countDates = 30; +var jet = ['black', 'blue', 'cyan', 'yellow', 'red']; +var vis = { + min: 0, + max: countDates, + palette: jet +}; + +// Add results to the map. +Map.addLayer(changeDetect, vis, 'Change Map Unfiltered'); + +// Digital Elevation Model SRTM. +// https://developers.google.com/earth-engine/datasets/catalog/USGS_SRTMGL1_003 +var srtm = ee.Image('USGS/SRTMGL1_003').clip(aoi); +var slope = ee.Terrain.slope(srtm); +var srtmVis = { + min: 0, + max: 1000, + palette: ['black', 'blue', 'cyan', 'yellow', 'red'] +}; +Map.addLayer(srtm, srtmVis, 'SRTM Elevation'); +var slopeVis = { + min: 0, + max: 15, + palette: ['black', 'blue', 'cyan', 'yellow', 'red'] +}; +Map.addLayer(slope, slopeVis, 'SRTM Slope'); + +// Hansen Global Forest Change v1.8 (2000-2020) +// https://developers.google.com/earth-engine/datasets/catalog/UMD_hansen_global_forest_change_2020_v1_8 +var gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8').clip( + aoi); +var forest2020 = gfc.select('treecover2000') + .gt(0) + .updateMask(gfc.select('loss') + .neq(1)) + .selfMask(); +Map.addLayer(forest2020, + { + min: 0, + max: 1, + palette: ['black', 'green'] + }, + 'Forest cover 2020'); + +// JRC Yearly Water Classification History, v1.3 (Updated until Dec 2020). +// https://developers.google.com/earth-engine/datasets/catalog/JRC_GSW1_3_GlobalSurfaceWater +var waterJRC = ee.Image('JRC/GSW1_3/GlobalSurfaceWater').select( + 'max_extent'); +var waterVis = { + min: 0, + max: 1, + palette: ['blue', 'black'] +}; +Map.addLayer(waterJRC.eq(0), waterVis, 'Water Bodies until 2020'); + +// Apply filters through masks. +var alertsFiltered = changeDetect + .updateMask(srtm.lt(1000)) + .updateMask(slope.lt(15)) + .updateMask(forest2020.eq(1)) + .updateMask(waterJRC.eq(0)) + .selfMask(); + +// Add filtered results to the map. +Map.addLayer(alertsFiltered, + { + min: 0, + max: countDates, + palette: jet + }, + 'Change Map Filtered', + 1); + +// Function to filter small patches and isolated pixels. +function filterMinPatchs(alerts0, minArea0, maxSize0) { + var pixelCount = alerts0.gt(0).connectedPixelCount(maxSize0); + var minPixelCount = ee.Image(minArea0).divide(ee.Image + .pixelArea()); + return alerts0.updateMask(pixelCount.gte(minPixelCount)); +} + +// Apply the function and visualize the filtered results. +var alertsFiltMinPatchs = filterMinPatchs(alertsFiltered, 10000, 200); + +Map.addLayer(alertsFiltMinPatchs, vis, + 'Alerts Filtered - Minimum Patches'); + +// Export filtered results to the Drive. +Export.image.toDrive({ + image: alertsFiltMinPatchs, + description: 'alertsFiltered', + folder: 'alertsFiltered', + region: aoi, + scale: 10, +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18e Checkpoint.py b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18e Checkpoint.py new file mode 100644 index 0000000..b954c3b --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/A18e Checkpoint.py @@ -0,0 +1,146 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A1.6 Monitoring Gold Mining Activity using SAR +# Checkpoint: A16e +# Authors: Lucio Villa, Sidney Novoa, Milagros Becerra, +# Andréa Puzzi Nicolau, Karen Dyson, Karis Tenneson, John Dilger +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +########################### +#/ Section Four +########################### + +# Define the area of study. +aoi = ee.FeatureCollection('projects/gee-book/assets/A1-8/mdd') + +# Center the map. +Map.centerObject(aoi, 10) + +# Create an empty image. +empty = ee.Image().byte() + +# Convert the area of study to an EE image object so we can visualize +# only the boundary. +aoiOutline = empty.paint({ + 'featureCollection': aoi, + 'color': 1, + 'width': 2 +}) + +# Select the satellite basemap view. +Map.setOptions('SATELLITE') + +# Add the area of study boundary to the map. +Map.addLayer(aoiOutline, { + 'palette': 'red' +}, 'Area of Study') + +# Import the smap result from section 3. +changeDetect = ee.Image('projects/gee-book/assets/A1-8/smap') + +# Visualization parameters. +countDates = 30 +jet = ['black', 'blue', 'cyan', 'yellow', 'red'] +vis = { + 'min': 0, + 'max': countDates, + 'palette': jet +} + +# Add results to the map. +Map.addLayer(changeDetect, vis, 'Change Map Unfiltered') + +# Digital Elevation Model SRTM. +# https:#developers.google.com/earth-engine/datasets/catalog/USGS_SRTMGL1_003 +srtm = ee.Image('USGS/SRTMGL1_003').clip(aoi) +slope = ee.Terrain.slope(srtm) +srtmVis = { + 'min': 0, + 'max': 1000, + 'palette': ['black', 'blue', 'cyan', 'yellow', 'red'] +} +Map.addLayer(srtm, srtmVis, 'SRTM Elevation') +slopeVis = { + 'min': 0, + 'max': 15, + 'palette': ['black', 'blue', 'cyan', 'yellow', 'red'] +} +Map.addLayer(slope, slopeVis, 'SRTM Slope') + +# Hansen Global Forest Change v1.8 (2000-2020) +# https:#developers.google.com/earth-engine/datasets/catalog/UMD_hansen_global_forest_change_2020_v1_8 +gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8').clip( + aoi) +forest2020 = gfc.select('treecover2000') \ + .gt(0) \ + .updateMask(gfc.select('loss') \ + .neq(1)) \ + .selfMask() +Map.addLayer(forest2020, + { + 'min': 0, + 'max': 1, + 'palette': ['black', 'green'] + }, + 'Forest cover 2020') + +# JRC Yearly Water Classification History, v1.3 (Updated until Dec 2020). +# https:#developers.google.com/earth-engine/datasets/catalog/JRC_GSW1_3_GlobalSurfaceWater +waterJRC = ee.Image('JRC/GSW1_3/GlobalSurfaceWater').select( + 'max_extent') +waterVis = { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'black'] +} +Map.addLayer(waterJRC.eq(0), waterVis, 'Water Bodies until 2020') + +# Apply filters through masks. +alertsFiltered = changeDetect \ + .updateMask(srtm.lt(1000)) \ + .updateMask(slope.lt(15)) \ + .updateMask(forest2020.eq(1)) \ + .updateMask(waterJRC.eq(0)) \ + .selfMask() + +# Add filtered results to the map. +Map.addLayer(alertsFiltered, + { + 'min': 0, + 'max': countDates, + 'palette': jet + }, + 'Change Map Filtered', + 1) + +# Function to filter small patches and isolated pixels. +def filterMinPatchs(alerts0, minArea0, maxSize0): + pixelCount = alerts0.gt(0).connectedPixelCount(maxSize0) + minPixelCount = ee.Image(minArea0).divide(ee.Image \ + .pixelArea()) + return alerts0.updateMask(pixelCount.gte(minPixelCount)) + + +# Apply the function and visualize the filtered results. +alertsFiltMinPatchs = filterMinPatchs(alertsFiltered, 10000, 200) + +Map.addLayer(alertsFiltMinPatchs, vis, + 'Alerts Filtered - Minimum Patches') + +# Export filtered results to the Drive. +Export.image.toDrive({ + 'image': alertsFiltMinPatchs, + 'description': 'alertsFiltered', + 'folder': 'alertsFiltered', + 'region': aoi, + 'scale': 10, +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/omnibusTest_v1.1 b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/omnibusTest_v1.1 new file mode 100644 index 0000000..534b0dd --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/omnibusTest_v1.1 @@ -0,0 +1,147 @@ +// **************************************** +// Modules for sequential omnibus algorithm +// **************************************** +var util = require('projects/gee-edu/book:Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/utilities_v1.1'); +//get 'VV' and 'VH' bands from sentinel-1 imageCollection and restore linear signal from db-values +exports.get_vvvh = function(image){ + var nbands = image.bandNames().length(); + return image.select(['VV','VH']).multiply(ee.Image.constant(Math.log(10.0)/10.0)).exp(); +}; +//get 'VV' and 'VH' bands from sentinel-1 imageCollection from ASF RTC data +exports.get_vvvh_asfRTC = function(image){ + var nbands = image.bandNames().length(); + return image.select(['VV','VH']) +}; +// clip a list of images +exports.clipList = function(current,prev){ + var imlist = ee.List(ee.Dictionary(prev).get('imlist')); + var geometry = ee.Dictionary(prev).get('geom'); + var imlist1 = imlist.add(ee.Image(current).clip(geometry)); + return ee.Dictionary({imlist:imlist1,geom:geometry}); +}; +// the algorithm +function multbyenl(image){ + return ee.Image(image).multiply(4.9) +} +function log_det_sum(imList,j){ +// return the log of the the determinant of the sum of the first j images in imList + imList = ee.List(imList); + var nbands = ee.Image(imList.get(0)).bandNames().length(); + var sumj = ee.ImageCollection(imList.slice(0,j)).reduce(ee.Reducer.sum()); + return ee.Algorithms.If( nbands.eq(2), + sumj.expression('b(0)*b(1)').log(), + sumj.log() ); +} +function log_det(imList,j){ +// return the log of the the determinant of the jth image in imList + var im = ee.Image(ee.List(imList).get(j.subtract(1))); + var nbands = im.bandNames().length(); + return ee.Algorithms.If(nbands.eq(2), + im.expression('b(0)*b(1)').log(), + im.log() ); +} +function pv(imList,p,median,j){ +// calculate -2log(R_ell,j) and return P-value + imList = ee.List(imList); + p = ee.Number(p); + j = ee.Number(j); + var f = p; + var one = ee.Number(1.0); +// 1 - (1. + 1./(j*(j-1)))/(6.*p*n) + var rhoj = one.subtract(one.add(one.divide(j.multiply(j.subtract(one)))).divide(6*4.9)); +// -(f/4.)*(1.-1./rhoj)**2' + var omega2j = one.subtract(one.divide(rhoj)).pow(2.0).multiply(f.divide(-4.0)); + var Z = ee.Image(ee.Image(log_det_sum(imList,j.subtract(1)))).multiply(j.subtract(1)) + .add(log_det(imList,j)) + .add(p.multiply(j).multiply(ee.Number(j).log())) + .subtract(p.multiply(j.subtract(1)).multiply(j.subtract(1).log())) + .subtract(ee.Image(log_det_sum(imList,j)).multiply(j)) + .multiply(rhoj) + .multiply(-2*4.9); +// (1.-omega2j)*stats.chi2.cdf(Z,[f])+omega2j*stats.chi2.cdf(Z,[f+4]) + var P = ee.Image( util.chi2cdf(Z,f).multiply(one.subtract(omega2j)).add(util.chi2cdf(Z,f.add(4)).multiply(omega2j)) ); +// 3x3 median filter + return ee.Algorithms.If(median, P.focal_median(), P); +} +function js_iter(current,prev){ + var j = ee.Number(current); + prev = ee.Dictionary(prev); + var median = prev.get('median'); + var p = prev.get('p'); + var imList = prev.get('imList'); + var pvs = ee.List(prev.get('pvs')); + return ee.Dictionary({'median':median,'p':p,'imList':imList,'pvs':pvs.add(pv(imList,p,median,j))}); +} +function ells_iter(current,prev){ + var ell = ee.Number(current); + prev = ee.Dictionary(prev); + var pv_arr = ee.List(prev.get('pv_arr')); + var k = ee.Number(prev.get('k')); + var median = prev.get('median'); + var p = prev.get('p'); + var imList = ee.List(prev.get('imList')); + var imList_ell = imList.slice(ell.subtract(1)); + var js = ee.List.sequence(2,k.subtract(ell).add(1)); + var first = ee.Dictionary({'median':median,'p':p,'imList':imList_ell,'pvs':ee.List([])}); +// list of P-values for R_ell,j, j = 2...k-ell+1 + var pvs = ee.List(ee.Dictionary(js.iterate(js_iter,first)).get('pvs')); + return ee.Dictionary({'k':k,'p':p,'median':median,'imList':imList,'pv_arr':pv_arr.add(pvs)}); +} +function filter_j(current,prev){ + var P = ee.Image(current); + prev = ee.Dictionary(prev); + var ell = ee.Number(prev.get('ell')); + var cmap = ee.Image(prev.get('cmap')); + var smap = ee.Image(prev.get('smap')); + var fmap = ee.Image(prev.get('fmap')); + var bmap = ee.Image(prev.get('bmap')); + var threshold = ee.Image(prev.get('threshold')); + var j = ee.Number(prev.get('j')); + var cmapj = cmap.multiply(0).add(ell.add(j).subtract(1)); + var cmap1 = cmap.multiply(0).add(1); + var tst = P.gt(threshold).and(cmap.eq(ell.subtract(1))); + cmap = cmap.where(tst,cmapj); + fmap = fmap.where(tst,fmap.add(1)); + smap = ee.Algorithms.If(ell.eq(1),smap.where(tst,cmapj),smap); + var idx = ell.add(j).subtract(2); + var tmp = bmap.select(idx); + var bname = bmap.bandNames().get(idx); + tmp = tmp.where(tst,cmap1); + tmp = tmp.rename([bname]); + bmap = bmap.addBands(tmp,[bname],true); + return ee.Dictionary({'ell':ell,'j':j.add(1),'threshold':threshold,'cmap':cmap,'smap':smap,'fmap':fmap,'bmap':bmap}); +} +function filter_ell(current,prev){ + var pvs = ee.List(current); + prev = ee.Dictionary(prev); + var ell = ee.Number(prev.get('ell')); + var threshold = ee.Image(prev.get('threshold')); + var cmap = prev.get('cmap'); + var smap = prev.get('smap'); + var fmap = prev.get('fmap'); + var bmap = prev.get('bmap'); + var first = ee.Dictionary({'ell':ell,'j':1, 'threshold':threshold,'cmap':cmap,'smap':smap,'fmap':fmap,'bmap':bmap}); + var result = ee.Dictionary(ee.List(pvs).iterate(filter_j,first)); + return ee.Dictionary({'ell':ell.add(1),'threshold':threshold,'cmap':result.get('cmap'), + 'smap':result.get('smap'), + 'fmap':result.get('fmap'), + 'bmap':result.get('bmap')}); +} +exports.omnibus = function(imList,significance,median){ +// return change maps for sequential omnibus change algorithm + imList = ee.List(imList).map(multbyenl); + var p = ee.Image(imList.get(0)).bandNames().length(); + var k = imList.length(); +// pre-calculate p-value array + var ells = ee.List.sequence(1,k.subtract(1)); + var first = ee.Dictionary({'k':k,'p':p,'median':median,'imList':imList,'pv_arr':ee.List([])}); + var pv_arr = ee.List(ee.Dictionary(ells.iterate(ells_iter,first)).get('pv_arr')); +// filter p-values to generate cmap, smap, fmap and bmap + var cmap = ee.Image(imList.get(0)).select(0).multiply(0.0); + var smap = ee.Image(imList.get(0)).select(0).multiply(0.0); + var fmap = ee.Image(imList.get(0)).select(0).multiply(0.0); + var bmap = ee.Image.constant(ee.List.repeat(0,k.subtract(1))); + var threshold = ee.Image.constant(1-significance); + var first1 = ee.Dictionary({'ell':1,'threshold':threshold,'cmap':cmap,'smap':smap,'fmap':fmap,'bmap':bmap}); + return ee.Dictionary(pv_arr.iterate(filter_ell,first1)); +}; \ No newline at end of file diff --git a/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/utilities_v1.1 b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/utilities_v1.1 new file mode 100644 index 0000000..33a909e --- /dev/null +++ b/docs/book/Part A - Applications/A1 - Human Applications/A1.8 Monitoring Gold Mining Activity Using SAR/modules/utilities_v1.1 @@ -0,0 +1,156 @@ +//********************************************************************************* +// Utilities for change detection +//********************************************************************************* +// References: +// +// Updated April 4, 2020 : Modified from 'users/mortcanty/changedetection:utilities' +// +//********************************************************************************* +exports.chi2cdf = function(chi2,df){ +// Chi square cumulative distribution function ''' + return ee.Image(chi2.divide(2)).gammainc(ee.Number(df).divide(2)); +}; +exports.makefeature = function(data){ +// for exporting as CSV to Drive + return ee.Feature(null, {'data': data});}; +exports.makeLegend = function(vis) { + var lon = ee.Image.pixelLonLat().select('longitude'); + var gradient = lon.multiply((vis.max-vis.min)/100.0).add(vis.min); + var legendImage = gradient.visualize(vis); +// Add legend to a panel + var thumb = ui.Thumbnail({ + image: legendImage, + params: {bbox:'0,0,100,8', dimensions:'256x15'}, + style: {padding: '1px', position: 'top-center'} + }); + var panel = ui.Panel({ + widgets: [ + ui.Label(String(vis['min'])), + ui.Label({style: {stretch: 'horizontal'}}), + ui.Label(vis['max']) + ], + layout: ui.Panel.Layout.flow('horizontal'), + style: {stretch: 'horizontal'} + }); + return ui.Panel().add(panel).add(thumb); +}; +exports.rcut = function(image,geometry,k,title,max){ +// generate time axis chart + var bmap = image.select(ee.List.sequence(3,k+2)); + var zeroes = bmap.multiply(0) + var ones = zeroes.add(1); + var twos = zeroes.add(2); + var threes = zeroes.add(3) + var bmapall = zeroes.where(bmap.gt(0),ones) + var bmappos = zeroes.where(bmap.eq(ones),ones); + var bmapneg = zeroes.where(bmap.eq(twos),ones); + var bmapind = zeroes.where(bmap.eq(threes),ones); + + var cutall = ee.Dictionary(bmapall.reduceRegion(ee.Reducer.mean(),geometry,null,null,null,false,1e11)); + var keys = cutall.keys().map( function(x) {return ee.String(x).slice(1,9)}); + var chartall = ui.Chart.array.values(cutall.toArray(),0,keys).setChartType('ColumnChart'); + + var cutpos = ee.Dictionary(bmappos.reduceRegion(ee.Reducer.mean(),geometry,null,null,null,false,1e11)); + var chartpos = ui.Chart.array.values(cutpos.toArray(),0,keys).setChartType('ColumnChart'); + + var cutneg = ee.Dictionary(bmapneg.reduceRegion(ee.Reducer.mean(),geometry,null,null,null,false,1e11)); + var chartneg = ui.Chart.array.values(cutneg.toArray(),0,keys).setChartType('ColumnChart'); + + var cutind = ee.Dictionary(bmapind.reduceRegion(ee.Reducer.mean(),geometry,null,null,null,false,1e11)); + var chartind = ui.Chart.array.values(cutind.toArray(),0,keys).setChartType('ColumnChart'); + + chartall.setOptions({ + title: title, + hAxis: { + title: 'End of Change Interval' + }, + vAxis: { + title: 'Fraction of Changes', + viewWindow: { + min: 0.0, + max: max + }, + textStyle : { + fontSize: 16 + } + }}); + chartpos.setOptions({ + title: title, + hAxis: { + title: 'End of Change Interval' + }, + vAxis: { + title: 'Fraction of Positive Definite Changes', + viewWindow: { + min: 0.0, + max: max + }, + textStyle : { + fontSize: 16 + } + }}); + chartneg.setOptions({ + title: title, + hAxis: { + title: 'End of Change Interval' + }, + vAxis: { + title: 'Fraction of Negative Definite Changes', + viewWindow: { + min: 0.0, + max: max + }, + textStyle : { + fontSize: 16 + } + }}); + chartind.setOptions({ + title: title, + hAxis: { + title: 'End of Change Interval' + }, + vAxis: { + title: 'Fraction of Indefinite Changes', + viewWindow: { + min: 0.0, + max: max + }, + textStyle : { + fontSize: 16 + } + }}); + return([chartall,chartpos,chartneg,chartind]); +}; +exports.makevideo = function(current,prev){ +// iterator function to generate video frames + var n = ee.Number(current); + prev = ee.Dictionary(prev); + var bmap = ee.Image(prev.get('bmap')); + var bnames = bmap.bandNames(); + var label = bnames.get(n); + var background = ee.Image(prev.get('background')); + var framelist = ee.List(prev.get('framelist')); + var bmapband = bmap.select(n); + var zeroes = bmapband.multiply(0); + var ones = zeroes.add(1); + var twos = zeroes.add(2); + var threes = zeroes.add(3) + var idxr = bmapband.eq(ones); + var idxg = bmapband.eq(twos); + var idxy = bmapband.eq(threes); + var imager = background.where(idxr,ones); + var imageg = background.where(idxr,zeroes); + var imageb = background.where(idxr,zeroes); + var imageg = imageg.where(idxg,ones); + var imager = imager.where(idxg,zeroes); + var imageb = imageb.where(idxg,zeroes); + var imageb = imageb.where(idxy,zeroes); + var imager = imager.where(idxy,ones); + var imageg = imageg.where(idxy,ones); + var frame = imager.addBands(imageg).addBands(imageb) + .multiply(256) + .uint8() + .rename(['r','g','b']) + .set({label:label}); + return ee.Dictionary({'bmap':bmap,'background':background,'framelist':framelist.add(frame)}); +}; \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21a Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21a Checkpoint.ipynb new file mode 100644 index 0000000..305336a --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21a Checkpoint.ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.1 Groundwater Monitoring with GRACE\n", + "# Checkpoint: A21a\n", + "# Authors: A.J. Purdy, J.S. Famiglietti\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import Basins.\n", + "basins = ee.FeatureCollection('USGS/WBD/2017/HUC04')\n", + "\n", + "# Extract the 3 HUC 04 basins for the Central Valley.\n", + "codes = ['1802', '1803', '1804']\n", + "basin = basins.filter(ee.Filter.inList('huc4', codes))\n", + "\n", + "# Add the basin to the map to show the extent of our analysis.\n", + "Map.centerObject(basin, 6)\n", + "Map.addLayer(basin, {\n", + " 'color': 'green'\n", + "}, 'Central Valley Basins', True, 0.5)\n", + "\n", + "landcover = ee.ImageCollection('USDA/NASS/CDL') \\\n", + " .filter(ee.Filter.date('2019-01-01', '2019-12-31')) \\\n", + " .select('cultivated')\n", + "\n", + "Map.addLayer(landcover.first().clip(basin), {}, 'Cropland', True,\n", + " 0.5)\n", + "\n", + "# This table was generated using the index from the CDEC website\n", + "res = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-1/ca_reservoirs_index')\n", + "# Filter reservoir locations by the Central Valley geometry\n", + "res_cv = res.filterBounds(basin)\n", + "Map.addLayer(res_cv, {\n", + " 'color': 'blue'\n", + "}, 'Reservoirs')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21a Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21a Checkpoint.js new file mode 100644 index 0000000..c4bbd7e --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21a Checkpoint.js @@ -0,0 +1,38 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.1 Groundwater Monitoring with GRACE +// Checkpoint: A21a +// Authors: A.J. Purdy, J.S. Famiglietti +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import Basins. +var basins = ee.FeatureCollection('USGS/WBD/2017/HUC04'); + +// Extract the 3 HUC 04 basins for the Central Valley. +var codes = ['1802', '1803', '1804']; +var basin = basins.filter(ee.Filter.inList('huc4', codes)); + +// Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6); +Map.addLayer(basin, { + color: 'green' +}, 'Central Valley Basins', true, 0.5); + +var landcover = ee.ImageCollection('USDA/NASS/CDL') + .filter(ee.Filter.date('2019-01-01', '2019-12-31')) + .select('cultivated'); + +Map.addLayer(landcover.first().clip(basin), {}, 'Cropland', true, + 0.5); + +// This table was generated using the index from the CDEC website +var res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index'); +// Filter reservoir locations by the Central Valley geometry +var res_cv = res.filterBounds(basin); +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21a Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21a Checkpoint.py new file mode 100644 index 0000000..19d2b3a --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21a Checkpoint.py @@ -0,0 +1,44 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.1 Groundwater Monitoring with GRACE +# Checkpoint: A21a +# Authors: A.J. Purdy, J.S. Famiglietti +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import Basins. +basins = ee.FeatureCollection('USGS/WBD/2017/HUC04') + +# Extract the 3 HUC 04 basins for the Central Valley. +codes = ['1802', '1803', '1804'] +basin = basins.filter(ee.Filter.inList('huc4', codes)) + +# Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6) +Map.addLayer(basin, { + 'color': 'green' +}, 'Central Valley Basins', True, 0.5) + +landcover = ee.ImageCollection('USDA/NASS/CDL') \ + .filter(ee.Filter.date('2019-01-01', '2019-12-31')) \ + .select('cultivated') + +Map.addLayer(landcover.first().clip(basin), {}, 'Cropland', True, + 0.5) + +# This table was generated using the index from the CDEC website +res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index') +# Filter reservoir locations by the Central Valley geometry +res_cv = res.filterBounds(basin) +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21b Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21b Checkpoint.ipynb new file mode 100644 index 0000000..bdd4d10 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21b Checkpoint.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.1 Groundwater Monitoring with GRACE\n", + "# Checkpoint: A21b\n", + "# Authors: A.J. Purdy, J.S. Famiglietti\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import Basins.\n", + "basins = ee.FeatureCollection('USGS/WBD/2017/HUC04')\n", + "\n", + "# Extract the 3 HUC 04 basins for the Central Valley.\n", + "codes = ['1802', '1803', '1804']\n", + "basin = basins.filter(ee.Filter.inList('huc4', codes))\n", + "\n", + "# Add the basin to the map to show the extent of our analysis.\n", + "Map.centerObject(basin, 6)\n", + "Map.addLayer(basin, {\n", + " 'color': 'green'\n", + "}, 'Central Valley Basins', True, 0.5)\n", + "\n", + "landcover = ee.ImageCollection('USDA/NASS/CDL') \\\n", + " .filter(ee.Filter.date('2019-01-01', '2019-12-31')) \\\n", + " .select('cultivated')\n", + "\n", + "Map.addLayer(landcover.first().clip(basin), {}, 'Cropland', True,\n", + " 0.5)\n", + "\n", + "# This table was generated using the index from the CDEC website\n", + "res = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-1/ca_reservoirs_index')\n", + "# Filter reservoir locations by the Central Valley geometry\n", + "res_cv = res.filterBounds(basin)\n", + "Map.addLayer(res_cv, {\n", + " 'color': 'blue'\n", + "}, 'Reservoirs')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI')\n", + "# Subset GRACE for liquid water equivalent dataset\n", + "basinTWSa = GRACE.select('lwe_thickness')\n", + "\n", + "# Make plot of TWSa for Basin Boundary\n", + "TWSaChart = ui.Chart.image.series({\n", + " 'imageCollection': basinTWSa.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " }) \\\n", + " .setOptions({\n", + " 'title': 'TWSa',\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'TWSa (cm)'\n", + " },\n", + " 'lineWidth': 1,\n", + " })\n", + "print(TWSaChart)\n", + "\n", + "# Compute Trend for each pixel to map regions of most change\n", + "def addVariables(image):\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('2003-01-01'), 'year')\n", + " # Return the image with the added bands.\n", + " return image \\\n", + " .addBands(ee.Image(years).rename('t').float()) \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "cvTWSa = basinTWSa.filterBounds(basin).map(addVariables)\n", + "print(cvTWSa)\n", + "# List of the independent variable names\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('lwe_thickness')\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 band called coefficients (columns are for dependent variables).\n", + "trend = cvTWSa.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Flatten the coefficients into a 2-band image\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Create a layer of the TWSa slope to add to the map\n", + "slope = coefficients.select('t')\n", + "# Set visualization parameters to represent positive (blue) & negative (red) trends\n", + "slopeParams = {\n", + " 'min': -3.5,\n", + " 'max': 3.5,\n", + " 'palette': ['red', 'white', 'blue']\n", + "}\n", + "Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Trend', True,\n", + " 0.75)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21b Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21b Checkpoint.js new file mode 100644 index 0000000..65924c8 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21b Checkpoint.js @@ -0,0 +1,105 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.1 Groundwater Monitoring with GRACE +// Checkpoint: A21b +// Authors: A.J. Purdy, J.S. Famiglietti +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import Basins. +var basins = ee.FeatureCollection('USGS/WBD/2017/HUC04'); + +// Extract the 3 HUC 04 basins for the Central Valley. +var codes = ['1802', '1803', '1804']; +var basin = basins.filter(ee.Filter.inList('huc4', codes)); + +// Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6); +Map.addLayer(basin, { + color: 'green' +}, 'Central Valley Basins', true, 0.5); + +var landcover = ee.ImageCollection('USDA/NASS/CDL') + .filter(ee.Filter.date('2019-01-01', '2019-12-31')) + .select('cultivated'); + +Map.addLayer(landcover.first().clip(basin), {}, 'Cropland', true, + 0.5); + +// This table was generated using the index from the CDEC website +var res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index'); +// Filter reservoir locations by the Central Valley geometry +var res_cv = res.filterBounds(basin); +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI'); +// Subset GRACE for liquid water equivalent dataset +var basinTWSa = GRACE.select('lwe_thickness'); + +// Make plot of TWSa for Basin Boundary +var TWSaChart = ui.Chart.image.series({ + imageCollection: basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + }) + .setOptions({ + title: 'TWSa', + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'TWSa (cm)' + }, + lineWidth: 1, + }); +print(TWSaChart); + +// Compute Trend for each pixel to map regions of most change +var addVariables = function(image) { + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('2003-01-01'), 'year'); + // Return the image with the added bands. + return image + // Add a time band. + .addBands(ee.Image(years).rename('t').float()) + // Add a constant band. + .addBands(ee.Image.constant(1)); +}; +var cvTWSa = basinTWSa.filterBounds(basin).map(addVariables); +print(cvTWSa); +// List of the independent variable names +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('lwe_thickness'); +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = cvTWSa.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image +var coefficients = trend.select('coefficients') + .arrayProject([0]) + .arrayFlatten([independents]); + +// Create a layer of the TWSa slope to add to the map +var slope = coefficients.select('t'); +// Set visualization parameters to represent positive (blue) & negative (red) trends +var slopeParams = { + min: -3.5, + max: 3.5, + palette: ['red', 'white', 'blue'] +}; +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Trend', true, + 0.75); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21b Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21b Checkpoint.py new file mode 100644 index 0000000..e2abe90 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21b Checkpoint.py @@ -0,0 +1,109 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.1 Groundwater Monitoring with GRACE +# Checkpoint: A21b +# Authors: A.J. Purdy, J.S. Famiglietti +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import Basins. +basins = ee.FeatureCollection('USGS/WBD/2017/HUC04') + +# Extract the 3 HUC 04 basins for the Central Valley. +codes = ['1802', '1803', '1804'] +basin = basins.filter(ee.Filter.inList('huc4', codes)) + +# Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6) +Map.addLayer(basin, { + 'color': 'green' +}, 'Central Valley Basins', True, 0.5) + +landcover = ee.ImageCollection('USDA/NASS/CDL') \ + .filter(ee.Filter.date('2019-01-01', '2019-12-31')) \ + .select('cultivated') + +Map.addLayer(landcover.first().clip(basin), {}, 'Cropland', True, + 0.5) + +# This table was generated using the index from the CDEC website +res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index') +# Filter reservoir locations by the Central Valley geometry +res_cv = res.filterBounds(basin) +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI') +# Subset GRACE for liquid water equivalent dataset +basinTWSa = GRACE.select('lwe_thickness') + +# Make plot of TWSa for Basin Boundary +TWSaChart = ui.Chart.image.series({ + 'imageCollection': basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + }) \ + .setOptions({ + 'title': 'TWSa', + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'TWSa (cm)' + }, + 'lineWidth': 1, + }) +print(TWSaChart) + +# Compute Trend for each pixel to map regions of most change +def addVariables(image): + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('2003-01-01'), 'year') + # Return the image with the added bands. + return image \ + .addBands(ee.Image(years).rename('t').float()) \ + .addBands(ee.Image.constant(1)) + +cvTWSa = basinTWSa.filterBounds(basin).map(addVariables) +print(cvTWSa) +# List of the independent variable names +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('lwe_thickness') +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 band called coefficients (columns are for dependent variables). +trend = cvTWSa.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Flatten the coefficients into a 2-band image +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Create a layer of the TWSa slope to add to the map +slope = coefficients.select('t') +# Set visualization parameters to represent positive (blue) & negative (red) trends +slopeParams = { + 'min': -3.5, + 'max': 3.5, + 'palette': ['red', 'white', 'blue'] +} +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Trend', True, + 0.75) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21c Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21c Checkpoint.ipynb new file mode 100644 index 0000000..2435f07 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21c Checkpoint.ipynb @@ -0,0 +1,271 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "res_table = ee.FeatureCollection(\"projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3\"),\n", + " sm2003 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2003\"),\n", + " sm2004 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2004\"),\n", + " sm2005 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2005\"),\n", + " sm2006 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2006\"),\n", + " sm2007 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2007\"),\n", + " sm2008 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2008\"),\n", + " sm2009 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2009\"),\n", + " sm2010 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2010\"),\n", + " sm2011 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2011\"),\n", + " sm2012 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2012\"),\n", + " sm2013 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2013\"),\n", + " sm2014 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2014\"),\n", + " sm2015 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2015\"),\n", + " sm2016 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2016\"),\n", + " swe2003 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2003\"),\n", + " swe2004 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2004\"),\n", + " swe2005 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2005\"),\n", + " swe2006 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2006\"),\n", + " swe2007 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2007\"),\n", + " swe2008 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2008\"),\n", + " swe2009 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2009\"),\n", + " swe2010 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2010\"),\n", + " swe2011 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2011\"),\n", + " swe2012 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2012\"),\n", + " swe2013 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2013\"),\n", + " swe2014 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2014\"),\n", + " swe2015 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2015\"),\n", + " swe2016 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2016\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.1 Groundwater Monitoring with GRACE\n", + "# Checkpoint: A21c\n", + "# Authors: A.J. Purdy, J.S. Famiglietti\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import Basins\n", + "basins = ee.FeatureCollection('USGS/WBD/2017/HUC04')\n", + "\n", + "# Extract the 3 HUC 04 basins for the Central Valley.\n", + "codes = ['1802', '1803', '1804']\n", + "basin = basins.filter(ee.Filter.inList('huc4', codes))\n", + "\n", + "# Add the basin to the map to show the extent of our analysis.\n", + "Map.centerObject(basin, 6)\n", + "Map.addLayer(basin, {\n", + " 'color': 'green'\n", + "}, 'Central Valley Basins', True, 0.5)\n", + "\n", + "# This table was generated using the index from the CDEC website\n", + "res = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-1/ca_reservoirs_index')\n", + "# Filter reservoir locations by the Central Valley geometry\n", + "res_cv = res.filterBounds(basin)\n", + "Map.addLayer(res_cv, {\n", + " 'color': 'blue'\n", + "}, 'Reservoirs')\n", + "\n", + "# Import GRACE groundwater.\n", + "GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI')\n", + "# Get Liquid Water Equivalent thickness.\n", + "basinTWSa = GRACE.select('lwe_thickness')\n", + "\n", + "# Make plot of TWSa for Basin Boundary\n", + "TWSaChart = ui.Chart.image.series({\n", + " 'imageCollection': basinTWSa.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " }) \\\n", + " .setOptions({\n", + " 'title': 'TWSa',\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'TWSa (cm)'\n", + " },\n", + " 'lineWidth': 1,\n", + " })\n", + "print(TWSaChart)\n", + "\n", + "# Set start and end years to annualize the data.\n", + "yrStart = 2003\n", + "yrEnd = 2016\n", + "years = ee.List.sequence(yrStart, yrEnd)\n", + "\n", + "def func_cdy(y):\n", + " date = ee.Date.fromYMD(y, 1, 1)\n", + " return basinTWSa.filter(ee.Filter.calendarRange(y, y,\n", + " 'year')) \\\n", + " .mean() \\\n", + " .set('system:time_start', date) \\\n", + " .rename('TWSa')\n", + "\n", + "GRACE_yr = ee.ImageCollection.fromImages(years.map(func_cdy\n", + ").flatten())\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten())\n", + "\n", + "# Make plot of annualized TWSa for Basin Boundary.\n", + "TWSaChart = ui.Chart.image.series({\n", + " 'imageCollection': GRACE_yr.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }).setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Annualized Total Water Storage anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'TWSa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(TWSaChart)\n", + "\n", + "# Compute Trend for each pixel to map regions of most change.\n", + "\n", + "def addVariables(image):\n", + " # Compute time in fractional years.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('2003-01-01'), 'year')\n", + " # Return the image with the added bands.\n", + " return image \\\n", + " .addBands(ee.Image(years).rename('t').float()) \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables)\n", + "print(cvTWSa)\n", + "\n", + "# List of the independent variable names\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('TWSa')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 band called coefficients (columns are for dependent variables).\n", + "trend = cvTWSa.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Flatten the coefficients into a 2-band image.\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Create a layer of the TWSa slope to add to the map.\n", + "slope = coefficients.select('t')\n", + "# Set visualization parameters to represent positive (blue)\n", + "# & negative (red) trends.\n", + "slopeParams = {\n", + " 'min': -3.5,\n", + " 'max': 3.5,\n", + " 'palette': ['red', 'white', 'blue']\n", + "}\n", + "Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', True,\n", + " 0.75)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# Paste the code from section 3.1 below\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21c Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21c Checkpoint.js new file mode 100644 index 0000000..8e5f50b --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21c Checkpoint.js @@ -0,0 +1,170 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var res_table = ee.FeatureCollection("projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3"), + sm2003 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2003"), + sm2004 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2004"), + sm2005 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2005"), + sm2006 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2006"), + sm2007 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2007"), + sm2008 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2008"), + sm2009 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2009"), + sm2010 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2010"), + sm2011 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2011"), + sm2012 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2012"), + sm2013 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2013"), + sm2014 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2014"), + sm2015 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2015"), + sm2016 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2016"), + swe2003 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2003"), + swe2004 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2004"), + swe2005 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2005"), + swe2006 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2006"), + swe2007 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2007"), + swe2008 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2008"), + swe2009 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2009"), + swe2010 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2010"), + swe2011 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2011"), + swe2012 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2012"), + swe2013 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2013"), + swe2014 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2014"), + swe2015 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2015"), + swe2016 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2016"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.1 Groundwater Monitoring with GRACE +// Checkpoint: A21c +// Authors: A.J. Purdy, J.S. Famiglietti +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import Basins +var basins = ee.FeatureCollection('USGS/WBD/2017/HUC04'); + +// Extract the 3 HUC 04 basins for the Central Valley. +var codes = ['1802', '1803', '1804']; +var basin = basins.filter(ee.Filter.inList('huc4', codes)); + +// Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6); +Map.addLayer(basin, { + color: 'green' +}, 'Central Valley Basins', true, 0.5); + +// This table was generated using the index from the CDEC website +var res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index'); +// Filter reservoir locations by the Central Valley geometry +var res_cv = res.filterBounds(basin); +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs'); + +// Import GRACE groundwater. +var GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI'); +// Get Liquid Water Equivalent thickness. +var basinTWSa = GRACE.select('lwe_thickness'); + +// Make plot of TWSa for Basin Boundary +var TWSaChart = ui.Chart.image.series({ + imageCollection: basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + }) + .setOptions({ + title: 'TWSa', + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'TWSa (cm)' + }, + lineWidth: 1, + }); +print(TWSaChart); + +// Set start and end years to annualize the data. +var yrStart = 2003; +var yrEnd = 2016; +var years = ee.List.sequence(yrStart, yrEnd); +var GRACE_yr = ee.ImageCollection.fromImages(years.map(function(y) { + var date = ee.Date.fromYMD(y, 1, 1); + return basinTWSa.filter(ee.Filter.calendarRange(y, y, + 'year')) + .mean() + .set('system:time_start', date) + .rename('TWSa'); +}).flatten()); + +// Make plot of annualized TWSa for Basin Boundary. +var TWSaChart = ui.Chart.image.series({ + imageCollection: GRACE_yr.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }).setChartType('ScatterChart') + .setOptions({ + title: 'Annualized Total Water Storage anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'TWSa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(TWSaChart); + +// Compute Trend for each pixel to map regions of most change. + +var addVariables = function(image) { + // Compute time in fractional years. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('2003-01-01'), 'year'); + // Return the image with the added bands. + return image + // Add a time band. + .addBands(ee.Image(years).rename('t').float()) + // Add a constant band. + .addBands(ee.Image.constant(1)); +}; + +var cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables); +print(cvTWSa); + +// List of the independent variable names +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('TWSa'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = cvTWSa.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image. +var coefficients = trend.select('coefficients') + .arrayProject([0]) + .arrayFlatten([independents]); + +// Create a layer of the TWSa slope to add to the map. +var slope = coefficients.select('t'); +// Set visualization parameters to represent positive (blue) +// & negative (red) trends. +var slopeParams = { + min: -3.5, + max: 3.5, + palette: ['red', 'white', 'blue'] +}; +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', true, + 0.75); + +// ----------------------------------------------------------------------- +// Paste the code from section 3.1 below +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21c Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21c Checkpoint.py new file mode 100644 index 0000000..b254ea2 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21c Checkpoint.py @@ -0,0 +1,184 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +res_table = ee.FeatureCollection("projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3"), + sm2003 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2003"), + sm2004 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2004"), + sm2005 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2005"), + sm2006 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2006"), + sm2007 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2007"), + sm2008 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2008"), + sm2009 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2009"), + sm2010 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2010"), + sm2011 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2011"), + sm2012 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2012"), + sm2013 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2013"), + sm2014 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2014"), + sm2015 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2015"), + sm2016 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2016"), + swe2003 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2003"), + swe2004 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2004"), + swe2005 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2005"), + swe2006 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2006"), + swe2007 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2007"), + swe2008 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2008"), + swe2009 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2009"), + swe2010 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2010"), + swe2011 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2011"), + swe2012 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2012"), + swe2013 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2013"), + swe2014 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2014"), + swe2015 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2015"), + swe2016 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2016") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.1 Groundwater Monitoring with GRACE +# Checkpoint: A21c +# Authors: A.J. Purdy, J.S. Famiglietti +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import Basins +basins = ee.FeatureCollection('USGS/WBD/2017/HUC04') + +# Extract the 3 HUC 04 basins for the Central Valley. +codes = ['1802', '1803', '1804'] +basin = basins.filter(ee.Filter.inList('huc4', codes)) + +# Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6) +Map.addLayer(basin, { + 'color': 'green' +}, 'Central Valley Basins', True, 0.5) + +# This table was generated using the index from the CDEC website +res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index') +# Filter reservoir locations by the Central Valley geometry +res_cv = res.filterBounds(basin) +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs') + +# Import GRACE groundwater. +GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI') +# Get Liquid Water Equivalent thickness. +basinTWSa = GRACE.select('lwe_thickness') + +# Make plot of TWSa for Basin Boundary +TWSaChart = ui.Chart.image.series({ + 'imageCollection': basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + }) \ + .setOptions({ + 'title': 'TWSa', + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'TWSa (cm)' + }, + 'lineWidth': 1, + }) +print(TWSaChart) + +# Set start and end years to annualize the data. +yrStart = 2003 +yrEnd = 2016 +years = ee.List.sequence(yrStart, yrEnd) + +def func_cdy(y): + date = ee.Date.fromYMD(y, 1, 1) + return basinTWSa.filter(ee.Filter.calendarRange(y, y, + 'year')) \ + .mean() \ + .set('system:time_start', date) \ + .rename('TWSa') + +GRACE_yr = ee.ImageCollection.fromImages(years.map(func_cdy +).flatten()) + + + + + + +).flatten()) + +# Make plot of annualized TWSa for Basin Boundary. +TWSaChart = ui.Chart.image.series({ + 'imageCollection': GRACE_yr.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }).setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Annualized Total Water Storage anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'TWSa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(TWSaChart) + +# Compute Trend for each pixel to map regions of most change. + +def addVariables(image): + # Compute time in fractional years. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('2003-01-01'), 'year') + # Return the image with the added bands. + return image \ + .addBands(ee.Image(years).rename('t').float()) \ + .addBands(ee.Image.constant(1)) + + +cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables) +print(cvTWSa) + +# List of the independent variable names +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('TWSa') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 band called coefficients (columns are for dependent variables). +trend = cvTWSa.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Flatten the coefficients into a 2-band image. +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Create a layer of the TWSa slope to add to the map. +slope = coefficients.select('t') +# Set visualization parameters to represent positive (blue) +# & negative (red) trends. +slopeParams = { + 'min': -3.5, + 'max': 3.5, + 'palette': ['red', 'white', 'blue'] +} +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', True, + 0.75) + +# ----------------------------------------------------------------------- +# Paste the code from section 3.1 below +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21d Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21d Checkpoint.ipynb new file mode 100644 index 0000000..07b516a --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21d Checkpoint.ipynb @@ -0,0 +1,368 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "res_table = ee.FeatureCollection(\"projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3\"),\n", + " sm2003 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2003\"),\n", + " sm2004 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2004\"),\n", + " sm2005 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2005\"),\n", + " sm2006 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2006\"),\n", + " sm2007 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2007\"),\n", + " sm2008 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2008\"),\n", + " sm2009 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2009\"),\n", + " sm2010 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2010\"),\n", + " sm2011 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2011\"),\n", + " sm2012 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2012\"),\n", + " sm2013 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2013\"),\n", + " sm2014 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2014\"),\n", + " sm2015 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2015\"),\n", + " sm2016 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2016\"),\n", + " swe2003 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2003\"),\n", + " swe2004 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2004\"),\n", + " swe2005 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2005\"),\n", + " swe2006 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2006\"),\n", + " swe2007 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2007\"),\n", + " swe2008 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2008\"),\n", + " swe2009 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2009\"),\n", + " swe2010 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2010\"),\n", + " swe2011 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2011\"),\n", + " swe2012 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2012\"),\n", + " swe2013 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2013\"),\n", + " swe2014 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2014\"),\n", + " swe2015 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2015\"),\n", + " swe2016 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2016\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.1 Groundwater Monitoring with GRACE\n", + "# Checkpoint: A21d\n", + "# Authors: A.J. Purdy, J.S. Famiglietti\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import Basins\n", + "basins = ee.FeatureCollection('USGS/WBD/2017/HUC04')\n", + "\n", + "# Extract the 3 HUC 04 basins for the Central Valley.\n", + "codes = ['1802', '1803', '1804']\n", + "basin = basins.filter(ee.Filter.inList('huc4', codes))\n", + "\n", + "# Add the basin to the map to show the extent of our analysis.\n", + "Map.centerObject(basin, 6)\n", + "Map.addLayer(basin, {\n", + " 'color': 'green'\n", + "}, 'Central Valley Basins', True, 0.5)\n", + "\n", + "# This table was generated using the index from the CDEC website\n", + "res = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-1/ca_reservoirs_index')\n", + "# Filter reservoir locations by the Central Valley geometry\n", + "res_cv = res.filterBounds(basin)\n", + "Map.addLayer(res_cv, {\n", + " 'color': 'blue'\n", + "}, 'Reservoirs')\n", + "\n", + "# Import GRACE groundwater.\n", + "GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI')\n", + "# Get Liquid Water Equivalent thickness.\n", + "basinTWSa = GRACE.select('lwe_thickness')\n", + "\n", + "# Make plot of TWSa for Basin Boundary\n", + "TWSaChart = ui.Chart.image.series({\n", + " 'imageCollection': basinTWSa.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " }) \\\n", + " .setOptions({\n", + " 'title': 'TWSa',\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'TWSa (cm)'\n", + " },\n", + " 'lineWidth': 1,\n", + " })\n", + "print(TWSaChart)\n", + "\n", + "# Set start and end years to annualize the data.\n", + "yrStart = 2003\n", + "yrEnd = 2016\n", + "years = ee.List.sequence(yrStart, yrEnd)\n", + "\n", + "def func_wng(y):\n", + " date = ee.Date.fromYMD(y, 1, 1)\n", + " return basinTWSa.filter(ee.Filter.calendarRange(y, y,\n", + " 'year')) \\\n", + " .mean() \\\n", + " .set('system:time_start', date) \\\n", + " .rename('TWSa')\n", + "\n", + "GRACE_yr = ee.ImageCollection.fromImages(years.map(func_wng\n", + ").flatten())\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten())\n", + "\n", + "# Make plot of annualized TWSa for Basin Boundary.\n", + "TWSaChart = ui.Chart.image.series({\n", + " 'imageCollection': GRACE_yr.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }).setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Annualized Total Water Storage anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'TWSa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(TWSaChart)\n", + "\n", + "# Compute Trend for each pixel to map regions of most change.\n", + "\n", + "def addVariables(image):\n", + " # Compute time in fractional years.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('2003-01-01'), 'year')\n", + " # Return the image with the added bands.\n", + " return image \\\n", + " .addBands(ee.Image(years).rename('t').float()) \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables)\n", + "print(cvTWSa)\n", + "\n", + "# List of the independent variable names\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('TWSa')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 band called coefficients (columns are for dependent variables).\n", + "trend = cvTWSa.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Flatten the coefficients into a 2-band image.\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Create a layer of the TWSa slope to add to the map.\n", + "slope = coefficients.select('t')\n", + "# Set visualization parameters to represent positive (blue)\n", + "# & negative (red) trends.\n", + "slopeParams = {\n", + " 'min': -3.5,\n", + " 'max': 3.5,\n", + " 'palette': ['red', 'white', 'blue']\n", + "}\n", + "Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', True,\n", + "0.75)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "gldas_sm_list = ee.List([sm2003, sm2004, sm2005, sm2006, sm2007,\n", + " sm2008, sm2009, sm2010, sm2011, sm2012, sm2013, sm2014,\n", + " sm2015, sm2016\n", + "])\n", + "sm_ic = ee.ImageCollection.fromImages(gldas_sm_list)\n", + "\n", + "kgm2_to_cm = 0.10\n", + "\n", + "def func_vva(img):\n", + " date = ee.Date.fromYMD(img.get('year'), 1, 1)\n", + " return img.select('RootMoist_inst').multiply(kgm2_to_cm) \\\n", + " .rename('SMa').set('system:time_start', date)\n", + "\n", + "sm_ic_ts = sm_ic.map(func_vva)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Make plot of SMa for Basin Boundary\n", + "SMaChart = ui.Chart.image.series({\n", + " 'imageCollection': sm_ic_ts.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Soil Moisture anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'SMa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(SMaChart)\n", + "\n", + "gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006,\n", + " swe2007, swe2008, swe2009, swe2010, swe2011, swe2012,\n", + " swe2013, swe2014, swe2015, swe2016\n", + "])\n", + "swe_ic = ee.ImageCollection.fromImages(gldas_swe_list)\n", + "\n", + "\n", + "def func_jhw(img):\n", + " date = ee.Date.fromYMD(img.get('year'), 1, 1)\n", + " return img.select('SWE_inst').multiply(kgm2_to_cm).rename(\n", + " 'SWEa').set('system:time_start', date)\n", + "\n", + "swe_ic_ts = swe_ic.map(func_jhw)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Make plot of SWEa for Basin Boundary\n", + "SWEaChart = ui.Chart.image.series({\n", + " 'imageCollection': swe_ic_ts.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Snow Water Equivalent anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'SWEa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(SWEaChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21d Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21d Checkpoint.js new file mode 100644 index 0000000..9850f0e --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21d Checkpoint.js @@ -0,0 +1,253 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var res_table = ee.FeatureCollection("projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3"), + sm2003 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2003"), + sm2004 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2004"), + sm2005 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2005"), + sm2006 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2006"), + sm2007 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2007"), + sm2008 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2008"), + sm2009 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2009"), + sm2010 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2010"), + sm2011 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2011"), + sm2012 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2012"), + sm2013 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2013"), + sm2014 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2014"), + sm2015 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2015"), + sm2016 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2016"), + swe2003 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2003"), + swe2004 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2004"), + swe2005 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2005"), + swe2006 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2006"), + swe2007 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2007"), + swe2008 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2008"), + swe2009 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2009"), + swe2010 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2010"), + swe2011 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2011"), + swe2012 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2012"), + swe2013 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2013"), + swe2014 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2014"), + swe2015 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2015"), + swe2016 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2016"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.1 Groundwater Monitoring with GRACE +// Checkpoint: A21d +// Authors: A.J. Purdy, J.S. Famiglietti +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import Basins +var basins = ee.FeatureCollection('USGS/WBD/2017/HUC04'); + +// Extract the 3 HUC 04 basins for the Central Valley. +var codes = ['1802', '1803', '1804']; +var basin = basins.filter(ee.Filter.inList('huc4', codes)); + +// Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6); +Map.addLayer(basin, { + color: 'green' +}, 'Central Valley Basins', true, 0.5); + +// This table was generated using the index from the CDEC website +var res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index'); +// Filter reservoir locations by the Central Valley geometry +var res_cv = res.filterBounds(basin); +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs'); + +// Import GRACE groundwater. +var GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI'); +// Get Liquid Water Equivalent thickness. +var basinTWSa = GRACE.select('lwe_thickness'); + +// Make plot of TWSa for Basin Boundary +var TWSaChart = ui.Chart.image.series({ + imageCollection: basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + }) + .setOptions({ + title: 'TWSa', + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'TWSa (cm)' + }, + lineWidth: 1, + }); +print(TWSaChart); + +// Set start and end years to annualize the data. +var yrStart = 2003; +var yrEnd = 2016; +var years = ee.List.sequence(yrStart, yrEnd); +var GRACE_yr = ee.ImageCollection.fromImages(years.map(function(y) { + var date = ee.Date.fromYMD(y, 1, 1); + return basinTWSa.filter(ee.Filter.calendarRange(y, y, + 'year')) + .mean() + .set('system:time_start', date) + .rename('TWSa'); +}).flatten()); + +// Make plot of annualized TWSa for Basin Boundary. +var TWSaChart = ui.Chart.image.series({ + imageCollection: GRACE_yr.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }).setChartType('ScatterChart') + .setOptions({ + title: 'Annualized Total Water Storage anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'TWSa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(TWSaChart); + +// Compute Trend for each pixel to map regions of most change. + +var addVariables = function(image) { + // Compute time in fractional years. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('2003-01-01'), 'year'); + // Return the image with the added bands. + return image + // Add a time band. + .addBands(ee.Image(years).rename('t').float()) + // Add a constant band. + .addBands(ee.Image.constant(1)); +}; + +var cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables); +print(cvTWSa); + +// List of the independent variable names +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('TWSa'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = cvTWSa.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image. +var coefficients = trend.select('coefficients') + .arrayProject([0]) + .arrayFlatten([independents]); + +// Create a layer of the TWSa slope to add to the map. +var slope = coefficients.select('t'); +// Set visualization parameters to represent positive (blue) +// & negative (red) trends. +var slopeParams = { + min: -3.5, + max: 3.5, + palette: ['red', 'white', 'blue'] +}; +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', true, +0.75); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var gldas_sm_list = ee.List([sm2003, sm2004, sm2005, sm2006, sm2007, + sm2008, sm2009, sm2010, sm2011, sm2012, sm2013, sm2014, + sm2015, sm2016 +]); +var sm_ic = ee.ImageCollection.fromImages(gldas_sm_list); + +var kgm2_to_cm = 0.10; +var sm_ic_ts = sm_ic.map(function(img) { + var date = ee.Date.fromYMD(img.get('year'), 1, 1); + return img.select('RootMoist_inst').multiply(kgm2_to_cm) + .rename('SMa').set('system:time_start', date); +}); + +// Make plot of SMa for Basin Boundary +var SMaChart = ui.Chart.image.series({ + imageCollection: sm_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Soil Moisture anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'SMa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(SMaChart); + +var gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]); +var swe_ic = ee.ImageCollection.fromImages(gldas_swe_list); + +var swe_ic_ts = swe_ic.map(function(img) { + var date = ee.Date.fromYMD(img.get('year'), 1, 1); + return img.select('SWE_inst').multiply(kgm2_to_cm).rename( + 'SWEa').set('system:time_start', date); +}); + +// Make plot of SWEa for Basin Boundary +var SWEaChart = ui.Chart.image.series({ + imageCollection: swe_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Snow Water Equivalent anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'SWEa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(SWEaChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21d Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21d Checkpoint.py new file mode 100644 index 0000000..6ca2d93 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21d Checkpoint.py @@ -0,0 +1,281 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +res_table = ee.FeatureCollection("projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3"), + sm2003 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2003"), + sm2004 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2004"), + sm2005 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2005"), + sm2006 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2006"), + sm2007 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2007"), + sm2008 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2008"), + sm2009 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2009"), + sm2010 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2010"), + sm2011 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2011"), + sm2012 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2012"), + sm2013 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2013"), + sm2014 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2014"), + sm2015 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2015"), + sm2016 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2016"), + swe2003 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2003"), + swe2004 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2004"), + swe2005 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2005"), + swe2006 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2006"), + swe2007 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2007"), + swe2008 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2008"), + swe2009 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2009"), + swe2010 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2010"), + swe2011 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2011"), + swe2012 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2012"), + swe2013 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2013"), + swe2014 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2014"), + swe2015 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2015"), + swe2016 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2016") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.1 Groundwater Monitoring with GRACE +# Checkpoint: A21d +# Authors: A.J. Purdy, J.S. Famiglietti +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import Basins +basins = ee.FeatureCollection('USGS/WBD/2017/HUC04') + +# Extract the 3 HUC 04 basins for the Central Valley. +codes = ['1802', '1803', '1804'] +basin = basins.filter(ee.Filter.inList('huc4', codes)) + +# Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6) +Map.addLayer(basin, { + 'color': 'green' +}, 'Central Valley Basins', True, 0.5) + +# This table was generated using the index from the CDEC website +res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index') +# Filter reservoir locations by the Central Valley geometry +res_cv = res.filterBounds(basin) +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs') + +# Import GRACE groundwater. +GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI') +# Get Liquid Water Equivalent thickness. +basinTWSa = GRACE.select('lwe_thickness') + +# Make plot of TWSa for Basin Boundary +TWSaChart = ui.Chart.image.series({ + 'imageCollection': basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + }) \ + .setOptions({ + 'title': 'TWSa', + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'TWSa (cm)' + }, + 'lineWidth': 1, + }) +print(TWSaChart) + +# Set start and end years to annualize the data. +yrStart = 2003 +yrEnd = 2016 +years = ee.List.sequence(yrStart, yrEnd) + +def func_wng(y): + date = ee.Date.fromYMD(y, 1, 1) + return basinTWSa.filter(ee.Filter.calendarRange(y, y, + 'year')) \ + .mean() \ + .set('system:time_start', date) \ + .rename('TWSa') + +GRACE_yr = ee.ImageCollection.fromImages(years.map(func_wng +).flatten()) + + + + + + +).flatten()) + +# Make plot of annualized TWSa for Basin Boundary. +TWSaChart = ui.Chart.image.series({ + 'imageCollection': GRACE_yr.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }).setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Annualized Total Water Storage anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'TWSa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(TWSaChart) + +# Compute Trend for each pixel to map regions of most change. + +def addVariables(image): + # Compute time in fractional years. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('2003-01-01'), 'year') + # Return the image with the added bands. + return image \ + .addBands(ee.Image(years).rename('t').float()) \ + .addBands(ee.Image.constant(1)) + + +cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables) +print(cvTWSa) + +# List of the independent variable names +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('TWSa') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 band called coefficients (columns are for dependent variables). +trend = cvTWSa.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Flatten the coefficients into a 2-band image. +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Create a layer of the TWSa slope to add to the map. +slope = coefficients.select('t') +# Set visualization parameters to represent positive (blue) +# & negative (red) trends. +slopeParams = { + 'min': -3.5, + 'max': 3.5, + 'palette': ['red', 'white', 'blue'] +} +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', True, +0.75) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +gldas_sm_list = ee.List([sm2003, sm2004, sm2005, sm2006, sm2007, + sm2008, sm2009, sm2010, sm2011, sm2012, sm2013, sm2014, + sm2015, sm2016 +]) +sm_ic = ee.ImageCollection.fromImages(gldas_sm_list) + +kgm2_to_cm = 0.10 + +def func_vva(img): + date = ee.Date.fromYMD(img.get('year'), 1, 1) + return img.select('RootMoist_inst').multiply(kgm2_to_cm) \ + .rename('SMa').set('system:time_start', date) + +sm_ic_ts = sm_ic.map(func_vva) + + + + + + +# Make plot of SMa for Basin Boundary +SMaChart = ui.Chart.image.series({ + 'imageCollection': sm_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Soil Moisture anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'SMa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(SMaChart) + +gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]) +swe_ic = ee.ImageCollection.fromImages(gldas_swe_list) + + +def func_jhw(img): + date = ee.Date.fromYMD(img.get('year'), 1, 1) + return img.select('SWE_inst').multiply(kgm2_to_cm).rename( + 'SWEa').set('system:time_start', date) + +swe_ic_ts = swe_ic.map(func_jhw) + + + + + + +# Make plot of SWEa for Basin Boundary +SWEaChart = ui.Chart.image.series({ + 'imageCollection': swe_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Snow Water Equivalent anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'SWEa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(SWEaChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21e Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21e Checkpoint.ipynb new file mode 100644 index 0000000..d28c0c4 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21e Checkpoint.ipynb @@ -0,0 +1,458 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "res_table = ee.FeatureCollection(\"projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3\"),\n", + " sm2003 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2003\"),\n", + " sm2004 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2004\"),\n", + " sm2005 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2005\"),\n", + " sm2006 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2006\"),\n", + " sm2007 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2007\"),\n", + " sm2008 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2008\"),\n", + " sm2009 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2009\"),\n", + " sm2010 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2010\"),\n", + " sm2011 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2011\"),\n", + " sm2012 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2012\"),\n", + " sm2013 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2013\"),\n", + " sm2014 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2014\"),\n", + " sm2015 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2015\"),\n", + " sm2016 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2016\"),\n", + " swe2003 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2003\"),\n", + " swe2004 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2004\"),\n", + " swe2005 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2005\"),\n", + " swe2006 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2006\"),\n", + " swe2007 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2007\"),\n", + " swe2008 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2008\"),\n", + " swe2009 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2009\"),\n", + " swe2010 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2010\"),\n", + " swe2011 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2011\"),\n", + " swe2012 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2012\"),\n", + " swe2013 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2013\"),\n", + " swe2014 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2014\"),\n", + " swe2015 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2015\"),\n", + " swe2016 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2016\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.1 Groundwater Monitoring with GRACE\n", + "# Checkpoint: A21e\n", + "# Authors: A.J. Purdy, J.S. Famiglietti\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# ** Part 1 **\n", + "\n", + "# Import Basins\n", + "basins = ee.FeatureCollection('USGS/WBD/2017/HUC04')\n", + "\n", + "# Extract the 3 HUC 04 basins for the Central Valley.\n", + "codes = ['1802', '1803', '1804']\n", + "basin = basins.filter(ee.Filter.inList('huc4', codes))\n", + "\n", + "# Add the basin to the map to show the extent of our analysis.\n", + "Map.centerObject(basin, 6)\n", + "Map.addLayer(basin, {\n", + " 'color': 'green'\n", + "}, 'Central Valley Basins', True, 0.5)\n", + "\n", + "res = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-1/ca_reservoirs_index')\n", + "res_cv = res.filterBounds(basin)\n", + "Map.addLayer(res_cv, {\n", + " 'color': 'blue'\n", + "}, 'Reservoirs')\n", + "\n", + "# Import GRACE groundwater.\n", + "GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI')\n", + "# Get Liquid Water Equivalent thickness.\n", + "basinTWSa = GRACE.select('lwe_thickness')\n", + "\n", + "# Make plot of TWSa for Basin Boundary\n", + "TWSaChart = ui.Chart.image.series({\n", + " 'imageCollection': basinTWSa.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " }) \\\n", + " .setOptions({\n", + " 'title': 'TWSa',\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'TWSa (cm)'\n", + " },\n", + " 'lineWidth': 1,\n", + " })\n", + "print(TWSaChart)\n", + "\n", + "# Set start and end years to annualize the data.\n", + "yrStart = 2003\n", + "yrEnd = 2016\n", + "years = ee.List.sequence(yrStart, yrEnd)\n", + "\n", + "def func_lnn(y):\n", + " date = ee.Date.fromYMD(y, 1, 1)\n", + " return basinTWSa.filter(ee.Filter.calendarRange(y, y,\n", + " 'year')) \\\n", + " .mean() \\\n", + " .set('system:time_start', date) \\\n", + " .rename('TWSa')\n", + "\n", + "GRACE_yr = ee.ImageCollection.fromImages(years.map(func_lnn\n", + ").flatten())\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten())\n", + "\n", + "# Make plot of annualized TWSa for Basin Boundary.\n", + "TWSaChart = ui.Chart.image.series({\n", + " 'imageCollection': GRACE_yr.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }).setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Annualized Total Water Storage anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'TWSa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(TWSaChart)\n", + "\n", + "# Compute Trend for each pixel to map regions of most change.\n", + "\n", + "def addVariables(image):\n", + " # Compute time in fractional years.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('2003-01-01'), 'year')\n", + " # Return the image with the added bands.\n", + " return image \\\n", + " .addBands(ee.Image(years).rename('t').float()) \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables)\n", + "print(cvTWSa)\n", + "\n", + "# List of the independent variable names\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('TWSa')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 band called coefficients (columns are for dependent variables).\n", + "trend = cvTWSa.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Flatten the coefficients into a 2-band image.\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Create a layer of the TWSa slope to add to the map.\n", + "slope = coefficients.select('t')\n", + "# Set visualization parameters to represent positive (blue)\n", + "# & negative (red) trends.\n", + "slopeParams = {\n", + " 'min': -3.5,\n", + " 'max': 3.5,\n", + " 'palette': ['red', 'white', 'blue']\n", + "}\n", + "Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', True,\n", + " 0.75)\n", + "\n", + "# ** Part 2 **\n", + "\n", + "# ** Section 3 **\n", + "\n", + "# 3.1 Load GLDAS Soil Moisture images from an Asset to an ImageCollection.\n", + "\n", + "gldas_sm_list = ee.List([sm2003, sm2004, sm2005, sm2006, sm2007,\n", + " sm2008, sm2009, sm2010, sm2011, sm2012, sm2013, sm2014,\n", + " sm2015, sm2016\n", + "])\n", + "sm_ic = ee.ImageCollection.fromImages(gldas_sm_list)\n", + "\n", + "kgm2_to_cm = 0.10\n", + "\n", + "def func_kmm(img):\n", + " date = ee.Date.fromYMD(img.get('year'), 1, 1)\n", + " return img.select('RootMoist_inst').multiply(kgm2_to_cm) \\\n", + " .rename('SMa').set('system:time_start', date)\n", + "\n", + "sm_ic_ts = sm_ic.map(func_kmm)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "kgm2_to_cm = 0.10\n", + "\n", + "def func_zvs(img):\n", + " date = ee.Date.fromYMD(img.get('year'), 1, 1)\n", + " return img.select('RootMoist_inst').multiply(kgm2_to_cm) \\\n", + " .rename('SMa').set('system:time_start', date)\n", + "\n", + "sm_ic_ts = sm_ic.map(func_zvs)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Make plot of SMa for Basin Boundary\n", + "SMaChart = ui.Chart.image.series({\n", + " 'imageCollection': sm_ic_ts.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Soil Moisture anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'SMa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(SMaChart)\n", + "\n", + "gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006,\n", + " swe2007, swe2008, swe2009, swe2010, swe2011, swe2012,\n", + " swe2013, swe2014, swe2015, swe2016\n", + "])\n", + "swe_ic = ee.ImageCollection.fromImages(gldas_swe_list)\n", + "\n", + "# 3.2. Load GLDAS Snow Water Equivalent Images from an Asset to an Image Collection\n", + "\n", + "gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006,\n", + " swe2007, swe2008, swe2009, swe2010, swe2011, swe2012,\n", + " swe2013, swe2014, swe2015, swe2016\n", + "])\n", + "swe_ic = ee.ImageCollection.fromImages(gldas_swe_list)\n", + "\n", + "\n", + "def func_oyl(img):\n", + " date = ee.Date.fromYMD(img.get('year'), 1, 1)\n", + " return img.select('SWE_inst').multiply(kgm2_to_cm).rename(\n", + " 'SWEa').set('system:time_start', date)\n", + "\n", + "swe_ic_ts = swe_ic.map(func_oyl)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Make plot of SWEa for Basin Boundary\n", + "SWEaChart = ui.Chart.image.series({\n", + " 'imageCollection': swe_ic_ts.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Snow Water Equivalent anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'SWEa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(SWEaChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Extract geometry to convert time series of anomalies in km3 to cm\n", + "area_km2 = basin.geometry().area().divide(1000 * 1000)\n", + "km_2_cm = 100000\n", + "\n", + "# Convert csv to image collection\n", + "res_list = res_table.toList(res_table.size())\n", + "\n", + "def func_wfd(ft):\n", + " return ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), 1, 1)\n", + "\n", + "yrs = res_list.map(func_wfd)\n", + "\n", + "\n", + "\n", + "\n", + "def func_awn(ft):\n", + " return ee.Image.constant(ee.Feature(ft).get('Anom_km3'))\n", + "\n", + "SWanoms = res_list.map(func_awn)\n", + "\n", + "\n", + "\n", + "sw_ic_ts = ee.ImageCollection.fromImages(\n", + " res_list.map(\n", + " def function(ft):\n", + " date = ee.Date.fromYMD(ee.Feature(ft).get('YEAR'),\n", + " 1, 1)\n", + " return ee.Image.constant(ee.Feature(ft).get(\n", + " 'Anom_km3')).divide(area_km2).multiply(\n", + " km_2_cm).rename('SWa').set(\n", + " 'system:time_start', date)\n", + "\n", + " )\n", + ")\n", + "\n", + "# Create a time series of Surface Water Anomalies\n", + "SWaChart = ui.Chart.image.series({\n", + " 'imageCollection': sw_ic_ts.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Surface Water anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'SWa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(SWaChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21e Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21e Checkpoint.js new file mode 100644 index 0000000..39e48d8 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21e Checkpoint.js @@ -0,0 +1,326 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var res_table = ee.FeatureCollection("projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3"), + sm2003 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2003"), + sm2004 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2004"), + sm2005 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2005"), + sm2006 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2006"), + sm2007 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2007"), + sm2008 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2008"), + sm2009 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2009"), + sm2010 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2010"), + sm2011 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2011"), + sm2012 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2012"), + sm2013 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2013"), + sm2014 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2014"), + sm2015 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2015"), + sm2016 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2016"), + swe2003 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2003"), + swe2004 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2004"), + swe2005 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2005"), + swe2006 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2006"), + swe2007 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2007"), + swe2008 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2008"), + swe2009 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2009"), + swe2010 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2010"), + swe2011 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2011"), + swe2012 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2012"), + swe2013 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2013"), + swe2014 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2014"), + swe2015 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2015"), + swe2016 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2016"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.1 Groundwater Monitoring with GRACE +// Checkpoint: A21e +// Authors: A.J. Purdy, J.S. Famiglietti +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ** Part 1 ** + +// Import Basins +var basins = ee.FeatureCollection('USGS/WBD/2017/HUC04'); + +// Extract the 3 HUC 04 basins for the Central Valley. +var codes = ['1802', '1803', '1804']; +var basin = basins.filter(ee.Filter.inList('huc4', codes)); + +// Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6); +Map.addLayer(basin, { + color: 'green' +}, 'Central Valley Basins', true, 0.5); + +var res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index'); +var res_cv = res.filterBounds(basin); +Map.addLayer(res_cv, { + color: 'blue' +}, 'Reservoirs'); + +// Import GRACE groundwater. +var GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI'); +// Get Liquid Water Equivalent thickness. +var basinTWSa = GRACE.select('lwe_thickness'); + +// Make plot of TWSa for Basin Boundary +var TWSaChart = ui.Chart.image.series({ + imageCollection: basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + }) + .setOptions({ + title: 'TWSa', + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'TWSa (cm)' + }, + lineWidth: 1, + }); +print(TWSaChart); + +// Set start and end years to annualize the data. +var yrStart = 2003; +var yrEnd = 2016; +var years = ee.List.sequence(yrStart, yrEnd); +var GRACE_yr = ee.ImageCollection.fromImages(years.map(function(y) { + var date = ee.Date.fromYMD(y, 1, 1); + return basinTWSa.filter(ee.Filter.calendarRange(y, y, + 'year')) + .mean() + .set('system:time_start', date) + .rename('TWSa'); +}).flatten()); + +// Make plot of annualized TWSa for Basin Boundary. +var TWSaChart = ui.Chart.image.series({ + imageCollection: GRACE_yr.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }).setChartType('ScatterChart') + .setOptions({ + title: 'Annualized Total Water Storage anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'TWSa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(TWSaChart); + +// Compute Trend for each pixel to map regions of most change. + +var addVariables = function(image) { + // Compute time in fractional years. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('2003-01-01'), 'year'); + // Return the image with the added bands. + return image + // Add a time band. + .addBands(ee.Image(years).rename('t').float()) + // Add a constant band. + .addBands(ee.Image.constant(1)); +}; + +var cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables); +print(cvTWSa); + +// List of the independent variable names +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('TWSa'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = cvTWSa.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image. +var coefficients = trend.select('coefficients') + .arrayProject([0]) + .arrayFlatten([independents]); + +// Create a layer of the TWSa slope to add to the map. +var slope = coefficients.select('t'); +// Set visualization parameters to represent positive (blue) +// & negative (red) trends. +var slopeParams = { + min: -3.5, + max: 3.5, + palette: ['red', 'white', 'blue'] +}; +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', true, + 0.75); + +// ** Part 2 ** + +// ** Section 3 ** + +// 3.1 Load GLDAS Soil Moisture images from an Asset to an ImageCollection. + +var gldas_sm_list = ee.List([sm2003, sm2004, sm2005, sm2006, sm2007, + sm2008, sm2009, sm2010, sm2011, sm2012, sm2013, sm2014, + sm2015, sm2016 +]); +var sm_ic = ee.ImageCollection.fromImages(gldas_sm_list); + +var kgm2_to_cm = 0.10; +var sm_ic_ts = sm_ic.map(function(img) { + var date = ee.Date.fromYMD(img.get('year'), 1, 1); + return img.select('RootMoist_inst').multiply(kgm2_to_cm) + .rename('SMa').set('system:time_start', date); +}); + +var kgm2_to_cm = 0.10; +var sm_ic_ts = sm_ic.map(function(img) { + var date = ee.Date.fromYMD(img.get('year'), 1, 1); + return img.select('RootMoist_inst').multiply(kgm2_to_cm) + .rename('SMa').set('system:time_start', date); +}); + +// Make plot of SMa for Basin Boundary +var SMaChart = ui.Chart.image.series({ + imageCollection: sm_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Soil Moisture anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'SMa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(SMaChart); + +var gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]); +var swe_ic = ee.ImageCollection.fromImages(gldas_swe_list); + +// 3.2. Load GLDAS Snow Water Equivalent Images from an Asset to an Image Collection + +var gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]); +var swe_ic = ee.ImageCollection.fromImages(gldas_swe_list); + +var swe_ic_ts = swe_ic.map(function(img) { + var date = ee.Date.fromYMD(img.get('year'), 1, 1); + return img.select('SWE_inst').multiply(kgm2_to_cm).rename( + 'SWEa').set('system:time_start', date); +}); + +// Make plot of SWEa for Basin Boundary +var SWEaChart = ui.Chart.image.series({ + imageCollection: swe_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Snow Water Equivalent anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'SWEa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(SWEaChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Extract geometry to convert time series of anomalies in km3 to cm +var area_km2 = basin.geometry().area().divide(1000 * 1000); +var km_2_cm = 100000; + +// Convert csv to image collection +var res_list = res_table.toList(res_table.size()); +var yrs = res_list.map(function(ft) { + return ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), 1, 1); +}); +var SWanoms = res_list.map(function(ft) { + return ee.Image.constant(ee.Feature(ft).get('Anom_km3')); +}); +var sw_ic_ts = ee.ImageCollection.fromImages( + res_list.map( + function(ft) { + var date = ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), + 1, 1); + return ee.Image.constant(ee.Feature(ft).get( + 'Anom_km3')).divide(area_km2).multiply( + km_2_cm).rename('SWa').set( + 'system:time_start', date); + } + ) +); + +// Create a time series of Surface Water Anomalies +var SWaChart = ui.Chart.image.series({ + imageCollection: sw_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Surface Water anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'SWa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(SWaChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21e Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21e Checkpoint.py new file mode 100644 index 0000000..36eac5e --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21e Checkpoint.py @@ -0,0 +1,371 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +res_table = ee.FeatureCollection("projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3"), + sm2003 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2003"), + sm2004 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2004"), + sm2005 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2005"), + sm2006 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2006"), + sm2007 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2007"), + sm2008 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2008"), + sm2009 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2009"), + sm2010 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2010"), + sm2011 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2011"), + sm2012 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2012"), + sm2013 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2013"), + sm2014 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2014"), + sm2015 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2015"), + sm2016 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2016"), + swe2003 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2003"), + swe2004 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2004"), + swe2005 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2005"), + swe2006 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2006"), + swe2007 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2007"), + swe2008 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2008"), + swe2009 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2009"), + swe2010 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2010"), + swe2011 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2011"), + swe2012 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2012"), + swe2013 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2013"), + swe2014 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2014"), + swe2015 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2015"), + swe2016 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2016") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.1 Groundwater Monitoring with GRACE +# Checkpoint: A21e +# Authors: A.J. Purdy, J.S. Famiglietti +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# ** Part 1 ** + +# Import Basins +basins = ee.FeatureCollection('USGS/WBD/2017/HUC04') + +# Extract the 3 HUC 04 basins for the Central Valley. +codes = ['1802', '1803', '1804'] +basin = basins.filter(ee.Filter.inList('huc4', codes)) + +# Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6) +Map.addLayer(basin, { + 'color': 'green' +}, 'Central Valley Basins', True, 0.5) + +res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index') +res_cv = res.filterBounds(basin) +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs') + +# Import GRACE groundwater. +GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI') +# Get Liquid Water Equivalent thickness. +basinTWSa = GRACE.select('lwe_thickness') + +# Make plot of TWSa for Basin Boundary +TWSaChart = ui.Chart.image.series({ + 'imageCollection': basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + }) \ + .setOptions({ + 'title': 'TWSa', + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'TWSa (cm)' + }, + 'lineWidth': 1, + }) +print(TWSaChart) + +# Set start and end years to annualize the data. +yrStart = 2003 +yrEnd = 2016 +years = ee.List.sequence(yrStart, yrEnd) + +def func_lnn(y): + date = ee.Date.fromYMD(y, 1, 1) + return basinTWSa.filter(ee.Filter.calendarRange(y, y, + 'year')) \ + .mean() \ + .set('system:time_start', date) \ + .rename('TWSa') + +GRACE_yr = ee.ImageCollection.fromImages(years.map(func_lnn +).flatten()) + + + + + + +).flatten()) + +# Make plot of annualized TWSa for Basin Boundary. +TWSaChart = ui.Chart.image.series({ + 'imageCollection': GRACE_yr.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }).setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Annualized Total Water Storage anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'TWSa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(TWSaChart) + +# Compute Trend for each pixel to map regions of most change. + +def addVariables(image): + # Compute time in fractional years. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('2003-01-01'), 'year') + # Return the image with the added bands. + return image \ + .addBands(ee.Image(years).rename('t').float()) \ + .addBands(ee.Image.constant(1)) + + +cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables) +print(cvTWSa) + +# List of the independent variable names +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('TWSa') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 band called coefficients (columns are for dependent variables). +trend = cvTWSa.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Flatten the coefficients into a 2-band image. +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Create a layer of the TWSa slope to add to the map. +slope = coefficients.select('t') +# Set visualization parameters to represent positive (blue) +# & negative (red) trends. +slopeParams = { + 'min': -3.5, + 'max': 3.5, + 'palette': ['red', 'white', 'blue'] +} +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', True, + 0.75) + +# ** Part 2 ** + +# ** Section 3 ** + +# 3.1 Load GLDAS Soil Moisture images from an Asset to an ImageCollection. + +gldas_sm_list = ee.List([sm2003, sm2004, sm2005, sm2006, sm2007, + sm2008, sm2009, sm2010, sm2011, sm2012, sm2013, sm2014, + sm2015, sm2016 +]) +sm_ic = ee.ImageCollection.fromImages(gldas_sm_list) + +kgm2_to_cm = 0.10 + +def func_kmm(img): + date = ee.Date.fromYMD(img.get('year'), 1, 1) + return img.select('RootMoist_inst').multiply(kgm2_to_cm) \ + .rename('SMa').set('system:time_start', date) + +sm_ic_ts = sm_ic.map(func_kmm) + + + + + + +kgm2_to_cm = 0.10 + +def func_zvs(img): + date = ee.Date.fromYMD(img.get('year'), 1, 1) + return img.select('RootMoist_inst').multiply(kgm2_to_cm) \ + .rename('SMa').set('system:time_start', date) + +sm_ic_ts = sm_ic.map(func_zvs) + + + + + + +# Make plot of SMa for Basin Boundary +SMaChart = ui.Chart.image.series({ + 'imageCollection': sm_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Soil Moisture anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'SMa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(SMaChart) + +gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]) +swe_ic = ee.ImageCollection.fromImages(gldas_swe_list) + +# 3.2. Load GLDAS Snow Water Equivalent Images from an Asset to an Image Collection + +gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]) +swe_ic = ee.ImageCollection.fromImages(gldas_swe_list) + + +def func_oyl(img): + date = ee.Date.fromYMD(img.get('year'), 1, 1) + return img.select('SWE_inst').multiply(kgm2_to_cm).rename( + 'SWEa').set('system:time_start', date) + +swe_ic_ts = swe_ic.map(func_oyl) + + + + + + +# Make plot of SWEa for Basin Boundary +SWEaChart = ui.Chart.image.series({ + 'imageCollection': swe_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Snow Water Equivalent anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'SWEa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(SWEaChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Extract geometry to convert time series of anomalies in km3 to cm +area_km2 = basin.geometry().area().divide(1000 * 1000) +km_2_cm = 100000 + +# Convert csv to image collection +res_list = res_table.toList(res_table.size()) + +def func_wfd(ft): + return ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), 1, 1) + +yrs = res_list.map(func_wfd) + + + + +def func_awn(ft): + return ee.Image.constant(ee.Feature(ft).get('Anom_km3')) + +SWanoms = res_list.map(func_awn) + + + +sw_ic_ts = ee.ImageCollection.fromImages( + res_list.map( + def function(ft): + date = ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), + 1, 1) + return ee.Image.constant(ee.Feature(ft).get( + 'Anom_km3')).divide(area_km2).multiply( + km_2_cm).rename('SWa').set( + 'system:time_start', date) + + ) +) + +# Create a time series of Surface Water Anomalies +SWaChart = ui.Chart.image.series({ + 'imageCollection': sw_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Surface Water anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'SWa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(SWaChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21f Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21f Checkpoint.ipynb new file mode 100644 index 0000000..a74c554 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21f Checkpoint.ipynb @@ -0,0 +1,576 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "res_table = ee.FeatureCollection(\"projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3\"),\n", + " sm2003 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2003\"),\n", + " sm2004 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2004\"),\n", + " sm2005 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2005\"),\n", + " sm2006 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2006\"),\n", + " sm2007 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2007\"),\n", + " sm2008 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2008\"),\n", + " sm2009 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2009\"),\n", + " sm2010 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2010\"),\n", + " sm2011 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2011\"),\n", + " sm2012 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2012\"),\n", + " sm2013 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2013\"),\n", + " sm2014 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2014\"),\n", + " sm2015 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2015\"),\n", + " sm2016 = ee.Image(\"projects/gee-book/assets/A2-1/SM/sm2016\"),\n", + " swe2003 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2003\"),\n", + " swe2004 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2004\"),\n", + " swe2005 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2005\"),\n", + " swe2006 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2006\"),\n", + " swe2007 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2007\"),\n", + " swe2008 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2008\"),\n", + " swe2009 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2009\"),\n", + " swe2010 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2010\"),\n", + " swe2011 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2011\"),\n", + " swe2012 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2012\"),\n", + " swe2013 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2013\"),\n", + " swe2014 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2014\"),\n", + " swe2015 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2015\"),\n", + " swe2016 = ee.Image(\"projects/gee-book/assets/A2-1/SWE/swe2016\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.1 Groundwater Monitoring with GRACE\n", + "# Checkpoint: A21f\n", + "# Authors: A.J. Purdy, J.S. Famiglietti\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import Basins\n", + "basins = ee.FeatureCollection('USGS/WBD/2017/HUC04')\n", + "\n", + "# Extract the 3 HUC 04 basins for the Central Valley.\n", + "codes = ['1802', '1803', '1804']\n", + "basin = basins.filter(ee.Filter.inList('huc4', codes))\n", + "\n", + "# Add the basin to the map to show the extent of our analysis.\n", + "Map.centerObject(basin, 6)\n", + "Map.addLayer(basin, {\n", + " 'color': 'green'\n", + "}, 'Central Valley Basins', True, 0.5)\n", + "\n", + "# This table was generated using the index from the CDEC website\n", + "res = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-1/ca_reservoirs_index')\n", + "# Filter reservoir locations by the Central Valley geometry\n", + "res_cv = res.filterBounds(basin)\n", + "Map.addLayer(res_cv, {\n", + " 'color': 'blue'\n", + "}, 'Reservoirs')\n", + "\n", + "# Import GRACE groundwater.\n", + "GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI')\n", + "# Get Liquid Water Equivalent thickness.\n", + "basinTWSa = GRACE.select('lwe_thickness')\n", + "\n", + "# Make plot of TWSa for Basin Boundary\n", + "TWSaChart = ui.Chart.image.series({\n", + " 'imageCollection': basinTWSa.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " }) \\\n", + " .setOptions({\n", + " 'title': 'TWSa',\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'TWSa (cm)'\n", + " },\n", + " 'lineWidth': 1,\n", + " })\n", + "print(TWSaChart)\n", + "\n", + "# Set start and end years to annualize the data.\n", + "yrStart = 2003\n", + "yrEnd = 2016\n", + "years = ee.List.sequence(yrStart, yrEnd)\n", + "\n", + "def func_flv(y):\n", + " date = ee.Date.fromYMD(y, 1, 1)\n", + " return basinTWSa.filter(ee.Filter.calendarRange(y, y,\n", + " 'year')) \\\n", + " .mean() \\\n", + " .set('system:time_start', date) \\\n", + " .rename('TWSa')\n", + "\n", + "GRACE_yr = ee.ImageCollection.fromImages(years.map(func_flv\n", + ").flatten())\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten())\n", + "\n", + "# Make plot of annualized TWSa for Basin Boundary.\n", + "TWSaChart = ui.Chart.image.series({\n", + " 'imageCollection': GRACE_yr.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }).setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Total Annualized Water Storage anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'TWSa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(TWSaChart)\n", + "\n", + "# Compute Trend for each pixel to map regions of most change.\n", + "\n", + "def addVariables(image):\n", + " # Compute time in fractional years.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('2003-01-01'), 'year')\n", + " # Return the image with the added bands.\n", + " return image \\\n", + " .addBands(ee.Image(years).rename('t').float()) \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables)\n", + "print(cvTWSa)\n", + "\n", + "# List of the independent variable names\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('TWSa')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 band called coefficients (columns are for dependent variables).\n", + "trend = cvTWSa.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Flatten the coefficients into a 2-band image.\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Create a layer of the TWSa slope to add to the map.\n", + "slope = coefficients.select('t')\n", + "# Set visualization parameters to represent positive (blue)\n", + "# & negative (red) trends.\n", + "slopeParams = {\n", + " 'min': -3.5,\n", + " 'max': 3.5,\n", + " 'palette': ['red', 'white', 'blue']\n", + "}\n", + "Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', True,\n", + " 0.75)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# 3.1 Load GLDAS Soil Moisture images from an Asset to an ImageCollection.\n", + "\n", + "gldas_sm_list = ee.List([sm2003, sm2004, sm2005, sm2006, sm2007,\n", + " sm2008, sm2009, sm2010, sm2011, sm2012, sm2013, sm2014,\n", + " sm2015, sm2016\n", + "])\n", + "sm_ic = ee.ImageCollection.fromImages(gldas_sm_list)\n", + "\n", + "kgm2_to_cm = 0.10\n", + "\n", + "def func_mpn(img):\n", + " date = ee.Date.fromYMD(img.get('year'), 1, 1)\n", + " return img.select('RootMoist_inst').multiply(kgm2_to_cm) \\\n", + " .rename('SMa').set('system:time_start', date)\n", + "\n", + "sm_ic_ts = sm_ic.map(func_mpn)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "kgm2_to_cm = 0.10\n", + "\n", + "def func_vsv(img):\n", + " date = ee.Date.fromYMD(img.get('year'), 1, 1)\n", + " return img.select('RootMoist_inst').multiply(kgm2_to_cm) \\\n", + " .rename('SMa').set('system:time_start', date)\n", + "\n", + "sm_ic_ts = sm_ic.map(func_vsv)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Make plot of SMa for Basin Boundary\n", + "SMaChart = ui.Chart.image.series({\n", + " 'imageCollection': sm_ic_ts.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Soil Moisture anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'SMa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(SMaChart)\n", + "\n", + "gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006,\n", + " swe2007, swe2008, swe2009, swe2010, swe2011, swe2012,\n", + " swe2013, swe2014, swe2015, swe2016\n", + "])\n", + "swe_ic = ee.ImageCollection.fromImages(gldas_swe_list)\n", + "\n", + "# 3.2. Load GLDAS Snow Water Equivalent Images from an Asset to an Image Collection\n", + "\n", + "gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006,\n", + " swe2007, swe2008, swe2009, swe2010, swe2011, swe2012,\n", + " swe2013, swe2014, swe2015, swe2016\n", + "])\n", + "swe_ic = ee.ImageCollection.fromImages(gldas_swe_list)\n", + "\n", + "\n", + "def func_qqm(img):\n", + " date = ee.Date.fromYMD(img.get('year'), 1, 1)\n", + " return img.select('SWE_inst').multiply(kgm2_to_cm).rename(\n", + " 'SWEa').set('system:time_start', date)\n", + "\n", + "swe_ic_ts = swe_ic.map(func_qqm)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Make plot of SWEa for Basin Boundary\n", + "SWEaChart = ui.Chart.image.series({\n", + " 'imageCollection': swe_ic_ts.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Snow Water Equivalent anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'SWEa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(SWEaChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Extract geometry to convert time series of anomalies in km3 to cm\n", + "area_km2 = basin.geometry().area().divide(1000 * 1000)\n", + "km_2_cm = 100000\n", + "\n", + "# Convert csv to image collection\n", + "res_list = res_table.toList(res_table.size())\n", + "\n", + "def func_lev(ft):\n", + " return ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), 1, 1)\n", + "\n", + "yrs = res_list.map(func_lev)\n", + "\n", + "\n", + "\n", + "\n", + "def func_kaz(ft):\n", + " return ee.Image.constant(ee.Feature(ft).get('Anom_km3'))\n", + "\n", + "SWanoms = res_list.map(func_kaz)\n", + "\n", + "\n", + "\n", + "sw_ic_ts = ee.ImageCollection.fromImages(\n", + " res_list.map(\n", + " def function(ft):\n", + " date = ee.Date.fromYMD(ee.Feature(ft).get('YEAR'),\n", + " 1, 1)\n", + " return ee.Image.constant(ee.Feature(ft).get(\n", + " 'Anom_km3')).divide(area_km2).multiply(\n", + " km_2_cm).rename('SWa').set(\n", + " 'system:time_start', date)\n", + "\n", + " )\n", + ")\n", + "\n", + "# Create a time series of Surface Water Anomalies\n", + "SWaChart = ui.Chart.image.series({\n", + " 'imageCollection': sw_ic_ts.filter(ee.Filter.date(\n", + " '2003-01-01', '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Surface Water anomalies',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'SWa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(SWaChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Combine GLDAS & GRACE Data to compute change in human accessible water\n", + "filter = ee.Filter.equals({\n", + " 'leftField': 'system:time_start',\n", + " 'rightField': 'system:time_start'\n", + "})\n", + "# Create the join.\n", + "joindata = ee.Join.inner()\n", + "# Join GLDAS data\n", + "firstJoin = ee.ImageCollection(joindata.apply(swe_ic_ts, sm_ic_ts,\n", + " filter))\n", + "\n", + "def func_kat(feature):\n", + " return ee.Image.cat(feature.get('primary'), feature.get(\n", + " 'secondary'))\n", + "\n", + "join_1 = firstJoin.map(func_kat)\n", + "\n", + "\n", + "\n", + "\n", + "print('Joined', join_1)\n", + "\n", + "# Repeat to append Reservoir Data now\n", + "secondJoin = ee.ImageCollection(joindata.apply(join_1, sw_ic_ts,\n", + " filter))\n", + "\n", + "def func_yoo(feature):\n", + " return ee.Image.cat(feature.get('primary'), feature.get(\n", + " 'secondary'))\n", + "\n", + "res_GLDAS = secondJoin.map(func_yoo)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Repeat to append GRACE now\n", + "thirdJoin = ee.ImageCollection(joindata.apply(res_GLDAS, GRACE_yr,\n", + " filter))\n", + "\n", + "def func_xjb(feature):\n", + " return ee.Image.cat(feature.get('primary'), feature.get(\n", + " 'secondary'))\n", + "\n", + "GRACE_res_GLDAS = thirdJoin.map(func_xjb)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Compute groundwater storage anomalies\n", + "\n", + "def func_laz(img):\n", + " date = ee.Date.fromYMD(img.get('year'), 1, 1)\n", + " return img.expression(\n", + " 'TWSa - SWa - SMa - SWEa', {\n", + " 'TWSa': img.select('TWSa'),\n", + " 'SMa': img.select('SMa'),\n", + " 'SWa': img.select('SWa'),\n", + " 'SWEa': img.select('SWEa')\n", + " }).rename('GWa').copyProperties(img, [\n", + " 'system:time_start'\n", + " ])\n", + "\n", + "GWa = ee.ImageCollection(GRACE_res_GLDAS.map(func_laz\n", + "))\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "))\n", + "print('GWa', GWa)\n", + "\n", + "# Chart Results\n", + "GWaChart = ui.Chart.image.series({\n", + " 'imageCollection': GWa.filter(ee.Filter.date('2003-01-01',\n", + " '2016-12-31')),\n", + " 'region': basin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 25000\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Changes in Groundwater Storage',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'hAxis': {\n", + " format: 'MM-yyyy'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'GWa (cm)'\n", + " },\n", + " 'lineWidth': 2,\n", + " 'pointSize': 2\n", + " })\n", + "print(GWaChart)\n", + "\n", + "# Now look at the values from the start of 2012 to the end of 2016 drought.\n", + "# 2012 -3.874 cm --> 2016 -16.95 cm\n", + "# This is a ~13 cm / 100000 (cm/km) * Area 155407 km2 =\n", + "loss_km3 = ee.Number(-3.874).subtract(-16.95).divide(km_2_cm) \\\n", + " .multiply(area_km2)\n", + "print('During the 2012-2016 drought, CA lost ', loss_km3,\n", + " 'km3 in groundwater')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21f Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21f Checkpoint.js new file mode 100644 index 0000000..3024b69 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21f Checkpoint.js @@ -0,0 +1,412 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var res_table = ee.FeatureCollection("projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3"), + sm2003 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2003"), + sm2004 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2004"), + sm2005 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2005"), + sm2006 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2006"), + sm2007 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2007"), + sm2008 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2008"), + sm2009 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2009"), + sm2010 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2010"), + sm2011 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2011"), + sm2012 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2012"), + sm2013 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2013"), + sm2014 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2014"), + sm2015 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2015"), + sm2016 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2016"), + swe2003 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2003"), + swe2004 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2004"), + swe2005 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2005"), + swe2006 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2006"), + swe2007 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2007"), + swe2008 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2008"), + swe2009 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2009"), + swe2010 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2010"), + swe2011 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2011"), + swe2012 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2012"), + swe2013 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2013"), + swe2014 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2014"), + swe2015 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2015"), + swe2016 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2016"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.1 Groundwater Monitoring with GRACE +// Checkpoint: A21f +// Authors: A.J. Purdy, J.S. Famiglietti +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import Basins +var basins = ee.FeatureCollection('USGS/WBD/2017/HUC04'); + +// Extract the 3 HUC 04 basins for the Central Valley. +var codes = ['1802', '1803', '1804']; +var basin = basins.filter(ee.Filter.inList('huc4', codes)); + +// Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6); +Map.addLayer(basin, { + color: 'green' +}, 'Central Valley Basins', true, 0.5); + +// This table was generated using the index from the CDEC website +var res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index'); +// Filter reservoir locations by the Central Valley geometry +var res_cv = res.filterBounds(basin); +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs'); + +// Import GRACE groundwater. +var GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI'); +// Get Liquid Water Equivalent thickness. +var basinTWSa = GRACE.select('lwe_thickness'); + +// Make plot of TWSa for Basin Boundary +var TWSaChart = ui.Chart.image.series({ + imageCollection: basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + }) + .setOptions({ + title: 'TWSa', + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'TWSa (cm)' + }, + lineWidth: 1, + }); +print(TWSaChart); + +// Set start and end years to annualize the data. +var yrStart = 2003; +var yrEnd = 2016; +var years = ee.List.sequence(yrStart, yrEnd); +var GRACE_yr = ee.ImageCollection.fromImages(years.map(function(y) { + var date = ee.Date.fromYMD(y, 1, 1); + return basinTWSa.filter(ee.Filter.calendarRange(y, y, + 'year')) + .mean() + .set('system:time_start', date) + .rename('TWSa'); +}).flatten()); + +// Make plot of annualized TWSa for Basin Boundary. +var TWSaChart = ui.Chart.image.series({ + imageCollection: GRACE_yr.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }).setChartType('ScatterChart') + .setOptions({ + title: 'Total Annualized Water Storage anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'TWSa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(TWSaChart); + +// Compute Trend for each pixel to map regions of most change. + +var addVariables = function(image) { + // Compute time in fractional years. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('2003-01-01'), 'year'); + // Return the image with the added bands. + return image + // Add a time band. + .addBands(ee.Image(years).rename('t').float()) + // Add a constant band. + .addBands(ee.Image.constant(1)); +}; + +var cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables); +print(cvTWSa); + +// List of the independent variable names +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('TWSa'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = cvTWSa.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image. +var coefficients = trend.select('coefficients') + .arrayProject([0]) + .arrayFlatten([independents]); + +// Create a layer of the TWSa slope to add to the map. +var slope = coefficients.select('t'); +// Set visualization parameters to represent positive (blue) +// & negative (red) trends. +var slopeParams = { + min: -3.5, + max: 3.5, + palette: ['red', 'white', 'blue'] +}; +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', true, + 0.75); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// 3.1 Load GLDAS Soil Moisture images from an Asset to an ImageCollection. + +var gldas_sm_list = ee.List([sm2003, sm2004, sm2005, sm2006, sm2007, + sm2008, sm2009, sm2010, sm2011, sm2012, sm2013, sm2014, + sm2015, sm2016 +]); +var sm_ic = ee.ImageCollection.fromImages(gldas_sm_list); + +var kgm2_to_cm = 0.10; +var sm_ic_ts = sm_ic.map(function(img) { + var date = ee.Date.fromYMD(img.get('year'), 1, 1); + return img.select('RootMoist_inst').multiply(kgm2_to_cm) + .rename('SMa').set('system:time_start', date); +}); + +var kgm2_to_cm = 0.10; +var sm_ic_ts = sm_ic.map(function(img) { + var date = ee.Date.fromYMD(img.get('year'), 1, 1); + return img.select('RootMoist_inst').multiply(kgm2_to_cm) + .rename('SMa').set('system:time_start', date); +}); + +// Make plot of SMa for Basin Boundary +var SMaChart = ui.Chart.image.series({ + imageCollection: sm_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Soil Moisture anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'SMa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(SMaChart); + +var gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]); +var swe_ic = ee.ImageCollection.fromImages(gldas_swe_list); + +// 3.2. Load GLDAS Snow Water Equivalent Images from an Asset to an Image Collection + +var gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]); +var swe_ic = ee.ImageCollection.fromImages(gldas_swe_list); + +var swe_ic_ts = swe_ic.map(function(img) { + var date = ee.Date.fromYMD(img.get('year'), 1, 1); + return img.select('SWE_inst').multiply(kgm2_to_cm).rename( + 'SWEa').set('system:time_start', date); +}); + +// Make plot of SWEa for Basin Boundary +var SWEaChart = ui.Chart.image.series({ + imageCollection: swe_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Snow Water Equivalent anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'SWEa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(SWEaChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Extract geometry to convert time series of anomalies in km3 to cm +var area_km2 = basin.geometry().area().divide(1000 * 1000); +var km_2_cm = 100000; + +// Convert csv to image collection +var res_list = res_table.toList(res_table.size()); +var yrs = res_list.map(function(ft) { + return ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), 1, 1); +}); +var SWanoms = res_list.map(function(ft) { + return ee.Image.constant(ee.Feature(ft).get('Anom_km3')); +}); +var sw_ic_ts = ee.ImageCollection.fromImages( + res_list.map( + function(ft) { + var date = ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), + 1, 1); + return ee.Image.constant(ee.Feature(ft).get( + 'Anom_km3')).divide(area_km2).multiply( + km_2_cm).rename('SWa').set( + 'system:time_start', date); + } + ) +); + +// Create a time series of Surface Water Anomalies +var SWaChart = ui.Chart.image.series({ + imageCollection: sw_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Surface Water anomalies', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'SWa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(SWaChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Combine GLDAS & GRACE Data to compute change in human accessible water +var filter = ee.Filter.equals({ + leftField: 'system:time_start', + rightField: 'system:time_start' +}); +// Create the join. +var joindata = ee.Join.inner(); +// Join GLDAS data +var firstJoin = ee.ImageCollection(joindata.apply(swe_ic_ts, sm_ic_ts, + filter)); +var join_1 = firstJoin.map(function(feature) { + return ee.Image.cat(feature.get('primary'), feature.get( + 'secondary')); +}); +print('Joined', join_1); + +// Repeat to append Reservoir Data now +var secondJoin = ee.ImageCollection(joindata.apply(join_1, sw_ic_ts, + filter)); +var res_GLDAS = secondJoin.map(function(feature) { + return ee.Image.cat(feature.get('primary'), feature.get( + 'secondary')); +}); + +// Repeat to append GRACE now +var thirdJoin = ee.ImageCollection(joindata.apply(res_GLDAS, GRACE_yr, + filter)); +var GRACE_res_GLDAS = thirdJoin.map(function(feature) { + return ee.Image.cat(feature.get('primary'), feature.get( + 'secondary')); +}); + +// Compute groundwater storage anomalies +var GWa = ee.ImageCollection(GRACE_res_GLDAS.map(function(img) { + var date = ee.Date.fromYMD(img.get('year'), 1, 1); + return img.expression( + 'TWSa - SWa - SMa - SWEa', { + 'TWSa': img.select('TWSa'), + 'SMa': img.select('SMa'), + 'SWa': img.select('SWa'), + 'SWEa': img.select('SWEa') + }).rename('GWa').copyProperties(img, [ + 'system:time_start' + ]); +})); +print('GWa', GWa); + +// Chart Results +var GWaChart = ui.Chart.image.series({ + imageCollection: GWa.filter(ee.Filter.date('2003-01-01', + '2016-12-31')), + region: basin, + reducer: ee.Reducer.mean(), + scale: 25000 + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Changes in Groundwater Storage', + trendlines: { + 0: { + color: 'CC0000' + } + }, + hAxis: { + format: 'MM-yyyy' + }, + vAxis: { + title: 'GWa (cm)' + }, + lineWidth: 2, + pointSize: 2 + }); +print(GWaChart); + +// Now look at the values from the start of 2012 to the end of 2016 drought. +// 2012 -3.874 cm --> 2016 -16.95 cm +// This is a ~13 cm / 100000 (cm/km) * Area 155407 km2 = +var loss_km3 = ee.Number(-3.874).subtract(-16.95).divide(km_2_cm) + .multiply(area_km2); +print('During the 2012-2016 drought, CA lost ', loss_km3, + 'km3 in groundwater'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21f Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21f Checkpoint.py new file mode 100644 index 0000000..90921b6 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21f Checkpoint.py @@ -0,0 +1,489 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +res_table = ee.FeatureCollection("projects/gee-book/assets/A2-1/SW/reservoir_anoms_km3"), + sm2003 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2003"), + sm2004 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2004"), + sm2005 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2005"), + sm2006 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2006"), + sm2007 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2007"), + sm2008 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2008"), + sm2009 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2009"), + sm2010 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2010"), + sm2011 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2011"), + sm2012 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2012"), + sm2013 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2013"), + sm2014 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2014"), + sm2015 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2015"), + sm2016 = ee.Image("projects/gee-book/assets/A2-1/SM/sm2016"), + swe2003 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2003"), + swe2004 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2004"), + swe2005 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2005"), + swe2006 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2006"), + swe2007 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2007"), + swe2008 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2008"), + swe2009 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2009"), + swe2010 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2010"), + swe2011 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2011"), + swe2012 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2012"), + swe2013 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2013"), + swe2014 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2014"), + swe2015 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2015"), + swe2016 = ee.Image("projects/gee-book/assets/A2-1/SWE/swe2016") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.1 Groundwater Monitoring with GRACE +# Checkpoint: A21f +# Authors: A.J. Purdy, J.S. Famiglietti +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import Basins +basins = ee.FeatureCollection('USGS/WBD/2017/HUC04') + +# Extract the 3 HUC 04 basins for the Central Valley. +codes = ['1802', '1803', '1804'] +basin = basins.filter(ee.Filter.inList('huc4', codes)) + +# Add the basin to the map to show the extent of our analysis. +Map.centerObject(basin, 6) +Map.addLayer(basin, { + 'color': 'green' +}, 'Central Valley Basins', True, 0.5) + +# This table was generated using the index from the CDEC website +res = ee.FeatureCollection( + 'projects/gee-book/assets/A2-1/ca_reservoirs_index') +# Filter reservoir locations by the Central Valley geometry +res_cv = res.filterBounds(basin) +Map.addLayer(res_cv, { + 'color': 'blue' +}, 'Reservoirs') + +# Import GRACE groundwater. +GRACE = ee.ImageCollection('NASA/GRACE/MASS_GRIDS/MASCON_CRI') +# Get Liquid Water Equivalent thickness. +basinTWSa = GRACE.select('lwe_thickness') + +# Make plot of TWSa for Basin Boundary +TWSaChart = ui.Chart.image.series({ + 'imageCollection': basinTWSa.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + }) \ + .setOptions({ + 'title': 'TWSa', + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'TWSa (cm)' + }, + 'lineWidth': 1, + }) +print(TWSaChart) + +# Set start and end years to annualize the data. +yrStart = 2003 +yrEnd = 2016 +years = ee.List.sequence(yrStart, yrEnd) + +def func_flv(y): + date = ee.Date.fromYMD(y, 1, 1) + return basinTWSa.filter(ee.Filter.calendarRange(y, y, + 'year')) \ + .mean() \ + .set('system:time_start', date) \ + .rename('TWSa') + +GRACE_yr = ee.ImageCollection.fromImages(years.map(func_flv +).flatten()) + + + + + + +).flatten()) + +# Make plot of annualized TWSa for Basin Boundary. +TWSaChart = ui.Chart.image.series({ + 'imageCollection': GRACE_yr.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }).setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Total Annualized Water Storage anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'TWSa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(TWSaChart) + +# Compute Trend for each pixel to map regions of most change. + +def addVariables(image): + # Compute time in fractional years. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('2003-01-01'), 'year') + # Return the image with the added bands. + return image \ + .addBands(ee.Image(years).rename('t').float()) \ + .addBands(ee.Image.constant(1)) + + +cvTWSa = GRACE_yr.filterBounds(basin).map(addVariables) +print(cvTWSa) + +# List of the independent variable names +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('TWSa') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 band called coefficients (columns are for dependent variables). +trend = cvTWSa.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Flatten the coefficients into a 2-band image. +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Create a layer of the TWSa slope to add to the map. +slope = coefficients.select('t') +# Set visualization parameters to represent positive (blue) +# & negative (red) trends. +slopeParams = { + 'min': -3.5, + 'max': 3.5, + 'palette': ['red', 'white', 'blue'] +} +Map.addLayer(slope.clip(basin), slopeParams, 'TWSa Annualized Trend', True, + 0.75) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# 3.1 Load GLDAS Soil Moisture images from an Asset to an ImageCollection. + +gldas_sm_list = ee.List([sm2003, sm2004, sm2005, sm2006, sm2007, + sm2008, sm2009, sm2010, sm2011, sm2012, sm2013, sm2014, + sm2015, sm2016 +]) +sm_ic = ee.ImageCollection.fromImages(gldas_sm_list) + +kgm2_to_cm = 0.10 + +def func_mpn(img): + date = ee.Date.fromYMD(img.get('year'), 1, 1) + return img.select('RootMoist_inst').multiply(kgm2_to_cm) \ + .rename('SMa').set('system:time_start', date) + +sm_ic_ts = sm_ic.map(func_mpn) + + + + + + +kgm2_to_cm = 0.10 + +def func_vsv(img): + date = ee.Date.fromYMD(img.get('year'), 1, 1) + return img.select('RootMoist_inst').multiply(kgm2_to_cm) \ + .rename('SMa').set('system:time_start', date) + +sm_ic_ts = sm_ic.map(func_vsv) + + + + + + +# Make plot of SMa for Basin Boundary +SMaChart = ui.Chart.image.series({ + 'imageCollection': sm_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Soil Moisture anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'SMa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(SMaChart) + +gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]) +swe_ic = ee.ImageCollection.fromImages(gldas_swe_list) + +# 3.2. Load GLDAS Snow Water Equivalent Images from an Asset to an Image Collection + +gldas_swe_list = ee.List([swe2003, swe2004, swe2005, swe2006, + swe2007, swe2008, swe2009, swe2010, swe2011, swe2012, + swe2013, swe2014, swe2015, swe2016 +]) +swe_ic = ee.ImageCollection.fromImages(gldas_swe_list) + + +def func_qqm(img): + date = ee.Date.fromYMD(img.get('year'), 1, 1) + return img.select('SWE_inst').multiply(kgm2_to_cm).rename( + 'SWEa').set('system:time_start', date) + +swe_ic_ts = swe_ic.map(func_qqm) + + + + + + +# Make plot of SWEa for Basin Boundary +SWEaChart = ui.Chart.image.series({ + 'imageCollection': swe_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Snow Water Equivalent anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'SWEa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(SWEaChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Extract geometry to convert time series of anomalies in km3 to cm +area_km2 = basin.geometry().area().divide(1000 * 1000) +km_2_cm = 100000 + +# Convert csv to image collection +res_list = res_table.toList(res_table.size()) + +def func_lev(ft): + return ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), 1, 1) + +yrs = res_list.map(func_lev) + + + + +def func_kaz(ft): + return ee.Image.constant(ee.Feature(ft).get('Anom_km3')) + +SWanoms = res_list.map(func_kaz) + + + +sw_ic_ts = ee.ImageCollection.fromImages( + res_list.map( + def function(ft): + date = ee.Date.fromYMD(ee.Feature(ft).get('YEAR'), + 1, 1) + return ee.Image.constant(ee.Feature(ft).get( + 'Anom_km3')).divide(area_km2).multiply( + km_2_cm).rename('SWa').set( + 'system:time_start', date) + + ) +) + +# Create a time series of Surface Water Anomalies +SWaChart = ui.Chart.image.series({ + 'imageCollection': sw_ic_ts.filter(ee.Filter.date( + '2003-01-01', '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Surface Water anomalies', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'SWa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(SWaChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Combine GLDAS & GRACE Data to compute change in human accessible water +filter = ee.Filter.equals({ + 'leftField': 'system:time_start', + 'rightField': 'system:time_start' +}) +# Create the join. +joindata = ee.Join.inner() +# Join GLDAS data +firstJoin = ee.ImageCollection(joindata.apply(swe_ic_ts, sm_ic_ts, + filter)) + +def func_kat(feature): + return ee.Image.cat(feature.get('primary'), feature.get( + 'secondary')) + +join_1 = firstJoin.map(func_kat) + + + + +print('Joined', join_1) + +# Repeat to append Reservoir Data now +secondJoin = ee.ImageCollection(joindata.apply(join_1, sw_ic_ts, + filter)) + +def func_yoo(feature): + return ee.Image.cat(feature.get('primary'), feature.get( + 'secondary')) + +res_GLDAS = secondJoin.map(func_yoo) + + + + + +# Repeat to append GRACE now +thirdJoin = ee.ImageCollection(joindata.apply(res_GLDAS, GRACE_yr, + filter)) + +def func_xjb(feature): + return ee.Image.cat(feature.get('primary'), feature.get( + 'secondary')) + +GRACE_res_GLDAS = thirdJoin.map(func_xjb) + + + + + +# Compute groundwater storage anomalies + +def func_laz(img): + date = ee.Date.fromYMD(img.get('year'), 1, 1) + return img.expression( + 'TWSa - SWa - SMa - SWEa', { + 'TWSa': img.select('TWSa'), + 'SMa': img.select('SMa'), + 'SWa': img.select('SWa'), + 'SWEa': img.select('SWEa') + }).rename('GWa').copyProperties(img, [ + 'system:time_start' + ]) + +GWa = ee.ImageCollection(GRACE_res_GLDAS.map(func_laz +)) + + + + + + + + + + +)) +print('GWa', GWa) + +# Chart Results +GWaChart = ui.Chart.image.series({ + 'imageCollection': GWa.filter(ee.Filter.date('2003-01-01', + '2016-12-31')), + 'region': basin, + 'reducer': ee.Reducer.mean(), + 'scale': 25000 + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Changes in Groundwater Storage', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'hAxis': { + format: 'MM-yyyy' + }, + 'vAxis': { + 'title': 'GWa (cm)' + }, + 'lineWidth': 2, + 'pointSize': 2 + }) +print(GWaChart) + +# Now look at the values from the start of 2012 to the end of 2016 drought. +# 2012 -3.874 cm --> 2016 -16.95 cm +# This is a ~13 cm / 100000 (cm/km) * Area 155407 km2 = +loss_km3 = ee.Number(-3.874).subtract(-16.95).divide(km_2_cm) \ + .multiply(area_km2) +print('During the 2012-2016 drought, CA lost ', loss_km3, + 'km3 in groundwater') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21s1 - Supplemental.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21s1 - Supplemental.ipynb new file mode 100644 index 0000000..f13ee2a --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21s1 - Supplemental.ipynb @@ -0,0 +1,152 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.1 Groundwater Monitoring with GRACE\n", + "# Section: Section 3 (A21s1 - Supplemental)\n", + "# Authors: A.J. Purdy, J.S. Famiglietti\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# The basins feature is being used to subset GLDAS geographically\n", + "# The first 7 lines are set for California.\n", + "# A user will need to adjust the basin to reflect another region\n", + "basins = ee.FeatureCollection('USGS/WBD/2017/HUC04')\n", + "# Extract the 3 HUC 04 basins for the Central Valley.\n", + "codes = ['1802', '1803', '1804']\n", + "basin = basins.filter(ee.Filter.inList('huc4', codes))\n", + "\n", + "# Set start / end year.\n", + "yrStart = 2003\n", + "yrEnd = 2016\n", + "years = ee.List.sequence(yrStart, yrEnd)\n", + "\n", + "# The varBand variable is set to evaluated Snow Water Equivalent.\n", + "# Need to adjust to export Soil Moisture (SM_inst)\n", + "varBand = 'SWE_inst'\n", + "\n", + "waterstorage = ee.ImageCollection('NASA/GLDAS/V021/NOAH/G025/T3H') \\\n", + " .select(varBand) \\\n", + " .filterDate({\n", + " 'start': ee.Date.fromYMD(yrStart, 1, 1),\n", + " 'end': ee.Date.fromYMD(yrEnd, 12, 1)\n", + " })\n", + "waterstorage_mean = waterstorage.select(varBand).mean()\n", + "print(waterstorage_mean)\n", + "\n", + "y = 2003\n", + "date = ee.Date.fromYMD(y, 1, 1)\n", + "\n", + "waterstorageIC = ee.Image(ee.ImageCollection(\n", + " 'NASA/GLDAS/V021/NOAH/G025/T3H') \\\n", + " .select(varBand) \\\n", + " .filter(ee.Filter.calendarRange(y, y, 'year')) \\\n", + " .mean())\n", + "print(waterstorageIC)\n", + "\n", + "waterstorage_out = ee.Image(waterstorageIC.subtract(\n", + " waterstorage_mean) \\\n", + " .set('year', y) \\\n", + " .set('system:time_start', date))\n", + "print(waterstorage_out)\n", + "\n", + "# Change the assetId & description below to reflect the variable being exported.\n", + "# These should be changed to reflect SM, SWE, Can etc.\n", + "\n", + "Export.image.toAsset({\n", + " 'image': waterstorage_out,\n", + " 'description': 'swe2003',\n", + " 'assetId': 'swe2003',\n", + " 'region': basin,\n", + " 'scale': 10000,\n", + " 'maxPixels': 1e13\n", + "})" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21s1 - Supplemental.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21s1 - Supplemental.js new file mode 100644 index 0000000..8c46c87 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21s1 - Supplemental.js @@ -0,0 +1,59 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.1 Groundwater Monitoring with GRACE +// Section: Section 3 (A21s1 - Supplemental) +// Authors: A.J. Purdy, J.S. Famiglietti +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// The basins feature is being used to subset GLDAS geographically +// The first 7 lines are set for California. +// A user will need to adjust the basin to reflect another region +var basins = ee.FeatureCollection('USGS/WBD/2017/HUC04'); +// Extract the 3 HUC 04 basins for the Central Valley. +var codes = ['1802', '1803', '1804']; +var basin = basins.filter(ee.Filter.inList('huc4', codes)); + +// Set start / end year. +var yrStart = 2003; +var yrEnd = 2016; +var years = ee.List.sequence(yrStart, yrEnd); + +// The varBand variable is set to evaluated Snow Water Equivalent. +// Need to adjust to export Soil Moisture (SM_inst) +var varBand = 'SWE_inst'; + +var waterstorage = ee.ImageCollection('NASA/GLDAS/V021/NOAH/G025/T3H') + .select(varBand) + .filterDate({ + start: ee.Date.fromYMD(yrStart, 1, 1), + end: ee.Date.fromYMD(yrEnd, 12, 1) + }); +var waterstorage_mean = waterstorage.select(varBand).mean(); +print(waterstorage_mean); + +var y = 2003; +var date = ee.Date.fromYMD(y, 1, 1); + +var waterstorageIC = ee.Image(ee.ImageCollection( + 'NASA/GLDAS/V021/NOAH/G025/T3H') + .select(varBand) + .filter(ee.Filter.calendarRange(y, y, 'year')) + .mean()); +print(waterstorageIC); + +var waterstorage_out = ee.Image(waterstorageIC.subtract( + waterstorage_mean) + .set('year', y) + .set('system:time_start', date)); +print(waterstorage_out); + +// Change the assetId & description below to reflect the variable being exported. +// These should be changed to reflect SM, SWE, Can etc. + +Export.image.toAsset({ + image: waterstorage_out, + description: 'swe2003', + assetId: 'swe2003', + region: basin, + scale: 10000, + maxPixels: 1e13 +}); \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21s1 - Supplemental.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21s1 - Supplemental.py new file mode 100644 index 0000000..e0335c2 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.1 GRACE Groundwater/A21s1 - Supplemental.py @@ -0,0 +1,65 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.1 Groundwater Monitoring with GRACE +# Section: Section 3 (A21s1 - Supplemental) +# Authors: A.J. Purdy, J.S. Famiglietti +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# The basins feature is being used to subset GLDAS geographically +# The first 7 lines are set for California. +# A user will need to adjust the basin to reflect another region +basins = ee.FeatureCollection('USGS/WBD/2017/HUC04') +# Extract the 3 HUC 04 basins for the Central Valley. +codes = ['1802', '1803', '1804'] +basin = basins.filter(ee.Filter.inList('huc4', codes)) + +# Set start / end year. +yrStart = 2003 +yrEnd = 2016 +years = ee.List.sequence(yrStart, yrEnd) + +# The varBand variable is set to evaluated Snow Water Equivalent. +# Need to adjust to export Soil Moisture (SM_inst) +varBand = 'SWE_inst' + +waterstorage = ee.ImageCollection('NASA/GLDAS/V021/NOAH/G025/T3H') \ + .select(varBand) \ + .filterDate({ + 'start': ee.Date.fromYMD(yrStart, 1, 1), + 'end': ee.Date.fromYMD(yrEnd, 12, 1) + }) +waterstorage_mean = waterstorage.select(varBand).mean() +print(waterstorage_mean) + +y = 2003 +date = ee.Date.fromYMD(y, 1, 1) + +waterstorageIC = ee.Image(ee.ImageCollection( + 'NASA/GLDAS/V021/NOAH/G025/T3H') \ + .select(varBand) \ + .filter(ee.Filter.calendarRange(y, y, 'year')) \ + .mean()) +print(waterstorageIC) + +waterstorage_out = ee.Image(waterstorageIC.subtract( + waterstorage_mean) \ + .set('year', y) \ + .set('system:time_start', date)) +print(waterstorage_out) + +# Change the assetId & description below to reflect the variable being exported. +# These should be changed to reflect SM, SWE, Can etc. + +Export.image.toAsset({ + 'image': waterstorage_out, + 'description': 'swe2003', + 'assetId': 'swe2003', + 'region': basin, + 'scale': 10000, + 'maxPixels': 1e13 +}) +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22a Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22a Checkpoint.ipynb new file mode 100644 index 0000000..77f618f --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22a Checkpoint.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.2 Benthic Habitats\n", + "# Checkpoint: A22a\n", + "# Authors: Dimitris Poursanidis, Aur\u00e9lie C. Shapiro, Spyros Christofilakos\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1\n", + "# Import and display satellite image.\n", + "planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \\\n", + " .divide(10000)\n", + "\n", + "Map.centerObject(planet, 12)\n", + "visParams = {\n", + " 'bands': ['b3', 'b2', 'b1'],\n", + " 'min': 0.17,\n", + " 'max': 0.68,\n", + " 'gamma': 0.8\n", + "}\n", + "Map.addLayer({\n", + " 'eeObject': planet,\n", + " 'visParams': visParams,\n", + " 'name': 'planet initial',\n", + " 'shown': True\n", + "})\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22a Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22a Checkpoint.js new file mode 100644 index 0000000..0d7a6e4 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22a Checkpoint.js @@ -0,0 +1,28 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.2 Benthic Habitats +// Checkpoint: A22a +// Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1 +// Import and display satellite image. +var planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') + .divide(10000); + +Map.centerObject(planet, 12); +var visParams = { + bands: ['b3', 'b2', 'b1'], + min: 0.17, + max: 0.68, + gamma: 0.8 +}; +Map.addLayer({ + eeObject: planet, + visParams: visParams, + name: 'planet initial', + shown: true +}); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22a Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22a Checkpoint.py new file mode 100644 index 0000000..a12b4ca --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22a Checkpoint.py @@ -0,0 +1,34 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.2 Benthic Habitats +# Checkpoint: A22a +# Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1 +# Import and display satellite image. +planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \ + .divide(10000) + +Map.centerObject(planet, 12) +visParams = { + 'bands': ['b3', 'b2', 'b1'], + 'min': 0.17, + 'max': 0.68, + 'gamma': 0.8 +} +Map.addLayer({ + 'eeObject': planet, + 'visParams': visParams, + 'name': 'planet initial', + 'shown': True +}) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22b Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22b Checkpoint.ipynb new file mode 100644 index 0000000..b99b8f7 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22b Checkpoint.ipynb @@ -0,0 +1,221 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "DIVsand = ee.Geometry.MultiPolygon(\n", + " [[[[23.85533614379952, 35.525671008126785],\n", + " [23.85808272583077, 35.52511217612521],\n", + " [23.860142662354207, 35.53880243984323],\n", + " [23.85653777343819, 35.539500860050644]]],\n", + " [[[23.783753349610066, 35.54863600968416],\n", + " [23.801091148682332, 35.55114998568017],\n", + " [23.799546196289754, 35.55464148823767],\n", + " [23.782723381348347, 35.551289648702024]]]]),\n", + "land = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.813750501438804, 35.53087476744296],\n", + " [23.834178205296226, 35.52696311538223],\n", + " [23.81306385593099, 35.53269082679277],\n", + " [23.836753125950523, 35.52863956104383],\n", + " [23.81684040622396, 35.53310991157428],\n", + " [23.835208173557945, 35.53073506886724],\n", + " [23.820273633763023, 35.53422746028901],\n", + " [23.83160328464193, 35.53324960601498]]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.77461170749349, 35.550849159238616],\n", + " [23.776328321263023, 35.53967528733693],\n", + " [23.791262861057945, 35.53478622880854],\n", + " [23.778044935032554, 35.540373699944034],\n", + " [23.775984998509117, 35.550988822784504],\n", + " [23.779589887425132, 35.5414911474658],\n", + " [23.792464490696617, 35.53646251101553],\n", + " [23.774783368870445, 35.543027612387064],\n", + " [23.777014966770835, 35.54959217637752],\n", + " [23.77667164401693, 35.53716095159702],\n", + " [23.79315113620443, 35.53855781451608]]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " })]),\n", + "water = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.815368450747332, 35.53525030188046],\n", + " [23.82712725506862, 35.538463126752895],\n", + " [23.813823498354754, 35.53629797630387],\n", + " [23.826955593691668, 35.53972028406574],\n", + " [23.813051022158465, 35.53720594973632],\n", + " [23.826268948183856, 35.54104726207508],\n", + " [23.81339434491237, 35.5381139128914],\n", + " [23.825582302676043, 35.54230437888493],\n", + " [23.81313685284694, 35.53951075921525],\n", + " [23.827213085757098, 35.53769485425075],\n", + " [23.823264874087176, 35.543421799507115]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.93656138287624, 35.520162273141004],\n", + " [23.922656811343035, 35.52700811924147],\n", + " [23.939651287661395, 35.52114028690721],\n", + " [23.920596874819598, 35.529662473875746],\n", + " [23.938449658022723, 35.52379483562914]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.789275921450457, 35.5804973627026],\n", + " [23.79768732892116, 35.57972949300953],\n", + " [23.786357678042254, 35.579589879547086],\n", + " [23.798631466494403, 35.578577674666],\n", + " [23.78446940289577, 35.578752193661586],\n", + " [23.798502720461688, 35.577670169758946],\n", + " [23.78292445050319, 35.57791449901465],\n", + " [23.79210841193106, 35.5772866256402],\n", + " [23.79923228131374, 35.57651832180017]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " })]),\n", + "sunglint = ee.Geometry.MultiPolygon(\n", + " [[[[23.786748725416697, 35.55612383758693],\n", + " [23.786748725416697, 35.54634742800967],\n", + " [23.802541572096384, 35.54634742800967],\n", + " [23.802541572096384, 35.55612383758693]]],\n", + " [[[23.829664069654978, 35.550537463803785],\n", + " [23.829664069654978, 35.5441126527256],\n", + " [23.842710334303415, 35.5441126527256],\n", + " [23.842710334303415, 35.550537463803785]]],\n", + " [[[23.871206122877634, 35.547464792297085],\n", + " [23.871206122877634, 35.54271588654758],\n", + " [23.87978919172529, 35.54271588654758],\n", + " [23.87978919172529, 35.547464792297085]]]], None, False)\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.2 Benthic Habitats\n", + "# Checkpoint: A22b\n", + "# Authors: Dimitris Poursanidis, Aur\u00e9lie C. Shapiro, Spyros Christofilakos\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1\n", + "# Import and display satellite image.\n", + "planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \\\n", + " .divide(10000)\n", + "\n", + "Map.centerObject(planet, 12)\n", + "visParams = {\n", + " 'bands': ['b3', 'b2', 'b1'],\n", + " 'min': 0.17,\n", + " 'max': 0.68,\n", + " 'gamma': 0.8\n", + "}\n", + "Map.addLayer({\n", + " 'eeObject': planet,\n", + " 'visParams': visParams,\n", + " 'name': 'planet initial',\n", + " 'shown': True\n", + "})\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22b Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22b Checkpoint.js new file mode 100644 index 0000000..d81c83b --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22b Checkpoint.js @@ -0,0 +1,128 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var DIVsand = /* color: #fbff00 */ee.Geometry.MultiPolygon( + [[[[23.85533614379952, 35.525671008126785], + [23.85808272583077, 35.52511217612521], + [23.860142662354207, 35.53880243984323], + [23.85653777343819, 35.539500860050644]]], + [[[23.783753349610066, 35.54863600968416], + [23.801091148682332, 35.55114998568017], + [23.799546196289754, 35.55464148823767], + [23.782723381348347, 35.551289648702024]]]]), + land = /* color: #ff0000 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.813750501438804, 35.53087476744296], + [23.834178205296226, 35.52696311538223], + [23.81306385593099, 35.53269082679277], + [23.836753125950523, 35.52863956104383], + [23.81684040622396, 35.53310991157428], + [23.835208173557945, 35.53073506886724], + [23.820273633763023, 35.53422746028901], + [23.83160328464193, 35.53324960601498]]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.77461170749349, 35.550849159238616], + [23.776328321263023, 35.53967528733693], + [23.791262861057945, 35.53478622880854], + [23.778044935032554, 35.540373699944034], + [23.775984998509117, 35.550988822784504], + [23.779589887425132, 35.5414911474658], + [23.792464490696617, 35.53646251101553], + [23.774783368870445, 35.543027612387064], + [23.777014966770835, 35.54959217637752], + [23.77667164401693, 35.53716095159702], + [23.79315113620443, 35.53855781451608]]), + { + "class": 0, + "system:index": "1" + })]), + water = /* color: #0d9ad6 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.815368450747332, 35.53525030188046], + [23.82712725506862, 35.538463126752895], + [23.813823498354754, 35.53629797630387], + [23.826955593691668, 35.53972028406574], + [23.813051022158465, 35.53720594973632], + [23.826268948183856, 35.54104726207508], + [23.81339434491237, 35.5381139128914], + [23.825582302676043, 35.54230437888493], + [23.81313685284694, 35.53951075921525], + [23.827213085757098, 35.53769485425075], + [23.823264874087176, 35.543421799507115]]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.93656138287624, 35.520162273141004], + [23.922656811343035, 35.52700811924147], + [23.939651287661395, 35.52114028690721], + [23.920596874819598, 35.529662473875746], + [23.938449658022723, 35.52379483562914]]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.789275921450457, 35.5804973627026], + [23.79768732892116, 35.57972949300953], + [23.786357678042254, 35.579589879547086], + [23.798631466494403, 35.578577674666], + [23.78446940289577, 35.578752193661586], + [23.798502720461688, 35.577670169758946], + [23.78292445050319, 35.57791449901465], + [23.79210841193106, 35.5772866256402], + [23.79923228131374, 35.57651832180017]]), + { + "class": 1, + "system:index": "2" + })]), + sunglint = /* color: #f5a400 */ee.Geometry.MultiPolygon( + [[[[23.786748725416697, 35.55612383758693], + [23.786748725416697, 35.54634742800967], + [23.802541572096384, 35.54634742800967], + [23.802541572096384, 35.55612383758693]]], + [[[23.829664069654978, 35.550537463803785], + [23.829664069654978, 35.5441126527256], + [23.842710334303415, 35.5441126527256], + [23.842710334303415, 35.550537463803785]]], + [[[23.871206122877634, 35.547464792297085], + [23.871206122877634, 35.54271588654758], + [23.87978919172529, 35.54271588654758], + [23.87978919172529, 35.547464792297085]]]], null, false); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.2 Benthic Habitats +// Checkpoint: A22b +// Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1 +// Import and display satellite image. +var planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') + .divide(10000); + +Map.centerObject(planet, 12); +var visParams = { + bands: ['b3', 'b2', 'b1'], + min: 0.17, + max: 0.68, + gamma: 0.8 +}; +Map.addLayer({ + eeObject: planet, + visParams: visParams, + name: 'planet initial', + shown: true +}); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22b Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22b Checkpoint.py new file mode 100644 index 0000000..60cf2b4 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22b Checkpoint.py @@ -0,0 +1,134 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +DIVsand = ee.Geometry.MultiPolygon( + [[[[23.85533614379952, 35.525671008126785], + [23.85808272583077, 35.52511217612521], + [23.860142662354207, 35.53880243984323], + [23.85653777343819, 35.539500860050644]]], + [[[23.783753349610066, 35.54863600968416], + [23.801091148682332, 35.55114998568017], + [23.799546196289754, 35.55464148823767], + [23.782723381348347, 35.551289648702024]]]]), +land = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.813750501438804, 35.53087476744296], + [23.834178205296226, 35.52696311538223], + [23.81306385593099, 35.53269082679277], + [23.836753125950523, 35.52863956104383], + [23.81684040622396, 35.53310991157428], + [23.835208173557945, 35.53073506886724], + [23.820273633763023, 35.53422746028901], + [23.83160328464193, 35.53324960601498]]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.77461170749349, 35.550849159238616], + [23.776328321263023, 35.53967528733693], + [23.791262861057945, 35.53478622880854], + [23.778044935032554, 35.540373699944034], + [23.775984998509117, 35.550988822784504], + [23.779589887425132, 35.5414911474658], + [23.792464490696617, 35.53646251101553], + [23.774783368870445, 35.543027612387064], + [23.777014966770835, 35.54959217637752], + [23.77667164401693, 35.53716095159702], + [23.79315113620443, 35.53855781451608]]), + { + "class": 0, + "system:index": "1" + })]), +water = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.815368450747332, 35.53525030188046], + [23.82712725506862, 35.538463126752895], + [23.813823498354754, 35.53629797630387], + [23.826955593691668, 35.53972028406574], + [23.813051022158465, 35.53720594973632], + [23.826268948183856, 35.54104726207508], + [23.81339434491237, 35.5381139128914], + [23.825582302676043, 35.54230437888493], + [23.81313685284694, 35.53951075921525], + [23.827213085757098, 35.53769485425075], + [23.823264874087176, 35.543421799507115]]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.93656138287624, 35.520162273141004], + [23.922656811343035, 35.52700811924147], + [23.939651287661395, 35.52114028690721], + [23.920596874819598, 35.529662473875746], + [23.938449658022723, 35.52379483562914]]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.789275921450457, 35.5804973627026], + [23.79768732892116, 35.57972949300953], + [23.786357678042254, 35.579589879547086], + [23.798631466494403, 35.578577674666], + [23.78446940289577, 35.578752193661586], + [23.798502720461688, 35.577670169758946], + [23.78292445050319, 35.57791449901465], + [23.79210841193106, 35.5772866256402], + [23.79923228131374, 35.57651832180017]]), + { + "class": 1, + "system:index": "2" + })]), +sunglint = ee.Geometry.MultiPolygon( + [[[[23.786748725416697, 35.55612383758693], + [23.786748725416697, 35.54634742800967], + [23.802541572096384, 35.54634742800967], + [23.802541572096384, 35.55612383758693]]], + [[[23.829664069654978, 35.550537463803785], + [23.829664069654978, 35.5441126527256], + [23.842710334303415, 35.5441126527256], + [23.842710334303415, 35.550537463803785]]], + [[[23.871206122877634, 35.547464792297085], + [23.871206122877634, 35.54271588654758], + [23.87978919172529, 35.54271588654758], + [23.87978919172529, 35.547464792297085]]]], None, False) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.2 Benthic Habitats +# Checkpoint: A22b +# Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1 +# Import and display satellite image. +planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \ + .divide(10000) + +Map.centerObject(planet, 12) +visParams = { + 'bands': ['b3', 'b2', 'b1'], + 'min': 0.17, + 'max': 0.68, + 'gamma': 0.8 +} +Map.addLayer({ + 'eeObject': planet, + 'visParams': visParams, + 'name': 'planet initial', + 'shown': True +}) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22c Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22c Checkpoint.ipynb new file mode 100644 index 0000000..85e10fc --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22c Checkpoint.ipynb @@ -0,0 +1,361 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "land =\n", + "\n", + " # shown: False #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.813750501438804, 35.53087476744296],\n", + " [23.834178205296226, 35.52696311538223],\n", + " [23.81306385593099, 35.53269082679277],\n", + " [23.836753125950523, 35.52863956104383],\n", + " [23.81684040622396, 35.53310991157428],\n", + " [23.835208173557945, 35.53073506886724],\n", + " [23.820273633763023, 35.53422746028901],\n", + " [23.83160328464193, 35.53324960601498]]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.77461170749349, 35.550849159238616],\n", + " [23.776328321263023, 35.53967528733693],\n", + " [23.791262861057945, 35.53478622880854],\n", + " [23.778044935032554, 35.540373699944034],\n", + " [23.775984998509117, 35.550988822784504],\n", + " [23.779589887425132, 35.5414911474658],\n", + " [23.792464490696617, 35.53646251101553],\n", + " [23.774783368870445, 35.543027612387064],\n", + " [23.777014966770835, 35.54959217637752],\n", + " [23.77667164401693, 35.53716095159702],\n", + " [23.79315113620443, 35.53855781451608]]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " })]),\n", + " DIVsand =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.MultiPolygon(\n", + " [[[[23.85533614379952, 35.525671008126785],\n", + " [23.85808272583077, 35.52511217612521],\n", + " [23.860142662354207, 35.53880243984323],\n", + " [23.85653777343819, 35.539500860050644]]],\n", + " [[[23.783753349610066, 35.54863600968416],\n", + " [23.801091148682332, 35.55114998568017],\n", + " [23.799546196289754, 35.55464148823767],\n", + " [23.782723381348347, 35.551289648702024]]]]),\n", + "water = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.815368450747332, 35.53525030188046],\n", + " [23.82712725506862, 35.538463126752895],\n", + " [23.813823498354754, 35.53629797630387],\n", + " [23.826955593691668, 35.53972028406574],\n", + " [23.813051022158465, 35.53720594973632],\n", + " [23.826268948183856, 35.54104726207508],\n", + " [23.81339434491237, 35.5381139128914],\n", + " [23.825582302676043, 35.54230437888493],\n", + " [23.81313685284694, 35.53951075921525],\n", + " [23.827213085757098, 35.53769485425075],\n", + " [23.823264874087176, 35.543421799507115]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.93656138287624, 35.520162273141004],\n", + " [23.922656811343035, 35.52700811924147],\n", + " [23.939651287661395, 35.52114028690721],\n", + " [23.920596874819598, 35.529662473875746],\n", + " [23.938449658022723, 35.52379483562914]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.789275921450457, 35.5804973627026],\n", + " [23.79768732892116, 35.57972949300953],\n", + " [23.786357678042254, 35.579589879547086],\n", + " [23.798631466494403, 35.578577674666],\n", + " [23.78446940289577, 35.578752193661586],\n", + " [23.798502720461688, 35.577670169758946],\n", + " [23.78292445050319, 35.57791449901465],\n", + " [23.79210841193106, 35.5772866256402],\n", + " [23.79923228131374, 35.57651832180017]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " })]),\n", + "sunglint = ee.Geometry.MultiPolygon(\n", + " [[[[23.786748725416697, 35.55612383758693],\n", + " [23.786748725416697, 35.54634742800967],\n", + " [23.802541572096384, 35.54634742800967],\n", + " [23.802541572096384, 35.55612383758693]]],\n", + " [[[23.829664069654978, 35.550537463803785],\n", + " [23.829664069654978, 35.5441126527256],\n", + " [23.842710334303415, 35.5441126527256],\n", + " [23.842710334303415, 35.550537463803785]]],\n", + " [[[23.871206122877634, 35.547464792297085],\n", + " [23.871206122877634, 35.54271588654758],\n", + " [23.87978919172529, 35.54271588654758],\n", + " [23.87978919172529, 35.547464792297085]]]], None, False)\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.2 Benthic Habitats\n", + "# Checkpoint: A22c\n", + "# Authors: Dimitris Poursanidis, Aur\u00e9lie C. Shapiro, Spyros Christofilakos\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1\n", + "# Import and display satellite image.\n", + "planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \\\n", + " .divide(10000)\n", + "\n", + "Map.centerObject(planet, 12)\n", + "visParams = {\n", + " 'bands': ['b3', 'b2', 'b1'],\n", + " 'min': 0.17,\n", + " 'max': 0.68,\n", + " 'gamma': 0.8\n", + "}\n", + "Map.addLayer({\n", + " 'eeObject': planet,\n", + " 'visParams': visParams,\n", + " 'name': 'planet initial',\n", + " 'shown': True\n", + "})\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------\n", + "\n", + "# Section 2\n", + "# Mask based to NDWI and RF.\n", + "def landmask(img):\n", + " ndwi = img.normalizedDifference(['b2', 'b4'])\n", + " training = ndwi.sampleRegions(land.merge(water), ['class'],\n", + " 3)\n", + " trained = ee.Classifier.smileRandomForest(10) \\\n", + " .train(training, 'class')\n", + " classified = ndwi.classify(trained)\n", + " mask = classified.eq(1)\n", + "\n", + " return img.updateMask(mask)\n", + "\n", + "\n", + "maskedImg = landmask(planet)\n", + "\n", + "Map.addLayer(maskedImg, visParams, 'maskedImg', False)\n", + "\n", + "# Sun-glint correction.\n", + "def sunglintRemoval(img):\n", + " linearFit1 = img.select(['b4', 'b1']).reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + " linearFit2 = img.select(['b4', 'b2']).reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + " linearFit3 = img.select(['b4', 'b3']).reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + "\n", + " slopeImage = ee.Dictionary({\n", + " 'b1': linearFit1.get('scale'),\n", + " 'b2': linearFit2.get('scale'),\n", + " 'b3': linearFit3.get('scale')\n", + " }).toImage()\n", + "\n", + " minNIR = img.select('b4').reduceRegion({\n", + " 'reducer': ee.Reducer.min(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " }).toImage(['b4'])\n", + "\n", + " return img.select(['b1', 'b2', 'b3']) \\\n", + " .subtract(slopeImage.multiply((img.select('b4')).subtract(\n", + " minNIR))) \\\n", + " .addBands(img.select('b4'))\n", + "\n", + "sgImg = sunglintRemoval(maskedImg)\n", + "Map.addLayer(sgImg, visParams, 'sgImg', False)\n", + "\n", + "# DIV procedure.\n", + "def kernel(img):\n", + " boxcar = ee.Kernel.square({\n", + " 'radius': 2,\n", + " 'units': 'pixels',\n", + " 'normalize': True\n", + " })\n", + " return img.convolve(boxcar)\n", + "\n", + "\n", + "def makePositive(img):\n", + " return img.where(img.lte(0), 0.0001)\n", + "\n", + "\n", + "def div(img):\n", + " band1 = ee.List(['b1', 'b2', 'b3', 'b1', 'b2'])\n", + " band2 = ee.List(['b3', 'b3', 'b2', 'b2', 'b1'])\n", + " nband = ee.List(['b1b3', 'b2b3', 'b3b2', 'b1b2', 'b2b1'])\n", + "\n", + " for i in range(0, 5, 1):\n", + " x = band1.get(i)\n", + " y = band2.get(i)\n", + " z = nband.get(i)\n", + "\n", + " imageLog = img.select([x, y]).log()\n", + "\n", + " covariance = imageLog.toArray().reduceRegion({\n", + " 'reducer': ee.Reducer.covariance(),\n", + " 'geometry': DIVsand,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + "\n", + " covarMatrix = ee.Array(covariance.get('array'))\n", + " var1 = covarMatrix.get([0, 0])\n", + " var2 = covarMatrix.get([1, 1])\n", + " covar = covarMatrix.get([0, 1])\n", + "\n", + " a = var1.subtract(var2).divide(covar.multiply(2))\n", + " attenCoeffRatio = a.add(((a.pow(2)).add(1)).sqrt())\n", + "\n", + " depthInvariantIndex = img.expression(\n", + " 'image1 - (image2 * coeff)', {\n", + " 'image1': imageLog.select([x]),\n", + " 'image2': imageLog.select([y]),\n", + " 'coeff': attenCoeffRatio\n", + " })\n", + "\n", + " img = ee.Image.cat([img, depthInvariantIndex.select([x], [\n", + " z\n", + " ])])\n", + "\n", + " return img\n", + "\n", + "\n", + "divImg = div(kernel(makePositive(sgImg))).select('b[1-3]',\n", + " 'b1b2')\n", + "vivVisParams = {\n", + " 'bands': ['b1b2'],\n", + " 'min': -0.81,\n", + " 'max': -0.04,\n", + " 'gamma': 0.75\n", + "}\n", + "Map.addLayer(divImg, vivVisParams, 'divImg', False)\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22c Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22c Checkpoint.js new file mode 100644 index 0000000..b6f4b1e --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22c Checkpoint.js @@ -0,0 +1,268 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var land = + /* color: #ff0000 */ + /* shown: false */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.813750501438804, 35.53087476744296], + [23.834178205296226, 35.52696311538223], + [23.81306385593099, 35.53269082679277], + [23.836753125950523, 35.52863956104383], + [23.81684040622396, 35.53310991157428], + [23.835208173557945, 35.53073506886724], + [23.820273633763023, 35.53422746028901], + [23.83160328464193, 35.53324960601498]]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.77461170749349, 35.550849159238616], + [23.776328321263023, 35.53967528733693], + [23.791262861057945, 35.53478622880854], + [23.778044935032554, 35.540373699944034], + [23.775984998509117, 35.550988822784504], + [23.779589887425132, 35.5414911474658], + [23.792464490696617, 35.53646251101553], + [23.774783368870445, 35.543027612387064], + [23.777014966770835, 35.54959217637752], + [23.77667164401693, 35.53716095159702], + [23.79315113620443, 35.53855781451608]]), + { + "class": 0, + "system:index": "1" + })]), + DIVsand = + /* color: #fbff00 */ + /* shown: false */ + ee.Geometry.MultiPolygon( + [[[[23.85533614379952, 35.525671008126785], + [23.85808272583077, 35.52511217612521], + [23.860142662354207, 35.53880243984323], + [23.85653777343819, 35.539500860050644]]], + [[[23.783753349610066, 35.54863600968416], + [23.801091148682332, 35.55114998568017], + [23.799546196289754, 35.55464148823767], + [23.782723381348347, 35.551289648702024]]]]), + water = /* color: #0d9ad6 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.815368450747332, 35.53525030188046], + [23.82712725506862, 35.538463126752895], + [23.813823498354754, 35.53629797630387], + [23.826955593691668, 35.53972028406574], + [23.813051022158465, 35.53720594973632], + [23.826268948183856, 35.54104726207508], + [23.81339434491237, 35.5381139128914], + [23.825582302676043, 35.54230437888493], + [23.81313685284694, 35.53951075921525], + [23.827213085757098, 35.53769485425075], + [23.823264874087176, 35.543421799507115]]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.93656138287624, 35.520162273141004], + [23.922656811343035, 35.52700811924147], + [23.939651287661395, 35.52114028690721], + [23.920596874819598, 35.529662473875746], + [23.938449658022723, 35.52379483562914]]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.789275921450457, 35.5804973627026], + [23.79768732892116, 35.57972949300953], + [23.786357678042254, 35.579589879547086], + [23.798631466494403, 35.578577674666], + [23.78446940289577, 35.578752193661586], + [23.798502720461688, 35.577670169758946], + [23.78292445050319, 35.57791449901465], + [23.79210841193106, 35.5772866256402], + [23.79923228131374, 35.57651832180017]]), + { + "class": 1, + "system:index": "2" + })]), + sunglint = /* color: #f5a400 */ee.Geometry.MultiPolygon( + [[[[23.786748725416697, 35.55612383758693], + [23.786748725416697, 35.54634742800967], + [23.802541572096384, 35.54634742800967], + [23.802541572096384, 35.55612383758693]]], + [[[23.829664069654978, 35.550537463803785], + [23.829664069654978, 35.5441126527256], + [23.842710334303415, 35.5441126527256], + [23.842710334303415, 35.550537463803785]]], + [[[23.871206122877634, 35.547464792297085], + [23.871206122877634, 35.54271588654758], + [23.87978919172529, 35.54271588654758], + [23.87978919172529, 35.547464792297085]]]], null, false); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.2 Benthic Habitats +// Checkpoint: A22c +// Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1 +// Import and display satellite image. +var planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') + .divide(10000); + +Map.centerObject(planet, 12); +var visParams = { + bands: ['b3', 'b2', 'b1'], + min: 0.17, + max: 0.68, + gamma: 0.8 +}; +Map.addLayer({ + eeObject: planet, + visParams: visParams, + name: 'planet initial', + shown: true +}); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ + +// Section 2 +// Mask based to NDWI and RF. +function landmask(img) { + var ndwi = img.normalizedDifference(['b2', 'b4']); + var training = ndwi.sampleRegions(land.merge(water), ['class'], + 3); + var trained = ee.Classifier.smileRandomForest(10) + .train(training, 'class'); + var classified = ndwi.classify(trained); + var mask = classified.eq(1); + + return img.updateMask(mask); +} + +var maskedImg = landmask(planet); + +Map.addLayer(maskedImg, visParams, 'maskedImg', false); + +// Sun-glint correction. +function sunglintRemoval(img) { + var linearFit1 = img.select(['b4', 'b1']).reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + var linearFit2 = img.select(['b4', 'b2']).reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + var linearFit3 = img.select(['b4', 'b3']).reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + + var slopeImage = ee.Dictionary({ + 'b1': linearFit1.get('scale'), + 'b2': linearFit2.get('scale'), + 'b3': linearFit3.get('scale') + }).toImage(); + + var minNIR = img.select('b4').reduceRegion({ + reducer: ee.Reducer.min(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }).toImage(['b4']); + + return img.select(['b1', 'b2', 'b3']) + .subtract(slopeImage.multiply((img.select('b4')).subtract( + minNIR))) + .addBands(img.select('b4')); +} +var sgImg = sunglintRemoval(maskedImg); +Map.addLayer(sgImg, visParams, 'sgImg', false); + +// DIV procedure. +function kernel(img) { + var boxcar = ee.Kernel.square({ + radius: 2, + units: 'pixels', + normalize: true + }); + return img.convolve(boxcar); +} + +function makePositive(img) { + return img.where(img.lte(0), 0.0001); +} + +function div(img) { + var band1 = ee.List(['b1', 'b2', 'b3', 'b1', 'b2']); + var band2 = ee.List(['b3', 'b3', 'b2', 'b2', 'b1']); + var nband = ee.List(['b1b3', 'b2b3', 'b3b2', 'b1b2', 'b2b1']); + + for (var i = 0; i < 5; i += 1) { + var x = band1.get(i); + var y = band2.get(i); + var z = nband.get(i); + + var imageLog = img.select([x, y]).log(); + + var covariance = imageLog.toArray().reduceRegion({ + reducer: ee.Reducer.covariance(), + geometry: DIVsand, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + + var covarMatrix = ee.Array(covariance.get('array')); + var var1 = covarMatrix.get([0, 0]); + var var2 = covarMatrix.get([1, 1]); + var covar = covarMatrix.get([0, 1]); + + var a = var1.subtract(var2).divide(covar.multiply(2)); + var attenCoeffRatio = a.add(((a.pow(2)).add(1)).sqrt()); + + var depthInvariantIndex = img.expression( + 'image1 - (image2 * coeff)', { + 'image1': imageLog.select([x]), + 'image2': imageLog.select([y]), + 'coeff': attenCoeffRatio + }); + + img = ee.Image.cat([img, depthInvariantIndex.select([x], [ + z + ])]); + } + return img; +} + +var divImg = div(kernel(makePositive(sgImg))).select('b[1-3]', + 'b1b2'); +var vivVisParams = { + bands: ['b1b2'], + min: -0.81, + max: -0.04, + gamma: 0.75 +}; +Map.addLayer(divImg, vivVisParams, 'divImg', false); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22c Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22c Checkpoint.py new file mode 100644 index 0000000..3ffa486 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22c Checkpoint.py @@ -0,0 +1,274 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +land = + + # shown: False # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.813750501438804, 35.53087476744296], + [23.834178205296226, 35.52696311538223], + [23.81306385593099, 35.53269082679277], + [23.836753125950523, 35.52863956104383], + [23.81684040622396, 35.53310991157428], + [23.835208173557945, 35.53073506886724], + [23.820273633763023, 35.53422746028901], + [23.83160328464193, 35.53324960601498]]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.77461170749349, 35.550849159238616], + [23.776328321263023, 35.53967528733693], + [23.791262861057945, 35.53478622880854], + [23.778044935032554, 35.540373699944034], + [23.775984998509117, 35.550988822784504], + [23.779589887425132, 35.5414911474658], + [23.792464490696617, 35.53646251101553], + [23.774783368870445, 35.543027612387064], + [23.777014966770835, 35.54959217637752], + [23.77667164401693, 35.53716095159702], + [23.79315113620443, 35.53855781451608]]), + { + "class": 0, + "system:index": "1" + })]), + DIVsand = + + # shown: False # + ee.Geometry.MultiPolygon( + [[[[23.85533614379952, 35.525671008126785], + [23.85808272583077, 35.52511217612521], + [23.860142662354207, 35.53880243984323], + [23.85653777343819, 35.539500860050644]]], + [[[23.783753349610066, 35.54863600968416], + [23.801091148682332, 35.55114998568017], + [23.799546196289754, 35.55464148823767], + [23.782723381348347, 35.551289648702024]]]]), +water = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.815368450747332, 35.53525030188046], + [23.82712725506862, 35.538463126752895], + [23.813823498354754, 35.53629797630387], + [23.826955593691668, 35.53972028406574], + [23.813051022158465, 35.53720594973632], + [23.826268948183856, 35.54104726207508], + [23.81339434491237, 35.5381139128914], + [23.825582302676043, 35.54230437888493], + [23.81313685284694, 35.53951075921525], + [23.827213085757098, 35.53769485425075], + [23.823264874087176, 35.543421799507115]]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.93656138287624, 35.520162273141004], + [23.922656811343035, 35.52700811924147], + [23.939651287661395, 35.52114028690721], + [23.920596874819598, 35.529662473875746], + [23.938449658022723, 35.52379483562914]]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.789275921450457, 35.5804973627026], + [23.79768732892116, 35.57972949300953], + [23.786357678042254, 35.579589879547086], + [23.798631466494403, 35.578577674666], + [23.78446940289577, 35.578752193661586], + [23.798502720461688, 35.577670169758946], + [23.78292445050319, 35.57791449901465], + [23.79210841193106, 35.5772866256402], + [23.79923228131374, 35.57651832180017]]), + { + "class": 1, + "system:index": "2" + })]), +sunglint = ee.Geometry.MultiPolygon( + [[[[23.786748725416697, 35.55612383758693], + [23.786748725416697, 35.54634742800967], + [23.802541572096384, 35.54634742800967], + [23.802541572096384, 35.55612383758693]]], + [[[23.829664069654978, 35.550537463803785], + [23.829664069654978, 35.5441126527256], + [23.842710334303415, 35.5441126527256], + [23.842710334303415, 35.550537463803785]]], + [[[23.871206122877634, 35.547464792297085], + [23.871206122877634, 35.54271588654758], + [23.87978919172529, 35.54271588654758], + [23.87978919172529, 35.547464792297085]]]], None, False) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.2 Benthic Habitats +# Checkpoint: A22c +# Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1 +# Import and display satellite image. +planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \ + .divide(10000) + +Map.centerObject(planet, 12) +visParams = { + 'bands': ['b3', 'b2', 'b1'], + 'min': 0.17, + 'max': 0.68, + 'gamma': 0.8 +} +Map.addLayer({ + 'eeObject': planet, + 'visParams': visParams, + 'name': 'planet initial', + 'shown': True +}) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ + +# Section 2 +# Mask based to NDWI and RF. +def landmask(img): + ndwi = img.normalizedDifference(['b2', 'b4']) + training = ndwi.sampleRegions(land.merge(water), ['class'], + 3) + trained = ee.Classifier.smileRandomForest(10) \ + .train(training, 'class') + classified = ndwi.classify(trained) + mask = classified.eq(1) + + return img.updateMask(mask) + + +maskedImg = landmask(planet) + +Map.addLayer(maskedImg, visParams, 'maskedImg', False) + +# Sun-glint correction. +def sunglintRemoval(img): + linearFit1 = img.select(['b4', 'b1']).reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + linearFit2 = img.select(['b4', 'b2']).reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + linearFit3 = img.select(['b4', 'b3']).reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + + slopeImage = ee.Dictionary({ + 'b1': linearFit1.get('scale'), + 'b2': linearFit2.get('scale'), + 'b3': linearFit3.get('scale') + }).toImage() + + minNIR = img.select('b4').reduceRegion({ + 'reducer': ee.Reducer.min(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }).toImage(['b4']) + + return img.select(['b1', 'b2', 'b3']) \ + .subtract(slopeImage.multiply((img.select('b4')).subtract( + minNIR))) \ + .addBands(img.select('b4')) + +sgImg = sunglintRemoval(maskedImg) +Map.addLayer(sgImg, visParams, 'sgImg', False) + +# DIV procedure. +def kernel(img): + boxcar = ee.Kernel.square({ + 'radius': 2, + 'units': 'pixels', + 'normalize': True + }) + return img.convolve(boxcar) + + +def makePositive(img): + return img.where(img.lte(0), 0.0001) + + +def div(img): + band1 = ee.List(['b1', 'b2', 'b3', 'b1', 'b2']) + band2 = ee.List(['b3', 'b3', 'b2', 'b2', 'b1']) + nband = ee.List(['b1b3', 'b2b3', 'b3b2', 'b1b2', 'b2b1']) + + for i in range(0, 5, 1): + x = band1.get(i) + y = band2.get(i) + z = nband.get(i) + + imageLog = img.select([x, y]).log() + + covariance = imageLog.toArray().reduceRegion({ + 'reducer': ee.Reducer.covariance(), + 'geometry': DIVsand, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + + covarMatrix = ee.Array(covariance.get('array')) + var1 = covarMatrix.get([0, 0]) + var2 = covarMatrix.get([1, 1]) + covar = covarMatrix.get([0, 1]) + + a = var1.subtract(var2).divide(covar.multiply(2)) + attenCoeffRatio = a.add(((a.pow(2)).add(1)).sqrt()) + + depthInvariantIndex = img.expression( + 'image1 - (image2 * coeff)', { + 'image1': imageLog.select([x]), + 'image2': imageLog.select([y]), + 'coeff': attenCoeffRatio + }) + + img = ee.Image.cat([img, depthInvariantIndex.select([x], [ + z + ])]) + + return img + + +divImg = div(kernel(makePositive(sgImg))).select('b[1-3]', + 'b1b2') +vivVisParams = { + 'bands': ['b1b2'], + 'min': -0.81, + 'max': -0.04, + 'gamma': 0.75 +} +Map.addLayer(divImg, vivVisParams, 'divImg', False) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22d Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22d Checkpoint.ipynb new file mode 100644 index 0000000..85f46a8 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22d Checkpoint.ipynb @@ -0,0 +1,514 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "DIVsand = ee.Geometry.MultiPolygon(\n", + " [[[[23.85533614379952, 35.525671008126785],\n", + " [23.85808272583077, 35.52511217612521],\n", + " [23.860142662354207, 35.53880243984323],\n", + " [23.85653777343819, 35.539500860050644]]],\n", + " [[[23.783753349610066, 35.54863600968416],\n", + " [23.801091148682332, 35.55114998568017],\n", + " [23.799546196289754, 35.55464148823767],\n", + " [23.782723381348347, 35.551289648702024]]]]),\n", + "land = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.813750501438804, 35.53087476744296],\n", + " [23.834178205296226, 35.52696311538223],\n", + " [23.81306385593099, 35.53269082679277],\n", + " [23.836753125950523, 35.52863956104383],\n", + " [23.81684040622396, 35.53310991157428],\n", + " [23.835208173557945, 35.53073506886724],\n", + " [23.820273633763023, 35.53422746028901],\n", + " [23.83160328464193, 35.53324960601498]]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.77461170749349, 35.550849159238616],\n", + " [23.776328321263023, 35.53967528733693],\n", + " [23.791262861057945, 35.53478622880854],\n", + " [23.778044935032554, 35.540373699944034],\n", + " [23.775984998509117, 35.550988822784504],\n", + " [23.779589887425132, 35.5414911474658],\n", + " [23.792464490696617, 35.53646251101553],\n", + " [23.774783368870445, 35.543027612387064],\n", + " [23.777014966770835, 35.54959217637752],\n", + " [23.77667164401693, 35.53716095159702],\n", + " [23.79315113620443, 35.53855781451608]]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " })]),\n", + "water = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.815368450747332, 35.53525030188046],\n", + " [23.82712725506862, 35.538463126752895],\n", + " [23.813823498354754, 35.53629797630387],\n", + " [23.826955593691668, 35.53972028406574],\n", + " [23.813051022158465, 35.53720594973632],\n", + " [23.826268948183856, 35.54104726207508],\n", + " [23.81339434491237, 35.5381139128914],\n", + " [23.825582302676043, 35.54230437888493],\n", + " [23.81313685284694, 35.53951075921525],\n", + " [23.827213085757098, 35.53769485425075],\n", + " [23.823264874087176, 35.543421799507115]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.93656138287624, 35.520162273141004],\n", + " [23.922656811343035, 35.52700811924147],\n", + " [23.939651287661395, 35.52114028690721],\n", + " [23.920596874819598, 35.529662473875746],\n", + " [23.938449658022723, 35.52379483562914]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.789275921450457, 35.5804973627026],\n", + " [23.79768732892116, 35.57972949300953],\n", + " [23.786357678042254, 35.579589879547086],\n", + " [23.798631466494403, 35.578577674666],\n", + " [23.78446940289577, 35.578752193661586],\n", + " [23.798502720461688, 35.577670169758946],\n", + " [23.78292445050319, 35.57791449901465],\n", + " [23.79210841193106, 35.5772866256402],\n", + " [23.79923228131374, 35.57651832180017]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " })]),\n", + "sunglint = ee.Geometry.MultiPolygon(\n", + " [[[[23.786748725416697, 35.55612383758693],\n", + " [23.786748725416697, 35.54634742800967],\n", + " [23.802541572096384, 35.54634742800967],\n", + " [23.802541572096384, 35.55612383758693]]],\n", + " [[[23.829664069654978, 35.550537463803785],\n", + " [23.829664069654978, 35.5441126527256],\n", + " [23.842710334303415, 35.5441126527256],\n", + " [23.842710334303415, 35.550537463803785]]],\n", + " [[[23.871206122877634, 35.547464792297085],\n", + " [23.871206122877634, 35.54271588654758],\n", + " [23.87978919172529, 35.54271588654758],\n", + " [23.87978919172529, 35.547464792297085]]]], None, False)\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.2 Benthic Habitats\n", + "# Checkpoint: A22d\n", + "# Authors: Dimitris Poursanidis, Aur\u00e9lie C. Shapiro, Spyros Christofilakos\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1\n", + "# Import and display satellite image.\n", + "planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \\\n", + " .divide(10000)\n", + "\n", + "Map.centerObject(planet, 12)\n", + "visParams = {\n", + " 'bands': ['b3', 'b2', 'b1'],\n", + " 'min': 0.17,\n", + " 'max': 0.68,\n", + " 'gamma': 0.8\n", + "}\n", + "Map.addLayer({\n", + " 'eeObject': planet,\n", + " 'visParams': visParams,\n", + " 'name': 'planet initial',\n", + " 'shown': True\n", + "})\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------\n", + "\n", + "# Section 2\n", + "# Mask based to NDWI and RF.\n", + "def landmask(img):\n", + " ndwi = img.normalizedDifference(['b2', 'b4'])\n", + " training = ndwi.sampleRegions(land.merge(water), ['class'],\n", + " 3)\n", + " trained = ee.Classifier.smileRandomForest(10) \\\n", + " .train(training, 'class')\n", + " classified = ndwi.classify(trained)\n", + " mask = classified.eq(1)\n", + "\n", + " return img.updateMask(mask)\n", + "\n", + "\n", + "maskedImg = landmask(planet)\n", + "\n", + "Map.addLayer(maskedImg, visParams, 'maskedImg', False)\n", + "\n", + "# Sun-glint correction.\n", + "def sunglintRemoval(img):\n", + " linearFit1 = img.select(['b4', 'b1']).reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + " linearFit2 = img.select(['b4', 'b2']).reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + " linearFit3 = img.select(['b4', 'b3']).reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + "\n", + " slopeImage = ee.Dictionary({\n", + " 'b1': linearFit1.get('scale'),\n", + " 'b2': linearFit2.get('scale'),\n", + " 'b3': linearFit3.get('scale')\n", + " }).toImage()\n", + "\n", + " minNIR = img.select('b4').reduceRegion({\n", + " 'reducer': ee.Reducer.min(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " }).toImage(['b4'])\n", + "\n", + " return img.select(['b1', 'b2', 'b3']) \\\n", + " .subtract(slopeImage.multiply((img.select('b4')).subtract(\n", + " minNIR))) \\\n", + " .addBands(img.select('b4'))\n", + "\n", + "sgImg = sunglintRemoval(maskedImg)\n", + "Map.addLayer(sgImg, visParams, 'sgImg', False)\n", + "\n", + "# DIV procedure.\n", + "def kernel(img):\n", + " boxcar = ee.Kernel.square({\n", + " 'radius': 2,\n", + " 'units': 'pixels',\n", + " 'normalize': True\n", + " })\n", + " return img.convolve(boxcar)\n", + "\n", + "\n", + "def makePositive(img):\n", + " return img.where(img.lte(0), 0.0001)\n", + "\n", + "\n", + "def div(img):\n", + " band1 = ee.List(['b1', 'b2', 'b3', 'b1', 'b2'])\n", + " band2 = ee.List(['b3', 'b3', 'b2', 'b2', 'b1'])\n", + " nband = ee.List(['b1b3', 'b2b3', 'b3b2', 'b1b2', 'b2b1'])\n", + "\n", + " for i in range(0, 5, 1):\n", + " x = band1.get(i)\n", + " y = band2.get(i)\n", + " z = nband.get(i)\n", + "\n", + " imageLog = img.select([x, y]).log()\n", + "\n", + " covariance = imageLog.toArray().reduceRegion({\n", + " 'reducer': ee.Reducer.covariance(),\n", + " 'geometry': DIVsand,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + "\n", + " covarMatrix = ee.Array(covariance.get('array'))\n", + " var1 = covarMatrix.get([0, 0])\n", + " var2 = covarMatrix.get([1, 1])\n", + " covar = covarMatrix.get([0, 1])\n", + "\n", + " a = var1.subtract(var2).divide(covar.multiply(2))\n", + " attenCoeffRatio = a.add(((a.pow(2)).add(1)).sqrt())\n", + "\n", + " depthInvariantIndex = img.expression(\n", + " 'image1 - (image2 * coeff)', {\n", + " 'image1': imageLog.select([x]),\n", + " 'image2': imageLog.select([y]),\n", + " 'coeff': attenCoeffRatio\n", + " })\n", + "\n", + " img = ee.Image.cat([img, depthInvariantIndex.select([x], [\n", + " z\n", + " ])])\n", + "\n", + " return img\n", + "\n", + "\n", + "divImg = div(kernel(makePositive(sgImg))).select('b[1-3]',\n", + " 'b1b2')\n", + "vivVisParams = {\n", + " 'bands': ['b1b2'],\n", + " 'min': -0.81,\n", + " 'max': -0.04,\n", + " 'gamma': 0.75\n", + "}\n", + "Map.addLayer(divImg, vivVisParams, 'divImg', False)\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------\n", + "\n", + "# Section 3, classification\n", + "# Import of reference data and split.\n", + "softBottom = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-2/SoftBottom')\n", + "rockyBottom = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-2/RockyBottom')\n", + "pO = ee.FeatureCollection('projects/gee-book/assets/A2-2/PO')\n", + "\n", + "sand = ee.FeatureCollection.randomPoints(softBottom, 150).map(\n", + " def function(s):\n", + " return s.set('class', 0)\n", + " ).randomColumn()\n", + "sandT = sand.filter(ee.Filter.lte('random', 0.7)).aside(print,\n", + " 'sand training')\n", + "sandV = sand.filter(ee.Filter.gt('random', 0.7)).aside(print,\n", + " 'sand validation')\n", + "Map.addLayer(sandT, {\n", + " 'color': 'yellow'\n", + "}, 'Sand Training', False)\n", + "Map.addLayer(sandV, {\n", + " 'color': 'yellow'\n", + "}, 'Sand Validation', False)\n", + "\n", + "hard = ee.FeatureCollection.randomPoints(rockyBottom, 79).map(\n", + " def function(s):\n", + " return s.set('class', 1)\n", + " ).randomColumn()\n", + "hardT = hard.filter(ee.Filter.lte('random', 0.7)).aside(print,\n", + " 'hard training')\n", + "hardV = hard.filter(ee.Filter.gt('random', 0.7)).aside(print,\n", + " 'hard validation')\n", + "Map.addLayer(hardT, {\n", + " 'color': 'red'\n", + "}, 'Rock Training', False)\n", + "Map.addLayer(hardV, {\n", + " 'color': 'red'\n", + "}, 'Rock Validation', False)\n", + "\n", + "\n", + "def func_yru(s):\n", + " return s.set('class', 2)\n", + "\n", + "posi = pO.map(func_yru) \\\n", + " .randomColumn('random')\n", + "posiT = posi.filter(ee.Filter.lte('random', 0.7)).aside(print,\n", + " 'posi training')\n", + "posiV = posi.filter(ee.Filter.gt('random', 0.7)).aside(print,\n", + " 'posi validation')\n", + "Map.addLayer(posiT, {\n", + " 'color': 'green'\n", + "}, 'Posidonia Training', False)\n", + "Map.addLayer(posiV, {\n", + " 'color': 'green'\n", + "}, 'Posidonia Validation', False)\n", + "\n", + "# Classification procedure.\n", + "def classify(img):\n", + " mergedT = ee.FeatureCollection([sandT, hardT, posiT]) \\\n", + " .flatten()\n", + " training = img.sampleRegions(mergedT, ['class'], 3)\n", + " trained = ee.Classifier.libsvm({\n", + " 'kernelType': 'RBF',\n", + " 'gamma': 1,\n", + " 'cost': 500\n", + " }).train(training, 'class')\n", + " classified = img.classify(trained)\n", + "\n", + " mergedV = ee.FeatureCollection([sandV, hardV, posiV]) \\\n", + " .flatten()\n", + " accuracyCol = classified.unmask().reduceRegions({\n", + " 'collection': mergedV,\n", + " 'reducer': ee.Reducer.first(),\n", + " 'scale': 10\n", + " })\n", + " classificationErrorMatrix = accuracyCol.errorMatrix({\n", + " 'actual': 'class',\n", + " 'predicted': 'first',\n", + " 'order': [0, 1, 2]\n", + " })\n", + " classNames = ['soft_bot', 'hard_bot', 'seagrass']\n", + " accuracyOA = classificationErrorMatrix.accuracy()\n", + " accuraccyCons = ee.Dictionary.fromLists({\n", + " 'keys': classNames,\n", + " 'values': classificationErrorMatrix.consumersAccuracy() \\\n", + " .toList() \\\n", + " .flatten()\n", + " })\n", + " accuracyProd = ee.Dictionary.fromLists({\n", + " 'keys': classNames,\n", + " 'values': classificationErrorMatrix.producersAccuracy() \\\n", + " .toList() \\\n", + " .flatten()\n", + " })\n", + "\n", + " classificationErrormatrixArray = classificationErrorMatrix \\\n", + " .array()\n", + "\n", + " def arrayToDatatable(array):\n", + " classesNames = ee.List(classNames)\n", + "\n", + " def toTableColumns(s):\n", + " return {\n", + " 'id': s,\n", + " 'label': s,\n", + " 'type': 'number'\n", + " }\n", + "\n", + " columns = classesNames.map(toTableColumns)\n", + "\n", + " def featureToTableRow(f):\n", + " return {\n", + "\n", + "def func_gsk(c):\n", + " return {\n", + " 'v': c\n", + " }\n", + "\n", + " 'c': ee.List(f).map(func_gsk)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " }\n", + "\n", + " rows = array.toList().map(featureToTableRow)\n", + " return ee.Dictionary({\n", + " 'cols': columns,\n", + " 'rows': rows\n", + " })\n", + " \n", + "\n", + " dataTable = arrayToDatatable(classificationErrormatrixArray) \\\n", + " .evaluate(function(dataTable) {\n", + " print('------------- Error matrix -------------',\n", + " ui.Chart(dataTable, 'Table') \\\n", + " .setOptions({\n", + " 'pageSize': 15\n", + " }),\n", + " 'rows: reference, 'cols': mapped')\n", + " })\n", + " print('Overall Accuracy', accuracyOA)\n", + " print('Users accuracy', accuraccyCons)\n", + " print('Producers accuracy', accuracyProd)\n", + " return classified\n", + "\n", + "\n", + "svmClassification = classify(divImg)\n", + "svmVis = {\n", + " 'min': 0,\n", + " 'max': 2,\n", + " 'palette': ['ffffbf', 'fc8d59', '91cf60']\n", + "}\n", + "Map.addLayer(svmClassification, svmVis, 'classification')\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22d Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22d Checkpoint.js new file mode 100644 index 0000000..d4fe831 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22d Checkpoint.js @@ -0,0 +1,412 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var DIVsand = /* color: #fbff00 */ee.Geometry.MultiPolygon( + [[[[23.85533614379952, 35.525671008126785], + [23.85808272583077, 35.52511217612521], + [23.860142662354207, 35.53880243984323], + [23.85653777343819, 35.539500860050644]]], + [[[23.783753349610066, 35.54863600968416], + [23.801091148682332, 35.55114998568017], + [23.799546196289754, 35.55464148823767], + [23.782723381348347, 35.551289648702024]]]]), + land = /* color: #ff0000 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.813750501438804, 35.53087476744296], + [23.834178205296226, 35.52696311538223], + [23.81306385593099, 35.53269082679277], + [23.836753125950523, 35.52863956104383], + [23.81684040622396, 35.53310991157428], + [23.835208173557945, 35.53073506886724], + [23.820273633763023, 35.53422746028901], + [23.83160328464193, 35.53324960601498]]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.77461170749349, 35.550849159238616], + [23.776328321263023, 35.53967528733693], + [23.791262861057945, 35.53478622880854], + [23.778044935032554, 35.540373699944034], + [23.775984998509117, 35.550988822784504], + [23.779589887425132, 35.5414911474658], + [23.792464490696617, 35.53646251101553], + [23.774783368870445, 35.543027612387064], + [23.777014966770835, 35.54959217637752], + [23.77667164401693, 35.53716095159702], + [23.79315113620443, 35.53855781451608]]), + { + "class": 0, + "system:index": "1" + })]), + water = /* color: #0d9ad6 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.815368450747332, 35.53525030188046], + [23.82712725506862, 35.538463126752895], + [23.813823498354754, 35.53629797630387], + [23.826955593691668, 35.53972028406574], + [23.813051022158465, 35.53720594973632], + [23.826268948183856, 35.54104726207508], + [23.81339434491237, 35.5381139128914], + [23.825582302676043, 35.54230437888493], + [23.81313685284694, 35.53951075921525], + [23.827213085757098, 35.53769485425075], + [23.823264874087176, 35.543421799507115]]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.93656138287624, 35.520162273141004], + [23.922656811343035, 35.52700811924147], + [23.939651287661395, 35.52114028690721], + [23.920596874819598, 35.529662473875746], + [23.938449658022723, 35.52379483562914]]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.789275921450457, 35.5804973627026], + [23.79768732892116, 35.57972949300953], + [23.786357678042254, 35.579589879547086], + [23.798631466494403, 35.578577674666], + [23.78446940289577, 35.578752193661586], + [23.798502720461688, 35.577670169758946], + [23.78292445050319, 35.57791449901465], + [23.79210841193106, 35.5772866256402], + [23.79923228131374, 35.57651832180017]]), + { + "class": 1, + "system:index": "2" + })]), + sunglint = /* color: #f5a400 */ee.Geometry.MultiPolygon( + [[[[23.786748725416697, 35.55612383758693], + [23.786748725416697, 35.54634742800967], + [23.802541572096384, 35.54634742800967], + [23.802541572096384, 35.55612383758693]]], + [[[23.829664069654978, 35.550537463803785], + [23.829664069654978, 35.5441126527256], + [23.842710334303415, 35.5441126527256], + [23.842710334303415, 35.550537463803785]]], + [[[23.871206122877634, 35.547464792297085], + [23.871206122877634, 35.54271588654758], + [23.87978919172529, 35.54271588654758], + [23.87978919172529, 35.547464792297085]]]], null, false); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.2 Benthic Habitats +// Checkpoint: A22d +// Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1 +// Import and display satellite image. +var planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') + .divide(10000); + +Map.centerObject(planet, 12); +var visParams = { + bands: ['b3', 'b2', 'b1'], + min: 0.17, + max: 0.68, + gamma: 0.8 +}; +Map.addLayer({ + eeObject: planet, + visParams: visParams, + name: 'planet initial', + shown: true +}); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ + +// Section 2 +// Mask based to NDWI and RF. +function landmask(img) { + var ndwi = img.normalizedDifference(['b2', 'b4']); + var training = ndwi.sampleRegions(land.merge(water), ['class'], + 3); + var trained = ee.Classifier.smileRandomForest(10) + .train(training, 'class'); + var classified = ndwi.classify(trained); + var mask = classified.eq(1); + + return img.updateMask(mask); +} + +var maskedImg = landmask(planet); + +Map.addLayer(maskedImg, visParams, 'maskedImg', false); + +// Sun-glint correction. +function sunglintRemoval(img) { + var linearFit1 = img.select(['b4', 'b1']).reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + var linearFit2 = img.select(['b4', 'b2']).reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + var linearFit3 = img.select(['b4', 'b3']).reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + + var slopeImage = ee.Dictionary({ + 'b1': linearFit1.get('scale'), + 'b2': linearFit2.get('scale'), + 'b3': linearFit3.get('scale') + }).toImage(); + + var minNIR = img.select('b4').reduceRegion({ + reducer: ee.Reducer.min(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }).toImage(['b4']); + + return img.select(['b1', 'b2', 'b3']) + .subtract(slopeImage.multiply((img.select('b4')).subtract( + minNIR))) + .addBands(img.select('b4')); +} +var sgImg = sunglintRemoval(maskedImg); +Map.addLayer(sgImg, visParams, 'sgImg', false); + +// DIV procedure. +function kernel(img) { + var boxcar = ee.Kernel.square({ + radius: 2, + units: 'pixels', + normalize: true + }); + return img.convolve(boxcar); +} + +function makePositive(img) { + return img.where(img.lte(0), 0.0001); +} + +function div(img) { + var band1 = ee.List(['b1', 'b2', 'b3', 'b1', 'b2']); + var band2 = ee.List(['b3', 'b3', 'b2', 'b2', 'b1']); + var nband = ee.List(['b1b3', 'b2b3', 'b3b2', 'b1b2', 'b2b1']); + + for (var i = 0; i < 5; i += 1) { + var x = band1.get(i); + var y = band2.get(i); + var z = nband.get(i); + + var imageLog = img.select([x, y]).log(); + + var covariance = imageLog.toArray().reduceRegion({ + reducer: ee.Reducer.covariance(), + geometry: DIVsand, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + + var covarMatrix = ee.Array(covariance.get('array')); + var var1 = covarMatrix.get([0, 0]); + var var2 = covarMatrix.get([1, 1]); + var covar = covarMatrix.get([0, 1]); + + var a = var1.subtract(var2).divide(covar.multiply(2)); + var attenCoeffRatio = a.add(((a.pow(2)).add(1)).sqrt()); + + var depthInvariantIndex = img.expression( + 'image1 - (image2 * coeff)', { + 'image1': imageLog.select([x]), + 'image2': imageLog.select([y]), + 'coeff': attenCoeffRatio + }); + + img = ee.Image.cat([img, depthInvariantIndex.select([x], [ + z + ])]); + } + return img; +} + +var divImg = div(kernel(makePositive(sgImg))).select('b[1-3]', + 'b1b2'); +var vivVisParams = { + bands: ['b1b2'], + min: -0.81, + max: -0.04, + gamma: 0.75 +}; +Map.addLayer(divImg, vivVisParams, 'divImg', false); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ + +// Section 3, classification +// Import of reference data and split. +var softBottom = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/SoftBottom'); +var rockyBottom = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/RockyBottom'); +var pO = ee.FeatureCollection('projects/gee-book/assets/A2-2/PO'); + +var sand = ee.FeatureCollection.randomPoints(softBottom, 150).map( + function(s) { + return s.set('class', 0); + }).randomColumn(); +var sandT = sand.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'sand training'); +var sandV = sand.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'sand validation'); +Map.addLayer(sandT, { + color: 'yellow' +}, 'Sand Training', false); +Map.addLayer(sandV, { + color: 'yellow' +}, 'Sand Validation', false); + +var hard = ee.FeatureCollection.randomPoints(rockyBottom, 79).map( + function(s) { + return s.set('class', 1); + }).randomColumn(); +var hardT = hard.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'hard training'); +var hardV = hard.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'hard validation'); +Map.addLayer(hardT, { + color: 'red' +}, 'Rock Training', false); +Map.addLayer(hardV, { + color: 'red' +}, 'Rock Validation', false); + +var posi = pO.map(function(s) { + return s.set('class', 2); + }) + .randomColumn('random'); +var posiT = posi.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'posi training'); +var posiV = posi.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'posi validation'); +Map.addLayer(posiT, { + color: 'green' +}, 'Posidonia Training', false); +Map.addLayer(posiV, { + color: 'green' +}, 'Posidonia Validation', false); + +// Classification procedure. +function classify(img) { + var mergedT = ee.FeatureCollection([sandT, hardT, posiT]) + .flatten(); + var training = img.sampleRegions(mergedT, ['class'], 3); + var trained = ee.Classifier.libsvm({ + kernelType: 'RBF', + gamma: 1, + cost: 500 + }).train(training, 'class'); + var classified = img.classify(trained); + + var mergedV = ee.FeatureCollection([sandV, hardV, posiV]) + .flatten(); + var accuracyCol = classified.unmask().reduceRegions({ + collection: mergedV, + reducer: ee.Reducer.first(), + scale: 10 + }); + var classificationErrorMatrix = accuracyCol.errorMatrix({ + actual: 'class', + predicted: 'first', + order: [0, 1, 2] + }); + var classNames = ['soft_bot', 'hard_bot', 'seagrass']; + var accuracyOA = classificationErrorMatrix.accuracy(); + var accuraccyCons = ee.Dictionary.fromLists({ + keys: classNames, + values: classificationErrorMatrix.consumersAccuracy() + .toList() + .flatten() + }); + var accuracyProd = ee.Dictionary.fromLists({ + keys: classNames, + values: classificationErrorMatrix.producersAccuracy() + .toList() + .flatten() + }); + + var classificationErrormatrixArray = classificationErrorMatrix + .array(); + + var arrayToDatatable = function(array) { + var classesNames = ee.List(classNames); + + function toTableColumns(s) { + return { + id: s, + label: s, + type: 'number' + }; + } + var columns = classesNames.map(toTableColumns); + + function featureToTableRow(f) { + return { + c: ee.List(f).map(function(c) { + return { + v: c + }; + }) + }; + } + var rows = array.toList().map(featureToTableRow); + return ee.Dictionary({ + cols: columns, + rows: rows + }); + }; + + var dataTable = arrayToDatatable(classificationErrormatrixArray) + .evaluate(function(dataTable) { + print('------------- Error matrix -------------', + ui.Chart(dataTable, 'Table') + .setOptions({ + pageSize: 15 + }), + 'rows: reference, cols: mapped'); + }); + print('Overall Accuracy', accuracyOA); + print('Users accuracy', accuraccyCons); + print('Producers accuracy', accuracyProd); + return classified; +} + +var svmClassification = classify(divImg); +var svmVis = { + min: 0, + max: 2, + palette: ['ffffbf', 'fc8d59', '91cf60'] +}; +Map.addLayer(svmClassification, svmVis, 'classification'); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22d Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22d Checkpoint.py new file mode 100644 index 0000000..505e758 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22d Checkpoint.py @@ -0,0 +1,427 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +DIVsand = ee.Geometry.MultiPolygon( + [[[[23.85533614379952, 35.525671008126785], + [23.85808272583077, 35.52511217612521], + [23.860142662354207, 35.53880243984323], + [23.85653777343819, 35.539500860050644]]], + [[[23.783753349610066, 35.54863600968416], + [23.801091148682332, 35.55114998568017], + [23.799546196289754, 35.55464148823767], + [23.782723381348347, 35.551289648702024]]]]), +land = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.813750501438804, 35.53087476744296], + [23.834178205296226, 35.52696311538223], + [23.81306385593099, 35.53269082679277], + [23.836753125950523, 35.52863956104383], + [23.81684040622396, 35.53310991157428], + [23.835208173557945, 35.53073506886724], + [23.820273633763023, 35.53422746028901], + [23.83160328464193, 35.53324960601498]]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.77461170749349, 35.550849159238616], + [23.776328321263023, 35.53967528733693], + [23.791262861057945, 35.53478622880854], + [23.778044935032554, 35.540373699944034], + [23.775984998509117, 35.550988822784504], + [23.779589887425132, 35.5414911474658], + [23.792464490696617, 35.53646251101553], + [23.774783368870445, 35.543027612387064], + [23.777014966770835, 35.54959217637752], + [23.77667164401693, 35.53716095159702], + [23.79315113620443, 35.53855781451608]]), + { + "class": 0, + "system:index": "1" + })]), +water = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.815368450747332, 35.53525030188046], + [23.82712725506862, 35.538463126752895], + [23.813823498354754, 35.53629797630387], + [23.826955593691668, 35.53972028406574], + [23.813051022158465, 35.53720594973632], + [23.826268948183856, 35.54104726207508], + [23.81339434491237, 35.5381139128914], + [23.825582302676043, 35.54230437888493], + [23.81313685284694, 35.53951075921525], + [23.827213085757098, 35.53769485425075], + [23.823264874087176, 35.543421799507115]]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.93656138287624, 35.520162273141004], + [23.922656811343035, 35.52700811924147], + [23.939651287661395, 35.52114028690721], + [23.920596874819598, 35.529662473875746], + [23.938449658022723, 35.52379483562914]]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.789275921450457, 35.5804973627026], + [23.79768732892116, 35.57972949300953], + [23.786357678042254, 35.579589879547086], + [23.798631466494403, 35.578577674666], + [23.78446940289577, 35.578752193661586], + [23.798502720461688, 35.577670169758946], + [23.78292445050319, 35.57791449901465], + [23.79210841193106, 35.5772866256402], + [23.79923228131374, 35.57651832180017]]), + { + "class": 1, + "system:index": "2" + })]), +sunglint = ee.Geometry.MultiPolygon( + [[[[23.786748725416697, 35.55612383758693], + [23.786748725416697, 35.54634742800967], + [23.802541572096384, 35.54634742800967], + [23.802541572096384, 35.55612383758693]]], + [[[23.829664069654978, 35.550537463803785], + [23.829664069654978, 35.5441126527256], + [23.842710334303415, 35.5441126527256], + [23.842710334303415, 35.550537463803785]]], + [[[23.871206122877634, 35.547464792297085], + [23.871206122877634, 35.54271588654758], + [23.87978919172529, 35.54271588654758], + [23.87978919172529, 35.547464792297085]]]], None, False) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.2 Benthic Habitats +# Checkpoint: A22d +# Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1 +# Import and display satellite image. +planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \ + .divide(10000) + +Map.centerObject(planet, 12) +visParams = { + 'bands': ['b3', 'b2', 'b1'], + 'min': 0.17, + 'max': 0.68, + 'gamma': 0.8 +} +Map.addLayer({ + 'eeObject': planet, + 'visParams': visParams, + 'name': 'planet initial', + 'shown': True +}) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ + +# Section 2 +# Mask based to NDWI and RF. +def landmask(img): + ndwi = img.normalizedDifference(['b2', 'b4']) + training = ndwi.sampleRegions(land.merge(water), ['class'], + 3) + trained = ee.Classifier.smileRandomForest(10) \ + .train(training, 'class') + classified = ndwi.classify(trained) + mask = classified.eq(1) + + return img.updateMask(mask) + + +maskedImg = landmask(planet) + +Map.addLayer(maskedImg, visParams, 'maskedImg', False) + +# Sun-glint correction. +def sunglintRemoval(img): + linearFit1 = img.select(['b4', 'b1']).reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + linearFit2 = img.select(['b4', 'b2']).reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + linearFit3 = img.select(['b4', 'b3']).reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + + slopeImage = ee.Dictionary({ + 'b1': linearFit1.get('scale'), + 'b2': linearFit2.get('scale'), + 'b3': linearFit3.get('scale') + }).toImage() + + minNIR = img.select('b4').reduceRegion({ + 'reducer': ee.Reducer.min(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }).toImage(['b4']) + + return img.select(['b1', 'b2', 'b3']) \ + .subtract(slopeImage.multiply((img.select('b4')).subtract( + minNIR))) \ + .addBands(img.select('b4')) + +sgImg = sunglintRemoval(maskedImg) +Map.addLayer(sgImg, visParams, 'sgImg', False) + +# DIV procedure. +def kernel(img): + boxcar = ee.Kernel.square({ + 'radius': 2, + 'units': 'pixels', + 'normalize': True + }) + return img.convolve(boxcar) + + +def makePositive(img): + return img.where(img.lte(0), 0.0001) + + +def div(img): + band1 = ee.List(['b1', 'b2', 'b3', 'b1', 'b2']) + band2 = ee.List(['b3', 'b3', 'b2', 'b2', 'b1']) + nband = ee.List(['b1b3', 'b2b3', 'b3b2', 'b1b2', 'b2b1']) + + for i in range(0, 5, 1): + x = band1.get(i) + y = band2.get(i) + z = nband.get(i) + + imageLog = img.select([x, y]).log() + + covariance = imageLog.toArray().reduceRegion({ + 'reducer': ee.Reducer.covariance(), + 'geometry': DIVsand, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + + covarMatrix = ee.Array(covariance.get('array')) + var1 = covarMatrix.get([0, 0]) + var2 = covarMatrix.get([1, 1]) + covar = covarMatrix.get([0, 1]) + + a = var1.subtract(var2).divide(covar.multiply(2)) + attenCoeffRatio = a.add(((a.pow(2)).add(1)).sqrt()) + + depthInvariantIndex = img.expression( + 'image1 - (image2 * coeff)', { + 'image1': imageLog.select([x]), + 'image2': imageLog.select([y]), + 'coeff': attenCoeffRatio + }) + + img = ee.Image.cat([img, depthInvariantIndex.select([x], [ + z + ])]) + + return img + + +divImg = div(kernel(makePositive(sgImg))).select('b[1-3]', + 'b1b2') +vivVisParams = { + 'bands': ['b1b2'], + 'min': -0.81, + 'max': -0.04, + 'gamma': 0.75 +} +Map.addLayer(divImg, vivVisParams, 'divImg', False) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ + +# Section 3, classification +# Import of reference data and split. +softBottom = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/SoftBottom') +rockyBottom = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/RockyBottom') +pO = ee.FeatureCollection('projects/gee-book/assets/A2-2/PO') + +sand = ee.FeatureCollection.randomPoints(softBottom, 150).map( + def function(s): + return s.set('class', 0) + ).randomColumn() +sandT = sand.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'sand training') +sandV = sand.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'sand validation') +Map.addLayer(sandT, { + 'color': 'yellow' +}, 'Sand Training', False) +Map.addLayer(sandV, { + 'color': 'yellow' +}, 'Sand Validation', False) + +hard = ee.FeatureCollection.randomPoints(rockyBottom, 79).map( + def function(s): + return s.set('class', 1) + ).randomColumn() +hardT = hard.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'hard training') +hardV = hard.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'hard validation') +Map.addLayer(hardT, { + 'color': 'red' +}, 'Rock Training', False) +Map.addLayer(hardV, { + 'color': 'red' +}, 'Rock Validation', False) + + +def func_yru(s): + return s.set('class', 2) + +posi = pO.map(func_yru) \ + .randomColumn('random') +posiT = posi.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'posi training') +posiV = posi.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'posi validation') +Map.addLayer(posiT, { + 'color': 'green' +}, 'Posidonia Training', False) +Map.addLayer(posiV, { + 'color': 'green' +}, 'Posidonia Validation', False) + +# Classification procedure. +def classify(img): + mergedT = ee.FeatureCollection([sandT, hardT, posiT]) \ + .flatten() + training = img.sampleRegions(mergedT, ['class'], 3) + trained = ee.Classifier.libsvm({ + 'kernelType': 'RBF', + 'gamma': 1, + 'cost': 500 + }).train(training, 'class') + classified = img.classify(trained) + + mergedV = ee.FeatureCollection([sandV, hardV, posiV]) \ + .flatten() + accuracyCol = classified.unmask().reduceRegions({ + 'collection': mergedV, + 'reducer': ee.Reducer.first(), + 'scale': 10 + }) + classificationErrorMatrix = accuracyCol.errorMatrix({ + 'actual': 'class', + 'predicted': 'first', + 'order': [0, 1, 2] + }) + classNames = ['soft_bot', 'hard_bot', 'seagrass'] + accuracyOA = classificationErrorMatrix.accuracy() + accuraccyCons = ee.Dictionary.fromLists({ + 'keys': classNames, + 'values': classificationErrorMatrix.consumersAccuracy() \ + .toList() \ + .flatten() + }) + accuracyProd = ee.Dictionary.fromLists({ + 'keys': classNames, + 'values': classificationErrorMatrix.producersAccuracy() \ + .toList() \ + .flatten() + }) + + classificationErrormatrixArray = classificationErrorMatrix \ + .array() + + def arrayToDatatable(array): + classesNames = ee.List(classNames) + + def toTableColumns(s): + return { + 'id': s, + 'label': s, + 'type': 'number' + } + + columns = classesNames.map(toTableColumns) + + def featureToTableRow(f): + return { + +def func_gsk(c): + return { + 'v': c + } + + 'c': ee.List(f).map(func_gsk) + + + + + + } + + rows = array.toList().map(featureToTableRow) + return ee.Dictionary({ + 'cols': columns, + 'rows': rows + }) + + + dataTable = arrayToDatatable(classificationErrormatrixArray) \ + .evaluate(function(dataTable) { + print('------------- Error matrix -------------', + ui.Chart(dataTable, 'Table') \ + .setOptions({ + 'pageSize': 15 + }), + 'rows: reference, 'cols': mapped') + }) + print('Overall Accuracy', accuracyOA) + print('Users accuracy', accuraccyCons) + print('Producers accuracy', accuracyProd) + return classified + + +svmClassification = classify(divImg) +svmVis = { + 'min': 0, + 'max': 2, + 'palette': ['ffffbf', 'fc8d59', '91cf60'] +} +Map.addLayer(svmClassification, svmVis, 'classification') + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22e Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22e Checkpoint.ipynb new file mode 100644 index 0000000..5ec78f7 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22e Checkpoint.ipynb @@ -0,0 +1,611 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "DIVsand = ee.Geometry.MultiPolygon(\n", + " [[[[23.85533614379952, 35.525671008126785],\n", + " [23.85808272583077, 35.52511217612521],\n", + " [23.860142662354207, 35.53880243984323],\n", + " [23.85653777343819, 35.539500860050644]]],\n", + " [[[23.783753349610066, 35.54863600968416],\n", + " [23.801091148682332, 35.55114998568017],\n", + " [23.799546196289754, 35.55464148823767],\n", + " [23.782723381348347, 35.551289648702024]]]]),\n", + "land = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.813750501438804, 35.53087476744296],\n", + " [23.834178205296226, 35.52696311538223],\n", + " [23.81306385593099, 35.53269082679277],\n", + " [23.836753125950523, 35.52863956104383],\n", + " [23.81684040622396, 35.53310991157428],\n", + " [23.835208173557945, 35.53073506886724],\n", + " [23.820273633763023, 35.53422746028901],\n", + " [23.83160328464193, 35.53324960601498]]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.77461170749349, 35.550849159238616],\n", + " [23.776328321263023, 35.53967528733693],\n", + " [23.791262861057945, 35.53478622880854],\n", + " [23.778044935032554, 35.540373699944034],\n", + " [23.775984998509117, 35.550988822784504],\n", + " [23.779589887425132, 35.5414911474658],\n", + " [23.792464490696617, 35.53646251101553],\n", + " [23.774783368870445, 35.543027612387064],\n", + " [23.777014966770835, 35.54959217637752],\n", + " [23.77667164401693, 35.53716095159702],\n", + " [23.79315113620443, 35.53855781451608]]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " })]),\n", + "water = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.815368450747332, 35.53525030188046],\n", + " [23.82712725506862, 35.538463126752895],\n", + " [23.813823498354754, 35.53629797630387],\n", + " [23.826955593691668, 35.53972028406574],\n", + " [23.813051022158465, 35.53720594973632],\n", + " [23.826268948183856, 35.54104726207508],\n", + " [23.81339434491237, 35.5381139128914],\n", + " [23.825582302676043, 35.54230437888493],\n", + " [23.81313685284694, 35.53951075921525],\n", + " [23.827213085757098, 35.53769485425075],\n", + " [23.823264874087176, 35.543421799507115]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.93656138287624, 35.520162273141004],\n", + " [23.922656811343035, 35.52700811924147],\n", + " [23.939651287661395, 35.52114028690721],\n", + " [23.920596874819598, 35.529662473875746],\n", + " [23.938449658022723, 35.52379483562914]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.LineString(\n", + " [[23.789275921450457, 35.5804973627026],\n", + " [23.79768732892116, 35.57972949300953],\n", + " [23.786357678042254, 35.579589879547086],\n", + " [23.798631466494403, 35.578577674666],\n", + " [23.78446940289577, 35.578752193661586],\n", + " [23.798502720461688, 35.577670169758946],\n", + " [23.78292445050319, 35.57791449901465],\n", + " [23.79210841193106, 35.5772866256402],\n", + " [23.79923228131374, 35.57651832180017]]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " })]),\n", + "sunglint = ee.Geometry.MultiPolygon(\n", + " [[[[23.786748725416697, 35.55612383758693],\n", + " [23.786748725416697, 35.54634742800967],\n", + " [23.802541572096384, 35.54634742800967],\n", + " [23.802541572096384, 35.55612383758693]]],\n", + " [[[23.829664069654978, 35.550537463803785],\n", + " [23.829664069654978, 35.5441126527256],\n", + " [23.842710334303415, 35.5441126527256],\n", + " [23.842710334303415, 35.550537463803785]]],\n", + " [[[23.871206122877634, 35.547464792297085],\n", + " [23.871206122877634, 35.54271588654758],\n", + " [23.87978919172529, 35.54271588654758],\n", + " [23.87978919172529, 35.547464792297085]]]], None, False)\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.2 Benthic Habitats\n", + "# Checkpoint: A22e\n", + "# Authors: Dimitris Poursanidis, Aur\u00e9lie C. Shapiro, Spyros Christofilakos\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Section 1\n", + "# Import and display satellite image.\n", + "planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \\\n", + " .divide(10000)\n", + "\n", + "Map.centerObject(planet, 12)\n", + "visParams = {\n", + " 'bands': ['b3', 'b2', 'b1'],\n", + " 'min': 0.17,\n", + " 'max': 0.68,\n", + " 'gamma': 0.8\n", + "}\n", + "Map.addLayer({\n", + " 'eeObject': planet,\n", + " 'visParams': visParams,\n", + " 'name': 'planet initial',\n", + " 'shown': True\n", + "})\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------\n", + "\n", + "# Section 2\n", + "# Mask based to NDWI and RF.\n", + "def landmask(img):\n", + " ndwi = img.normalizedDifference(['b2', 'b4'])\n", + " training = ndwi.sampleRegions(land.merge(water), ['class'],\n", + " 3)\n", + " trained = ee.Classifier.smileRandomForest(10) \\\n", + " .train(training, 'class')\n", + " classified = ndwi.classify(trained)\n", + " mask = classified.eq(1)\n", + "\n", + " return img.updateMask(mask)\n", + "\n", + "\n", + "maskedImg = landmask(planet)\n", + "\n", + "Map.addLayer(maskedImg, visParams, 'maskedImg', False)\n", + "\n", + "# Sun-glint correction.\n", + "def sunglintRemoval(img):\n", + " linearFit1 = img.select(['b4', 'b1']).reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + " linearFit2 = img.select(['b4', 'b2']).reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + " linearFit3 = img.select(['b4', 'b3']).reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + "\n", + " slopeImage = ee.Dictionary({\n", + " 'b1': linearFit1.get('scale'),\n", + " 'b2': linearFit2.get('scale'),\n", + " 'b3': linearFit3.get('scale')\n", + " }).toImage()\n", + "\n", + " minNIR = img.select('b4').reduceRegion({\n", + " 'reducer': ee.Reducer.min(),\n", + " 'geometry': sunglint,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " }).toImage(['b4'])\n", + "\n", + " return img.select(['b1', 'b2', 'b3']) \\\n", + " .subtract(slopeImage.multiply((img.select('b4')).subtract(\n", + " minNIR))) \\\n", + " .addBands(img.select('b4'))\n", + "\n", + "sgImg = sunglintRemoval(maskedImg)\n", + "Map.addLayer(sgImg, visParams, 'sgImg', False)\n", + "\n", + "# DIV procedure.\n", + "def kernel(img):\n", + " boxcar = ee.Kernel.square({\n", + " 'radius': 2,\n", + " 'units': 'pixels',\n", + " 'normalize': True\n", + " })\n", + " return img.convolve(boxcar)\n", + "\n", + "\n", + "def makePositive(img):\n", + " return img.where(img.lte(0), 0.0001)\n", + "\n", + "\n", + "def div(img):\n", + " band1 = ee.List(['b1', 'b2', 'b3', 'b1', 'b2'])\n", + " band2 = ee.List(['b3', 'b3', 'b2', 'b2', 'b1'])\n", + " nband = ee.List(['b1b3', 'b2b3', 'b3b2', 'b1b2', 'b2b1'])\n", + "\n", + " for i in range(0, 5, 1):\n", + " x = band1.get(i)\n", + " y = band2.get(i)\n", + " z = nband.get(i)\n", + "\n", + " imageLog = img.select([x, y]).log()\n", + "\n", + " covariance = imageLog.toArray().reduceRegion({\n", + " 'reducer': ee.Reducer.covariance(),\n", + " 'geometry': DIVsand,\n", + " 'scale': 3,\n", + " 'maxPixels': 1e12,\n", + " 'bestEffort': True,\n", + " })\n", + "\n", + " covarMatrix = ee.Array(covariance.get('array'))\n", + " var1 = covarMatrix.get([0, 0])\n", + " var2 = covarMatrix.get([1, 1])\n", + " covar = covarMatrix.get([0, 1])\n", + "\n", + " a = var1.subtract(var2).divide(covar.multiply(2))\n", + " attenCoeffRatio = a.add(((a.pow(2)).add(1)).sqrt())\n", + "\n", + " depthInvariantIndex = img.expression(\n", + " 'image1 - (image2 * coeff)', {\n", + " 'image1': imageLog.select([x]),\n", + " 'image2': imageLog.select([y]),\n", + " 'coeff': attenCoeffRatio\n", + " })\n", + "\n", + " img = ee.Image.cat([img, depthInvariantIndex.select([x], [\n", + " z\n", + " ])])\n", + "\n", + " return img\n", + "\n", + "\n", + "divImg = div(kernel(makePositive(sgImg))).select('b[1-3]',\n", + " 'b1b2')\n", + "vivVisParams = {\n", + " 'bands': ['b1b2'],\n", + " 'min': -0.81,\n", + " 'max': -0.04,\n", + " 'gamma': 0.75\n", + "}\n", + "Map.addLayer(divImg, vivVisParams, 'divImg', False)\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------\n", + "\n", + "# Section 3, classification\n", + "# Import of reference data and split.\n", + "softBottom = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-2/SoftBottom')\n", + "rockyBottom = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-2/RockyBottom')\n", + "pO = ee.FeatureCollection('projects/gee-book/assets/A2-2/PO')\n", + "\n", + "sand = ee.FeatureCollection.randomPoints(softBottom, 150).map(\n", + " def function(s):\n", + " return s.set('class', 0)\n", + " ).randomColumn()\n", + "sandT = sand.filter(ee.Filter.lte('random', 0.7)).aside(print,\n", + " 'sand training')\n", + "sandV = sand.filter(ee.Filter.gt('random', 0.7)).aside(print,\n", + " 'sand validation')\n", + "Map.addLayer(sandT, {\n", + " 'color': 'yellow'\n", + "}, 'Sand Training', False)\n", + "Map.addLayer(sandV, {\n", + " 'color': 'yellow'\n", + "}, 'Sand Validation', False)\n", + "\n", + "hard = ee.FeatureCollection.randomPoints(rockyBottom, 79).map(\n", + " def function(s):\n", + " return s.set('class', 1)\n", + " ).randomColumn()\n", + "hardT = hard.filter(ee.Filter.lte('random', 0.7)).aside(print,\n", + " 'hard training')\n", + "hardV = hard.filter(ee.Filter.gt('random', 0.7)).aside(print,\n", + " 'hard validation')\n", + "Map.addLayer(hardT, {\n", + " 'color': 'red'\n", + "}, 'Rock Training', False)\n", + "Map.addLayer(hardV, {\n", + " 'color': 'red'\n", + "}, 'Rock Validation', False)\n", + "\n", + "\n", + "def func_pym(s):\n", + " return s.set('class', 2)\n", + "\n", + "posi = pO.map(func_pym) \\\n", + " .randomColumn('random')\n", + "posiT = posi.filter(ee.Filter.lte('random', 0.7)).aside(print,\n", + " 'posi training')\n", + "posiV = posi.filter(ee.Filter.gt('random', 0.7)).aside(print,\n", + " 'posi validation')\n", + "Map.addLayer(posiT, {\n", + " 'color': 'green'\n", + "}, 'Posidonia Training', False)\n", + "Map.addLayer(posiV, {\n", + " 'color': 'green'\n", + "}, 'Posidonia Validation', False)\n", + "\n", + "# Classification procedure.\n", + "def classify(img):\n", + " mergedT = ee.FeatureCollection([sandT, hardT, posiT]) \\\n", + " .flatten()\n", + " training = img.sampleRegions(mergedT, ['class'], 3)\n", + " trained = ee.Classifier.libsvm({\n", + " 'kernelType': 'RBF',\n", + " 'gamma': 1,\n", + " 'cost': 500\n", + " }).train(training, 'class')\n", + " classified = img.classify(trained)\n", + "\n", + " mergedV = ee.FeatureCollection([sandV, hardV, posiV]) \\\n", + " .flatten()\n", + " accuracyCol = classified.unmask().reduceRegions({\n", + " 'collection': mergedV,\n", + " 'reducer': ee.Reducer.first(),\n", + " 'scale': 10\n", + " })\n", + " classificationErrorMatrix = accuracyCol.errorMatrix({\n", + " 'actual': 'class',\n", + " 'predicted': 'first',\n", + " 'order': [0, 1, 2]\n", + " })\n", + " classNames = ['soft_bot', 'hard_bot', 'seagrass']\n", + " accuracyOA = classificationErrorMatrix.accuracy()\n", + " accuraccyCons = ee.Dictionary.fromLists({\n", + " 'keys': classNames,\n", + " 'values': classificationErrorMatrix.consumersAccuracy() \\\n", + " .toList() \\\n", + " .flatten()\n", + " })\n", + " accuracyProd = ee.Dictionary.fromLists({\n", + " 'keys': classNames,\n", + " 'values': classificationErrorMatrix.producersAccuracy() \\\n", + " .toList() \\\n", + " .flatten()\n", + " })\n", + "\n", + " classificationErrormatrixArray = classificationErrorMatrix \\\n", + " .array()\n", + "\n", + " def arrayToDatatable(array):\n", + " classesNames = ee.List(classNames)\n", + "\n", + " def toTableColumns(s):\n", + " return {\n", + " 'id': s,\n", + " 'label': s,\n", + " 'type': 'number'\n", + " }\n", + "\n", + " columns = classesNames.map(toTableColumns)\n", + "\n", + " def featureToTableRow(f):\n", + " return {\n", + "\n", + "def func_zns(c):\n", + " return {\n", + " 'v': c\n", + " }\n", + "\n", + " 'c': ee.List(f).map(func_zns)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " }\n", + "\n", + " rows = array.toList().map(featureToTableRow)\n", + " return ee.Dictionary({\n", + " 'cols': columns,\n", + " 'rows': rows\n", + " })\n", + " \n", + "\n", + " dataTable = arrayToDatatable(classificationErrormatrixArray) \\\n", + " .evaluate(function(dataTable) {\n", + " print('------------- Error matrix -------------',\n", + " ui.Chart(dataTable, 'Table') \\\n", + " .setOptions({\n", + " 'pageSize': 15\n", + " }),\n", + " 'rows: reference, 'cols': mapped')\n", + " })\n", + " print('Overall Accuracy', accuracyOA)\n", + " print('Users accuracy', accuraccyCons)\n", + " print('Producers accuracy', accuracyProd)\n", + " return classified\n", + "\n", + "\n", + "svmClassification = classify(divImg)\n", + "svmVis = {\n", + " 'min': 0,\n", + " 'max': 2,\n", + " 'palette': ['ffffbf', 'fc8d59', '91cf60']\n", + "}\n", + "Map.addLayer(svmClassification, svmVis, 'classification')\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------\n", + "\n", + "# Section 4, Bathymetry\n", + "# Import and split training and validation data for the bathymetry.\n", + "depth = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-2/DepthDataTill09072020_v2')\n", + "depth = depth.randomColumn()\n", + "depthT = depth.filter(ee.Filter.lte('random', 0.7))\n", + "depthV = depth.filter(ee.Filter.gt('random', 0.7))\n", + "Map.addLayer(depthT, {\n", + " 'color': 'black'\n", + "}, 'Depth Training', False)\n", + "Map.addLayer(depthV, {\n", + " 'color': 'gray'\n", + "}, 'Depth Validation', False)\n", + "\n", + "def vector2image(vector):\n", + " rasterisedVectorData = vector \\\n", + " .filter(ee.Filter.neq('Depth',\n", + " None)) # Filter out NA depth values. \\\n", + " .reduceToImage({\n", + " 'properties': ['Depth'],\n", + " 'reducer': ee.Reducer.mean()\n", + " })\n", + " return (rasterisedVectorData)\n", + "\n", + "\n", + "depthTImage = vector2image(depthT) \\\n", + " .aside(Map.addLayer, {\n", + " 'color': 'white'\n", + " }, 'Depth Training2', False)\n", + "depthVImage = vector2image(depthV) \\\n", + " .aside(Map.addLayer, {\n", + " 'color': 'white'\n", + " }, 'Depth Validation2', False)\n", + "\n", + "def rfbathymetry(img):\n", + " training = img.sampleRegions({\n", + " 'collection': depthT,\n", + " 'scale': 3\n", + " })\n", + "\n", + " regclass = ee.Classifier.smileRandomForest(15) \\\n", + " .train(training, 'Depth')\n", + " bathyClass = img \\\n", + " .classify(regclass.setOutputMode('REGRESSION')).rename(\n", + " 'Depth')\n", + "\n", + " sdbEstimate = bathyClass.clip(depthV)\n", + "\n", + " # Prepare data by putting SDB estimated data and in situ data\n", + " # in one image to compare them afterwards.\n", + " imageI = ee.Image.cat([sdbEstimate, depthVImage])\n", + " # Calculate covariance.\n", + " covariance = imageI.toArray().reduceRegion({\n", + " 'reducer': ee.Reducer.covariance(),\n", + " 'geometry': depthV,\n", + " 'scale': 3,\n", + " 'bestEffort': True,\n", + " 'maxPixels': 1e9\n", + " })\n", + " covarMatrix = ee.Array(covariance.get('array'))\n", + "\n", + " rSqr = covarMatrix.get([0, 1]).pow(2) \\\n", + " .divide(covarMatrix.get([0, 0]) \\\n", + " .multiply(covarMatrix.get([1, 1])))\n", + "\n", + " deviation = depthVImage.select('mean') \\\n", + " .subtract(sdbEstimate.select('Depth')).pow(2)\n", + "\n", + " rmse = ee.Number(deviation.reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': depthV,\n", + " 'scale': 3,\n", + " 'bestEffort': True,\n", + " 'maxPixels': 1e12\n", + " }).get('mean')) \\\n", + " .sqrt()\n", + "\n", + " # Print together, so that they appear in the same output.\n", + " print('R\u00b2', rSqr, 'RMSE', rmse)\n", + "\n", + " return bathyClass\n", + "\n", + "\n", + "rfBathymetry = rfbathymetry(divImg)\n", + "bathyVis = {\n", + " 'min': -50,\n", + " 'max': 0,\n", + " 'palette': ['084594', '2171b5', '4292c6', '6baed6',\n", + " '9ecae1', 'c6dbef', 'deebf7', 'f7fbff'\n", + " ]\n", + "}\n", + "Map.addLayer(rfBathymetry, bathyVis, 'bathymetry')\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22e Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22e Checkpoint.js new file mode 100644 index 0000000..cf4d8fd --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22e Checkpoint.js @@ -0,0 +1,509 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var DIVsand = /* color: #fbff00 */ee.Geometry.MultiPolygon( + [[[[23.85533614379952, 35.525671008126785], + [23.85808272583077, 35.52511217612521], + [23.860142662354207, 35.53880243984323], + [23.85653777343819, 35.539500860050644]]], + [[[23.783753349610066, 35.54863600968416], + [23.801091148682332, 35.55114998568017], + [23.799546196289754, 35.55464148823767], + [23.782723381348347, 35.551289648702024]]]]), + land = /* color: #ff0000 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.813750501438804, 35.53087476744296], + [23.834178205296226, 35.52696311538223], + [23.81306385593099, 35.53269082679277], + [23.836753125950523, 35.52863956104383], + [23.81684040622396, 35.53310991157428], + [23.835208173557945, 35.53073506886724], + [23.820273633763023, 35.53422746028901], + [23.83160328464193, 35.53324960601498]]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.77461170749349, 35.550849159238616], + [23.776328321263023, 35.53967528733693], + [23.791262861057945, 35.53478622880854], + [23.778044935032554, 35.540373699944034], + [23.775984998509117, 35.550988822784504], + [23.779589887425132, 35.5414911474658], + [23.792464490696617, 35.53646251101553], + [23.774783368870445, 35.543027612387064], + [23.777014966770835, 35.54959217637752], + [23.77667164401693, 35.53716095159702], + [23.79315113620443, 35.53855781451608]]), + { + "class": 0, + "system:index": "1" + })]), + water = /* color: #0d9ad6 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.815368450747332, 35.53525030188046], + [23.82712725506862, 35.538463126752895], + [23.813823498354754, 35.53629797630387], + [23.826955593691668, 35.53972028406574], + [23.813051022158465, 35.53720594973632], + [23.826268948183856, 35.54104726207508], + [23.81339434491237, 35.5381139128914], + [23.825582302676043, 35.54230437888493], + [23.81313685284694, 35.53951075921525], + [23.827213085757098, 35.53769485425075], + [23.823264874087176, 35.543421799507115]]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.93656138287624, 35.520162273141004], + [23.922656811343035, 35.52700811924147], + [23.939651287661395, 35.52114028690721], + [23.920596874819598, 35.529662473875746], + [23.938449658022723, 35.52379483562914]]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.789275921450457, 35.5804973627026], + [23.79768732892116, 35.57972949300953], + [23.786357678042254, 35.579589879547086], + [23.798631466494403, 35.578577674666], + [23.78446940289577, 35.578752193661586], + [23.798502720461688, 35.577670169758946], + [23.78292445050319, 35.57791449901465], + [23.79210841193106, 35.5772866256402], + [23.79923228131374, 35.57651832180017]]), + { + "class": 1, + "system:index": "2" + })]), + sunglint = /* color: #f5a400 */ee.Geometry.MultiPolygon( + [[[[23.786748725416697, 35.55612383758693], + [23.786748725416697, 35.54634742800967], + [23.802541572096384, 35.54634742800967], + [23.802541572096384, 35.55612383758693]]], + [[[23.829664069654978, 35.550537463803785], + [23.829664069654978, 35.5441126527256], + [23.842710334303415, 35.5441126527256], + [23.842710334303415, 35.550537463803785]]], + [[[23.871206122877634, 35.547464792297085], + [23.871206122877634, 35.54271588654758], + [23.87978919172529, 35.54271588654758], + [23.87978919172529, 35.547464792297085]]]], null, false); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.2 Benthic Habitats +// Checkpoint: A22e +// Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Section 1 +// Import and display satellite image. +var planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') + .divide(10000); + +Map.centerObject(planet, 12); +var visParams = { + bands: ['b3', 'b2', 'b1'], + min: 0.17, + max: 0.68, + gamma: 0.8 +}; +Map.addLayer({ + eeObject: planet, + visParams: visParams, + name: 'planet initial', + shown: true +}); +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ + +// Section 2 +// Mask based to NDWI and RF. +function landmask(img) { + var ndwi = img.normalizedDifference(['b2', 'b4']); + var training = ndwi.sampleRegions(land.merge(water), ['class'], + 3); + var trained = ee.Classifier.smileRandomForest(10) + .train(training, 'class'); + var classified = ndwi.classify(trained); + var mask = classified.eq(1); + + return img.updateMask(mask); +} + +var maskedImg = landmask(planet); + +Map.addLayer(maskedImg, visParams, 'maskedImg', false); + +// Sun-glint correction. +function sunglintRemoval(img) { + var linearFit1 = img.select(['b4', 'b1']).reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + var linearFit2 = img.select(['b4', 'b2']).reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + var linearFit3 = img.select(['b4', 'b3']).reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + + var slopeImage = ee.Dictionary({ + 'b1': linearFit1.get('scale'), + 'b2': linearFit2.get('scale'), + 'b3': linearFit3.get('scale') + }).toImage(); + + var minNIR = img.select('b4').reduceRegion({ + reducer: ee.Reducer.min(), + geometry: sunglint, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }).toImage(['b4']); + + return img.select(['b1', 'b2', 'b3']) + .subtract(slopeImage.multiply((img.select('b4')).subtract( + minNIR))) + .addBands(img.select('b4')); +} +var sgImg = sunglintRemoval(maskedImg); +Map.addLayer(sgImg, visParams, 'sgImg', false); + +// DIV procedure. +function kernel(img) { + var boxcar = ee.Kernel.square({ + radius: 2, + units: 'pixels', + normalize: true + }); + return img.convolve(boxcar); +} + +function makePositive(img) { + return img.where(img.lte(0), 0.0001); +} + +function div(img) { + var band1 = ee.List(['b1', 'b2', 'b3', 'b1', 'b2']); + var band2 = ee.List(['b3', 'b3', 'b2', 'b2', 'b1']); + var nband = ee.List(['b1b3', 'b2b3', 'b3b2', 'b1b2', 'b2b1']); + + for (var i = 0; i < 5; i += 1) { + var x = band1.get(i); + var y = band2.get(i); + var z = nband.get(i); + + var imageLog = img.select([x, y]).log(); + + var covariance = imageLog.toArray().reduceRegion({ + reducer: ee.Reducer.covariance(), + geometry: DIVsand, + scale: 3, + maxPixels: 1e12, + bestEffort: true, + }); + + var covarMatrix = ee.Array(covariance.get('array')); + var var1 = covarMatrix.get([0, 0]); + var var2 = covarMatrix.get([1, 1]); + var covar = covarMatrix.get([0, 1]); + + var a = var1.subtract(var2).divide(covar.multiply(2)); + var attenCoeffRatio = a.add(((a.pow(2)).add(1)).sqrt()); + + var depthInvariantIndex = img.expression( + 'image1 - (image2 * coeff)', { + 'image1': imageLog.select([x]), + 'image2': imageLog.select([y]), + 'coeff': attenCoeffRatio + }); + + img = ee.Image.cat([img, depthInvariantIndex.select([x], [ + z + ])]); + } + return img; +} + +var divImg = div(kernel(makePositive(sgImg))).select('b[1-3]', + 'b1b2'); +var vivVisParams = { + bands: ['b1b2'], + min: -0.81, + max: -0.04, + gamma: 0.75 +}; +Map.addLayer(divImg, vivVisParams, 'divImg', false); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ + +// Section 3, classification +// Import of reference data and split. +var softBottom = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/SoftBottom'); +var rockyBottom = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/RockyBottom'); +var pO = ee.FeatureCollection('projects/gee-book/assets/A2-2/PO'); + +var sand = ee.FeatureCollection.randomPoints(softBottom, 150).map( + function(s) { + return s.set('class', 0); + }).randomColumn(); +var sandT = sand.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'sand training'); +var sandV = sand.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'sand validation'); +Map.addLayer(sandT, { + color: 'yellow' +}, 'Sand Training', false); +Map.addLayer(sandV, { + color: 'yellow' +}, 'Sand Validation', false); + +var hard = ee.FeatureCollection.randomPoints(rockyBottom, 79).map( + function(s) { + return s.set('class', 1); + }).randomColumn(); +var hardT = hard.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'hard training'); +var hardV = hard.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'hard validation'); +Map.addLayer(hardT, { + color: 'red' +}, 'Rock Training', false); +Map.addLayer(hardV, { + color: 'red' +}, 'Rock Validation', false); + +var posi = pO.map(function(s) { + return s.set('class', 2); + }) + .randomColumn('random'); +var posiT = posi.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'posi training'); +var posiV = posi.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'posi validation'); +Map.addLayer(posiT, { + color: 'green' +}, 'Posidonia Training', false); +Map.addLayer(posiV, { + color: 'green' +}, 'Posidonia Validation', false); + +// Classification procedure. +function classify(img) { + var mergedT = ee.FeatureCollection([sandT, hardT, posiT]) + .flatten(); + var training = img.sampleRegions(mergedT, ['class'], 3); + var trained = ee.Classifier.libsvm({ + kernelType: 'RBF', + gamma: 1, + cost: 500 + }).train(training, 'class'); + var classified = img.classify(trained); + + var mergedV = ee.FeatureCollection([sandV, hardV, posiV]) + .flatten(); + var accuracyCol = classified.unmask().reduceRegions({ + collection: mergedV, + reducer: ee.Reducer.first(), + scale: 10 + }); + var classificationErrorMatrix = accuracyCol.errorMatrix({ + actual: 'class', + predicted: 'first', + order: [0, 1, 2] + }); + var classNames = ['soft_bot', 'hard_bot', 'seagrass']; + var accuracyOA = classificationErrorMatrix.accuracy(); + var accuraccyCons = ee.Dictionary.fromLists({ + keys: classNames, + values: classificationErrorMatrix.consumersAccuracy() + .toList() + .flatten() + }); + var accuracyProd = ee.Dictionary.fromLists({ + keys: classNames, + values: classificationErrorMatrix.producersAccuracy() + .toList() + .flatten() + }); + + var classificationErrormatrixArray = classificationErrorMatrix + .array(); + + var arrayToDatatable = function(array) { + var classesNames = ee.List(classNames); + + function toTableColumns(s) { + return { + id: s, + label: s, + type: 'number' + }; + } + var columns = classesNames.map(toTableColumns); + + function featureToTableRow(f) { + return { + c: ee.List(f).map(function(c) { + return { + v: c + }; + }) + }; + } + var rows = array.toList().map(featureToTableRow); + return ee.Dictionary({ + cols: columns, + rows: rows + }); + }; + + var dataTable = arrayToDatatable(classificationErrormatrixArray) + .evaluate(function(dataTable) { + print('------------- Error matrix -------------', + ui.Chart(dataTable, 'Table') + .setOptions({ + pageSize: 15 + }), + 'rows: reference, cols: mapped'); + }); + print('Overall Accuracy', accuracyOA); + print('Users accuracy', accuraccyCons); + print('Producers accuracy', accuracyProd); + return classified; +} + +var svmClassification = classify(divImg); +var svmVis = { + min: 0, + max: 2, + palette: ['ffffbf', 'fc8d59', '91cf60'] +}; +Map.addLayer(svmClassification, svmVis, 'classification'); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ + +// Section 4, Bathymetry +// Import and split training and validation data for the bathymetry. +var depth = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/DepthDataTill09072020_v2'); +depth = depth.randomColumn(); +var depthT = depth.filter(ee.Filter.lte('random', 0.7)); +var depthV = depth.filter(ee.Filter.gt('random', 0.7)); +Map.addLayer(depthT, { + color: 'black' +}, 'Depth Training', false); +Map.addLayer(depthV, { + color: 'gray' +}, 'Depth Validation', false); + +function vector2image(vector) { + var rasterisedVectorData = vector + .filter(ee.Filter.neq('Depth', + null)) // Filter out NA depth values. + .reduceToImage({ + properties: ['Depth'], + reducer: ee.Reducer.mean() + }); + return (rasterisedVectorData); +} + +var depthTImage = vector2image(depthT) + .aside(Map.addLayer, { + color: 'white' + }, 'Depth Training2', false); +var depthVImage = vector2image(depthV) + .aside(Map.addLayer, { + color: 'white' + }, 'Depth Validation2', false); + +function rfbathymetry(img) { + var training = img.sampleRegions({ + collection: depthT, + scale: 3 + }); + + var regclass = ee.Classifier.smileRandomForest(15) + .train(training, 'Depth'); + var bathyClass = img + .classify(regclass.setOutputMode('REGRESSION')).rename( + 'Depth'); + + var sdbEstimate = bathyClass.clip(depthV); + + // Prepare data by putting SDB estimated data and in situ data + // in one image to compare them afterwards. + var imageI = ee.Image.cat([sdbEstimate, depthVImage]); + // Calculate covariance. + var covariance = imageI.toArray().reduceRegion({ + reducer: ee.Reducer.covariance(), + geometry: depthV, + scale: 3, + bestEffort: true, + maxPixels: 1e9 + }); + var covarMatrix = ee.Array(covariance.get('array')); + + var rSqr = covarMatrix.get([0, 1]).pow(2) + .divide(covarMatrix.get([0, 0]) + .multiply(covarMatrix.get([1, 1]))); + + var deviation = depthVImage.select('mean') + .subtract(sdbEstimate.select('Depth')).pow(2); + + var rmse = ee.Number(deviation.reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: depthV, + scale: 3, + bestEffort: true, + maxPixels: 1e12 + }).get('mean')) + .sqrt(); + + // Print together, so that they appear in the same output. + print('R²', rSqr, 'RMSE', rmse); + + return bathyClass; +} + +var rfBathymetry = rfbathymetry(divImg); +var bathyVis = { + min: -50, + max: 0, + palette: ['084594', '2171b5', '4292c6', '6baed6', + '9ecae1', 'c6dbef', 'deebf7', 'f7fbff' + ] +}; +Map.addLayer(rfBathymetry, bathyVis, 'bathymetry'); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22e Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22e Checkpoint.py new file mode 100644 index 0000000..9dbecaf --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.2 Benthic Habitats/A22e Checkpoint.py @@ -0,0 +1,524 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +DIVsand = ee.Geometry.MultiPolygon( + [[[[23.85533614379952, 35.525671008126785], + [23.85808272583077, 35.52511217612521], + [23.860142662354207, 35.53880243984323], + [23.85653777343819, 35.539500860050644]]], + [[[23.783753349610066, 35.54863600968416], + [23.801091148682332, 35.55114998568017], + [23.799546196289754, 35.55464148823767], + [23.782723381348347, 35.551289648702024]]]]), +land = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.813750501438804, 35.53087476744296], + [23.834178205296226, 35.52696311538223], + [23.81306385593099, 35.53269082679277], + [23.836753125950523, 35.52863956104383], + [23.81684040622396, 35.53310991157428], + [23.835208173557945, 35.53073506886724], + [23.820273633763023, 35.53422746028901], + [23.83160328464193, 35.53324960601498]]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.77461170749349, 35.550849159238616], + [23.776328321263023, 35.53967528733693], + [23.791262861057945, 35.53478622880854], + [23.778044935032554, 35.540373699944034], + [23.775984998509117, 35.550988822784504], + [23.779589887425132, 35.5414911474658], + [23.792464490696617, 35.53646251101553], + [23.774783368870445, 35.543027612387064], + [23.777014966770835, 35.54959217637752], + [23.77667164401693, 35.53716095159702], + [23.79315113620443, 35.53855781451608]]), + { + "class": 0, + "system:index": "1" + })]), +water = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.LineString( + [[23.815368450747332, 35.53525030188046], + [23.82712725506862, 35.538463126752895], + [23.813823498354754, 35.53629797630387], + [23.826955593691668, 35.53972028406574], + [23.813051022158465, 35.53720594973632], + [23.826268948183856, 35.54104726207508], + [23.81339434491237, 35.5381139128914], + [23.825582302676043, 35.54230437888493], + [23.81313685284694, 35.53951075921525], + [23.827213085757098, 35.53769485425075], + [23.823264874087176, 35.543421799507115]]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.93656138287624, 35.520162273141004], + [23.922656811343035, 35.52700811924147], + [23.939651287661395, 35.52114028690721], + [23.920596874819598, 35.529662473875746], + [23.938449658022723, 35.52379483562914]]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.LineString( + [[23.789275921450457, 35.5804973627026], + [23.79768732892116, 35.57972949300953], + [23.786357678042254, 35.579589879547086], + [23.798631466494403, 35.578577674666], + [23.78446940289577, 35.578752193661586], + [23.798502720461688, 35.577670169758946], + [23.78292445050319, 35.57791449901465], + [23.79210841193106, 35.5772866256402], + [23.79923228131374, 35.57651832180017]]), + { + "class": 1, + "system:index": "2" + })]), +sunglint = ee.Geometry.MultiPolygon( + [[[[23.786748725416697, 35.55612383758693], + [23.786748725416697, 35.54634742800967], + [23.802541572096384, 35.54634742800967], + [23.802541572096384, 35.55612383758693]]], + [[[23.829664069654978, 35.550537463803785], + [23.829664069654978, 35.5441126527256], + [23.842710334303415, 35.5441126527256], + [23.842710334303415, 35.550537463803785]]], + [[[23.871206122877634, 35.547464792297085], + [23.871206122877634, 35.54271588654758], + [23.87978919172529, 35.54271588654758], + [23.87978919172529, 35.547464792297085]]]], None, False) +#**** End of imports. If edited, may not auto-convert in the playground. ****# + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.2 Benthic Habitats +# Checkpoint: A22e +# Authors: Dimitris Poursanidis, Aurélie C. Shapiro, Spyros Christofilakos +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Section 1 +# Import and display satellite image. +planet = ee.Image('projects/gee-book/assets/A2-2/20200505_N2000') \ + .divide(10000) + +Map.centerObject(planet, 12) +visParams = { + 'bands': ['b3', 'b2', 'b1'], + 'min': 0.17, + 'max': 0.68, + 'gamma': 0.8 +} +Map.addLayer({ + 'eeObject': planet, + 'visParams': visParams, + 'name': 'planet initial', + 'shown': True +}) +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ + +# Section 2 +# Mask based to NDWI and RF. +def landmask(img): + ndwi = img.normalizedDifference(['b2', 'b4']) + training = ndwi.sampleRegions(land.merge(water), ['class'], + 3) + trained = ee.Classifier.smileRandomForest(10) \ + .train(training, 'class') + classified = ndwi.classify(trained) + mask = classified.eq(1) + + return img.updateMask(mask) + + +maskedImg = landmask(planet) + +Map.addLayer(maskedImg, visParams, 'maskedImg', False) + +# Sun-glint correction. +def sunglintRemoval(img): + linearFit1 = img.select(['b4', 'b1']).reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + linearFit2 = img.select(['b4', 'b2']).reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + linearFit3 = img.select(['b4', 'b3']).reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + + slopeImage = ee.Dictionary({ + 'b1': linearFit1.get('scale'), + 'b2': linearFit2.get('scale'), + 'b3': linearFit3.get('scale') + }).toImage() + + minNIR = img.select('b4').reduceRegion({ + 'reducer': ee.Reducer.min(), + 'geometry': sunglint, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }).toImage(['b4']) + + return img.select(['b1', 'b2', 'b3']) \ + .subtract(slopeImage.multiply((img.select('b4')).subtract( + minNIR))) \ + .addBands(img.select('b4')) + +sgImg = sunglintRemoval(maskedImg) +Map.addLayer(sgImg, visParams, 'sgImg', False) + +# DIV procedure. +def kernel(img): + boxcar = ee.Kernel.square({ + 'radius': 2, + 'units': 'pixels', + 'normalize': True + }) + return img.convolve(boxcar) + + +def makePositive(img): + return img.where(img.lte(0), 0.0001) + + +def div(img): + band1 = ee.List(['b1', 'b2', 'b3', 'b1', 'b2']) + band2 = ee.List(['b3', 'b3', 'b2', 'b2', 'b1']) + nband = ee.List(['b1b3', 'b2b3', 'b3b2', 'b1b2', 'b2b1']) + + for i in range(0, 5, 1): + x = band1.get(i) + y = band2.get(i) + z = nband.get(i) + + imageLog = img.select([x, y]).log() + + covariance = imageLog.toArray().reduceRegion({ + 'reducer': ee.Reducer.covariance(), + 'geometry': DIVsand, + 'scale': 3, + 'maxPixels': 1e12, + 'bestEffort': True, + }) + + covarMatrix = ee.Array(covariance.get('array')) + var1 = covarMatrix.get([0, 0]) + var2 = covarMatrix.get([1, 1]) + covar = covarMatrix.get([0, 1]) + + a = var1.subtract(var2).divide(covar.multiply(2)) + attenCoeffRatio = a.add(((a.pow(2)).add(1)).sqrt()) + + depthInvariantIndex = img.expression( + 'image1 - (image2 * coeff)', { + 'image1': imageLog.select([x]), + 'image2': imageLog.select([y]), + 'coeff': attenCoeffRatio + }) + + img = ee.Image.cat([img, depthInvariantIndex.select([x], [ + z + ])]) + + return img + + +divImg = div(kernel(makePositive(sgImg))).select('b[1-3]', + 'b1b2') +vivVisParams = { + 'bands': ['b1b2'], + 'min': -0.81, + 'max': -0.04, + 'gamma': 0.75 +} +Map.addLayer(divImg, vivVisParams, 'divImg', False) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ + +# Section 3, classification +# Import of reference data and split. +softBottom = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/SoftBottom') +rockyBottom = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/RockyBottom') +pO = ee.FeatureCollection('projects/gee-book/assets/A2-2/PO') + +sand = ee.FeatureCollection.randomPoints(softBottom, 150).map( + def function(s): + return s.set('class', 0) + ).randomColumn() +sandT = sand.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'sand training') +sandV = sand.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'sand validation') +Map.addLayer(sandT, { + 'color': 'yellow' +}, 'Sand Training', False) +Map.addLayer(sandV, { + 'color': 'yellow' +}, 'Sand Validation', False) + +hard = ee.FeatureCollection.randomPoints(rockyBottom, 79).map( + def function(s): + return s.set('class', 1) + ).randomColumn() +hardT = hard.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'hard training') +hardV = hard.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'hard validation') +Map.addLayer(hardT, { + 'color': 'red' +}, 'Rock Training', False) +Map.addLayer(hardV, { + 'color': 'red' +}, 'Rock Validation', False) + + +def func_pym(s): + return s.set('class', 2) + +posi = pO.map(func_pym) \ + .randomColumn('random') +posiT = posi.filter(ee.Filter.lte('random', 0.7)).aside(print, + 'posi training') +posiV = posi.filter(ee.Filter.gt('random', 0.7)).aside(print, + 'posi validation') +Map.addLayer(posiT, { + 'color': 'green' +}, 'Posidonia Training', False) +Map.addLayer(posiV, { + 'color': 'green' +}, 'Posidonia Validation', False) + +# Classification procedure. +def classify(img): + mergedT = ee.FeatureCollection([sandT, hardT, posiT]) \ + .flatten() + training = img.sampleRegions(mergedT, ['class'], 3) + trained = ee.Classifier.libsvm({ + 'kernelType': 'RBF', + 'gamma': 1, + 'cost': 500 + }).train(training, 'class') + classified = img.classify(trained) + + mergedV = ee.FeatureCollection([sandV, hardV, posiV]) \ + .flatten() + accuracyCol = classified.unmask().reduceRegions({ + 'collection': mergedV, + 'reducer': ee.Reducer.first(), + 'scale': 10 + }) + classificationErrorMatrix = accuracyCol.errorMatrix({ + 'actual': 'class', + 'predicted': 'first', + 'order': [0, 1, 2] + }) + classNames = ['soft_bot', 'hard_bot', 'seagrass'] + accuracyOA = classificationErrorMatrix.accuracy() + accuraccyCons = ee.Dictionary.fromLists({ + 'keys': classNames, + 'values': classificationErrorMatrix.consumersAccuracy() \ + .toList() \ + .flatten() + }) + accuracyProd = ee.Dictionary.fromLists({ + 'keys': classNames, + 'values': classificationErrorMatrix.producersAccuracy() \ + .toList() \ + .flatten() + }) + + classificationErrormatrixArray = classificationErrorMatrix \ + .array() + + def arrayToDatatable(array): + classesNames = ee.List(classNames) + + def toTableColumns(s): + return { + 'id': s, + 'label': s, + 'type': 'number' + } + + columns = classesNames.map(toTableColumns) + + def featureToTableRow(f): + return { + +def func_zns(c): + return { + 'v': c + } + + 'c': ee.List(f).map(func_zns) + + + + + + } + + rows = array.toList().map(featureToTableRow) + return ee.Dictionary({ + 'cols': columns, + 'rows': rows + }) + + + dataTable = arrayToDatatable(classificationErrormatrixArray) \ + .evaluate(function(dataTable) { + print('------------- Error matrix -------------', + ui.Chart(dataTable, 'Table') \ + .setOptions({ + 'pageSize': 15 + }), + 'rows: reference, 'cols': mapped') + }) + print('Overall Accuracy', accuracyOA) + print('Users accuracy', accuraccyCons) + print('Producers accuracy', accuracyProd) + return classified + + +svmClassification = classify(divImg) +svmVis = { + 'min': 0, + 'max': 2, + 'palette': ['ffffbf', 'fc8d59', '91cf60'] +} +Map.addLayer(svmClassification, svmVis, 'classification') + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ + +# Section 4, Bathymetry +# Import and split training and validation data for the bathymetry. +depth = ee.FeatureCollection( + 'projects/gee-book/assets/A2-2/DepthDataTill09072020_v2') +depth = depth.randomColumn() +depthT = depth.filter(ee.Filter.lte('random', 0.7)) +depthV = depth.filter(ee.Filter.gt('random', 0.7)) +Map.addLayer(depthT, { + 'color': 'black' +}, 'Depth Training', False) +Map.addLayer(depthV, { + 'color': 'gray' +}, 'Depth Validation', False) + +def vector2image(vector): + rasterisedVectorData = vector \ + .filter(ee.Filter.neq('Depth', + None)) # Filter out NA depth values. \ + .reduceToImage({ + 'properties': ['Depth'], + 'reducer': ee.Reducer.mean() + }) + return (rasterisedVectorData) + + +depthTImage = vector2image(depthT) \ + .aside(Map.addLayer, { + 'color': 'white' + }, 'Depth Training2', False) +depthVImage = vector2image(depthV) \ + .aside(Map.addLayer, { + 'color': 'white' + }, 'Depth Validation2', False) + +def rfbathymetry(img): + training = img.sampleRegions({ + 'collection': depthT, + 'scale': 3 + }) + + regclass = ee.Classifier.smileRandomForest(15) \ + .train(training, 'Depth') + bathyClass = img \ + .classify(regclass.setOutputMode('REGRESSION')).rename( + 'Depth') + + sdbEstimate = bathyClass.clip(depthV) + + # Prepare data by putting SDB estimated data and in situ data + # in one image to compare them afterwards. + imageI = ee.Image.cat([sdbEstimate, depthVImage]) + # Calculate covariance. + covariance = imageI.toArray().reduceRegion({ + 'reducer': ee.Reducer.covariance(), + 'geometry': depthV, + 'scale': 3, + 'bestEffort': True, + 'maxPixels': 1e9 + }) + covarMatrix = ee.Array(covariance.get('array')) + + rSqr = covarMatrix.get([0, 1]).pow(2) \ + .divide(covarMatrix.get([0, 0]) \ + .multiply(covarMatrix.get([1, 1]))) + + deviation = depthVImage.select('mean') \ + .subtract(sdbEstimate.select('Depth')).pow(2) + + rmse = ee.Number(deviation.reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': depthV, + 'scale': 3, + 'bestEffort': True, + 'maxPixels': 1e12 + }).get('mean')) \ + .sqrt() + + # Print together, so that they appear in the same output. + print('R²', rSqr, 'RMSE', rmse) + + return bathyClass + + +rfBathymetry = rfbathymetry(divImg) +bathyVis = { + 'min': -50, + 'max': 0, + 'palette': ['084594', '2171b5', '4292c6', '6baed6', + '9ecae1', 'c6dbef', 'deebf7', 'f7fbff' + ] +} +Map.addLayer(rfBathymetry, bathyVis, 'bathymetry') + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23a Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23a Checkpoint.ipynb new file mode 100644 index 0000000..6f003e1 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23a Checkpoint.ipynb @@ -0,0 +1,324 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.3 Surface Water Mapping\n", + "# Checkpoint: A23a\n", + "# Authors: K. Markert, G. Donchyts, A. Haag\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# *** Section 1 ***\n", + "\n", + "# Define a point in Cambodia to filter by location.\n", + "point = ee.Geometry.Point(104.9632, 11.7686)\n", + "\n", + "Map.centerObject(point, 11)\n", + "\n", + "# Get the Sentinel-1 collection and filter by space/time.\n", + "s1Collection = ee.ImageCollection('COPERNICUS/S1_GRD') \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2019-10-05', '2019-10-06') \\\n", + " .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING')) \\\n", + " .filter(ee.Filter.eq('instrumentMode', 'IW'))\n", + "\n", + "# Grab the first image in the collection.\n", + "s1Image = s1Collection.first()\n", + "\n", + "# Add the Sentinel-1 image to the map.\n", + "Map.addLayer(s1Image, {\n", + " 'min': -25,\n", + " 'max': 0,\n", + " 'bands': 'VV'\n", + "}, 'Sentinel-1 image')\n", + "\n", + "# Specify band to use for Otsu thresholding.\n", + "band = 'VV'\n", + "\n", + "# Define a reducer to calculate a histogram of values.\n", + "histogramReducer = ee.Reducer.histogram(255, 0.1)\n", + "\n", + "# Reduce all of the image values.\n", + "globalHistogram = ee.Dictionary(\n", + " s1Image.select(band).reduceRegion({\n", + " 'reducer': histogramReducer,\n", + " 'geometry': s1Image.geometry(),\n", + " 'scale': 90,\n", + " 'maxPixels': 1e10\n", + " }).get(band)\n", + ")\n", + "\n", + "# Extract out the histogram buckets and counts per bucket.\n", + "x = ee.List(globalHistogram.get('bucketMeans'))\n", + "y = ee.List(globalHistogram.get('histogram'))\n", + "\n", + "# Define a list of values to plot.\n", + "dataCol = ee.Array.cat([x, y], 1).toList()\n", + "\n", + "# Define the header information for data.\n", + "columnHeader = ee.List([\n", + " [\n", + " {\n", + " 'label': 'Backscatter',\n", + " 'role': 'domain',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Values',\n", + " 'role': 'data',\n", + " 'type': 'number'\n", + " }, ]\n", + "])\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create plot using the ui.Chart function with the dataTable.\n", + "# Use 'evaluate' to transfer the server-side table to the client.\n", + "# Define the chart and print it to the console.\n", + "dataTable.evaluate(function(dataTableClient) {\n", + " chart = ui.Chart(dataTableClient) \\\n", + " .setChartType('AreaChart') \\\n", + " .setOptions({\n", + " 'title': band + ' Global Histogram',\n", + " 'hAxis': {\n", + " 'title': 'Backscatter [dB]',\n", + " 'viewWindow': {\n", + " 'min': -35,\n", + " 'max': 15\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Count'\n", + " }\n", + " })\n", + " print(chart)\n", + "})\n", + "\n", + "# See:\n", + "# https:#medium.com/google-earth/otsus-method-for-image-segmentation-f5c48f405e\n", + "def otsu(histogram):\n", + " # Make sure histogram is an ee.Dictionary object.\n", + " histogram = ee.Dictionary(histogram)\n", + " # Extract relevant values into arrays.\n", + " counts = ee.Array(histogram.get('histogram'))\n", + " means = ee.Array(histogram.get('bucketMeans'))\n", + " # Calculate single statistics over arrays\n", + " size = means.length().get([0])\n", + " total = counts.reduce(ee.Reducer.sum(), [0]).get([0])\n", + " sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) \\\n", + " .get([0])\n", + " mean = sum.divide(total)\n", + " # Compute between sum of squares, where each mean partitions the data.\n", + " indices = ee.List.sequence(1, size)\n", + "\n", + "def func_rhf(i):\n", + " aCounts = counts.slice(0, 0, i)\n", + " aCount = aCounts.reduce(ee.Reducer.sum(), [0]) \\\n", + " .get([0])\n", + " aMeans = means.slice(0, 0, i)\n", + " aMean = aMeans.multiply(aCounts) \\\n", + " .reduce(ee.Reducer.sum(), [0]).get([0]) \\\n", + " .divide(aCount)\n", + " bCount = total.subtract(aCount)\n", + " bMean = sum.subtract(aCount.multiply(aMean)) \\\n", + " .divide(bCount)\n", + " return aCount.multiply(aMean.subtract(mean).pow(2)) \\\n", + " .add(\n", + " bCount.multiply(bMean.subtract(mean).pow(2)))\n", + "\n", + " bss = indices.map(func_rhf)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " # Return the mean value corresponding to the maximum BSS.\n", + " return means.sort(bss).get([-1])\n", + "\n", + "\n", + "# Apply otsu thresholding.\n", + "globalThreshold = otsu(globalHistogram)\n", + "print('Global threshold value:', globalThreshold)\n", + "\n", + "# Create list of empty strings that will be used for annotation.\n", + "thresholdCol = ee.List.repeat('', x.length())\n", + "# Find the index where the bucketMean equals the threshold.\n", + "threshIndex = x.indexOf(globalThreshold)\n", + "# Set the index to the annotation text.\n", + "thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold')\n", + "\n", + "# Redefine the column header information with annotation column.\n", + "columnHeader = ee.List([\n", + " [\n", + " {\n", + " 'label': 'Backscatter',\n", + " 'role': 'domain',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Values',\n", + " 'role': 'data',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Threshold',\n", + " 'role': 'annotation',\n", + " 'type': 'string'\n", + " }]\n", + "])\n", + "\n", + "# Loop through the data rows and add the annotation column.\n", + "i) {\n", + " i = ee.Number(i)\n", + " row = ee.List(dataCol.get(i))\n", + " return row.add(ee.String(thresholdCol.get(i)))\n", + "})\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create plot using the ui.Chart function with the dataTable.\n", + "# Use 'evaluate' to transfer the server-side table to the client.\n", + "# Define the chart and print it to the console.\n", + "dataTable.evaluate(function(dataTableClient) {\n", + " # loop through the client-side table and set empty strings to None\n", + " for i in range(0, dataTableClient.length, 1):\n", + " if (dataTableClient[i][2] === '') {\n", + " dataTableClient[i][2] = None\n", + " }\n", + "\n", + " chart = ui.Chart(dataTableClient) \\\n", + " .setChartType('AreaChart') \\\n", + " .setOptions({\n", + " 'title': band + \\\n", + " ' Global Histogram with Threshold annotation',\n", + " 'hAxis': {\n", + " 'title': 'Backscatter [dB]',\n", + " 'viewWindow': {\n", + " 'min': -35,\n", + " 'max': 15\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Count'\n", + " },\n", + " 'annotations': {\n", + " 'style': 'line'\n", + " }\n", + " })\n", + " print(chart)\n", + "})\n", + "\n", + "# Apply the threshold on the image to extract water.\n", + "globalWater = s1Image.select(band).lt(globalThreshold)\n", + "\n", + "# Add the water image to the map and mask 0 (no-water) values.\n", + "Map.addLayer(globalWater.selfMask(),\n", + " {\n", + " 'palette': 'blue'\n", + " },\n", + " 'Water (global threshold)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23a Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23a Checkpoint.js new file mode 100644 index 0000000..61e98b7 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23a Checkpoint.js @@ -0,0 +1,215 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.3 Surface Water Mapping +// Checkpoint: A23a +// Authors: K. Markert, G. Donchyts, A. Haag +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// *** Section 1 *** + +// Define a point in Cambodia to filter by location. +var point = ee.Geometry.Point(104.9632, 11.7686); + +Map.centerObject(point, 11); + +// Get the Sentinel-1 collection and filter by space/time. +var s1Collection = ee.ImageCollection('COPERNICUS/S1_GRD') + .filterBounds(point) + .filterDate('2019-10-05', '2019-10-06') + .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING')) + .filter(ee.Filter.eq('instrumentMode', 'IW')); + +// Grab the first image in the collection. +var s1Image = s1Collection.first(); + +// Add the Sentinel-1 image to the map. +Map.addLayer(s1Image, { + min: -25, + max: 0, + bands: 'VV' +}, 'Sentinel-1 image'); + +// Specify band to use for Otsu thresholding. +var band = 'VV'; + +// Define a reducer to calculate a histogram of values. +var histogramReducer = ee.Reducer.histogram(255, 0.1); + +// Reduce all of the image values. +var globalHistogram = ee.Dictionary( + s1Image.select(band).reduceRegion({ + reducer: histogramReducer, + geometry: s1Image.geometry(), + scale: 90, + maxPixels: 1e10 + }).get(band) +); + +// Extract out the histogram buckets and counts per bucket. +var x = ee.List(globalHistogram.get('bucketMeans')); +var y = ee.List(globalHistogram.get('histogram')); + +// Define a list of values to plot. +var dataCol = ee.Array.cat([x, y], 1).toList(); + +// Define the header information for data. +var columnHeader = ee.List([ + [ + { + label: 'Backscatter', + role: 'domain', + type: 'number' + }, + { + label: 'Values', + role: 'data', + type: 'number' + }, ] +]); + +// Concat the header and data for plotting. +var dataTable = columnHeader.cat(dataCol); + +// Create plot using the ui.Chart function with the dataTable. +// Use 'evaluate' to transfer the server-side table to the client. +// Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + var chart = ui.Chart(dataTableClient) + .setChartType('AreaChart') + .setOptions({ + title: band + ' Global Histogram', + hAxis: { + title: 'Backscatter [dB]', + viewWindow: { + min: -35, + max: 15 + } + }, + vAxis: { + title: 'Count' + } + }); + print(chart); +}); + +// See: +// https://medium.com/google-earth/otsus-method-for-image-segmentation-f5c48f405e +function otsu(histogram) { + // Make sure histogram is an ee.Dictionary object. + histogram = ee.Dictionary(histogram); + // Extract relevant values into arrays. + var counts = ee.Array(histogram.get('histogram')); + var means = ee.Array(histogram.get('bucketMeans')); + // Calculate single statistics over arrays + var size = means.length().get([0]); + var total = counts.reduce(ee.Reducer.sum(), [0]).get([0]); + var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) + .get([0]); + var mean = sum.divide(total); + // Compute between sum of squares, where each mean partitions the data. + var indices = ee.List.sequence(1, size); + var bss = indices.map(function(i) { + var aCounts = counts.slice(0, 0, i); + var aCount = aCounts.reduce(ee.Reducer.sum(), [0]) + .get([0]); + var aMeans = means.slice(0, 0, i); + var aMean = aMeans.multiply(aCounts) + .reduce(ee.Reducer.sum(), [0]).get([0]) + .divide(aCount); + var bCount = total.subtract(aCount); + var bMean = sum.subtract(aCount.multiply(aMean)) + .divide(bCount); + return aCount.multiply(aMean.subtract(mean).pow(2)) + .add( + bCount.multiply(bMean.subtract(mean).pow(2))); + }); + // Return the mean value corresponding to the maximum BSS. + return means.sort(bss).get([-1]); +} + +// Apply otsu thresholding. +var globalThreshold = otsu(globalHistogram); +print('Global threshold value:', globalThreshold); + +// Create list of empty strings that will be used for annotation. +var thresholdCol = ee.List.repeat('', x.length()); +// Find the index where the bucketMean equals the threshold. +var threshIndex = x.indexOf(globalThreshold); +// Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold'); + +// Redefine the column header information with annotation column. +columnHeader = ee.List([ + [ + { + label: 'Backscatter', + role: 'domain', + type: 'number' + }, + { + label: 'Values', + role: 'data', + type: 'number' + }, + { + label: 'Threshold', + role: 'annotation', + type: 'string' + }] +]); + +// Loop through the data rows and add the annotation column. +dataCol = ee.List.sequence(0, x.length().subtract(1)).map(function( +i) { + i = ee.Number(i); + var row = ee.List(dataCol.get(i)); + return row.add(ee.String(thresholdCol.get(i))); +}); + +// Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol); + +// Create plot using the ui.Chart function with the dataTable. +// Use 'evaluate' to transfer the server-side table to the client. +// Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + // loop through the client-side table and set empty strings to null + for (var i = 0; i < dataTableClient.length; i++) { + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = null; + } + } + var chart = ui.Chart(dataTableClient) + .setChartType('AreaChart') + .setOptions({ + title: band + + ' Global Histogram with Threshold annotation', + hAxis: { + title: 'Backscatter [dB]', + viewWindow: { + min: -35, + max: 15 + } + }, + vAxis: { + title: 'Count' + }, + annotations: { + style: 'line' + } + }); + print(chart); +}); + +// Apply the threshold on the image to extract water. +var globalWater = s1Image.select(band).lt(globalThreshold); + +// Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(globalWater.selfMask(), + { + palette: 'blue' + }, + 'Water (global threshold)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23a Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23a Checkpoint.py new file mode 100644 index 0000000..0cd5e30 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23a Checkpoint.py @@ -0,0 +1,237 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.3 Surface Water Mapping +# Checkpoint: A23a +# Authors: K. Markert, G. Donchyts, A. Haag +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# *** Section 1 *** + +# Define a point in Cambodia to filter by location. +point = ee.Geometry.Point(104.9632, 11.7686) + +Map.centerObject(point, 11) + +# Get the Sentinel-1 collection and filter by space/time. +s1Collection = ee.ImageCollection('COPERNICUS/S1_GRD') \ + .filterBounds(point) \ + .filterDate('2019-10-05', '2019-10-06') \ + .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING')) \ + .filter(ee.Filter.eq('instrumentMode', 'IW')) + +# Grab the first image in the collection. +s1Image = s1Collection.first() + +# Add the Sentinel-1 image to the map. +Map.addLayer(s1Image, { + 'min': -25, + 'max': 0, + 'bands': 'VV' +}, 'Sentinel-1 image') + +# Specify band to use for Otsu thresholding. +band = 'VV' + +# Define a reducer to calculate a histogram of values. +histogramReducer = ee.Reducer.histogram(255, 0.1) + +# Reduce all of the image values. +globalHistogram = ee.Dictionary( + s1Image.select(band).reduceRegion({ + 'reducer': histogramReducer, + 'geometry': s1Image.geometry(), + 'scale': 90, + 'maxPixels': 1e10 + }).get(band) +) + +# Extract out the histogram buckets and counts per bucket. +x = ee.List(globalHistogram.get('bucketMeans')) +y = ee.List(globalHistogram.get('histogram')) + +# Define a list of values to plot. +dataCol = ee.Array.cat([x, y], 1).toList() + +# Define the header information for data. +columnHeader = ee.List([ + [ + { + 'label': 'Backscatter', + 'role': 'domain', + 'type': 'number' + }, + { + 'label': 'Values', + 'role': 'data', + 'type': 'number' + }, ] +]) + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create plot using the ui.Chart function with the dataTable. +# Use 'evaluate' to transfer the server-side table to the client. +# Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + chart = ui.Chart(dataTableClient) \ + .setChartType('AreaChart') \ + .setOptions({ + 'title': band + ' Global Histogram', + 'hAxis': { + 'title': 'Backscatter [dB]', + 'viewWindow': { + 'min': -35, + 'max': 15 + } + }, + 'vAxis': { + 'title': 'Count' + } + }) + print(chart) +}) + +# See: +# https:#medium.com/google-earth/otsus-method-for-image-segmentation-f5c48f405e +def otsu(histogram): + # Make sure histogram is an ee.Dictionary object. + histogram = ee.Dictionary(histogram) + # Extract relevant values into arrays. + counts = ee.Array(histogram.get('histogram')) + means = ee.Array(histogram.get('bucketMeans')) + # Calculate single statistics over arrays + size = means.length().get([0]) + total = counts.reduce(ee.Reducer.sum(), [0]).get([0]) + sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) \ + .get([0]) + mean = sum.divide(total) + # Compute between sum of squares, where each mean partitions the data. + indices = ee.List.sequence(1, size) + +def func_rhf(i): + aCounts = counts.slice(0, 0, i) + aCount = aCounts.reduce(ee.Reducer.sum(), [0]) \ + .get([0]) + aMeans = means.slice(0, 0, i) + aMean = aMeans.multiply(aCounts) \ + .reduce(ee.Reducer.sum(), [0]).get([0]) \ + .divide(aCount) + bCount = total.subtract(aCount) + bMean = sum.subtract(aCount.multiply(aMean)) \ + .divide(bCount) + return aCount.multiply(aMean.subtract(mean).pow(2)) \ + .add( + bCount.multiply(bMean.subtract(mean).pow(2))) + + bss = indices.map(func_rhf) + + + + + + + + + + + + + + + + # Return the mean value corresponding to the maximum BSS. + return means.sort(bss).get([-1]) + + +# Apply otsu thresholding. +globalThreshold = otsu(globalHistogram) +print('Global threshold value:', globalThreshold) + +# Create list of empty strings that will be used for annotation. +thresholdCol = ee.List.repeat('', x.length()) +# Find the index where the bucketMean equals the threshold. +threshIndex = x.indexOf(globalThreshold) +# Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold') + +# Redefine the column header information with annotation column. +columnHeader = ee.List([ + [ + { + 'label': 'Backscatter', + 'role': 'domain', + 'type': 'number' + }, + { + 'label': 'Values', + 'role': 'data', + 'type': 'number' + }, + { + 'label': 'Threshold', + 'role': 'annotation', + 'type': 'string' + }] +]) + +# Loop through the data rows and add the annotation column. +i) { + i = ee.Number(i) + row = ee.List(dataCol.get(i)) + return row.add(ee.String(thresholdCol.get(i))) +}) + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create plot using the ui.Chart function with the dataTable. +# Use 'evaluate' to transfer the server-side table to the client. +# Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + # loop through the client-side table and set empty strings to None + for i in range(0, dataTableClient.length, 1): + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = None + } + + chart = ui.Chart(dataTableClient) \ + .setChartType('AreaChart') \ + .setOptions({ + 'title': band + \ + ' Global Histogram with Threshold annotation', + 'hAxis': { + 'title': 'Backscatter [dB]', + 'viewWindow': { + 'min': -35, + 'max': 15 + } + }, + 'vAxis': { + 'title': 'Count' + }, + 'annotations': { + 'style': 'line' + } + }) + print(chart) +}) + +# Apply the threshold on the image to extract water. +globalWater = s1Image.select(band).lt(globalThreshold) + +# Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(globalWater.selfMask(), + { + 'palette': 'blue' + }, + 'Water (global threshold)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23b Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23b Checkpoint.ipynb new file mode 100644 index 0000000..3fd8de9 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23b Checkpoint.ipynb @@ -0,0 +1,493 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.3 Surface Water Mapping\n", + "# Checkpoint: A23b\n", + "# Authors: K. Markert, G. Donchyts, A. Haag\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# *** Section 1 ***\n", + "\n", + "# Define a point in Cambodia to filter by location.\n", + "point = ee.Geometry.Point(104.9632, 11.7686)\n", + "\n", + "Map.centerObject(point, 11)\n", + "\n", + "# Get the Sentinel-1 collection and filter by space/time.\n", + "s1Collection = ee.ImageCollection('COPERNICUS/S1_GRD') \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2019-10-05', '2019-10-06') \\\n", + " .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING')) \\\n", + " .filter(ee.Filter.eq('instrumentMode', 'IW'))\n", + "\n", + "# Grab the first image in the collection.\n", + "s1Image = s1Collection.first()\n", + "\n", + "# Add the Sentinel-1 image to the map.\n", + "Map.addLayer(s1Image, {\n", + " 'min': -25,\n", + " 'max': 0,\n", + " 'bands': 'VV'\n", + "}, 'Sentinel-1 image')\n", + "\n", + "# Specify band to use for Otsu thresholding.\n", + "band = 'VV'\n", + "\n", + "# Define a reducer to calculate a histogram of values.\n", + "histogramReducer = ee.Reducer.histogram(255, 0.1)\n", + "\n", + "# Reduce all of the image values.\n", + "globalHistogram = ee.Dictionary(\n", + " s1Image.select(band).reduceRegion({\n", + " 'reducer': histogramReducer,\n", + " 'geometry': s1Image.geometry(),\n", + " 'scale': 90,\n", + " 'maxPixels': 1e10\n", + " }).get(band)\n", + ")\n", + "\n", + "# Extract out the histogram buckets and counts per bucket.\n", + "x = ee.List(globalHistogram.get('bucketMeans'))\n", + "y = ee.List(globalHistogram.get('histogram'))\n", + "\n", + "# Define a list of values to plot.\n", + "dataCol = ee.Array.cat([x, y], 1).toList()\n", + "\n", + "# Define the header information for data.\n", + "columnHeader = ee.List([\n", + " [\n", + " {\n", + " 'label': 'Backscatter',\n", + " 'role': 'domain',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Values',\n", + " 'role': 'data',\n", + " 'type': 'number'\n", + " }, ]\n", + "])\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create plot using the ui.Chart function with the dataTable.\n", + "# Use 'evaluate' to transfer the server-side table to the client.\n", + "# Define the chart and print it to the console.\n", + "dataTable.evaluate(function(dataTableClient) {\n", + " chart = ui.Chart(dataTableClient) \\\n", + " .setChartType('AreaChart') \\\n", + " .setOptions({\n", + " 'title': band + ' Global Histogram',\n", + " 'hAxis': {\n", + " 'title': 'Backscatter [dB]',\n", + " 'viewWindow': {\n", + " 'min': -35,\n", + " 'max': 15\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Count'\n", + " }\n", + " })\n", + " print(chart)\n", + "})\n", + "\n", + "# See:\n", + "# https:#medium.com/google-earth/otsus-method-for-image-segmentation-f5c48f405e\n", + "def otsu(histogram):\n", + " # Make sure histogram is an ee.Dictionary object.\n", + " histogram = ee.Dictionary(histogram)\n", + " # Extract relevant values into arrays.\n", + " counts = ee.Array(histogram.get('histogram'))\n", + " means = ee.Array(histogram.get('bucketMeans'))\n", + " # Calculate single statistics over arrays\n", + " size = means.length().get([0])\n", + " total = counts.reduce(ee.Reducer.sum(), [0]).get([0])\n", + " sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) \\\n", + " .get([0])\n", + " mean = sum.divide(total)\n", + " # Compute between sum of squares, where each mean partitions the data.\n", + " indices = ee.List.sequence(1, size)\n", + "\n", + "def func_leh(i):\n", + " aCounts = counts.slice(0, 0, i)\n", + " aCount = aCounts.reduce(ee.Reducer.sum(), [0]) \\\n", + " .get([0])\n", + " aMeans = means.slice(0, 0, i)\n", + " aMean = aMeans.multiply(aCounts) \\\n", + " .reduce(ee.Reducer.sum(), [0]).get([0]) \\\n", + " .divide(aCount)\n", + " bCount = total.subtract(aCount)\n", + " bMean = sum.subtract(aCount.multiply(aMean)) \\\n", + " .divide(bCount)\n", + " return aCount.multiply(aMean.subtract(mean).pow(2)) \\\n", + " .add(\n", + " bCount.multiply(bMean.subtract(mean).pow(2)))\n", + "\n", + " bss = indices.map(func_leh)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " # Return the mean value corresponding to the maximum BSS.\n", + " return means.sort(bss).get([-1])\n", + "\n", + "\n", + "# Apply otsu thresholding.\n", + "globalThreshold = otsu(globalHistogram)\n", + "print('Global threshold value:', globalThreshold)\n", + "\n", + "# Create list of empty strings that will be used for annotation.\n", + "thresholdCol = ee.List.repeat('', x.length())\n", + "# Find the index where the bucketMean equals the threshold.\n", + "threshIndex = x.indexOf(globalThreshold)\n", + "# Set the index to the annotation text.\n", + "thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold')\n", + "\n", + "# Redefine the column header information with annotation column.\n", + "columnHeader = ee.List([\n", + " [\n", + " {\n", + " 'label': 'Backscatter',\n", + " 'role': 'domain',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Values',\n", + " 'role': 'data',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Threshold',\n", + " 'role': 'annotation',\n", + " 'type': 'string'\n", + " }]\n", + "])\n", + "\n", + "# Loop through the data rows and add the annotation column.\n", + "i) {\n", + " i = ee.Number(i)\n", + " row = ee.List(dataCol.get(i))\n", + " return row.add(ee.String(thresholdCol.get(i)))\n", + "})\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create plot using the ui.Chart function with the dataTable.\n", + "# Use 'evaluate' to transfer the server-side table to the client.\n", + "# Define the chart and print it to the console.\n", + "dataTable.evaluate(function(dataTableClient) {\n", + " # loop through the client-side table and set empty strings to None\n", + " for i in range(0, dataTableClient.length, 1):\n", + " if (dataTableClient[i][2] === '') {\n", + " dataTableClient[i][2] = None\n", + " }\n", + "\n", + " chart = ui.Chart(dataTableClient) \\\n", + " .setChartType('AreaChart') \\\n", + " .setOptions({\n", + " 'title': band + \\\n", + " ' Global Histogram with Threshold annotation',\n", + " 'hAxis': {\n", + " 'title': 'Backscatter [dB]',\n", + " 'viewWindow': {\n", + " 'min': -35,\n", + " 'max': 15\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Count'\n", + " },\n", + " 'annotations': {\n", + " 'style': 'line'\n", + " }\n", + " })\n", + " print(chart)\n", + "})\n", + "\n", + "# Apply the threshold on the image to extract water.\n", + "globalWater = s1Image.select(band).lt(globalThreshold)\n", + "\n", + "# Add the water image to the map and mask 0 (no-water) values.\n", + "Map.addLayer(globalWater.selfMask(),\n", + " {\n", + " 'palette': 'blue'\n", + " },\n", + " 'Water (global threshold)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# *** Section 2 ***\n", + "\n", + "# Define parameters for the adaptive thresholding.\n", + "# Initial estimate of water/no-water for estimating the edges\n", + "initialThreshold = -16\n", + "# Number of connected pixels to use for length calculation.\n", + "connectedPixels = 100\n", + "# Length of edges to be considered water edges.\n", + "edgeLength = 20\n", + "# Buffer in meters to apply to edges.\n", + "edgeBuffer = 300\n", + "# Threshold for canny edge detection.\n", + "cannyThreshold = 1\n", + "# Sigma value for gaussian filter in canny edge detection.\n", + "cannySigma = 1\n", + "# Lower threshold for canny detection.\n", + "cannyLt = 0.05\n", + "\n", + "# Get preliminary water.\n", + "binary = s1Image.select(band).lt(initialThreshold) \\\n", + " .rename('binary')\n", + "\n", + "# Get projection information to convert buffer size to pixels.\n", + "imageProj = s1Image.select(band).projection()\n", + "\n", + "# Get canny edges.\n", + "canny = ee.Algorithms.CannyEdgeDetector({\n", + " 'image': binary,\n", + " 'threshold': cannyThreshold,\n", + " 'sigma': cannySigma\n", + "})\n", + "\n", + "# Process canny edges.\n", + "\n", + "# Get the edges and length of edges.\n", + "connected = canny.updateMask(canny).lt(cannyLt) \\\n", + " .connectedPixelCount(connectedPixels, True)\n", + "\n", + "# Mask short edges that can be noise.\n", + "edges = connected.gte(edgeLength)\n", + "\n", + "# Calculate the buffer in pixel size.\n", + "edgeBufferPixel = ee.Number(edgeBuffer).divide(imageProj \\\n", + " .nominalScale())\n", + "\n", + "# Buffer the edges using a dilation operation.\n", + "bufferedEdges = edges.fastDistanceTransform().lt(edgeBufferPixel)\n", + "\n", + "# Mask areas not within the buffer .\n", + "edgeImage = s1Image.select(band).updateMask(bufferedEdges)\n", + "\n", + "# Add the detected edges and buffered edges to the map.\n", + "Map.addLayer(edges, {\n", + " 'palette': 'red'\n", + "}, 'Detected water edges')\n", + "edgesVis = {\n", + " 'palette': 'yellow',\n", + " 'opacity': 0.5\n", + "}\n", + "Map.addLayer(bufferedEdges.selfMask(), edgesVis,\n", + " 'Buffered water edges')\n", + "\n", + "# Reduce all of the image values.\n", + "localHistogram = ee.Dictionary(\n", + " edgeImage.reduceRegion({\n", + " 'reducer': histogramReducer,\n", + " 'geometry': s1Image.geometry(),\n", + " 'scale': 90,\n", + " 'maxPixels': 1e10\n", + " }).get(band)\n", + ")\n", + "\n", + "# Apply otsu thresholding.\n", + "localThreshold = otsu(localHistogram)\n", + "print('Adaptive threshold value:', localThreshold)\n", + "\n", + "# Extract out the histogram buckets and counts per bucket.\n", + "x = ee.List(localHistogram.get('bucketMeans'))\n", + "y = ee.List(localHistogram.get('histogram'))\n", + "\n", + "# Define a list of values to plot.\n", + "dataCol = ee.Array.cat([x, y], 1).toList()\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create list of empty strings that will be used for annotation.\n", + "thresholdCol = ee.List.repeat('', x.length())\n", + "# Find the index that bucketMean equals the threshold.\n", + "threshIndex = x.indexOf(localThreshold)\n", + "# Set the index to the annotation text.\n", + "thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold')\n", + "\n", + "# Redefine the column header information now with annotation col.\n", + "columnHeader = ee.List([\n", + " [\n", + " {\n", + " 'label': 'Backscatter',\n", + " 'role': 'domain',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Values',\n", + " 'role': 'data',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Threshold',\n", + " 'role': 'annotation',\n", + " 'type': 'string'\n", + " }]\n", + "])\n", + "\n", + "# Loop through the data rows and add the annotation col.\n", + "i) {\n", + " i = ee.Number(i)\n", + " row = ee.List(dataCol.get(i))\n", + " return row.add(ee.String(thresholdCol.get(i)))\n", + "})\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create plot using the ui.Chart function with the dataTable.\n", + "# Use 'evaluate' to transfer the server-side table to the client.\n", + "# Define the chart and print it to the console.\n", + "dataTable.evaluate(function(dataTableClient) {\n", + " # Loop through the client-side table and set empty strings to None.\n", + " for i in range(0, dataTableClient.length, 1):\n", + " if (dataTableClient[i][2] === '') {\n", + " dataTableClient[i][2] = None\n", + " }\n", + "\n", + " chart = ui.Chart(dataTableClient) \\\n", + " .setChartType('AreaChart') \\\n", + " .setOptions({\n", + " 'title': band + \\\n", + " ' Adaptive Histogram with Threshold annotation',\n", + " 'hAxis': {\n", + " 'title': 'Backscatter [dB]',\n", + " 'viewWindow': {\n", + " 'min': -35,\n", + " 'max': 15\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Count'\n", + " },\n", + " 'annotations': {\n", + " 'style': 'line'\n", + " }\n", + " })\n", + " print(chart)\n", + "})\n", + "\n", + "# Apply the threshold on the image to extract water.\n", + "localWater = s1Image.select(band).lt(localThreshold)\n", + "\n", + "# Add the water image to the map and mask 0 (no-water) values.\n", + "Map.addLayer(localWater.selfMask(),\n", + " {\n", + " 'palette': 'darkblue'\n", + " },\n", + " 'Water (adaptive threshold)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23b Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23b Checkpoint.js new file mode 100644 index 0000000..e5d0d45 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23b Checkpoint.js @@ -0,0 +1,385 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.3 Surface Water Mapping +// Checkpoint: A23b +// Authors: K. Markert, G. Donchyts, A. Haag +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// *** Section 1 *** + +// Define a point in Cambodia to filter by location. +var point = ee.Geometry.Point(104.9632, 11.7686); + +Map.centerObject(point, 11); + +// Get the Sentinel-1 collection and filter by space/time. +var s1Collection = ee.ImageCollection('COPERNICUS/S1_GRD') + .filterBounds(point) + .filterDate('2019-10-05', '2019-10-06') + .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING')) + .filter(ee.Filter.eq('instrumentMode', 'IW')); + +// Grab the first image in the collection. +var s1Image = s1Collection.first(); + +// Add the Sentinel-1 image to the map. +Map.addLayer(s1Image, { + min: -25, + max: 0, + bands: 'VV' +}, 'Sentinel-1 image'); + +// Specify band to use for Otsu thresholding. +var band = 'VV'; + +// Define a reducer to calculate a histogram of values. +var histogramReducer = ee.Reducer.histogram(255, 0.1); + +// Reduce all of the image values. +var globalHistogram = ee.Dictionary( + s1Image.select(band).reduceRegion({ + reducer: histogramReducer, + geometry: s1Image.geometry(), + scale: 90, + maxPixels: 1e10 + }).get(band) +); + +// Extract out the histogram buckets and counts per bucket. +var x = ee.List(globalHistogram.get('bucketMeans')); +var y = ee.List(globalHistogram.get('histogram')); + +// Define a list of values to plot. +var dataCol = ee.Array.cat([x, y], 1).toList(); + +// Define the header information for data. +var columnHeader = ee.List([ + [ + { + label: 'Backscatter', + role: 'domain', + type: 'number' + }, + { + label: 'Values', + role: 'data', + type: 'number' + }, ] +]); + +// Concat the header and data for plotting. +var dataTable = columnHeader.cat(dataCol); + +// Create plot using the ui.Chart function with the dataTable. +// Use 'evaluate' to transfer the server-side table to the client. +// Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + var chart = ui.Chart(dataTableClient) + .setChartType('AreaChart') + .setOptions({ + title: band + ' Global Histogram', + hAxis: { + title: 'Backscatter [dB]', + viewWindow: { + min: -35, + max: 15 + } + }, + vAxis: { + title: 'Count' + } + }); + print(chart); +}); + +// See: +// https://medium.com/google-earth/otsus-method-for-image-segmentation-f5c48f405e +function otsu(histogram) { + // Make sure histogram is an ee.Dictionary object. + histogram = ee.Dictionary(histogram); + // Extract relevant values into arrays. + var counts = ee.Array(histogram.get('histogram')); + var means = ee.Array(histogram.get('bucketMeans')); + // Calculate single statistics over arrays + var size = means.length().get([0]); + var total = counts.reduce(ee.Reducer.sum(), [0]).get([0]); + var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) + .get([0]); + var mean = sum.divide(total); + // Compute between sum of squares, where each mean partitions the data. + var indices = ee.List.sequence(1, size); + var bss = indices.map(function(i) { + var aCounts = counts.slice(0, 0, i); + var aCount = aCounts.reduce(ee.Reducer.sum(), [0]) + .get([0]); + var aMeans = means.slice(0, 0, i); + var aMean = aMeans.multiply(aCounts) + .reduce(ee.Reducer.sum(), [0]).get([0]) + .divide(aCount); + var bCount = total.subtract(aCount); + var bMean = sum.subtract(aCount.multiply(aMean)) + .divide(bCount); + return aCount.multiply(aMean.subtract(mean).pow(2)) + .add( + bCount.multiply(bMean.subtract(mean).pow(2))); + }); + // Return the mean value corresponding to the maximum BSS. + return means.sort(bss).get([-1]); +} + +// Apply otsu thresholding. +var globalThreshold = otsu(globalHistogram); +print('Global threshold value:', globalThreshold); + +// Create list of empty strings that will be used for annotation. +var thresholdCol = ee.List.repeat('', x.length()); +// Find the index where the bucketMean equals the threshold. +var threshIndex = x.indexOf(globalThreshold); +// Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold'); + +// Redefine the column header information with annotation column. +columnHeader = ee.List([ + [ + { + label: 'Backscatter', + role: 'domain', + type: 'number' + }, + { + label: 'Values', + role: 'data', + type: 'number' + }, + { + label: 'Threshold', + role: 'annotation', + type: 'string' + }] +]); + +// Loop through the data rows and add the annotation column. +dataCol = ee.List.sequence(0, x.length().subtract(1)).map(function( +i) { + i = ee.Number(i); + var row = ee.List(dataCol.get(i)); + return row.add(ee.String(thresholdCol.get(i))); +}); + +// Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol); + +// Create plot using the ui.Chart function with the dataTable. +// Use 'evaluate' to transfer the server-side table to the client. +// Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + // loop through the client-side table and set empty strings to null + for (var i = 0; i < dataTableClient.length; i++) { + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = null; + } + } + var chart = ui.Chart(dataTableClient) + .setChartType('AreaChart') + .setOptions({ + title: band + + ' Global Histogram with Threshold annotation', + hAxis: { + title: 'Backscatter [dB]', + viewWindow: { + min: -35, + max: 15 + } + }, + vAxis: { + title: 'Count' + }, + annotations: { + style: 'line' + } + }); + print(chart); +}); + +// Apply the threshold on the image to extract water. +var globalWater = s1Image.select(band).lt(globalThreshold); + +// Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(globalWater.selfMask(), + { + palette: 'blue' + }, + 'Water (global threshold)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// *** Section 2 *** + +// Define parameters for the adaptive thresholding. +// Initial estimate of water/no-water for estimating the edges +var initialThreshold = -16; +// Number of connected pixels to use for length calculation. +var connectedPixels = 100; +// Length of edges to be considered water edges. +var edgeLength = 20; +// Buffer in meters to apply to edges. +var edgeBuffer = 300; +// Threshold for canny edge detection. +var cannyThreshold = 1; +// Sigma value for gaussian filter in canny edge detection. +var cannySigma = 1; +// Lower threshold for canny detection. +var cannyLt = 0.05; + +// Get preliminary water. +var binary = s1Image.select(band).lt(initialThreshold) + .rename('binary'); + +// Get projection information to convert buffer size to pixels. +var imageProj = s1Image.select(band).projection(); + +// Get canny edges. +var canny = ee.Algorithms.CannyEdgeDetector({ + image: binary, + threshold: cannyThreshold, + sigma: cannySigma +}); + +// Process canny edges. + +// Get the edges and length of edges. +var connected = canny.updateMask(canny).lt(cannyLt) + .connectedPixelCount(connectedPixels, true); + +// Mask short edges that can be noise. +var edges = connected.gte(edgeLength); + +// Calculate the buffer in pixel size. +var edgeBufferPixel = ee.Number(edgeBuffer).divide(imageProj + .nominalScale()); + +// Buffer the edges using a dilation operation. +var bufferedEdges = edges.fastDistanceTransform().lt(edgeBufferPixel); + +// Mask areas not within the buffer . +var edgeImage = s1Image.select(band).updateMask(bufferedEdges); + +// Add the detected edges and buffered edges to the map. +Map.addLayer(edges, { + palette: 'red' +}, 'Detected water edges'); +var edgesVis = { + palette: 'yellow', + opacity: 0.5 +}; +Map.addLayer(bufferedEdges.selfMask(), edgesVis, + 'Buffered water edges'); + +// Reduce all of the image values. +var localHistogram = ee.Dictionary( + edgeImage.reduceRegion({ + reducer: histogramReducer, + geometry: s1Image.geometry(), + scale: 90, + maxPixels: 1e10 + }).get(band) +); + +// Apply otsu thresholding. +var localThreshold = otsu(localHistogram); +print('Adaptive threshold value:', localThreshold); + +// Extract out the histogram buckets and counts per bucket. +var x = ee.List(localHistogram.get('bucketMeans')); +var y = ee.List(localHistogram.get('histogram')); + +// Define a list of values to plot. +var dataCol = ee.Array.cat([x, y], 1).toList(); + +// Concat the header and data for plotting. +var dataTable = columnHeader.cat(dataCol); + +// Create list of empty strings that will be used for annotation. +var thresholdCol = ee.List.repeat('', x.length()); +// Find the index that bucketMean equals the threshold. +var threshIndex = x.indexOf(localThreshold); +// Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold'); + +// Redefine the column header information now with annotation col. +columnHeader = ee.List([ + [ + { + label: 'Backscatter', + role: 'domain', + type: 'number' + }, + { + label: 'Values', + role: 'data', + type: 'number' + }, + { + label: 'Threshold', + role: 'annotation', + type: 'string' + }] +]); + +// Loop through the data rows and add the annotation col. +dataCol = ee.List.sequence(0, x.length().subtract(1)).map(function( +i) { + i = ee.Number(i); + var row = ee.List(dataCol.get(i)); + return row.add(ee.String(thresholdCol.get(i))); +}); + +// Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol); + +// Create plot using the ui.Chart function with the dataTable. +// Use 'evaluate' to transfer the server-side table to the client. +// Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + // Loop through the client-side table and set empty strings to null. + for (var i = 0; i < dataTableClient.length; i++) { + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = null; + } + } + var chart = ui.Chart(dataTableClient) + .setChartType('AreaChart') + .setOptions({ + title: band + + ' Adaptive Histogram with Threshold annotation', + hAxis: { + title: 'Backscatter [dB]', + viewWindow: { + min: -35, + max: 15 + } + }, + vAxis: { + title: 'Count' + }, + annotations: { + style: 'line' + } + }); + print(chart); +}); + +// Apply the threshold on the image to extract water. +var localWater = s1Image.select(band).lt(localThreshold); + +// Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(localWater.selfMask(), + { + palette: 'darkblue' + }, + 'Water (adaptive threshold)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23b Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23b Checkpoint.py new file mode 100644 index 0000000..2e85779 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23b Checkpoint.py @@ -0,0 +1,406 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.3 Surface Water Mapping +# Checkpoint: A23b +# Authors: K. Markert, G. Donchyts, A. Haag +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# *** Section 1 *** + +# Define a point in Cambodia to filter by location. +point = ee.Geometry.Point(104.9632, 11.7686) + +Map.centerObject(point, 11) + +# Get the Sentinel-1 collection and filter by space/time. +s1Collection = ee.ImageCollection('COPERNICUS/S1_GRD') \ + .filterBounds(point) \ + .filterDate('2019-10-05', '2019-10-06') \ + .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING')) \ + .filter(ee.Filter.eq('instrumentMode', 'IW')) + +# Grab the first image in the collection. +s1Image = s1Collection.first() + +# Add the Sentinel-1 image to the map. +Map.addLayer(s1Image, { + 'min': -25, + 'max': 0, + 'bands': 'VV' +}, 'Sentinel-1 image') + +# Specify band to use for Otsu thresholding. +band = 'VV' + +# Define a reducer to calculate a histogram of values. +histogramReducer = ee.Reducer.histogram(255, 0.1) + +# Reduce all of the image values. +globalHistogram = ee.Dictionary( + s1Image.select(band).reduceRegion({ + 'reducer': histogramReducer, + 'geometry': s1Image.geometry(), + 'scale': 90, + 'maxPixels': 1e10 + }).get(band) +) + +# Extract out the histogram buckets and counts per bucket. +x = ee.List(globalHistogram.get('bucketMeans')) +y = ee.List(globalHistogram.get('histogram')) + +# Define a list of values to plot. +dataCol = ee.Array.cat([x, y], 1).toList() + +# Define the header information for data. +columnHeader = ee.List([ + [ + { + 'label': 'Backscatter', + 'role': 'domain', + 'type': 'number' + }, + { + 'label': 'Values', + 'role': 'data', + 'type': 'number' + }, ] +]) + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create plot using the ui.Chart function with the dataTable. +# Use 'evaluate' to transfer the server-side table to the client. +# Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + chart = ui.Chart(dataTableClient) \ + .setChartType('AreaChart') \ + .setOptions({ + 'title': band + ' Global Histogram', + 'hAxis': { + 'title': 'Backscatter [dB]', + 'viewWindow': { + 'min': -35, + 'max': 15 + } + }, + 'vAxis': { + 'title': 'Count' + } + }) + print(chart) +}) + +# See: +# https:#medium.com/google-earth/otsus-method-for-image-segmentation-f5c48f405e +def otsu(histogram): + # Make sure histogram is an ee.Dictionary object. + histogram = ee.Dictionary(histogram) + # Extract relevant values into arrays. + counts = ee.Array(histogram.get('histogram')) + means = ee.Array(histogram.get('bucketMeans')) + # Calculate single statistics over arrays + size = means.length().get([0]) + total = counts.reduce(ee.Reducer.sum(), [0]).get([0]) + sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) \ + .get([0]) + mean = sum.divide(total) + # Compute between sum of squares, where each mean partitions the data. + indices = ee.List.sequence(1, size) + +def func_leh(i): + aCounts = counts.slice(0, 0, i) + aCount = aCounts.reduce(ee.Reducer.sum(), [0]) \ + .get([0]) + aMeans = means.slice(0, 0, i) + aMean = aMeans.multiply(aCounts) \ + .reduce(ee.Reducer.sum(), [0]).get([0]) \ + .divide(aCount) + bCount = total.subtract(aCount) + bMean = sum.subtract(aCount.multiply(aMean)) \ + .divide(bCount) + return aCount.multiply(aMean.subtract(mean).pow(2)) \ + .add( + bCount.multiply(bMean.subtract(mean).pow(2))) + + bss = indices.map(func_leh) + + + + + + + + + + + + + + + + # Return the mean value corresponding to the maximum BSS. + return means.sort(bss).get([-1]) + + +# Apply otsu thresholding. +globalThreshold = otsu(globalHistogram) +print('Global threshold value:', globalThreshold) + +# Create list of empty strings that will be used for annotation. +thresholdCol = ee.List.repeat('', x.length()) +# Find the index where the bucketMean equals the threshold. +threshIndex = x.indexOf(globalThreshold) +# Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold') + +# Redefine the column header information with annotation column. +columnHeader = ee.List([ + [ + { + 'label': 'Backscatter', + 'role': 'domain', + 'type': 'number' + }, + { + 'label': 'Values', + 'role': 'data', + 'type': 'number' + }, + { + 'label': 'Threshold', + 'role': 'annotation', + 'type': 'string' + }] +]) + +# Loop through the data rows and add the annotation column. +i) { + i = ee.Number(i) + row = ee.List(dataCol.get(i)) + return row.add(ee.String(thresholdCol.get(i))) +}) + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create plot using the ui.Chart function with the dataTable. +# Use 'evaluate' to transfer the server-side table to the client. +# Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + # loop through the client-side table and set empty strings to None + for i in range(0, dataTableClient.length, 1): + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = None + } + + chart = ui.Chart(dataTableClient) \ + .setChartType('AreaChart') \ + .setOptions({ + 'title': band + \ + ' Global Histogram with Threshold annotation', + 'hAxis': { + 'title': 'Backscatter [dB]', + 'viewWindow': { + 'min': -35, + 'max': 15 + } + }, + 'vAxis': { + 'title': 'Count' + }, + 'annotations': { + 'style': 'line' + } + }) + print(chart) +}) + +# Apply the threshold on the image to extract water. +globalWater = s1Image.select(band).lt(globalThreshold) + +# Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(globalWater.selfMask(), + { + 'palette': 'blue' + }, + 'Water (global threshold)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# *** Section 2 *** + +# Define parameters for the adaptive thresholding. +# Initial estimate of water/no-water for estimating the edges +initialThreshold = -16 +# Number of connected pixels to use for length calculation. +connectedPixels = 100 +# Length of edges to be considered water edges. +edgeLength = 20 +# Buffer in meters to apply to edges. +edgeBuffer = 300 +# Threshold for canny edge detection. +cannyThreshold = 1 +# Sigma value for gaussian filter in canny edge detection. +cannySigma = 1 +# Lower threshold for canny detection. +cannyLt = 0.05 + +# Get preliminary water. +binary = s1Image.select(band).lt(initialThreshold) \ + .rename('binary') + +# Get projection information to convert buffer size to pixels. +imageProj = s1Image.select(band).projection() + +# Get canny edges. +canny = ee.Algorithms.CannyEdgeDetector({ + 'image': binary, + 'threshold': cannyThreshold, + 'sigma': cannySigma +}) + +# Process canny edges. + +# Get the edges and length of edges. +connected = canny.updateMask(canny).lt(cannyLt) \ + .connectedPixelCount(connectedPixels, True) + +# Mask short edges that can be noise. +edges = connected.gte(edgeLength) + +# Calculate the buffer in pixel size. +edgeBufferPixel = ee.Number(edgeBuffer).divide(imageProj \ + .nominalScale()) + +# Buffer the edges using a dilation operation. +bufferedEdges = edges.fastDistanceTransform().lt(edgeBufferPixel) + +# Mask areas not within the buffer . +edgeImage = s1Image.select(band).updateMask(bufferedEdges) + +# Add the detected edges and buffered edges to the map. +Map.addLayer(edges, { + 'palette': 'red' +}, 'Detected water edges') +edgesVis = { + 'palette': 'yellow', + 'opacity': 0.5 +} +Map.addLayer(bufferedEdges.selfMask(), edgesVis, + 'Buffered water edges') + +# Reduce all of the image values. +localHistogram = ee.Dictionary( + edgeImage.reduceRegion({ + 'reducer': histogramReducer, + 'geometry': s1Image.geometry(), + 'scale': 90, + 'maxPixels': 1e10 + }).get(band) +) + +# Apply otsu thresholding. +localThreshold = otsu(localHistogram) +print('Adaptive threshold value:', localThreshold) + +# Extract out the histogram buckets and counts per bucket. +x = ee.List(localHistogram.get('bucketMeans')) +y = ee.List(localHistogram.get('histogram')) + +# Define a list of values to plot. +dataCol = ee.Array.cat([x, y], 1).toList() + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create list of empty strings that will be used for annotation. +thresholdCol = ee.List.repeat('', x.length()) +# Find the index that bucketMean equals the threshold. +threshIndex = x.indexOf(localThreshold) +# Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold') + +# Redefine the column header information now with annotation col. +columnHeader = ee.List([ + [ + { + 'label': 'Backscatter', + 'role': 'domain', + 'type': 'number' + }, + { + 'label': 'Values', + 'role': 'data', + 'type': 'number' + }, + { + 'label': 'Threshold', + 'role': 'annotation', + 'type': 'string' + }] +]) + +# Loop through the data rows and add the annotation col. +i) { + i = ee.Number(i) + row = ee.List(dataCol.get(i)) + return row.add(ee.String(thresholdCol.get(i))) +}) + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create plot using the ui.Chart function with the dataTable. +# Use 'evaluate' to transfer the server-side table to the client. +# Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + # Loop through the client-side table and set empty strings to None. + for i in range(0, dataTableClient.length, 1): + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = None + } + + chart = ui.Chart(dataTableClient) \ + .setChartType('AreaChart') \ + .setOptions({ + 'title': band + \ + ' Adaptive Histogram with Threshold annotation', + 'hAxis': { + 'title': 'Backscatter [dB]', + 'viewWindow': { + 'min': -35, + 'max': 15 + } + }, + 'vAxis': { + 'title': 'Count' + }, + 'annotations': { + 'style': 'line' + } + }) + print(chart) +}) + +# Apply the threshold on the image to extract water. +localWater = s1Image.select(band).lt(localThreshold) + +# Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(localWater.selfMask(), + { + 'palette': 'darkblue' + }, + 'Water (adaptive threshold)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23c Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23c Checkpoint.ipynb new file mode 100644 index 0000000..d4087d6 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23c Checkpoint.ipynb @@ -0,0 +1,537 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.3 Surface Water Mapping\n", + "# Checkpoint: A23c\n", + "# Authors: K. Markert, G. Donchyts, A. Haag\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# *** Section 1 ***\n", + "\n", + "# Define a point in Cambodia to filter by location.\n", + "point = ee.Geometry.Point(104.9632, 11.7686)\n", + "\n", + "Map.centerObject(point, 11)\n", + "\n", + "# Get the Sentinel-1 collection and filter by space/time.\n", + "s1Collection = ee.ImageCollection('COPERNICUS/S1_GRD') \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2019-10-05', '2019-10-06') \\\n", + " .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING')) \\\n", + " .filter(ee.Filter.eq('instrumentMode', 'IW'))\n", + "\n", + "# Grab the first image in the collection.\n", + "s1Image = s1Collection.first()\n", + "\n", + "# Add the Sentinel-1 image to the map.\n", + "Map.addLayer(s1Image, {\n", + " 'min': -25,\n", + " 'max': 0,\n", + " 'bands': 'VV'\n", + "}, 'Sentinel-1 image')\n", + "\n", + "# Specify band to use for Otsu thresholding.\n", + "band = 'VV'\n", + "\n", + "# Define a reducer to calculate a histogram of values.\n", + "histogramReducer = ee.Reducer.histogram(255, 0.1)\n", + "\n", + "# Reduce all of the image values.\n", + "globalHistogram = ee.Dictionary(\n", + " s1Image.select(band).reduceRegion({\n", + " 'reducer': histogramReducer,\n", + " 'geometry': s1Image.geometry(),\n", + " 'scale': 90,\n", + " 'maxPixels': 1e10\n", + " }).get(band)\n", + ")\n", + "\n", + "# Extract out the histogram buckets and counts per bucket.\n", + "x = ee.List(globalHistogram.get('bucketMeans'))\n", + "y = ee.List(globalHistogram.get('histogram'))\n", + "\n", + "# Define a list of values to plot.\n", + "dataCol = ee.Array.cat([x, y], 1).toList()\n", + "\n", + "# Define the header information for data.\n", + "columnHeader = ee.List([\n", + " [\n", + " {\n", + " 'label': 'Backscatter',\n", + " 'role': 'domain',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Values',\n", + " 'role': 'data',\n", + " 'type': 'number'\n", + " }, ]\n", + "])\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create plot using the ui.Chart function with the dataTable.\n", + "# Use 'evaluate' to transfer the server-side table to the client.\n", + "# Define the chart and print it to the console.\n", + "dataTable.evaluate(function(dataTableClient) {\n", + " chart = ui.Chart(dataTableClient) \\\n", + " .setChartType('AreaChart') \\\n", + " .setOptions({\n", + " 'title': band + ' Global Histogram',\n", + " 'hAxis': {\n", + " 'title': 'Backscatter [dB]',\n", + " 'viewWindow': {\n", + " 'min': -35,\n", + " 'max': 15\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Count'\n", + " }\n", + " })\n", + " print(chart)\n", + "})\n", + "\n", + "# See:\n", + "# https:#medium.com/google-earth/otsus-method-for-image-segmentation-f5c48f405e\n", + "def otsu(histogram):\n", + " # Make sure histogram is an ee.Dictionary object.\n", + " histogram = ee.Dictionary(histogram)\n", + " # Extract relevant values into arrays.\n", + " counts = ee.Array(histogram.get('histogram'))\n", + " means = ee.Array(histogram.get('bucketMeans'))\n", + " # Calculate single statistics over arrays\n", + " size = means.length().get([0])\n", + " total = counts.reduce(ee.Reducer.sum(), [0]).get([0])\n", + " sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) \\\n", + " .get([0])\n", + " mean = sum.divide(total)\n", + " # Compute between sum of squares, where each mean partitions the data.\n", + " indices = ee.List.sequence(1, size)\n", + "\n", + "def func_gfk(i):\n", + " aCounts = counts.slice(0, 0, i)\n", + " aCount = aCounts.reduce(ee.Reducer.sum(), [0]) \\\n", + " .get([0])\n", + " aMeans = means.slice(0, 0, i)\n", + " aMean = aMeans.multiply(aCounts) \\\n", + " .reduce(ee.Reducer.sum(), [0]).get([0]) \\\n", + " .divide(aCount)\n", + " bCount = total.subtract(aCount)\n", + " bMean = sum.subtract(aCount.multiply(aMean)) \\\n", + " .divide(bCount)\n", + " return aCount.multiply(aMean.subtract(mean).pow(2)) \\\n", + " .add(\n", + " bCount.multiply(bMean.subtract(mean).pow(2)))\n", + "\n", + " bss = indices.map(func_gfk)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " # Return the mean value corresponding to the maximum BSS.\n", + " return means.sort(bss).get([-1])\n", + "\n", + "\n", + "# Apply otsu thresholding.\n", + "globalThreshold = otsu(globalHistogram)\n", + "print('Global threshold value:', globalThreshold)\n", + "\n", + "# Create list of empty strings that will be used for annotation.\n", + "thresholdCol = ee.List.repeat('', x.length())\n", + "# Find the index where the bucketMean equals the threshold.\n", + "threshIndex = x.indexOf(globalThreshold)\n", + "# Set the index to the annotation text.\n", + "thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold')\n", + "\n", + "# Redefine the column header information with annotation column.\n", + "columnHeader = ee.List([\n", + " [\n", + " {\n", + " 'label': 'Backscatter',\n", + " 'role': 'domain',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Values',\n", + " 'role': 'data',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Threshold',\n", + " 'role': 'annotation',\n", + " 'type': 'string'\n", + " }]\n", + "])\n", + "\n", + "# Loop through the data rows and add the annotation column.\n", + "i) {\n", + " i = ee.Number(i)\n", + " row = ee.List(dataCol.get(i))\n", + " return row.add(ee.String(thresholdCol.get(i)))\n", + "})\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create plot using the ui.Chart function with the dataTable.\n", + "# Use 'evaluate' to transfer the server-side table to the client.\n", + "# Define the chart and print it to the console.\n", + "dataTable.evaluate(function(dataTableClient) {\n", + " # loop through the client-side table and set empty strings to None\n", + " for i in range(0, dataTableClient.length, 1):\n", + " if (dataTableClient[i][2] === '') {\n", + " dataTableClient[i][2] = None\n", + " }\n", + "\n", + " chart = ui.Chart(dataTableClient) \\\n", + " .setChartType('AreaChart') \\\n", + " .setOptions({\n", + " 'title': band + \\\n", + " ' Global Histogram with Threshold annotation',\n", + " 'hAxis': {\n", + " 'title': 'Backscatter [dB]',\n", + " 'viewWindow': {\n", + " 'min': -35,\n", + " 'max': 15\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Count'\n", + " },\n", + " 'annotations': {\n", + " 'style': 'line'\n", + " }\n", + " })\n", + " print(chart)\n", + "})\n", + "\n", + "# Apply the threshold on the image to extract water.\n", + "globalWater = s1Image.select(band).lt(globalThreshold)\n", + "\n", + "# Add the water image to the map and mask 0 (no-water) values.\n", + "Map.addLayer(globalWater.selfMask(),\n", + " {\n", + " 'palette': 'blue'\n", + " },\n", + " 'Water (global threshold)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# *** Section 2 ***\n", + "\n", + "# Define parameters for the adaptive thresholding.\n", + "# Initial estimate of water/no-water for estimating the edges\n", + "initialThreshold = -16\n", + "# Number of connected pixels to use for length calculation.\n", + "connectedPixels = 100\n", + "# Length of edges to be considered water edges.\n", + "edgeLength = 20\n", + "# Buffer in meters to apply to edges.\n", + "edgeBuffer = 300\n", + "# Threshold for canny edge detection.\n", + "cannyThreshold = 1\n", + "# Sigma value for gaussian filter in canny edge detection.\n", + "cannySigma = 1\n", + "# Lower threshold for canny detection.\n", + "cannyLt = 0.05\n", + "\n", + "# Get preliminary water.\n", + "binary = s1Image.select(band).lt(initialThreshold) \\\n", + " .rename('binary')\n", + "\n", + "# Get projection information to convert buffer size to pixels.\n", + "imageProj = s1Image.select(band).projection()\n", + "\n", + "# Get canny edges.\n", + "canny = ee.Algorithms.CannyEdgeDetector({\n", + " 'image': binary,\n", + " 'threshold': cannyThreshold,\n", + " 'sigma': cannySigma\n", + "})\n", + "\n", + "# Process canny edges.\n", + "\n", + "# Get the edges and length of edges.\n", + "connected = canny.updateMask(canny).lt(cannyLt) \\\n", + " .connectedPixelCount(connectedPixels, True)\n", + "\n", + "# Mask short edges that can be noise.\n", + "edges = connected.gte(edgeLength)\n", + "\n", + "# Calculate the buffer in pixel size.\n", + "edgeBufferPixel = ee.Number(edgeBuffer).divide(imageProj \\\n", + " .nominalScale())\n", + "\n", + "# Buffer the edges using a dilation operation.\n", + "bufferedEdges = edges.fastDistanceTransform().lt(edgeBufferPixel)\n", + "\n", + "# Mask areas not within the buffer .\n", + "edgeImage = s1Image.select(band).updateMask(bufferedEdges)\n", + "\n", + "# Add the detected edges and buffered edges to the map.\n", + "Map.addLayer(edges, {\n", + " 'palette': 'red'\n", + "}, 'Detected water edges')\n", + "edgesVis = {\n", + " 'palette': 'yellow',\n", + " 'opacity': 0.5\n", + "}\n", + "Map.addLayer(bufferedEdges.selfMask(), edgesVis,\n", + " 'Buffered water edges')\n", + "\n", + "# Reduce all of the image values.\n", + "localHistogram = ee.Dictionary(\n", + " edgeImage.reduceRegion({\n", + " 'reducer': histogramReducer,\n", + " 'geometry': s1Image.geometry(),\n", + " 'scale': 90,\n", + " 'maxPixels': 1e10\n", + " }).get(band)\n", + ")\n", + "\n", + "# Apply otsu thresholding.\n", + "localThreshold = otsu(localHistogram)\n", + "print('Adaptive threshold value:', localThreshold)\n", + "\n", + "# Extract out the histogram buckets and counts per bucket.\n", + "x = ee.List(localHistogram.get('bucketMeans'))\n", + "y = ee.List(localHistogram.get('histogram'))\n", + "\n", + "# Define a list of values to plot.\n", + "dataCol = ee.Array.cat([x, y], 1).toList()\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create list of empty strings that will be used for annotation.\n", + "thresholdCol = ee.List.repeat('', x.length())\n", + "# Find the index that bucketMean equals the threshold.\n", + "threshIndex = x.indexOf(localThreshold)\n", + "# Set the index to the annotation text.\n", + "thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold')\n", + "\n", + "# Redefine the column header information now with annotation col.\n", + "columnHeader = ee.List([\n", + " [\n", + " {\n", + " 'label': 'Backscatter',\n", + " 'role': 'domain',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Values',\n", + " 'role': 'data',\n", + " 'type': 'number'\n", + " },\n", + " {\n", + " 'label': 'Threshold',\n", + " 'role': 'annotation',\n", + " 'type': 'string'\n", + " }]\n", + "])\n", + "\n", + "# Loop through the data rows and add the annotation col.\n", + "i) {\n", + " i = ee.Number(i)\n", + " row = ee.List(dataCol.get(i))\n", + " return row.add(ee.String(thresholdCol.get(i)))\n", + "})\n", + "\n", + "# Concat the header and data for plotting.\n", + "dataTable = columnHeader.cat(dataCol)\n", + "\n", + "# Create plot using the ui.Chart function with the dataTable.\n", + "# Use 'evaluate' to transfer the server-side table to the client.\n", + "# Define the chart and print it to the console.\n", + "dataTable.evaluate(function(dataTableClient) {\n", + " # Loop through the client-side table and set empty strings to None.\n", + " for i in range(0, dataTableClient.length, 1):\n", + " if (dataTableClient[i][2] === '') {\n", + " dataTableClient[i][2] = None\n", + " }\n", + "\n", + " chart = ui.Chart(dataTableClient) \\\n", + " .setChartType('AreaChart') \\\n", + " .setOptions({\n", + " 'title': band + \\\n", + " ' Adaptive Histogram with Threshold annotation',\n", + " 'hAxis': {\n", + " 'title': 'Backscatter [dB]',\n", + " 'viewWindow': {\n", + " 'min': -35,\n", + " 'max': 15\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Count'\n", + " },\n", + " 'annotations': {\n", + " 'style': 'line'\n", + " }\n", + " })\n", + " print(chart)\n", + "})\n", + "\n", + "# Apply the threshold on the image to extract water.\n", + "localWater = s1Image.select(band).lt(localThreshold)\n", + "\n", + "# Add the water image to the map and mask 0 (no-water) values.\n", + "Map.addLayer(localWater.selfMask(),\n", + " {\n", + " 'palette': 'darkblue'\n", + " },\n", + " 'Water (adaptive threshold)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Get the previous 5 years of permanent water.\n", + "\n", + "# Get the JRC historical yearly dataset.\n", + "jrc = ee.ImageCollection('JRC/GSW1_3/YearlyHistory') \\\n", + " .filterDate('1985-01-01', s1Image.date()) \\\n", + " .limit(5, 'system:time_start', False)\n", + "\n", + "\n", + "def func_fjc(image):\n", + " # Extract out the permanent water class.\n", + " return image.select('waterClass').eq(3)\n", + " # Reduce the collection to get information on if a pixel has\n", + " # been classified as permanent water in the past 5 years.\n", + "\n", + "permanentWater = jrc.map(func_fjc\n", + ").sum()\n", + "\n", + "\n", + "\n", + "\n", + ").sum() \\\n", + " .unmask(0) \\\n", + " .gt(0) \\\n", + " .updateMask(localWater.mask())\n", + "\n", + "# Add the permanent water layer to the map.\n", + "Map.addLayer(permanentWater.selfMask(),\n", + " {\n", + " 'palette': 'royalblue'\n", + " },\n", + " 'JRC permanent water')\n", + "\n", + "# Find areas where there is not permanent water, but water is observed.\n", + "floodImage = permanentWater.Not().And(localWater)\n", + "\n", + "# Add flood image to map.\n", + "Map.addLayer(floodImage.selfMask(), {\n", + " 'palette': 'firebrick'\n", + "}, 'Flood areas')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23c Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23c Checkpoint.js new file mode 100644 index 0000000..03c50cf --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23c Checkpoint.js @@ -0,0 +1,426 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.3 Surface Water Mapping +// Checkpoint: A23c +// Authors: K. Markert, G. Donchyts, A. Haag +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// *** Section 1 *** + +// Define a point in Cambodia to filter by location. +var point = ee.Geometry.Point(104.9632, 11.7686); + +Map.centerObject(point, 11); + +// Get the Sentinel-1 collection and filter by space/time. +var s1Collection = ee.ImageCollection('COPERNICUS/S1_GRD') + .filterBounds(point) + .filterDate('2019-10-05', '2019-10-06') + .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING')) + .filter(ee.Filter.eq('instrumentMode', 'IW')); + +// Grab the first image in the collection. +var s1Image = s1Collection.first(); + +// Add the Sentinel-1 image to the map. +Map.addLayer(s1Image, { + min: -25, + max: 0, + bands: 'VV' +}, 'Sentinel-1 image'); + +// Specify band to use for Otsu thresholding. +var band = 'VV'; + +// Define a reducer to calculate a histogram of values. +var histogramReducer = ee.Reducer.histogram(255, 0.1); + +// Reduce all of the image values. +var globalHistogram = ee.Dictionary( + s1Image.select(band).reduceRegion({ + reducer: histogramReducer, + geometry: s1Image.geometry(), + scale: 90, + maxPixels: 1e10 + }).get(band) +); + +// Extract out the histogram buckets and counts per bucket. +var x = ee.List(globalHistogram.get('bucketMeans')); +var y = ee.List(globalHistogram.get('histogram')); + +// Define a list of values to plot. +var dataCol = ee.Array.cat([x, y], 1).toList(); + +// Define the header information for data. +var columnHeader = ee.List([ + [ + { + label: 'Backscatter', + role: 'domain', + type: 'number' + }, + { + label: 'Values', + role: 'data', + type: 'number' + }, ] +]); + +// Concat the header and data for plotting. +var dataTable = columnHeader.cat(dataCol); + +// Create plot using the ui.Chart function with the dataTable. +// Use 'evaluate' to transfer the server-side table to the client. +// Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + var chart = ui.Chart(dataTableClient) + .setChartType('AreaChart') + .setOptions({ + title: band + ' Global Histogram', + hAxis: { + title: 'Backscatter [dB]', + viewWindow: { + min: -35, + max: 15 + } + }, + vAxis: { + title: 'Count' + } + }); + print(chart); +}); + +// See: +// https://medium.com/google-earth/otsus-method-for-image-segmentation-f5c48f405e +function otsu(histogram) { + // Make sure histogram is an ee.Dictionary object. + histogram = ee.Dictionary(histogram); + // Extract relevant values into arrays. + var counts = ee.Array(histogram.get('histogram')); + var means = ee.Array(histogram.get('bucketMeans')); + // Calculate single statistics over arrays + var size = means.length().get([0]); + var total = counts.reduce(ee.Reducer.sum(), [0]).get([0]); + var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) + .get([0]); + var mean = sum.divide(total); + // Compute between sum of squares, where each mean partitions the data. + var indices = ee.List.sequence(1, size); + var bss = indices.map(function(i) { + var aCounts = counts.slice(0, 0, i); + var aCount = aCounts.reduce(ee.Reducer.sum(), [0]) + .get([0]); + var aMeans = means.slice(0, 0, i); + var aMean = aMeans.multiply(aCounts) + .reduce(ee.Reducer.sum(), [0]).get([0]) + .divide(aCount); + var bCount = total.subtract(aCount); + var bMean = sum.subtract(aCount.multiply(aMean)) + .divide(bCount); + return aCount.multiply(aMean.subtract(mean).pow(2)) + .add( + bCount.multiply(bMean.subtract(mean).pow(2))); + }); + // Return the mean value corresponding to the maximum BSS. + return means.sort(bss).get([-1]); +} + +// Apply otsu thresholding. +var globalThreshold = otsu(globalHistogram); +print('Global threshold value:', globalThreshold); + +// Create list of empty strings that will be used for annotation. +var thresholdCol = ee.List.repeat('', x.length()); +// Find the index where the bucketMean equals the threshold. +var threshIndex = x.indexOf(globalThreshold); +// Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold'); + +// Redefine the column header information with annotation column. +columnHeader = ee.List([ + [ + { + label: 'Backscatter', + role: 'domain', + type: 'number' + }, + { + label: 'Values', + role: 'data', + type: 'number' + }, + { + label: 'Threshold', + role: 'annotation', + type: 'string' + }] +]); + +// Loop through the data rows and add the annotation column. +dataCol = ee.List.sequence(0, x.length().subtract(1)).map(function( +i) { + i = ee.Number(i); + var row = ee.List(dataCol.get(i)); + return row.add(ee.String(thresholdCol.get(i))); +}); + +// Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol); + +// Create plot using the ui.Chart function with the dataTable. +// Use 'evaluate' to transfer the server-side table to the client. +// Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + // loop through the client-side table and set empty strings to null + for (var i = 0; i < dataTableClient.length; i++) { + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = null; + } + } + var chart = ui.Chart(dataTableClient) + .setChartType('AreaChart') + .setOptions({ + title: band + + ' Global Histogram with Threshold annotation', + hAxis: { + title: 'Backscatter [dB]', + viewWindow: { + min: -35, + max: 15 + } + }, + vAxis: { + title: 'Count' + }, + annotations: { + style: 'line' + } + }); + print(chart); +}); + +// Apply the threshold on the image to extract water. +var globalWater = s1Image.select(band).lt(globalThreshold); + +// Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(globalWater.selfMask(), + { + palette: 'blue' + }, + 'Water (global threshold)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// *** Section 2 *** + +// Define parameters for the adaptive thresholding. +// Initial estimate of water/no-water for estimating the edges +var initialThreshold = -16; +// Number of connected pixels to use for length calculation. +var connectedPixels = 100; +// Length of edges to be considered water edges. +var edgeLength = 20; +// Buffer in meters to apply to edges. +var edgeBuffer = 300; +// Threshold for canny edge detection. +var cannyThreshold = 1; +// Sigma value for gaussian filter in canny edge detection. +var cannySigma = 1; +// Lower threshold for canny detection. +var cannyLt = 0.05; + +// Get preliminary water. +var binary = s1Image.select(band).lt(initialThreshold) + .rename('binary'); + +// Get projection information to convert buffer size to pixels. +var imageProj = s1Image.select(band).projection(); + +// Get canny edges. +var canny = ee.Algorithms.CannyEdgeDetector({ + image: binary, + threshold: cannyThreshold, + sigma: cannySigma +}); + +// Process canny edges. + +// Get the edges and length of edges. +var connected = canny.updateMask(canny).lt(cannyLt) + .connectedPixelCount(connectedPixels, true); + +// Mask short edges that can be noise. +var edges = connected.gte(edgeLength); + +// Calculate the buffer in pixel size. +var edgeBufferPixel = ee.Number(edgeBuffer).divide(imageProj + .nominalScale()); + +// Buffer the edges using a dilation operation. +var bufferedEdges = edges.fastDistanceTransform().lt(edgeBufferPixel); + +// Mask areas not within the buffer . +var edgeImage = s1Image.select(band).updateMask(bufferedEdges); + +// Add the detected edges and buffered edges to the map. +Map.addLayer(edges, { + palette: 'red' +}, 'Detected water edges'); +var edgesVis = { + palette: 'yellow', + opacity: 0.5 +}; +Map.addLayer(bufferedEdges.selfMask(), edgesVis, + 'Buffered water edges'); + +// Reduce all of the image values. +var localHistogram = ee.Dictionary( + edgeImage.reduceRegion({ + reducer: histogramReducer, + geometry: s1Image.geometry(), + scale: 90, + maxPixels: 1e10 + }).get(band) +); + +// Apply otsu thresholding. +var localThreshold = otsu(localHistogram); +print('Adaptive threshold value:', localThreshold); + +// Extract out the histogram buckets and counts per bucket. +var x = ee.List(localHistogram.get('bucketMeans')); +var y = ee.List(localHistogram.get('histogram')); + +// Define a list of values to plot. +var dataCol = ee.Array.cat([x, y], 1).toList(); + +// Concat the header and data for plotting. +var dataTable = columnHeader.cat(dataCol); + +// Create list of empty strings that will be used for annotation. +var thresholdCol = ee.List.repeat('', x.length()); +// Find the index that bucketMean equals the threshold. +var threshIndex = x.indexOf(localThreshold); +// Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold'); + +// Redefine the column header information now with annotation col. +columnHeader = ee.List([ + [ + { + label: 'Backscatter', + role: 'domain', + type: 'number' + }, + { + label: 'Values', + role: 'data', + type: 'number' + }, + { + label: 'Threshold', + role: 'annotation', + type: 'string' + }] +]); + +// Loop through the data rows and add the annotation col. +dataCol = ee.List.sequence(0, x.length().subtract(1)).map(function( +i) { + i = ee.Number(i); + var row = ee.List(dataCol.get(i)); + return row.add(ee.String(thresholdCol.get(i))); +}); + +// Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol); + +// Create plot using the ui.Chart function with the dataTable. +// Use 'evaluate' to transfer the server-side table to the client. +// Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + // Loop through the client-side table and set empty strings to null. + for (var i = 0; i < dataTableClient.length; i++) { + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = null; + } + } + var chart = ui.Chart(dataTableClient) + .setChartType('AreaChart') + .setOptions({ + title: band + + ' Adaptive Histogram with Threshold annotation', + hAxis: { + title: 'Backscatter [dB]', + viewWindow: { + min: -35, + max: 15 + } + }, + vAxis: { + title: 'Count' + }, + annotations: { + style: 'line' + } + }); + print(chart); +}); + +// Apply the threshold on the image to extract water. +var localWater = s1Image.select(band).lt(localThreshold); + +// Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(localWater.selfMask(), + { + palette: 'darkblue' + }, + 'Water (adaptive threshold)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Get the previous 5 years of permanent water. + +// Get the JRC historical yearly dataset. +var jrc = ee.ImageCollection('JRC/GSW1_3/YearlyHistory') + // Filter for historical data up to date of interest. + .filterDate('1985-01-01', s1Image.date()) + // Grab the 5 latest images/years. + .limit(5, 'system:time_start', false); + +var permanentWater = jrc.map(function(image) { + // Extract out the permanent water class. + return image.select('waterClass').eq(3); + // Reduce the collection to get information on if a pixel has + // been classified as permanent water in the past 5 years. + }).sum() + // Make sure we have a value everywhere. + .unmask(0) + // Get an image of 1 if permanent water in the past 5 years, otherwise 0. + .gt(0) + // Mask for only the water image we just calculated. + .updateMask(localWater.mask()); + +// Add the permanent water layer to the map. +Map.addLayer(permanentWater.selfMask(), + { + palette: 'royalblue' + }, + 'JRC permanent water'); + +// Find areas where there is not permanent water, but water is observed. +var floodImage = permanentWater.not().and(localWater); + +// Add flood image to map. +Map.addLayer(floodImage.selfMask(), { + palette: 'firebrick' +}, 'Flood areas'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23c Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23c Checkpoint.py new file mode 100644 index 0000000..1d50464 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.3 Surface Water Mapping/A23c Checkpoint.py @@ -0,0 +1,450 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.3 Surface Water Mapping +# Checkpoint: A23c +# Authors: K. Markert, G. Donchyts, A. Haag +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# *** Section 1 *** + +# Define a point in Cambodia to filter by location. +point = ee.Geometry.Point(104.9632, 11.7686) + +Map.centerObject(point, 11) + +# Get the Sentinel-1 collection and filter by space/time. +s1Collection = ee.ImageCollection('COPERNICUS/S1_GRD') \ + .filterBounds(point) \ + .filterDate('2019-10-05', '2019-10-06') \ + .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING')) \ + .filter(ee.Filter.eq('instrumentMode', 'IW')) + +# Grab the first image in the collection. +s1Image = s1Collection.first() + +# Add the Sentinel-1 image to the map. +Map.addLayer(s1Image, { + 'min': -25, + 'max': 0, + 'bands': 'VV' +}, 'Sentinel-1 image') + +# Specify band to use for Otsu thresholding. +band = 'VV' + +# Define a reducer to calculate a histogram of values. +histogramReducer = ee.Reducer.histogram(255, 0.1) + +# Reduce all of the image values. +globalHistogram = ee.Dictionary( + s1Image.select(band).reduceRegion({ + 'reducer': histogramReducer, + 'geometry': s1Image.geometry(), + 'scale': 90, + 'maxPixels': 1e10 + }).get(band) +) + +# Extract out the histogram buckets and counts per bucket. +x = ee.List(globalHistogram.get('bucketMeans')) +y = ee.List(globalHistogram.get('histogram')) + +# Define a list of values to plot. +dataCol = ee.Array.cat([x, y], 1).toList() + +# Define the header information for data. +columnHeader = ee.List([ + [ + { + 'label': 'Backscatter', + 'role': 'domain', + 'type': 'number' + }, + { + 'label': 'Values', + 'role': 'data', + 'type': 'number' + }, ] +]) + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create plot using the ui.Chart function with the dataTable. +# Use 'evaluate' to transfer the server-side table to the client. +# Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + chart = ui.Chart(dataTableClient) \ + .setChartType('AreaChart') \ + .setOptions({ + 'title': band + ' Global Histogram', + 'hAxis': { + 'title': 'Backscatter [dB]', + 'viewWindow': { + 'min': -35, + 'max': 15 + } + }, + 'vAxis': { + 'title': 'Count' + } + }) + print(chart) +}) + +# See: +# https:#medium.com/google-earth/otsus-method-for-image-segmentation-f5c48f405e +def otsu(histogram): + # Make sure histogram is an ee.Dictionary object. + histogram = ee.Dictionary(histogram) + # Extract relevant values into arrays. + counts = ee.Array(histogram.get('histogram')) + means = ee.Array(histogram.get('bucketMeans')) + # Calculate single statistics over arrays + size = means.length().get([0]) + total = counts.reduce(ee.Reducer.sum(), [0]).get([0]) + sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) \ + .get([0]) + mean = sum.divide(total) + # Compute between sum of squares, where each mean partitions the data. + indices = ee.List.sequence(1, size) + +def func_gfk(i): + aCounts = counts.slice(0, 0, i) + aCount = aCounts.reduce(ee.Reducer.sum(), [0]) \ + .get([0]) + aMeans = means.slice(0, 0, i) + aMean = aMeans.multiply(aCounts) \ + .reduce(ee.Reducer.sum(), [0]).get([0]) \ + .divide(aCount) + bCount = total.subtract(aCount) + bMean = sum.subtract(aCount.multiply(aMean)) \ + .divide(bCount) + return aCount.multiply(aMean.subtract(mean).pow(2)) \ + .add( + bCount.multiply(bMean.subtract(mean).pow(2))) + + bss = indices.map(func_gfk) + + + + + + + + + + + + + + + + # Return the mean value corresponding to the maximum BSS. + return means.sort(bss).get([-1]) + + +# Apply otsu thresholding. +globalThreshold = otsu(globalHistogram) +print('Global threshold value:', globalThreshold) + +# Create list of empty strings that will be used for annotation. +thresholdCol = ee.List.repeat('', x.length()) +# Find the index where the bucketMean equals the threshold. +threshIndex = x.indexOf(globalThreshold) +# Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold') + +# Redefine the column header information with annotation column. +columnHeader = ee.List([ + [ + { + 'label': 'Backscatter', + 'role': 'domain', + 'type': 'number' + }, + { + 'label': 'Values', + 'role': 'data', + 'type': 'number' + }, + { + 'label': 'Threshold', + 'role': 'annotation', + 'type': 'string' + }] +]) + +# Loop through the data rows and add the annotation column. +i) { + i = ee.Number(i) + row = ee.List(dataCol.get(i)) + return row.add(ee.String(thresholdCol.get(i))) +}) + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create plot using the ui.Chart function with the dataTable. +# Use 'evaluate' to transfer the server-side table to the client. +# Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + # loop through the client-side table and set empty strings to None + for i in range(0, dataTableClient.length, 1): + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = None + } + + chart = ui.Chart(dataTableClient) \ + .setChartType('AreaChart') \ + .setOptions({ + 'title': band + \ + ' Global Histogram with Threshold annotation', + 'hAxis': { + 'title': 'Backscatter [dB]', + 'viewWindow': { + 'min': -35, + 'max': 15 + } + }, + 'vAxis': { + 'title': 'Count' + }, + 'annotations': { + 'style': 'line' + } + }) + print(chart) +}) + +# Apply the threshold on the image to extract water. +globalWater = s1Image.select(band).lt(globalThreshold) + +# Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(globalWater.selfMask(), + { + 'palette': 'blue' + }, + 'Water (global threshold)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# *** Section 2 *** + +# Define parameters for the adaptive thresholding. +# Initial estimate of water/no-water for estimating the edges +initialThreshold = -16 +# Number of connected pixels to use for length calculation. +connectedPixels = 100 +# Length of edges to be considered water edges. +edgeLength = 20 +# Buffer in meters to apply to edges. +edgeBuffer = 300 +# Threshold for canny edge detection. +cannyThreshold = 1 +# Sigma value for gaussian filter in canny edge detection. +cannySigma = 1 +# Lower threshold for canny detection. +cannyLt = 0.05 + +# Get preliminary water. +binary = s1Image.select(band).lt(initialThreshold) \ + .rename('binary') + +# Get projection information to convert buffer size to pixels. +imageProj = s1Image.select(band).projection() + +# Get canny edges. +canny = ee.Algorithms.CannyEdgeDetector({ + 'image': binary, + 'threshold': cannyThreshold, + 'sigma': cannySigma +}) + +# Process canny edges. + +# Get the edges and length of edges. +connected = canny.updateMask(canny).lt(cannyLt) \ + .connectedPixelCount(connectedPixels, True) + +# Mask short edges that can be noise. +edges = connected.gte(edgeLength) + +# Calculate the buffer in pixel size. +edgeBufferPixel = ee.Number(edgeBuffer).divide(imageProj \ + .nominalScale()) + +# Buffer the edges using a dilation operation. +bufferedEdges = edges.fastDistanceTransform().lt(edgeBufferPixel) + +# Mask areas not within the buffer . +edgeImage = s1Image.select(band).updateMask(bufferedEdges) + +# Add the detected edges and buffered edges to the map. +Map.addLayer(edges, { + 'palette': 'red' +}, 'Detected water edges') +edgesVis = { + 'palette': 'yellow', + 'opacity': 0.5 +} +Map.addLayer(bufferedEdges.selfMask(), edgesVis, + 'Buffered water edges') + +# Reduce all of the image values. +localHistogram = ee.Dictionary( + edgeImage.reduceRegion({ + 'reducer': histogramReducer, + 'geometry': s1Image.geometry(), + 'scale': 90, + 'maxPixels': 1e10 + }).get(band) +) + +# Apply otsu thresholding. +localThreshold = otsu(localHistogram) +print('Adaptive threshold value:', localThreshold) + +# Extract out the histogram buckets and counts per bucket. +x = ee.List(localHistogram.get('bucketMeans')) +y = ee.List(localHistogram.get('histogram')) + +# Define a list of values to plot. +dataCol = ee.Array.cat([x, y], 1).toList() + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create list of empty strings that will be used for annotation. +thresholdCol = ee.List.repeat('', x.length()) +# Find the index that bucketMean equals the threshold. +threshIndex = x.indexOf(localThreshold) +# Set the index to the annotation text. +thresholdCol = thresholdCol.set(threshIndex, 'Otsu Threshold') + +# Redefine the column header information now with annotation col. +columnHeader = ee.List([ + [ + { + 'label': 'Backscatter', + 'role': 'domain', + 'type': 'number' + }, + { + 'label': 'Values', + 'role': 'data', + 'type': 'number' + }, + { + 'label': 'Threshold', + 'role': 'annotation', + 'type': 'string' + }] +]) + +# Loop through the data rows and add the annotation col. +i) { + i = ee.Number(i) + row = ee.List(dataCol.get(i)) + return row.add(ee.String(thresholdCol.get(i))) +}) + +# Concat the header and data for plotting. +dataTable = columnHeader.cat(dataCol) + +# Create plot using the ui.Chart function with the dataTable. +# Use 'evaluate' to transfer the server-side table to the client. +# Define the chart and print it to the console. +dataTable.evaluate(function(dataTableClient) { + # Loop through the client-side table and set empty strings to None. + for i in range(0, dataTableClient.length, 1): + if (dataTableClient[i][2] === '') { + dataTableClient[i][2] = None + } + + chart = ui.Chart(dataTableClient) \ + .setChartType('AreaChart') \ + .setOptions({ + 'title': band + \ + ' Adaptive Histogram with Threshold annotation', + 'hAxis': { + 'title': 'Backscatter [dB]', + 'viewWindow': { + 'min': -35, + 'max': 15 + } + }, + 'vAxis': { + 'title': 'Count' + }, + 'annotations': { + 'style': 'line' + } + }) + print(chart) +}) + +# Apply the threshold on the image to extract water. +localWater = s1Image.select(band).lt(localThreshold) + +# Add the water image to the map and mask 0 (no-water) values. +Map.addLayer(localWater.selfMask(), + { + 'palette': 'darkblue' + }, + 'Water (adaptive threshold)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Get the previous 5 years of permanent water. + +# Get the JRC historical yearly dataset. +jrc = ee.ImageCollection('JRC/GSW1_3/YearlyHistory') \ + .filterDate('1985-01-01', s1Image.date()) \ + .limit(5, 'system:time_start', False) + + +def func_fjc(image): + # Extract out the permanent water class. + return image.select('waterClass').eq(3) + # Reduce the collection to get information on if a pixel has + # been classified as permanent water in the past 5 years. + +permanentWater = jrc.map(func_fjc +).sum() + + + + +).sum() \ + .unmask(0) \ + .gt(0) \ + .updateMask(localWater.mask()) + +# Add the permanent water layer to the map. +Map.addLayer(permanentWater.selfMask(), + { + 'palette': 'royalblue' + }, + 'JRC permanent water') + +# Find areas where there is not permanent water, but water is observed. +floodImage = permanentWater.Not().And(localWater) + +# Add flood image to map. +Map.addLayer(floodImage.selfMask(), { + 'palette': 'firebrick' +}, 'Flood areas') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24a Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24a Checkpoint.ipynb new file mode 100644 index 0000000..3e0e360 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24a Checkpoint.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "aoi =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-67.18414102495456, -11.09095257894929],\n", + " [-67.18414102495456, -11.402427204567534],\n", + " [-66.57886300981784, -11.402427204567534],\n", + " [-66.57886300981784, -11.09095257894929]]], None, False),\n", + " sword = ee.FeatureCollection(\"projects/gee-book/assets/A2-4/SWORD\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.4 River Morphology\n", + "# Checkpoint: A24a\n", + "# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# THIS SCRIPT IS DESIGNED AS A TUTORIAL TO SHOWCASE USING GOOGLE EARTH ENGINE TO ANALYSE\n", + "# RIVER PLANVIEW GEOMETRIES AND MORPHOLOGICAL DYNAMICS. THE ANALYSIS IS BUILT ON EXISTING\n", + "# MONTHLY WATER CLASSIFICATIONS DATASETS AVAILABLE IN GOOGLE EARTH ENGINE. BY SHOWING\n", + "# PREPROCESSING STEPS LIKE HOW TO IDENTIFY RIVERS FROM OTHER TYPES OF WATER BODIES, AND HOW\n", + "# TO USE MULTI TEMPORAL WATER LAYERS TO EXTRACT DYNAMICAL CHANGES IN RIVER MORPHOLOGY, IT PROVIDES\n", + "# A GUIDE TO EXTRACT INFORMATIONS ON RIVERS USING GOOGLE EARTH ENGINE.\n", + "\n", + "# ==========================================================\n", + "\n", + "def getUTMProj(lon, lat):\n", + " # given longitude and latitude (in degree decimals) return EPSG string for the\n", + " # corresponding UTM projection\n", + " # see https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily and\n", + " # https:#sis.apache.Org/faq.html\n", + " utmCode = ee.Number(lon).add(180).divide(6).ceil().int()\n", + " output = ee.Algorithms.If(ee.Number(lat).gte(0),\n", + " ee.String('EPSG:326').cat(utmCode.format('%02d')),\n", + " ee.String('EPSG:327').cat(utmCode.format('%02d')))\n", + " return (output)\n", + "\n", + "\n", + "coords = aoi.centroid(30).coordinates()\n", + "lon = coords.get(0)\n", + "lat = coords.get(1)\n", + "crs = getUTMProj(lon, lat)\n", + "scale = ee.Number(30)\n", + "\n", + "def rpj(image):\n", + " return image.reproject({\n", + " 'crs': crs,\n", + " 'scale': scale\n", + " })\n", + "\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24a Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24a Checkpoint.js new file mode 100644 index 0000000..2081d75 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24a Checkpoint.js @@ -0,0 +1,58 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var aoi = + /* color: #d63000 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-67.18414102495456, -11.09095257894929], + [-67.18414102495456, -11.402427204567534], + [-66.57886300981784, -11.402427204567534], + [-66.57886300981784, -11.09095257894929]]], null, false), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.4 River Morphology +// Checkpoint: A24a +// Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// THIS SCRIPT IS DESIGNED AS A TUTORIAL TO SHOWCASE USING GOOGLE EARTH ENGINE TO ANALYSE +// RIVER PLANVIEW GEOMETRIES AND MORPHOLOGICAL DYNAMICS. THE ANALYSIS IS BUILT ON EXISTING +// MONTHLY WATER CLASSIFICATIONS DATASETS AVAILABLE IN GOOGLE EARTH ENGINE. BY SHOWING +// PREPROCESSING STEPS LIKE HOW TO IDENTIFY RIVERS FROM OTHER TYPES OF WATER BODIES, AND HOW +// TO USE MULTI TEMPORAL WATER LAYERS TO EXTRACT DYNAMICAL CHANGES IN RIVER MORPHOLOGY, IT PROVIDES +// A GUIDE TO EXTRACT INFORMATIONS ON RIVERS USING GOOGLE EARTH ENGINE. + +// ========================================================== + +var getUTMProj = function(lon, lat) { + // given longitude and latitude (in degree decimals) return EPSG string for the + // corresponding UTM projection + // see https://apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily and + // https://sis.apache.org/faq.html + var utmCode = ee.Number(lon).add(180).divide(6).ceil().int(); + var output = ee.Algorithms.If(ee.Number(lat).gte(0), + ee.String('EPSG:326').cat(utmCode.format('%02d')), + ee.String('EPSG:327').cat(utmCode.format('%02d'))); + return (output); +}; + +var coords = aoi.centroid(30).coordinates(); +var lon = coords.get(0); +var lat = coords.get(1); +var crs = getUTMProj(lon, lat); +var scale = ee.Number(30); + +var rpj = function(image) { + return image.reproject({ + crs: crs, + scale: scale + }); +}; + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24a Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24a Checkpoint.py new file mode 100644 index 0000000..5f684b8 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24a Checkpoint.py @@ -0,0 +1,64 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +aoi = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-67.18414102495456, -11.09095257894929], + [-67.18414102495456, -11.402427204567534], + [-66.57886300981784, -11.402427204567534], + [-66.57886300981784, -11.09095257894929]]], None, False), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.4 River Morphology +# Checkpoint: A24a +# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# THIS SCRIPT IS DESIGNED AS A TUTORIAL TO SHOWCASE USING GOOGLE EARTH ENGINE TO ANALYSE +# RIVER PLANVIEW GEOMETRIES AND MORPHOLOGICAL DYNAMICS. THE ANALYSIS IS BUILT ON EXISTING +# MONTHLY WATER CLASSIFICATIONS DATASETS AVAILABLE IN GOOGLE EARTH ENGINE. BY SHOWING +# PREPROCESSING STEPS LIKE HOW TO IDENTIFY RIVERS FROM OTHER TYPES OF WATER BODIES, AND HOW +# TO USE MULTI TEMPORAL WATER LAYERS TO EXTRACT DYNAMICAL CHANGES IN RIVER MORPHOLOGY, IT PROVIDES +# A GUIDE TO EXTRACT INFORMATIONS ON RIVERS USING GOOGLE EARTH ENGINE. + +# ========================================================== + +def getUTMProj(lon, lat): + # given longitude and latitude (in degree decimals) return EPSG string for the + # corresponding UTM projection + # see https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily and + # https:#sis.apache.Org/faq.html + utmCode = ee.Number(lon).add(180).divide(6).ceil().int() + output = ee.Algorithms.If(ee.Number(lat).gte(0), + ee.String('EPSG:326').cat(utmCode.format('%02d')), + ee.String('EPSG:327').cat(utmCode.format('%02d'))) + return (output) + + +coords = aoi.centroid(30).coordinates() +lon = coords.get(0) +lat = coords.get(1) +crs = getUTMProj(lon, lat) +scale = ee.Number(30) + +def rpj(image): + return image.reproject({ + 'crs': crs, + 'scale': scale + }) + + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24b Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24b Checkpoint.ipynb new file mode 100644 index 0000000..6e2f1b4 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24b Checkpoint.ipynb @@ -0,0 +1,214 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "aoi =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-67.18414102495456, -11.09095257894929],\n", + " [-67.18414102495456, -11.402427204567534],\n", + " [-66.57886300981784, -11.402427204567534],\n", + " [-66.57886300981784, -11.09095257894929]]], None, False),\n", + " sword = ee.FeatureCollection(\"projects/gee-book/assets/A2-4/SWORD\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.4 River Morphology\n", + "# Checkpoint: A24b\n", + "# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# THIS SCRIPT IS DESIGNED AS A TUTORIAL TO SHOWCASE USING GOOGLE EARTH ENGINE TO ANALYSE\n", + "# RIVER PLANVIEW GEOMETRIES AND MORPHOLOGICAL DYNAMICS. THE ANALYSIS IS BUILT ON EXISTING\n", + "# MONTHLY WATER CLASSIFICATIONS DATASETS AVAILABLE IN GOOGLE EARTH ENGINE. BY SHOWING\n", + "# PREPROCESSING STEPS LIKE HOW TO IDENTIFY RIVERS FROM OTHER TYPES OF WATER BODIES, AND HOW\n", + "# TO USE MULTI TEMPORAL WATER LAYERS TO EXTRACT DYNAMICAL CHANGES IN RIVER MORPHOLOGY, IT PROVIDES\n", + "# A GUIDE TO EXTRACT INFORMATIONS ON RIVERS USING GOOGLE EARTH ENGINE.\n", + "\n", + "# ==========================================================\n", + "\n", + "def getUTMProj(lon, lat):\n", + " # given longitude and latitude (in degree decimals) return EPSG string for the\n", + " # corresponding UTM projection\n", + " # see https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily and\n", + " # https:#sis.apache.Org/faq.html\n", + " utmCode = ee.Number(lon).add(180).divide(6).ceil().int()\n", + " output = ee.Algorithms.If(ee.Number(lat).gte(0),\n", + " ee.String('EPSG:326').cat(utmCode.format('%02d')),\n", + " ee.String('EPSG:327').cat(utmCode.format('%02d')))\n", + " return (output)\n", + "\n", + "\n", + "coords = aoi.centroid(30).coordinates()\n", + "lon = coords.get(0)\n", + "lat = coords.get(1)\n", + "crs = getUTMProj(lon, lat)\n", + "scale = ee.Number(30)\n", + "\n", + "def rpj(image):\n", + " return image.reproject({\n", + " 'crs': crs,\n", + " 'scale': scale\n", + " })\n", + "\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------\n", + "\n", + "# IMPORT AND VISUALIZE SURFACE WATER MASK.\n", + "# Surface water occurrence dataset from the JRC (Pekel et al., 2016).\n", + "jrcYearly = ee.ImageCollection('JRC/GSW1_3/YearlyHistory')\n", + "\n", + "# Select the seasonal and permanent pixels image representing the year 2000\n", + "watermask = jrcYearly.filter(ee.Filter.eq('year', 2000)).first() \\\n", + " .gte(2).unmask(0) \\\n", + " .clip(aoi)\n", + "\n", + "Map.centerObject(aoi)\n", + "Map.addLayer(ee.Image.constant(0), {\n", + " 'min': 0,\n", + " 'palette': ['black']\n", + "}, 'bg', False)\n", + "Map.addLayer(watermask, {}, 'watermask', False)\n", + "\n", + "# REMOVE NOISE AND SMALL ISLANDS TO SIMPLIFY THE TOPOLOGY.\n", + "\n", + "# a. Image closure operation to fill small holes.\n", + "watermask = watermask.focal_max().focal_min()\n", + "\n", + "# b. Identify small bars and fill them in to create a filled water mask.\n", + "MIN_SIZE = 2E3\n", + "barPolys = watermask.Not().selfMask() \\\n", + " .reduceToVectors({\n", + " 'geometry': aoi,\n", + " 'scale': 30,\n", + " 'eightConnected': True\n", + " }) \\\n", + " .filter(ee.Filter.lte('count', MIN_SIZE)); \n", + "filled = watermask.paint(barPolys, 1)\n", + "\n", + "Map.addLayer(rpj(filled), {\n", + " 'min': 0,\n", + " 'max': 1\n", + "}, 'filled water mask', False)\n", + "\n", + "# IDENTIFYING RIVERS FROM OTHER TYPES OF WATER BODIES.\n", + "# Cumulative cost mapping to find pixels connected to a reference centerline.\n", + "costmap = filled.Not().cumulativeCost({\n", + " 'source': watermask.And(ee.Image().toByte().paint(sword,\n", + " 1)),\n", + " 'maxDistance': 3E3,\n", + " 'geodeticDistance': False\n", + "})\n", + "\n", + "rivermask = costmap.eq(0).rename('riverMask')\n", + "channelmask = rivermask.And(watermask)\n", + "\n", + "Map.addLayer(sword, {\n", + " 'color': 'red'\n", + "}, 'sword', False)\n", + "Map.addLayer(rpj(costmap), {\n", + " 'min': 0,\n", + " 'max': 1E3\n", + "}, 'costmap', False)\n", + "Map.addLayer(rpj(rivermask), {}, 'rivermask', False)\n", + "Map.addLayer(rpj(channelmask), {}, 'channelmask', False)\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24b Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24b Checkpoint.js new file mode 100644 index 0000000..5748aa2 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24b Checkpoint.js @@ -0,0 +1,121 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var aoi = + /* color: #d63000 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-67.18414102495456, -11.09095257894929], + [-67.18414102495456, -11.402427204567534], + [-66.57886300981784, -11.402427204567534], + [-66.57886300981784, -11.09095257894929]]], null, false), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.4 River Morphology +// Checkpoint: A24b +// Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// THIS SCRIPT IS DESIGNED AS A TUTORIAL TO SHOWCASE USING GOOGLE EARTH ENGINE TO ANALYSE +// RIVER PLANVIEW GEOMETRIES AND MORPHOLOGICAL DYNAMICS. THE ANALYSIS IS BUILT ON EXISTING +// MONTHLY WATER CLASSIFICATIONS DATASETS AVAILABLE IN GOOGLE EARTH ENGINE. BY SHOWING +// PREPROCESSING STEPS LIKE HOW TO IDENTIFY RIVERS FROM OTHER TYPES OF WATER BODIES, AND HOW +// TO USE MULTI TEMPORAL WATER LAYERS TO EXTRACT DYNAMICAL CHANGES IN RIVER MORPHOLOGY, IT PROVIDES +// A GUIDE TO EXTRACT INFORMATIONS ON RIVERS USING GOOGLE EARTH ENGINE. + +// ========================================================== + +var getUTMProj = function(lon, lat) { + // given longitude and latitude (in degree decimals) return EPSG string for the + // corresponding UTM projection + // see https://apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily and + // https://sis.apache.org/faq.html + var utmCode = ee.Number(lon).add(180).divide(6).ceil().int(); + var output = ee.Algorithms.If(ee.Number(lat).gte(0), + ee.String('EPSG:326').cat(utmCode.format('%02d')), + ee.String('EPSG:327').cat(utmCode.format('%02d'))); + return (output); +}; + +var coords = aoi.centroid(30).coordinates(); +var lon = coords.get(0); +var lat = coords.get(1); +var crs = getUTMProj(lon, lat); +var scale = ee.Number(30); + +var rpj = function(image) { + return image.reproject({ + crs: crs, + scale: scale + }); +}; + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ + +// IMPORT AND VISUALIZE SURFACE WATER MASK. +// Surface water occurrence dataset from the JRC (Pekel et al., 2016). +var jrcYearly = ee.ImageCollection('JRC/GSW1_3/YearlyHistory'); + +// Select the seasonal and permanent pixels image representing the year 2000 +var watermask = jrcYearly.filter(ee.Filter.eq('year', 2000)).first() + .gte(2).unmask(0) + .clip(aoi); + +Map.centerObject(aoi); +Map.addLayer(ee.Image.constant(0), { + min: 0, + palette: ['black'] +}, 'bg', false); +Map.addLayer(watermask, {}, 'watermask', false); + +// REMOVE NOISE AND SMALL ISLANDS TO SIMPLIFY THE TOPOLOGY. + +// a. Image closure operation to fill small holes. +watermask = watermask.focal_max().focal_min(); + +// b. Identify small bars and fill them in to create a filled water mask. +var MIN_SIZE = 2E3; +var barPolys = watermask.not().selfMask() + .reduceToVectors({ + geometry: aoi, + scale: 30, + eightConnected: true + }) + .filter(ee.Filter.lte('count', MIN_SIZE)); // Get small polys. +var filled = watermask.paint(barPolys, 1); + +Map.addLayer(rpj(filled), { + min: 0, + max: 1 +}, 'filled water mask', false); + +// IDENTIFYING RIVERS FROM OTHER TYPES OF WATER BODIES. +// Cumulative cost mapping to find pixels connected to a reference centerline. +var costmap = filled.not().cumulativeCost({ + source: watermask.and(ee.Image().toByte().paint(sword, + 1)), + maxDistance: 3E3, + geodeticDistance: false +}); + +var rivermask = costmap.eq(0).rename('riverMask'); +var channelmask = rivermask.and(watermask); + +Map.addLayer(sword, { + color: 'red' +}, 'sword', false); +Map.addLayer(rpj(costmap), { + min: 0, + max: 1E3 +}, 'costmap', false); +Map.addLayer(rpj(rivermask), {}, 'rivermask', false); +Map.addLayer(rpj(channelmask), {}, 'channelmask', false); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24b Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24b Checkpoint.py new file mode 100644 index 0000000..7e57406 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24b Checkpoint.py @@ -0,0 +1,127 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +aoi = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-67.18414102495456, -11.09095257894929], + [-67.18414102495456, -11.402427204567534], + [-66.57886300981784, -11.402427204567534], + [-66.57886300981784, -11.09095257894929]]], None, False), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.4 River Morphology +# Checkpoint: A24b +# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# THIS SCRIPT IS DESIGNED AS A TUTORIAL TO SHOWCASE USING GOOGLE EARTH ENGINE TO ANALYSE +# RIVER PLANVIEW GEOMETRIES AND MORPHOLOGICAL DYNAMICS. THE ANALYSIS IS BUILT ON EXISTING +# MONTHLY WATER CLASSIFICATIONS DATASETS AVAILABLE IN GOOGLE EARTH ENGINE. BY SHOWING +# PREPROCESSING STEPS LIKE HOW TO IDENTIFY RIVERS FROM OTHER TYPES OF WATER BODIES, AND HOW +# TO USE MULTI TEMPORAL WATER LAYERS TO EXTRACT DYNAMICAL CHANGES IN RIVER MORPHOLOGY, IT PROVIDES +# A GUIDE TO EXTRACT INFORMATIONS ON RIVERS USING GOOGLE EARTH ENGINE. + +# ========================================================== + +def getUTMProj(lon, lat): + # given longitude and latitude (in degree decimals) return EPSG string for the + # corresponding UTM projection + # see https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily and + # https:#sis.apache.Org/faq.html + utmCode = ee.Number(lon).add(180).divide(6).ceil().int() + output = ee.Algorithms.If(ee.Number(lat).gte(0), + ee.String('EPSG:326').cat(utmCode.format('%02d')), + ee.String('EPSG:327').cat(utmCode.format('%02d'))) + return (output) + + +coords = aoi.centroid(30).coordinates() +lon = coords.get(0) +lat = coords.get(1) +crs = getUTMProj(lon, lat) +scale = ee.Number(30) + +def rpj(image): + return image.reproject({ + 'crs': crs, + 'scale': scale + }) + + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ + +# IMPORT AND VISUALIZE SURFACE WATER MASK. +# Surface water occurrence dataset from the JRC (Pekel et al., 2016). +jrcYearly = ee.ImageCollection('JRC/GSW1_3/YearlyHistory') + +# Select the seasonal and permanent pixels image representing the year 2000 +watermask = jrcYearly.filter(ee.Filter.eq('year', 2000)).first() \ + .gte(2).unmask(0) \ + .clip(aoi) + +Map.centerObject(aoi) +Map.addLayer(ee.Image.constant(0), { + 'min': 0, + 'palette': ['black'] +}, 'bg', False) +Map.addLayer(watermask, {}, 'watermask', False) + +# REMOVE NOISE AND SMALL ISLANDS TO SIMPLIFY THE TOPOLOGY. + +# a. Image closure operation to fill small holes. +watermask = watermask.focal_max().focal_min() + +# b. Identify small bars and fill them in to create a filled water mask. +MIN_SIZE = 2E3 +barPolys = watermask.Not().selfMask() \ + .reduceToVectors({ + 'geometry': aoi, + 'scale': 30, + 'eightConnected': True + }) \ + .filter(ee.Filter.lte('count', MIN_SIZE)); +filled = watermask.paint(barPolys, 1) + +Map.addLayer(rpj(filled), { + 'min': 0, + 'max': 1 +}, 'filled water mask', False) + +# IDENTIFYING RIVERS FROM OTHER TYPES OF WATER BODIES. +# Cumulative cost mapping to find pixels connected to a reference centerline. +costmap = filled.Not().cumulativeCost({ + 'source': watermask.And(ee.Image().toByte().paint(sword, + 1)), + 'maxDistance': 3E3, + 'geodeticDistance': False +}) + +rivermask = costmap.eq(0).rename('riverMask') +channelmask = rivermask.And(watermask) + +Map.addLayer(sword, { + 'color': 'red' +}, 'sword', False) +Map.addLayer(rpj(costmap), { + 'min': 0, + 'max': 1E3 +}, 'costmap', False) +Map.addLayer(rpj(rivermask), {}, 'rivermask', False) +Map.addLayer(rpj(channelmask), {}, 'channelmask', False) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24c Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24c Checkpoint.ipynb new file mode 100644 index 0000000..7171573 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24c Checkpoint.ipynb @@ -0,0 +1,322 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "aoi =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-67.18414102495456, -11.09095257894929],\n", + " [-67.18414102495456, -11.402427204567534],\n", + " [-66.57886300981784, -11.402427204567534],\n", + " [-66.57886300981784, -11.09095257894929]]], None, False),\n", + " sword = ee.FeatureCollection(\"projects/gee-book/assets/A2-4/SWORD\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.4 River Morphology\n", + "# Checkpoint: A24c\n", + "# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# THIS SCRIPT IS DESIGNED AS A TUTORIAL TO SHOWCASE USING GOOGLE EARTH ENGINE TO ANALYSE\n", + "# RIVER PLANVIEW GEOMETRIES AND MORPHOLOGICAL DYNAMICS. THE ANALYSIS IS BUILT ON EXISTING\n", + "# MONTHLY WATER CLASSIFICATIONS DATASETS AVAILABLE IN GOOGLE EARTH ENGINE. BY SHOWING\n", + "# PREPROCESSING STEPS LIKE HOW TO IDENTIFY RIVERS FROM OTHER TYPES OF WATER BODIES, AND HOW\n", + "# TO USE MULTI TEMPORAL WATER LAYERS TO EXTRACT DYNAMICAL CHANGES IN RIVER MORPHOLOGY, IT PROVIDES\n", + "# A GUIDE TO EXTRACT INFORMATIONS ON RIVERS USING GOOGLE EARTH ENGINE.\n", + "\n", + "# ==========================================================\n", + "def getUTMProj(lon, lat):\n", + " # given longitude and latitude (in degree decimals) return EPSG string for the\n", + " # corresponding UTM projection\n", + " # see https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily and\n", + " # https:#sis.apache.Org/faq.html\n", + " utmCode = ee.Number(lon).add(180).divide(6).ceil().int()\n", + " output = ee.Algorithms.If(ee.Number(lat).gte(0),\n", + " ee.String('EPSG:326').cat(utmCode.format('%02d')),\n", + " ee.String('EPSG:327').cat(utmCode.format('%02d')))\n", + " return (output)\n", + "\n", + "\n", + "coords = aoi.centroid(30).coordinates()\n", + "lon = coords.get(0)\n", + "lat = coords.get(1)\n", + "crs = getUTMProj(lon, lat)\n", + "scale = ee.Number(30)\n", + "\n", + "def rpj(image):\n", + " return image.reproject({\n", + " 'crs': crs,\n", + " 'scale': scale\n", + " })\n", + "\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------\n", + "\n", + "# IMPORT AND VISUALIZE SURFACE WATER MASK.\n", + "# Surface water occurrence dataset from the JRC (Pekel et al., 2016).\n", + "jrcYearly = ee.ImageCollection('JRC/GSW1_3/YearlyHistory')\n", + "\n", + "# Select the seasonal and permanent pixels image representing the year 2000\n", + "watermask = jrcYearly.filter(ee.Filter.eq('year', 2000)).first() \\\n", + " .gte(2).unmask(0) \\\n", + " .clip(aoi)\n", + "\n", + "Map.centerObject(aoi)\n", + "Map.addLayer(ee.Image.constant(0), {\n", + " 'min': 0,\n", + " 'palette': ['black']\n", + "}, 'bg', False)\n", + "Map.addLayer(watermask, {}, 'watermask', False)\n", + "\n", + "# REMOVE NOISE AND SMALL ISLANDS TO SIMPLIFY THE TOPOLOGY.\n", + "\n", + "# a. Image closure operation to fill small holes.\n", + "watermask = watermask.focal_max().focal_min()\n", + "\n", + "# b. Identify small bars and fill them in to create a filled water mask.\n", + "MIN_SIZE = 2E3\n", + "barPolys = watermask.Not().selfMask() \\\n", + " .reduceToVectors({\n", + " 'geometry': aoi,\n", + " 'scale': 30,\n", + " 'eightConnected': True\n", + " }) \\\n", + " .filter(ee.Filter.lte('count', MIN_SIZE)); \n", + "filled = watermask.paint(barPolys, 1)\n", + "\n", + "Map.addLayer(rpj(filled), {\n", + " 'min': 0,\n", + " 'max': 1\n", + "}, 'filled water mask', False)\n", + "\n", + "# IDENTIFYING RIVERS FROM OTHER TYPES OF WATER BODIES.\n", + "# Cumulative cost mapping to find pixels connected to a reference centerline.\n", + "costmap = filled.Not().cumulativeCost({\n", + " 'source': watermask.And(ee.Image().toByte().paint(sword,\n", + " 1)),\n", + " 'maxDistance': 3E3,\n", + " 'geodeticDistance': False\n", + "})\n", + "\n", + "rivermask = costmap.eq(0).rename('riverMask')\n", + "channelmask = rivermask.And(watermask)\n", + "\n", + "Map.addLayer(sword, {\n", + " 'color': 'red'\n", + "}, 'sword', False)\n", + "Map.addLayer(rpj(costmap), {\n", + " 'min': 0,\n", + " 'max': 1E3\n", + "}, 'costmap', False)\n", + "Map.addLayer(rpj(rivermask), {}, 'rivermask', False)\n", + "Map.addLayer(rpj(channelmask), {}, 'channelmask', False)\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------\n", + "\n", + "# Import existing functions from RivWidthCloud.\n", + "# Code repository for RivWidthCloud can be accessed at\n", + "# https:#code.earthengine.google.com/?accept_repo=users/eeProject/RivWidthCloudPaper\n", + "riverFunctions = require(\n", + " 'users/eeProject/RivWidthCloudPaper:functions_river.js')\n", + "clFunctions = require(\n", + " 'users/eeProject/RivWidthCloudPaper:functions_centerline_width.js'\n", + ")\n", + "\n", + "#Calculate distance from shoreline using distance transform.\n", + "\n", + "distance = clFunctions.CalcDistanceMap(rivermask, 256, scale)\n", + "Map.addLayer(rpj(distance), {\n", + " 'min': 0,\n", + " 'max': 500\n", + "}, 'distance raster', False)\n", + "\n", + "# Calculate gradient of the distance raster.\n", + "# There are three different ways (kernels) to calculate the gradient.\n", + "# By default, the function used the second approach.\n", + "# For details on the kernels, please see the source code for this function.\n", + "gradient = clFunctions.CalcGradientMap(distance, 2, scale)\n", + "Map.addLayer(rpj(gradient), {}, 'gradient raster', False)\n", + "\n", + "# Threshold the gradient raster and derive 1px width centerline using skeletonization.\n", + "\n", + "centerlineRaw = clFunctions.CalcOnePixelWidthCenterline(rivermask,\n", + " gradient, 0.9)\n", + "raw1pxCenterline = rpj(centerlineRaw).eq(1).selfMask()\n", + "Map.addLayer(raw1pxCenterline, {\n", + " 'palette': ['red']\n", + "}, 'raw 1px centerline', False)\n", + "\n", + "# Prune the centerline to remove spurious branches.\n", + "MAXDISTANCE_BRANCH_REMOVAL = 500\n", + "# Note: the last argument of the CleanCenterline function enables removal of the pixels\n", + "# so that the resulting centerline will have 1px width in an 8-connected way.\n", + "# Once it is done, it doesn\u2019t need to be done the second time (thus it equals False)\n", + "cl1px = clFunctions \\\n", + " .CleanCenterline(centerlineRaw, MAXDISTANCE_BRANCH_REMOVAL, True)\n", + "cl1px = clFunctions \\\n", + " .CleanCenterline(cl1px, MAXDISTANCE_BRANCH_REMOVAL, False)\n", + "final1pxCenterline = rpj(cl1px).eq(1).selfMask()\n", + "Map.addLayer(final1pxCenterline, {\n", + " 'palette': ['red']\n", + "}, 'final 1px centerline', False)\n", + "\n", + "# Calculate perpendicular direction for the cleaned centerline.\n", + "angle = clFunctions.CalculateAngle(cl1px)\n", + "angleVis = {\n", + " 'min': 0,\n", + " 'max': 360,\n", + " 'palette': ['#ffffd4', '#fed98e', '#fe9929', '#d95f0e',\n", + " '#993404'\n", + " ]\n", + "}\n", + "Map.addLayer(rpj(angle), angleVis, 'cross-sectional directions',\n", + " False)\n", + "\n", + "# Estimate width.\n", + "rwcFunction = require(\n", + " 'users/eeProject/RivWidthCloudPaper:rwc_watermask.js')\n", + "rwc = rwcFunction.rwGen_waterMask(4000, 333, 500, aoi)\n", + "watermask = ee.Image(watermask.rename(['waterMask']).setMulti({\n", + " 'crs': crs,\n", + " 'scale': 30,\n", + " 'image_id': 'aoi'\n", + "}))\n", + "\n", + "widths = rwc(watermask)\n", + "print('example width output', widths.first())\n", + "\n", + "bankMask = channelmask.focal_max(1).neq(channelmask)\n", + "\n", + "bankDistance = channelmask.Not().cumulativeCost({\n", + " 'source': channelmask,\n", + " 'maxDistance': 1E2,\n", + " 'geodeticDistance': False\n", + "})\n", + "\n", + "bankAspect = ee.Terrain.aspect(bankDistance) \\\n", + " .multiply(math.pi).divide(180) \\\n", + " .mask(bankMask).rename('bankAspect')\n", + "\n", + "distanceKernel = ee.Kernel.euclidean({\n", + " 'radius': 30,\n", + " 'units': 'meters',\n", + " 'magnitude': 0.5\n", + "})\n", + "bankLength = bankMask.convolve(distanceKernel) \\\n", + " .mask(bankMask).rename('bankLength')\n", + "\n", + "radianVis = {\n", + " 'min': 0,\n", + " 'max': 2 * math.pi,\n", + " 'palette': ['red', 'yellow', 'green', 'teal', 'blue', 'magenta',\n", + " 'red'\n", + " ]\n", + "}\n", + "Map.addLayer(rpj(bankAspect), radianVis, 'bank aspect', False)\n", + "Map.addLayer(rpj(bankLength), {\n", + " 'min': 0,\n", + " 'max': 60\n", + "}, 'bank length', False)\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24c Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24c Checkpoint.js new file mode 100644 index 0000000..cebbf2b --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24c Checkpoint.js @@ -0,0 +1,229 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var aoi = + /* color: #d63000 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-67.18414102495456, -11.09095257894929], + [-67.18414102495456, -11.402427204567534], + [-66.57886300981784, -11.402427204567534], + [-66.57886300981784, -11.09095257894929]]], null, false), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.4 River Morphology +// Checkpoint: A24c +// Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// THIS SCRIPT IS DESIGNED AS A TUTORIAL TO SHOWCASE USING GOOGLE EARTH ENGINE TO ANALYSE +// RIVER PLANVIEW GEOMETRIES AND MORPHOLOGICAL DYNAMICS. THE ANALYSIS IS BUILT ON EXISTING +// MONTHLY WATER CLASSIFICATIONS DATASETS AVAILABLE IN GOOGLE EARTH ENGINE. BY SHOWING +// PREPROCESSING STEPS LIKE HOW TO IDENTIFY RIVERS FROM OTHER TYPES OF WATER BODIES, AND HOW +// TO USE MULTI TEMPORAL WATER LAYERS TO EXTRACT DYNAMICAL CHANGES IN RIVER MORPHOLOGY, IT PROVIDES +// A GUIDE TO EXTRACT INFORMATIONS ON RIVERS USING GOOGLE EARTH ENGINE. + +// ========================================================== +var getUTMProj = function(lon, lat) { + // given longitude and latitude (in degree decimals) return EPSG string for the + // corresponding UTM projection + // see https://apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily and + // https://sis.apache.org/faq.html + var utmCode = ee.Number(lon).add(180).divide(6).ceil().int(); + var output = ee.Algorithms.If(ee.Number(lat).gte(0), + ee.String('EPSG:326').cat(utmCode.format('%02d')), + ee.String('EPSG:327').cat(utmCode.format('%02d'))); + return (output); +}; + +var coords = aoi.centroid(30).coordinates(); +var lon = coords.get(0); +var lat = coords.get(1); +var crs = getUTMProj(lon, lat); +var scale = ee.Number(30); + +var rpj = function(image) { + return image.reproject({ + crs: crs, + scale: scale + }); +}; + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ + +// IMPORT AND VISUALIZE SURFACE WATER MASK. +// Surface water occurrence dataset from the JRC (Pekel et al., 2016). +var jrcYearly = ee.ImageCollection('JRC/GSW1_3/YearlyHistory'); + +// Select the seasonal and permanent pixels image representing the year 2000 +var watermask = jrcYearly.filter(ee.Filter.eq('year', 2000)).first() + .gte(2).unmask(0) + .clip(aoi); + +Map.centerObject(aoi); +Map.addLayer(ee.Image.constant(0), { + min: 0, + palette: ['black'] +}, 'bg', false); +Map.addLayer(watermask, {}, 'watermask', false); + +// REMOVE NOISE AND SMALL ISLANDS TO SIMPLIFY THE TOPOLOGY. + +// a. Image closure operation to fill small holes. +watermask = watermask.focal_max().focal_min(); + +// b. Identify small bars and fill them in to create a filled water mask. +var MIN_SIZE = 2E3; +var barPolys = watermask.not().selfMask() + .reduceToVectors({ + geometry: aoi, + scale: 30, + eightConnected: true + }) + .filter(ee.Filter.lte('count', MIN_SIZE)); // Get small polys. +var filled = watermask.paint(barPolys, 1); + +Map.addLayer(rpj(filled), { + min: 0, + max: 1 +}, 'filled water mask', false); + +// IDENTIFYING RIVERS FROM OTHER TYPES OF WATER BODIES. +// Cumulative cost mapping to find pixels connected to a reference centerline. +var costmap = filled.not().cumulativeCost({ + source: watermask.and(ee.Image().toByte().paint(sword, + 1)), + maxDistance: 3E3, + geodeticDistance: false +}); + +var rivermask = costmap.eq(0).rename('riverMask'); +var channelmask = rivermask.and(watermask); + +Map.addLayer(sword, { + color: 'red' +}, 'sword', false); +Map.addLayer(rpj(costmap), { + min: 0, + max: 1E3 +}, 'costmap', false); +Map.addLayer(rpj(rivermask), {}, 'rivermask', false); +Map.addLayer(rpj(channelmask), {}, 'channelmask', false); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ + +// Import existing functions from RivWidthCloud. +// Code repository for RivWidthCloud can be accessed at +// https://code.earthengine.google.com/?accept_repo=users/eeProject/RivWidthCloudPaper +var riverFunctions = require( + 'users/eeProject/RivWidthCloudPaper:functions_river.js'); +var clFunctions = require( + 'users/eeProject/RivWidthCloudPaper:functions_centerline_width.js' +); + +//Calculate distance from shoreline using distance transform. + +var distance = clFunctions.CalcDistanceMap(rivermask, 256, scale); +Map.addLayer(rpj(distance), { + min: 0, + max: 500 +}, 'distance raster', false); + +// Calculate gradient of the distance raster. +// There are three different ways (kernels) to calculate the gradient. +// By default, the function used the second approach. +// For details on the kernels, please see the source code for this function. +var gradient = clFunctions.CalcGradientMap(distance, 2, scale); +Map.addLayer(rpj(gradient), {}, 'gradient raster', false); + +// Threshold the gradient raster and derive 1px width centerline using skeletonization. + +var centerlineRaw = clFunctions.CalcOnePixelWidthCenterline(rivermask, + gradient, 0.9); +var raw1pxCenterline = rpj(centerlineRaw).eq(1).selfMask(); +Map.addLayer(raw1pxCenterline, { + palette: ['red'] +}, 'raw 1px centerline', false); + +// Prune the centerline to remove spurious branches. +var MAXDISTANCE_BRANCH_REMOVAL = 500; +// Note: the last argument of the CleanCenterline function enables removal of the pixels +// so that the resulting centerline will have 1px width in an 8-connected way. +// Once it is done, it doesn’t need to be done the second time (thus it equals false) +var cl1px = clFunctions + .CleanCenterline(centerlineRaw, MAXDISTANCE_BRANCH_REMOVAL, true); +var cl1px = clFunctions + .CleanCenterline(cl1px, MAXDISTANCE_BRANCH_REMOVAL, false); +var final1pxCenterline = rpj(cl1px).eq(1).selfMask(); +Map.addLayer(final1pxCenterline, { + palette: ['red'] +}, 'final 1px centerline', false); + +// Calculate perpendicular direction for the cleaned centerline. +var angle = clFunctions.CalculateAngle(cl1px); +var angleVis = { + min: 0, + max: 360, + palette: ['#ffffd4', '#fed98e', '#fe9929', '#d95f0e', + '#993404' + ] +}; +Map.addLayer(rpj(angle), angleVis, 'cross-sectional directions', + false); + +// Estimate width. +var rwcFunction = require( + 'users/eeProject/RivWidthCloudPaper:rwc_watermask.js'); +var rwc = rwcFunction.rwGen_waterMask(4000, 333, 500, aoi); +watermask = ee.Image(watermask.rename(['waterMask']).setMulti({ + crs: crs, + scale: 30, + image_id: 'aoi' +})); + +var widths = rwc(watermask); +print('example width output', widths.first()); + +var bankMask = channelmask.focal_max(1).neq(channelmask); + +var bankDistance = channelmask.not().cumulativeCost({ + source: channelmask, + maxDistance: 1E2, + geodeticDistance: false +}); + +var bankAspect = ee.Terrain.aspect(bankDistance) + .multiply(Math.PI).divide(180) + .mask(bankMask).rename('bankAspect'); + +var distanceKernel = ee.Kernel.euclidean({ + radius: 30, + units: 'meters', + magnitude: 0.5 +}); +var bankLength = bankMask.convolve(distanceKernel) + .mask(bankMask).rename('bankLength'); + +var radianVis = { + min: 0, + max: 2 * Math.PI, + palette: ['red', 'yellow', 'green', 'teal', 'blue', 'magenta', + 'red' + ] +}; +Map.addLayer(rpj(bankAspect), radianVis, 'bank aspect', false); +Map.addLayer(rpj(bankLength), { + min: 0, + max: 60 +}, 'bank length', false); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24c Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24c Checkpoint.py new file mode 100644 index 0000000..0f7d044 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24c Checkpoint.py @@ -0,0 +1,236 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +aoi = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-67.18414102495456, -11.09095257894929], + [-67.18414102495456, -11.402427204567534], + [-66.57886300981784, -11.402427204567534], + [-66.57886300981784, -11.09095257894929]]], None, False), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.4 River Morphology +# Checkpoint: A24c +# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# THIS SCRIPT IS DESIGNED AS A TUTORIAL TO SHOWCASE USING GOOGLE EARTH ENGINE TO ANALYSE +# RIVER PLANVIEW GEOMETRIES AND MORPHOLOGICAL DYNAMICS. THE ANALYSIS IS BUILT ON EXISTING +# MONTHLY WATER CLASSIFICATIONS DATASETS AVAILABLE IN GOOGLE EARTH ENGINE. BY SHOWING +# PREPROCESSING STEPS LIKE HOW TO IDENTIFY RIVERS FROM OTHER TYPES OF WATER BODIES, AND HOW +# TO USE MULTI TEMPORAL WATER LAYERS TO EXTRACT DYNAMICAL CHANGES IN RIVER MORPHOLOGY, IT PROVIDES +# A GUIDE TO EXTRACT INFORMATIONS ON RIVERS USING GOOGLE EARTH ENGINE. + +# ========================================================== +def getUTMProj(lon, lat): + # given longitude and latitude (in degree decimals) return EPSG string for the + # corresponding UTM projection + # see https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily and + # https:#sis.apache.Org/faq.html + utmCode = ee.Number(lon).add(180).divide(6).ceil().int() + output = ee.Algorithms.If(ee.Number(lat).gte(0), + ee.String('EPSG:326').cat(utmCode.format('%02d')), + ee.String('EPSG:327').cat(utmCode.format('%02d'))) + return (output) + + +coords = aoi.centroid(30).coordinates() +lon = coords.get(0) +lat = coords.get(1) +crs = getUTMProj(lon, lat) +scale = ee.Number(30) + +def rpj(image): + return image.reproject({ + 'crs': crs, + 'scale': scale + }) + + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ + +# IMPORT AND VISUALIZE SURFACE WATER MASK. +# Surface water occurrence dataset from the JRC (Pekel et al., 2016). +jrcYearly = ee.ImageCollection('JRC/GSW1_3/YearlyHistory') + +# Select the seasonal and permanent pixels image representing the year 2000 +watermask = jrcYearly.filter(ee.Filter.eq('year', 2000)).first() \ + .gte(2).unmask(0) \ + .clip(aoi) + +Map.centerObject(aoi) +Map.addLayer(ee.Image.constant(0), { + 'min': 0, + 'palette': ['black'] +}, 'bg', False) +Map.addLayer(watermask, {}, 'watermask', False) + +# REMOVE NOISE AND SMALL ISLANDS TO SIMPLIFY THE TOPOLOGY. + +# a. Image closure operation to fill small holes. +watermask = watermask.focal_max().focal_min() + +# b. Identify small bars and fill them in to create a filled water mask. +MIN_SIZE = 2E3 +barPolys = watermask.Not().selfMask() \ + .reduceToVectors({ + 'geometry': aoi, + 'scale': 30, + 'eightConnected': True + }) \ + .filter(ee.Filter.lte('count', MIN_SIZE)); +filled = watermask.paint(barPolys, 1) + +Map.addLayer(rpj(filled), { + 'min': 0, + 'max': 1 +}, 'filled water mask', False) + +# IDENTIFYING RIVERS FROM OTHER TYPES OF WATER BODIES. +# Cumulative cost mapping to find pixels connected to a reference centerline. +costmap = filled.Not().cumulativeCost({ + 'source': watermask.And(ee.Image().toByte().paint(sword, + 1)), + 'maxDistance': 3E3, + 'geodeticDistance': False +}) + +rivermask = costmap.eq(0).rename('riverMask') +channelmask = rivermask.And(watermask) + +Map.addLayer(sword, { + 'color': 'red' +}, 'sword', False) +Map.addLayer(rpj(costmap), { + 'min': 0, + 'max': 1E3 +}, 'costmap', False) +Map.addLayer(rpj(rivermask), {}, 'rivermask', False) +Map.addLayer(rpj(channelmask), {}, 'channelmask', False) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ + +# Import existing functions from RivWidthCloud. +# Code repository for RivWidthCloud can be accessed at +# https:#code.earthengine.google.com/?accept_repo=users/eeProject/RivWidthCloudPaper +riverFunctions = require( + 'users/eeProject/RivWidthCloudPaper:functions_river.js') +clFunctions = require( + 'users/eeProject/RivWidthCloudPaper:functions_centerline_width.js' +) + +#Calculate distance from shoreline using distance transform. + +distance = clFunctions.CalcDistanceMap(rivermask, 256, scale) +Map.addLayer(rpj(distance), { + 'min': 0, + 'max': 500 +}, 'distance raster', False) + +# Calculate gradient of the distance raster. +# There are three different ways (kernels) to calculate the gradient. +# By default, the function used the second approach. +# For details on the kernels, please see the source code for this function. +gradient = clFunctions.CalcGradientMap(distance, 2, scale) +Map.addLayer(rpj(gradient), {}, 'gradient raster', False) + +# Threshold the gradient raster and derive 1px width centerline using skeletonization. + +centerlineRaw = clFunctions.CalcOnePixelWidthCenterline(rivermask, + gradient, 0.9) +raw1pxCenterline = rpj(centerlineRaw).eq(1).selfMask() +Map.addLayer(raw1pxCenterline, { + 'palette': ['red'] +}, 'raw 1px centerline', False) + +# Prune the centerline to remove spurious branches. +MAXDISTANCE_BRANCH_REMOVAL = 500 +# Note: the last argument of the CleanCenterline function enables removal of the pixels +# so that the resulting centerline will have 1px width in an 8-connected way. +# Once it is done, it doesn’t need to be done the second time (thus it equals False) +cl1px = clFunctions \ + .CleanCenterline(centerlineRaw, MAXDISTANCE_BRANCH_REMOVAL, True) +cl1px = clFunctions \ + .CleanCenterline(cl1px, MAXDISTANCE_BRANCH_REMOVAL, False) +final1pxCenterline = rpj(cl1px).eq(1).selfMask() +Map.addLayer(final1pxCenterline, { + 'palette': ['red'] +}, 'final 1px centerline', False) + +# Calculate perpendicular direction for the cleaned centerline. +angle = clFunctions.CalculateAngle(cl1px) +angleVis = { + 'min': 0, + 'max': 360, + 'palette': ['#ffffd4', '#fed98e', '#fe9929', '#d95f0e', + '#993404' + ] +} +Map.addLayer(rpj(angle), angleVis, 'cross-sectional directions', + False) + +# Estimate width. +rwcFunction = require( + 'users/eeProject/RivWidthCloudPaper:rwc_watermask.js') +rwc = rwcFunction.rwGen_waterMask(4000, 333, 500, aoi) +watermask = ee.Image(watermask.rename(['waterMask']).setMulti({ + 'crs': crs, + 'scale': 30, + 'image_id': 'aoi' +})) + +widths = rwc(watermask) +print('example width output', widths.first()) + +bankMask = channelmask.focal_max(1).neq(channelmask) + +bankDistance = channelmask.Not().cumulativeCost({ + 'source': channelmask, + 'maxDistance': 1E2, + 'geodeticDistance': False +}) + +bankAspect = ee.Terrain.aspect(bankDistance) \ + .multiply(math.pi).divide(180) \ + .mask(bankMask).rename('bankAspect') + +distanceKernel = ee.Kernel.euclidean({ + 'radius': 30, + 'units': 'meters', + 'magnitude': 0.5 +}) +bankLength = bankMask.convolve(distanceKernel) \ + .mask(bankMask).rename('bankLength') + +radianVis = { + 'min': 0, + 'max': 2 * math.pi, + 'palette': ['red', 'yellow', 'green', 'teal', 'blue', 'magenta', + 'red' + ] +} +Map.addLayer(rpj(bankAspect), radianVis, 'bank aspect', False) +Map.addLayer(rpj(bankLength), { + 'min': 0, + 'max': 60 +}, 'bank length', False) + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24d Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24d Checkpoint.ipynb new file mode 100644 index 0000000..d05d005 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24d Checkpoint.ipynb @@ -0,0 +1,217 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.4 River Morphology\n", + "# Checkpoint: A24d\n", + "# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Include the helper function getUTMProj introduced at the beginning\n", + "# of the chapter in Code Checkpoint A24a.\n", + "def getUTMProj(lon, lat):\n", + " # Given longitude and latitude in decimal degrees,\n", + " # return EPSG string for the corresponding UTM projection. See:\n", + " # https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily\n", + " # https:#sis.apache.Org/faq.html\n", + " utmCode = ee.Number(lon).add(180).divide(6).ceil().int()\n", + " output = ee.Algorithms.If({\n", + " 'condition': ee.Number(lat).gte(0),\n", + " 'TrueCase': ee.String('EPSG:326').cat(utmCode \\\n", + " .format('%02d')),\n", + " 'FalseCase': ee.String('EPSG:327').cat(utmCode \\\n", + " .format('%02d'))\n", + " })\n", + " return (output)\n", + "\n", + "\n", + "# IMPORT AND VISUALIZE SURFACE WATER MASK\n", + "# Surface water occurrence dataset from the JRC (Pekel et al., 2016).\n", + "jrcYearly = ee.ImageCollection('JRC/GSW1_3/YearlyHistory')\n", + "poi = ee.Geometry.LineString([\n", + " [110.77450764660864, 30.954167027937988],\n", + " [110.77158940320044, 30.950633845897112]\n", + "])\n", + "\n", + "rwcFunction = require(\n", + " 'users/eeProject/RivWidthCloudPaper:rwc_watermask.js')\n", + "\n", + "# Function to identify the nearest river width to a given location.\n", + "def GetNearestClGen(poi):\n", + " def temp(widths):\n", + "\n", + "def func_kck(f):\n", + " return f.set('dist2cl', f.distance(poi,\n", + " 30))\n", + "\n", + " widths = widths.map(func_kck)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " return ee.Feature(widths.sort('dist2cl', True) \\\n", + " .first())\n", + " \n", + " return temp\n", + "\n", + "getNearestCl = GetNearestClGen(poi)\n", + "\n", + "# Multitemporal width extraction.\n", + "polygon = poi.buffer(2000)\n", + "coords = poi.centroid().coordinates()\n", + "lon = coords.get(0)\n", + "lat = coords.get(1)\n", + "crs = getUTMProj(lon, lat)\n", + "scale = ee.Number(30)\n", + "\n", + "\n", + "def func_qhz(i):\n", + " watermask = i.gte(2).unmask(0)\n", + "\n", + " watermask = ee.Image(watermask.rename(['waterMask']) \\\n", + " .setMulti({\n", + " 'crs': crs,\n", + " 'scale': scale,\n", + " 'image_id': i.getNumber('year')\n", + " }))\n", + " rwc = rwcFunction.rwGen_waterMask(2000, 333, 300,\n", + " polygon)\n", + " widths = rwc(watermask) \\\n", + " .filter(ee.Filter.eq('endsInWater', 0)) \\\n", + " .filter(ee.Filter.eq('endsOverEdge', 0))\n", + "\n", + " return ee.Algorithms.If(widths.size(), getNearestCl(\n", + " widths), None)\n", + "\n", + "multiwidths = ee.FeatureCollection(jrcYearly.map(func_qhz\n", + ", True))\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ", True))\n", + "\n", + "widthTs = ui.Chart.feature.byFeature(multiwidths, 'image_id', [\n", + " 'width'\n", + " ]) \\\n", + " .setOptions({\n", + " 'hAxis': {\n", + " 'title': 'Year',\n", + " format: '####'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Width (meter)'\n", + " },\n", + " 'title': 'River width time series upstream of the Three Gorges Dam'\n", + " })\n", + "print(widthTs)\n", + "\n", + "Map.centerObject(polygon)\n", + "Map.addLayer(polygon, {}, 'area of width calculation')\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24d Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24d Checkpoint.js new file mode 100644 index 0000000..d362401 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24d Checkpoint.js @@ -0,0 +1,98 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.4 River Morphology +// Checkpoint: A24d +// Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Include the helper function getUTMProj introduced at the beginning +// of the chapter in Code Checkpoint A24a. +var getUTMProj = function(lon, lat) { + // Given longitude and latitude in decimal degrees, + // return EPSG string for the corresponding UTM projection. See: + // https://apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily + // https://sis.apache.org/faq.html + var utmCode = ee.Number(lon).add(180).divide(6).ceil().int(); + var output = ee.Algorithms.If({ + condition: ee.Number(lat).gte(0), + trueCase: ee.String('EPSG:326').cat(utmCode + .format('%02d')), + falseCase: ee.String('EPSG:327').cat(utmCode + .format('%02d')) + }); + return (output); +}; + +// IMPORT AND VISUALIZE SURFACE WATER MASK +// Surface water occurrence dataset from the JRC (Pekel et al., 2016). +var jrcYearly = ee.ImageCollection('JRC/GSW1_3/YearlyHistory'); +var poi = ee.Geometry.LineString([ + [110.77450764660864, 30.954167027937988], + [110.77158940320044, 30.950633845897112] +]); + +var rwcFunction = require( + 'users/eeProject/RivWidthCloudPaper:rwc_watermask.js'); + +// Function to identify the nearest river width to a given location. +var GetNearestClGen = function(poi) { + var temp = function(widths) { + widths = widths.map(function(f) { + return f.set('dist2cl', f.distance(poi, + 30)); + }); + + return ee.Feature(widths.sort('dist2cl', true) + .first()); + }; + return temp; +}; +var getNearestCl = GetNearestClGen(poi); + +// Multitemporal width extraction. +var polygon = poi.buffer(2000); +var coords = poi.centroid().coordinates(); +var lon = coords.get(0); +var lat = coords.get(1); +var crs = getUTMProj(lon, lat); +var scale = ee.Number(30); + +var multiwidths = ee.FeatureCollection(jrcYearly.map(function(i) { + var watermask = i.gte(2).unmask(0); + + watermask = ee.Image(watermask.rename(['waterMask']) + .setMulti({ + crs: crs, + scale: scale, + image_id: i.getNumber('year') + })); + var rwc = rwcFunction.rwGen_waterMask(2000, 333, 300, + polygon); + var widths = rwc(watermask) + .filter(ee.Filter.eq('endsInWater', 0)) + .filter(ee.Filter.eq('endsOverEdge', 0)); + + return ee.Algorithms.If(widths.size(), getNearestCl( + widths), null); +}, true)); + +var widthTs = ui.Chart.feature.byFeature(multiwidths, 'image_id', [ + 'width' + ]) + .setOptions({ + hAxis: { + title: 'Year', + format: '####' + }, + vAxis: { + title: 'Width (meter)' + }, + title: 'River width time series upstream of the Three Gorges Dam' + }); +print(widthTs); + +Map.centerObject(polygon); +Map.addLayer(polygon, {}, 'area of width calculation'); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24d Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24d Checkpoint.py new file mode 100644 index 0000000..f1e7523 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24d Checkpoint.py @@ -0,0 +1,130 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.4 River Morphology +# Checkpoint: A24d +# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include the helper function getUTMProj introduced at the beginning +# of the chapter in Code Checkpoint A24a. +def getUTMProj(lon, lat): + # Given longitude and latitude in decimal degrees, + # return EPSG string for the corresponding UTM projection. See: + # https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily + # https:#sis.apache.Org/faq.html + utmCode = ee.Number(lon).add(180).divide(6).ceil().int() + output = ee.Algorithms.If({ + 'condition': ee.Number(lat).gte(0), + 'TrueCase': ee.String('EPSG:326').cat(utmCode \ + .format('%02d')), + 'FalseCase': ee.String('EPSG:327').cat(utmCode \ + .format('%02d')) + }) + return (output) + + +# IMPORT AND VISUALIZE SURFACE WATER MASK +# Surface water occurrence dataset from the JRC (Pekel et al., 2016). +jrcYearly = ee.ImageCollection('JRC/GSW1_3/YearlyHistory') +poi = ee.Geometry.LineString([ + [110.77450764660864, 30.954167027937988], + [110.77158940320044, 30.950633845897112] +]) + +rwcFunction = require( + 'users/eeProject/RivWidthCloudPaper:rwc_watermask.js') + +# Function to identify the nearest river width to a given location. +def GetNearestClGen(poi): + def temp(widths): + +def func_kck(f): + return f.set('dist2cl', f.distance(poi, + 30)) + + widths = widths.map(func_kck) + + + + + + return ee.Feature(widths.sort('dist2cl', True) \ + .first()) + + return temp + +getNearestCl = GetNearestClGen(poi) + +# Multitemporal width extraction. +polygon = poi.buffer(2000) +coords = poi.centroid().coordinates() +lon = coords.get(0) +lat = coords.get(1) +crs = getUTMProj(lon, lat) +scale = ee.Number(30) + + +def func_qhz(i): + watermask = i.gte(2).unmask(0) + + watermask = ee.Image(watermask.rename(['waterMask']) \ + .setMulti({ + 'crs': crs, + 'scale': scale, + 'image_id': i.getNumber('year') + })) + rwc = rwcFunction.rwGen_waterMask(2000, 333, 300, + polygon) + widths = rwc(watermask) \ + .filter(ee.Filter.eq('endsInWater', 0)) \ + .filter(ee.Filter.eq('endsOverEdge', 0)) + + return ee.Algorithms.If(widths.size(), getNearestCl( + widths), None) + +multiwidths = ee.FeatureCollection(jrcYearly.map(func_qhz +, True)) + + + + + + + + + + + + + + + + +, True)) + +widthTs = ui.Chart.feature.byFeature(multiwidths, 'image_id', [ + 'width' + ]) \ + .setOptions({ + 'hAxis': { + 'title': 'Year', + format: '####' + }, + 'vAxis': { + 'title': 'Width (meter)' + }, + 'title': 'River width time series upstream of the Three Gorges Dam' + }) +print(widthTs) + +Map.centerObject(polygon) +Map.addLayer(polygon, {}, 'area of width calculation') + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24e Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24e Checkpoint.ipynb new file mode 100644 index 0000000..6884864 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24e Checkpoint.ipynb @@ -0,0 +1,202 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "jrcYearly = ee.ImageCollection(\"JRC/GSW1_3/YearlyHistory\"),\n", + " aoi =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-66.75498758257174, -11.090110301403685],\n", + " [-66.75498758257174, -11.258517279582335],\n", + " [-66.56650339067721, -11.258517279582335],\n", + " [-66.56650339067721, -11.090110301403685]]], None, False),\n", + " sword = ee.FeatureCollection(\"projects/gee-book/assets/A2-4/SWORD\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.4 River Morphology\n", + "# Checkpoint: A24e\n", + "# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "def getUTMProj(lon, lat):\n", + " # Given longitude and latitude in decimal degrees,\n", + " # return EPSG string for the corresponding UTM projection. See:\n", + " # https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily\n", + " # https:#sis.apache.Org/faq.html\n", + " utmCode = ee.Number(lon).add(180).divide(6).ceil().int()\n", + " output = ee.Algorithms.If({\n", + " 'condition': ee.Number(lat).gte(0),\n", + " 'TrueCase': ee.String('EPSG:326').cat(utmCode \\\n", + " .format('%02d')),\n", + " 'FalseCase': ee.String('EPSG:327').cat(utmCode \\\n", + " .format('%02d'))\n", + " })\n", + " return (output)\n", + "\n", + "\n", + "coords = aoi.centroid(30).coordinates()\n", + "lon = coords.get(0)\n", + "lat = coords.get(1)\n", + "crs = getUTMProj(lon, lat)\n", + "scale = 30\n", + "\n", + "def rpj(image):\n", + " return image.reproject({\n", + " 'crs': crs,\n", + " 'scale': scale\n", + " })\n", + "\n", + "\n", + "distanceKernel = ee.Kernel.euclidean({\n", + " 'radius': 30,\n", + " 'units': 'meters',\n", + " 'magnitude': 0.5\n", + "})\n", + "\n", + "def makeChannelmask(year):\n", + " watermask = jrcYearly.filter(ee.Filter.eq('year', year)) \\\n", + " .first() \\\n", + " .gte(2).unmask() \\\n", + " .focal_max().focal_min() \\\n", + " .rename('watermask')\n", + "\n", + " barPolys = watermask.Not().selfMask() \\\n", + " .reduceToVectors({\n", + " 'geometry': aoi,\n", + " 'scale': 30,\n", + " 'eightConnected': False\n", + " }) \\\n", + " .filter(ee.Filter.lte('count', 1E4)); \n", + "\n", + " filled = watermask.paint(barPolys, 1).rename('filled')\n", + "\n", + " costmap = filled.Not().cumulativeCost({\n", + " 'source': watermask.And(ee.Image().toByte().paint(\n", + " sword, 1)),\n", + " 'maxDistance': 5E3,\n", + " 'geodeticDistance': False\n", + " }).rename('costmap')\n", + "\n", + " rivermask = costmap.eq(0).rename('rivermask')\n", + " channelmask = rivermask.And(watermask).rename(\n", + " 'channelmask')\n", + "\n", + " bankMask = channelmask.focal_max(1).neq(channelmask) \\\n", + " .rename('bankMask')\n", + " bankDistance = channelmask.Not().cumulativeCost({\n", + " 'source': channelmask,\n", + " 'maxDistance': 1E2,\n", + " 'geodeticDistance': False\n", + " })\n", + " bankAspect = ee.Terrain.aspect(bankDistance).mask(\n", + " bankMask).rename('bankAspect')\n", + "\n", + " bankLength = bankMask.convolve(distanceKernel) \\\n", + " .mask(bankMask).rename('bankLength')\n", + "\n", + " return ee.Image.cat([\n", + " watermask, channelmask, rivermask, bankMask,\n", + " bankAspect, bankLength\n", + " ]).set('year', year) \\\n", + " .clip(aoi)\n", + "\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24e Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24e Checkpoint.js new file mode 100644 index 0000000..ec66c48 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24e Checkpoint.js @@ -0,0 +1,109 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var jrcYearly = ee.ImageCollection("JRC/GSW1_3/YearlyHistory"), + aoi = + /* color: #d63000 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-66.75498758257174, -11.090110301403685], + [-66.75498758257174, -11.258517279582335], + [-66.56650339067721, -11.258517279582335], + [-66.56650339067721, -11.090110301403685]]], null, false), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.4 River Morphology +// Checkpoint: A24e +// Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var getUTMProj = function(lon, lat) { + // Given longitude and latitude in decimal degrees, + // return EPSG string for the corresponding UTM projection. See: + // https://apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily + // https://sis.apache.org/faq.html + var utmCode = ee.Number(lon).add(180).divide(6).ceil().int(); + var output = ee.Algorithms.If({ + condition: ee.Number(lat).gte(0), + trueCase: ee.String('EPSG:326').cat(utmCode + .format('%02d')), + falseCase: ee.String('EPSG:327').cat(utmCode + .format('%02d')) + }); + return (output); +}; + +var coords = aoi.centroid(30).coordinates(); +var lon = coords.get(0); +var lat = coords.get(1); +var crs = getUTMProj(lon, lat); +var scale = 30; + +var rpj = function(image) { + return image.reproject({ + crs: crs, + scale: scale + }); +}; + +var distanceKernel = ee.Kernel.euclidean({ + radius: 30, + units: 'meters', + magnitude: 0.5 +}); + +var makeChannelmask = function(year) { + var watermask = jrcYearly.filter(ee.Filter.eq('year', year)) + .first() + .gte(2).unmask() + .focal_max().focal_min() + .rename('watermask'); + + var barPolys = watermask.not().selfMask() + .reduceToVectors({ + geometry: aoi, + scale: 30, + eightConnected: false + }) + .filter(ee.Filter.lte('count', 1E4)); // Get small polys. + + var filled = watermask.paint(barPolys, 1).rename('filled'); + + var costmap = filled.not().cumulativeCost({ + source: watermask.and(ee.Image().toByte().paint( + sword, 1)), + maxDistance: 5E3, + geodeticDistance: false + }).rename('costmap'); + + var rivermask = costmap.eq(0).rename('rivermask'); + var channelmask = rivermask.and(watermask).rename( + 'channelmask'); + + var bankMask = channelmask.focal_max(1).neq(channelmask) + .rename('bankMask'); + var bankDistance = channelmask.not().cumulativeCost({ + source: channelmask, + maxDistance: 1E2, + geodeticDistance: false + }); + var bankAspect = ee.Terrain.aspect(bankDistance).mask( + bankMask).rename('bankAspect'); + + var bankLength = bankMask.convolve(distanceKernel) + .mask(bankMask).rename('bankLength'); + + return ee.Image.cat([ + watermask, channelmask, rivermask, bankMask, + bankAspect, bankLength + ]).set('year', year) + .clip(aoi); +}; + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24e Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24e Checkpoint.py new file mode 100644 index 0000000..5c4a816 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24e Checkpoint.py @@ -0,0 +1,115 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +jrcYearly = ee.ImageCollection("JRC/GSW1_3/YearlyHistory"), + aoi = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-66.75498758257174, -11.090110301403685], + [-66.75498758257174, -11.258517279582335], + [-66.56650339067721, -11.258517279582335], + [-66.56650339067721, -11.090110301403685]]], None, False), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.4 River Morphology +# Checkpoint: A24e +# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def getUTMProj(lon, lat): + # Given longitude and latitude in decimal degrees, + # return EPSG string for the corresponding UTM projection. See: + # https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily + # https:#sis.apache.Org/faq.html + utmCode = ee.Number(lon).add(180).divide(6).ceil().int() + output = ee.Algorithms.If({ + 'condition': ee.Number(lat).gte(0), + 'TrueCase': ee.String('EPSG:326').cat(utmCode \ + .format('%02d')), + 'FalseCase': ee.String('EPSG:327').cat(utmCode \ + .format('%02d')) + }) + return (output) + + +coords = aoi.centroid(30).coordinates() +lon = coords.get(0) +lat = coords.get(1) +crs = getUTMProj(lon, lat) +scale = 30 + +def rpj(image): + return image.reproject({ + 'crs': crs, + 'scale': scale + }) + + +distanceKernel = ee.Kernel.euclidean({ + 'radius': 30, + 'units': 'meters', + 'magnitude': 0.5 +}) + +def makeChannelmask(year): + watermask = jrcYearly.filter(ee.Filter.eq('year', year)) \ + .first() \ + .gte(2).unmask() \ + .focal_max().focal_min() \ + .rename('watermask') + + barPolys = watermask.Not().selfMask() \ + .reduceToVectors({ + 'geometry': aoi, + 'scale': 30, + 'eightConnected': False + }) \ + .filter(ee.Filter.lte('count', 1E4)); + + filled = watermask.paint(barPolys, 1).rename('filled') + + costmap = filled.Not().cumulativeCost({ + 'source': watermask.And(ee.Image().toByte().paint( + sword, 1)), + 'maxDistance': 5E3, + 'geodeticDistance': False + }).rename('costmap') + + rivermask = costmap.eq(0).rename('rivermask') + channelmask = rivermask.And(watermask).rename( + 'channelmask') + + bankMask = channelmask.focal_max(1).neq(channelmask) \ + .rename('bankMask') + bankDistance = channelmask.Not().cumulativeCost({ + 'source': channelmask, + 'maxDistance': 1E2, + 'geodeticDistance': False + }) + bankAspect = ee.Terrain.aspect(bankDistance).mask( + bankMask).rename('bankAspect') + + bankLength = bankMask.convolve(distanceKernel) \ + .mask(bankMask).rename('bankLength') + + return ee.Image.cat([ + watermask, channelmask, rivermask, bankMask, + bankAspect, bankLength + ]).set('year', year) \ + .clip(aoi) + + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24f Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24f Checkpoint.ipynb new file mode 100644 index 0000000..9205f1a --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24f Checkpoint.ipynb @@ -0,0 +1,360 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "jrcYearly = ee.ImageCollection(\"JRC/GSW1_3/YearlyHistory\"),\n", + " aoi =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-66.75498758257174, -11.090110301403685],\n", + " [-66.75498758257174, -11.258517279582335],\n", + " [-66.56650339067721, -11.258517279582335],\n", + " [-66.56650339067721, -11.090110301403685]]], None, False),\n", + " sword = ee.FeatureCollection(\"projects/gee-book/assets/A2-4/SWORD\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.4 River Morphology\n", + "# Checkpoint: A24f\n", + "# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "def getUTMProj(lon, lat):\n", + " # Given longitude and latitude in decimal degrees,\n", + " # return EPSG string for the corresponding UTM projection. See:\n", + " # https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily\n", + " # https:#sis.apache.Org/faq.html\n", + " utmCode = ee.Number(lon).add(180).divide(6).ceil().int()\n", + " output = ee.Algorithms.If({\n", + " 'condition': ee.Number(lat).gte(0),\n", + " 'TrueCase': ee.String('EPSG:326').cat(utmCode \\\n", + " .format('%02d')),\n", + " 'FalseCase': ee.String('EPSG:327').cat(utmCode \\\n", + " .format('%02d'))\n", + " })\n", + " return (output)\n", + "\n", + "\n", + "coords = aoi.centroid(30).coordinates()\n", + "lon = coords.get(0)\n", + "lat = coords.get(1)\n", + "crs = getUTMProj(lon, lat)\n", + "scale = 30\n", + "\n", + "def rpj(image):\n", + " return image.reproject({\n", + " 'crs': crs,\n", + " 'scale': scale\n", + " })\n", + "\n", + "\n", + "distanceKernel = ee.Kernel.euclidean({\n", + " 'radius': 30,\n", + " 'units': 'meters',\n", + " 'magnitude': 0.5\n", + "})\n", + "\n", + "def makeChannelmask(year):\n", + " watermask = jrcYearly.filter(ee.Filter.eq('year', year)) \\\n", + " .first() \\\n", + " .gte(2).unmask() \\\n", + " .focal_max().focal_min() \\\n", + " .rename('watermask')\n", + "\n", + " barPolys = watermask.Not().selfMask() \\\n", + " .reduceToVectors({\n", + " 'geometry': aoi,\n", + " 'scale': 30,\n", + " 'eightConnected': False\n", + " }) \\\n", + " .filter(ee.Filter.lte('count', 1E4)); \n", + "\n", + " filled = watermask.paint(barPolys, 1).rename('filled')\n", + "\n", + " costmap = filled.Not().cumulativeCost({\n", + " 'source': watermask.And(ee.Image().toByte().paint(\n", + " sword, 1)),\n", + " 'maxDistance': 5E3,\n", + " 'geodeticDistance': False\n", + " }).rename('costmap')\n", + "\n", + " rivermask = costmap.eq(0).rename('rivermask')\n", + " channelmask = rivermask.And(watermask).rename(\n", + " 'channelmask')\n", + "\n", + " bankMask = channelmask.focal_max(1).neq(channelmask) \\\n", + " .rename('bankMask')\n", + " bankDistance = channelmask.Not().cumulativeCost({\n", + " 'source': channelmask,\n", + " 'maxDistance': 1E2,\n", + " 'geodeticDistance': False\n", + " })\n", + " bankAspect = ee.Terrain.aspect(bankDistance).mask(\n", + " bankMask).rename('bankAspect')\n", + "\n", + " bankLength = bankMask.convolve(distanceKernel) \\\n", + " .mask(bankMask).rename('bankLength')\n", + "\n", + " return ee.Image.cat([\n", + " watermask, channelmask, rivermask, bankMask,\n", + " bankAspect, bankLength\n", + " ]).set('year', year) \\\n", + " .clip(aoi)\n", + "\n", + "\n", + "#\n", + " Isolate the river channel from the JRC data for two years and apply the bank morphology\n", + " calculations from Section 1. Here we will simply compare two years with two explicit\n", + " calls to the makeChannelmask() function, but you can also map this function over a list\n", + " 'of years like follows':\n", + "\n", + " masks = ee.List.sequence(2000,2020,5).map(makeChannelmask)\n", + "#\n", + "\n", + "masks1 = makeChannelmask(2015)\n", + "masks2 = makeChannelmask(2020)\n", + "Map.centerObject(aoi, 13)\n", + "year1mask = rpj(masks1.select('channelmask').selfMask())\n", + "Map.addLayer(year1mask, {\n", + " 'palette': ['blue']\n", + "}, 'year 1')\n", + "year2mask = rpj(masks2.select('channelmask').selfMask())\n", + "Map.addLayer(year2mask, {\n", + " 'palette': ['red']\n", + "}, 'year 2', True, 0.5)\n", + "\n", + "# Pixels that are now the river channel but were previously land.\n", + "erosion = masks2.select('channelmask') \\\n", + " .And(masks1.select('watermask').Not()).rename('erosion')\n", + "Map.addLayer(rpj(erosion).selfMask(), {}, 'erosion', False)\n", + "\n", + "# Erosion distance assuming the shortest distance between banks.\n", + "erosionEndpoints = erosion.focal_max(1).And(masks2.select(\n", + " 'bankMask'))\n", + "erosionDistance = erosion.focal_max(1).selfMask() \\\n", + " .cumulativeCost({\n", + " 'source': erosionEndpoints,\n", + " 'maxDistance': 1E3,\n", + " 'geodeticDistance': True\n", + " }).rename('erosionDistance')\n", + "Map.addLayer(rpj(erosionDistance),\n", + " {\n", + " 'min': 0,\n", + " 'max': 300\n", + " },\n", + " 'erosion distance',\n", + " False)\n", + "\n", + "# Direction of the erosion following slope of distance.\n", + "erosionDirection = ee.Terrain.aspect(erosionDistance) \\\n", + " .multiply(math.pi).divide(180) \\\n", + " .clip(aoi) \\\n", + " .rename('erosionDirection')\n", + "erosionDistance = erosionDistance.mask(erosion)\n", + "Map.addLayer(rpj(erosionDirection),\n", + " {\n", + " 'min': 0,\n", + " 'max': math.pi\n", + " },\n", + " 'erosion direction',\n", + " False)\n", + "\n", + "#\n", + " Map each pixel to the closest river centerline point.\n", + "#\n", + "\n", + "# Distance to nearest SWORD centerline point.\n", + "distance = sword.distance(2E3).clip(aoi)\n", + "\n", + "# Second derivatives of distance.\n", + "# Finding the 0s identifies boundaries between centerline points.\n", + "concavityBounds = distance.convolve(ee.Kernel.laplacian8()) \\\n", + " .gte(0).rename('bounds')\n", + "\n", + "Map.addLayer(rpj(distance), {\n", + " 'min': 0,\n", + " 'max': 1E3\n", + "}, 'distance', False)\n", + "Map.addLayer(rpj(concavityBounds), {}, 'bounds', False)\n", + "\n", + "# Reduce the pixels according to the concavity boundaries,\n", + "# and set the value to SWORD node ID. Note that focalMode is used\n", + "# to fill in the empty pixels that were the boundaries.\n", + "swordImg = ee.Image(0).paint(sword, 'node_id').rename('node_id') \\\n", + " .clip(aoi)\n", + "nodePixels = concavityBounds.addBands(swordImg) \\\n", + " .reduceConnectedComponents({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'labelBand': 'bounds'\n", + " }).focalMode({\n", + " 'radius': 3,\n", + " 'iterations': 2\n", + " })\n", + "Map.addLayer(rpj(nodePixels).randomVisualizer(),\n", + " {},\n", + " 'node assignments',\n", + " False)\n", + "\n", + "# Set up a custom reducing function to summarize the data.\n", + "def groupReduce(dataImg, nodeIds, reducer):\n", + " # Create a grouped reducer for each band in the data image.\n", + " groupReducer = reducer.forEach(dataImg.bandNames()) \\\n", + " .group({\n", + " 'groupField': dataImg.bandNames().length(),\n", + " 'groupName': 'node_id'\n", + " })\n", + "\n", + " # Apply the grouped reducer.\n", + " statsList = dataImg.addBands(nodeIds).clip(aoi) \\\n", + " .reduceRegion({\n", + " 'reducer': groupReducer,\n", + " 'scale': 30,\n", + " }).get('groups')\n", + "\n", + " # Convert list of dictionaries to FeatureCollection.\n", + "\n", + "def func_hhz(dict):\n", + " return ee.Feature(None, dict)\n", + "\n", + " statsOut = ee.List(statsList).map(func_hhz)\n", + "\n", + "\n", + "\n", + " return ee.FeatureCollection(statsOut)\n", + "\n", + "\n", + "dataMask = masks1.addBands(masks2).reduce(ee.Reducer \\\n", + " .anyNonZero())\n", + "\n", + "sumBands = ['watermask', 'channelmask', 'bankLength']\n", + "sumImg = erosion \\\n", + " .addBands(masks1, sumBands) \\\n", + " .addBands(masks2, sumBands)\n", + "sumStats = groupReduce(sumImg, nodePixels, ee.Reducer.sum())\n", + "\n", + "angleImg = erosionDirection \\\n", + " .addBands(masks1, ['bankAspect']) \\\n", + " .addBands(masks2, ['bankAspect'])\n", + "angleStats = groupReduce(angleImg, nodePixels, ee.Reducer \\\n", + " .circularMean())\n", + "\n", + "\n", + "def func_kqd(feat):\n", + " nodeFilter = ee.Filter.eq('node_id', feat.get(\n", + " 'node_id'))\n", + " sumFeat = sumStats.filter(nodeFilter).first()\n", + " angleFeat = angleStats.filter(nodeFilter).first()\n", + " return feat.copyProperties(sumFeat).copyProperties(\n", + " angleFeat)\n", + "\n", + "vectorData = sword.filterBounds(aoi).map(func_kqd)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "print(vectorData)\n", + "Map.addLayer(vectorData, {}, 'final data')\n", + "\n", + "# ------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24f Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24f Checkpoint.js new file mode 100644 index 0000000..b6b309c --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24f Checkpoint.js @@ -0,0 +1,252 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var jrcYearly = ee.ImageCollection("JRC/GSW1_3/YearlyHistory"), + aoi = + /* color: #d63000 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-66.75498758257174, -11.090110301403685], + [-66.75498758257174, -11.258517279582335], + [-66.56650339067721, -11.258517279582335], + [-66.56650339067721, -11.090110301403685]]], null, false), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.4 River Morphology +// Checkpoint: A24f +// Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var getUTMProj = function(lon, lat) { + // Given longitude and latitude in decimal degrees, + // return EPSG string for the corresponding UTM projection. See: + // https://apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily + // https://sis.apache.org/faq.html + var utmCode = ee.Number(lon).add(180).divide(6).ceil().int(); + var output = ee.Algorithms.If({ + condition: ee.Number(lat).gte(0), + trueCase: ee.String('EPSG:326').cat(utmCode + .format('%02d')), + falseCase: ee.String('EPSG:327').cat(utmCode + .format('%02d')) + }); + return (output); +}; + +var coords = aoi.centroid(30).coordinates(); +var lon = coords.get(0); +var lat = coords.get(1); +var crs = getUTMProj(lon, lat); +var scale = 30; + +var rpj = function(image) { + return image.reproject({ + crs: crs, + scale: scale + }); +}; + +var distanceKernel = ee.Kernel.euclidean({ + radius: 30, + units: 'meters', + magnitude: 0.5 +}); + +var makeChannelmask = function(year) { + var watermask = jrcYearly.filter(ee.Filter.eq('year', year)) + .first() + .gte(2).unmask() + .focal_max().focal_min() + .rename('watermask'); + + var barPolys = watermask.not().selfMask() + .reduceToVectors({ + geometry: aoi, + scale: 30, + eightConnected: false + }) + .filter(ee.Filter.lte('count', 1E4)); // Get small polys. + + var filled = watermask.paint(barPolys, 1).rename('filled'); + + var costmap = filled.not().cumulativeCost({ + source: watermask.and(ee.Image().toByte().paint( + sword, 1)), + maxDistance: 5E3, + geodeticDistance: false + }).rename('costmap'); + + var rivermask = costmap.eq(0).rename('rivermask'); + var channelmask = rivermask.and(watermask).rename( + 'channelmask'); + + var bankMask = channelmask.focal_max(1).neq(channelmask) + .rename('bankMask'); + var bankDistance = channelmask.not().cumulativeCost({ + source: channelmask, + maxDistance: 1E2, + geodeticDistance: false + }); + var bankAspect = ee.Terrain.aspect(bankDistance).mask( + bankMask).rename('bankAspect'); + + var bankLength = bankMask.convolve(distanceKernel) + .mask(bankMask).rename('bankLength'); + + return ee.Image.cat([ + watermask, channelmask, rivermask, bankMask, + bankAspect, bankLength + ]).set('year', year) + .clip(aoi); +}; + +/* + Isolate the river channel from the JRC data for two years and apply the bank morphology + calculations from Section 1. Here we will simply compare two years with two explicit + calls to the makeChannelmask() function, but you can also map this function over a list + of years like follows: + + var masks = ee.List.sequence(2000,2020,5).map(makeChannelmask) +*/ + +var masks1 = makeChannelmask(2015); +var masks2 = makeChannelmask(2020); +Map.centerObject(aoi, 13); +var year1mask = rpj(masks1.select('channelmask').selfMask()); +Map.addLayer(year1mask, { + palette: ['blue'] +}, 'year 1'); +var year2mask = rpj(masks2.select('channelmask').selfMask()); +Map.addLayer(year2mask, { + palette: ['red'] +}, 'year 2', true, 0.5); + +// Pixels that are now the river channel but were previously land. +var erosion = masks2.select('channelmask') + .and(masks1.select('watermask').not()).rename('erosion'); +Map.addLayer(rpj(erosion).selfMask(), {}, 'erosion', false); + +// Erosion distance assuming the shortest distance between banks. +var erosionEndpoints = erosion.focal_max(1).and(masks2.select( + 'bankMask')); +var erosionDistance = erosion.focal_max(1).selfMask() + .cumulativeCost({ + source: erosionEndpoints, + maxDistance: 1E3, + geodeticDistance: true + }).rename('erosionDistance'); +Map.addLayer(rpj(erosionDistance), + { + min: 0, + max: 300 + }, + 'erosion distance', + false); + +// Direction of the erosion following slope of distance. +var erosionDirection = ee.Terrain.aspect(erosionDistance) + .multiply(Math.PI).divide(180) + .clip(aoi) + .rename('erosionDirection'); +erosionDistance = erosionDistance.mask(erosion); +Map.addLayer(rpj(erosionDirection), + { + min: 0, + max: Math.PI + }, + 'erosion direction', + false); + +/* + Map each pixel to the closest river centerline point. +*/ + +// Distance to nearest SWORD centerline point. +var distance = sword.distance(2E3).clip(aoi); + +// Second derivatives of distance. +// Finding the 0s identifies boundaries between centerline points. +var concavityBounds = distance.convolve(ee.Kernel.laplacian8()) + .gte(0).rename('bounds'); + +Map.addLayer(rpj(distance), { + min: 0, + max: 1E3 +}, 'distance', false); +Map.addLayer(rpj(concavityBounds), {}, 'bounds', false); + +// Reduce the pixels according to the concavity boundaries, +// and set the value to SWORD node ID. Note that focalMode is used +// to fill in the empty pixels that were the boundaries. +var swordImg = ee.Image(0).paint(sword, 'node_id').rename('node_id') + .clip(aoi); +var nodePixels = concavityBounds.addBands(swordImg) + .reduceConnectedComponents({ + reducer: ee.Reducer.max(), + labelBand: 'bounds' + }).focalMode({ + radius: 3, + iterations: 2 + }); +Map.addLayer(rpj(nodePixels).randomVisualizer(), + {}, + 'node assignments', + false); + +// Set up a custom reducing function to summarize the data. +var groupReduce = function(dataImg, nodeIds, reducer) { + // Create a grouped reducer for each band in the data image. + var groupReducer = reducer.forEach(dataImg.bandNames()) + .group({ + groupField: dataImg.bandNames().length(), + groupName: 'node_id' + }); + + // Apply the grouped reducer. + var statsList = dataImg.addBands(nodeIds).clip(aoi) + .reduceRegion({ + reducer: groupReducer, + scale: 30, + }).get('groups'); + + // Convert list of dictionaries to FeatureCollection. + var statsOut = ee.List(statsList).map(function(dict) { + return ee.Feature(null, dict); + }); + return ee.FeatureCollection(statsOut); +}; + +var dataMask = masks1.addBands(masks2).reduce(ee.Reducer + .anyNonZero()); + +var sumBands = ['watermask', 'channelmask', 'bankLength']; +var sumImg = erosion + .addBands(masks1, sumBands) + .addBands(masks2, sumBands); +var sumStats = groupReduce(sumImg, nodePixels, ee.Reducer.sum()); + +var angleImg = erosionDirection + .addBands(masks1, ['bankAspect']) + .addBands(masks2, ['bankAspect']); +var angleStats = groupReduce(angleImg, nodePixels, ee.Reducer + .circularMean()); + +var vectorData = sword.filterBounds(aoi).map(function(feat) { + var nodeFilter = ee.Filter.eq('node_id', feat.get( + 'node_id')); + var sumFeat = sumStats.filter(nodeFilter).first(); + var angleFeat = angleStats.filter(nodeFilter).first(); + return feat.copyProperties(sumFeat).copyProperties( + angleFeat); +}); + +print(vectorData); +Map.addLayer(vectorData, {}, 'final data'); + +// ------------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24f Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24f Checkpoint.py new file mode 100644 index 0000000..4410a0e --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.4 River Morphology/A24f Checkpoint.py @@ -0,0 +1,274 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +jrcYearly = ee.ImageCollection("JRC/GSW1_3/YearlyHistory"), + aoi = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-66.75498758257174, -11.090110301403685], + [-66.75498758257174, -11.258517279582335], + [-66.56650339067721, -11.258517279582335], + [-66.56650339067721, -11.090110301403685]]], None, False), + sword = ee.FeatureCollection("projects/gee-book/assets/A2-4/SWORD") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.4 River Morphology +# Checkpoint: A24f +# Authors: Xiao Yang, Theodore Langhorst, Tamlin M. Pavelsky +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def getUTMProj(lon, lat): + # Given longitude and latitude in decimal degrees, + # return EPSG string for the corresponding UTM projection. See: + # https:#apollomapping.com/blog/gtm-finding-a-utm-zone-number-easily + # https:#sis.apache.Org/faq.html + utmCode = ee.Number(lon).add(180).divide(6).ceil().int() + output = ee.Algorithms.If({ + 'condition': ee.Number(lat).gte(0), + 'TrueCase': ee.String('EPSG:326').cat(utmCode \ + .format('%02d')), + 'FalseCase': ee.String('EPSG:327').cat(utmCode \ + .format('%02d')) + }) + return (output) + + +coords = aoi.centroid(30).coordinates() +lon = coords.get(0) +lat = coords.get(1) +crs = getUTMProj(lon, lat) +scale = 30 + +def rpj(image): + return image.reproject({ + 'crs': crs, + 'scale': scale + }) + + +distanceKernel = ee.Kernel.euclidean({ + 'radius': 30, + 'units': 'meters', + 'magnitude': 0.5 +}) + +def makeChannelmask(year): + watermask = jrcYearly.filter(ee.Filter.eq('year', year)) \ + .first() \ + .gte(2).unmask() \ + .focal_max().focal_min() \ + .rename('watermask') + + barPolys = watermask.Not().selfMask() \ + .reduceToVectors({ + 'geometry': aoi, + 'scale': 30, + 'eightConnected': False + }) \ + .filter(ee.Filter.lte('count', 1E4)); + + filled = watermask.paint(barPolys, 1).rename('filled') + + costmap = filled.Not().cumulativeCost({ + 'source': watermask.And(ee.Image().toByte().paint( + sword, 1)), + 'maxDistance': 5E3, + 'geodeticDistance': False + }).rename('costmap') + + rivermask = costmap.eq(0).rename('rivermask') + channelmask = rivermask.And(watermask).rename( + 'channelmask') + + bankMask = channelmask.focal_max(1).neq(channelmask) \ + .rename('bankMask') + bankDistance = channelmask.Not().cumulativeCost({ + 'source': channelmask, + 'maxDistance': 1E2, + 'geodeticDistance': False + }) + bankAspect = ee.Terrain.aspect(bankDistance).mask( + bankMask).rename('bankAspect') + + bankLength = bankMask.convolve(distanceKernel) \ + .mask(bankMask).rename('bankLength') + + return ee.Image.cat([ + watermask, channelmask, rivermask, bankMask, + bankAspect, bankLength + ]).set('year', year) \ + .clip(aoi) + + +# + Isolate the river channel from the JRC data for two years and apply the bank morphology + calculations from Section 1. Here we will simply compare two years with two explicit + calls to the makeChannelmask() function, but you can also map this function over a list + 'of years like follows': + + masks = ee.List.sequence(2000,2020,5).map(makeChannelmask) +# + +masks1 = makeChannelmask(2015) +masks2 = makeChannelmask(2020) +Map.centerObject(aoi, 13) +year1mask = rpj(masks1.select('channelmask').selfMask()) +Map.addLayer(year1mask, { + 'palette': ['blue'] +}, 'year 1') +year2mask = rpj(masks2.select('channelmask').selfMask()) +Map.addLayer(year2mask, { + 'palette': ['red'] +}, 'year 2', True, 0.5) + +# Pixels that are now the river channel but were previously land. +erosion = masks2.select('channelmask') \ + .And(masks1.select('watermask').Not()).rename('erosion') +Map.addLayer(rpj(erosion).selfMask(), {}, 'erosion', False) + +# Erosion distance assuming the shortest distance between banks. +erosionEndpoints = erosion.focal_max(1).And(masks2.select( + 'bankMask')) +erosionDistance = erosion.focal_max(1).selfMask() \ + .cumulativeCost({ + 'source': erosionEndpoints, + 'maxDistance': 1E3, + 'geodeticDistance': True + }).rename('erosionDistance') +Map.addLayer(rpj(erosionDistance), + { + 'min': 0, + 'max': 300 + }, + 'erosion distance', + False) + +# Direction of the erosion following slope of distance. +erosionDirection = ee.Terrain.aspect(erosionDistance) \ + .multiply(math.pi).divide(180) \ + .clip(aoi) \ + .rename('erosionDirection') +erosionDistance = erosionDistance.mask(erosion) +Map.addLayer(rpj(erosionDirection), + { + 'min': 0, + 'max': math.pi + }, + 'erosion direction', + False) + +# + Map each pixel to the closest river centerline point. +# + +# Distance to nearest SWORD centerline point. +distance = sword.distance(2E3).clip(aoi) + +# Second derivatives of distance. +# Finding the 0s identifies boundaries between centerline points. +concavityBounds = distance.convolve(ee.Kernel.laplacian8()) \ + .gte(0).rename('bounds') + +Map.addLayer(rpj(distance), { + 'min': 0, + 'max': 1E3 +}, 'distance', False) +Map.addLayer(rpj(concavityBounds), {}, 'bounds', False) + +# Reduce the pixels according to the concavity boundaries, +# and set the value to SWORD node ID. Note that focalMode is used +# to fill in the empty pixels that were the boundaries. +swordImg = ee.Image(0).paint(sword, 'node_id').rename('node_id') \ + .clip(aoi) +nodePixels = concavityBounds.addBands(swordImg) \ + .reduceConnectedComponents({ + 'reducer': ee.Reducer.max(), + 'labelBand': 'bounds' + }).focalMode({ + 'radius': 3, + 'iterations': 2 + }) +Map.addLayer(rpj(nodePixels).randomVisualizer(), + {}, + 'node assignments', + False) + +# Set up a custom reducing function to summarize the data. +def groupReduce(dataImg, nodeIds, reducer): + # Create a grouped reducer for each band in the data image. + groupReducer = reducer.forEach(dataImg.bandNames()) \ + .group({ + 'groupField': dataImg.bandNames().length(), + 'groupName': 'node_id' + }) + + # Apply the grouped reducer. + statsList = dataImg.addBands(nodeIds).clip(aoi) \ + .reduceRegion({ + 'reducer': groupReducer, + 'scale': 30, + }).get('groups') + + # Convert list of dictionaries to FeatureCollection. + +def func_hhz(dict): + return ee.Feature(None, dict) + + statsOut = ee.List(statsList).map(func_hhz) + + + + return ee.FeatureCollection(statsOut) + + +dataMask = masks1.addBands(masks2).reduce(ee.Reducer \ + .anyNonZero()) + +sumBands = ['watermask', 'channelmask', 'bankLength'] +sumImg = erosion \ + .addBands(masks1, sumBands) \ + .addBands(masks2, sumBands) +sumStats = groupReduce(sumImg, nodePixels, ee.Reducer.sum()) + +angleImg = erosionDirection \ + .addBands(masks1, ['bankAspect']) \ + .addBands(masks2, ['bankAspect']) +angleStats = groupReduce(angleImg, nodePixels, ee.Reducer \ + .circularMean()) + + +def func_kqd(feat): + nodeFilter = ee.Filter.eq('node_id', feat.get( + 'node_id')) + sumFeat = sumStats.filter(nodeFilter).first() + angleFeat = angleStats.filter(nodeFilter).first() + return feat.copyProperties(sumFeat).copyProperties( + angleFeat) + +vectorData = sword.filterBounds(aoi).map(func_kqd) + + + + + + + + + +print(vectorData) +Map.addLayer(vectorData, {}, 'final data') + +# ------------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25a Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25a Checkpoint.ipynb new file mode 100644 index 0000000..6758e21 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25a Checkpoint.ipynb @@ -0,0 +1,207 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.5 Water Balance and Drought\n", + "# Checkpoint: A25a\n", + "# Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andr\u00e9a Puzzi Nicolau\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Lower Mekong boundary.\n", + "mekongBasin = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-5/lowerMekongBasin')\n", + "\n", + "# Center the map.\n", + "Map.centerObject(mekongBasin, 5)\n", + "\n", + "# Add the Lower Mekong Basin boundary to the map.\n", + "Map.addLayer(mekongBasin, {}, 'Lower Mekong basin')\n", + "\n", + "# Set start and end years.\n", + "startYear = 2010\n", + "endYear = 2020\n", + "\n", + "# Create two date objects for start and end years.\n", + "startDate = ee.Date.fromYMD(startYear, 1, 1)\n", + "endDate = ee.Date.fromYMD(endYear + 1, 1, 1)\n", + "\n", + "# Make a list with years.\n", + "years = ee.List.sequence(startYear, endYear)\n", + "\n", + "# Make a list with months.\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Import the CHIRPS dataset.\n", + "CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "\n", + "# Filter for the relevant time period.\n", + "CHIRPS = CHIRPS.filterDate(startDate, endDate)\n", + "\n", + "# We apply a nested loop where we first map over\n", + "# the relevant years and then map over the relevant\n", + "# months. The function returns an image with the total (sum)\n", + "# rainfall for each month. A flatten is applied to convert a\n", + "# feature collection of features into a single feature collection.\n", + "monthlyPrecip = ee.ImageCollection.fromImages(\n", + "\n", + "def func_bgd(y):\n", + " return months.map(function(m) {\n", + " w = CHIRPS.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum()\n", + " return w.set('year', y) \\\n", + " .set('month', m) \\\n", + " .set('system:time_start', ee.Date \\\n", + " .fromYMD(y, m, 1))\n", + "\n", + " })\n", + "\n", + " years.map(func_bgd\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + ")\n", + "\n", + "# Add the layer with monthly mean. Note that we clip for the Mekong river basin.\n", + "precipVis = {\n", + " 'min': 0,\n", + " 'max': 250,\n", + " 'palette': 'white, blue, darkblue, red, purple'\n", + "}\n", + "\n", + "Map.addLayer(monthlyPrecip.mean().clip(mekongBasin),\n", + " precipVis,\n", + " '2015 precipitation')\n", + "\n", + "# Set the title and axis labels for the chart.\n", + "title = {\n", + " 'title': 'Monthly precipitation',\n", + " 'hAxis': {\n", + " 'title': 'Time'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Precipitation (mm)'\n", + " },\n", + "}\n", + "\n", + "# Plot the chart using the Mekong boundary.\n", + "chartMonthly = ui.Chart.image.seriesByRegion({\n", + " 'imageCollection': monthlyPrecip,\n", + " 'regions': mekongBasin.geometry(),\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'band': 'precipitation',\n", + " 'scale': 5000,\n", + " 'xProperty': 'system:time_start'\n", + " }).setSeriesNames(['P']) \\\n", + " .setOptions(title) \\\n", + " .setChartType('ColumnChart')\n", + "\n", + "# Print the chart.\n", + "print(chartMonthly)\n", + "\n", + "# -----------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25a Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25a Checkpoint.js new file mode 100644 index 0000000..aea2659 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25a Checkpoint.js @@ -0,0 +1,98 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.5 Water Balance and Drought +// Checkpoint: A25a +// Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Lower Mekong boundary. +var mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin'); + +// Center the map. +Map.centerObject(mekongBasin, 5); + +// Add the Lower Mekong Basin boundary to the map. +Map.addLayer(mekongBasin, {}, 'Lower Mekong basin'); + +// Set start and end years. +var startYear = 2010; +var endYear = 2020; + +// Create two date objects for start and end years. +var startDate = ee.Date.fromYMD(startYear, 1, 1); +var endDate = ee.Date.fromYMD(endYear + 1, 1, 1); + +// Make a list with years. +var years = ee.List.sequence(startYear, endYear); + +// Make a list with months. +var months = ee.List.sequence(1, 12); + +// Import the CHIRPS dataset. +var CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Filter for the relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate); + +// We apply a nested loop where we first map over +// the relevant years and then map over the relevant +// months. The function returns an image with the total (sum) +// rainfall for each month. A flatten is applied to convert a +// feature collection of features into a single feature collection. +var monthlyPrecip = ee.ImageCollection.fromImages( + years.map(function(y) { + return months.map(function(m) { + var w = CHIRPS.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum(); + return w.set('year', y) + .set('month', m) + .set('system:time_start', ee.Date + .fromYMD(y, m, 1)); + + }); + }).flatten() +); + +// Add the layer with monthly mean. Note that we clip for the Mekong river basin. +var precipVis = { + min: 0, + max: 250, + palette: 'white, blue, darkblue, red, purple' +}; + +Map.addLayer(monthlyPrecip.mean().clip(mekongBasin), + precipVis, + '2015 precipitation'); + +// Set the title and axis labels for the chart. +var title = { + title: 'Monthly precipitation', + hAxis: { + title: 'Time' + }, + vAxis: { + title: 'Precipitation (mm)' + }, +}; + +// Plot the chart using the Mekong boundary. +var chartMonthly = ui.Chart.image.seriesByRegion({ + imageCollection: monthlyPrecip, + regions: mekongBasin.geometry(), + reducer: ee.Reducer.mean(), + band: 'precipitation', + scale: 5000, + xProperty: 'system:time_start' + }).setSeriesNames(['P']) + .setOptions(title) + .setChartType('ColumnChart'); + +// Print the chart. +print(chartMonthly); + +// ----------------------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25a Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25a Checkpoint.py new file mode 100644 index 0000000..8c1536d --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25a Checkpoint.py @@ -0,0 +1,120 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.5 Water Balance and Drought +# Checkpoint: A25a +# Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Lower Mekong boundary. +mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin') + +# Center the map. +Map.centerObject(mekongBasin, 5) + +# Add the Lower Mekong Basin boundary to the map. +Map.addLayer(mekongBasin, {}, 'Lower Mekong basin') + +# Set start and end years. +startYear = 2010 +endYear = 2020 + +# Create two date objects for start and end years. +startDate = ee.Date.fromYMD(startYear, 1, 1) +endDate = ee.Date.fromYMD(endYear + 1, 1, 1) + +# Make a list with years. +years = ee.List.sequence(startYear, endYear) + +# Make a list with months. +months = ee.List.sequence(1, 12) + +# Import the CHIRPS dataset. +CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') + +# Filter for the relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate) + +# We apply a nested loop where we first map over +# the relevant years and then map over the relevant +# months. The function returns an image with the total (sum) +# rainfall for each month. A flatten is applied to convert a +# feature collection of features into a single feature collection. +monthlyPrecip = ee.ImageCollection.fromImages( + +def func_bgd(y): + return months.map(function(m) { + w = CHIRPS.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() + return w.set('year', y) \ + .set('month', m) \ + .set('system:time_start', ee.Date \ + .fromYMD(y, m, 1)) + + }) + + years.map(func_bgd +).flatten() + + + + + + + + + + + + +).flatten() +) + +# Add the layer with monthly mean. Note that we clip for the Mekong river basin. +precipVis = { + 'min': 0, + 'max': 250, + 'palette': 'white, blue, darkblue, red, purple' +} + +Map.addLayer(monthlyPrecip.mean().clip(mekongBasin), + precipVis, + '2015 precipitation') + +# Set the title and axis labels for the chart. +title = { + 'title': 'Monthly precipitation', + 'hAxis': { + 'title': 'Time' + }, + 'vAxis': { + 'title': 'Precipitation (mm)' + }, +} + +# Plot the chart using the Mekong boundary. +chartMonthly = ui.Chart.image.seriesByRegion({ + 'imageCollection': monthlyPrecip, + 'regions': mekongBasin.geometry(), + 'reducer': ee.Reducer.mean(), + 'band': 'precipitation', + 'scale': 5000, + 'xProperty': 'system:time_start' + }).setSeriesNames(['P']) \ + .setOptions(title) \ + .setChartType('ColumnChart') + +# Print the chart. +print(chartMonthly) + +# ----------------------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25b Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25b Checkpoint.ipynb new file mode 100644 index 0000000..0b37c6a --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25b Checkpoint.ipynb @@ -0,0 +1,211 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.5 Water Balance and Drought\n", + "# Checkpoint: A25b\n", + "# Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andr\u00e9a Puzzi Nicolau\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Lower Mekong boundary.\n", + "mekongBasin = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-5/lowerMekongBasin')\n", + "\n", + "# Center the map.\n", + "Map.centerObject(mekongBasin, 5)\n", + "\n", + "# Add the Lower Mekong Basin boundary to the map.\n", + "Map.addLayer(mekongBasin, {}, 'Lower Mekong basin')\n", + "\n", + "# Set start and end years.\n", + "startYear = 2010\n", + "endYear = 2020\n", + "\n", + "# Create two date objects for start and end years.\n", + "startDate = ee.Date.fromYMD(startYear, 1, 1)\n", + "endDate = ee.Date.fromYMD(endYear + 1, 1, 1)\n", + "\n", + "# Make a list with years.\n", + "years = ee.List.sequence(startYear, endYear)\n", + "\n", + "# Make a list with months.\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Import the MOD16 dataset.\n", + "mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET')\n", + "\n", + "# Filter for the relevant time period.\n", + "mod16 = mod16.filterDate(startDate, endDate)\n", + "\n", + "# We apply a nested loop where we first map over\n", + "# the relevant years and then map over the relevant\n", + "# months. The function returns an image with the total (sum)\n", + "# evapotranspiration for each month. A flatten is applied to convert a\n", + "# collection of collections into a single collection.\n", + "# We multiply by 0.1 because of the ET scaling factor.\n", + "monthlyEvap = ee.ImageCollection.fromImages(\n", + "\n", + "def func_ttm(y):\n", + " return months.map(function(m) {\n", + " w = mod16.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum() \\\n", + " .multiply(0.1)\n", + " return w.set('year', y) \\\n", + " .set('month', m) \\\n", + " .set('system:time_start', ee.Date \\\n", + " .fromYMD(y, m, 1))\n", + "\n", + " })\n", + "\n", + " years.map(func_ttm\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + ")\n", + "\n", + "# Add the layer with monthly mean. Note that we clip for the Mekong river basin.\n", + "evapVis = {\n", + " 'min': 0,\n", + " 'max': 140,\n", + " 'palette': 'red, orange, yellow, blue, darkblue'\n", + "}\n", + "\n", + "Map.addLayer(monthlyEvap.mean().clip(mekongBasin),\n", + " evapVis,\n", + " 'Mean monthly ET')\n", + "\n", + "# Set the title and axis labels for the chart.\n", + "title = {\n", + " 'title': 'Monthly evapotranspiration',\n", + " 'hAxis': {\n", + " 'title': 'Time'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Evapotranspiration (mm)'\n", + " },\n", + " 'colors': ['red']\n", + "}\n", + "\n", + "# Plot the chart using the Mekong boundary.\n", + "chartMonthly = ui.Chart.image.seriesByRegion({\n", + " 'imageCollection': monthlyEvap,\n", + " 'regions': mekongBasin.geometry(),\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'band': 'ET',\n", + " 'scale': 500,\n", + " 'xProperty': 'system:time_start'\n", + " }).setSeriesNames(['ET']) \\\n", + " .setOptions(title) \\\n", + " .setChartType('ColumnChart')\n", + "\n", + "# Print the chart.\n", + "print(chartMonthly)\n", + "\n", + "# -----------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25b Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25b Checkpoint.js new file mode 100644 index 0000000..48e536a --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25b Checkpoint.js @@ -0,0 +1,101 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.5 Water Balance and Drought +// Checkpoint: A25b +// Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Lower Mekong boundary. +var mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin'); + +// Center the map. +Map.centerObject(mekongBasin, 5); + +// Add the Lower Mekong Basin boundary to the map. +Map.addLayer(mekongBasin, {}, 'Lower Mekong basin'); + +// Set start and end years. +var startYear = 2010; +var endYear = 2020; + +// Create two date objects for start and end years. +var startDate = ee.Date.fromYMD(startYear, 1, 1); +var endDate = ee.Date.fromYMD(endYear + 1, 1, 1); + +// Make a list with years. +var years = ee.List.sequence(startYear, endYear); + +// Make a list with months. +var months = ee.List.sequence(1, 12); + +// Import the MOD16 dataset. +var mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET'); + +// Filter for the relevant time period. +mod16 = mod16.filterDate(startDate, endDate); + +// We apply a nested loop where we first map over +// the relevant years and then map over the relevant +// months. The function returns an image with the total (sum) +// evapotranspiration for each month. A flatten is applied to convert a +// collection of collections into a single collection. +// We multiply by 0.1 because of the ET scaling factor. +var monthlyEvap = ee.ImageCollection.fromImages( + years.map(function(y) { + return months.map(function(m) { + var w = mod16.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum() + .multiply(0.1); + return w.set('year', y) + .set('month', m) + .set('system:time_start', ee.Date + .fromYMD(y, m, 1)); + + }); + }).flatten() +); + +// Add the layer with monthly mean. Note that we clip for the Mekong river basin. +var evapVis = { + min: 0, + max: 140, + palette: 'red, orange, yellow, blue, darkblue' +}; + +Map.addLayer(monthlyEvap.mean().clip(mekongBasin), + evapVis, + 'Mean monthly ET'); + +// Set the title and axis labels for the chart. +var title = { + title: 'Monthly evapotranspiration', + hAxis: { + title: 'Time' + }, + vAxis: { + title: 'Evapotranspiration (mm)' + }, + colors: ['red'] +}; + +// Plot the chart using the Mekong boundary. +var chartMonthly = ui.Chart.image.seriesByRegion({ + imageCollection: monthlyEvap, + regions: mekongBasin.geometry(), + reducer: ee.Reducer.mean(), + band: 'ET', + scale: 500, + xProperty: 'system:time_start' + }).setSeriesNames(['ET']) + .setOptions(title) + .setChartType('ColumnChart'); + +// Print the chart. +print(chartMonthly); + +// ----------------------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25b Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25b Checkpoint.py new file mode 100644 index 0000000..5556757 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25b Checkpoint.py @@ -0,0 +1,124 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.5 Water Balance and Drought +# Checkpoint: A25b +# Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Lower Mekong boundary. +mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin') + +# Center the map. +Map.centerObject(mekongBasin, 5) + +# Add the Lower Mekong Basin boundary to the map. +Map.addLayer(mekongBasin, {}, 'Lower Mekong basin') + +# Set start and end years. +startYear = 2010 +endYear = 2020 + +# Create two date objects for start and end years. +startDate = ee.Date.fromYMD(startYear, 1, 1) +endDate = ee.Date.fromYMD(endYear + 1, 1, 1) + +# Make a list with years. +years = ee.List.sequence(startYear, endYear) + +# Make a list with months. +months = ee.List.sequence(1, 12) + +# Import the MOD16 dataset. +mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET') + +# Filter for the relevant time period. +mod16 = mod16.filterDate(startDate, endDate) + +# We apply a nested loop where we first map over +# the relevant years and then map over the relevant +# months. The function returns an image with the total (sum) +# evapotranspiration for each month. A flatten is applied to convert a +# collection of collections into a single collection. +# We multiply by 0.1 because of the ET scaling factor. +monthlyEvap = ee.ImageCollection.fromImages( + +def func_ttm(y): + return months.map(function(m) { + w = mod16.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() \ + .multiply(0.1) + return w.set('year', y) \ + .set('month', m) \ + .set('system:time_start', ee.Date \ + .fromYMD(y, m, 1)) + + }) + + years.map(func_ttm +).flatten() + + + + + + + + + + + + + +).flatten() +) + +# Add the layer with monthly mean. Note that we clip for the Mekong river basin. +evapVis = { + 'min': 0, + 'max': 140, + 'palette': 'red, orange, yellow, blue, darkblue' +} + +Map.addLayer(monthlyEvap.mean().clip(mekongBasin), + evapVis, + 'Mean monthly ET') + +# Set the title and axis labels for the chart. +title = { + 'title': 'Monthly evapotranspiration', + 'hAxis': { + 'title': 'Time' + }, + 'vAxis': { + 'title': 'Evapotranspiration (mm)' + }, + 'colors': ['red'] +} + +# Plot the chart using the Mekong boundary. +chartMonthly = ui.Chart.image.seriesByRegion({ + 'imageCollection': monthlyEvap, + 'regions': mekongBasin.geometry(), + 'reducer': ee.Reducer.mean(), + 'band': 'ET', + 'scale': 500, + 'xProperty': 'system:time_start' + }).setSeriesNames(['ET']) \ + .setOptions(title) \ + .setChartType('ColumnChart') + +# Print the chart. +print(chartMonthly) + +# ----------------------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25c Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25c Checkpoint.ipynb new file mode 100644 index 0000000..c1502ed --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25c Checkpoint.ipynb @@ -0,0 +1,236 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.5 Water Balance and Drought\n", + "# Checkpoint: A25c\n", + "# Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andr\u00e9a Puzzi Nicolau\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Lower Mekong boundary.\n", + "mekongBasin = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-5/lowerMekongBasin')\n", + "\n", + "# Center the map.\n", + "Map.centerObject(mekongBasin, 5)\n", + "\n", + "# Add the Lower Mekong Basin boundary to the map.\n", + "Map.addLayer(mekongBasin, {}, 'Lower Mekong basin')\n", + "\n", + "# Set start and end years.\n", + "startYear = 2010\n", + "endYear = 2020\n", + "\n", + "# Create two date objects for start and end years.\n", + "startDate = ee.Date.fromYMD(startYear, 1, 1)\n", + "endDate = ee.Date.fromYMD(endYear + 1, 1, 1)\n", + "\n", + "# Make a list with years.\n", + "years = ee.List.sequence(startYear, endYear)\n", + "\n", + "# Make a list with months.\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Import the CHIRPS dataset.\n", + "CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "\n", + "# Filter for relevant time period.\n", + "CHIRPS = CHIRPS.filterDate(startDate, endDate)\n", + "\n", + "# Import the MOD16 dataset.\n", + "mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET')\n", + "\n", + "# Filter for relevant time period.\n", + "mod16 = mod16.filterDate(startDate, endDate)\n", + "\n", + "# We apply a nested loop where we first iterate over\n", + "# the relevant years and then iterate over the relevant\n", + "# months. The function returns an image with P - ET\n", + "# for each month. A flatten is applied to convert an\n", + "# collection of collections into a single collection.\n", + "waterBalance = ee.ImageCollection.fromImages(\n", + "\n", + "def func_egz(y):\n", + " return months.map(function(m) {\n", + "\n", + " P = CHIRPS.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum()\n", + "\n", + " ET = mod16.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum() \\\n", + " .multiply(0.1)\n", + "\n", + " wb = P.subtract(ET).rename('wb')\n", + "\n", + " return wb.set('year', y) \\\n", + " .set('month', m) \\\n", + " .set('system:time_start', ee.Date \\\n", + " .fromYMD(y, m, 1))\n", + "\n", + " })\n", + "\n", + " years.map(func_egz\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + ")\n", + "\n", + "# Add layer with monthly mean. note that we clip for the Mekong river basin.\n", + "balanceVis = {\n", + " 'min': -50,\n", + " 'max': 200,\n", + " 'palette': 'red, orange, yellow, blue, darkblue, purple'\n", + "}\n", + "\n", + "Map.addLayer(waterBalance.mean().clip(mekongBasin),\n", + " balanceVis,\n", + " 'Mean monthly water balance')\n", + "\n", + "# Set the title and axis labels for the chart.\n", + "title = {\n", + " 'title': 'Monthly water balance',\n", + " 'hAxis': {\n", + " 'title': 'Time'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Evapotranspiration (mm)'\n", + " },\n", + " 'colors': ['green']\n", + "}\n", + "\n", + "# Plot the chart using the Mekong boundary.\n", + "chartMonthly = ui.Chart.image.seriesByRegion({\n", + " 'imageCollection': waterBalance,\n", + " 'regions': mekongBasin.geometry(),\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'band': 'wb',\n", + " 'scale': 500,\n", + " 'xProperty': 'system:time_start'\n", + " }).setSeriesNames(['WB']) \\\n", + " .setOptions(title) \\\n", + " .setChartType('ColumnChart')\n", + "\n", + "# Print the chart.\n", + "print(chartMonthly)\n", + "\n", + "# -----------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25c Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25c Checkpoint.js new file mode 100644 index 0000000..1684fb7 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25c Checkpoint.js @@ -0,0 +1,116 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.5 Water Balance and Drought +// Checkpoint: A25c +// Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Lower Mekong boundary. +var mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin'); + +// Center the map. +Map.centerObject(mekongBasin, 5); + +// Add the Lower Mekong Basin boundary to the map. +Map.addLayer(mekongBasin, {}, 'Lower Mekong basin'); + +// Set start and end years. +var startYear = 2010; +var endYear = 2020; + +// Create two date objects for start and end years. +var startDate = ee.Date.fromYMD(startYear, 1, 1); +var endDate = ee.Date.fromYMD(endYear + 1, 1, 1); + +// Make a list with years. +var years = ee.List.sequence(startYear, endYear); + +// Make a list with months. +var months = ee.List.sequence(1, 12); + +// Import the CHIRPS dataset. +var CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Filter for relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate); + +// Import the MOD16 dataset. +var mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET'); + +// Filter for relevant time period. +mod16 = mod16.filterDate(startDate, endDate); + +// We apply a nested loop where we first iterate over +// the relevant years and then iterate over the relevant +// months. The function returns an image with P - ET +// for each month. A flatten is applied to convert an +// collection of collections into a single collection. +var waterBalance = ee.ImageCollection.fromImages( + years.map(function(y) { + return months.map(function(m) { + + var P = CHIRPS.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum(); + + var ET = mod16.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum() + .multiply(0.1); + + var wb = P.subtract(ET).rename('wb'); + + return wb.set('year', y) + .set('month', m) + .set('system:time_start', ee.Date + .fromYMD(y, m, 1)); + + }); + }).flatten() +); + +// Add layer with monthly mean. note that we clip for the Mekong river basin. +var balanceVis = { + min: -50, + max: 200, + palette: 'red, orange, yellow, blue, darkblue, purple' +}; + +Map.addLayer(waterBalance.mean().clip(mekongBasin), + balanceVis, + 'Mean monthly water balance'); + +// Set the title and axis labels for the chart. +var title = { + title: 'Monthly water balance', + hAxis: { + title: 'Time' + }, + vAxis: { + title: 'Evapotranspiration (mm)' + }, + colors: ['green'] +}; + +// Plot the chart using the Mekong boundary. +var chartMonthly = ui.Chart.image.seriesByRegion({ + imageCollection: waterBalance, + regions: mekongBasin.geometry(), + reducer: ee.Reducer.mean(), + band: 'wb', + scale: 500, + xProperty: 'system:time_start' + }).setSeriesNames(['WB']) + .setOptions(title) + .setChartType('ColumnChart'); + +// Print the chart. +print(chartMonthly); + +// ----------------------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25c Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25c Checkpoint.py new file mode 100644 index 0000000..555ed72 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25c Checkpoint.py @@ -0,0 +1,149 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.5 Water Balance and Drought +# Checkpoint: A25c +# Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Lower Mekong boundary. +mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin') + +# Center the map. +Map.centerObject(mekongBasin, 5) + +# Add the Lower Mekong Basin boundary to the map. +Map.addLayer(mekongBasin, {}, 'Lower Mekong basin') + +# Set start and end years. +startYear = 2010 +endYear = 2020 + +# Create two date objects for start and end years. +startDate = ee.Date.fromYMD(startYear, 1, 1) +endDate = ee.Date.fromYMD(endYear + 1, 1, 1) + +# Make a list with years. +years = ee.List.sequence(startYear, endYear) + +# Make a list with months. +months = ee.List.sequence(1, 12) + +# Import the CHIRPS dataset. +CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') + +# Filter for relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate) + +# Import the MOD16 dataset. +mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET') + +# Filter for relevant time period. +mod16 = mod16.filterDate(startDate, endDate) + +# We apply a nested loop where we first iterate over +# the relevant years and then iterate over the relevant +# months. The function returns an image with P - ET +# for each month. A flatten is applied to convert an +# collection of collections into a single collection. +waterBalance = ee.ImageCollection.fromImages( + +def func_egz(y): + return months.map(function(m) { + + P = CHIRPS.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() + + ET = mod16.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() \ + .multiply(0.1) + + wb = P.subtract(ET).rename('wb') + + return wb.set('year', y) \ + .set('month', m) \ + .set('system:time_start', ee.Date \ + .fromYMD(y, m, 1)) + + }) + + years.map(func_egz +).flatten() + + + + + + + + + + + + + + + + + + + + + + + +).flatten() +) + +# Add layer with monthly mean. note that we clip for the Mekong river basin. +balanceVis = { + 'min': -50, + 'max': 200, + 'palette': 'red, orange, yellow, blue, darkblue, purple' +} + +Map.addLayer(waterBalance.mean().clip(mekongBasin), + balanceVis, + 'Mean monthly water balance') + +# Set the title and axis labels for the chart. +title = { + 'title': 'Monthly water balance', + 'hAxis': { + 'title': 'Time' + }, + 'vAxis': { + 'title': 'Evapotranspiration (mm)' + }, + 'colors': ['green'] +} + +# Plot the chart using the Mekong boundary. +chartMonthly = ui.Chart.image.seriesByRegion({ + 'imageCollection': waterBalance, + 'regions': mekongBasin.geometry(), + 'reducer': ee.Reducer.mean(), + 'band': 'wb', + 'scale': 500, + 'xProperty': 'system:time_start' + }).setSeriesNames(['WB']) \ + .setOptions(title) \ + .setChartType('ColumnChart') + +# Print the chart. +print(chartMonthly) + +# ----------------------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25d Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25d Checkpoint.ipynb new file mode 100644 index 0000000..7ddb19e --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25d Checkpoint.ipynb @@ -0,0 +1,384 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.5 Water Balance and Drought\n", + "# Checkpoint: A25d\n", + "# Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andr\u00e9a Puzzi Nicolau\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Lower Mekong boundary.\n", + "mekongBasin = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-5/lowerMekongBasin')\n", + "\n", + "# Center the map.\n", + "Map.centerObject(mekongBasin, 5)\n", + "\n", + "# Add the Lower Mekong Basin boundary to the map.\n", + "Map.addLayer(mekongBasin, {}, 'Lower Mekong basin')\n", + "\n", + "# Set start and end years.\n", + "startYear = 2010\n", + "endYear = 2020\n", + "\n", + "# Create two date objects for start and end years.\n", + "startDate = ee.Date.fromYMD(startYear, 1, 1)\n", + "endDate = ee.Date.fromYMD(endYear + 1, 1, 1)\n", + "\n", + "# Make a list with years.\n", + "years = ee.List.sequence(startYear, endYear)\n", + "\n", + "# Make a list with months.\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Import the CHIRPS dataset.\n", + "CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "\n", + "# Filter for relevant time period.\n", + "CHIRPS = CHIRPS.filterDate(startDate, endDate)\n", + "\n", + "# Import the MOD16 dataset.\n", + "mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET')\n", + "\n", + "# Filter for relevant time period.\n", + "mod16 = mod16.filterDate(startDate, endDate)\n", + "\n", + "# Import and filter the MOD13 dataset.\n", + "mod13 = ee.ImageCollection('MODIS/006/MOD13A1')\n", + "mod13 = mod13.filterDate(startDate, endDate)\n", + "\n", + "# Select the EVI.\n", + "EVI = mod13.select('EVI')\n", + "\n", + "# Import and filter the MODIS Terra surface reflectance dataset.\n", + "mod09 = ee.ImageCollection('MODIS/006/MOD09A1')\n", + "mod09 = mod09.filterDate(startDate, endDate)\n", + "\n", + "# We use a function to remove clouds and cloud shadows.\n", + "# We map over the mod09 image collection and select the StateQA band.\n", + "# We mask pixels and return the image with clouds and cloud shadows masked.\n", + "\n", + "def func_rzy(image):\n", + " quality = image.select('StateQA')\n", + " mask = image.And(quality.bitwiseAnd(1).eq(\n", + " 0)) # No clouds. \\\n", + " .And(quality.bitwiseAnd(2).eq(0)); \n", + "\n", + " return image.updateMask(mask)\n", + "\n", + "mod09 = mod09.map(func_rzy)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# We use a function to calculate the Moisture Stress Index.\n", + "# We map over the mod09 image collection and select the NIR and SWIR bands\n", + "# We set the timestamp and return the MSI.\n", + "\n", + "def func_fjo(image):\n", + " nirband = image.select('sur_refl_b02')\n", + " swirband = image.select('sur_refl_b06')\n", + "\n", + " msi = swirband.divide(nirband).rename('MSI') \\\n", + " .set('system:time_start', image.get(\n", + " 'system:time_start'))\n", + " return msi\n", + "\n", + "MSI = mod09.map(func_fjo)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# We apply a nested loop where we first iterate over\n", + "# the relevant years and then iterate over the relevant\n", + "# months. The function returns an image with bands for\n", + "# water balance (wb), rainfall (P), evapotranspiration (ET),\n", + "# EVI and MSI for each month. A flatten is applied to\n", + "# convert an collection of collections\n", + "# into a single collection.\n", + "ic = ee.ImageCollection.fromImages(\n", + "\n", + "def func_gjw(y):\n", + " return months.map(function(m) {\n", + " # Calculate rainfall.\n", + " P = CHIRPS.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum()\n", + "\n", + " # Calculate evapotranspiration.\n", + " ET = mod16.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum() \\\n", + " .multiply(0.1)\n", + "\n", + " # Calculate EVI.\n", + " evi = EVI.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .mean() \\\n", + " .multiply(0.0001)\n", + "\n", + " # Calculate MSI.\n", + " msi = MSI.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .mean()\n", + "\n", + " # Calculate monthly water balance.\n", + " wb = P.subtract(ET).rename('wb')\n", + "\n", + " # Return an image with all images as bands.\n", + " return ee.Image.cat([wb, P, ET, evi, msi]) \\\n", + " .set('year', y) \\\n", + " .set('month', m) \\\n", + " .set('system:time_start', ee.Date \\\n", + " .fromYMD(y, m, 1))\n", + "\n", + " })\n", + "\n", + " years.map(func_gjw\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + ")\n", + "\n", + "# Add the mean monthly EVI and MSI to the map.\n", + "eviVis = {\n", + " 'min': 0,\n", + " 'max': 0.7,\n", + " 'palette': 'red, orange, yellow, green, darkgreen'\n", + "}\n", + "\n", + "Map.addLayer(ic.select('EVI').mean().clip(mekongBasin),\n", + " eviVis,\n", + " 'EVI')\n", + "\n", + "msiVis = {\n", + " 'min': 0.25,\n", + " 'max': 1,\n", + " 'palette': 'darkblue, blue, yellow, orange, red'\n", + "}\n", + "\n", + "Map.addLayer(ic.select('MSI').mean().clip(mekongBasin),\n", + " msiVis,\n", + " 'MSI')\n", + "\n", + "# Define the water balance chart and print it to the console.\n", + "chartWB =\n", + " ui.Chart.image.series({\n", + " 'imageCollection': ic.select(['wb', 'precipitation', 'ET']),\n", + " 'region': mekongBasin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 5000,\n", + " 'xProperty': 'system:time_start'\n", + " }) \\\n", + " .setSeriesNames(['wb', 'P', 'ET']) \\\n", + " .setOptions({\n", + " 'title': 'water balance',\n", + " 'hAxis': {\n", + " 'title': 'Date',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Water (mm)',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'colors': ['green', 'blue', 'red'],\n", + " 'curveType': 'function'\n", + " })\n", + "\n", + "# Print the water balance chart.\n", + "print(chartWB)\n", + "\n", + "# Define the indices chart and print it to the console.\n", + "chartIndices =\n", + " ui.Chart.image.series({\n", + " 'imageCollection': ic.select(['EVI', 'MSI']),\n", + " 'region': mekongBasin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 5000,\n", + " 'xProperty': 'system:time_start'\n", + " }) \\\n", + " .setSeriesNames(['EVI', 'MSI']) \\\n", + " .setOptions({\n", + " 'title': 'Monthly indices',\n", + " 'hAxis': {\n", + " 'title': 'Date',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Index',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'colors': ['darkgreen', 'brown'],\n", + " 'curveType': 'function'\n", + " })\n", + "\n", + "# Print the indices chart.\n", + "print(chartIndices)\n", + "\n", + "# -----------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25d Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25d Checkpoint.js new file mode 100644 index 0000000..7b8cb02 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25d Checkpoint.js @@ -0,0 +1,224 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.5 Water Balance and Drought +// Checkpoint: A25d +// Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Lower Mekong boundary. +var mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin'); + +// Center the map. +Map.centerObject(mekongBasin, 5); + +// Add the Lower Mekong Basin boundary to the map. +Map.addLayer(mekongBasin, {}, 'Lower Mekong basin'); + +// Set start and end years. +var startYear = 2010; +var endYear = 2020; + +// Create two date objects for start and end years. +var startDate = ee.Date.fromYMD(startYear, 1, 1); +var endDate = ee.Date.fromYMD(endYear + 1, 1, 1); + +// Make a list with years. +var years = ee.List.sequence(startYear, endYear); + +// Make a list with months. +var months = ee.List.sequence(1, 12); + +// Import the CHIRPS dataset. +var CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Filter for relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate); + +// Import the MOD16 dataset. +var mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET'); + +// Filter for relevant time period. +mod16 = mod16.filterDate(startDate, endDate); + +// Import and filter the MOD13 dataset. +var mod13 = ee.ImageCollection('MODIS/006/MOD13A1'); +mod13 = mod13.filterDate(startDate, endDate); + +// Select the EVI. +var EVI = mod13.select('EVI'); + +// Import and filter the MODIS Terra surface reflectance dataset. +var mod09 = ee.ImageCollection('MODIS/006/MOD09A1'); +mod09 = mod09.filterDate(startDate, endDate); + +// We use a function to remove clouds and cloud shadows. +// We map over the mod09 image collection and select the StateQA band. +// We mask pixels and return the image with clouds and cloud shadows masked. +mod09 = mod09.map(function(image) { + var quality = image.select('StateQA'); + var mask = image.and(quality.bitwiseAnd(1).eq( + 0)) // No clouds. + .and(quality.bitwiseAnd(2).eq(0)); // No cloud shadow. + + return image.updateMask(mask); +}); + +// We use a function to calculate the Moisture Stress Index. +// We map over the mod09 image collection and select the NIR and SWIR bands +// We set the timestamp and return the MSI. +var MSI = mod09.map(function(image) { + var nirband = image.select('sur_refl_b02'); + var swirband = image.select('sur_refl_b06'); + + var msi = swirband.divide(nirband).rename('MSI') + .set('system:time_start', image.get( + 'system:time_start')); + return msi; +}); + +// We apply a nested loop where we first iterate over +// the relevant years and then iterate over the relevant +// months. The function returns an image with bands for +// water balance (wb), rainfall (P), evapotranspiration (ET), +// EVI and MSI for each month. A flatten is applied to +// convert an collection of collections +// into a single collection. +var ic = ee.ImageCollection.fromImages( + years.map(function(y) { + return months.map(function(m) { + // Calculate rainfall. + var P = CHIRPS.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum(); + + // Calculate evapotranspiration. + var ET = mod16.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum() + .multiply(0.1); + + // Calculate EVI. + var evi = EVI.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .mean() + .multiply(0.0001); + + // Calculate MSI. + var msi = MSI.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .mean(); + + // Calculate monthly water balance. + var wb = P.subtract(ET).rename('wb'); + + // Return an image with all images as bands. + return ee.Image.cat([wb, P, ET, evi, msi]) + .set('year', y) + .set('month', m) + .set('system:time_start', ee.Date + .fromYMD(y, m, 1)); + + }); + }).flatten() +); + +// Add the mean monthly EVI and MSI to the map. +var eviVis = { + min: 0, + max: 0.7, + palette: 'red, orange, yellow, green, darkgreen' +}; + +Map.addLayer(ic.select('EVI').mean().clip(mekongBasin), + eviVis, + 'EVI'); + +var msiVis = { + min: 0.25, + max: 1, + palette: 'darkblue, blue, yellow, orange, red' +}; + +Map.addLayer(ic.select('MSI').mean().clip(mekongBasin), + msiVis, + 'MSI'); + +// Define the water balance chart and print it to the console. +var chartWB = + ui.Chart.image.series({ + imageCollection: ic.select(['wb', 'precipitation', 'ET']), + region: mekongBasin, + reducer: ee.Reducer.mean(), + scale: 5000, + xProperty: 'system:time_start' + }) + .setSeriesNames(['wb', 'P', 'ET']) + .setOptions({ + title: 'water balance', + hAxis: { + title: 'Date', + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Water (mm)', + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1, + colors: ['green', 'blue', 'red'], + curveType: 'function' + }); + +// Print the water balance chart. +print(chartWB); + +// Define the indices chart and print it to the console. +var chartIndices = + ui.Chart.image.series({ + imageCollection: ic.select(['EVI', 'MSI']), + region: mekongBasin, + reducer: ee.Reducer.mean(), + scale: 5000, + xProperty: 'system:time_start' + }) + .setSeriesNames(['EVI', 'MSI']) + .setOptions({ + title: 'Monthly indices', + hAxis: { + title: 'Date', + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Index', + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1, + colors: ['darkgreen', 'brown'], + curveType: 'function' + }); + +// Print the indices chart. +print(chartIndices); + +// ----------------------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25d Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25d Checkpoint.py new file mode 100644 index 0000000..b5c4575 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25d Checkpoint.py @@ -0,0 +1,297 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.5 Water Balance and Drought +# Checkpoint: A25d +# Authors: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Lower Mekong boundary. +mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin') + +# Center the map. +Map.centerObject(mekongBasin, 5) + +# Add the Lower Mekong Basin boundary to the map. +Map.addLayer(mekongBasin, {}, 'Lower Mekong basin') + +# Set start and end years. +startYear = 2010 +endYear = 2020 + +# Create two date objects for start and end years. +startDate = ee.Date.fromYMD(startYear, 1, 1) +endDate = ee.Date.fromYMD(endYear + 1, 1, 1) + +# Make a list with years. +years = ee.List.sequence(startYear, endYear) + +# Make a list with months. +months = ee.List.sequence(1, 12) + +# Import the CHIRPS dataset. +CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') + +# Filter for relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate) + +# Import the MOD16 dataset. +mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET') + +# Filter for relevant time period. +mod16 = mod16.filterDate(startDate, endDate) + +# Import and filter the MOD13 dataset. +mod13 = ee.ImageCollection('MODIS/006/MOD13A1') +mod13 = mod13.filterDate(startDate, endDate) + +# Select the EVI. +EVI = mod13.select('EVI') + +# Import and filter the MODIS Terra surface reflectance dataset. +mod09 = ee.ImageCollection('MODIS/006/MOD09A1') +mod09 = mod09.filterDate(startDate, endDate) + +# We use a function to remove clouds and cloud shadows. +# We map over the mod09 image collection and select the StateQA band. +# We mask pixels and return the image with clouds and cloud shadows masked. + +def func_rzy(image): + quality = image.select('StateQA') + mask = image.And(quality.bitwiseAnd(1).eq( + 0)) # No clouds. \ + .And(quality.bitwiseAnd(2).eq(0)); + + return image.updateMask(mask) + +mod09 = mod09.map(func_rzy) + + + + + + + + + +# We use a function to calculate the Moisture Stress Index. +# We map over the mod09 image collection and select the NIR and SWIR bands +# We set the timestamp and return the MSI. + +def func_fjo(image): + nirband = image.select('sur_refl_b02') + swirband = image.select('sur_refl_b06') + + msi = swirband.divide(nirband).rename('MSI') \ + .set('system:time_start', image.get( + 'system:time_start')) + return msi + +MSI = mod09.map(func_fjo) + + + + + + + + + + +# We apply a nested loop where we first iterate over +# the relevant years and then iterate over the relevant +# months. The function returns an image with bands for +# water balance (wb), rainfall (P), evapotranspiration (ET), +# EVI and MSI for each month. A flatten is applied to +# convert an collection of collections +# into a single collection. +ic = ee.ImageCollection.fromImages( + +def func_gjw(y): + return months.map(function(m) { + # Calculate rainfall. + P = CHIRPS.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() + + # Calculate evapotranspiration. + ET = mod16.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() \ + .multiply(0.1) + + # Calculate EVI. + evi = EVI.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .mean() \ + .multiply(0.0001) + + # Calculate MSI. + msi = MSI.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .mean() + + # Calculate monthly water balance. + wb = P.subtract(ET).rename('wb') + + # Return an image with all images as bands. + return ee.Image.cat([wb, P, ET, evi, msi]) \ + .set('year', y) \ + .set('month', m) \ + .set('system:time_start', ee.Date \ + .fromYMD(y, m, 1)) + + }) + + years.map(func_gjw +).flatten() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +).flatten() +) + +# Add the mean monthly EVI and MSI to the map. +eviVis = { + 'min': 0, + 'max': 0.7, + 'palette': 'red, orange, yellow, green, darkgreen' +} + +Map.addLayer(ic.select('EVI').mean().clip(mekongBasin), + eviVis, + 'EVI') + +msiVis = { + 'min': 0.25, + 'max': 1, + 'palette': 'darkblue, blue, yellow, orange, red' +} + +Map.addLayer(ic.select('MSI').mean().clip(mekongBasin), + msiVis, + 'MSI') + +# Define the water balance chart and print it to the console. +chartWB = + ui.Chart.image.series({ + 'imageCollection': ic.select(['wb', 'precipitation', 'ET']), + 'region': mekongBasin, + 'reducer': ee.Reducer.mean(), + 'scale': 5000, + 'xProperty': 'system:time_start' + }) \ + .setSeriesNames(['wb', 'P', 'ET']) \ + .setOptions({ + 'title': 'water balance', + 'hAxis': { + 'title': 'Date', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Water (mm)', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'lineWidth': 1, + 'colors': ['green', 'blue', 'red'], + 'curveType': 'function' + }) + +# Print the water balance chart. +print(chartWB) + +# Define the indices chart and print it to the console. +chartIndices = + ui.Chart.image.series({ + 'imageCollection': ic.select(['EVI', 'MSI']), + 'region': mekongBasin, + 'reducer': ee.Reducer.mean(), + 'scale': 5000, + 'xProperty': 'system:time_start' + }) \ + .setSeriesNames(['EVI', 'MSI']) \ + .setOptions({ + 'title': 'Monthly indices', + 'hAxis': { + 'title': 'Date', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Index', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'lineWidth': 1, + 'colors': ['darkgreen', 'brown'], + 'curveType': 'function' + }) + +# Print the indices chart. +print(chartIndices) + +# ----------------------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s1 - Annual.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s1 - Annual.ipynb new file mode 100644 index 0000000..391e934 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s1 - Annual.ipynb @@ -0,0 +1,294 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.5 Water Balance and Drought\n", + "# Checkpoint: A25s1\n", + "# Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andr\u00e9a Puzzi Nicolau\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Lower Mekong boundary.\n", + "mekongBasin = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-5/lowerMekongBasin')\n", + "\n", + "Map.centerObject(mekongBasin, 6)\n", + "\n", + "classStruct = {\n", + " 'unknown': {\n", + " 'number': 0,\n", + " 'color': '6f6f6f'\n", + " },\n", + " 'surface water': {\n", + " 'number': 1,\n", + " 'color': 'aec3d4'\n", + " },\n", + " 'snow and ice': {\n", + " 'number': 2,\n", + " 'color': 'b1f9ff'\n", + " },\n", + " 'mangroves': {\n", + " 'number': 3,\n", + " 'color': '111149'\n", + " },\n", + " 'flooded forest': {\n", + " 'number': 4,\n", + " 'color': '287463'\n", + " },\n", + " 'Deciduous forest': {\n", + " 'number': 5,\n", + " 'color': '152106'\n", + " },\n", + " 'Orchard or plantation forest': {\n", + " 'number': 6,\n", + " 'color': 'c3aa69'\n", + " },\n", + " 'evergreen Broadleaf': {\n", + " 'number': 7,\n", + " 'color': '7db087'\n", + " },\n", + " 'mixed forest': {\n", + " 'number': 8,\n", + " 'color': '387242'\n", + " },\n", + " 'urban and built up': {\n", + " 'number': 9,\n", + " 'color': 'cc0013'\n", + " },\n", + " 'cropland': {\n", + " 'number': 10,\n", + " 'color': '8dc33b'\n", + " },\n", + " 'rice': {\n", + " 'number': 11,\n", + " 'color': 'ffff00'\n", + " },\n", + " 'mining': {\n", + " 'number': 12,\n", + " 'color': 'cec2a5'\n", + " },\n", + " 'barren': {\n", + " 'number': 13,\n", + " 'color': '674c06'\n", + " },\n", + " 'wetlands': {\n", + " 'number': 14,\n", + " 'color': '3bc3b2'\n", + " },\n", + " 'grassland': {\n", + " 'number': 15,\n", + " 'color': 'f4a460'\n", + " },\n", + " 'shrubland': {\n", + " 'number': 16,\n", + " 'color': '800080'\n", + " },\n", + " 'aquaculture': {\n", + " 'number': 17,\n", + " 'color': '51768e'\n", + " }\n", + "}\n", + "\n", + "classNamesList = getIds(classStruct)\n", + "probNames = cleanList(classNamesList)\n", + "classNames = ee.List(classNamesList)\n", + "classNumbers = getList(classStruct, 'number')\n", + "paletteList = getList(classStruct, 'color')\n", + "PALETTE = paletteList.join(',')\n", + "\n", + "collection = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A2-5/RLCMSv3')\n", + "\n", + "lcVis = {\n", + " 'palette': PALETTE,\n", + " 'min': 0,\n", + " 'max': classNamesList.length - 1\n", + "}\n", + "\n", + "for y in range(2000, 2019, 1):\n", + " startDate = ee.Date.fromYMD(y, 1, 1)\n", + " endDate = ee.Date.fromYMD(y, 12, 31)\n", + " lcMap = ee.Image(collection.filterDate(startDate, endDate) \\\n", + " .first()) \\\n", + " .select('lc') \\\n", + " .clip(mekongBasin)\n", + " Map.addLayer(lcMap, lcVis, y.toString(), False)\n", + "\n", + "\n", + "# Function to get a list of ids (keys) from a structure.\n", + "def getIds(struct):\n", + " return Object.keys(struct)\n", + "\n", + "\n", + "# Function to replace spaces with underscores in a list of strings.\n", + "def cleanList(list):\n", + "\n", + "def func_kdt(name):\n", + " return name.replace(/\\s+/g, '_')\n", + "\n", + " return list.map(func_kdt)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Function to get a list of column values from a structure.\n", + "def getList(struct, column):\n", + "\n", + "def func_waf(k):\n", + " value = struct[k][column]\n", + " return value\n", + "\n", + " return Object.keys(struct).map(func_waf)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Create the panel for the legend items.\n", + "legend = ui.Panel({\n", + " 'style': {\n", + " 'position': 'bottom-left',\n", + " 'padding': '8px 15px'\n", + " }\n", + "})\n", + "\n", + "# Create and add the legend title.\n", + "legendTitle = ui.Label({\n", + " 'value': 'Legend',\n", + " 'style': {\n", + " 'fontWeight': 'bold',\n", + " 'fontSize': '18px',\n", + " 'margin': '0 0 4px 0',\n", + " 'padding': '0'\n", + " }\n", + "})\n", + "\n", + "# Creates and styles 1 row of the legend.\n", + "def makeRow(color, name):\n", + " # Create the label that is actually the colored box.\n", + " colorBox = ui.Label({\n", + " 'style': {\n", + " 'backgroundColor': '#' + color,\n", + " # Use padding to give the box height and width.\n", + " 'padding': '8px',\n", + " 'margin': '0 0 4px 0'\n", + " }\n", + " })\n", + "\n", + " # Create the label filled with the description text.\n", + " description = ui.Label({\n", + " 'value': name,\n", + " 'style': {\n", + " 'margin': '0 0 4px 6px'\n", + " }\n", + " })\n", + "\n", + " return ui.Panel({\n", + " 'widgets': [colorBox, description],\n", + " 'layout': ui.Panel.Layout.Flow('horizontal')\n", + " })\n", + "\n", + "\n", + "for i in range(0, classNamesList.length, 1):\n", + " legend.add(makeRow(paletteList[i], classNamesList[i]))\n", + "\n", + "\n", + "legend.add(legendTitle)\n", + "\n", + "# Add the legend to the map.\n", + "Map.add(legend)\n", + "\n", + "# -----------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s1 - Annual.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s1 - Annual.js new file mode 100644 index 0000000..bae410d --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s1 - Annual.js @@ -0,0 +1,190 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.5 Water Balance and Drought +// Checkpoint: A25s1 +// Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Lower Mekong boundary. +var mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin'); + +Map.centerObject(mekongBasin, 6); + +var classStruct = { + 'unknown': { + number: 0, + color: '6f6f6f' + }, + 'surface water': { + number: 1, + color: 'aec3d4' + }, + 'snow and ice': { + number: 2, + color: 'b1f9ff' + }, + 'mangroves': { + number: 3, + color: '111149' + }, + 'flooded forest': { + number: 4, + color: '287463' + }, + 'Deciduous forest': { + number: 5, + color: '152106' + }, + 'Orchard or plantation forest': { + number: 6, + color: 'c3aa69' + }, + 'evergreen Broadleaf': { + number: 7, + color: '7db087' + }, + 'mixed forest': { + number: 8, + color: '387242' + }, + 'urban and built up': { + number: 9, + color: 'cc0013' + }, + 'cropland': { + number: 10, + color: '8dc33b' + }, + 'rice': { + number: 11, + color: 'ffff00' + }, + 'mining': { + number: 12, + color: 'cec2a5' + }, + 'barren': { + number: 13, + color: '674c06' + }, + 'wetlands': { + number: 14, + color: '3bc3b2' + }, + 'grassland': { + number: 15, + color: 'f4a460' + }, + 'shrubland': { + number: 16, + color: '800080' + }, + 'aquaculture': { + number: 17, + color: '51768e' + } +}; + +var classNamesList = getIds(classStruct); +var probNames = cleanList(classNamesList); +var classNames = ee.List(classNamesList); +var classNumbers = getList(classStruct, 'number'); +var paletteList = getList(classStruct, 'color'); +var PALETTE = paletteList.join(','); + +var collection = ee.ImageCollection( + 'projects/gee-book/assets/A2-5/RLCMSv3'); + +var lcVis = { + palette: PALETTE, + min: 0, + max: classNamesList.length - 1 +}; + +for (var y = 2000; y < 2019; y++) { + var startDate = ee.Date.fromYMD(y, 1, 1); + var endDate = ee.Date.fromYMD(y, 12, 31); + var lcMap = ee.Image(collection.filterDate(startDate, endDate) + .first()) + .select('lc') + .clip(mekongBasin); + Map.addLayer(lcMap, lcVis, y.toString(), false); +} + +// Function to get a list of ids (keys) from a structure. +function getIds(struct) { + return Object.keys(struct); +} + +// Function to replace spaces with underscores in a list of strings. +function cleanList(list) { + return list.map(function(name) { + return name.replace(/\s+/g, '_'); + }); +} + +// Function to get a list of column values from a structure. +function getList(struct, column) { + return Object.keys(struct).map(function(k) { + var value = struct[k][column]; + return value; + }); +} + +// Create the panel for the legend items. +var legend = ui.Panel({ + style: { + position: 'bottom-left', + padding: '8px 15px' + } +}); + +// Create and add the legend title. +var legendTitle = ui.Label({ + value: 'Legend', + style: { + fontWeight: 'bold', + fontSize: '18px', + margin: '0 0 4px 0', + padding: '0' + } +}); + +// Creates and styles 1 row of the legend. +var makeRow = function(color, name) { + // Create the label that is actually the colored box. + var colorBox = ui.Label({ + style: { + backgroundColor: '#' + color, + // Use padding to give the box height and width. + padding: '8px', + margin: '0 0 4px 0' + } + }); + + // Create the label filled with the description text. + var description = ui.Label({ + value: name, + style: { + margin: '0 0 4px 6px' + } + }); + + return ui.Panel({ + widgets: [colorBox, description], + layout: ui.Panel.Layout.Flow('horizontal') + }); +}; + +for (var i = 0; i < classNamesList.length; i++) { + legend.add(makeRow(paletteList[i], classNamesList[i])); +} + +legend.add(legendTitle); + +// Add the legend to the map. +Map.add(legend); + +// ----------------------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s1 - Annual.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s1 - Annual.py new file mode 100644 index 0000000..bb12157 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s1 - Annual.py @@ -0,0 +1,207 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.5 Water Balance and Drought +# Checkpoint: A25s1 +# Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Lower Mekong boundary. +mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin') + +Map.centerObject(mekongBasin, 6) + +classStruct = { + 'unknown': { + 'number': 0, + 'color': '6f6f6f' + }, + 'surface water': { + 'number': 1, + 'color': 'aec3d4' + }, + 'snow and ice': { + 'number': 2, + 'color': 'b1f9ff' + }, + 'mangroves': { + 'number': 3, + 'color': '111149' + }, + 'flooded forest': { + 'number': 4, + 'color': '287463' + }, + 'Deciduous forest': { + 'number': 5, + 'color': '152106' + }, + 'Orchard or plantation forest': { + 'number': 6, + 'color': 'c3aa69' + }, + 'evergreen Broadleaf': { + 'number': 7, + 'color': '7db087' + }, + 'mixed forest': { + 'number': 8, + 'color': '387242' + }, + 'urban and built up': { + 'number': 9, + 'color': 'cc0013' + }, + 'cropland': { + 'number': 10, + 'color': '8dc33b' + }, + 'rice': { + 'number': 11, + 'color': 'ffff00' + }, + 'mining': { + 'number': 12, + 'color': 'cec2a5' + }, + 'barren': { + 'number': 13, + 'color': '674c06' + }, + 'wetlands': { + 'number': 14, + 'color': '3bc3b2' + }, + 'grassland': { + 'number': 15, + 'color': 'f4a460' + }, + 'shrubland': { + 'number': 16, + 'color': '800080' + }, + 'aquaculture': { + 'number': 17, + 'color': '51768e' + } +} + +classNamesList = getIds(classStruct) +probNames = cleanList(classNamesList) +classNames = ee.List(classNamesList) +classNumbers = getList(classStruct, 'number') +paletteList = getList(classStruct, 'color') +PALETTE = paletteList.join(',') + +collection = ee.ImageCollection( + 'projects/gee-book/assets/A2-5/RLCMSv3') + +lcVis = { + 'palette': PALETTE, + 'min': 0, + 'max': classNamesList.length - 1 +} + +for y in range(2000, 2019, 1): + startDate = ee.Date.fromYMD(y, 1, 1) + endDate = ee.Date.fromYMD(y, 12, 31) + lcMap = ee.Image(collection.filterDate(startDate, endDate) \ + .first()) \ + .select('lc') \ + .clip(mekongBasin) + Map.addLayer(lcMap, lcVis, y.toString(), False) + + +# Function to get a list of ids (keys) from a structure. +def getIds(struct): + return Object.keys(struct) + + +# Function to replace spaces with underscores in a list of strings. +def cleanList(list): + +def func_kdt(name): + return name.replace(/\s+/g, '_') + + return list.map(func_kdt) + + + + + +# Function to get a list of column values from a structure. +def getList(struct, column): + +def func_waf(k): + value = struct[k][column] + return value + + return Object.keys(struct).map(func_waf) + + + + + + +# Create the panel for the legend items. +legend = ui.Panel({ + 'style': { + 'position': 'bottom-left', + 'padding': '8px 15px' + } +}) + +# Create and add the legend title. +legendTitle = ui.Label({ + 'value': 'Legend', + 'style': { + 'fontWeight': 'bold', + 'fontSize': '18px', + 'margin': '0 0 4px 0', + 'padding': '0' + } +}) + +# Creates and styles 1 row of the legend. +def makeRow(color, name): + # Create the label that is actually the colored box. + colorBox = ui.Label({ + 'style': { + 'backgroundColor': '#' + color, + # Use padding to give the box height and width. + 'padding': '8px', + 'margin': '0 0 4px 0' + } + }) + + # Create the label filled with the description text. + description = ui.Label({ + 'value': name, + 'style': { + 'margin': '0 0 4px 6px' + } + }) + + return ui.Panel({ + 'widgets': [colorBox, description], + 'layout': ui.Panel.Layout.Flow('horizontal') + }) + + +for i in range(0, classNamesList.length, 1): + legend.add(makeRow(paletteList[i], classNamesList[i])) + + +legend.add(legendTitle) + +# Add the legend to the map. +Map.add(legend) + +# ----------------------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s2 - PET.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s2 - PET.ipynb new file mode 100644 index 0000000..54c3842 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s2 - PET.ipynb @@ -0,0 +1,473 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.5 Water Balance and Drought\n", + "# Checkpoint: A25s2\n", + "# Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andr\u00e9a Puzzi Nicolau\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Lower Mekong boundary.\n", + "mekongBasin = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-5/lowerMekongBasin')\n", + "\n", + "Map.centerObject(mekongBasin, 6)\n", + "\n", + "classStruct = {\n", + " 'unknown': {\n", + " 'number': 0,\n", + " 'color': '6f6f6f'\n", + " },\n", + " 'surface water': {\n", + " 'number': 1,\n", + " 'color': 'aec3d4'\n", + " },\n", + " 'snow and ice': {\n", + " 'number': 2,\n", + " 'color': 'b1f9ff'\n", + " },\n", + " 'mangroves': {\n", + " 'number': 3,\n", + " 'color': '111149'\n", + " },\n", + " 'flooded forest': {\n", + " 'number': 4,\n", + " 'color': '287463'\n", + " },\n", + " 'Deciduous forest': {\n", + " 'number': 5,\n", + " 'color': '152106'\n", + " },\n", + " 'Orchard or plantation forest': {\n", + " 'number': 6,\n", + " 'color': 'c3aa69'\n", + " },\n", + " 'evergreen Broadleaf': {\n", + " 'number': 7,\n", + " 'color': '7db087'\n", + " },\n", + " 'mixed forest': {\n", + " 'number': 8,\n", + " 'color': '387242'\n", + " },\n", + " 'urban and built up': {\n", + " 'number': 9,\n", + " 'color': 'cc0013'\n", + " },\n", + " 'cropland': {\n", + " 'number': 10,\n", + " 'color': '8dc33b'\n", + " },\n", + " 'rice': {\n", + " 'number': 11,\n", + " 'color': 'ffff00'\n", + " },\n", + " 'mining': {\n", + " 'number': 12,\n", + " 'color': 'cec2a5'\n", + " },\n", + " 'barren': {\n", + " 'number': 13,\n", + " 'color': '674c06'\n", + " },\n", + " 'wetlands': {\n", + " 'number': 14,\n", + " 'color': '3bc3b2'\n", + " },\n", + " 'grassland': {\n", + " 'number': 15,\n", + " 'color': 'f4a460'\n", + " },\n", + " 'shrubland': {\n", + " 'number': 16,\n", + " 'color': '800080'\n", + " },\n", + " 'aquaculture': {\n", + " 'number': 17,\n", + " 'color': '51768e'\n", + " }\n", + "}\n", + "\n", + "# Function to get a list of ids (keys) from a structure.\n", + "def getIds(struct):\n", + " return Object.keys(struct)\n", + "\n", + "\n", + "# Function to replace spaces with underscores in a list of strings.\n", + "def cleanList(list):\n", + "\n", + "def func_ebb(name):\n", + " return name.replace(/\\s+/g, '_')\n", + "\n", + " return list.map(func_ebb)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Function to get a list of column values from a structure.\n", + "def getList(struct, column):\n", + "\n", + "def func_ycx(k):\n", + " value = struct[k][column]\n", + " return value\n", + "\n", + " return Object.keys(struct).map(func_ycx)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "classNamesList = getIds(classStruct)\n", + "probNames = cleanList(classNamesList)\n", + "classNames = ee.List(classNamesList)\n", + "classNumbers = getList(classStruct, 'number')\n", + "paletteList = getList(classStruct, 'color')\n", + "PALETTE = paletteList.join(',')\n", + "\n", + "# JSON dictionary that defines piechart colors based on the\n", + "# landcover class palette.\n", + "# https:#developers.google.com/chart/interactive/docs/gallery/piechart\n", + "colors = []\n", + "for i in range(0, paletteList.length, 1):\n", + " colors.push({\n", + " 'color': '_'.replace('_', paletteList[i])\n", + " })\n", + "\n", + "\n", + "# Set start and end years.\n", + "startYear = 2010\n", + "endYear = 2020\n", + "\n", + "# Create two date objects for start and end years.\n", + "startDate = ee.Date.fromYMD(startYear, 1, 1)\n", + "endDate = ee.Date.fromYMD(endYear + 1, 1, 1)\n", + "\n", + "# Make a list with years.\n", + "years = ee.List.sequence(startYear, endYear)\n", + "\n", + "# Make a list with months.\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Import the MOD16 dataset.\n", + "mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET')\n", + "\n", + "# Filter for relevant time period.\n", + "mod16 = mod16.filterDate(startDate, endDate)\n", + "\n", + "# Import the CHIRPS dataset.\n", + "CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "\n", + "# Filter for relevant time period.\n", + "CHIRPS = CHIRPS.filterDate(startDate, endDate)\n", + "\n", + "landcover = ee.Image(\n", + " 'projects/gee-book/assets/A2-5/RLCMSv3/Mekonglandcover2018') \\\n", + " .select('lc').clip(mekongBasin)\n", + "\n", + "lcVis = {\n", + " 'palette': PALETTE,\n", + " 'min': 0,\n", + " 'max': classNamesList.length - 1\n", + "}\n", + "Map.addLayer(landcover, lcVis, '2018 Land Cover')\n", + "\n", + "# We apply a nested loop where we first iterate over\n", + "# the relevant years and then iterate over the relevant\n", + "# months. The function returns an image with P - ET\n", + "# for each month. A flatten is applied to convert an\n", + "# collection of collections into a single collection.\n", + "waterBalance = ee.ImageCollection.fromImages(\n", + "\n", + "def func_cly(y):\n", + " return months.map(function(m) {\n", + "\n", + " P = CHIRPS.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum()\n", + "\n", + " ET = mod16.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum() \\\n", + " .multiply(0.1)\n", + "\n", + " wb = P.subtract(ET).rename('wb')\n", + "\n", + " return wb.addBands(P).addBands(ET).set(\n", + " 'year', y) \\\n", + " .set('month', m) \\\n", + " .set('system:time_start', ee.Date \\\n", + " .fromYMD(y, m, 1))\n", + " })\n", + "\n", + " years.map(func_cly\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + ")\n", + "\n", + "# Calculate mean monthly values.\n", + "monthlyP = waterBalance.select('precipitation').mean()\n", + "monthlyET = waterBalance.select('ET').mean()\n", + "monthlyWB = waterBalance.select('wb').mean()\n", + "\n", + "# Apply reducer per land cover category.\n", + "# We create binary map for each class and multiply by mean ET.\n", + "# The results are stored in a feature with other properties of the class.\n", + "# The function returns a feature which are stored in a feature collection.\n", + "\n", + "def func_vdu(nr):\n", + " lc = landcover.eq(ee.Number(nr))\n", + "\n", + " P = monthlyP.multiply(lc)\n", + " et = monthlyET.multiply(lc)\n", + "\n", + " pSum = P.reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': mekongBasin,\n", + " 'scale': 500\n", + " }).get('precipitation')\n", + "\n", + " etSum = et.reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': mekongBasin,\n", + " 'scale': 500\n", + " }).get('ET')\n", + "\n", + " return ee.Feature(None).set('et', etSum) \\\n", + " .set('p', pSum) \\\n", + " .set('class_name', classNames.get(nr)) \\\n", + " .set('palette', paletteList[nr]) \\\n", + " .set('class_number', nr)\n", + "\n", + "lcFc = ee.FeatureCollection(classNumbers.map(func_vdu\n", + "))\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "))\n", + "\n", + "# Create the chart.\n", + "pChart = ui.Chart.feature.byFeature({\n", + " 'features': lcFc,\n", + " 'xProperty': 'class_name',\n", + " 'yProperties': ['p', 'class_number']\n", + " }) \\\n", + " .setChartType('PieChart') \\\n", + " .setOptions({\n", + " 'title': 'amount of P per landcover class',\n", + " 'slices': colors,\n", + " 'sliceVisibilityThreshold': 0 # Don't group small slices.\n", + " })\n", + "\n", + "# Display the chart.\n", + "print(pChart)\n", + "\n", + "# Create the chart.\n", + "etChart = ui.Chart.feature.byFeature({\n", + " 'features': lcFc,\n", + " 'xProperty': 'class_name',\n", + " 'yProperties': ['et', 'class_number']\n", + " }) \\\n", + " .setChartType('PieChart') \\\n", + " .setOptions({\n", + " 'title': 'amount of ET per landcover class',\n", + " 'slices': colors,\n", + " 'sliceVisibilityThreshold': 0 # Don't group small slices.\n", + " })\n", + "\n", + "# Display the chart\n", + "print(etChart)\n", + "\n", + "# Create the panel for the legend items.\n", + "legend = ui.Panel({\n", + " 'style': {\n", + " 'position': 'bottom-left',\n", + " 'padding': '8px 15px'\n", + " }\n", + "})\n", + "\n", + "# Create and add the legend title.\n", + "legendTitle = ui.Label({\n", + " 'value': 'Legend',\n", + " 'style': {\n", + " 'fontWeight': 'bold',\n", + " 'fontSize': '18px',\n", + " 'margin': '0 0 4px 0',\n", + " 'padding': '0'\n", + " }\n", + "})\n", + "\n", + "# Creates and styles 1 row of the legend.\n", + "def makeRow(color, name):\n", + " # Create the label that is actually the colored box.\n", + " colorBox = ui.Label({\n", + " 'style': {\n", + " 'backgroundColor': '#' + color,\n", + " # Use padding to give the box height and width.\n", + " 'padding': '8px',\n", + " 'margin': '0 0 4px 0'\n", + " }\n", + " })\n", + "\n", + " # Create the label filled with the description text.\n", + " description = ui.Label({\n", + " 'value': name,\n", + " 'style': {\n", + " 'margin': '0 0 4px 6px'\n", + " }\n", + " })\n", + "\n", + " return ui.Panel({\n", + " 'widgets': [colorBox, description],\n", + " 'layout': ui.Panel.Layout.Flow('horizontal')\n", + " })\n", + "\n", + "\n", + "legend.add(legendTitle)\n", + "for i in range(0, classNamesList.length, 1):\n", + " legend.add(makeRow(paletteList[i], classNamesList[i]))\n", + "\n", + "\n", + "# Add the legend to the map.\n", + "Map.add(legend)\n", + "\n", + "# -----------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s2 - PET.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s2 - PET.js new file mode 100644 index 0000000..8dbf3fc --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s2 - PET.js @@ -0,0 +1,316 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.5 Water Balance and Drought +// Checkpoint: A25s2 +// Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Lower Mekong boundary. +var mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin'); + +Map.centerObject(mekongBasin, 6); + +var classStruct = { + 'unknown': { + number: 0, + color: '6f6f6f' + }, + 'surface water': { + number: 1, + color: 'aec3d4' + }, + 'snow and ice': { + number: 2, + color: 'b1f9ff' + }, + 'mangroves': { + number: 3, + color: '111149' + }, + 'flooded forest': { + number: 4, + color: '287463' + }, + 'Deciduous forest': { + number: 5, + color: '152106' + }, + 'Orchard or plantation forest': { + number: 6, + color: 'c3aa69' + }, + 'evergreen Broadleaf': { + number: 7, + color: '7db087' + }, + 'mixed forest': { + number: 8, + color: '387242' + }, + 'urban and built up': { + number: 9, + color: 'cc0013' + }, + 'cropland': { + number: 10, + color: '8dc33b' + }, + 'rice': { + number: 11, + color: 'ffff00' + }, + 'mining': { + number: 12, + color: 'cec2a5' + }, + 'barren': { + number: 13, + color: '674c06' + }, + 'wetlands': { + number: 14, + color: '3bc3b2' + }, + 'grassland': { + number: 15, + color: 'f4a460' + }, + 'shrubland': { + number: 16, + color: '800080' + }, + 'aquaculture': { + number: 17, + color: '51768e' + } +}; + +// Function to get a list of ids (keys) from a structure. +function getIds(struct) { + return Object.keys(struct); +} + +// Function to replace spaces with underscores in a list of strings. +function cleanList(list) { + return list.map(function(name) { + return name.replace(/\s+/g, '_'); + }); +} + +// Function to get a list of column values from a structure. +function getList(struct, column) { + return Object.keys(struct).map(function(k) { + var value = struct[k][column]; + return value; + }); +} + +var classNamesList = getIds(classStruct); +var probNames = cleanList(classNamesList); +var classNames = ee.List(classNamesList); +var classNumbers = getList(classStruct, 'number'); +var paletteList = getList(classStruct, 'color'); +var PALETTE = paletteList.join(','); + +// JSON dictionary that defines piechart colors based on the +// landcover class palette. +// https://developers.google.com/chart/interactive/docs/gallery/piechart +var colors = []; +for (var i = 0; i < paletteList.length; i++) { + colors.push({ + 'color': '_'.replace('_', paletteList[i]) + }); +} + +// Set start and end years. +var startYear = 2010; +var endYear = 2020; + +// Create two date objects for start and end years. +var startDate = ee.Date.fromYMD(startYear, 1, 1); +var endDate = ee.Date.fromYMD(endYear + 1, 1, 1); + +// Make a list with years. +var years = ee.List.sequence(startYear, endYear); + +// Make a list with months. +var months = ee.List.sequence(1, 12); + +// Import the MOD16 dataset. +var mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET'); + +// Filter for relevant time period. +mod16 = mod16.filterDate(startDate, endDate); + +// Import the CHIRPS dataset. +var CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Filter for relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate); + +var landcover = ee.Image( + 'projects/gee-book/assets/A2-5/RLCMSv3/Mekonglandcover2018') + .select('lc').clip(mekongBasin); + +var lcVis = { + palette: PALETTE, + min: 0, + max: classNamesList.length - 1 +}; +Map.addLayer(landcover, lcVis, '2018 Land Cover'); + +// We apply a nested loop where we first iterate over +// the relevant years and then iterate over the relevant +// months. The function returns an image with P - ET +// for each month. A flatten is applied to convert an +// collection of collections into a single collection. +var waterBalance = ee.ImageCollection.fromImages( + years.map(function(y) { + return months.map(function(m) { + + var P = CHIRPS.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum(); + + var ET = mod16.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum() + .multiply(0.1); + + var wb = P.subtract(ET).rename('wb'); + + return wb.addBands(P).addBands(ET).set( + 'year', y) + .set('month', m) + .set('system:time_start', ee.Date + .fromYMD(y, m, 1)); + }); + }).flatten() +); + +// Calculate mean monthly values. +var monthlyP = waterBalance.select('precipitation').mean(); +var monthlyET = waterBalance.select('ET').mean(); +var monthlyWB = waterBalance.select('wb').mean(); + +// Apply reducer per land cover category. +// We create binary map for each class and multiply by mean ET. +// The results are stored in a feature with other properties of the class. +// The function returns a feature which are stored in a feature collection. +var lcFc = ee.FeatureCollection(classNumbers.map(function(nr) { + var lc = landcover.eq(ee.Number(nr)); + + var P = monthlyP.multiply(lc); + var et = monthlyET.multiply(lc); + + var pSum = P.reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: mekongBasin, + scale: 500 + }).get('precipitation'); + + var etSum = et.reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: mekongBasin, + scale: 500 + }).get('ET'); + + return ee.Feature(null).set('et', etSum) + .set('p', pSum) + .set('class_name', classNames.get(nr)) + .set('palette', paletteList[nr]) + .set('class_number', nr); +})); + +// Create the chart. +var pChart = ui.Chart.feature.byFeature({ + features: lcFc, + xProperty: 'class_name', + yProperties: ['p', 'class_number'] + }) + .setChartType('PieChart') + .setOptions({ + title: 'amount of P per landcover class', + slices: colors, + sliceVisibilityThreshold: 0 // Don't group small slices. + }); + +// Display the chart. +print(pChart); + +// Create the chart. +var etChart = ui.Chart.feature.byFeature({ + features: lcFc, + xProperty: 'class_name', + yProperties: ['et', 'class_number'] + }) + .setChartType('PieChart') + .setOptions({ + title: 'amount of ET per landcover class', + slices: colors, + sliceVisibilityThreshold: 0 // Don't group small slices. + }); + +// Display the chart +print(etChart); + +// Create the panel for the legend items. +var legend = ui.Panel({ + style: { + position: 'bottom-left', + padding: '8px 15px' + } +}); + +// Create and add the legend title. +var legendTitle = ui.Label({ + value: 'Legend', + style: { + fontWeight: 'bold', + fontSize: '18px', + margin: '0 0 4px 0', + padding: '0' + } +}); + +// Creates and styles 1 row of the legend. +var makeRow = function(color, name) { + // Create the label that is actually the colored box. + var colorBox = ui.Label({ + style: { + backgroundColor: '#' + color, + // Use padding to give the box height and width. + padding: '8px', + margin: '0 0 4px 0' + } + }); + + // Create the label filled with the description text. + var description = ui.Label({ + value: name, + style: { + margin: '0 0 4px 6px' + } + }); + + return ui.Panel({ + widgets: [colorBox, description], + layout: ui.Panel.Layout.Flow('horizontal') + }); +}; + +legend.add(legendTitle); +for (var i = 0; i < classNamesList.length; i++) { + legend.add(makeRow(paletteList[i], classNamesList[i])); +} + +// Add the legend to the map. +Map.add(legend); + +// ----------------------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s2 - PET.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s2 - PET.py new file mode 100644 index 0000000..79d8b4e --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s2 - PET.py @@ -0,0 +1,386 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.5 Water Balance and Drought +# Checkpoint: A25s2 +# Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Lower Mekong boundary. +mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin') + +Map.centerObject(mekongBasin, 6) + +classStruct = { + 'unknown': { + 'number': 0, + 'color': '6f6f6f' + }, + 'surface water': { + 'number': 1, + 'color': 'aec3d4' + }, + 'snow and ice': { + 'number': 2, + 'color': 'b1f9ff' + }, + 'mangroves': { + 'number': 3, + 'color': '111149' + }, + 'flooded forest': { + 'number': 4, + 'color': '287463' + }, + 'Deciduous forest': { + 'number': 5, + 'color': '152106' + }, + 'Orchard or plantation forest': { + 'number': 6, + 'color': 'c3aa69' + }, + 'evergreen Broadleaf': { + 'number': 7, + 'color': '7db087' + }, + 'mixed forest': { + 'number': 8, + 'color': '387242' + }, + 'urban and built up': { + 'number': 9, + 'color': 'cc0013' + }, + 'cropland': { + 'number': 10, + 'color': '8dc33b' + }, + 'rice': { + 'number': 11, + 'color': 'ffff00' + }, + 'mining': { + 'number': 12, + 'color': 'cec2a5' + }, + 'barren': { + 'number': 13, + 'color': '674c06' + }, + 'wetlands': { + 'number': 14, + 'color': '3bc3b2' + }, + 'grassland': { + 'number': 15, + 'color': 'f4a460' + }, + 'shrubland': { + 'number': 16, + 'color': '800080' + }, + 'aquaculture': { + 'number': 17, + 'color': '51768e' + } +} + +# Function to get a list of ids (keys) from a structure. +def getIds(struct): + return Object.keys(struct) + + +# Function to replace spaces with underscores in a list of strings. +def cleanList(list): + +def func_ebb(name): + return name.replace(/\s+/g, '_') + + return list.map(func_ebb) + + + + + +# Function to get a list of column values from a structure. +def getList(struct, column): + +def func_ycx(k): + value = struct[k][column] + return value + + return Object.keys(struct).map(func_ycx) + + + + + + +classNamesList = getIds(classStruct) +probNames = cleanList(classNamesList) +classNames = ee.List(classNamesList) +classNumbers = getList(classStruct, 'number') +paletteList = getList(classStruct, 'color') +PALETTE = paletteList.join(',') + +# JSON dictionary that defines piechart colors based on the +# landcover class palette. +# https:#developers.google.com/chart/interactive/docs/gallery/piechart +colors = [] +for i in range(0, paletteList.length, 1): + colors.push({ + 'color': '_'.replace('_', paletteList[i]) + }) + + +# Set start and end years. +startYear = 2010 +endYear = 2020 + +# Create two date objects for start and end years. +startDate = ee.Date.fromYMD(startYear, 1, 1) +endDate = ee.Date.fromYMD(endYear + 1, 1, 1) + +# Make a list with years. +years = ee.List.sequence(startYear, endYear) + +# Make a list with months. +months = ee.List.sequence(1, 12) + +# Import the MOD16 dataset. +mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET') + +# Filter for relevant time period. +mod16 = mod16.filterDate(startDate, endDate) + +# Import the CHIRPS dataset. +CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') + +# Filter for relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate) + +landcover = ee.Image( + 'projects/gee-book/assets/A2-5/RLCMSv3/Mekonglandcover2018') \ + .select('lc').clip(mekongBasin) + +lcVis = { + 'palette': PALETTE, + 'min': 0, + 'max': classNamesList.length - 1 +} +Map.addLayer(landcover, lcVis, '2018 Land Cover') + +# We apply a nested loop where we first iterate over +# the relevant years and then iterate over the relevant +# months. The function returns an image with P - ET +# for each month. A flatten is applied to convert an +# collection of collections into a single collection. +waterBalance = ee.ImageCollection.fromImages( + +def func_cly(y): + return months.map(function(m) { + + P = CHIRPS.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() + + ET = mod16.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() \ + .multiply(0.1) + + wb = P.subtract(ET).rename('wb') + + return wb.addBands(P).addBands(ET).set( + 'year', y) \ + .set('month', m) \ + .set('system:time_start', ee.Date \ + .fromYMD(y, m, 1)) + }) + + years.map(func_cly +).flatten() + + + + + + + + + + + + + + + + + + + + + + + +).flatten() +) + +# Calculate mean monthly values. +monthlyP = waterBalance.select('precipitation').mean() +monthlyET = waterBalance.select('ET').mean() +monthlyWB = waterBalance.select('wb').mean() + +# Apply reducer per land cover category. +# We create binary map for each class and multiply by mean ET. +# The results are stored in a feature with other properties of the class. +# The function returns a feature which are stored in a feature collection. + +def func_vdu(nr): + lc = landcover.eq(ee.Number(nr)) + + P = monthlyP.multiply(lc) + et = monthlyET.multiply(lc) + + pSum = P.reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': mekongBasin, + 'scale': 500 + }).get('precipitation') + + etSum = et.reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': mekongBasin, + 'scale': 500 + }).get('ET') + + return ee.Feature(None).set('et', etSum) \ + .set('p', pSum) \ + .set('class_name', classNames.get(nr)) \ + .set('palette', paletteList[nr]) \ + .set('class_number', nr) + +lcFc = ee.FeatureCollection(classNumbers.map(func_vdu +)) + + + + + + + + + + + + + + + + + + + + + + +)) + +# Create the chart. +pChart = ui.Chart.feature.byFeature({ + 'features': lcFc, + 'xProperty': 'class_name', + 'yProperties': ['p', 'class_number'] + }) \ + .setChartType('PieChart') \ + .setOptions({ + 'title': 'amount of P per landcover class', + 'slices': colors, + 'sliceVisibilityThreshold': 0 # Don't group small slices. + }) + +# Display the chart. +print(pChart) + +# Create the chart. +etChart = ui.Chart.feature.byFeature({ + 'features': lcFc, + 'xProperty': 'class_name', + 'yProperties': ['et', 'class_number'] + }) \ + .setChartType('PieChart') \ + .setOptions({ + 'title': 'amount of ET per landcover class', + 'slices': colors, + 'sliceVisibilityThreshold': 0 # Don't group small slices. + }) + +# Display the chart +print(etChart) + +# Create the panel for the legend items. +legend = ui.Panel({ + 'style': { + 'position': 'bottom-left', + 'padding': '8px 15px' + } +}) + +# Create and add the legend title. +legendTitle = ui.Label({ + 'value': 'Legend', + 'style': { + 'fontWeight': 'bold', + 'fontSize': '18px', + 'margin': '0 0 4px 0', + 'padding': '0' + } +}) + +# Creates and styles 1 row of the legend. +def makeRow(color, name): + # Create the label that is actually the colored box. + colorBox = ui.Label({ + 'style': { + 'backgroundColor': '#' + color, + # Use padding to give the box height and width. + 'padding': '8px', + 'margin': '0 0 4px 0' + } + }) + + # Create the label filled with the description text. + description = ui.Label({ + 'value': name, + 'style': { + 'margin': '0 0 4px 6px' + } + }) + + return ui.Panel({ + 'widgets': [colorBox, description], + 'layout': ui.Panel.Layout.Flow('horizontal') + }) + + +legend.add(legendTitle) +for i in range(0, classNamesList.length, 1): + legend.add(makeRow(paletteList[i], classNamesList[i])) + + +# Add the legend to the map. +Map.add(legend) + +# ----------------------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s3 - Monthly.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s3 - Monthly.ipynb new file mode 100644 index 0000000..534c007 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s3 - Monthly.ipynb @@ -0,0 +1,480 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.5 Water Balance and Drought\n", + "# Checkpoint: A25s3\n", + "# Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andr\u00e9a Puzzi Nicolau\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Lower Mekong boundary.\n", + "mekongBasin = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-5/lowerMekongBasin')\n", + "\n", + "Map.centerObject(mekongBasin, 6)\n", + "\n", + "classStruct = {\n", + " 'unknown': {\n", + " 'number': 0,\n", + " 'color': '6f6f6f'\n", + " },\n", + " 'surface water': {\n", + " 'number': 1,\n", + " 'color': 'aec3d4'\n", + " },\n", + " 'snow and ice': {\n", + " 'number': 2,\n", + " 'color': 'b1f9ff'\n", + " },\n", + " 'mangroves': {\n", + " 'number': 3,\n", + " 'color': '111149'\n", + " },\n", + " 'flooded forest': {\n", + " 'number': 4,\n", + " 'color': '287463'\n", + " },\n", + " 'Deciduous forest': {\n", + " 'number': 5,\n", + " 'color': '152106'\n", + " },\n", + " 'Orchard or plantation forest': {\n", + " 'number': 6,\n", + " 'color': 'c3aa69'\n", + " },\n", + " 'evergreen Broadleaf': {\n", + " 'number': 7,\n", + " 'color': '7db087'\n", + " },\n", + " 'mixed forest': {\n", + " 'number': 8,\n", + " 'color': '387242'\n", + " },\n", + " 'urban and built up': {\n", + " 'number': 9,\n", + " 'color': 'cc0013'\n", + " },\n", + " 'cropland': {\n", + " 'number': 10,\n", + " 'color': '8dc33b'\n", + " },\n", + " 'rice': {\n", + " 'number': 11,\n", + " 'color': 'ffff00'\n", + " },\n", + " 'mining': {\n", + " 'number': 12,\n", + " 'color': 'cec2a5'\n", + " },\n", + " 'barren': {\n", + " 'number': 13,\n", + " 'color': '674c06'\n", + " },\n", + " 'wetlands': {\n", + " 'number': 14,\n", + " 'color': '3bc3b2'\n", + " },\n", + " 'grassland': {\n", + " 'number': 15,\n", + " 'color': 'f4a460'\n", + " },\n", + " 'shrubland': {\n", + " 'number': 16,\n", + " 'color': '800080'\n", + " },\n", + " 'aquaculture': {\n", + " 'number': 17,\n", + " 'color': '51768e'\n", + " }\n", + "}\n", + "\n", + "# Function to get a list of ids (keys) from a structure.\n", + "def getIds(struct):\n", + " return Object.keys(struct)\n", + "\n", + "\n", + "# Function to replace spaces with underscores in a list of strings.\n", + "def cleanList(list):\n", + "\n", + "def func_qat(name):\n", + " return name.replace(/\\s+/g, '_')\n", + "\n", + " return list.map(func_qat)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Function to get a list of column values from a structure.\n", + "def getList(struct, column):\n", + "\n", + "def func_iax(k):\n", + " value = struct[k][column]\n", + " return value\n", + "\n", + " return Object.keys(struct).map(func_iax)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "classNamesList = getIds(classStruct)\n", + "probNames = cleanList(classNamesList)\n", + "classNames = ee.List(classNamesList)\n", + "classNumbers = getList(classStruct, 'number')\n", + "paletteList = getList(classStruct, 'color')\n", + "PALETTE = paletteList.join(',')\n", + "\n", + "# JSON dictionary that defines piechart colors based on the\n", + "# landcover class palette.\n", + "# https:#developers.google.com/chart/interactive/docs/gallery/piechart\n", + "colors = []\n", + "for i in range(0, paletteList.length, 1):\n", + " colors.push({\n", + " 'color': '_'.replace('_', paletteList[i])\n", + " })\n", + "\n", + "\n", + "# Set start and end years.\n", + "startYear = 2010\n", + "endYear = 2020\n", + "\n", + "# Create two date objects for start and end years.\n", + "startDate = ee.Date.fromYMD(startYear, 1, 1)\n", + "endDate = ee.Date.fromYMD(endYear + 1, 1, 1)\n", + "\n", + "# Make a list with years.\n", + "years = ee.List.sequence(startYear, endYear)\n", + "\n", + "# Make a list with months.\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Import the MOD16 dataset.\n", + "mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET')\n", + "\n", + "# Filter for relevant time period.\n", + "mod16 = mod16.filterDate(startDate, endDate)\n", + "\n", + "# Import the CHIRPS dataset.\n", + "CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "\n", + "# Filter for relevant time period.\n", + "CHIRPS = CHIRPS.filterDate(startDate, endDate)\n", + "\n", + "landcover = ee.Image(\n", + " 'projects/gee-book/assets/A2-5/RLCMSv3/Mekonglandcover2018') \\\n", + " .select('lc').clip(mekongBasin)\n", + "\n", + "lcVis = {\n", + " 'palette': PALETTE,\n", + " 'min': 0,\n", + " 'max': classNamesList.length - 1\n", + "}\n", + "Map.addLayer(landcover, lcVis, '2018 Land Cover')\n", + "\n", + "# We apply a nested loop where we first iterate over\n", + "# the relevant years and then iterate over the relevant\n", + "# months. The function returns an image with P - ET\n", + "# for each month. A flatten is applied to convert an\n", + "# collection of collections into a single collection.\n", + "waterBalance = ee.ImageCollection.fromImages(\n", + "\n", + "def func_pqv(y):\n", + " return months.map(function(m) {\n", + "\n", + " P = CHIRPS.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum()\n", + "\n", + " ET = mod16.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum() \\\n", + " .multiply(0.1)\n", + "\n", + " wb = P.subtract(ET).rename('wb')\n", + "\n", + " return wb.addBands(P).addBands(ET).set(\n", + " 'year', y) \\\n", + " .set('month', m) \\\n", + " .set('system:time_start', ee.Date \\\n", + " .fromYMD(y, m, 1))\n", + " })\n", + "\n", + " years.map(func_pqv\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + ")\n", + "\n", + "\n", + "def func_ygw(m):\n", + " wbM = waterBalance.filter(ee.Filter.eq('month',\n", + " m)) \\\n", + " .mean() \\\n", + " .select('wb')\n", + " return ee.Image(wbM).set('month', m)\n", + "\n", + "wbMonth = ee.ImageCollection(months.map(func_ygw\n", + "))\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "))\n", + "\n", + "# We convert the image collection to an image.\n", + "wbMonth = wbMonth.toBands() \\\n", + " .select(['0_wb', '1_wb', '2_wb',\n", + " '3_wb', '4_wb', '5_wb',\n", + " '6_wb', '7_wb', '8_wb',\n", + " '9_wb', '10_wb', '11_wb'\n", + " ],\n", + " ['01_wb', '02_wb', '03_wb',\n", + " '04_wb', '05_wb', '06_wb',\n", + " '07_wb', '08_wb', '09_wb',\n", + " '10_wb', '11_wb', '12_wb'\n", + " ])\n", + "\n", + "# Select our classes of interest.\n", + "classNumbers = ee.List([5, 7, 10, 11])\n", + "\n", + "# Apply reducer per land cover category.\n", + "# We create binary map for each class and multiply by the monthly water balance.\n", + "# The results are stored in a feature with other properties of the class.\n", + "# The function returns a feature which are stored in a feature collection.\n", + "\n", + "def func_twh(nr):\n", + " lc = landcover.eq(ee.Number(nr))\n", + " wbM = wbMonth.multiply(lc)\n", + " wbSum = wbM.reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': mekongBasin,\n", + " 'scale': 1000\n", + " })\n", + " return ee.Feature(None).set(wbSum) \\\n", + " .set('label', classNames.get(nr)) \\\n", + " .set('palette', paletteList[nr]) \\\n", + " .set('class_number', nr)\n", + "\n", + "lcFc = ee.FeatureCollection(classNumbers.map(func_twh\n", + "))\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "))\n", + "\n", + "chart = ui.Chart.feature.byFeature({\n", + " 'features': lcFc.select('[0-9][0-9]_wb|label'),\n", + " 'xProperty': 'label',\n", + " }) \\\n", + " .setSeriesNames(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n", + " 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'\n", + " ]) \\\n", + " .setChartType('ColumnChart') \\\n", + " .setOptions({\n", + " 'title': 'water balance',\n", + " 'hAxis': {\n", + " 'title': 'landcover type',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Water balance (mm)',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'colors': ['604791', '1d6b99', '39a8a7', '0f8755', '76b349',\n", + " 'f0af07',\n", + " 'e37d05', 'cf513e', '96356f', '724173', '9c4f97',\n", + " '696969'\n", + " ]\n", + " })\n", + "\n", + "print(chart)\n", + "\n", + "# Create the panel for the legend items.\n", + "legend = ui.Panel({\n", + " 'style': {\n", + " 'position': 'bottom-left',\n", + " 'padding': '8px 15px'\n", + " }\n", + "})\n", + "\n", + "# Create and add the legend title.\n", + "legendTitle = ui.Label({\n", + " 'value': 'Legend',\n", + " 'style': {\n", + " 'fontWeight': 'bold',\n", + " 'fontSize': '18px',\n", + " 'margin': '0 0 4px 0',\n", + " 'padding': '0'\n", + " }\n", + "})\n", + "\n", + "# Creates and styles 1 row of the legend.\n", + "def makeRow(color, name):\n", + " # Create the label that is actually the colored box.\n", + " colorBox = ui.Label({\n", + " 'style': {\n", + " 'backgroundColor': '#' + color,\n", + " # Use padding to give the box height and width.\n", + " 'padding': '8px',\n", + " 'margin': '0 0 4px 0'\n", + " }\n", + " })\n", + "\n", + " # Create the label filled with the description text.\n", + " description = ui.Label({\n", + " 'value': name,\n", + " 'style': {\n", + " 'margin': '0 0 4px 6px'\n", + " }\n", + " })\n", + "\n", + " return ui.Panel({\n", + " 'widgets': [colorBox, description],\n", + " 'layout': ui.Panel.Layout.Flow('horizontal')\n", + " })\n", + "\n", + "\n", + "legend.add(legendTitle)\n", + "for i in range(0, classNamesList.length, 1):\n", + " legend.add(makeRow(paletteList[i], classNamesList[i]))\n", + "\n", + "\n", + "# Add the legend to the map.\n", + "Map.add(legend)\n", + "\n", + "# -----------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s3 - Monthly.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s3 - Monthly.js new file mode 100644 index 0000000..85e526a --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s3 - Monthly.js @@ -0,0 +1,325 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.5 Water Balance and Drought +// Checkpoint: A25s3 +// Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Lower Mekong boundary. +var mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin'); + +Map.centerObject(mekongBasin, 6); + +var classStruct = { + 'unknown': { + number: 0, + color: '6f6f6f' + }, + 'surface water': { + number: 1, + color: 'aec3d4' + }, + 'snow and ice': { + number: 2, + color: 'b1f9ff' + }, + 'mangroves': { + number: 3, + color: '111149' + }, + 'flooded forest': { + number: 4, + color: '287463' + }, + 'Deciduous forest': { + number: 5, + color: '152106' + }, + 'Orchard or plantation forest': { + number: 6, + color: 'c3aa69' + }, + 'evergreen Broadleaf': { + number: 7, + color: '7db087' + }, + 'mixed forest': { + number: 8, + color: '387242' + }, + 'urban and built up': { + number: 9, + color: 'cc0013' + }, + 'cropland': { + number: 10, + color: '8dc33b' + }, + 'rice': { + number: 11, + color: 'ffff00' + }, + 'mining': { + number: 12, + color: 'cec2a5' + }, + 'barren': { + number: 13, + color: '674c06' + }, + 'wetlands': { + number: 14, + color: '3bc3b2' + }, + 'grassland': { + number: 15, + color: 'f4a460' + }, + 'shrubland': { + number: 16, + color: '800080' + }, + 'aquaculture': { + number: 17, + color: '51768e' + } +}; + +// Function to get a list of ids (keys) from a structure. +function getIds(struct) { + return Object.keys(struct); +} + +// Function to replace spaces with underscores in a list of strings. +function cleanList(list) { + return list.map(function(name) { + return name.replace(/\s+/g, '_'); + }); +} + +// Function to get a list of column values from a structure. +function getList(struct, column) { + return Object.keys(struct).map(function(k) { + var value = struct[k][column]; + return value; + }); +} + +var classNamesList = getIds(classStruct); +var probNames = cleanList(classNamesList); +var classNames = ee.List(classNamesList); +var classNumbers = getList(classStruct, 'number'); +var paletteList = getList(classStruct, 'color'); +var PALETTE = paletteList.join(','); + +// JSON dictionary that defines piechart colors based on the +// landcover class palette. +// https://developers.google.com/chart/interactive/docs/gallery/piechart +var colors = []; +for (var i = 0; i < paletteList.length; i++) { + colors.push({ + 'color': '_'.replace('_', paletteList[i]) + }); +} + +// Set start and end years. +var startYear = 2010; +var endYear = 2020; + +// Create two date objects for start and end years. +var startDate = ee.Date.fromYMD(startYear, 1, 1); +var endDate = ee.Date.fromYMD(endYear + 1, 1, 1); + +// Make a list with years. +var years = ee.List.sequence(startYear, endYear); + +// Make a list with months. +var months = ee.List.sequence(1, 12); + +// Import the MOD16 dataset. +var mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET'); + +// Filter for relevant time period. +mod16 = mod16.filterDate(startDate, endDate); + +// Import the CHIRPS dataset. +var CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Filter for relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate); + +var landcover = ee.Image( + 'projects/gee-book/assets/A2-5/RLCMSv3/Mekonglandcover2018') + .select('lc').clip(mekongBasin); + +var lcVis = { + palette: PALETTE, + min: 0, + max: classNamesList.length - 1 +}; +Map.addLayer(landcover, lcVis, '2018 Land Cover'); + +// We apply a nested loop where we first iterate over +// the relevant years and then iterate over the relevant +// months. The function returns an image with P - ET +// for each month. A flatten is applied to convert an +// collection of collections into a single collection. +var waterBalance = ee.ImageCollection.fromImages( + years.map(function(y) { + return months.map(function(m) { + + var P = CHIRPS.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum(); + + var ET = mod16.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum() + .multiply(0.1); + + var wb = P.subtract(ET).rename('wb'); + + return wb.addBands(P).addBands(ET).set( + 'year', y) + .set('month', m) + .set('system:time_start', ee.Date + .fromYMD(y, m, 1)); + }); + }).flatten() +); + +var wbMonth = ee.ImageCollection(months.map(function(m) { + var wbM = waterBalance.filter(ee.Filter.eq('month', + m)) + .mean() + .select('wb'); + return ee.Image(wbM).set('month', m); +})); + +// We convert the image collection to an image. +var wbMonth = wbMonth.toBands() + .select(['0_wb', '1_wb', '2_wb', + '3_wb', '4_wb', '5_wb', + '6_wb', '7_wb', '8_wb', + '9_wb', '10_wb', '11_wb' + ], + ['01_wb', '02_wb', '03_wb', + '04_wb', '05_wb', '06_wb', + '07_wb', '08_wb', '09_wb', + '10_wb', '11_wb', '12_wb' + ]); + +// Select our classes of interest. +var classNumbers = ee.List([5, 7, 10, 11]); + +// Apply reducer per land cover category. +// We create binary map for each class and multiply by the monthly water balance. +// The results are stored in a feature with other properties of the class. +// The function returns a feature which are stored in a feature collection. +var lcFc = ee.FeatureCollection(classNumbers.map(function(nr) { + var lc = landcover.eq(ee.Number(nr)); + var wbM = wbMonth.multiply(lc); + var wbSum = wbM.reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: mekongBasin, + scale: 1000 + }); + return ee.Feature(null).set(wbSum) + .set('label', classNames.get(nr)) + .set('palette', paletteList[nr]) + .set('class_number', nr); +})); + +var chart = ui.Chart.feature.byFeature({ + features: lcFc.select('[0-9][0-9]_wb|label'), + xProperty: 'label', + }) + .setSeriesNames(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' + ]) + .setChartType('ColumnChart') + .setOptions({ + title: 'water balance', + hAxis: { + title: 'landcover type', + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Water balance (mm)', + titleTextStyle: { + italic: false, + bold: true + } + }, + colors: ['604791', '1d6b99', '39a8a7', '0f8755', '76b349', + 'f0af07', + 'e37d05', 'cf513e', '96356f', '724173', '9c4f97', + '696969' + ] + }); + +print(chart); + +// Create the panel for the legend items. +var legend = ui.Panel({ + style: { + position: 'bottom-left', + padding: '8px 15px' + } +}); + +// Create and add the legend title. +var legendTitle = ui.Label({ + value: 'Legend', + style: { + fontWeight: 'bold', + fontSize: '18px', + margin: '0 0 4px 0', + padding: '0' + } +}); + +// Creates and styles 1 row of the legend. +var makeRow = function(color, name) { + // Create the label that is actually the colored box. + var colorBox = ui.Label({ + style: { + backgroundColor: '#' + color, + // Use padding to give the box height and width. + padding: '8px', + margin: '0 0 4px 0' + } + }); + + // Create the label filled with the description text. + var description = ui.Label({ + value: name, + style: { + margin: '0 0 4px 6px' + } + }); + + return ui.Panel({ + widgets: [colorBox, description], + layout: ui.Panel.Layout.Flow('horizontal') + }); +}; + +legend.add(legendTitle); +for (var i = 0; i < classNamesList.length; i++) { + legend.add(makeRow(paletteList[i], classNamesList[i])); +} + +// Add the legend to the map. +Map.add(legend); + +// ----------------------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s3 - Monthly.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s3 - Monthly.py new file mode 100644 index 0000000..608f019 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s3 - Monthly.py @@ -0,0 +1,393 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.5 Water Balance and Drought +# Checkpoint: A25s3 +# Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Lower Mekong boundary. +mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin') + +Map.centerObject(mekongBasin, 6) + +classStruct = { + 'unknown': { + 'number': 0, + 'color': '6f6f6f' + }, + 'surface water': { + 'number': 1, + 'color': 'aec3d4' + }, + 'snow and ice': { + 'number': 2, + 'color': 'b1f9ff' + }, + 'mangroves': { + 'number': 3, + 'color': '111149' + }, + 'flooded forest': { + 'number': 4, + 'color': '287463' + }, + 'Deciduous forest': { + 'number': 5, + 'color': '152106' + }, + 'Orchard or plantation forest': { + 'number': 6, + 'color': 'c3aa69' + }, + 'evergreen Broadleaf': { + 'number': 7, + 'color': '7db087' + }, + 'mixed forest': { + 'number': 8, + 'color': '387242' + }, + 'urban and built up': { + 'number': 9, + 'color': 'cc0013' + }, + 'cropland': { + 'number': 10, + 'color': '8dc33b' + }, + 'rice': { + 'number': 11, + 'color': 'ffff00' + }, + 'mining': { + 'number': 12, + 'color': 'cec2a5' + }, + 'barren': { + 'number': 13, + 'color': '674c06' + }, + 'wetlands': { + 'number': 14, + 'color': '3bc3b2' + }, + 'grassland': { + 'number': 15, + 'color': 'f4a460' + }, + 'shrubland': { + 'number': 16, + 'color': '800080' + }, + 'aquaculture': { + 'number': 17, + 'color': '51768e' + } +} + +# Function to get a list of ids (keys) from a structure. +def getIds(struct): + return Object.keys(struct) + + +# Function to replace spaces with underscores in a list of strings. +def cleanList(list): + +def func_qat(name): + return name.replace(/\s+/g, '_') + + return list.map(func_qat) + + + + + +# Function to get a list of column values from a structure. +def getList(struct, column): + +def func_iax(k): + value = struct[k][column] + return value + + return Object.keys(struct).map(func_iax) + + + + + + +classNamesList = getIds(classStruct) +probNames = cleanList(classNamesList) +classNames = ee.List(classNamesList) +classNumbers = getList(classStruct, 'number') +paletteList = getList(classStruct, 'color') +PALETTE = paletteList.join(',') + +# JSON dictionary that defines piechart colors based on the +# landcover class palette. +# https:#developers.google.com/chart/interactive/docs/gallery/piechart +colors = [] +for i in range(0, paletteList.length, 1): + colors.push({ + 'color': '_'.replace('_', paletteList[i]) + }) + + +# Set start and end years. +startYear = 2010 +endYear = 2020 + +# Create two date objects for start and end years. +startDate = ee.Date.fromYMD(startYear, 1, 1) +endDate = ee.Date.fromYMD(endYear + 1, 1, 1) + +# Make a list with years. +years = ee.List.sequence(startYear, endYear) + +# Make a list with months. +months = ee.List.sequence(1, 12) + +# Import the MOD16 dataset. +mod16 = ee.ImageCollection('MODIS/006/MOD16A2').select('ET') + +# Filter for relevant time period. +mod16 = mod16.filterDate(startDate, endDate) + +# Import the CHIRPS dataset. +CHIRPS = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') + +# Filter for relevant time period. +CHIRPS = CHIRPS.filterDate(startDate, endDate) + +landcover = ee.Image( + 'projects/gee-book/assets/A2-5/RLCMSv3/Mekonglandcover2018') \ + .select('lc').clip(mekongBasin) + +lcVis = { + 'palette': PALETTE, + 'min': 0, + 'max': classNamesList.length - 1 +} +Map.addLayer(landcover, lcVis, '2018 Land Cover') + +# We apply a nested loop where we first iterate over +# the relevant years and then iterate over the relevant +# months. The function returns an image with P - ET +# for each month. A flatten is applied to convert an +# collection of collections into a single collection. +waterBalance = ee.ImageCollection.fromImages( + +def func_pqv(y): + return months.map(function(m) { + + P = CHIRPS.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() + + ET = mod16.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum() \ + .multiply(0.1) + + wb = P.subtract(ET).rename('wb') + + return wb.addBands(P).addBands(ET).set( + 'year', y) \ + .set('month', m) \ + .set('system:time_start', ee.Date \ + .fromYMD(y, m, 1)) + }) + + years.map(func_pqv +).flatten() + + + + + + + + + + + + + + + + + + + + + + + +).flatten() +) + + +def func_ygw(m): + wbM = waterBalance.filter(ee.Filter.eq('month', + m)) \ + .mean() \ + .select('wb') + return ee.Image(wbM).set('month', m) + +wbMonth = ee.ImageCollection(months.map(func_ygw +)) + + + + + +)) + +# We convert the image collection to an image. +wbMonth = wbMonth.toBands() \ + .select(['0_wb', '1_wb', '2_wb', + '3_wb', '4_wb', '5_wb', + '6_wb', '7_wb', '8_wb', + '9_wb', '10_wb', '11_wb' + ], + ['01_wb', '02_wb', '03_wb', + '04_wb', '05_wb', '06_wb', + '07_wb', '08_wb', '09_wb', + '10_wb', '11_wb', '12_wb' + ]) + +# Select our classes of interest. +classNumbers = ee.List([5, 7, 10, 11]) + +# Apply reducer per land cover category. +# We create binary map for each class and multiply by the monthly water balance. +# The results are stored in a feature with other properties of the class. +# The function returns a feature which are stored in a feature collection. + +def func_twh(nr): + lc = landcover.eq(ee.Number(nr)) + wbM = wbMonth.multiply(lc) + wbSum = wbM.reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': mekongBasin, + 'scale': 1000 + }) + return ee.Feature(None).set(wbSum) \ + .set('label', classNames.get(nr)) \ + .set('palette', paletteList[nr]) \ + .set('class_number', nr) + +lcFc = ee.FeatureCollection(classNumbers.map(func_twh +)) + + + + + + + + + + + +)) + +chart = ui.Chart.feature.byFeature({ + 'features': lcFc.select('[0-9][0-9]_wb|label'), + 'xProperty': 'label', + }) \ + .setSeriesNames(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' + ]) \ + .setChartType('ColumnChart') \ + .setOptions({ + 'title': 'water balance', + 'hAxis': { + 'title': 'landcover type', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Water balance (mm)', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'colors': ['604791', '1d6b99', '39a8a7', '0f8755', '76b349', + 'f0af07', + 'e37d05', 'cf513e', '96356f', '724173', '9c4f97', + '696969' + ] + }) + +print(chart) + +# Create the panel for the legend items. +legend = ui.Panel({ + 'style': { + 'position': 'bottom-left', + 'padding': '8px 15px' + } +}) + +# Create and add the legend title. +legendTitle = ui.Label({ + 'value': 'Legend', + 'style': { + 'fontWeight': 'bold', + 'fontSize': '18px', + 'margin': '0 0 4px 0', + 'padding': '0' + } +}) + +# Creates and styles 1 row of the legend. +def makeRow(color, name): + # Create the label that is actually the colored box. + colorBox = ui.Label({ + 'style': { + 'backgroundColor': '#' + color, + # Use padding to give the box height and width. + 'padding': '8px', + 'margin': '0 0 4px 0' + } + }) + + # Create the label filled with the description text. + description = ui.Label({ + 'value': name, + 'style': { + 'margin': '0 0 4px 6px' + } + }) + + return ui.Panel({ + 'widgets': [colorBox, description], + 'layout': ui.Panel.Layout.Flow('horizontal') + }) + + +legend.add(legendTitle) +for i in range(0, classNamesList.length, 1): + legend.add(makeRow(paletteList[i], classNamesList[i])) + + +# Add the legend to the map. +Map.add(legend) + +# ----------------------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s4 - Per Class Balance.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s4 - Per Class Balance.ipynb new file mode 100644 index 0000000..c19b985 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s4 - Per Class Balance.ipynb @@ -0,0 +1,612 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.5 Water Balance and Drought\n", + "# Checkpoint: A25s4\n", + "# Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andr\u00e9a Puzzi Nicolau\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Lower Mekong boundary.\n", + "mekongBasin = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A2-5/lowerMekongBasin')\n", + "\n", + "Map.centerObject(mekongBasin, 6)\n", + "\n", + "classStruct = {\n", + " 'unknown': {\n", + " 'number': 0,\n", + " 'color': '6f6f6f'\n", + " },\n", + " 'surface water': {\n", + " 'number': 1,\n", + " 'color': 'aec3d4'\n", + " },\n", + " 'snow and ice': {\n", + " 'number': 2,\n", + " 'color': 'b1f9ff'\n", + " },\n", + " 'mangroves': {\n", + " 'number': 3,\n", + " 'color': '111149'\n", + " },\n", + " 'flooded forest': {\n", + " 'number': 4,\n", + " 'color': '287463'\n", + " },\n", + " 'Deciduous forest': {\n", + " 'number': 5,\n", + " 'color': '152106'\n", + " },\n", + " 'Orchard or plantation forest': {\n", + " 'number': 6,\n", + " 'color': 'c3aa69'\n", + " },\n", + " 'evergreen Broadleaf': {\n", + " 'number': 7,\n", + " 'color': '7db087'\n", + " },\n", + " 'mixed forest': {\n", + " 'number': 8,\n", + " 'color': '387242'\n", + " },\n", + " 'urban and built up': {\n", + " 'number': 9,\n", + " 'color': 'cc0013'\n", + " },\n", + " 'cropland': {\n", + " 'number': 10,\n", + " 'color': '8dc33b'\n", + " },\n", + " 'rice': {\n", + " 'number': 11,\n", + " 'color': 'ffff00'\n", + " },\n", + " 'mining': {\n", + " 'number': 12,\n", + " 'color': 'cec2a5'\n", + " },\n", + " 'barren': {\n", + " 'number': 13,\n", + " 'color': '674c06'\n", + " },\n", + " 'wetlands': {\n", + " 'number': 14,\n", + " 'color': '3bc3b2'\n", + " },\n", + " 'grassland': {\n", + " 'number': 15,\n", + " 'color': 'f4a460'\n", + " },\n", + " 'shrubland': {\n", + " 'number': 16,\n", + " 'color': '800080'\n", + " },\n", + " 'aquaculture': {\n", + " 'number': 17,\n", + " 'color': '51768e'\n", + " }\n", + "}\n", + "\n", + "# Function to get a list of ids (keys) from a structure.\n", + "def getIds(struct):\n", + " return Object.keys(struct)\n", + "\n", + "\n", + "# Function to replace spaces with underscores in a list of strings.\n", + "def cleanList(list):\n", + "\n", + "def func_nzj(name):\n", + " return name.replace(/\\s+/g, '_')\n", + "\n", + " return list.map(func_nzj)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Function to get a list of column values from a structure.\n", + "def getList(struct, column):\n", + "\n", + "def func_dkz(k):\n", + " value = struct[k][column]\n", + " return value\n", + "\n", + " return Object.keys(struct).map(func_dkz)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "classNamesList = getIds(classStruct)\n", + "probNames = cleanList(classNamesList)\n", + "classNames = ee.List(classNamesList)\n", + "classNumbers = getList(classStruct, 'number')\n", + "paletteList = getList(classStruct, 'color')\n", + "PALETTE = paletteList.join(',')\n", + "\n", + "# JSON dictionary that defines piechart colors based on the\n", + "# landcover class palette.\n", + "# https:#developers.google.com/chart/interactive/docs/gallery/piechart\n", + "colors = []\n", + "for i in range(0, paletteList.length, 1):\n", + " colors.push({\n", + " 'color': '_'.replace('_', paletteList[i])\n", + " })\n", + "\n", + "\n", + "# Set start and end years.\n", + "startYear = 2010\n", + "endYear = 2020\n", + "\n", + "# Create two date objects for start and end years.\n", + "startDate = ee.Date.fromYMD(startYear, 1, 1)\n", + "endDate = ee.Date.fromYMD(endYear + 1, 1, 1)\n", + "\n", + "# Make a list with years.\n", + "years = ee.List.sequence(startYear, endYear)\n", + "\n", + "# Make a list with months.\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Import and filter the MOD13 dataset.\n", + "mod13 = ee.ImageCollection('MODIS/006/MOD13A1')\n", + "mod13 = mod13.filterDate(startDate, endDate)\n", + "\n", + "# Select the EVI.\n", + "EVI = mod13.select('EVI')\n", + "\n", + "# Import and filter the MODIS Terra surface reflectance dataset.\n", + "mod09 = ee.ImageCollection('MODIS/006/MOD09A1')\n", + "mod09 = mod09.filterDate(startDate, endDate)\n", + "\n", + "landcover = ee.Image(\n", + " 'projects/gee-book/assets/A2-5/RLCMSv3/Mekonglandcover2018') \\\n", + " .select('lc').clip(mekongBasin)\n", + "\n", + "lcVis = {\n", + " 'palette': PALETTE,\n", + " 'min': 0,\n", + " 'max': classNamesList.length - 1\n", + "}\n", + "Map.addLayer(landcover, lcVis, '2018 Land Cover')\n", + "\n", + "# We use a function to remove clouds and cloud shadows.\n", + "# We map over the mod09 image collection and select the StateQA band.\n", + "# We mask pixels and return the image with clouds and cloud shadows masked.\n", + "\n", + "def func_hao(image):\n", + " quality = image.select('StateQA')\n", + " mask = image.And(quality.bitwiseAnd(1).eq(\n", + " 0)) # No clouds. \\\n", + " .And(quality.bitwiseAnd(2).eq(0)); \n", + "\n", + " return image.updateMask(mask)\n", + "\n", + "mod09 = mod09.map(func_hao)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# We use a function to calculate the Moisture Stress Index.\n", + "# We map over the mod09 image collection and select the NIR and SWIR bands\n", + "# We set the timestamp and return the MSI.\n", + "\n", + "def func_lru(image):\n", + " nirband = image.select('sur_refl_b02')\n", + " swirband = image.select('sur_refl_b06')\n", + " msi = swirband.divide(nirband) \\\n", + " .rename('MSI') \\\n", + " .set('system:time_start', image.get(\n", + " 'system:time_start'))\n", + " return msi\n", + "\n", + "MSI = mod09.map(func_lru)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# We apply a nested loop where we first iterate over\n", + "# the relevant years and then iterate over the relevant\n", + "# months. The function returns an image with the MSI and EVI\n", + "# for each month. A flatten is applied to convert an\n", + "# collection of collections into a single collection.\n", + "monthlyIndices = ee.ImageCollection.fromImages(\n", + "\n", + "def func_wsp(y):\n", + " return months.map(function(m) {\n", + "\n", + " # Calculate EVI.\n", + " evi = EVI.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .mean() \\\n", + " .multiply(0.0001)\n", + "\n", + " # Calculate MSI.\n", + " msi = MSI.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .mean()\n", + "\n", + " # Return an image with all images as bands.\n", + " return evi.addBands(msi) \\\n", + " .set('year', y) \\\n", + " .set('month', m) \\\n", + " .set('system:time_start', ee.Date \\\n", + " .fromYMD(y, m, 1))\n", + "\n", + " })\n", + "\n", + " years.map(func_wsp\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + ")\n", + "\n", + "# We select the landcover types for evergreen, deciduous forest, cropland and rice.\n", + "evergreenForest = landcover.eq(7)\n", + "deciduousForest = landcover.eq(5)\n", + "cropland = landcover.eq(10)\n", + "rice = landcover.eq(11)\n", + "\n", + "# Mask pixels that do not belong to the category.\n", + "\n", + "def func_yqe(img):\n", + " return img.updateMask(evergreenForest)\n", + "\n", + "evergreenIndex = monthlyIndices.map(func_yqe)\n", + "\n", + "\n", + "\n", + "\n", + "# Mask pixels that do not belong to the category.\n", + "\n", + "def func_cip(img):\n", + " return img.updateMask(deciduousForest)\n", + "\n", + "deciduousIndex = monthlyIndices.map(func_cip)\n", + "\n", + "\n", + "\n", + "\n", + "# Mask pixels that do not belong to the category.\n", + "\n", + "def func_vrq(img):\n", + " return img.updateMask(cropland)\n", + "\n", + "croplandIndex = monthlyIndices.map(func_vrq)\n", + "\n", + "\n", + "\n", + "\n", + "# Mask pixels that do not belong to the category.\n", + "\n", + "def func_jit(img):\n", + " return img.updateMask(rice)\n", + "\n", + "riceIndex = monthlyIndices.map(func_jit)\n", + "\n", + "\n", + "\n", + "\n", + "# Define the chart and print it to the console.\n", + "chartIndices =\n", + " ui.Chart.image.series({\n", + " 'imageCollection': deciduousIndex.select(['EVI', 'MSI']),\n", + " 'region': mekongBasin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000,\n", + " 'xProperty': 'system:time_start'\n", + " }) \\\n", + " .setSeriesNames(['EVI', 'MSI']) \\\n", + " .setOptions({\n", + " 'title': 'Monthly deciduous forest indices',\n", + " 'hAxis': {\n", + " 'title': 'Date',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Index',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'colors': ['darkgreen', 'brown'],\n", + " 'curveType': 'function'\n", + " })\n", + "\n", + "# Print the chart.\n", + "print(chartIndices)\n", + "\n", + "# Define the chart and print it to the console.\n", + "chartIndices =\n", + " ui.Chart.image.series({\n", + " 'imageCollection': evergreenIndex.select(['EVI', 'MSI']),\n", + " 'region': mekongBasin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000,\n", + " 'xProperty': 'system:time_start'\n", + " }) \\\n", + " .setSeriesNames(['EVI', 'MSI']) \\\n", + " .setOptions({\n", + " 'title': 'Monthly deciduous forest indices',\n", + " 'hAxis': {\n", + " 'title': 'Date',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Index',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'colors': ['darkgreen', 'brown'],\n", + " 'curveType': 'function'\n", + " })\n", + "\n", + "# Print the chart.\n", + "print(chartIndices)\n", + "\n", + "# Define the chart and print it to the console.\n", + "chartIndices =\n", + " ui.Chart.image.series({\n", + " 'imageCollection': croplandIndex.select(['EVI', 'MSI']),\n", + " 'region': mekongBasin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000,\n", + " 'xProperty': 'system:time_start'\n", + " }) \\\n", + " .setSeriesNames(['EVI', 'MSI']) \\\n", + " .setOptions({\n", + " 'title': 'Monthly cropland indices',\n", + " 'hAxis': {\n", + " 'title': 'Date',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Index',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'colors': ['darkgreen', 'brown'],\n", + " 'curveType': 'function'\n", + " })\n", + "\n", + "# Print the chart.\n", + "print(chartIndices)\n", + "\n", + "# Define the chart and print it to the console.\n", + "chartIndices =\n", + " ui.Chart.image.series({\n", + " 'imageCollection': riceIndex.select(['EVI', 'MSI']),\n", + " 'region': mekongBasin,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 1000,\n", + " 'xProperty': 'system:time_start'\n", + " }) \\\n", + " .setSeriesNames(['EVI', 'MSI']) \\\n", + " .setOptions({\n", + " 'title': 'Monthly rice indices',\n", + " 'hAxis': {\n", + " 'title': 'Date',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Index',\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'colors': ['darkgreen', 'brown'],\n", + " 'curveType': 'function'\n", + " })\n", + "\n", + "# Print the chart.\n", + "print(chartIndices)\n", + "\n", + "# Create the panel for the legend items.\n", + "legend = ui.Panel({\n", + " 'style': {\n", + " 'position': 'bottom-left',\n", + " 'padding': '8px 15px'\n", + " }\n", + "})\n", + "\n", + "# Create and add the legend title.\n", + "legendTitle = ui.Label({\n", + " 'value': 'Legend',\n", + " 'style': {\n", + " 'fontWeight': 'bold',\n", + " 'fontSize': '18px',\n", + " 'margin': '0 0 4px 0',\n", + " 'padding': '0'\n", + " }\n", + "})\n", + "\n", + "# Creates and styles 1 row of the legend.\n", + "def makeRow(color, name):\n", + " # Create the label that is actually the colored box.\n", + " colorBox = ui.Label({\n", + " 'style': {\n", + " 'backgroundColor': '#' + color,\n", + " # Use padding to give the box height and width.\n", + " 'padding': '8px',\n", + " 'margin': '0 0 4px 0'\n", + " }\n", + " })\n", + "\n", + " # Create the label filled with the description text.\n", + " description = ui.Label({\n", + " 'value': name,\n", + " 'style': {\n", + " 'margin': '0 0 4px 6px'\n", + " }\n", + " })\n", + "\n", + " return ui.Panel({\n", + " 'widgets': [colorBox, description],\n", + " 'layout': ui.Panel.Layout.Flow('horizontal')\n", + " })\n", + "\n", + "\n", + "legend.add(legendTitle)\n", + "for i in range(0, classNamesList.length, 1):\n", + " legend.add(makeRow(paletteList[i], classNamesList[i]))\n", + "\n", + "\n", + "# Add the legend to the map.\n", + "Map.add(legend)\n", + "\n", + "# -----------------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s4 - Per Class Balance.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s4 - Per Class Balance.js new file mode 100644 index 0000000..274051c --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s4 - Per Class Balance.js @@ -0,0 +1,438 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.5 Water Balance and Drought +// Checkpoint: A25s4 +// Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Lower Mekong boundary. +var mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin'); + +Map.centerObject(mekongBasin, 6); + +var classStruct = { + 'unknown': { + number: 0, + color: '6f6f6f' + }, + 'surface water': { + number: 1, + color: 'aec3d4' + }, + 'snow and ice': { + number: 2, + color: 'b1f9ff' + }, + 'mangroves': { + number: 3, + color: '111149' + }, + 'flooded forest': { + number: 4, + color: '287463' + }, + 'Deciduous forest': { + number: 5, + color: '152106' + }, + 'Orchard or plantation forest': { + number: 6, + color: 'c3aa69' + }, + 'evergreen Broadleaf': { + number: 7, + color: '7db087' + }, + 'mixed forest': { + number: 8, + color: '387242' + }, + 'urban and built up': { + number: 9, + color: 'cc0013' + }, + 'cropland': { + number: 10, + color: '8dc33b' + }, + 'rice': { + number: 11, + color: 'ffff00' + }, + 'mining': { + number: 12, + color: 'cec2a5' + }, + 'barren': { + number: 13, + color: '674c06' + }, + 'wetlands': { + number: 14, + color: '3bc3b2' + }, + 'grassland': { + number: 15, + color: 'f4a460' + }, + 'shrubland': { + number: 16, + color: '800080' + }, + 'aquaculture': { + number: 17, + color: '51768e' + } +}; + +// Function to get a list of ids (keys) from a structure. +function getIds(struct) { + return Object.keys(struct); +} + +// Function to replace spaces with underscores in a list of strings. +function cleanList(list) { + return list.map(function(name) { + return name.replace(/\s+/g, '_'); + }); +} + +// Function to get a list of column values from a structure. +function getList(struct, column) { + return Object.keys(struct).map(function(k) { + var value = struct[k][column]; + return value; + }); +} + +var classNamesList = getIds(classStruct); +var probNames = cleanList(classNamesList); +var classNames = ee.List(classNamesList); +var classNumbers = getList(classStruct, 'number'); +var paletteList = getList(classStruct, 'color'); +var PALETTE = paletteList.join(','); + +// JSON dictionary that defines piechart colors based on the +// landcover class palette. +// https://developers.google.com/chart/interactive/docs/gallery/piechart +var colors = []; +for (var i = 0; i < paletteList.length; i++) { + colors.push({ + 'color': '_'.replace('_', paletteList[i]) + }); +} + +// Set start and end years. +var startYear = 2010; +var endYear = 2020; + +// Create two date objects for start and end years. +var startDate = ee.Date.fromYMD(startYear, 1, 1); +var endDate = ee.Date.fromYMD(endYear + 1, 1, 1); + +// Make a list with years. +var years = ee.List.sequence(startYear, endYear); + +// Make a list with months. +var months = ee.List.sequence(1, 12); + +// Import and filter the MOD13 dataset. +var mod13 = ee.ImageCollection('MODIS/006/MOD13A1'); +mod13 = mod13.filterDate(startDate, endDate); + +// Select the EVI. +var EVI = mod13.select('EVI'); + +// Import and filter the MODIS Terra surface reflectance dataset. +var mod09 = ee.ImageCollection('MODIS/006/MOD09A1'); +mod09 = mod09.filterDate(startDate, endDate); + +var landcover = ee.Image( + 'projects/gee-book/assets/A2-5/RLCMSv3/Mekonglandcover2018') + .select('lc').clip(mekongBasin); + +var lcVis = { + palette: PALETTE, + min: 0, + max: classNamesList.length - 1 +}; +Map.addLayer(landcover, lcVis, '2018 Land Cover'); + +// We use a function to remove clouds and cloud shadows. +// We map over the mod09 image collection and select the StateQA band. +// We mask pixels and return the image with clouds and cloud shadows masked. +var mod09 = mod09.map(function(image) { + var quality = image.select('StateQA'); + var mask = image.and(quality.bitwiseAnd(1).eq( + 0)) // No clouds. + .and(quality.bitwiseAnd(2).eq(0)); // No cloud shadow. + + return image.updateMask(mask); +}); + +// We use a function to calculate the Moisture Stress Index. +// We map over the mod09 image collection and select the NIR and SWIR bands +// We set the timestamp and return the MSI. +var MSI = mod09.map(function(image) { + var nirband = image.select('sur_refl_b02'); + var swirband = image.select('sur_refl_b06'); + var msi = swirband.divide(nirband) + .rename('MSI') + .set('system:time_start', image.get( + 'system:time_start')); + return msi; +}); + +// We apply a nested loop where we first iterate over +// the relevant years and then iterate over the relevant +// months. The function returns an image with the MSI and EVI +// for each month. A flatten is applied to convert an +// collection of collections into a single collection. +var monthlyIndices = ee.ImageCollection.fromImages( + years.map(function(y) { + return months.map(function(m) { + + // Calculate EVI. + var evi = EVI.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .mean() + .multiply(0.0001); + + // Calculate MSI. + var msi = MSI.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .mean(); + + // Return an image with all images as bands. + return evi.addBands(msi) + .set('year', y) + .set('month', m) + .set('system:time_start', ee.Date + .fromYMD(y, m, 1)); + + }); + }).flatten() +); + +// We select the landcover types for evergreen, deciduous forest, cropland and rice. +var evergreenForest = landcover.eq(7); +var deciduousForest = landcover.eq(5); +var cropland = landcover.eq(10); +var rice = landcover.eq(11); + +// Mask pixels that do not belong to the category. +var evergreenIndex = monthlyIndices.map(function(img) { + return img.updateMask(evergreenForest); +}); + +// Mask pixels that do not belong to the category. +var deciduousIndex = monthlyIndices.map(function(img) { + return img.updateMask(deciduousForest); +}); + +// Mask pixels that do not belong to the category. +var croplandIndex = monthlyIndices.map(function(img) { + return img.updateMask(cropland); +}); + +// Mask pixels that do not belong to the category. +var riceIndex = monthlyIndices.map(function(img) { + return img.updateMask(rice); +}); + +// Define the chart and print it to the console. +var chartIndices = + ui.Chart.image.series({ + imageCollection: deciduousIndex.select(['EVI', 'MSI']), + region: mekongBasin, + reducer: ee.Reducer.mean(), + scale: 1000, + xProperty: 'system:time_start' + }) + .setSeriesNames(['EVI', 'MSI']) + .setOptions({ + title: 'Monthly deciduous forest indices', + hAxis: { + title: 'Date', + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Index', + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1, + colors: ['darkgreen', 'brown'], + curveType: 'function' + }); + +// Print the chart. +print(chartIndices); + +// Define the chart and print it to the console. +var chartIndices = + ui.Chart.image.series({ + imageCollection: evergreenIndex.select(['EVI', 'MSI']), + region: mekongBasin, + reducer: ee.Reducer.mean(), + scale: 1000, + xProperty: 'system:time_start' + }) + .setSeriesNames(['EVI', 'MSI']) + .setOptions({ + title: 'Monthly deciduous forest indices', + hAxis: { + title: 'Date', + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Index', + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1, + colors: ['darkgreen', 'brown'], + curveType: 'function' + }); + +// Print the chart. +print(chartIndices); + +// Define the chart and print it to the console. +var chartIndices = + ui.Chart.image.series({ + imageCollection: croplandIndex.select(['EVI', 'MSI']), + region: mekongBasin, + reducer: ee.Reducer.mean(), + scale: 1000, + xProperty: 'system:time_start' + }) + .setSeriesNames(['EVI', 'MSI']) + .setOptions({ + title: 'Monthly cropland indices', + hAxis: { + title: 'Date', + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Index', + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1, + colors: ['darkgreen', 'brown'], + curveType: 'function' + }); + +// Print the chart. +print(chartIndices); + +// Define the chart and print it to the console. +var chartIndices = + ui.Chart.image.series({ + imageCollection: riceIndex.select(['EVI', 'MSI']), + region: mekongBasin, + reducer: ee.Reducer.mean(), + scale: 1000, + xProperty: 'system:time_start' + }) + .setSeriesNames(['EVI', 'MSI']) + .setOptions({ + title: 'Monthly rice indices', + hAxis: { + title: 'Date', + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Index', + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1, + colors: ['darkgreen', 'brown'], + curveType: 'function' + }); + +// Print the chart. +print(chartIndices); + +// Create the panel for the legend items. +var legend = ui.Panel({ + style: { + position: 'bottom-left', + padding: '8px 15px' + } +}); + +// Create and add the legend title. +var legendTitle = ui.Label({ + value: 'Legend', + style: { + fontWeight: 'bold', + fontSize: '18px', + margin: '0 0 4px 0', + padding: '0' + } +}); + +// Creates and styles 1 row of the legend. +var makeRow = function(color, name) { + // Create the label that is actually the colored box. + var colorBox = ui.Label({ + style: { + backgroundColor: '#' + color, + // Use padding to give the box height and width. + padding: '8px', + margin: '0 0 4px 0' + } + }); + + // Create the label filled with the description text. + var description = ui.Label({ + value: name, + style: { + margin: '0 0 4px 6px' + } + }); + + return ui.Panel({ + widgets: [colorBox, description], + layout: ui.Panel.Layout.Flow('horizontal') + }); +}; + +legend.add(legendTitle); +for (var i = 0; i < classNamesList.length; i++) { + legend.add(makeRow(paletteList[i], classNamesList[i])); +} + +// Add the legend to the map. +Map.add(legend); + +// ----------------------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s4 - Per Class Balance.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s4 - Per Class Balance.py new file mode 100644 index 0000000..37e8f4e --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.5 Water Balance and Drought/A25s4 - Per Class Balance.py @@ -0,0 +1,525 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.5 Water Balance and Drought +# Checkpoint: A25s4 +# Author: Ate Poortinga, Quyen Nguyen, Nyein Soe Thwal, Andréa Puzzi Nicolau +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Lower Mekong boundary. +mekongBasin = ee.FeatureCollection( + 'projects/gee-book/assets/A2-5/lowerMekongBasin') + +Map.centerObject(mekongBasin, 6) + +classStruct = { + 'unknown': { + 'number': 0, + 'color': '6f6f6f' + }, + 'surface water': { + 'number': 1, + 'color': 'aec3d4' + }, + 'snow and ice': { + 'number': 2, + 'color': 'b1f9ff' + }, + 'mangroves': { + 'number': 3, + 'color': '111149' + }, + 'flooded forest': { + 'number': 4, + 'color': '287463' + }, + 'Deciduous forest': { + 'number': 5, + 'color': '152106' + }, + 'Orchard or plantation forest': { + 'number': 6, + 'color': 'c3aa69' + }, + 'evergreen Broadleaf': { + 'number': 7, + 'color': '7db087' + }, + 'mixed forest': { + 'number': 8, + 'color': '387242' + }, + 'urban and built up': { + 'number': 9, + 'color': 'cc0013' + }, + 'cropland': { + 'number': 10, + 'color': '8dc33b' + }, + 'rice': { + 'number': 11, + 'color': 'ffff00' + }, + 'mining': { + 'number': 12, + 'color': 'cec2a5' + }, + 'barren': { + 'number': 13, + 'color': '674c06' + }, + 'wetlands': { + 'number': 14, + 'color': '3bc3b2' + }, + 'grassland': { + 'number': 15, + 'color': 'f4a460' + }, + 'shrubland': { + 'number': 16, + 'color': '800080' + }, + 'aquaculture': { + 'number': 17, + 'color': '51768e' + } +} + +# Function to get a list of ids (keys) from a structure. +def getIds(struct): + return Object.keys(struct) + + +# Function to replace spaces with underscores in a list of strings. +def cleanList(list): + +def func_nzj(name): + return name.replace(/\s+/g, '_') + + return list.map(func_nzj) + + + + + +# Function to get a list of column values from a structure. +def getList(struct, column): + +def func_dkz(k): + value = struct[k][column] + return value + + return Object.keys(struct).map(func_dkz) + + + + + + +classNamesList = getIds(classStruct) +probNames = cleanList(classNamesList) +classNames = ee.List(classNamesList) +classNumbers = getList(classStruct, 'number') +paletteList = getList(classStruct, 'color') +PALETTE = paletteList.join(',') + +# JSON dictionary that defines piechart colors based on the +# landcover class palette. +# https:#developers.google.com/chart/interactive/docs/gallery/piechart +colors = [] +for i in range(0, paletteList.length, 1): + colors.push({ + 'color': '_'.replace('_', paletteList[i]) + }) + + +# Set start and end years. +startYear = 2010 +endYear = 2020 + +# Create two date objects for start and end years. +startDate = ee.Date.fromYMD(startYear, 1, 1) +endDate = ee.Date.fromYMD(endYear + 1, 1, 1) + +# Make a list with years. +years = ee.List.sequence(startYear, endYear) + +# Make a list with months. +months = ee.List.sequence(1, 12) + +# Import and filter the MOD13 dataset. +mod13 = ee.ImageCollection('MODIS/006/MOD13A1') +mod13 = mod13.filterDate(startDate, endDate) + +# Select the EVI. +EVI = mod13.select('EVI') + +# Import and filter the MODIS Terra surface reflectance dataset. +mod09 = ee.ImageCollection('MODIS/006/MOD09A1') +mod09 = mod09.filterDate(startDate, endDate) + +landcover = ee.Image( + 'projects/gee-book/assets/A2-5/RLCMSv3/Mekonglandcover2018') \ + .select('lc').clip(mekongBasin) + +lcVis = { + 'palette': PALETTE, + 'min': 0, + 'max': classNamesList.length - 1 +} +Map.addLayer(landcover, lcVis, '2018 Land Cover') + +# We use a function to remove clouds and cloud shadows. +# We map over the mod09 image collection and select the StateQA band. +# We mask pixels and return the image with clouds and cloud shadows masked. + +def func_hao(image): + quality = image.select('StateQA') + mask = image.And(quality.bitwiseAnd(1).eq( + 0)) # No clouds. \ + .And(quality.bitwiseAnd(2).eq(0)); + + return image.updateMask(mask) + +mod09 = mod09.map(func_hao) + + + + + + + + + +# We use a function to calculate the Moisture Stress Index. +# We map over the mod09 image collection and select the NIR and SWIR bands +# We set the timestamp and return the MSI. + +def func_lru(image): + nirband = image.select('sur_refl_b02') + swirband = image.select('sur_refl_b06') + msi = swirband.divide(nirband) \ + .rename('MSI') \ + .set('system:time_start', image.get( + 'system:time_start')) + return msi + +MSI = mod09.map(func_lru) + + + + + + + + + + +# We apply a nested loop where we first iterate over +# the relevant years and then iterate over the relevant +# months. The function returns an image with the MSI and EVI +# for each month. A flatten is applied to convert an +# collection of collections into a single collection. +monthlyIndices = ee.ImageCollection.fromImages( + +def func_wsp(y): + return months.map(function(m) { + + # Calculate EVI. + evi = EVI.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .mean() \ + .multiply(0.0001) + + # Calculate MSI. + msi = MSI.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .mean() + + # Return an image with all images as bands. + return evi.addBands(msi) \ + .set('year', y) \ + .set('month', m) \ + .set('system:time_start', ee.Date \ + .fromYMD(y, m, 1)) + + }) + + years.map(func_wsp +).flatten() + + + + + + + + + + + + + + + + + + + + + + + + + +).flatten() +) + +# We select the landcover types for evergreen, deciduous forest, cropland and rice. +evergreenForest = landcover.eq(7) +deciduousForest = landcover.eq(5) +cropland = landcover.eq(10) +rice = landcover.eq(11) + +# Mask pixels that do not belong to the category. + +def func_yqe(img): + return img.updateMask(evergreenForest) + +evergreenIndex = monthlyIndices.map(func_yqe) + + + + +# Mask pixels that do not belong to the category. + +def func_cip(img): + return img.updateMask(deciduousForest) + +deciduousIndex = monthlyIndices.map(func_cip) + + + + +# Mask pixels that do not belong to the category. + +def func_vrq(img): + return img.updateMask(cropland) + +croplandIndex = monthlyIndices.map(func_vrq) + + + + +# Mask pixels that do not belong to the category. + +def func_jit(img): + return img.updateMask(rice) + +riceIndex = monthlyIndices.map(func_jit) + + + + +# Define the chart and print it to the console. +chartIndices = + ui.Chart.image.series({ + 'imageCollection': deciduousIndex.select(['EVI', 'MSI']), + 'region': mekongBasin, + 'reducer': ee.Reducer.mean(), + 'scale': 1000, + 'xProperty': 'system:time_start' + }) \ + .setSeriesNames(['EVI', 'MSI']) \ + .setOptions({ + 'title': 'Monthly deciduous forest indices', + 'hAxis': { + 'title': 'Date', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Index', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'lineWidth': 1, + 'colors': ['darkgreen', 'brown'], + 'curveType': 'function' + }) + +# Print the chart. +print(chartIndices) + +# Define the chart and print it to the console. +chartIndices = + ui.Chart.image.series({ + 'imageCollection': evergreenIndex.select(['EVI', 'MSI']), + 'region': mekongBasin, + 'reducer': ee.Reducer.mean(), + 'scale': 1000, + 'xProperty': 'system:time_start' + }) \ + .setSeriesNames(['EVI', 'MSI']) \ + .setOptions({ + 'title': 'Monthly deciduous forest indices', + 'hAxis': { + 'title': 'Date', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Index', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'lineWidth': 1, + 'colors': ['darkgreen', 'brown'], + 'curveType': 'function' + }) + +# Print the chart. +print(chartIndices) + +# Define the chart and print it to the console. +chartIndices = + ui.Chart.image.series({ + 'imageCollection': croplandIndex.select(['EVI', 'MSI']), + 'region': mekongBasin, + 'reducer': ee.Reducer.mean(), + 'scale': 1000, + 'xProperty': 'system:time_start' + }) \ + .setSeriesNames(['EVI', 'MSI']) \ + .setOptions({ + 'title': 'Monthly cropland indices', + 'hAxis': { + 'title': 'Date', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Index', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'lineWidth': 1, + 'colors': ['darkgreen', 'brown'], + 'curveType': 'function' + }) + +# Print the chart. +print(chartIndices) + +# Define the chart and print it to the console. +chartIndices = + ui.Chart.image.series({ + 'imageCollection': riceIndex.select(['EVI', 'MSI']), + 'region': mekongBasin, + 'reducer': ee.Reducer.mean(), + 'scale': 1000, + 'xProperty': 'system:time_start' + }) \ + .setSeriesNames(['EVI', 'MSI']) \ + .setOptions({ + 'title': 'Monthly rice indices', + 'hAxis': { + 'title': 'Date', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Index', + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'lineWidth': 1, + 'colors': ['darkgreen', 'brown'], + 'curveType': 'function' + }) + +# Print the chart. +print(chartIndices) + +# Create the panel for the legend items. +legend = ui.Panel({ + 'style': { + 'position': 'bottom-left', + 'padding': '8px 15px' + } +}) + +# Create and add the legend title. +legendTitle = ui.Label({ + 'value': 'Legend', + 'style': { + 'fontWeight': 'bold', + 'fontSize': '18px', + 'margin': '0 0 4px 0', + 'padding': '0' + } +}) + +# Creates and styles 1 row of the legend. +def makeRow(color, name): + # Create the label that is actually the colored box. + colorBox = ui.Label({ + 'style': { + 'backgroundColor': '#' + color, + # Use padding to give the box height and width. + 'padding': '8px', + 'margin': '0 0 4px 0' + } + }) + + # Create the label filled with the description text. + description = ui.Label({ + 'value': name, + 'style': { + 'margin': '0 0 4px 6px' + } + }) + + return ui.Panel({ + 'widgets': [colorBox, description], + 'layout': ui.Panel.Layout.Flow('horizontal') + }) + + +legend.add(legendTitle) +for i in range(0, classNamesList.length, 1): + legend.add(makeRow(paletteList[i], classNamesList[i])) + + +# Add the legend to the map. +Map.add(legend) + +# ----------------------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26a Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26a Checkpoint.ipynb new file mode 100644 index 0000000..5096c51 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26a Checkpoint.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.6 Defining Seasonality: First Date of No Snow\n", + "# Checkpoint: A26a\n", + "# Authors: Amanda Armstrong, Morgan Tassone, Justin Braaten\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "startDoy = 1\n", + "startYear = 2000\n", + "endYear = 2019\n", + "\n", + "startDate\n", + "startYear\n", + "\n", + "def addDateBands(img):\n", + " # Get image date.\n", + " date = img.date()\n", + " # Get calendar day-of-year.\n", + " calDoy = date.getRelative('day', 'year')\n", + " # Get relative day-of-year; enumerate from user-defined startDoy.\n", + " relDoy = date.difference(startDate, 'day')\n", + " # Get the date as milliseconds from Unix epoch.\n", + " millis = date.millis()\n", + " # Add all of the above date info as bands to the snow fraction image.\n", + " dateBands = ee.Image.constant([calDoy, relDoy, millis,\n", + " startYear\n", + " ]) \\\n", + " .rename(['calDoy', 'relDoy', 'millis', 'year'])\n", + " # Cast bands to correct data type before returning the image.\n", + " return img.addBands(dateBands) \\\n", + " .cast({\n", + " 'calDoy': 'int',\n", + " 'relDoy': 'int',\n", + " 'millis': 'long',\n", + " 'year': 'int'\n", + " }) \\\n", + " .set('millis', millis)\n", + "\n", + "\n", + "waterMask = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24') \\\n", + " .select('water_mask') \\\n", + " .Not()\n", + "\n", + "completeCol = ee.ImageCollection('MODIS/006/MOD10A1') \\\n", + " .select('NDSI_Snow_Cover')\n", + "\n", + "# Pixels must have been 10% snow covered for at least 2 weeks in 2018.\n", + "snowCoverEphem = completeCol.filterDate('2018-01-01',\n", + " '2019-01-01')\n", + "\n", + "def func_teo(img):\n", + " return img.gte(10) \\\n", + " .map(func_teo) \\\n", + " .sum() \\\n", + " .gte(14)\n", + "\n", + "# Pixels must not be 10% snow covered more than 124 days in 2018.\n", + "snowCoverConst = completeCol.filterDate('2018-01-01',\n", + " '2019-01-01')\n", + "\n", + "def func_jlk(img):\n", + " return img.gte(10) \\\n", + " .map(func_jlk) \\\n", + " .sum() \\\n", + " .lte(124)\n", + "\n", + "analysisMask = waterMask.multiply(snowCoverEphem).multiply(\n", + " snowCoverConst)\n", + "\n", + "years = ee.List.sequence(startYear, endYear)\n", + "\n", + "\n", + "def func_kis(year):\n", + " # Set the global startYear variable as the year being worked on so that\n", + " # it will be accessible to the addDateBands mapped to the collection below.\n", + " startYear = year\n", + " # Get the first day-of-year for this year as an ee.Date object.\n", + " firstDoy = ee.Date.fromYMD(year, 1, 1)\n", + " # Advance from the firstDoy to the user-defined startDay; subtract 1 since\n", + " # firstDoy is already 1. Set the result as the global startDate variable so\n", + " # that it is accessible to the addDateBands mapped to the collection below.\n", + " startDate = firstDoy.advance(startDoy - 1, 'day')\n", + " # Get endDate for this year by advancing 1 year from startDate.\n", + " # Need to advance an extra day because end date of filterDate() function\n", + " # is exclusive.\n", + " endDate = startDate.advance(1, 'year').advance(1,\n", + " 'day')\n", + " # Filter the complete collection by the start and end dates just defined.\n", + " yearCol = completeCol.filterDate(startDate, endDate)\n", + " # Construct an image where pixels represent the first day within the date\n", + " # range that the lowest snow fraction is observed.\n", + " noSnowImg = yearCol \\\n", + " .map(addDateBands)\n", + " # Sort the images by ascending time to identify the first day without\n", + " # snow. Alternatively, you can use .sort('millis', False) to \\\n", + " .sort('millis')\n", + " # Make a mosaic composed of pixels from images that represent the\n", + " # observation with the minimum percent snow cover (defined by the\n", + " # NDSI_Snow_Cover band); include all associated bands for the selected \\\n", + " .reduce(ee.Reducer.min(5)) \\\n", + " .rename(['snowCover', 'calDoy', 'relDoy', 'millis',\n", + " 'year'\n", + " ]) \\\n", + " .updateMask(analysisMask) \\\n", + " .set('year', year)\n", + "\n", + " # Mask by minimum snow fraction - only include pixels that reach 0\n", + " # percent cover. Return the resulting image.\n", + " return noSnowImg.updateMask(noSnowImg.select('snowCover') \\\n", + " .eq(0))\n", + "\n", + "annualList = years.map(func_kis)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "annualCol = ee.ImageCollection.fromImages(annualList)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26a Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26a Checkpoint.js new file mode 100644 index 0000000..6a3a3be --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26a Checkpoint.js @@ -0,0 +1,119 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.6 Defining Seasonality: First Date of No Snow +// Checkpoint: A26a +// Authors: Amanda Armstrong, Morgan Tassone, Justin Braaten +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var startDoy = 1; +var startYear = 2000; +var endYear = 2019; + +var startDate; +var startYear; + +function addDateBands(img) { + // Get image date. + var date = img.date(); + // Get calendar day-of-year. + var calDoy = date.getRelative('day', 'year'); + // Get relative day-of-year; enumerate from user-defined startDoy. + var relDoy = date.difference(startDate, 'day'); + // Get the date as milliseconds from Unix epoch. + var millis = date.millis(); + // Add all of the above date info as bands to the snow fraction image. + var dateBands = ee.Image.constant([calDoy, relDoy, millis, + startYear + ]) + .rename(['calDoy', 'relDoy', 'millis', 'year']); + // Cast bands to correct data type before returning the image. + return img.addBands(dateBands) + .cast({ + 'calDoy': 'int', + 'relDoy': 'int', + 'millis': 'long', + 'year': 'int' + }) + .set('millis', millis); +} + +var waterMask = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24') + .select('water_mask') + .not(); + +var completeCol = ee.ImageCollection('MODIS/006/MOD10A1') + .select('NDSI_Snow_Cover'); + +// Pixels must have been 10% snow covered for at least 2 weeks in 2018. +var snowCoverEphem = completeCol.filterDate('2018-01-01', + '2019-01-01') + .map(function(img) { + return img.gte(10); + }) + .sum() + .gte(14); + +// Pixels must not be 10% snow covered more than 124 days in 2018. +var snowCoverConst = completeCol.filterDate('2018-01-01', + '2019-01-01') + .map(function(img) { + return img.gte(10); + }) + .sum() + .lte(124); + +var analysisMask = waterMask.multiply(snowCoverEphem).multiply( + snowCoverConst); + +var years = ee.List.sequence(startYear, endYear); + +var annualList = years.map(function(year) { + // Set the global startYear variable as the year being worked on so that + // it will be accessible to the addDateBands mapped to the collection below. + startYear = year; + // Get the first day-of-year for this year as an ee.Date object. + var firstDoy = ee.Date.fromYMD(year, 1, 1); + // Advance from the firstDoy to the user-defined startDay; subtract 1 since + // firstDoy is already 1. Set the result as the global startDate variable so + // that it is accessible to the addDateBands mapped to the collection below. + startDate = firstDoy.advance(startDoy - 1, 'day'); + // Get endDate for this year by advancing 1 year from startDate. + // Need to advance an extra day because end date of filterDate() function + // is exclusive. + var endDate = startDate.advance(1, 'year').advance(1, + 'day'); + // Filter the complete collection by the start and end dates just defined. + var yearCol = completeCol.filterDate(startDate, endDate); + // Construct an image where pixels represent the first day within the date + // range that the lowest snow fraction is observed. + var noSnowImg = yearCol + // Add date bands to all images in this particular collection. + .map(addDateBands) + // Sort the images by ascending time to identify the first day without + // snow. Alternatively, you can use .sort('millis', false) to + // reverse sort (find first day of snow in the fall). + .sort('millis') + // Make a mosaic composed of pixels from images that represent the + // observation with the minimum percent snow cover (defined by the + // NDSI_Snow_Cover band); include all associated bands for the selected + // image. + .reduce(ee.Reducer.min(5)) + // Rename the bands - band names were altered by previous operation. + .rename(['snowCover', 'calDoy', 'relDoy', 'millis', + 'year' + ]) + // Apply the mask. + .updateMask(analysisMask) + // Set the year as a property for filtering by later. + .set('year', year); + + // Mask by minimum snow fraction - only include pixels that reach 0 + // percent cover. Return the resulting image. + return noSnowImg.updateMask(noSnowImg.select('snowCover') + .eq(0)); +}); + +var annualCol = ee.ImageCollection.fromImages(annualList); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26a Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26a Checkpoint.py new file mode 100644 index 0000000..78653e5 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26a Checkpoint.py @@ -0,0 +1,168 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.6 Defining Seasonality: First Date of No Snow +# Checkpoint: A26a +# Authors: Amanda Armstrong, Morgan Tassone, Justin Braaten +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +startDoy = 1 +startYear = 2000 +endYear = 2019 + +startDate +startYear + +def addDateBands(img): + # Get image date. + date = img.date() + # Get calendar day-of-year. + calDoy = date.getRelative('day', 'year') + # Get relative day-of-year; enumerate from user-defined startDoy. + relDoy = date.difference(startDate, 'day') + # Get the date as milliseconds from Unix epoch. + millis = date.millis() + # Add all of the above date info as bands to the snow fraction image. + dateBands = ee.Image.constant([calDoy, relDoy, millis, + startYear + ]) \ + .rename(['calDoy', 'relDoy', 'millis', 'year']) + # Cast bands to correct data type before returning the image. + return img.addBands(dateBands) \ + .cast({ + 'calDoy': 'int', + 'relDoy': 'int', + 'millis': 'long', + 'year': 'int' + }) \ + .set('millis', millis) + + +waterMask = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24') \ + .select('water_mask') \ + .Not() + +completeCol = ee.ImageCollection('MODIS/006/MOD10A1') \ + .select('NDSI_Snow_Cover') + +# Pixels must have been 10% snow covered for at least 2 weeks in 2018. +snowCoverEphem = completeCol.filterDate('2018-01-01', + '2019-01-01') + +def func_teo(img): + return img.gte(10) \ + .map(func_teo) \ + .sum() \ + .gte(14) + +# Pixels must not be 10% snow covered more than 124 days in 2018. +snowCoverConst = completeCol.filterDate('2018-01-01', + '2019-01-01') + +def func_jlk(img): + return img.gte(10) \ + .map(func_jlk) \ + .sum() \ + .lte(124) + +analysisMask = waterMask.multiply(snowCoverEphem).multiply( + snowCoverConst) + +years = ee.List.sequence(startYear, endYear) + + +def func_kis(year): + # Set the global startYear variable as the year being worked on so that + # it will be accessible to the addDateBands mapped to the collection below. + startYear = year + # Get the first day-of-year for this year as an ee.Date object. + firstDoy = ee.Date.fromYMD(year, 1, 1) + # Advance from the firstDoy to the user-defined startDay; subtract 1 since + # firstDoy is already 1. Set the result as the global startDate variable so + # that it is accessible to the addDateBands mapped to the collection below. + startDate = firstDoy.advance(startDoy - 1, 'day') + # Get endDate for this year by advancing 1 year from startDate. + # Need to advance an extra day because end date of filterDate() function + # is exclusive. + endDate = startDate.advance(1, 'year').advance(1, + 'day') + # Filter the complete collection by the start and end dates just defined. + yearCol = completeCol.filterDate(startDate, endDate) + # Construct an image where pixels represent the first day within the date + # range that the lowest snow fraction is observed. + noSnowImg = yearCol \ + .map(addDateBands) + # Sort the images by ascending time to identify the first day without + # snow. Alternatively, you can use .sort('millis', False) to \ + .sort('millis') + # Make a mosaic composed of pixels from images that represent the + # observation with the minimum percent snow cover (defined by the + # NDSI_Snow_Cover band); include all associated bands for the selected \ + .reduce(ee.Reducer.min(5)) \ + .rename(['snowCover', 'calDoy', 'relDoy', 'millis', + 'year' + ]) \ + .updateMask(analysisMask) \ + .set('year', year) + + # Mask by minimum snow fraction - only include pixels that reach 0 + # percent cover. Return the resulting image. + return noSnowImg.updateMask(noSnowImg.select('snowCover') \ + .eq(0)) + +annualList = years.map(func_kis) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +annualCol = ee.ImageCollection.fromImages(annualList) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26b Checkpoint.ipynb b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26b Checkpoint.ipynb new file mode 100644 index 0000000..00c313d --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26b Checkpoint.ipynb @@ -0,0 +1,373 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A2.6 Defining Seasonality: First Date of No Snow\n", + "# Checkpoint: A26b\n", + "# Authors: Amanda Armstrong, Morgan Tassone, Justin Braaten\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "startDoy = 1\n", + "startYear = 2000\n", + "endYear = 2019\n", + "\n", + "startDate\n", + "startYear\n", + "\n", + "def addDateBands(img):\n", + " # Get image date.\n", + " date = img.date()\n", + " # Get calendar day-of-year.\n", + " calDoy = date.getRelative('day', 'year')\n", + " # Get relative day-of-year; enumerate from user-defined startDoy.\n", + " relDoy = date.difference(startDate, 'day')\n", + " # Get the date as milliseconds from Unix epoch.\n", + " millis = date.millis()\n", + " # Add all of the above date info as bands to the snow fraction image.\n", + " dateBands = ee.Image.constant([calDoy, relDoy, millis,\n", + " startYear\n", + " ]) \\\n", + " .rename(['calDoy', 'relDoy', 'millis', 'year'])\n", + " # Cast bands to correct data type before returning the image.\n", + " return img.addBands(dateBands) \\\n", + " .cast({\n", + " 'calDoy': 'int',\n", + " 'relDoy': 'int',\n", + " 'millis': 'long',\n", + " 'year': 'int'\n", + " }) \\\n", + " .set('millis', millis)\n", + "\n", + "\n", + "waterMask = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24') \\\n", + " .select('water_mask') \\\n", + " .Not()\n", + "\n", + "completeCol = ee.ImageCollection('MODIS/006/MOD10A1') \\\n", + " .select('NDSI_Snow_Cover')\n", + "\n", + "# Pixels must have been 10% snow covered for at least 2 weeks in 2018.\n", + "snowCoverEphem = completeCol.filterDate('2018-01-01',\n", + " '2019-01-01')\n", + "\n", + "def func_yvu(img):\n", + " return img.gte(10) \\\n", + " .map(func_yvu) \\\n", + " .sum() \\\n", + " .gte(14)\n", + "\n", + "# Pixels must not be 10% snow covered more than 124 days in 2018.\n", + "snowCoverConst = completeCol.filterDate('2018-01-01',\n", + " '2019-01-01')\n", + "\n", + "def func_hsm(img):\n", + " return img.gte(10) \\\n", + " .map(func_hsm) \\\n", + " .sum() \\\n", + " .lte(124)\n", + "\n", + "analysisMask = waterMask.multiply(snowCoverEphem).multiply(\n", + " snowCoverConst)\n", + "\n", + "years = ee.List.sequence(startYear, endYear)\n", + "\n", + "\n", + "def func_anh(year):\n", + " # Set the global startYear variable as the year being worked on so that\n", + " # it will be accessible to the addDateBands mapped to the collection below.\n", + " startYear = year\n", + " # Get the first day-of-year for this year as an ee.Date object.\n", + " firstDoy = ee.Date.fromYMD(year, 1, 1)\n", + " # Advance from the firstDoy to the user-defined startDay; subtract 1 since\n", + " # firstDoy is already 1. Set the result as the global startDate variable so\n", + " # that it is accessible to the addDateBands mapped to the collection below.\n", + " startDate = firstDoy.advance(startDoy - 1, 'day')\n", + " # Get endDate for this year by advancing 1 year from startDate.\n", + " # Need to advance an extra day because end date of filterDate() function\n", + " # is exclusive.\n", + " endDate = startDate.advance(1, 'year').advance(1,\n", + " 'day')\n", + " # Filter the complete collection by the start and end dates just defined.\n", + " yearCol = completeCol.filterDate(startDate, endDate)\n", + " # Construct an image where pixels represent the first day within the date\n", + " # range that the lowest snow fraction is observed.\n", + " noSnowImg = yearCol \\\n", + " .map(addDateBands)\n", + " # Sort the images by ascending time to identify the first day without\n", + " # snow. Alternatively, you can use .sort('millis', False) to \\\n", + " .sort('millis')\n", + " # Make a mosaic composed of pixels from images that represent the\n", + " # observation with the minimum percent snow cover (defined by \u00c7the\n", + " # NDSI_Snow_Cover band); include all associated bands for the selected \\\n", + " .reduce(ee.Reducer.min(5)) \\\n", + " .rename(['snowCover', 'calDoy', 'relDoy', 'millis',\n", + " 'year'\n", + " ]) \\\n", + " .updateMask(analysisMask) \\\n", + " .set('year', year)\n", + "\n", + " # Mask by minimum snow fraction - only include pixels that reach 0\n", + " # percent cover. Return the resulting image.\n", + " return noSnowImg.updateMask(noSnowImg.select('snowCover') \\\n", + " .eq(0))\n", + "\n", + "annualList = years.map(func_anh)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "annualCol = ee.ImageCollection.fromImages(annualList)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Define a year to visualize.\n", + "thisYear = 2018\n", + "\n", + "# Define visualization arguments.\n", + "visArgs = {\n", + " 'bands': ['calDoy'],\n", + " 'min': 150,\n", + " 'max': 200,\n", + " 'palette': [\n", + " '0D0887', '5B02A3', '9A179B', 'CB4678', 'EB7852',\n", + " 'FBB32F', 'F0F921'\n", + " ]\n", + "}\n", + "\n", + "# Subset the year of interest.\n", + "firstDayNoSnowYear = annualCol.filter(ee.Filter.eq('year',\n", + " thisYear)).first()\n", + "\n", + "# Display it on the map.\n", + "Map.setCenter(-95.78, 59.451, 5)\n", + "Map.addLayer(firstDayNoSnowYear, visArgs,\n", + " 'First day of no snow, 2018')\n", + "\n", + "# Define the years to difference.\n", + "firstYear = 2005\n", + "secondYear = 2015\n", + "\n", + "# Calculate difference image.\n", + "firstImg = annualCol.filter(ee.Filter.eq('year', firstYear)) \\\n", + " .first().select('calDoy')\n", + "secondImg = annualCol.filter(ee.Filter.eq('year', secondYear)) \\\n", + " .first().select('calDoy')\n", + "dif = secondImg.subtract(firstImg)\n", + "\n", + "# Define visualization arguments.\n", + "visArgs = {\n", + " 'min': -15,\n", + " 'max': 15,\n", + " 'palette': ['b2182b', 'ef8a62', 'fddbc7', 'f7f7f7', 'd1e5f0',\n", + " '67a9cf', '2166ac'\n", + " ]\n", + "}\n", + "\n", + "# Display it on the map.\n", + "Map.setCenter(95.427, 29.552, 8)\n", + "Map.addLayer(dif, visArgs, '2015-2005 first day no snow dif')\n", + "\n", + "# Calculate slope image.\n", + "slope = annualCol.sort('year').select(['year', 'calDoy']) \\\n", + " .reduce(ee.Reducer.linearFit()).select('scale')\n", + "\n", + "# Define visualization arguments.\n", + "visArgs = {\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': ['b2182b', 'ef8a62', 'fddbc7', 'f7f7f7',\n", + " 'd1e5f0', '67a9cf', '2166ac'\n", + " ]\n", + "}\n", + "\n", + "# Display it on the map.\n", + "Map.setCenter(11.25, 59.88, 6)\n", + "Map.addLayer(slope, visArgs, '2000-2019 first day no snow slope')\n", + "\n", + "# Define an AOI.\n", + "aoi = ee.Geometry.Point(-94.242, 65.79).buffer(1e4)\n", + "Map.addLayer(aoi, None, 'Area of interest')\n", + "\n", + "# Calculate annual mean DOY of AOI.\n", + "\n", + "def func_xob(img):\n", + " summary = img.reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': aoi,\n", + " 'scale': 1e3,\n", + " 'bestEffort': True,\n", + " 'maxPixels': 1e14,\n", + " 'tileScale': 4,\n", + " })\n", + " return ee.Feature(None, summary).set('year', img.get(\n", + " 'year'))\n", + "\n", + "annualAoiMean = annualCol.select('calDoy').map(func_xob)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Print chart to console.\n", + "chart = ui.Chart.feature.byFeature(annualAoiMean, 'year',\n", + " 'calDoy') \\\n", + " .setOptions({\n", + " 'title': 'Regional mean first day of year with no snow cover',\n", + " 'legend': {\n", + " 'position': 'none'\n", + " },\n", + " 'hAxis': {\n", + " 'title': 'Year',\n", + " format: '####'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Day-of-year'\n", + " }\n", + " })\n", + "print(chart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26b Checkpoint.js b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26b Checkpoint.js new file mode 100644 index 0000000..d37e948 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26b Checkpoint.js @@ -0,0 +1,223 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A2.6 Defining Seasonality: First Date of No Snow +// Checkpoint: A26b +// Authors: Amanda Armstrong, Morgan Tassone, Justin Braaten +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var startDoy = 1; +var startYear = 2000; +var endYear = 2019; + +var startDate; +var startYear; + +function addDateBands(img) { + // Get image date. + var date = img.date(); + // Get calendar day-of-year. + var calDoy = date.getRelative('day', 'year'); + // Get relative day-of-year; enumerate from user-defined startDoy. + var relDoy = date.difference(startDate, 'day'); + // Get the date as milliseconds from Unix epoch. + var millis = date.millis(); + // Add all of the above date info as bands to the snow fraction image. + var dateBands = ee.Image.constant([calDoy, relDoy, millis, + startYear + ]) + .rename(['calDoy', 'relDoy', 'millis', 'year']); + // Cast bands to correct data type before returning the image. + return img.addBands(dateBands) + .cast({ + 'calDoy': 'int', + 'relDoy': 'int', + 'millis': 'long', + 'year': 'int' + }) + .set('millis', millis); +} + +var waterMask = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24') + .select('water_mask') + .not(); + +var completeCol = ee.ImageCollection('MODIS/006/MOD10A1') + .select('NDSI_Snow_Cover'); + +// Pixels must have been 10% snow covered for at least 2 weeks in 2018. +var snowCoverEphem = completeCol.filterDate('2018-01-01', + '2019-01-01') + .map(function(img) { + return img.gte(10); + }) + .sum() + .gte(14); + +// Pixels must not be 10% snow covered more than 124 days in 2018. +var snowCoverConst = completeCol.filterDate('2018-01-01', + '2019-01-01') + .map(function(img) { + return img.gte(10); + }) + .sum() + .lte(124); + +var analysisMask = waterMask.multiply(snowCoverEphem).multiply( + snowCoverConst); + +var years = ee.List.sequence(startYear, endYear); + +var annualList = years.map(function(year) { + // Set the global startYear variable as the year being worked on so that + // it will be accessible to the addDateBands mapped to the collection below. + startYear = year; + // Get the first day-of-year for this year as an ee.Date object. + var firstDoy = ee.Date.fromYMD(year, 1, 1); + // Advance from the firstDoy to the user-defined startDay; subtract 1 since + // firstDoy is already 1. Set the result as the global startDate variable so + // that it is accessible to the addDateBands mapped to the collection below. + startDate = firstDoy.advance(startDoy - 1, 'day'); + // Get endDate for this year by advancing 1 year from startDate. + // Need to advance an extra day because end date of filterDate() function + // is exclusive. + var endDate = startDate.advance(1, 'year').advance(1, + 'day'); + // Filter the complete collection by the start and end dates just defined. + var yearCol = completeCol.filterDate(startDate, endDate); + // Construct an image where pixels represent the first day within the date + // range that the lowest snow fraction is observed. + var noSnowImg = yearCol + // Add date bands to all images in this particular collection. + .map(addDateBands) + // Sort the images by ascending time to identify the first day without + // snow. Alternatively, you can use .sort('millis', false) to + // reverse sort (find first day of snow in the fall). + .sort('millis') + // Make a mosaic composed of pixels from images that represent the + // observation with the minimum percent snow cover (defined by Çthe + // NDSI_Snow_Cover band); include all associated bands for the selected + // image. + .reduce(ee.Reducer.min(5)) + // Rename the bands - band names were altered by previous operation. + .rename(['snowCover', 'calDoy', 'relDoy', 'millis', + 'year' + ]) + // Apply the mask. + .updateMask(analysisMask) + // Set the year as a property for filtering by later. + .set('year', year); + + // Mask by minimum snow fraction - only include pixels that reach 0 + // percent cover. Return the resulting image. + return noSnowImg.updateMask(noSnowImg.select('snowCover') + .eq(0)); +}); + +var annualCol = ee.ImageCollection.fromImages(annualList); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Define a year to visualize. +var thisYear = 2018; + +// Define visualization arguments. +var visArgs = { + bands: ['calDoy'], + min: 150, + max: 200, + palette: [ + '0D0887', '5B02A3', '9A179B', 'CB4678', 'EB7852', + 'FBB32F', 'F0F921' + ] +}; + +// Subset the year of interest. +var firstDayNoSnowYear = annualCol.filter(ee.Filter.eq('year', + thisYear)).first(); + +// Display it on the map. +Map.setCenter(-95.78, 59.451, 5); +Map.addLayer(firstDayNoSnowYear, visArgs, + 'First day of no snow, 2018'); + +// Define the years to difference. +var firstYear = 2005; +var secondYear = 2015; + +// Calculate difference image. +var firstImg = annualCol.filter(ee.Filter.eq('year', firstYear)) + .first().select('calDoy'); +var secondImg = annualCol.filter(ee.Filter.eq('year', secondYear)) + .first().select('calDoy'); +var dif = secondImg.subtract(firstImg); + +// Define visualization arguments. +var visArgs = { + min: -15, + max: 15, + palette: ['b2182b', 'ef8a62', 'fddbc7', 'f7f7f7', 'd1e5f0', + '67a9cf', '2166ac' + ] +}; + +// Display it on the map. +Map.setCenter(95.427, 29.552, 8); +Map.addLayer(dif, visArgs, '2015-2005 first day no snow dif'); + +// Calculate slope image. +var slope = annualCol.sort('year').select(['year', 'calDoy']) + .reduce(ee.Reducer.linearFit()).select('scale'); + +// Define visualization arguments. +var visArgs = { + min: -1, + max: 1, + palette: ['b2182b', 'ef8a62', 'fddbc7', 'f7f7f7', + 'd1e5f0', '67a9cf', '2166ac' + ] +}; + +// Display it on the map. +Map.setCenter(11.25, 59.88, 6); +Map.addLayer(slope, visArgs, '2000-2019 first day no snow slope'); + +// Define an AOI. +var aoi = ee.Geometry.Point(-94.242, 65.79).buffer(1e4); +Map.addLayer(aoi, null, 'Area of interest'); + +// Calculate annual mean DOY of AOI. +var annualAoiMean = annualCol.select('calDoy').map(function(img) { + var summary = img.reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: aoi, + scale: 1e3, + bestEffort: true, + maxPixels: 1e14, + tileScale: 4, + }); + return ee.Feature(null, summary).set('year', img.get( + 'year')); +}); + +// Print chart to console. +var chart = ui.Chart.feature.byFeature(annualAoiMean, 'year', + 'calDoy') + .setOptions({ + title: 'Regional mean first day of year with no snow cover', + legend: { + position: 'none' + }, + hAxis: { + title: 'Year', + format: '####' + }, + vAxis: { + title: 'Day-of-year' + } + }); +print(chart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26b Checkpoint.py b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26b Checkpoint.py new file mode 100644 index 0000000..3e08fe0 --- /dev/null +++ b/docs/book/Part A - Applications/A2 - Aquatic and Hydrological Applications/A2.6 First Date of No Snow/A26b Checkpoint.py @@ -0,0 +1,286 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A2.6 Defining Seasonality: First Date of No Snow +# Checkpoint: A26b +# Authors: Amanda Armstrong, Morgan Tassone, Justin Braaten +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +startDoy = 1 +startYear = 2000 +endYear = 2019 + +startDate +startYear + +def addDateBands(img): + # Get image date. + date = img.date() + # Get calendar day-of-year. + calDoy = date.getRelative('day', 'year') + # Get relative day-of-year; enumerate from user-defined startDoy. + relDoy = date.difference(startDate, 'day') + # Get the date as milliseconds from Unix epoch. + millis = date.millis() + # Add all of the above date info as bands to the snow fraction image. + dateBands = ee.Image.constant([calDoy, relDoy, millis, + startYear + ]) \ + .rename(['calDoy', 'relDoy', 'millis', 'year']) + # Cast bands to correct data type before returning the image. + return img.addBands(dateBands) \ + .cast({ + 'calDoy': 'int', + 'relDoy': 'int', + 'millis': 'long', + 'year': 'int' + }) \ + .set('millis', millis) + + +waterMask = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24') \ + .select('water_mask') \ + .Not() + +completeCol = ee.ImageCollection('MODIS/006/MOD10A1') \ + .select('NDSI_Snow_Cover') + +# Pixels must have been 10% snow covered for at least 2 weeks in 2018. +snowCoverEphem = completeCol.filterDate('2018-01-01', + '2019-01-01') + +def func_yvu(img): + return img.gte(10) \ + .map(func_yvu) \ + .sum() \ + .gte(14) + +# Pixels must not be 10% snow covered more than 124 days in 2018. +snowCoverConst = completeCol.filterDate('2018-01-01', + '2019-01-01') + +def func_hsm(img): + return img.gte(10) \ + .map(func_hsm) \ + .sum() \ + .lte(124) + +analysisMask = waterMask.multiply(snowCoverEphem).multiply( + snowCoverConst) + +years = ee.List.sequence(startYear, endYear) + + +def func_anh(year): + # Set the global startYear variable as the year being worked on so that + # it will be accessible to the addDateBands mapped to the collection below. + startYear = year + # Get the first day-of-year for this year as an ee.Date object. + firstDoy = ee.Date.fromYMD(year, 1, 1) + # Advance from the firstDoy to the user-defined startDay; subtract 1 since + # firstDoy is already 1. Set the result as the global startDate variable so + # that it is accessible to the addDateBands mapped to the collection below. + startDate = firstDoy.advance(startDoy - 1, 'day') + # Get endDate for this year by advancing 1 year from startDate. + # Need to advance an extra day because end date of filterDate() function + # is exclusive. + endDate = startDate.advance(1, 'year').advance(1, + 'day') + # Filter the complete collection by the start and end dates just defined. + yearCol = completeCol.filterDate(startDate, endDate) + # Construct an image where pixels represent the first day within the date + # range that the lowest snow fraction is observed. + noSnowImg = yearCol \ + .map(addDateBands) + # Sort the images by ascending time to identify the first day without + # snow. Alternatively, you can use .sort('millis', False) to \ + .sort('millis') + # Make a mosaic composed of pixels from images that represent the + # observation with the minimum percent snow cover (defined by Çthe + # NDSI_Snow_Cover band); include all associated bands for the selected \ + .reduce(ee.Reducer.min(5)) \ + .rename(['snowCover', 'calDoy', 'relDoy', 'millis', + 'year' + ]) \ + .updateMask(analysisMask) \ + .set('year', year) + + # Mask by minimum snow fraction - only include pixels that reach 0 + # percent cover. Return the resulting image. + return noSnowImg.updateMask(noSnowImg.select('snowCover') \ + .eq(0)) + +annualList = years.map(func_anh) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +annualCol = ee.ImageCollection.fromImages(annualList) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Define a year to visualize. +thisYear = 2018 + +# Define visualization arguments. +visArgs = { + 'bands': ['calDoy'], + 'min': 150, + 'max': 200, + 'palette': [ + '0D0887', '5B02A3', '9A179B', 'CB4678', 'EB7852', + 'FBB32F', 'F0F921' + ] +} + +# Subset the year of interest. +firstDayNoSnowYear = annualCol.filter(ee.Filter.eq('year', + thisYear)).first() + +# Display it on the map. +Map.setCenter(-95.78, 59.451, 5) +Map.addLayer(firstDayNoSnowYear, visArgs, + 'First day of no snow, 2018') + +# Define the years to difference. +firstYear = 2005 +secondYear = 2015 + +# Calculate difference image. +firstImg = annualCol.filter(ee.Filter.eq('year', firstYear)) \ + .first().select('calDoy') +secondImg = annualCol.filter(ee.Filter.eq('year', secondYear)) \ + .first().select('calDoy') +dif = secondImg.subtract(firstImg) + +# Define visualization arguments. +visArgs = { + 'min': -15, + 'max': 15, + 'palette': ['b2182b', 'ef8a62', 'fddbc7', 'f7f7f7', 'd1e5f0', + '67a9cf', '2166ac' + ] +} + +# Display it on the map. +Map.setCenter(95.427, 29.552, 8) +Map.addLayer(dif, visArgs, '2015-2005 first day no snow dif') + +# Calculate slope image. +slope = annualCol.sort('year').select(['year', 'calDoy']) \ + .reduce(ee.Reducer.linearFit()).select('scale') + +# Define visualization arguments. +visArgs = { + 'min': -1, + 'max': 1, + 'palette': ['b2182b', 'ef8a62', 'fddbc7', 'f7f7f7', + 'd1e5f0', '67a9cf', '2166ac' + ] +} + +# Display it on the map. +Map.setCenter(11.25, 59.88, 6) +Map.addLayer(slope, visArgs, '2000-2019 first day no snow slope') + +# Define an AOI. +aoi = ee.Geometry.Point(-94.242, 65.79).buffer(1e4) +Map.addLayer(aoi, None, 'Area of interest') + +# Calculate annual mean DOY of AOI. + +def func_xob(img): + summary = img.reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': aoi, + 'scale': 1e3, + 'bestEffort': True, + 'maxPixels': 1e14, + 'tileScale': 4, + }) + return ee.Feature(None, summary).set('year', img.get( + 'year')) + +annualAoiMean = annualCol.select('calDoy').map(func_xob) + + + + + + + + + + + + + +# Print chart to console. +chart = ui.Chart.feature.byFeature(annualAoiMean, 'year', + 'calDoy') \ + .setOptions({ + 'title': 'Regional mean first day of year with no snow cover', + 'legend': { + 'position': 'none' + }, + 'hAxis': { + 'title': 'Year', + format: '####' + }, + 'vAxis': { + 'title': 'Day-of-year' + } + }) +print(chart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31a Checkpoint.ipynb new file mode 100644 index 0000000..346bd18 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31a Checkpoint.ipynb @@ -0,0 +1,361 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.1 Active fire monitoring\n", + "# Checkpoint: A31a\n", + "# Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship)\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "#\n", + " We will use the Bobcat Fire as an example in this practicum.\n", + "\n", + " Bobcat Fire, Los Angeles County, CA\n", + " 'Ignition': Sep 6, 2020\n", + " 'Total burned area': 115796 acres\n", + " 'Lon': -117.868 W, 'Lat': 34.241 N\n", + " 'https':#inciweb.nwcg.gov/incident/7152/\n", + "#\n", + "\n", + "# --------\n", + "# Inputs\n", + "# --------\n", + "\n", + "# Define the location of the fire.\n", + "lon = -117.868\n", + "lat = 34.241\n", + "zoom = 9\n", + "\n", + "# Filter datasets to a specific date range:\n", + "# start date of fire.\n", + "inYear = 2020\n", + "inMonth = 9\n", + "inDay = 6\n", + "\n", + "durationAF = 15; # in days\n", + "durationBA = 1; # in months\n", + "\n", + "# Date range for active fires.\n", + "startDateAF = ee.Date.fromYMD(inYear, inMonth, inDay)\n", + "endDateAF = startDateAF.advance(durationAF, 'day')\n", + "\n", + "# Date range for burned area.\n", + "startDateBA = ee.Date.fromYMD(inYear, inMonth, 1)\n", + "endDateBA = startDateBA.advance(durationBA, 'month')\n", + "\n", + "# -------------------------------\n", + "# 1. Reference Perimeter (WFIGS)\n", + "# -------------------------------\n", + "# Note: each fire has multiple versions, so here we are\n", + "# filtering WFIGS by the name of the fire, sorting the\n", + "# area of the filtered polygons in descending order,\n", + "# and retrieving the polygon with the highest area.\n", + "WFIGS = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-1/WFIGS')\n", + "reference = ee.Feature(WFIGS.filter(ee.Filter.eq('irwin_In_1',\n", + " 'BOBCAT')) \\\n", + " .sort('poly_Acres', False).first())\n", + "\n", + "# -------------------------------\n", + "# 2. MODIS active fire datasets\n", + "# -------------------------------\n", + "# MOD14A1, MYD14A1 = MODIS/Terra and Aqua active fires and thermal anomalies\n", + "# resolution: daily, gridded at 1km in sinusoidal projection (SR-ORG:6974)\n", + "# variables: fire mask (FireMask), fire radiative power in MW (MaxFRP)\n", + "# satellite overpasses: Terra (10:30am/pm local time), Aqua (1:30am/pm local time)\n", + "\n", + "# Define the Earth Engine paths for MOD14A1 and MYD14A1, collection 6.\n", + "mod14a1 = ee.ImageCollection('MODIS/006/MOD14A1')\n", + "myd14a1 = ee.ImageCollection('MODIS/006/MYD14A1')\n", + "\n", + "# Filter the datasets according to the date range.\n", + "mod14a1Img = mod14a1.filterDate(startDateAF, endDateAF)\n", + "myd14a1Img = myd14a1.filterDate(startDateAF, endDateAF)\n", + "\n", + "def getFireMask(image):\n", + " # Fire Mask (FireMask): values \u2265 7 are active fire pixels\n", + " return image.select('FireMask').gte(7)\n", + "\n", + "\n", + "def getMaxFRP(image):\n", + " # FRP (MaxFRP): MaxFRP needs to be scaled by 0.1 to be in units of MW.\n", + " return image.select('MaxFRP').multiply(0.1)\n", + "\n", + "\n", + "# Define the active fire mask (count of active fire pixels).\n", + "mod14a1ImgMask = mod14a1Img.map(getFireMask).sum()\n", + "myd14a1ImgMask = myd14a1Img.map(getFireMask).sum()\n", + "\n", + "# Define the total FRP (MW).\n", + "mod14a1ImgFrp = mod14a1Img.map(getMaxFRP).sum()\n", + "myd14a1ImgFrp = myd14a1Img.map(getMaxFRP).sum()\n", + "\n", + "# ------------------------------\n", + "# 3. MODIS burned area dataset\n", + "# ------------------------------\n", + "# MCD64A1 = MODIS/Terra and Aqua combined burned area\n", + "# resolution: monthly, gridded at 500m in sinusoidal projection (SR-ORG:6974),\n", + "# can be disaggregated to daily resolution\n", + "# variables: burn date as day of year (BurnDate)\n", + "\n", + "# Define the Earth Engine paths for MCD64A1, collection 6.\n", + "mcd64a1 = ee.ImageCollection('MODIS/006/MCD64A1')\n", + "\n", + "def getBurnDate(image):\n", + " # burn day of year (BurnDate)\n", + " return image.select('BurnDate')\n", + "\n", + "\n", + "# Define the burned area mask.\n", + "mcd64a1Img = mcd64a1.filterDate(startDateBA, endDateBA)\n", + "mcd64a1ImgMask = mcd64a1Img.map(getBurnDate).min()\n", + "\n", + "# ------------------------------\n", + "# 4. GOES 16/17 active fires\n", + "# ------------------------------\n", + "# GOES-16/17 - geostationary satellites over North/South America\n", + "# resolution: every 10-30 minutes, 2 km\n", + "# variables: fire mask (Mask), FRP (Power)\n", + "\n", + "# Define the Earth Engine paths for GOES-16/17.\n", + "goes16 = ee.ImageCollection('NOAA/GOES/16/FDCF')\n", + "goes17 = ee.ImageCollection('NOAA/GOES/17/FDCF')\n", + "\n", + "filterGOES = ee.Filter.calendarRange(0, 0, 'minute')\n", + "\n", + "# Filter the datasets according to the date range.\n", + "goes16Img = goes16.filterDate(startDateAF, endDateAF) \\\n", + " .filter(filterGOES)\n", + "goes17Img = goes17.filterDate(startDateAF, endDateAF) \\\n", + " .filter(filterGOES)\n", + "\n", + "def getFireMask(image):\n", + " # fire mask (Mask): values from 10-35 are active fire pixels,\n", + " # see the description for QA values to filter out low confidence fires\n", + " return image.select('Mask').gte(10).And(image.select('Mask') \\\n", + " .lte(35))\n", + "\n", + "\n", + "def getFRP(image):\n", + " # FRP (Power), in MW\n", + " return image.select('Power')\n", + "\n", + "\n", + "# Define the active fire mask (count of active fire pixels).\n", + "goes16ImgMask = goes16Img.map(getFireMask).sum()\n", + "goes17ImgMask = goes17Img.map(getFireMask).sum()\n", + "\n", + "# Define the total FRP (MW).\n", + "goes16ImgFrp = goes16Img.map(getFRP).sum()\n", + "goes17ImgFrp = goes17Img.map(getFRP).sum()\n", + "\n", + "# -------------------------------\n", + "# 5. Map Visualization - Layers\n", + "# -------------------------------\n", + "# Use the 'Layers' dropdown menu on the map panel to toggle on and off layers.\n", + "Map.addLayer(mod14a1ImgMask.selfMask(), {\n", + " 'palette': 'orange'\n", + "}, 'MOD14A1')\n", + "Map.addLayer(myd14a1ImgMask.selfMask(), {\n", + " 'palette': 'red'\n", + "}, 'MYD14A1')\n", + "\n", + "Map.addLayer(mcd64a1ImgMask.selfMask(), {\n", + " 'palette': 'black'\n", + "}, 'MCD64A1')\n", + "\n", + "Map.addLayer(goes16ImgMask.selfMask(), {\n", + " 'palette': 'skyblue'\n", + "}, 'GOES16', False)\n", + "Map.addLayer(goes17ImgMask.selfMask(), {\n", + " 'palette': 'purple'\n", + "}, 'GOES17', False)\n", + "\n", + "Map.setCenter(lon, lat, zoom)\n", + "\n", + "# ------------------------------------\n", + "# 6. Map Visualization - Panel Layout\n", + "# ------------------------------------\n", + "\n", + "# Define the panel layout.\n", + "panelNames = [\n", + " 'MODIS active fires', # panel 0 - top left\n", + " 'MODIS burned area', # panel 1 - bottom left\n", + " 'GOES active fires', # panel 2 - top right\n", + " 'Reference' # panel 3 - bottom right\n", + "]\n", + "\n", + "# Create a map for each visualization option.\n", + "maps = []\n", + "panelNames.forEach(function(name, index) {\n", + " map = ui.Map()\n", + " map.setControlVisibility({\n", + " 'fullscreenControl': False\n", + " })\n", + "\n", + " if (index === 0) {\n", + " map.addLayer(mod14a1ImgMask.selfMask(), {\n", + " 'palette': 'orange'\n", + " }, 'MOD14A1')\n", + " map.addLayer(myd14a1ImgMask.selfMask(), {\n", + " 'palette': 'red'\n", + " }, 'MYD14A1')\n", + " map.add(ui.Label(panelNames[0], {\n", + " 'fontWeight': 'bold',\n", + " 'position': 'bottom-left'\n", + " }))\n", + " }\n", + " if (index == 1) {\n", + " map.addLayer(mcd64a1ImgMask.selfMask(), {\n", + " 'palette': 'black'\n", + " }, 'MCD64A1')\n", + " map.add(ui.Label(panelNames[1], {\n", + " 'fontWeight': 'bold',\n", + " 'position': 'bottom-left'\n", + " }))\n", + " }\n", + " if (index == 2) {\n", + " map.addLayer(goes16ImgMask.selfMask(), {\n", + " 'palette': 'skyblue'\n", + " }, 'GOES16')\n", + " map.addLayer(goes17ImgMask.selfMask(), {\n", + " 'palette': 'purple'\n", + " }, 'GOES17')\n", + " map.add(ui.Label(panelNames[2], {\n", + " 'fontWeight': 'bold',\n", + " 'position': 'bottom-left'\n", + " }))\n", + " }\n", + " if (index == 3) {\n", + " map.addLayer(reference, {}, 'Reference')\n", + " map.add(ui.Label(panelNames[3], {\n", + " 'fontWeight': 'bold',\n", + " 'position': 'bottom-left'\n", + " }))\n", + " }\n", + " maps.push(map)\n", + "})\n", + "\n", + "linker = ui.Map.Linker(maps)\n", + "\n", + "# Make a label for the main title of the app.\n", + "title = ui.Label(\n", + " 'Visualizing Fire Datasets in Google Earth Engine', {\n", + " 'stretch': 'horizontal',\n", + " 'textAlign': 'center',\n", + " 'fontWeight': 'bold',\n", + " 'fontSize': '24px'\n", + " })\n", + "\n", + "# Define a map grid of 2x2 sub panels.\n", + "mapGrid = ui.Panel(\n", + " [\n", + " ui.Panel([maps[0], maps[1]], None, {\n", + " 'stretch': 'both'\n", + " }),\n", + " ui.Panel([maps[2], maps[3]], None, {\n", + " 'stretch': 'both'\n", + " })\n", + " ],\n", + " ui.Panel.Layout.Flow('horizontal'), {\n", + " 'stretch': 'both'\n", + " }\n", + ")\n", + "maps[0].setCenter(lon, lat, zoom)\n", + "\n", + "# Add the maps and title to the ui.root().\n", + "ui.root.widgets().reset([title, mapGrid])\n", + "ui.root.setLayout(ui.Panel.Layout.Flow('vertical'))\n", + "\n", + "# -----------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31a Checkpoint.js new file mode 100644 index 0000000..5f1dc23 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31a Checkpoint.js @@ -0,0 +1,268 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.1 Active fire monitoring +// Checkpoint: A31a +// Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship) +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* + We will use the Bobcat Fire as an example in this practicum. + + Bobcat Fire, Los Angeles County, CA + Ignition: Sep 6, 2020 + Total burned area: 115796 acres + Lon: -117.868 W, Lat: 34.241 N + https://inciweb.nwcg.gov/incident/7152/ +*/ + +// -------- +// Inputs +// -------- + +// Define the location of the fire. +var lon = -117.868; +var lat = 34.241; +var zoom = 9; + +// Filter datasets to a specific date range: +// start date of fire. +var inYear = 2020; +var inMonth = 9; +var inDay = 6; + +var durationAF = 15; // in days +var durationBA = 1; // in months + +// Date range for active fires. +var startDateAF = ee.Date.fromYMD(inYear, inMonth, inDay); +var endDateAF = startDateAF.advance(durationAF, 'day'); + +// Date range for burned area. +var startDateBA = ee.Date.fromYMD(inYear, inMonth, 1); +var endDateBA = startDateBA.advance(durationBA, 'month'); + +// ------------------------------- +// 1. Reference Perimeter (WFIGS) +// ------------------------------- +// Note: each fire has multiple versions, so here we are +// filtering WFIGS by the name of the fire, sorting the +// area of the filtered polygons in descending order, +// and retrieving the polygon with the highest area. +var WFIGS = ee.FeatureCollection( + 'projects/gee-book/assets/A3-1/WFIGS'); +var reference = ee.Feature(WFIGS.filter(ee.Filter.eq('irwin_In_1', + 'BOBCAT')) + .sort('poly_Acres', false).first()); + +// ------------------------------- +// 2. MODIS active fire datasets +// ------------------------------- +// MOD14A1, MYD14A1 = MODIS/Terra and Aqua active fires and thermal anomalies +// resolution: daily, gridded at 1km in sinusoidal projection (SR-ORG:6974) +// variables: fire mask (FireMask), fire radiative power in MW (MaxFRP) +// satellite overpasses: Terra (10:30am/pm local time), Aqua (1:30am/pm local time) + +// Define the Earth Engine paths for MOD14A1 and MYD14A1, collection 6. +var mod14a1 = ee.ImageCollection('MODIS/006/MOD14A1'); +var myd14a1 = ee.ImageCollection('MODIS/006/MYD14A1'); + +// Filter the datasets according to the date range. +var mod14a1Img = mod14a1.filterDate(startDateAF, endDateAF); +var myd14a1Img = myd14a1.filterDate(startDateAF, endDateAF); + +var getFireMask = function(image) { + // Fire Mask (FireMask): values ≥ 7 are active fire pixels + return image.select('FireMask').gte(7); +}; + +var getMaxFRP = function(image) { + // FRP (MaxFRP): MaxFRP needs to be scaled by 0.1 to be in units of MW. + return image.select('MaxFRP').multiply(0.1); +}; + +// Define the active fire mask (count of active fire pixels). +var mod14a1ImgMask = mod14a1Img.map(getFireMask).sum(); +var myd14a1ImgMask = myd14a1Img.map(getFireMask).sum(); + +// Define the total FRP (MW). +var mod14a1ImgFrp = mod14a1Img.map(getMaxFRP).sum(); +var myd14a1ImgFrp = myd14a1Img.map(getMaxFRP).sum(); + +// ------------------------------ +// 3. MODIS burned area dataset +// ------------------------------ +// MCD64A1 = MODIS/Terra and Aqua combined burned area +// resolution: monthly, gridded at 500m in sinusoidal projection (SR-ORG:6974), +// can be disaggregated to daily resolution +// variables: burn date as day of year (BurnDate) + +// Define the Earth Engine paths for MCD64A1, collection 6. +var mcd64a1 = ee.ImageCollection('MODIS/006/MCD64A1'); + +var getBurnDate = function(image) { + // burn day of year (BurnDate) + return image.select('BurnDate'); +}; + +// Define the burned area mask. +var mcd64a1Img = mcd64a1.filterDate(startDateBA, endDateBA); +var mcd64a1ImgMask = mcd64a1Img.map(getBurnDate).min(); + +// ------------------------------ +// 4. GOES 16/17 active fires +// ------------------------------ +// GOES-16/17 - geostationary satellites over North/South America +// resolution: every 10-30 minutes, 2 km +// variables: fire mask (Mask), FRP (Power) + +// Define the Earth Engine paths for GOES-16/17. +var goes16 = ee.ImageCollection('NOAA/GOES/16/FDCF'); +var goes17 = ee.ImageCollection('NOAA/GOES/17/FDCF'); + +var filterGOES = ee.Filter.calendarRange(0, 0, 'minute'); + +// Filter the datasets according to the date range. +var goes16Img = goes16.filterDate(startDateAF, endDateAF) + .filter(filterGOES); +var goes17Img = goes17.filterDate(startDateAF, endDateAF) + .filter(filterGOES); + +var getFireMask = function(image) { + // fire mask (Mask): values from 10-35 are active fire pixels, + // see the description for QA values to filter out low confidence fires + return image.select('Mask').gte(10).and(image.select('Mask') + .lte(35)); +}; + +var getFRP = function(image) { + // FRP (Power), in MW + return image.select('Power'); +}; + +// Define the active fire mask (count of active fire pixels). +var goes16ImgMask = goes16Img.map(getFireMask).sum(); +var goes17ImgMask = goes17Img.map(getFireMask).sum(); + +// Define the total FRP (MW). +var goes16ImgFrp = goes16Img.map(getFRP).sum(); +var goes17ImgFrp = goes17Img.map(getFRP).sum(); + +// ------------------------------- +// 5. Map Visualization - Layers +// ------------------------------- +// Use the 'Layers' dropdown menu on the map panel to toggle on and off layers. +Map.addLayer(mod14a1ImgMask.selfMask(), { + palette: 'orange' +}, 'MOD14A1'); +Map.addLayer(myd14a1ImgMask.selfMask(), { + palette: 'red' +}, 'MYD14A1'); + +Map.addLayer(mcd64a1ImgMask.selfMask(), { + palette: 'black' +}, 'MCD64A1'); + +Map.addLayer(goes16ImgMask.selfMask(), { + palette: 'skyblue' +}, 'GOES16', false); +Map.addLayer(goes17ImgMask.selfMask(), { + palette: 'purple' +}, 'GOES17', false); + +Map.setCenter(lon, lat, zoom); + +// ------------------------------------ +// 6. Map Visualization - Panel Layout +// ------------------------------------ + +// Define the panel layout. +var panelNames = [ + 'MODIS active fires', // panel 0 - top left + 'MODIS burned area', // panel 1 - bottom left + 'GOES active fires', // panel 2 - top right + 'Reference' // panel 3 - bottom right +]; + +// Create a map for each visualization option. +var maps = []; +panelNames.forEach(function(name, index) { + var map = ui.Map(); + map.setControlVisibility({ + fullscreenControl: false + }); + + if (index === 0) { + map.addLayer(mod14a1ImgMask.selfMask(), { + palette: 'orange' + }, 'MOD14A1'); + map.addLayer(myd14a1ImgMask.selfMask(), { + palette: 'red' + }, 'MYD14A1'); + map.add(ui.Label(panelNames[0], { + fontWeight: 'bold', + position: 'bottom-left' + })); + } + if (index == 1) { + map.addLayer(mcd64a1ImgMask.selfMask(), { + palette: 'black' + }, 'MCD64A1'); + map.add(ui.Label(panelNames[1], { + fontWeight: 'bold', + position: 'bottom-left' + })); + } + if (index == 2) { + map.addLayer(goes16ImgMask.selfMask(), { + palette: 'skyblue' + }, 'GOES16'); + map.addLayer(goes17ImgMask.selfMask(), { + palette: 'purple' + }, 'GOES17'); + map.add(ui.Label(panelNames[2], { + fontWeight: 'bold', + position: 'bottom-left' + })); + } + if (index == 3) { + map.addLayer(reference, {}, 'Reference'); + map.add(ui.Label(panelNames[3], { + fontWeight: 'bold', + position: 'bottom-left' + })); + } + maps.push(map); +}); + +var linker = ui.Map.Linker(maps); + +// Make a label for the main title of the app. +var title = ui.Label( + 'Visualizing Fire Datasets in Google Earth Engine', { + stretch: 'horizontal', + textAlign: 'center', + fontWeight: 'bold', + fontSize: '24px' + }); + +// Define a map grid of 2x2 sub panels. +var mapGrid = ui.Panel( + [ + ui.Panel([maps[0], maps[1]], null, { + stretch: 'both' + }), + ui.Panel([maps[2], maps[3]], null, { + stretch: 'both' + }) + ], + ui.Panel.Layout.Flow('horizontal'), { + stretch: 'both' + } +); +maps[0].setCenter(lon, lat, zoom); + +// Add the maps and title to the ui.root(). +ui.root.widgets().reset([title, mapGrid]); +ui.root.setLayout(ui.Panel.Layout.Flow('vertical')); + +// ----------------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31a Checkpoint.py new file mode 100644 index 0000000..fe1e091 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31a Checkpoint.py @@ -0,0 +1,274 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.1 Active fire monitoring +# Checkpoint: A31a +# Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# + We will use the Bobcat Fire as an example in this practicum. + + Bobcat Fire, Los Angeles County, CA + 'Ignition': Sep 6, 2020 + 'Total burned area': 115796 acres + 'Lon': -117.868 W, 'Lat': 34.241 N + 'https':#inciweb.nwcg.gov/incident/7152/ +# + +# -------- +# Inputs +# -------- + +# Define the location of the fire. +lon = -117.868 +lat = 34.241 +zoom = 9 + +# Filter datasets to a specific date range: +# start date of fire. +inYear = 2020 +inMonth = 9 +inDay = 6 + +durationAF = 15; # in days +durationBA = 1; # in months + +# Date range for active fires. +startDateAF = ee.Date.fromYMD(inYear, inMonth, inDay) +endDateAF = startDateAF.advance(durationAF, 'day') + +# Date range for burned area. +startDateBA = ee.Date.fromYMD(inYear, inMonth, 1) +endDateBA = startDateBA.advance(durationBA, 'month') + +# ------------------------------- +# 1. Reference Perimeter (WFIGS) +# ------------------------------- +# Note: each fire has multiple versions, so here we are +# filtering WFIGS by the name of the fire, sorting the +# area of the filtered polygons in descending order, +# and retrieving the polygon with the highest area. +WFIGS = ee.FeatureCollection( + 'projects/gee-book/assets/A3-1/WFIGS') +reference = ee.Feature(WFIGS.filter(ee.Filter.eq('irwin_In_1', + 'BOBCAT')) \ + .sort('poly_Acres', False).first()) + +# ------------------------------- +# 2. MODIS active fire datasets +# ------------------------------- +# MOD14A1, MYD14A1 = MODIS/Terra and Aqua active fires and thermal anomalies +# resolution: daily, gridded at 1km in sinusoidal projection (SR-ORG:6974) +# variables: fire mask (FireMask), fire radiative power in MW (MaxFRP) +# satellite overpasses: Terra (10:30am/pm local time), Aqua (1:30am/pm local time) + +# Define the Earth Engine paths for MOD14A1 and MYD14A1, collection 6. +mod14a1 = ee.ImageCollection('MODIS/006/MOD14A1') +myd14a1 = ee.ImageCollection('MODIS/006/MYD14A1') + +# Filter the datasets according to the date range. +mod14a1Img = mod14a1.filterDate(startDateAF, endDateAF) +myd14a1Img = myd14a1.filterDate(startDateAF, endDateAF) + +def getFireMask(image): + # Fire Mask (FireMask): values ≥ 7 are active fire pixels + return image.select('FireMask').gte(7) + + +def getMaxFRP(image): + # FRP (MaxFRP): MaxFRP needs to be scaled by 0.1 to be in units of MW. + return image.select('MaxFRP').multiply(0.1) + + +# Define the active fire mask (count of active fire pixels). +mod14a1ImgMask = mod14a1Img.map(getFireMask).sum() +myd14a1ImgMask = myd14a1Img.map(getFireMask).sum() + +# Define the total FRP (MW). +mod14a1ImgFrp = mod14a1Img.map(getMaxFRP).sum() +myd14a1ImgFrp = myd14a1Img.map(getMaxFRP).sum() + +# ------------------------------ +# 3. MODIS burned area dataset +# ------------------------------ +# MCD64A1 = MODIS/Terra and Aqua combined burned area +# resolution: monthly, gridded at 500m in sinusoidal projection (SR-ORG:6974), +# can be disaggregated to daily resolution +# variables: burn date as day of year (BurnDate) + +# Define the Earth Engine paths for MCD64A1, collection 6. +mcd64a1 = ee.ImageCollection('MODIS/006/MCD64A1') + +def getBurnDate(image): + # burn day of year (BurnDate) + return image.select('BurnDate') + + +# Define the burned area mask. +mcd64a1Img = mcd64a1.filterDate(startDateBA, endDateBA) +mcd64a1ImgMask = mcd64a1Img.map(getBurnDate).min() + +# ------------------------------ +# 4. GOES 16/17 active fires +# ------------------------------ +# GOES-16/17 - geostationary satellites over North/South America +# resolution: every 10-30 minutes, 2 km +# variables: fire mask (Mask), FRP (Power) + +# Define the Earth Engine paths for GOES-16/17. +goes16 = ee.ImageCollection('NOAA/GOES/16/FDCF') +goes17 = ee.ImageCollection('NOAA/GOES/17/FDCF') + +filterGOES = ee.Filter.calendarRange(0, 0, 'minute') + +# Filter the datasets according to the date range. +goes16Img = goes16.filterDate(startDateAF, endDateAF) \ + .filter(filterGOES) +goes17Img = goes17.filterDate(startDateAF, endDateAF) \ + .filter(filterGOES) + +def getFireMask(image): + # fire mask (Mask): values from 10-35 are active fire pixels, + # see the description for QA values to filter out low confidence fires + return image.select('Mask').gte(10).And(image.select('Mask') \ + .lte(35)) + + +def getFRP(image): + # FRP (Power), in MW + return image.select('Power') + + +# Define the active fire mask (count of active fire pixels). +goes16ImgMask = goes16Img.map(getFireMask).sum() +goes17ImgMask = goes17Img.map(getFireMask).sum() + +# Define the total FRP (MW). +goes16ImgFrp = goes16Img.map(getFRP).sum() +goes17ImgFrp = goes17Img.map(getFRP).sum() + +# ------------------------------- +# 5. Map Visualization - Layers +# ------------------------------- +# Use the 'Layers' dropdown menu on the map panel to toggle on and off layers. +Map.addLayer(mod14a1ImgMask.selfMask(), { + 'palette': 'orange' +}, 'MOD14A1') +Map.addLayer(myd14a1ImgMask.selfMask(), { + 'palette': 'red' +}, 'MYD14A1') + +Map.addLayer(mcd64a1ImgMask.selfMask(), { + 'palette': 'black' +}, 'MCD64A1') + +Map.addLayer(goes16ImgMask.selfMask(), { + 'palette': 'skyblue' +}, 'GOES16', False) +Map.addLayer(goes17ImgMask.selfMask(), { + 'palette': 'purple' +}, 'GOES17', False) + +Map.setCenter(lon, lat, zoom) + +# ------------------------------------ +# 6. Map Visualization - Panel Layout +# ------------------------------------ + +# Define the panel layout. +panelNames = [ + 'MODIS active fires', # panel 0 - top left + 'MODIS burned area', # panel 1 - bottom left + 'GOES active fires', # panel 2 - top right + 'Reference' # panel 3 - bottom right +] + +# Create a map for each visualization option. +maps = [] +panelNames.forEach(function(name, index) { + map = ui.Map() + map.setControlVisibility({ + 'fullscreenControl': False + }) + + if (index === 0) { + map.addLayer(mod14a1ImgMask.selfMask(), { + 'palette': 'orange' + }, 'MOD14A1') + map.addLayer(myd14a1ImgMask.selfMask(), { + 'palette': 'red' + }, 'MYD14A1') + map.add(ui.Label(panelNames[0], { + 'fontWeight': 'bold', + 'position': 'bottom-left' + })) + } + if (index == 1) { + map.addLayer(mcd64a1ImgMask.selfMask(), { + 'palette': 'black' + }, 'MCD64A1') + map.add(ui.Label(panelNames[1], { + 'fontWeight': 'bold', + 'position': 'bottom-left' + })) + } + if (index == 2) { + map.addLayer(goes16ImgMask.selfMask(), { + 'palette': 'skyblue' + }, 'GOES16') + map.addLayer(goes17ImgMask.selfMask(), { + 'palette': 'purple' + }, 'GOES17') + map.add(ui.Label(panelNames[2], { + 'fontWeight': 'bold', + 'position': 'bottom-left' + })) + } + if (index == 3) { + map.addLayer(reference, {}, 'Reference') + map.add(ui.Label(panelNames[3], { + 'fontWeight': 'bold', + 'position': 'bottom-left' + })) + } + maps.push(map) +}) + +linker = ui.Map.Linker(maps) + +# Make a label for the main title of the app. +title = ui.Label( + 'Visualizing Fire Datasets in Google Earth Engine', { + 'stretch': 'horizontal', + 'textAlign': 'center', + 'fontWeight': 'bold', + 'fontSize': '24px' + }) + +# Define a map grid of 2x2 sub panels. +mapGrid = ui.Panel( + [ + ui.Panel([maps[0], maps[1]], None, { + 'stretch': 'both' + }), + ui.Panel([maps[2], maps[3]], None, { + 'stretch': 'both' + }) + ], + ui.Panel.Layout.Flow('horizontal'), { + 'stretch': 'both' + } +) +maps[0].setCenter(lon, lat, zoom) + +# Add the maps and title to the ui.root(). +ui.root.widgets().reset([title, mapGrid]) +ui.root.setLayout(ui.Panel.Layout.Flow('vertical')) + +# ----------------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31b Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31b Checkpoint.ipynb new file mode 100644 index 0000000..c3016b3 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31b Checkpoint.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.1 Active fire monitoring\n", + "# Checkpoint: A31b\n", + "# Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship)\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "Bobcat Fire in the Earth Engine app FIRMS Active Fires (\n", + "\n", + " 'https':#globalfires.earthengine.app/view/firms\n", + "\n", + ").\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31b Checkpoint.js new file mode 100644 index 0000000..5618e63 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31b Checkpoint.js @@ -0,0 +1,12 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.1 Active fire monitoring +// Checkpoint: A31b +// Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship) +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bobcat Fire in the Earth Engine app FIRMS Active Fires ( + + https://globalfires.earthengine.app/view/firms + +). + diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31b Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31b Checkpoint.py new file mode 100644 index 0000000..859ea57 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31b Checkpoint.py @@ -0,0 +1,18 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.1 Active fire monitoring +# Checkpoint: A31b +# Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bobcat Fire in the Earth Engine app FIRMS Active Fires ( + + 'https':#globalfires.earthengine.app/view/firms + +). + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31c Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31c Checkpoint.ipynb new file mode 100644 index 0000000..bbc3f36 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31c Checkpoint.ipynb @@ -0,0 +1,102 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.1 Active fire monitoring\n", + "# Checkpoint: A31c\n", + "# Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship)\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "'Your app should now look like this (click the Submit button)':\n", + "\n", + "'https':#bit.ly/FIRMS_Bobcat.\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31c Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31c Checkpoint.js new file mode 100644 index 0000000..ee238af --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31c Checkpoint.js @@ -0,0 +1,10 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.1 Active fire monitoring +// Checkpoint: A31c +// Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship) +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Your app should now look like this (click the Submit button): + +https://bit.ly/FIRMS_Bobcat. + \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31c Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31c Checkpoint.py new file mode 100644 index 0000000..b775363 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31c Checkpoint.py @@ -0,0 +1,16 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.1 Active fire monitoring +# Checkpoint: A31c +# Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +'Your app should now look like this (click the Submit button)': + +'https':#bit.ly/FIRMS_Bobcat. + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31d Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31d Checkpoint.ipynb new file mode 100644 index 0000000..c1afce0 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31d Checkpoint.ipynb @@ -0,0 +1,105 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.1 Active fire monitoring\n", + "# Checkpoint: A31d\n", + "# Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship)\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "\n", + "the Earth Engine app U.S. Fire Dashboard (\n", + "\n", + " 'https':#globalfires.earthengine.app/view/us-fire-dashboard\n", + "\n", + ")." + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31d Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31d Checkpoint.js new file mode 100644 index 0000000..4d09550 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31d Checkpoint.js @@ -0,0 +1,12 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.1 Active fire monitoring +// Checkpoint: A31d +// Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship) +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +the Earth Engine app U.S. Fire Dashboard ( + + https://globalfires.earthengine.app/view/us-fire-dashboard + +). \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31d Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31d Checkpoint.py new file mode 100644 index 0000000..268b101 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.1 Active Fire Monitoring/A31d Checkpoint.py @@ -0,0 +1,18 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.1 Active fire monitoring +# Checkpoint: A31d +# Authors: Morgan A. Crowley* and Tianjia Liu* (*shared first-authorship) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +the Earth Engine app U.S. Fire Dashboard ( + + 'https':#globalfires.earthengine.app/view/us-fire-dashboard + +). +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310a Checkpoint.ipynb new file mode 100644 index 0000000..cca7988 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310a Checkpoint.ipynb @@ -0,0 +1,165 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: Chapter A3.10 Conservation II - Assessing Agricultural\n", + "# Intensification Near Protected Areas\n", + "# Checkpoint: A310a\n", + "# Authors: Pradeep Koulgi, MD Madhusudan\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# 1. Parameters to function calls\n", + "\n", + "# 1.1. Annual dry season max NDVI calculation\n", + "modis_veg = ee.ImageCollection('MODIS/006/MOD13Q1')\n", + "ndviBandName = 'NDVI'\n", + "ndviValuesScaling = 0.0001\n", + "modisVegScale = 250; # meters\n", + "maxNDVIBandname = 'max_dryseason_ndvi'\n", + "yearTimestampBandname = 'year'\n", + "years = ee.List.sequence(2000, 2021, 1)\n", + "drySeasonStart_doy = 1\n", + "drySeasonEnd_doy = 90\n", + "\n", + "# 1.2. Boundaries of Protected Areas of interest\n", + "paBoundaries = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-10/IndiaMainlandPAs')\n", + "boundaryBufferWidth = 5000; # meters\n", + "bufferingMaxError = 30; # meters\n", + "# Choose PAs in only the western states\n", + "western_states = [\n", + " 'Rajasthan', 'Gujarat', 'Madhya Pradesh',\n", + " 'Maharashtra', 'Goa', 'Karnataka', 'Kerala'\n", + "]\n", + "western_pas = paBoundaries \\\n", + " .filter(ee.Filter.inList('STATE', western_states))\n", + "\n", + "# 1.3. Regression analysis\n", + "regressionReducer = ee.Reducer.sensSlope()\n", + "regressionX = yearTimestampBandname\n", + "regressionY = maxNDVIBandname\n", + "\n", + "# 1.4. Surface water layer to mask water pixels from assessment\n", + "# Selects pixels where water has ever been detected between 1984 and 2021\n", + "surfaceWaterExtent = ee.Image('JRC/GSW1_3/GlobalSurfaceWater') \\\n", + " .select('max_extent')\n", + "\n", + "# 1.5. Average annual precipitation layer\n", + "rainfall = ee.Image('WORLDCLIM/V1/BIO').select('bio12')\n", + "\n", + "# 1.6. Visualization parameters\n", + "regressionResultVisParams = {\n", + " 'min': -3,\n", + " 'max': 3,\n", + " 'palette': ['ff8202', 'ffffff', '356e02']\n", + "}\n", + "regressionSummaryChartingOptions = {\n", + " 'title': 'Yearly change in dry-season vegetation greenness ' + \\\n", + " 'in PA buffers in relation to average annual rainfall',\n", + " 'hAxis': {\n", + " 'title': 'Annual Precipitation'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Median % yearly change in vegetation greenness ' + \\\n", + " 'in 5 km buffer'\n", + " },\n", + " 'series': {\n", + " '0': {\n", + " 'visibleInLegend': False\n", + " }\n", + " },\n", + "}\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310a Checkpoint.js new file mode 100644 index 0000000..235ec33 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310a Checkpoint.js @@ -0,0 +1,72 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: Chapter A3.10 Conservation II - Assessing Agricultural +// Intensification Near Protected Areas +// Checkpoint: A310a +// Authors: Pradeep Koulgi, MD Madhusudan +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// 1. Parameters to function calls + +// 1.1. Annual dry season max NDVI calculation +var modis_veg = ee.ImageCollection('MODIS/006/MOD13Q1'); +var ndviBandName = 'NDVI'; +var ndviValuesScaling = 0.0001; +var modisVegScale = 250; // meters +var maxNDVIBandname = 'max_dryseason_ndvi'; +var yearTimestampBandname = 'year'; +var years = ee.List.sequence(2000, 2021, 1); +var drySeasonStart_doy = 1; +var drySeasonEnd_doy = 90; + +// 1.2. Boundaries of Protected Areas of interest +var paBoundaries = ee.FeatureCollection( + 'projects/gee-book/assets/A3-10/IndiaMainlandPAs'); +var boundaryBufferWidth = 5000; // meters +var bufferingMaxError = 30; // meters +// Choose PAs in only the western states +var western_states = [ + 'Rajasthan', 'Gujarat', 'Madhya Pradesh', + 'Maharashtra', 'Goa', 'Karnataka', 'Kerala' +]; +var western_pas = paBoundaries + .filter(ee.Filter.inList('STATE', western_states)); + +// 1.3. Regression analysis +var regressionReducer = ee.Reducer.sensSlope(); +var regressionX = yearTimestampBandname; +var regressionY = maxNDVIBandname; + +// 1.4. Surface water layer to mask water pixels from assessment +// Selects pixels where water has ever been detected between 1984 and 2021 +var surfaceWaterExtent = ee.Image('JRC/GSW1_3/GlobalSurfaceWater') + .select('max_extent'); + +// 1.5. Average annual precipitation layer +var rainfall = ee.Image('WORLDCLIM/V1/BIO').select('bio12'); + +// 1.6. Visualization parameters +var regressionResultVisParams = { + min: -3, + max: 3, + palette: ['ff8202', 'ffffff', '356e02'] +}; +var regressionSummaryChartingOptions = { + title: 'Yearly change in dry-season vegetation greenness ' + + 'in PA buffers in relation to average annual rainfall', + hAxis: { + title: 'Annual Precipitation' + }, + vAxis: { + title: 'Median % yearly change in vegetation greenness ' + + 'in 5 km buffer' + }, + series: { + 0: { + visibleInLegend: false + } + }, +}; + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310a Checkpoint.py new file mode 100644 index 0000000..66b68e1 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310a Checkpoint.py @@ -0,0 +1,78 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: Chapter A3.10 Conservation II - Assessing Agricultural +# Intensification Near Protected Areas +# Checkpoint: A310a +# Authors: Pradeep Koulgi, MD Madhusudan +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# 1. Parameters to function calls + +# 1.1. Annual dry season max NDVI calculation +modis_veg = ee.ImageCollection('MODIS/006/MOD13Q1') +ndviBandName = 'NDVI' +ndviValuesScaling = 0.0001 +modisVegScale = 250; # meters +maxNDVIBandname = 'max_dryseason_ndvi' +yearTimestampBandname = 'year' +years = ee.List.sequence(2000, 2021, 1) +drySeasonStart_doy = 1 +drySeasonEnd_doy = 90 + +# 1.2. Boundaries of Protected Areas of interest +paBoundaries = ee.FeatureCollection( + 'projects/gee-book/assets/A3-10/IndiaMainlandPAs') +boundaryBufferWidth = 5000; # meters +bufferingMaxError = 30; # meters +# Choose PAs in only the western states +western_states = [ + 'Rajasthan', 'Gujarat', 'Madhya Pradesh', + 'Maharashtra', 'Goa', 'Karnataka', 'Kerala' +] +western_pas = paBoundaries \ + .filter(ee.Filter.inList('STATE', western_states)) + +# 1.3. Regression analysis +regressionReducer = ee.Reducer.sensSlope() +regressionX = yearTimestampBandname +regressionY = maxNDVIBandname + +# 1.4. Surface water layer to mask water pixels from assessment +# Selects pixels where water has ever been detected between 1984 and 2021 +surfaceWaterExtent = ee.Image('JRC/GSW1_3/GlobalSurfaceWater') \ + .select('max_extent') + +# 1.5. Average annual precipitation layer +rainfall = ee.Image('WORLDCLIM/V1/BIO').select('bio12') + +# 1.6. Visualization parameters +regressionResultVisParams = { + 'min': -3, + 'max': 3, + 'palette': ['ff8202', 'ffffff', '356e02'] +} +regressionSummaryChartingOptions = { + 'title': 'Yearly change in dry-season vegetation greenness ' + \ + 'in PA buffers in relation to average annual rainfall', + 'hAxis': { + 'title': 'Annual Precipitation' + }, + 'vAxis': { + 'title': 'Median % yearly change in vegetation greenness ' + \ + 'in 5 km buffer' + }, + 'series': { + '0': { + 'visibleInLegend': False + } + }, +} + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310b Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310b Checkpoint.ipynb new file mode 100644 index 0000000..60455b1 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310b Checkpoint.ipynb @@ -0,0 +1,248 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: Chapter A3.10 Conservation II - Assessing Agricultural\n", + "# Intensification Near Protected Areas\n", + "# Checkpoint: A310b\n", + "# Authors: Pradeep Koulgi, MD Madhusudan\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# 1. Parameters to function calls\n", + "\n", + "# 1.1. Annual dry season max NDVI calculation\n", + "modis_veg = ee.ImageCollection('MODIS/006/MOD13Q1')\n", + "ndviBandName = 'NDVI'\n", + "ndviValuesScaling = 0.0001\n", + "modisVegScale = 250; # meters\n", + "maxNDVIBandname = 'max_dryseason_ndvi'\n", + "yearTimestampBandname = 'year'\n", + "years = ee.List.sequence(2000, 2021, 1)\n", + "drySeasonStart_doy = 1\n", + "drySeasonEnd_doy = 90\n", + "\n", + "# 1.2. Boundaries of Protected Areas of interest\n", + "paBoundaries = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-10/IndiaMainlandPAs')\n", + "boundaryBufferWidth = 5000; # meters\n", + "bufferingMaxError = 30; # meters\n", + "# Choose PAs in only the western states\n", + "western_states = [\n", + " 'Rajasthan', 'Gujarat', 'Madhya Pradesh',\n", + " 'Maharashtra', 'Goa', 'Karnataka', 'Kerala'\n", + "]\n", + "western_pas = paBoundaries \\\n", + " .filter(ee.Filter.inList('STATE', western_states))\n", + "\n", + "# 1.3. Regression analysis\n", + "regressionReducer = ee.Reducer.sensSlope()\n", + "regressionX = yearTimestampBandname\n", + "regressionY = maxNDVIBandname\n", + "\n", + "# 1.4. Surface water layer to mask water pixels from assessment\n", + "# Selects pixels where water has ever been detected between 1984 and 2021\n", + "surfaceWaterExtent = ee.Image('JRC/GSW1_3/GlobalSurfaceWater') \\\n", + " .select('max_extent')\n", + "\n", + "# 1.5. Average annual precipitation layer\n", + "rainfall = ee.Image('WORLDCLIM/V1/BIO').select('bio12')\n", + "\n", + "# 1.6. Visualization parameters\n", + "regressionResultVisParams = {\n", + " 'min': -3,\n", + " 'max': 3,\n", + " 'palette': ['ff8202', 'ffffff', '356e02']\n", + "}\n", + "regressionSummaryChartingOptions = {\n", + " 'title': 'Yearly change in dry-season vegetation greenness ' + \\\n", + " 'in PA buffers in relation to average annual rainfall',\n", + " 'hAxis': {\n", + " 'title': 'Annual Precipitation'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Median % yearly change in vegetation greenness ' + \\\n", + " 'in 5 km buffer'\n", + " },\n", + " 'series': {\n", + " '0': {\n", + " 'visibleInLegend': False\n", + " }\n", + " },\n", + "}\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# 2. Raster processing for change analysis\n", + "\n", + "# Defining functions to be used in this script\n", + "\n", + "# 2.1. Annual dry season maxima of NDVI\n", + "\n", + "def annualDrySeasonMaximumNDVIAndTime(y):\n", + " # Convert year y to a date object\n", + " yDate = ee.Date.fromYMD(y, 1, 1)\n", + " # Calculate max NDVI for year y\n", + " yMaxNdvi = drySeasonNdviColl \\\n", + " .filter(ee.Filter.date(yDate, yDate.advance(1, 'year'))) \\\n", + " .max()\n", + " # Apply appropriate scale, as per the dataset's \\\n", + " .multiply(ndviValuesScaling) \\\n", + " .rename(maxNDVIBandname)\n", + " # Create an image with constant value y, to be used in regression. Name it something comprehensible.\n", + " # Name it something comprehensible.\n", + " yTime = ee.Image.constant(y).int().rename(\n", + " yearTimestampBandname)\n", + " # Combine the two images into a single 2-band image, and return\n", + " return ee.Image.cat([yMaxNdvi, yTime]).set('year', y)\n", + "\n", + "\n", + "# Create a collection of annual dry season maxima\n", + "# for the years of interest. Select the NDVI band and\n", + "# filter to the collection of dry season observations.\n", + "drySeasonNdviColl = modis_veg.select([ndviBandName]) \\\n", + " .filter(ee.Filter.calendarRange(drySeasonStart_doy,\n", + " drySeasonEnd_doy, 'day_of_year'))\n", + "# For each year of interest, calculate the NDVI maxima and create a corresponding time band\n", + "dryseason_coll = ee.ImageCollection.fromImages(\n", + " years.map(annualDrySeasonMaximumNDVIAndTime)\n", + ")\n", + "\n", + "# 2.2. Annual regression to estimate average yearly change in greenness\n", + "\n", + "ss = dryseason_coll.select([regressionX, regressionY]).reduce(\n", + " regressionReducer)\n", + "\n", + "# Mask surface water from vegetation change image\n", + "ss = ss.updateMask(surfaceWaterExtent.eq(0))\n", + "\n", + "# 2.3. Summarise estimates of change in buffer regions of PAs of interest\n", + "def extractBufferRegion(pa):\n", + " #reduce vertices in PA boundary\n", + " pa = pa.simplify({\n", + " 'maxError': 100\n", + " })\n", + " # Extend boundary into its buffer\n", + " withBuffer = pa.buffer(boundaryBufferWidth,\n", + " bufferingMaxError)\n", + " # Compute the buffer-only region by \"subtracting\" boundary with buffer from boundary\n", + " # Subtracting the whole set of boundaries eliminates inclusion of forests from adjacent PAs into buffers.\n", + " bufferOnly = withBuffer.difference(paBoundaries.geometry())\n", + "\n", + " return bufferOnly\n", + "\n", + "\n", + "# Create buffer regions of PAs\n", + "pa_buff = western_pas.map(extractBufferRegion)\n", + "\n", + "# Normalize the metric of NDVI change to a baseline (dry-season max NDVI in the very first year)\n", + "baselineNdvi = dryseason_coll.select([maxNDVIBandname]).filter(ee \\\n", + " .Filter.eq('year', years.getNumber(0))).first()\n", + "stats = ss.select('slope').divide(baselineNdvi).multiply(100) \\\n", + " .rename('vegchange')\n", + "\n", + "# Combine it with average annual rainfall data\n", + "stats = stats.addBands(rainfall.rename('rainfall'))\n", + "\n", + "# Calculate mean of change metric over buffer regions of each PA of interest\n", + "paBufferwiseMedianChange = stats.reduceRegions({\n", + " 'collection': pa_buff,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'scale': 1000,\n", + " 'tileScale': 16\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310b Checkpoint.js new file mode 100644 index 0000000..1a45d8b --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310b Checkpoint.js @@ -0,0 +1,159 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: Chapter A3.10 Conservation II - Assessing Agricultural +// Intensification Near Protected Areas +// Checkpoint: A310b +// Authors: Pradeep Koulgi, MD Madhusudan +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// 1. Parameters to function calls + +// 1.1. Annual dry season max NDVI calculation +var modis_veg = ee.ImageCollection('MODIS/006/MOD13Q1'); +var ndviBandName = 'NDVI'; +var ndviValuesScaling = 0.0001; +var modisVegScale = 250; // meters +var maxNDVIBandname = 'max_dryseason_ndvi'; +var yearTimestampBandname = 'year'; +var years = ee.List.sequence(2000, 2021, 1); +var drySeasonStart_doy = 1; +var drySeasonEnd_doy = 90; + +// 1.2. Boundaries of Protected Areas of interest +var paBoundaries = ee.FeatureCollection( + 'projects/gee-book/assets/A3-10/IndiaMainlandPAs'); +var boundaryBufferWidth = 5000; // meters +var bufferingMaxError = 30; // meters +// Choose PAs in only the western states +var western_states = [ + 'Rajasthan', 'Gujarat', 'Madhya Pradesh', + 'Maharashtra', 'Goa', 'Karnataka', 'Kerala' +]; +var western_pas = paBoundaries + .filter(ee.Filter.inList('STATE', western_states)); + +// 1.3. Regression analysis +var regressionReducer = ee.Reducer.sensSlope(); +var regressionX = yearTimestampBandname; +var regressionY = maxNDVIBandname; + +// 1.4. Surface water layer to mask water pixels from assessment +// Selects pixels where water has ever been detected between 1984 and 2021 +var surfaceWaterExtent = ee.Image('JRC/GSW1_3/GlobalSurfaceWater') + .select('max_extent'); + +// 1.5. Average annual precipitation layer +var rainfall = ee.Image('WORLDCLIM/V1/BIO').select('bio12'); + +// 1.6. Visualization parameters +var regressionResultVisParams = { + min: -3, + max: 3, + palette: ['ff8202', 'ffffff', '356e02'] +}; +var regressionSummaryChartingOptions = { + title: 'Yearly change in dry-season vegetation greenness ' + + 'in PA buffers in relation to average annual rainfall', + hAxis: { + title: 'Annual Precipitation' + }, + vAxis: { + title: 'Median % yearly change in vegetation greenness ' + + 'in 5 km buffer' + }, + series: { + 0: { + visibleInLegend: false + } + }, +}; + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// 2. Raster processing for change analysis + +// Defining functions to be used in this script + +// 2.1. Annual dry season maxima of NDVI + +function annualDrySeasonMaximumNDVIAndTime(y) { + // Convert year y to a date object + var yDate = ee.Date.fromYMD(y, 1, 1); + // Calculate max NDVI for year y + var yMaxNdvi = drySeasonNdviColl + // Filter to year y + .filter(ee.Filter.date(yDate, yDate.advance(1, 'year'))) + // Compute max value + .max() + // Apply appropriate scale, as per the dataset's + // technical description for NDVI band. + .multiply(ndviValuesScaling) + // rename the band to be more comprehensible + .rename(maxNDVIBandname); + // Create an image with constant value y, to be used in regression. Name it something comprehensible. + // Name it something comprehensible. + var yTime = ee.Image.constant(y).int().rename( + yearTimestampBandname); + // Combine the two images into a single 2-band image, and return + return ee.Image.cat([yMaxNdvi, yTime]).set('year', y); +} + +// Create a collection of annual dry season maxima +// for the years of interest. Select the NDVI band and +// filter to the collection of dry season observations. +var drySeasonNdviColl = modis_veg.select([ndviBandName]) + .filter(ee.Filter.calendarRange(drySeasonStart_doy, + drySeasonEnd_doy, 'day_of_year')); +// For each year of interest, calculate the NDVI maxima and create a corresponding time band +var dryseason_coll = ee.ImageCollection.fromImages( + years.map(annualDrySeasonMaximumNDVIAndTime) +); + +// 2.2. Annual regression to estimate average yearly change in greenness + +var ss = dryseason_coll.select([regressionX, regressionY]).reduce( + regressionReducer); + +// Mask surface water from vegetation change image +var ss = ss.updateMask(surfaceWaterExtent.eq(0)); + +// 2.3. Summarise estimates of change in buffer regions of PAs of interest +function extractBufferRegion(pa) { + //reduce vertices in PA boundary + pa = pa.simplify({ + maxError: 100 + }); + // Extend boundary into its buffer + var withBuffer = pa.buffer(boundaryBufferWidth, + bufferingMaxError); + // Compute the buffer-only region by "subtracting" boundary with buffer from boundary + // Subtracting the whole set of boundaries eliminates inclusion of forests from adjacent PAs into buffers. + var bufferOnly = withBuffer.difference(paBoundaries.geometry()); + + return bufferOnly; +} + +// Create buffer regions of PAs +var pa_buff = western_pas.map(extractBufferRegion); + +// Normalize the metric of NDVI change to a baseline (dry-season max NDVI in the very first year) +var baselineNdvi = dryseason_coll.select([maxNDVIBandname]).filter(ee + .Filter.eq('year', years.getNumber(0))).first(); +var stats = ss.select('slope').divide(baselineNdvi).multiply(100) + .rename('vegchange'); + +// Combine it with average annual rainfall data +stats = stats.addBands(rainfall.rename('rainfall')); + +// Calculate mean of change metric over buffer regions of each PA of interest +var paBufferwiseMedianChange = stats.reduceRegions({ + collection: pa_buff, + reducer: ee.Reducer.median(), + scale: 1000, + tileScale: 16 +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310b Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310b Checkpoint.py new file mode 100644 index 0000000..2a43867 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310b Checkpoint.py @@ -0,0 +1,161 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: Chapter A3.10 Conservation II - Assessing Agricultural +# Intensification Near Protected Areas +# Checkpoint: A310b +# Authors: Pradeep Koulgi, MD Madhusudan +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# 1. Parameters to function calls + +# 1.1. Annual dry season max NDVI calculation +modis_veg = ee.ImageCollection('MODIS/006/MOD13Q1') +ndviBandName = 'NDVI' +ndviValuesScaling = 0.0001 +modisVegScale = 250; # meters +maxNDVIBandname = 'max_dryseason_ndvi' +yearTimestampBandname = 'year' +years = ee.List.sequence(2000, 2021, 1) +drySeasonStart_doy = 1 +drySeasonEnd_doy = 90 + +# 1.2. Boundaries of Protected Areas of interest +paBoundaries = ee.FeatureCollection( + 'projects/gee-book/assets/A3-10/IndiaMainlandPAs') +boundaryBufferWidth = 5000; # meters +bufferingMaxError = 30; # meters +# Choose PAs in only the western states +western_states = [ + 'Rajasthan', 'Gujarat', 'Madhya Pradesh', + 'Maharashtra', 'Goa', 'Karnataka', 'Kerala' +] +western_pas = paBoundaries \ + .filter(ee.Filter.inList('STATE', western_states)) + +# 1.3. Regression analysis +regressionReducer = ee.Reducer.sensSlope() +regressionX = yearTimestampBandname +regressionY = maxNDVIBandname + +# 1.4. Surface water layer to mask water pixels from assessment +# Selects pixels where water has ever been detected between 1984 and 2021 +surfaceWaterExtent = ee.Image('JRC/GSW1_3/GlobalSurfaceWater') \ + .select('max_extent') + +# 1.5. Average annual precipitation layer +rainfall = ee.Image('WORLDCLIM/V1/BIO').select('bio12') + +# 1.6. Visualization parameters +regressionResultVisParams = { + 'min': -3, + 'max': 3, + 'palette': ['ff8202', 'ffffff', '356e02'] +} +regressionSummaryChartingOptions = { + 'title': 'Yearly change in dry-season vegetation greenness ' + \ + 'in PA buffers in relation to average annual rainfall', + 'hAxis': { + 'title': 'Annual Precipitation' + }, + 'vAxis': { + 'title': 'Median % yearly change in vegetation greenness ' + \ + 'in 5 km buffer' + }, + 'series': { + '0': { + 'visibleInLegend': False + } + }, +} + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# 2. Raster processing for change analysis + +# Defining functions to be used in this script + +# 2.1. Annual dry season maxima of NDVI + +def annualDrySeasonMaximumNDVIAndTime(y): + # Convert year y to a date object + yDate = ee.Date.fromYMD(y, 1, 1) + # Calculate max NDVI for year y + yMaxNdvi = drySeasonNdviColl \ + .filter(ee.Filter.date(yDate, yDate.advance(1, 'year'))) \ + .max() + # Apply appropriate scale, as per the dataset's \ + .multiply(ndviValuesScaling) \ + .rename(maxNDVIBandname) + # Create an image with constant value y, to be used in regression. Name it something comprehensible. + # Name it something comprehensible. + yTime = ee.Image.constant(y).int().rename( + yearTimestampBandname) + # Combine the two images into a single 2-band image, and return + return ee.Image.cat([yMaxNdvi, yTime]).set('year', y) + + +# Create a collection of annual dry season maxima +# for the years of interest. Select the NDVI band and +# filter to the collection of dry season observations. +drySeasonNdviColl = modis_veg.select([ndviBandName]) \ + .filter(ee.Filter.calendarRange(drySeasonStart_doy, + drySeasonEnd_doy, 'day_of_year')) +# For each year of interest, calculate the NDVI maxima and create a corresponding time band +dryseason_coll = ee.ImageCollection.fromImages( + years.map(annualDrySeasonMaximumNDVIAndTime) +) + +# 2.2. Annual regression to estimate average yearly change in greenness + +ss = dryseason_coll.select([regressionX, regressionY]).reduce( + regressionReducer) + +# Mask surface water from vegetation change image +ss = ss.updateMask(surfaceWaterExtent.eq(0)) + +# 2.3. Summarise estimates of change in buffer regions of PAs of interest +def extractBufferRegion(pa): + #reduce vertices in PA boundary + pa = pa.simplify({ + 'maxError': 100 + }) + # Extend boundary into its buffer + withBuffer = pa.buffer(boundaryBufferWidth, + bufferingMaxError) + # Compute the buffer-only region by "subtracting" boundary with buffer from boundary + # Subtracting the whole set of boundaries eliminates inclusion of forests from adjacent PAs into buffers. + bufferOnly = withBuffer.difference(paBoundaries.geometry()) + + return bufferOnly + + +# Create buffer regions of PAs +pa_buff = western_pas.map(extractBufferRegion) + +# Normalize the metric of NDVI change to a baseline (dry-season max NDVI in the very first year) +baselineNdvi = dryseason_coll.select([maxNDVIBandname]).filter(ee \ + .Filter.eq('year', years.getNumber(0))).first() +stats = ss.select('slope').divide(baselineNdvi).multiply(100) \ + .rename('vegchange') + +# Combine it with average annual rainfall data +stats = stats.addBands(rainfall.rename('rainfall')) + +# Calculate mean of change metric over buffer regions of each PA of interest +paBufferwiseMedianChange = stats.reduceRegions({ + 'collection': pa_buff, + 'reducer': ee.Reducer.median(), + 'scale': 1000, + 'tileScale': 16 +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310c Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310c Checkpoint.ipynb new file mode 100644 index 0000000..87ce7d2 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310c Checkpoint.ipynb @@ -0,0 +1,268 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: Chapter A3.10 Conservation II - Assessing Agricultural\n", + "# Intensification Near Protected Areas\n", + "# Checkpoint: A310c\n", + "# Authors: Pradeep Koulgi, MD Madhusudan\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# 1. Parameters to function calls\n", + "\n", + "# 1.1. Annual dry season max NDVI calculation\n", + "modis_veg = ee.ImageCollection('MODIS/006/MOD13Q1')\n", + "ndviBandName = 'NDVI'\n", + "ndviValuesScaling = 0.0001\n", + "modisVegScale = 250; # meters\n", + "maxNDVIBandname = 'max_dryseason_ndvi'\n", + "yearTimestampBandname = 'year'\n", + "years = ee.List.sequence(2000, 2021, 1)\n", + "drySeasonStart_doy = 1\n", + "drySeasonEnd_doy = 90\n", + "\n", + "# 1.2. Boundaries of Protected Areas of interest\n", + "paBoundaries = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-10/IndiaMainlandPAs')\n", + "boundaryBufferWidth = 5000; # meters\n", + "bufferingMaxError = 30; # meters\n", + "# Choose PAs in only the western states\n", + "western_states = [\n", + " 'Rajasthan', 'Gujarat', 'Madhya Pradesh',\n", + " 'Maharashtra', 'Goa', 'Karnataka', 'Kerala'\n", + "]\n", + "western_pas = paBoundaries \\\n", + " .filter(ee.Filter.inList('STATE', western_states))\n", + "\n", + "# 1.3. Regression analysis\n", + "regressionReducer = ee.Reducer.sensSlope()\n", + "regressionX = yearTimestampBandname\n", + "regressionY = maxNDVIBandname\n", + "\n", + "# 1.4. Surface water layer to mask water pixels from assessment\n", + "# Selects pixels where water has ever been detected between 1984 and 2021\n", + "surfaceWaterExtent = ee.Image('JRC/GSW1_3/GlobalSurfaceWater') \\\n", + " .select('max_extent')\n", + "\n", + "# 1.5. Average annual precipitation layer\n", + "rainfall = ee.Image('WORLDCLIM/V1/BIO').select('bio12')\n", + "\n", + "# 1.6. Visualization parameters\n", + "regressionResultVisParams = {\n", + " 'min': -3,\n", + " 'max': 3,\n", + " 'palette': ['ff8202', 'ffffff', '356e02']\n", + "}\n", + "regressionSummaryChartingOptions = {\n", + " 'title': 'Yearly change in dry-season vegetation greenness ' + \\\n", + " 'in PA buffers in relation to average annual rainfall',\n", + " 'hAxis': {\n", + " 'title': 'Annual Precipitation'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Median % yearly change in vegetation greenness ' + \\\n", + " 'in 5 km buffer'\n", + " },\n", + " 'series': {\n", + " '0': {\n", + " 'visibleInLegend': False\n", + " }\n", + " },\n", + "}\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# 2. Raster processing for change analysis\n", + "\n", + "# Defining functions to be used in this script\n", + "\n", + "# 2.1. Annual dry season maxima of NDVI\n", + "\n", + "def annualDrySeasonMaximumNDVIAndTime(y):\n", + " # Convert year y to a date object\n", + " yDate = ee.Date.fromYMD(y, 1, 1)\n", + " # Calculate max NDVI for year y\n", + " yMaxNdvi = drySeasonNdviColl \\\n", + " .filter(ee.Filter.date(yDate, yDate.advance(1, 'year'))) \\\n", + " .max()\n", + " # Apply appropriate scale, as per the dataset's \\\n", + " .multiply(ndviValuesScaling) \\\n", + " .rename(maxNDVIBandname)\n", + " # Create an image with constant value y, to be used in regression. Name it something comprehensible.\n", + " # Name it something comprehensible.\n", + " yTime = ee.Image.constant(y).int().rename(\n", + " yearTimestampBandname)\n", + " # Combine the two images into a single 2-band image, and return\n", + " return ee.Image.cat([yMaxNdvi, yTime]).set('year', y)\n", + "\n", + "\n", + "# Create a collection of annual dry season maxima\n", + "# for the years of interest. Select the NDVI band and\n", + "# filter to the collection of dry season observations.\n", + "drySeasonNdviColl = modis_veg.select([ndviBandName]) \\\n", + " .filter(ee.Filter.calendarRange(drySeasonStart_doy,\n", + " drySeasonEnd_doy, 'day_of_year'))\n", + "# For each year of interest, calculate the NDVI maxima and create a corresponding time band\n", + "dryseason_coll = ee.ImageCollection.fromImages(\n", + " years.map(annualDrySeasonMaximumNDVIAndTime)\n", + ")\n", + "\n", + "# 2.2. Annual regression to estimate average yearly change in greenness\n", + "\n", + "ss = dryseason_coll.select([regressionX, regressionY]).reduce(\n", + " regressionReducer)\n", + "\n", + "# Mask surface water from vegetation change image\n", + "ss = ss.updateMask(surfaceWaterExtent.eq(0))\n", + "\n", + "# 2.3. Summarise estimates of change in buffer regions of PAs of interest\n", + "def extractBufferRegion(pa):\n", + " #reduce vertices in PA boundary\n", + " pa = pa.simplify({\n", + " 'maxError': 100\n", + " })\n", + " # Extend boundary into its buffer\n", + " withBuffer = pa.buffer(boundaryBufferWidth,\n", + " bufferingMaxError)\n", + " # Compute the buffer-only region by \"subtracting\" boundary with buffer from boundary\n", + " # Subtracting the whole set of boundaries eliminates inclusion of forests from adjacent PAs into buffers.\n", + " bufferOnly = withBuffer.difference(paBoundaries.geometry())\n", + "\n", + " return bufferOnly\n", + "\n", + "\n", + "# Create buffer regions of PAs\n", + "pa_buff = western_pas.map(extractBufferRegion)\n", + "\n", + "# Normalize the metric of NDVI change to a baseline (dry-season max NDVI in the very first year)\n", + "baselineNdvi = dryseason_coll.select([maxNDVIBandname]).filter(ee \\\n", + " .Filter.eq('year', years.getNumber(0))).first()\n", + "stats = ss.select('slope').divide(baselineNdvi).multiply(100) \\\n", + " .rename('vegchange')\n", + "\n", + "# Combine it with average annual rainfall data\n", + "stats = stats.addBands(rainfall.rename('rainfall'))\n", + "\n", + "# Calculate mean of change metric over buffer regions of each PA of interest\n", + "paBufferwiseMedianChange = stats.reduceRegions({\n", + " 'collection': pa_buff,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'scale': 1000,\n", + " 'tileScale': 16\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# 3. Visualize results\n", + "medianChangeChart = ui.Chart.feature.byFeature({\n", + " 'features': paBufferwiseMedianChange,\n", + " 'xProperty': 'rainfall',\n", + " 'yProperties': ['vegchange']\n", + "}).setOptions(regressionSummaryChartingOptions).setChartType(\n", + " 'ScatterChart')\n", + "print(medianChangeChart)\n", + "\n", + "Map.centerObject(western_pas, 9)\n", + "Map.setCenter(79.2205, 23.3991, 9)\n", + "Map.setOptions('SATELLITE')\n", + "Map.addLayer(stats.select('vegchange').clipToCollection(pa_buff),\n", + " regressionResultVisParams, 'yearly % change')\n", + "Map.addLayer(western_pas, {}, 'Western PAs')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310c Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310c Checkpoint.js new file mode 100644 index 0000000..3e9a0e8 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310c Checkpoint.js @@ -0,0 +1,179 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: Chapter A3.10 Conservation II - Assessing Agricultural +// Intensification Near Protected Areas +// Checkpoint: A310c +// Authors: Pradeep Koulgi, MD Madhusudan +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// 1. Parameters to function calls + +// 1.1. Annual dry season max NDVI calculation +var modis_veg = ee.ImageCollection('MODIS/006/MOD13Q1'); +var ndviBandName = 'NDVI'; +var ndviValuesScaling = 0.0001; +var modisVegScale = 250; // meters +var maxNDVIBandname = 'max_dryseason_ndvi'; +var yearTimestampBandname = 'year'; +var years = ee.List.sequence(2000, 2021, 1); +var drySeasonStart_doy = 1; +var drySeasonEnd_doy = 90; + +// 1.2. Boundaries of Protected Areas of interest +var paBoundaries = ee.FeatureCollection( + 'projects/gee-book/assets/A3-10/IndiaMainlandPAs'); +var boundaryBufferWidth = 5000; // meters +var bufferingMaxError = 30; // meters +// Choose PAs in only the western states +var western_states = [ + 'Rajasthan', 'Gujarat', 'Madhya Pradesh', + 'Maharashtra', 'Goa', 'Karnataka', 'Kerala' +]; +var western_pas = paBoundaries + .filter(ee.Filter.inList('STATE', western_states)); + +// 1.3. Regression analysis +var regressionReducer = ee.Reducer.sensSlope(); +var regressionX = yearTimestampBandname; +var regressionY = maxNDVIBandname; + +// 1.4. Surface water layer to mask water pixels from assessment +// Selects pixels where water has ever been detected between 1984 and 2021 +var surfaceWaterExtent = ee.Image('JRC/GSW1_3/GlobalSurfaceWater') + .select('max_extent'); + +// 1.5. Average annual precipitation layer +var rainfall = ee.Image('WORLDCLIM/V1/BIO').select('bio12'); + +// 1.6. Visualization parameters +var regressionResultVisParams = { + min: -3, + max: 3, + palette: ['ff8202', 'ffffff', '356e02'] +}; +var regressionSummaryChartingOptions = { + title: 'Yearly change in dry-season vegetation greenness ' + + 'in PA buffers in relation to average annual rainfall', + hAxis: { + title: 'Annual Precipitation' + }, + vAxis: { + title: 'Median % yearly change in vegetation greenness ' + + 'in 5 km buffer' + }, + series: { + 0: { + visibleInLegend: false + } + }, +}; + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// 2. Raster processing for change analysis + +// Defining functions to be used in this script + +// 2.1. Annual dry season maxima of NDVI + +function annualDrySeasonMaximumNDVIAndTime(y) { + // Convert year y to a date object + var yDate = ee.Date.fromYMD(y, 1, 1); + // Calculate max NDVI for year y + var yMaxNdvi = drySeasonNdviColl + // Filter to year y + .filter(ee.Filter.date(yDate, yDate.advance(1, 'year'))) + // Compute max value + .max() + // Apply appropriate scale, as per the dataset's + // technical description for NDVI band. + .multiply(ndviValuesScaling) + // rename the band to be more comprehensible + .rename(maxNDVIBandname); + // Create an image with constant value y, to be used in regression. Name it something comprehensible. + // Name it something comprehensible. + var yTime = ee.Image.constant(y).int().rename( + yearTimestampBandname); + // Combine the two images into a single 2-band image, and return + return ee.Image.cat([yMaxNdvi, yTime]).set('year', y); +} + +// Create a collection of annual dry season maxima +// for the years of interest. Select the NDVI band and +// filter to the collection of dry season observations. +var drySeasonNdviColl = modis_veg.select([ndviBandName]) + .filter(ee.Filter.calendarRange(drySeasonStart_doy, + drySeasonEnd_doy, 'day_of_year')); +// For each year of interest, calculate the NDVI maxima and create a corresponding time band +var dryseason_coll = ee.ImageCollection.fromImages( + years.map(annualDrySeasonMaximumNDVIAndTime) +); + +// 2.2. Annual regression to estimate average yearly change in greenness + +var ss = dryseason_coll.select([regressionX, regressionY]).reduce( + regressionReducer); + +// Mask surface water from vegetation change image +var ss = ss.updateMask(surfaceWaterExtent.eq(0)); + +// 2.3. Summarise estimates of change in buffer regions of PAs of interest +function extractBufferRegion(pa) { + //reduce vertices in PA boundary + pa = pa.simplify({ + maxError: 100 + }); + // Extend boundary into its buffer + var withBuffer = pa.buffer(boundaryBufferWidth, + bufferingMaxError); + // Compute the buffer-only region by "subtracting" boundary with buffer from boundary + // Subtracting the whole set of boundaries eliminates inclusion of forests from adjacent PAs into buffers. + var bufferOnly = withBuffer.difference(paBoundaries.geometry()); + + return bufferOnly; +} + +// Create buffer regions of PAs +var pa_buff = western_pas.map(extractBufferRegion); + +// Normalize the metric of NDVI change to a baseline (dry-season max NDVI in the very first year) +var baselineNdvi = dryseason_coll.select([maxNDVIBandname]).filter(ee + .Filter.eq('year', years.getNumber(0))).first(); +var stats = ss.select('slope').divide(baselineNdvi).multiply(100) + .rename('vegchange'); + +// Combine it with average annual rainfall data +stats = stats.addBands(rainfall.rename('rainfall')); + +// Calculate mean of change metric over buffer regions of each PA of interest +var paBufferwiseMedianChange = stats.reduceRegions({ + collection: pa_buff, + reducer: ee.Reducer.median(), + scale: 1000, + tileScale: 16 +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// 3. Visualize results +var medianChangeChart = ui.Chart.feature.byFeature({ + features: paBufferwiseMedianChange, + xProperty: 'rainfall', + yProperties: ['vegchange'] +}).setOptions(regressionSummaryChartingOptions).setChartType( + 'ScatterChart'); +print(medianChangeChart); + +Map.centerObject(western_pas, 9); +Map.setCenter(79.2205, 23.3991, 9); +Map.setOptions('SATELLITE'); +Map.addLayer(stats.select('vegchange').clipToCollection(pa_buff), + regressionResultVisParams, 'yearly % change'); +Map.addLayer(western_pas, {}, 'Western PAs'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310c Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310c Checkpoint.py new file mode 100644 index 0000000..93847ce --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.10 Conservation II - Mapping and Assessing Agricultural Intensification in Production Landscapes outside Protected Areas/A310c Checkpoint.py @@ -0,0 +1,181 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: Chapter A3.10 Conservation II - Assessing Agricultural +# Intensification Near Protected Areas +# Checkpoint: A310c +# Authors: Pradeep Koulgi, MD Madhusudan +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# 1. Parameters to function calls + +# 1.1. Annual dry season max NDVI calculation +modis_veg = ee.ImageCollection('MODIS/006/MOD13Q1') +ndviBandName = 'NDVI' +ndviValuesScaling = 0.0001 +modisVegScale = 250; # meters +maxNDVIBandname = 'max_dryseason_ndvi' +yearTimestampBandname = 'year' +years = ee.List.sequence(2000, 2021, 1) +drySeasonStart_doy = 1 +drySeasonEnd_doy = 90 + +# 1.2. Boundaries of Protected Areas of interest +paBoundaries = ee.FeatureCollection( + 'projects/gee-book/assets/A3-10/IndiaMainlandPAs') +boundaryBufferWidth = 5000; # meters +bufferingMaxError = 30; # meters +# Choose PAs in only the western states +western_states = [ + 'Rajasthan', 'Gujarat', 'Madhya Pradesh', + 'Maharashtra', 'Goa', 'Karnataka', 'Kerala' +] +western_pas = paBoundaries \ + .filter(ee.Filter.inList('STATE', western_states)) + +# 1.3. Regression analysis +regressionReducer = ee.Reducer.sensSlope() +regressionX = yearTimestampBandname +regressionY = maxNDVIBandname + +# 1.4. Surface water layer to mask water pixels from assessment +# Selects pixels where water has ever been detected between 1984 and 2021 +surfaceWaterExtent = ee.Image('JRC/GSW1_3/GlobalSurfaceWater') \ + .select('max_extent') + +# 1.5. Average annual precipitation layer +rainfall = ee.Image('WORLDCLIM/V1/BIO').select('bio12') + +# 1.6. Visualization parameters +regressionResultVisParams = { + 'min': -3, + 'max': 3, + 'palette': ['ff8202', 'ffffff', '356e02'] +} +regressionSummaryChartingOptions = { + 'title': 'Yearly change in dry-season vegetation greenness ' + \ + 'in PA buffers in relation to average annual rainfall', + 'hAxis': { + 'title': 'Annual Precipitation' + }, + 'vAxis': { + 'title': 'Median % yearly change in vegetation greenness ' + \ + 'in 5 km buffer' + }, + 'series': { + '0': { + 'visibleInLegend': False + } + }, +} + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# 2. Raster processing for change analysis + +# Defining functions to be used in this script + +# 2.1. Annual dry season maxima of NDVI + +def annualDrySeasonMaximumNDVIAndTime(y): + # Convert year y to a date object + yDate = ee.Date.fromYMD(y, 1, 1) + # Calculate max NDVI for year y + yMaxNdvi = drySeasonNdviColl \ + .filter(ee.Filter.date(yDate, yDate.advance(1, 'year'))) \ + .max() + # Apply appropriate scale, as per the dataset's \ + .multiply(ndviValuesScaling) \ + .rename(maxNDVIBandname) + # Create an image with constant value y, to be used in regression. Name it something comprehensible. + # Name it something comprehensible. + yTime = ee.Image.constant(y).int().rename( + yearTimestampBandname) + # Combine the two images into a single 2-band image, and return + return ee.Image.cat([yMaxNdvi, yTime]).set('year', y) + + +# Create a collection of annual dry season maxima +# for the years of interest. Select the NDVI band and +# filter to the collection of dry season observations. +drySeasonNdviColl = modis_veg.select([ndviBandName]) \ + .filter(ee.Filter.calendarRange(drySeasonStart_doy, + drySeasonEnd_doy, 'day_of_year')) +# For each year of interest, calculate the NDVI maxima and create a corresponding time band +dryseason_coll = ee.ImageCollection.fromImages( + years.map(annualDrySeasonMaximumNDVIAndTime) +) + +# 2.2. Annual regression to estimate average yearly change in greenness + +ss = dryseason_coll.select([regressionX, regressionY]).reduce( + regressionReducer) + +# Mask surface water from vegetation change image +ss = ss.updateMask(surfaceWaterExtent.eq(0)) + +# 2.3. Summarise estimates of change in buffer regions of PAs of interest +def extractBufferRegion(pa): + #reduce vertices in PA boundary + pa = pa.simplify({ + 'maxError': 100 + }) + # Extend boundary into its buffer + withBuffer = pa.buffer(boundaryBufferWidth, + bufferingMaxError) + # Compute the buffer-only region by "subtracting" boundary with buffer from boundary + # Subtracting the whole set of boundaries eliminates inclusion of forests from adjacent PAs into buffers. + bufferOnly = withBuffer.difference(paBoundaries.geometry()) + + return bufferOnly + + +# Create buffer regions of PAs +pa_buff = western_pas.map(extractBufferRegion) + +# Normalize the metric of NDVI change to a baseline (dry-season max NDVI in the very first year) +baselineNdvi = dryseason_coll.select([maxNDVIBandname]).filter(ee \ + .Filter.eq('year', years.getNumber(0))).first() +stats = ss.select('slope').divide(baselineNdvi).multiply(100) \ + .rename('vegchange') + +# Combine it with average annual rainfall data +stats = stats.addBands(rainfall.rename('rainfall')) + +# Calculate mean of change metric over buffer regions of each PA of interest +paBufferwiseMedianChange = stats.reduceRegions({ + 'collection': pa_buff, + 'reducer': ee.Reducer.median(), + 'scale': 1000, + 'tileScale': 16 +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# 3. Visualize results +medianChangeChart = ui.Chart.feature.byFeature({ + 'features': paBufferwiseMedianChange, + 'xProperty': 'rainfall', + 'yProperties': ['vegchange'] +}).setOptions(regressionSummaryChartingOptions).setChartType( + 'ScatterChart') +print(medianChangeChart) + +Map.centerObject(western_pas, 9) +Map.setCenter(79.2205, 23.3991, 9) +Map.setOptions('SATELLITE') +Map.addLayer(stats.select('vegchange').clipToCollection(pa_buff), + regressionResultVisParams, 'yearly % change') +Map.addLayer(western_pas, {}, 'Western PAs') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32a Checkpoint.ipynb new file mode 100644 index 0000000..279f2ae --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32a Checkpoint.ipynb @@ -0,0 +1,157 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.2 Mangroves\n", + "# Checkpoint: A32a\n", + "# Author: Aur\u00e9lie Shapiro\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Create an ee.Geometry.\n", + "aoi = ee.Geometry.Polygon([\n", + " [\n", + " [88.3, 22.61],\n", + " [90, 22.61],\n", + " [90, 21.47],\n", + " [88.3, 21.47]\n", + " ]\n", + "])\n", + "\n", + "# Locate a coordinate in the aoi with land and water.\n", + "point = ee.Geometry.Point([89.2595, 21.7317])\n", + "\n", + "# Position the map.\n", + "Map.centerObject(point, 13)\n", + "Map.addLayer(aoi, {}, 'AOI')\n", + "\n", + "# Sentinel-1 wet season data.\n", + "wetS1 = ee.Image(\n", + " 'projects/gee-book/assets/A3-2/wet_season_tscan_2020')\n", + "# Sentinel-1 dry season data.\n", + "dryS1 = ee.Image(\n", + " 'projects/gee-book/assets/A3-2/dry_season_tscan_2020')\n", + "# Sentinel-2 mosaic.\n", + "S2 = ee.Image('projects/gee-book/assets/A3-2/Sundarbans_S2_2020')\n", + "\n", + "#Visualize the input data.\n", + "s1VisParams = {\n", + " 'bands': ['VV_min', 'VH_min', 'VVVH_ratio_min'],\n", + " 'min': -36,\n", + " 'max': 3\n", + "}\n", + "s2VisParams = {\n", + " 'bands': ['swir1', 'nir', 'red'],\n", + " 'min': 82,\n", + " 'max': 3236\n", + "}\n", + "\n", + "Map.addLayer(dryS1, s1VisParams, 'S1 dry', False)\n", + "Map.addLayer(wetS1, s1VisParams, 'S1 wet', False)\n", + "Map.addLayer(S2, s2VisParams, 'S2 2020')\n", + "\n", + "NDVI = S2.normalizedDifference(['nir', 'red']).rename(['NDVI'])\n", + "\n", + "ratio_swir1_nir = S2.expression(\n", + " 'swir1/(nir+0.1)', {\n", + " 'swir1': S2.select('swir1'),\n", + " 'nir': S2.select('nir')\n", + " }) \\\n", + " .rename('ratio_swir1_nir_wet')\n", + "\n", + "data_stack = S2.addBands(NDVI).addBands(ratio_swir1_nir).addBands(\n", + " dryS1).addBands(wetS1)\n", + "\n", + "print(data_stack)\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32a Checkpoint.js new file mode 100644 index 0000000..84ec598 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32a Checkpoint.js @@ -0,0 +1,64 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.2 Mangroves +// Checkpoint: A32a +// Author: Aurélie Shapiro +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create an ee.Geometry. +var aoi = ee.Geometry.Polygon([ + [ + [88.3, 22.61], + [90, 22.61], + [90, 21.47], + [88.3, 21.47] + ] +]); + +// Locate a coordinate in the aoi with land and water. +var point = ee.Geometry.Point([89.2595, 21.7317]); + +// Position the map. +Map.centerObject(point, 13); +Map.addLayer(aoi, {}, 'AOI'); + +// Sentinel-1 wet season data. +var wetS1 = ee.Image( + 'projects/gee-book/assets/A3-2/wet_season_tscan_2020'); +// Sentinel-1 dry season data. +var dryS1 = ee.Image( + 'projects/gee-book/assets/A3-2/dry_season_tscan_2020'); +// Sentinel-2 mosaic. +var S2 = ee.Image('projects/gee-book/assets/A3-2/Sundarbans_S2_2020'); + +//Visualize the input data. +var s1VisParams = { + bands: ['VV_min', 'VH_min', 'VVVH_ratio_min'], + min: -36, + max: 3 +}; +var s2VisParams = { + bands: ['swir1', 'nir', 'red'], + min: 82, + max: 3236 +}; + +Map.addLayer(dryS1, s1VisParams, 'S1 dry', false); +Map.addLayer(wetS1, s1VisParams, 'S1 wet', false); +Map.addLayer(S2, s2VisParams, 'S2 2020'); + +var NDVI = S2.normalizedDifference(['nir', 'red']).rename(['NDVI']); + +var ratio_swir1_nir = S2.expression( + 'swir1/(nir+0.1)', { + 'swir1': S2.select('swir1'), + 'nir': S2.select('nir') + }) + .rename('ratio_swir1_nir_wet'); + +var data_stack = S2.addBands(NDVI).addBands(ratio_swir1_nir).addBands( + dryS1).addBands(wetS1); + +print(data_stack); +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32a Checkpoint.py new file mode 100644 index 0000000..72d158a --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32a Checkpoint.py @@ -0,0 +1,70 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.2 Mangroves +# Checkpoint: A32a +# Author: Aurélie Shapiro +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Create an ee.Geometry. +aoi = ee.Geometry.Polygon([ + [ + [88.3, 22.61], + [90, 22.61], + [90, 21.47], + [88.3, 21.47] + ] +]) + +# Locate a coordinate in the aoi with land and water. +point = ee.Geometry.Point([89.2595, 21.7317]) + +# Position the map. +Map.centerObject(point, 13) +Map.addLayer(aoi, {}, 'AOI') + +# Sentinel-1 wet season data. +wetS1 = ee.Image( + 'projects/gee-book/assets/A3-2/wet_season_tscan_2020') +# Sentinel-1 dry season data. +dryS1 = ee.Image( + 'projects/gee-book/assets/A3-2/dry_season_tscan_2020') +# Sentinel-2 mosaic. +S2 = ee.Image('projects/gee-book/assets/A3-2/Sundarbans_S2_2020') + +#Visualize the input data. +s1VisParams = { + 'bands': ['VV_min', 'VH_min', 'VVVH_ratio_min'], + 'min': -36, + 'max': 3 +} +s2VisParams = { + 'bands': ['swir1', 'nir', 'red'], + 'min': 82, + 'max': 3236 +} + +Map.addLayer(dryS1, s1VisParams, 'S1 dry', False) +Map.addLayer(wetS1, s1VisParams, 'S1 wet', False) +Map.addLayer(S2, s2VisParams, 'S2 2020') + +NDVI = S2.normalizedDifference(['nir', 'red']).rename(['NDVI']) + +ratio_swir1_nir = S2.expression( + 'swir1/(nir+0.1)', { + 'swir1': S2.select('swir1'), + 'nir': S2.select('nir') + }) \ + .rename('ratio_swir1_nir_wet') + +data_stack = S2.addBands(NDVI).addBands(ratio_swir1_nir).addBands( + dryS1).addBands(wetS1) + +print(data_stack) +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32b Checkpoint.js new file mode 100644 index 0000000..4e6e1c2 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32b Checkpoint.js @@ -0,0 +1,243 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.2 Mangroves +// Checkpoint: A32b +// Author: Aurélie Shapiro +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create an ee.Geometry. +var aoi = ee.Geometry.Polygon([ + [ + [88.3, 22.61], + [90, 22.61], + [90, 21.47], + [88.3, 21.47] + ] +]); + +// Locate a coordinate in the aoi with land and water. +var point = ee.Geometry.Point([89.2595, 21.7317]); + +// Position the map. +Map.centerObject(point, 13); +Map.addLayer(aoi, {}, 'AOI'); + +// Sentinel-1 wet season data. +var wetS1 = ee.Image( + 'projects/gee-book/assets/A3-2/wet_season_tscan_2020'); +// Sentinel-1 dry season data. +var dryS1 = ee.Image( + 'projects/gee-book/assets/A3-2/dry_season_tscan_2020'); +// Sentinel-2 mosaic. +var S2 = ee.Image('projects/gee-book/assets/A3-2/Sundarbans_S2_2020'); + +//Visualize the input data. +var s1VisParams = { + bands: ['VV_min', 'VH_min', 'VVVH_ratio_min'], + min: -36, + max: 3 +}; +var s2VisParams = { + bands: ['swir1', 'nir', 'red'], + min: 82, + max: 3236 +}; + +Map.addLayer(dryS1, s1VisParams, 'S1 dry', false); +Map.addLayer(wetS1, s1VisParams, 'S1 wet', false); +Map.addLayer(S2, s2VisParams, 'S2 2020'); + +var NDVI = S2.normalizedDifference(['nir', 'red']).rename(['NDVI']); + +var ratio_swir1_nir = S2.expression( + 'swir1/(nir+0.1)', { + 'swir1': S2.select('swir1'), + 'nir': S2.select('nir') + }) + .rename('ratio_swir1_nir_wet'); + +var data_stack = S2.addBands(NDVI).addBands(ratio_swir1_nir).addBands( + dryS1).addBands(wetS1); + +print(data_stack); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +/*** + * This script computes surface water mask using + * Canny Edge detector and Otsu thresholding. + * See the following paper for details: + * http://www.mdpi.com/2072-4292/8/5/386 + * + * Author: Gennadii Donchyts + * Contributors: Nicholas Clinton + * + */ + +/*** + * Return the DN that maximizes interclass variance in B5 (in the region). + */ +var otsu = function(histogram) { + histogram = ee.Dictionary(histogram); + + var counts = ee.Array(histogram.get('histogram')); + var means = ee.Array(histogram.get('bucketMeans')); + var size = means.length().get([0]); + var total = counts.reduce(ee.Reducer.sum(), [0]).get([0]); + var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) + .get([0]); + var mean = sum.divide(total); + + var indices = ee.List.sequence(1, size); + + // Compute between sum of squares, where each mean partitions the data. + var bss = indices.map(function(i) { + var aCounts = counts.slice(0, 0, i); + var aCount = aCounts.reduce(ee.Reducer.sum(), [0]) + .get([0]); + var aMeans = means.slice(0, 0, i); + var aMean = aMeans.multiply(aCounts) + .reduce(ee.Reducer.sum(), [0]).get([0]) + .divide(aCount); + var bCount = total.subtract(aCount); + var bMean = sum.subtract(aCount.multiply(aMean)) + .divide(bCount); + return aCount.multiply(aMean.subtract(mean).pow( + 2)).add( + bCount.multiply(bMean.subtract(mean).pow( + 2))); + }); + + // Return the mean value corresponding to the maximum BSS. + return means.sort(bss).get([-1]); +}; + +/*** + * Compute a threshold using Otsu method (bimodal). + */ + +function computeThresholdUsingOtsu(image, scale, bounds, + cannyThreshold, + cannySigma, minValue, debug) { + // Clip image edges. + var mask = image.mask().gt(0) + .focal_min(ee.Number(scale).multiply(3), 'circle', 'meters'); + + // Detect sharp changes. + var edge = ee.Algorithms.CannyEdgeDetector(image, cannyThreshold, + cannySigma); + edge = edge.multiply(mask); + + // Buffer around NDWI edges. + var edgeBuffer = edge + .focal_max(ee.Number(scale).multiply(1), 'square', 'meters'); + var imageEdge = image.mask(edgeBuffer); + + // Compute threshold using Otsu thresholding. + var buckets = 100; + var hist = ee.Dictionary(ee.Dictionary(imageEdge + .reduceRegion({ + reducer: ee.Reducer.histogram(buckets), + geometry: bounds, + scale: scale, + maxPixels: 1e9 + })) + .values() + .get(0)); + + var threshold = ee.Number(ee.Algorithms.If({ + condition: hist.contains('bucketMeans'), + trueCase: otsu(hist), + falseCase: 0.3 + })); + + if (debug) { + Map.addLayer(edge.mask(edge), { + palette: ['ff0000'] + }, 'edges', false); + print('Threshold: ', threshold); + print(ui.Chart.image.histogram(image, bounds, scale, + buckets)); + print(ui.Chart.image.histogram(imageEdge, bounds, scale, + buckets)); + } + + return minValue !== 'undefined' ? threshold.max(minValue) : + threshold; +} + +var bounds = ee.Geometry(Map.getBounds(true)); + +var image = data_stack; +print('image', image); + +var ndwi_for_water = image.normalizedDifference(['green', 'nir']); +var debug = true; +var scale = 10; +var cannyThreshold = 0.9; +var cannySigma = 1; +var minValue = -0.1; +var th = computeThresholdUsingOtsu(ndwi_for_water, scale, bounds, + cannyThreshold, cannySigma, minValue, debug); + +print('th', th); + +function getEdge(mask) { + return mask.subtract(mask.focal_min(1)); +} + +var water_mask = ndwi_for_water.mask(ndwi_for_water.gt(th)); + +th.evaluate(function(th) { + Map.addLayer(water_mask, { + palette: '0000ff' + }, 'water mask (th=' + th + ')'); +}); + +// Create land mask area. +var land = water_mask.unmask(); +var land_mask = land.eq(0); +Map.addLayer(land_mask, {}, 'Land mask', false); + +// Remove areas with elevation greater than mangrove elevation threshold. +var elev_thresh = 40; +var dem = ee.Image('NASA/NASADEM_HGT/001').select('elevation'); +var elev_mask = dem.lte(elev_thresh); +var land_mask = land_mask.updateMask(elev_mask); + +// Load global mangrove dataset as reference for training. +var mangrove_ref = ee.ImageCollection('LANDSAT/MANGROVE_FORESTS') + .filterBounds(aoi) + .first() + .clip(aoi); +Map.addLayer(mangrove_ref, { + palette: 'Green' +}, 'Reference Mangroves', false); + +// Buffer around known mangrove area with a specified distance. +var buffer_dist = 1000; +var mang_buffer = mangrove_ref + .focal_max(buffer_dist, 'square', 'meters') + .rename('mangrove_buffer'); +Map.addLayer(mang_buffer, {}, 'Mangrove Buffer', false); + +// Mask land from mangrove buffer. +var area_to_classify = mang_buffer.updateMask(land_mask).selfMask(); +Map.addLayer(area_to_classify, + {}, + 'Mangrove buffer with water and elevation mask', + false); +var image_to_classify = data_stack.updateMask(area_to_classify); +Map.addLayer(image_to_classify, + { + bands: ['swir1', 'nir', 'red'], + min: 82, + max: 3236 + }, + 'Masked Data Stack', + false); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32c Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32c Checkpoint.js new file mode 100644 index 0000000..a72d291 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32c Checkpoint.js @@ -0,0 +1,399 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.2 Mangroves +// Checkpoint: A32c +// Author: Aurélie Shapiro +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create an ee.Geometry. +var aoi = ee.Geometry.Polygon([ + [ + [88.3, 22.61], + [90, 22.61], + [90, 21.47], + [88.3, 21.47] + ] +]); + +// Locate a coordinate in the aoi with land and water. +var point = ee.Geometry.Point([89.2595, 21.7317]); + +// Position the map. +Map.centerObject(point, 13); +Map.addLayer(aoi, {}, 'AOI'); + +// Sentinel-1 wet season data. +var wetS1 = ee.Image( + 'projects/gee-book/assets/A3-2/wet_season_tscan_2020'); +// Sentinel-1 dry season data. +var dryS1 = ee.Image( + 'projects/gee-book/assets/A3-2/dry_season_tscan_2020'); +// Sentinel-2 mosaic. +var S2 = ee.Image('projects/gee-book/assets/A3-2/Sundarbans_S2_2020'); + +//Visualize the input data. +var s1VisParams = { + bands: ['VV_min', 'VH_min', 'VVVH_ratio_min'], + min: -36, + max: 3 +}; +var s2VisParams = { + bands: ['swir1', 'nir', 'red'], + min: 82, + max: 3236 +}; + +Map.addLayer(dryS1, s1VisParams, 'S1 dry', false); +Map.addLayer(wetS1, s1VisParams, 'S1 wet', false); +Map.addLayer(S2, s2VisParams, 'S2 2020'); + +var NDVI = S2.normalizedDifference(['nir', 'red']).rename(['NDVI']); + +var ratio_swir1_nir = S2.expression( + 'swir1/(nir+0.1)', { + 'swir1': S2.select('swir1'), + 'nir': S2.select('nir') + }) + .rename('ratio_swir1_nir_wet'); + +var data_stack = S2.addBands(NDVI).addBands(ratio_swir1_nir).addBands( + dryS1).addBands(wetS1); + +print(data_stack); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +/*** + * This script computes surface water mask using + * Canny Edge detector and Otsu thresholding. + * See the following paper for details: + * http://www.mdpi.com/2072-4292/8/5/386 + * + * Author: Gennadii Donchyts + * Contributors: Nicholas Clinton + * + */ + +/*** + * Return the DN that maximizes interclass variance in B5 (in the region). + */ +var otsu = function(histogram) { + histogram = ee.Dictionary(histogram); + + var counts = ee.Array(histogram.get('histogram')); + var means = ee.Array(histogram.get('bucketMeans')); + var size = means.length().get([0]); + var total = counts.reduce(ee.Reducer.sum(), [0]).get([0]); + var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]) + .get([0]); + var mean = sum.divide(total); + + var indices = ee.List.sequence(1, size); + + // Compute between sum of squares, where each mean partitions the data. + var bss = indices.map(function(i) { + var aCounts = counts.slice(0, 0, i); + var aCount = aCounts.reduce(ee.Reducer.sum(), [0]) + .get([0]); + var aMeans = means.slice(0, 0, i); + var aMean = aMeans.multiply(aCounts) + .reduce(ee.Reducer.sum(), [0]).get([0]) + .divide(aCount); + var bCount = total.subtract(aCount); + var bMean = sum.subtract(aCount.multiply(aMean)) + .divide(bCount); + return aCount.multiply(aMean.subtract(mean).pow( + 2)).add( + bCount.multiply(bMean.subtract(mean).pow( + 2))); + }); + + // Return the mean value corresponding to the maximum BSS. + return means.sort(bss).get([-1]); +}; + +/*** + * Compute a threshold using Otsu method (bimodal). + */ + +function computeThresholdUsingOtsu(image, scale, bounds, + cannyThreshold, + cannySigma, minValue, debug) { + // Clip image edges. + var mask = image.mask().gt(0) + .focal_min(ee.Number(scale).multiply(3), 'circle', 'meters'); + + // Detect sharp changes. + var edge = ee.Algorithms.CannyEdgeDetector(image, cannyThreshold, + cannySigma); + edge = edge.multiply(mask); + + // Buffer around NDWI edges. + var edgeBuffer = edge + .focal_max(ee.Number(scale).multiply(1), 'square', 'meters'); + var imageEdge = image.mask(edgeBuffer); + + // Compute threshold using Otsu thresholding. + var buckets = 100; + var hist = ee.Dictionary(ee.Dictionary(imageEdge + .reduceRegion({ + reducer: ee.Reducer.histogram(buckets), + geometry: bounds, + scale: scale, + maxPixels: 1e9 + })) + .values() + .get(0)); + + var threshold = ee.Number(ee.Algorithms.If({ + condition: hist.contains('bucketMeans'), + trueCase: otsu(hist), + falseCase: 0.3 + })); + + if (debug) { + Map.addLayer(edge.mask(edge), { + palette: ['ff0000'] + }, 'edges', false); + print('Threshold: ', threshold); + print(ui.Chart.image.histogram(image, bounds, scale, + buckets)); + print(ui.Chart.image.histogram(imageEdge, bounds, scale, + buckets)); + } + + return minValue !== 'undefined' ? threshold.max(minValue) : + threshold; +} + +var bounds = ee.Geometry(Map.getBounds(true)); + +var image = data_stack; +print('image', image); + +var ndwi_for_water = image.normalizedDifference(['green', 'nir']); +var debug = true; +var scale = 10; +var cannyThreshold = 0.9; +var cannySigma = 1; +var minValue = -0.1; +var th = computeThresholdUsingOtsu(ndwi_for_water, scale, bounds, + cannyThreshold, cannySigma, minValue, debug); + +print('th', th); + +function getEdge(mask) { + return mask.subtract(mask.focal_min(1)); +} + +var water_mask = ndwi_for_water.mask(ndwi_for_water.gt(th)); + +th.evaluate(function(th) { + Map.addLayer(water_mask, {palette: '0000ff'}, 'water mask (th=' + th + ')'); +}); + +// Create land mask area. +var land = water_mask.unmask(); +var land_mask = land.eq(0); +Map.addLayer(land_mask, {}, 'Land mask', false); + +// Remove areas with elevation greater than mangrove elevation threshold. +var elev_thresh = 40; +var dem = ee.Image('NASA/NASADEM_HGT/001').select('elevation'); +var elev_mask = dem.lte(elev_thresh); +var land_mask = land_mask.updateMask(elev_mask); + +// Load global mangrove dataset as reference for training. +var mangrove_ref = ee.ImageCollection('LANDSAT/MANGROVE_FORESTS') + .filterBounds(aoi) + .first() + .clip(aoi); +Map.addLayer(mangrove_ref, { + palette: 'Green' +}, 'Reference Mangroves', false); + +// Buffer around known mangrove area with a specified distance. +var buffer_dist = 1000; +var mang_buffer = mangrove_ref + .focal_max(buffer_dist, 'square', 'meters') + .rename('mangrove_buffer'); +Map.addLayer(mang_buffer, {}, 'Mangrove Buffer', false); + +// Mask land from mangrove buffer. +var area_to_classify = mang_buffer.updateMask(land_mask).selfMask(); +Map.addLayer(area_to_classify, + {}, + 'Mangrove buffer with water and elevation mask', + false); +var image_to_classify = data_stack.updateMask(area_to_classify); +Map.addLayer(image_to_classify, + { + bands: ['swir1', 'nir', 'red'], + min: 82, + max: 3236 + }, + 'Masked Data Stack', + false); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Create training data from existing data +// Class values: mangrove = 1, not mangrove = 0 +var ref_mangrove = mangrove_ref.unmask(); +var mangroveVis = { + min: 0, + max: 1, + palette: ['grey', 'green'] +}; +Map.addLayer(ref_mangrove, mangroveVis, 'mangrove = 1'); + +// Class values: not mangrove = 1 and mangrove = 0 +var notmang = ref_mangrove.eq(0); +var notMangroveVis = { + min: 0, + max: 1, + palette: ['grey', 'red'] +}; +Map.addLayer(notmang, notMangroveVis, 'not mangrove = 1', false); + +// Define a kernel for core mangrove areas. +var kernel = ee.Kernel.circle({ + radius: 3 +}); + +// Perform a dilation to identify core mangroves. +var mang_dilate = ref_mangrove + .focal_min({ + kernel: kernel, + iterations: 3 + }); +var mang_dilate = mang_dilate.updateMask(mang_dilate); +var mang_dilate = mang_dilate.rename('auto_train').unmask(); +Map.addLayer(mang_dilate, {}, 'Core mangrove areas to sample', false); + +// Do the same for non-mangrove areas. +var kernel1 = ee.Kernel.circle({ + radius: 3 +}); +var notmang_dilate = notmang + .focal_min({ + kernel: kernel1, + iterations: 2 + }); +var notmang_dilate = notmang_dilate.updateMask(notmang_dilate); +var notmang_dilate = notmang_dilate.multiply(2).unmask().rename( + 'auto_train'); +Map.addLayer(notmang_dilate, {}, 'Not mangrove areas to sample', + false); + +// Core mangrove = 1, core non mangrove = 2, neither = 0. +var train_labels = notmang_dilate.add(mang_dilate).clip(aoi); +var train_labels = train_labels.int8().updateMask(area_to_classify); +var trainingVis = { + min: 0, + max: 2, + palette: ['grey', 'green', 'red'] +}; +Map.addLayer(train_labels, trainingVis, 'Training areas', false); + +// Begin Classification. +// Get image and bands for training - including automatic training band. +var trainingImage = image_to_classify.addBands(train_labels); +var trainingBands = trainingImage.bandNames(); +print(trainingBands, 'training bands'); + +// Get training samples and classify. +// Select the number of training samples per class. +var numPoints = 2000; +var numPoints2 = 2000; + +var training = trainingImage.stratifiedSample({ + numPoints: 0, + classBand: 'auto_train', + region: aoi, + scale: 100, + classValues: [1, 2], + classPoints: [numPoints, numPoints2], + seed: 0, + dropNulls: true, + tileScale: 16, +}); + +var validation = trainingImage.stratifiedSample({ + numPoints: 0, + classBand: 'auto_train', + region: aoi, + scale: 100, + classValues: [1, 2], + classPoints: [numPoints, numPoints2], + seed: 1, + dropNulls: true, + tileScale: 16, +}); + +// Create a random forest classifier and train it. +var nTrees = 50; +var classifier = ee.Classifier.smileRandomForest(nTrees) + .train(training, 'auto_train'); + +var classified = image_to_classify.classify(classifier); + +// Classify the test set. +var validated = validation.classify(classifier); + +// Get a confusion matrix representing resubstitution accuracy. +var trainAccuracy = classifier.confusionMatrix(); +print('Resubstitution error matrix: ', trainAccuracy); +print('Training overall accuracy: ', trainAccuracy.accuracy()); +var testAccuracy = validated.errorMatrix('mangrove', + 'classification'); + +var dict = classifier.explain(); +print('Explain:', dict); + +var variable_importance = ee.Feature(null, ee.Dictionary(dict).get( + 'importance')); + +// Chart variable importance. +var chart = ui.Chart.feature.byProperty(variable_importance) + .setChartType('ColumnChart') + .setOptions({ + title: 'Random Forest Variable Importance', + legend: { + position: 'none' + }, + hAxis: { + title: 'Bands' + }, + vAxis: { + title: 'Importance' + } + }); +print(chart); + +var classificationVis = { + min: 1, + max: 2, + palette: ['green', 'grey'] +}; +Map.addLayer(classified, classificationVis, + 'Mangrove Classification'); + +// Clean up results to remove small patches/pixels. +var mang_only = classified.eq(1); +// Compute the number of pixels in each connected mangrove patch +// and apply the minimum mapping unit (number of pixels). +var mang_patchsize = mang_only.connectedPixelCount(); + +//mask pixels based on the number of connected neighbors +var mmu = 25; +var mang_mmu = mang_patchsize.gte(mmu); +var mang_mmu = classified.updateMask(mang_mmu).toInt8(); +Map.addLayer(mang_mmu, classificationVis, 'Mangrove Map MMU'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32s1 - Supplemental.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32s1 - Supplemental.ipynb new file mode 100644 index 0000000..bd305e4 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32s1 - Supplemental.ipynb @@ -0,0 +1,200 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.2 Mangroves\n", + "# Section: Synthesis (Assignment 2)\n", + "# Author: Aur\u00e9lie Shapiro\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Index functions - many sources for Sentinel-2 are here:\n", + "# https:#www.indexdatabase.de/db/s-single.php?id=96\n", + "\n", + "# Various NDVI calculations.\n", + "NDVI = S2.normalizedDifference(['nir', 'red']) \\\n", + " .rename('NDVI')\n", + "NDVI_red = S2.normalizedDifference(['red', 'green']) \\\n", + " .rename(['NDVI_red'])\n", + "NDVI_re1 = S2.normalizedDifference(['nir', 'redEdge1']) \\\n", + " .rename('NDVI_re1')\n", + "NDVI_re2 = S2.normalizedDifference(['nir', 'redEdge2']) \\\n", + " .rename('NDVI_re2')\n", + "NDVI_re3 = S2.normalizedDifference(['nir', 'redEdge3']) \\\n", + " .rename('NDVI_re3')\n", + "# NDYI: Yellowness index\n", + "NDYI = S2.normalizedDifference(['green', 'blue']) \\\n", + " .rename('NDYI')\n", + "# MNDWI: Modified Normalized Difference Wetness Index\n", + "MNDWI = S2.normalizedDifference(['green', 'swir1']) \\\n", + " .rename('MNDWI')\n", + "# MNDWI: Normalized Difference Wetness Index\n", + "NDWI = S2.normalizedDifference(['blue', 'red']) \\\n", + " .rename(['NDWI'])\n", + "# MNDWI: Normalized Difference Blue/Nir Index\n", + "NDBN = S2.normalizedDifference(['blue', 'nir']) \\\n", + " .rename(['NDBN'])\n", + "SAVI = S2.select('nir').subtract(S2.select('red')).multiply(1.5) \\\n", + " .divide(S2.select('nir').add(S2.select('red').add(0.5)))\n", + "OSAVI = S2.select('red').subtract(S2.select('nir')) \\\n", + " .divide((S2.select('red')).add(S2.select('nir')).add(0.16)) \\\n", + " .rename(['OSAVI'])\n", + "LSWI = S2.normalizedDifference(['red', 'nir']).rename(['LSWI'])\n", + "\n", + "ratio_swir1_nir = S2.expression(\n", + " 'swir1/(nir+0.1)', {\n", + " 'swir1': S2.select('swir1'),\n", + " 'nir': S2.select('nir')\n", + " }) \\\n", + " .rename('ratio_swir1_nir_wet')\n", + "\n", + "# ratio_red_swir1\n", + "ratio_red_swir1 = S2.expression('red/(swir1+0.1)', {\n", + " 'red': S2.select('red'),\n", + " 'swir1': S2.select('swir1')\n", + " }) \\\n", + " .rename('ratio_red_swir1_wet')\n", + "\n", + "# FDI Forest Discrimination Index from Wang et al., 2018\n", + "FDI = S2.expression('nir-(red+green)', {\n", + " 'nir': S2.select('nir'),\n", + " 'red': S2.select('red'),\n", + " 'green': S2.select('green')\n", + " }) \\\n", + " .rename('FDI_wet')\n", + "\n", + "# Tasseled cap wetness.\n", + "wetTC = S2.expression(\n", + " '(0.1509 * BLUE) + (0.1973 * GREEN) + (0.3279 * RED) + ' + \\\n", + " '(3406 * NIR) - (0.7112 * SWIR) - (0.4572 * SWIR2)', {\n", + " 'BLUE': S2.select('blue'),\n", + " 'GREEN': S2.select('green'),\n", + " 'RED': S2.select('red'),\n", + " 'NIR': S2.select('nir'),\n", + " 'SWIR': S2.select('swir1'),\n", + " 'SWIR2': S2.select('swir2')\n", + " }).rename('wetTC')\n", + "\n", + "# Tasseled cap greenness.\n", + "greenTC = S2.expression(\n", + " '(-0.2848 * BLUE) - (0.2435 * GREEN) - (0.5436 * RED) + ' + \\\n", + " '(0.7243 * NIR) + (0.084011 * NIR) - (0.1800 * SWIR)', {\n", + " 'BLUE': S2.select('blue'),\n", + " 'GREEN': S2.select('green'),\n", + " 'RED': S2.select('red'),\n", + " 'NIR': S2.select('nir'),\n", + " 'SWIR': S2.select('swir1'),\n", + " 'SWIR2': S2.select('swir2')\n", + " }).rename('greenTC')\n", + "\n", + "# Stack all bands together\n", + "data_stack = S2.addBands(ratio_swir1_nir) \\\n", + " .addBands(ratio_red_swir1) \\\n", + " .addBands(FDI) \\\n", + " .addBands(NDVI) \\\n", + " .addBands(NDVI_red) \\\n", + " .addBands(NDVI_re1) \\\n", + " .addBands(NDVI_re2) \\\n", + " .addBands(NDVI_re3) \\\n", + " .addBands(NDYI) \\\n", + " .addBands(MNDWI) \\\n", + " .addBands(NDWI) \\\n", + " .addBands(MNDWI) \\\n", + " .addBands(SAVI) \\\n", + " .addBands(OSAVI) \\\n", + " .addBands(wetTC) \\\n", + " .addBands(greenTC) \\\n", + " .addBands(LSWI) \\\n", + " .addBands(wetS1) \\\n", + " .addBands(wetS1)\n", + "\n", + "print(data_stack, 'data stack')" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32s1 - Supplemental.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32s1 - Supplemental.js new file mode 100644 index 0000000..0728df6 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32s1 - Supplemental.js @@ -0,0 +1,107 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.2 Mangroves +// Section: Synthesis (Assignment 2) +// Author: Aurélie Shapiro +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Index functions - many sources for Sentinel-2 are here: +// https://www.indexdatabase.de/db/s-single.php?id=96 + +// Various NDVI calculations. +var NDVI = S2.normalizedDifference(['nir', 'red']) + .rename('NDVI'); +var NDVI_red = S2.normalizedDifference(['red', 'green']) + .rename(['NDVI_red']); +var NDVI_re1 = S2.normalizedDifference(['nir', 'redEdge1']) + .rename('NDVI_re1'); +var NDVI_re2 = S2.normalizedDifference(['nir', 'redEdge2']) + .rename('NDVI_re2'); +var NDVI_re3 = S2.normalizedDifference(['nir', 'redEdge3']) + .rename('NDVI_re3'); +// NDYI: Yellowness index +var NDYI = S2.normalizedDifference(['green', 'blue']) + .rename('NDYI'); +// MNDWI: Modified Normalized Difference Wetness Index +var MNDWI = S2.normalizedDifference(['green', 'swir1']) + .rename('MNDWI'); +// MNDWI: Normalized Difference Wetness Index +var NDWI = S2.normalizedDifference(['blue', 'red']) + .rename(['NDWI']); +// MNDWI: Normalized Difference Blue/Nir Index +var NDBN = S2.normalizedDifference(['blue', 'nir']) + .rename(['NDBN']); +var SAVI = S2.select('nir').subtract(S2.select('red')).multiply(1.5) + .divide(S2.select('nir').add(S2.select('red').add(0.5))); +var OSAVI = S2.select('red').subtract(S2.select('nir')) + .divide((S2.select('red')).add(S2.select('nir')).add(0.16)) + .rename(['OSAVI']); +var LSWI = S2.normalizedDifference(['red', 'nir']).rename(['LSWI']); + +var ratio_swir1_nir = S2.expression( + 'swir1/(nir+0.1)', { + 'swir1': S2.select('swir1'), + 'nir': S2.select('nir') + }) + .rename('ratio_swir1_nir_wet'); + +// ratio_red_swir1 +var ratio_red_swir1 = S2.expression('red/(swir1+0.1)', { + 'red': S2.select('red'), + 'swir1': S2.select('swir1') + }) + .rename('ratio_red_swir1_wet'); + +// FDI Forest Discrimination Index from Wang et al., 2018 +var FDI = S2.expression('nir-(red+green)', { + 'nir': S2.select('nir'), + 'red': S2.select('red'), + 'green': S2.select('green') + }) + .rename('FDI_wet'); + +// Tasseled cap wetness. +var wetTC = S2.expression( + '(0.1509 * BLUE) + (0.1973 * GREEN) + (0.3279 * RED) + ' + + '(3406 * NIR) - (0.7112 * SWIR) - (0.4572 * SWIR2)', { + 'BLUE': S2.select('blue'), + 'GREEN': S2.select('green'), + 'RED': S2.select('red'), + 'NIR': S2.select('nir'), + 'SWIR': S2.select('swir1'), + 'SWIR2': S2.select('swir2') + }).rename('wetTC'); + +// Tasseled cap greenness. +var greenTC = S2.expression( + '(-0.2848 * BLUE) - (0.2435 * GREEN) - (0.5436 * RED) + ' + + '(0.7243 * NIR) + (0.084011 * NIR) - (0.1800 * SWIR)', { + 'BLUE': S2.select('blue'), + 'GREEN': S2.select('green'), + 'RED': S2.select('red'), + 'NIR': S2.select('nir'), + 'SWIR': S2.select('swir1'), + 'SWIR2': S2.select('swir2') + }).rename('greenTC'); + +// Stack all bands together +var data_stack = S2.addBands(ratio_swir1_nir) + .addBands(ratio_red_swir1) + .addBands(FDI) + .addBands(NDVI) + .addBands(NDVI_red) + .addBands(NDVI_re1) + .addBands(NDVI_re2) + .addBands(NDVI_re3) + .addBands(NDYI) + .addBands(MNDWI) + .addBands(NDWI) + .addBands(MNDWI) + .addBands(SAVI) + .addBands(OSAVI) + .addBands(wetTC) + .addBands(greenTC) + .addBands(LSWI) + .addBands(wetS1) + .addBands(wetS1); + +print(data_stack, 'data stack'); \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32s1 - Supplemental.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32s1 - Supplemental.py new file mode 100644 index 0000000..2e6194e --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.2 Mangroves/A32s1 - Supplemental.py @@ -0,0 +1,113 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.2 Mangroves +# Section: Synthesis (Assignment 2) +# Author: Aurélie Shapiro +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Index functions - many sources for Sentinel-2 are here: +# https:#www.indexdatabase.de/db/s-single.php?id=96 + +# Various NDVI calculations. +NDVI = S2.normalizedDifference(['nir', 'red']) \ + .rename('NDVI') +NDVI_red = S2.normalizedDifference(['red', 'green']) \ + .rename(['NDVI_red']) +NDVI_re1 = S2.normalizedDifference(['nir', 'redEdge1']) \ + .rename('NDVI_re1') +NDVI_re2 = S2.normalizedDifference(['nir', 'redEdge2']) \ + .rename('NDVI_re2') +NDVI_re3 = S2.normalizedDifference(['nir', 'redEdge3']) \ + .rename('NDVI_re3') +# NDYI: Yellowness index +NDYI = S2.normalizedDifference(['green', 'blue']) \ + .rename('NDYI') +# MNDWI: Modified Normalized Difference Wetness Index +MNDWI = S2.normalizedDifference(['green', 'swir1']) \ + .rename('MNDWI') +# MNDWI: Normalized Difference Wetness Index +NDWI = S2.normalizedDifference(['blue', 'red']) \ + .rename(['NDWI']) +# MNDWI: Normalized Difference Blue/Nir Index +NDBN = S2.normalizedDifference(['blue', 'nir']) \ + .rename(['NDBN']) +SAVI = S2.select('nir').subtract(S2.select('red')).multiply(1.5) \ + .divide(S2.select('nir').add(S2.select('red').add(0.5))) +OSAVI = S2.select('red').subtract(S2.select('nir')) \ + .divide((S2.select('red')).add(S2.select('nir')).add(0.16)) \ + .rename(['OSAVI']) +LSWI = S2.normalizedDifference(['red', 'nir']).rename(['LSWI']) + +ratio_swir1_nir = S2.expression( + 'swir1/(nir+0.1)', { + 'swir1': S2.select('swir1'), + 'nir': S2.select('nir') + }) \ + .rename('ratio_swir1_nir_wet') + +# ratio_red_swir1 +ratio_red_swir1 = S2.expression('red/(swir1+0.1)', { + 'red': S2.select('red'), + 'swir1': S2.select('swir1') + }) \ + .rename('ratio_red_swir1_wet') + +# FDI Forest Discrimination Index from Wang et al., 2018 +FDI = S2.expression('nir-(red+green)', { + 'nir': S2.select('nir'), + 'red': S2.select('red'), + 'green': S2.select('green') + }) \ + .rename('FDI_wet') + +# Tasseled cap wetness. +wetTC = S2.expression( + '(0.1509 * BLUE) + (0.1973 * GREEN) + (0.3279 * RED) + ' + \ + '(3406 * NIR) - (0.7112 * SWIR) - (0.4572 * SWIR2)', { + 'BLUE': S2.select('blue'), + 'GREEN': S2.select('green'), + 'RED': S2.select('red'), + 'NIR': S2.select('nir'), + 'SWIR': S2.select('swir1'), + 'SWIR2': S2.select('swir2') + }).rename('wetTC') + +# Tasseled cap greenness. +greenTC = S2.expression( + '(-0.2848 * BLUE) - (0.2435 * GREEN) - (0.5436 * RED) + ' + \ + '(0.7243 * NIR) + (0.084011 * NIR) - (0.1800 * SWIR)', { + 'BLUE': S2.select('blue'), + 'GREEN': S2.select('green'), + 'RED': S2.select('red'), + 'NIR': S2.select('nir'), + 'SWIR': S2.select('swir1'), + 'SWIR2': S2.select('swir2') + }).rename('greenTC') + +# Stack all bands together +data_stack = S2.addBands(ratio_swir1_nir) \ + .addBands(ratio_red_swir1) \ + .addBands(FDI) \ + .addBands(NDVI) \ + .addBands(NDVI_red) \ + .addBands(NDVI_re1) \ + .addBands(NDVI_re2) \ + .addBands(NDVI_re3) \ + .addBands(NDYI) \ + .addBands(MNDWI) \ + .addBands(NDWI) \ + .addBands(MNDWI) \ + .addBands(SAVI) \ + .addBands(OSAVI) \ + .addBands(wetTC) \ + .addBands(greenTC) \ + .addBands(LSWI) \ + .addBands(wetS1) \ + .addBands(wetS1) + +print(data_stack, 'data stack') +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33a Checkpoint.ipynb new file mode 100644 index 0000000..d2add2a --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33a Checkpoint.ipynb @@ -0,0 +1,171 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.3 Mangroves II - Change Mapping\n", + "# Checkpoint: A33a\n", + "# Authors: Celio de Sousa, David Lagomasino, and Lola Fatoyinbo\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# STEP 1 - ADD THE MAPS\n", + "areaOfstudy = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-3/Border5km')\n", + "mangrove2000 = ee.Image(\n", + " 'projects/gee-book/assets/A3-3/MangroveGuinea2000_v2')\n", + "mangrove2020 = ee.Image(\n", + " 'projects/gee-book/assets/A3-3/MangroveGuinea2020_v2')\n", + "\n", + "Map.setCenter(-13.6007, 9.6295, 10)\n", + "# Sets the map center to Conakry, Guinea\n", + "Map.addLayer(areaOfstudy, {}, 'Area of Study')\n", + "Map.addLayer(mangrove2000, {\n", + " 'palette': '#16a596'\n", + "}, 'Mangrove Extent 2000')\n", + "Map.addLayer(mangrove2020, {\n", + " 'palette': '#9ad3bc'\n", + "}, 'Mangrove Extent 2020')\n", + "\n", + "# STEP 2 - MAP TO MAP CHANGE\n", + "\n", + "mang2020 = mangrove2020.unmask(0)\n", + "mang2000 = mangrove2000.unmask(0)\n", + "change = mang2020.subtract(mang2000) \\\n", + " .clip(areaOfstudy)\n", + "\n", + "paletteCHANGE = [\n", + " 'red', # Loss/conversion\n", + " 'white', # No Change\n", + " 'green', # Gain/Expansion\n", + "]\n", + "\n", + "Map.addLayer(change, {\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': paletteCHANGE\n", + "}, 'Changes 2000-2020')\n", + "\n", + "# Calculate the area of each pixel\n", + "gain = change.eq(1)\n", + "loss = change.eq(-1)\n", + "\n", + "gainArea = gain.multiply(ee.Image.pixelArea().divide(1000000))\n", + "lossArea = loss.multiply(ee.Image.pixelArea().divide(1000000))\n", + "\n", + "# Sum all the areas\n", + "statsgain = gainArea.reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'scale': 30,\n", + " 'maxPixels': 1e14\n", + "})\n", + "\n", + "statsloss = lossArea.reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'scale': 30,\n", + " 'maxPixels': 1e14\n", + "})\n", + "\n", + "print(statsgain.get('classification'),\n", + " 'km\u00b2 of new mangroves in 2020')\n", + "print(statsloss.get('classification'),\n", + " 'of mangrove was lost in 2020')\n", + "\n", + "Map.addLayer(gain.selfMask(), {\n", + " 'palette': 'green'\n", + "}, 'Gains')\n", + "Map.addLayer(loss.selfMask(), {\n", + " 'palette': 'red'\n", + "}, 'Loss')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33a Checkpoint.js new file mode 100644 index 0000000..996d02d --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33a Checkpoint.js @@ -0,0 +1,78 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.3 Mangroves II - Change Mapping +// Checkpoint: A33a +// Authors: Celio de Sousa, David Lagomasino, and Lola Fatoyinbo +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// STEP 1 - ADD THE MAPS +var areaOfstudy = ee.FeatureCollection( + 'projects/gee-book/assets/A3-3/Border5km'); +var mangrove2000 = ee.Image( + 'projects/gee-book/assets/A3-3/MangroveGuinea2000_v2'); +var mangrove2020 = ee.Image( + 'projects/gee-book/assets/A3-3/MangroveGuinea2020_v2'); + +Map.setCenter(-13.6007, 9.6295, 10); +// Sets the map center to Conakry, Guinea +Map.addLayer(areaOfstudy, {}, 'Area of Study'); +Map.addLayer(mangrove2000, { + palette: '#16a596' +}, 'Mangrove Extent 2000'); +Map.addLayer(mangrove2020, { + palette: '#9ad3bc' +}, 'Mangrove Extent 2020'); + +// STEP 2 - MAP TO MAP CHANGE + +var mang2020 = mangrove2020.unmask(0); +var mang2000 = mangrove2000.unmask(0); +var change = mang2020.subtract(mang2000) + .clip(areaOfstudy); + +var paletteCHANGE = [ + 'red', // Loss/conversion + 'white', // No Change + 'green', // Gain/Expansion +]; + +Map.addLayer(change, { + min: -1, + max: 1, + palette: paletteCHANGE +}, 'Changes 2000-2020'); + +// Calculate the area of each pixel +var gain = change.eq(1); +var loss = change.eq(-1); + +var gainArea = gain.multiply(ee.Image.pixelArea().divide(1000000)); +var lossArea = loss.multiply(ee.Image.pixelArea().divide(1000000)); + +// Sum all the areas +var statsgain = gainArea.reduceRegion({ + reducer: ee.Reducer.sum(), + scale: 30, + maxPixels: 1e14 +}); + +var statsloss = lossArea.reduceRegion({ + reducer: ee.Reducer.sum(), + scale: 30, + maxPixels: 1e14 +}); + +print(statsgain.get('classification'), + 'km² of new mangroves in 2020'); +print(statsloss.get('classification'), + 'of mangrove was lost in 2020'); + +Map.addLayer(gain.selfMask(), { + palette: 'green' +}, 'Gains'); +Map.addLayer(loss.selfMask(), { + palette: 'red' +}, 'Loss'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33a Checkpoint.py new file mode 100644 index 0000000..3acb310 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33a Checkpoint.py @@ -0,0 +1,84 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.3 Mangroves II - Change Mapping +# Checkpoint: A33a +# Authors: Celio de Sousa, David Lagomasino, and Lola Fatoyinbo +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# STEP 1 - ADD THE MAPS +areaOfstudy = ee.FeatureCollection( + 'projects/gee-book/assets/A3-3/Border5km') +mangrove2000 = ee.Image( + 'projects/gee-book/assets/A3-3/MangroveGuinea2000_v2') +mangrove2020 = ee.Image( + 'projects/gee-book/assets/A3-3/MangroveGuinea2020_v2') + +Map.setCenter(-13.6007, 9.6295, 10) +# Sets the map center to Conakry, Guinea +Map.addLayer(areaOfstudy, {}, 'Area of Study') +Map.addLayer(mangrove2000, { + 'palette': '#16a596' +}, 'Mangrove Extent 2000') +Map.addLayer(mangrove2020, { + 'palette': '#9ad3bc' +}, 'Mangrove Extent 2020') + +# STEP 2 - MAP TO MAP CHANGE + +mang2020 = mangrove2020.unmask(0) +mang2000 = mangrove2000.unmask(0) +change = mang2020.subtract(mang2000) \ + .clip(areaOfstudy) + +paletteCHANGE = [ + 'red', # Loss/conversion + 'white', # No Change + 'green', # Gain/Expansion +] + +Map.addLayer(change, { + 'min': -1, + 'max': 1, + 'palette': paletteCHANGE +}, 'Changes 2000-2020') + +# Calculate the area of each pixel +gain = change.eq(1) +loss = change.eq(-1) + +gainArea = gain.multiply(ee.Image.pixelArea().divide(1000000)) +lossArea = loss.multiply(ee.Image.pixelArea().divide(1000000)) + +# Sum all the areas +statsgain = gainArea.reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'scale': 30, + 'maxPixels': 1e14 +}) + +statsloss = lossArea.reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'scale': 30, + 'maxPixels': 1e14 +}) + +print(statsgain.get('classification'), + 'km² of new mangroves in 2020') +print(statsloss.get('classification'), + 'of mangrove was lost in 2020') + +Map.addLayer(gain.selfMask(), { + 'palette': 'green' +}, 'Gains') +Map.addLayer(loss.selfMask(), { + 'palette': 'red' +}, 'Loss') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33b Checkpoint.js new file mode 100644 index 0000000..027fd92 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33b Checkpoint.js @@ -0,0 +1,272 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.3 Mangroves II - Change Mapping +// Checkpoint: A33b +// Authors: Celio de Sousa, David Lagomasino, and Lola Fatoyinbo +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// STEP 1 - ADD THE MAPS +var areaOfstudy = ee.FeatureCollection( + 'projects/gee-book/assets/A3-3/Border5km'); +var mangrove2000 = ee.Image( + 'projects/gee-book/assets/A3-3/MangroveGuinea2000_v2'); +var mangrove2020 = ee.Image( + 'projects/gee-book/assets/A3-3/MangroveGuinea2020_v2'); + +Map.setCenter(-13.6007, 9.6295, 10); +// Sets the map center to Conakry, Guinea +Map.addLayer(areaOfstudy, {}, 'Area of Study'); +Map.addLayer(mangrove2000, { + palette: '#16a596' +}, 'Mangrove Extent 2000'); +Map.addLayer(mangrove2020, { + palette: '#9ad3bc' +}, 'Mangrove Extent 2020'); + +// STEP 2 - MAP TO MAP CHANGE + +var mang2020 = mangrove2020.unmask(0); +var mang2000 = mangrove2000.unmask(0); +var change = mang2020.subtract(mang2000) + .clip(areaOfstudy); + +var paletteCHANGE = [ + 'red', // Loss/conversion + 'white', // No Change + 'green', // Gain/Expansion +]; + +Map.addLayer(change, { + min: -1, + max: 1, + palette: paletteCHANGE +}, 'Changes 2000-2020'); + +// Calculate the area of each pixel +var gain = change.eq(1); +var loss = change.eq(-1); + +var gainArea = gain.multiply(ee.Image.pixelArea().divide(1000000)); +var lossArea = loss.multiply(ee.Image.pixelArea().divide(1000000)); + +// Sum all the areas +var statsgain = gainArea.reduceRegion({ + reducer: ee.Reducer.sum(), + scale: 30, + maxPixels: 1e14 +}); + +var statsloss = lossArea.reduceRegion({ + reducer: ee.Reducer.sum(), + scale: 30, + maxPixels: 1e14 +}); + +print(statsgain.get('classification'), + 'km² of new mangroves in 2020 in Guinea'); +print(statsloss.get('classification'), + 'of mangrove was lost in 2020 in Guinea'); + +Map.addLayer(gain.selfMask(), { + palette: 'green' +}, 'Gains'); +Map.addLayer(loss.selfMask(), { + palette: 'red' +}, 'Loss'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// SECTION 2 + +// STEP 1 - SET THE BASELINE EXTENT AND BUFFER + +var buffer = 1000; // In meters +var extentBuffer = mangrove2000.focal_max(buffer, 'circle', 'meters'); +Map.addLayer(mangrove2000, { + palette: '#000000' +}, 'Baseline', false); +Map.addLayer(extentBuffer, { + palette: '#0e49b5', + opacity: 0.3 +}, 'Mangrove Buffer', false); + +// STEP 2 - HARMONIZING LANDSAT 5/7/8 IMAGE COLLECTIONS + +// 2.1 Temporal parameters +var startYear = 1984; +var endyear = 2020; +var startDay = '01-01'; +var endDay = '12-31'; + +// 2.2 Harmonization function. +// Slopes and interceps were retrieved from Roy et. al (2016) +var harmonizationRoy = function(oli) { + var slopes = ee.Image.constant([0.9785, 0.9542, 0.9825, + 1.0073, 1.0171, 0.9949 + ]); + var itcp = ee.Image.constant([-0.0095, -0.0016, -0.0022, - + 0.0021, -0.0030, 0.0029 + ]); + var y = oli.select(['B2', 'B3', 'B4', 'B5', 'B6', 'B7'], [ + 'B1', 'B2', 'B3', 'B4', 'B5', 'B7' + ]) + .resample('bicubic') + .subtract(itcp.multiply(10000)).divide(slopes) + .set('system:time_start', oli.get('system:time_start')); + return y.toShort(); +}; + +// 2.3 Retrieve a particular sensor function +var getSRcollection = function(year, startDay, endYear, endDay, + sensor) { + var srCollection = ee.ImageCollection('LANDSAT/' + sensor + + '/C01/T1_SR') + .filterDate(year + '-' + startDay, endYear + '-' + endDay) + .map(function(img) { + var dat; + if (sensor == 'LC08') { + dat = harmonizationRoy(img.unmask()); + } else { + dat = img.select(['B1', 'B2', 'B3', 'B4', + 'B5', 'B7' + ]) + .unmask() + .resample('bicubic') + .set('system:time_start', img.get( + 'system:time_start')); + } + // Cloud, cloud shadow and snow mask. + var qa = img.select('pixel_qa'); + var mask = qa.bitwiseAnd(8).eq(0).and( + qa.bitwiseAnd(16).eq(0)).and( + qa.bitwiseAnd(32).eq(0)); + return dat.mask(mask); + }); + return srCollection; +}; + +// 2.4 Combining the collections functio +var getCombinedSRcollection = function(year, startDay, endYear, + endDay) { + var lt5 = getSRcollection(year, startDay, endYear, endDay, + 'LT05'); + var le7 = getSRcollection(year, startDay, endYear, endDay, + 'LE07'); + var lc8 = getSRcollection(year, startDay, endYear, endDay, + 'LC08'); + var mergedCollection = ee.ImageCollection(le7.merge(lc8) + .merge(lt5)); + return mergedCollection; +}; + +// 2.5 Calculating vegetation indices. +var addIndices = function(image) { + var ndvi = image.normalizedDifference(['B4', 'B3']).rename( + 'NDVI'); + var evi = image.expression( + '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', { + 'NIR': image.select('B4'), + 'RED': image.select('B3'), + 'BLUE': image.select('B1') + }).rename('EVI'); + var savi = image.expression( + '((NIR - RED) / (NIR + RED + 0.5) * (0.5 + 1))', { + 'NIR': image.select('B4'), + 'RED': image.select('B3'), + 'BLUE': image.select('B1') + }).rename('SAVI'); + var ndmi = image.normalizedDifference(['B7', 'B2']).rename( + 'NDMI'); + var ndwi = image.normalizedDifference(['B5', 'B4']).rename( + 'NDWI'); + var mndwi = image.normalizedDifference(['B2', 'B5']).rename( + 'MNDWI'); + return image.addBands(ndvi) + .addBands(evi) + .addBands(savi) + .addBands(ndmi) + .addBands(ndwi) + .addBands(mndwi); +}; + +// 2.6 Apply the indices function to the collection +var collectionSR_wIndex = getCombinedSRcollection(startYear, startDay, + endyear, endDay).map(addIndices); +var collectionL5L7L8 = collectionSR_wIndex.filterBounds(areaOfstudy); + +// STEP 3 - VEGETATION INDEX ANOMALY + +var index = 'NDVI'; +var ref_start = '1984-01-01'; // Start of the period +var ref_end = '1999-12-31'; // End of the period + +var reference = collectionL5L7L8 + .filterDate(ref_start, ref_end) + .select(index) + .sort('system:time_start', true); +print('Number of images in Reference Collection', reference.size()); + +// 3.2 Compute the Mean value for the vegetation index +// (and other stats) for the reference period. +var mean = reference.mean().mask(extentBuffer); +var median = reference.median().mask(extentBuffer); +var max = reference.max().mask(extentBuffer); +var min = reference.min().mask(extentBuffer); + +var period_start = '2000-01-01'; // Full period +var period_end = '2020-12-31'; + +// 3.4 Anomaly calculation +var anomalyfunction = function(image) { + return image.subtract(mean) + .set('system:time_start', image.get('system:time_start')); +}; + +var series = collectionL5L7L8.filterDate(period_start, period_end) + .map(anomalyfunction); + +// Sum the values of the series. +var seriesSum = series.select(index).sum().mask(extentBuffer); +var numImages = series.select(index).count().mask(extentBuffer); +var anomaly = seriesSum.divide(numImages); + +var visAnon = { + min: -0.20, + max: 0.20, + palette: ['#481567FF', '#482677FF', '#453781FF', '#404788FF', + '#39568CFF', '#33638DFF', '#2D708EFF', '#287D8EFF', + '#238A8DFF', + '#1F968BFF', '#20A387FF', '#29AF7FFF', '#3CBB75FF', + '#55C667FF', + '#73D055FF', '#95D840FF', '#B8DE29FF', '#DCE319FF', + '#FDE725FF' + ] +}; +Map.addLayer(anomaly, visAnon, index + ' anomaly'); + +var thresholdLoss = -0.05; +var lossfromndvi = anomaly.lte(thresholdLoss) + .selfMask() + .updateMask( + mangrove2000 + ); // Only show the losses within the mangrove extent of year 2000 + +Map.addLayer(lossfromndvi, { + palette: ['orange'] +}, 'Loss from Anomaly 00-20'); + +var thresholdGain = 0.20; +var gainfromndvi = anomaly.gte(thresholdGain) + .selfMask() + .updateMask( + extentBuffer + ); // Only show the gains within the mangrove extent buffer of year 2000 + +Map.addLayer(gainfromndvi, { + palette: ['blue'] +}, 'Gain from Anomaly 00-20'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33s1 - Supplemental.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33s1 - Supplemental.ipynb new file mode 100644 index 0000000..cf2ee3e --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33s1 - Supplemental.ipynb @@ -0,0 +1,9396 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "imageCollection = ee.ImageCollection(\"LANDSAT/MANGROVE_FORESTS\"),\n", + " Mangrove =\n", + "\n", + " # shown: False #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([-13.661310159982044, 9.863979956913798]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.662340128243763, 9.860766590107316]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.666974985421497, 9.860428339147328]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.671094858468372, 9.857891445884547]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.670579874337513, 9.852310212005683]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.671953165353138, 9.847405413374954]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.66165348273595, 9.847236281087548]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.661481821358997, 9.851295432063562]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.658563577950794, 9.848251073512062]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.659936868966419, 9.84317708019428]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.671609842599231, 9.844361018943362]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.680021250069935, 9.842500541860387]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.681222879708606, 9.84520668687933]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.686201059640247, 9.847067148713466]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.690149271310169, 9.849096731482412]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.690492594064075, 9.851802822424787]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.684999430001575, 9.854508891171829]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.682767832101185, 9.864318204228617]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.68139454108556, 9.870237476020813]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.677789652169544, 9.864149080614622]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.67864795905431, 9.861950465733774]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.651010477364856, 9.872943393406452]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.655130350411731, 9.876833110681515]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.654443704903919, 9.884950633398141]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.648950540841419, 9.880553666792991]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.646375620187122, 9.87564928855102]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.638822519601185, 9.871083077592651]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.63744922858556, 9.868038901772325]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.633157694161731, 9.86753153639998]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.633501016915638, 9.864149080614622]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.63470264655431, 9.860428339147328]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.626806223214466, 9.862288715131701]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.630239450753528, 9.866685925709453]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.625261270821888, 9.868038901772325]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.621828043282825, 9.867024170246147]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.616678201974231, 9.865163820996548]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.623029672921497, 9.862457839700498]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6204547522672, 9.865163820996548]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.618394815743763, 9.862119590476139]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.627321207345325, 9.861273965896487]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.630754434884388, 9.858567952663368]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.632814371407825, 9.854508891171829]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.630067789376575, 9.865163820996548]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.637792551339466, 9.866685925709453]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.645002329171497, 9.8715904374934]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.649637186349231, 9.872436035590608]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.654100382150013, 9.873281631515944]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.65289875251134, 9.879200742165947]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.653242075265247, 9.882921271500603]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.657876932442981, 9.882921271500603]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"49\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.648778879464466, 9.886134422054315]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"50\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.642255747140247, 9.880046320709882]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"51\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6424274085172, 9.877171344793748]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"52\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.644830667794544, 9.88089189708034]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"53\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.646032297433216, 9.884443294097883]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"54\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.625261270821888, 9.876325758861322]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"55\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.625261270821888, 9.873281631515944]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"56\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.618738138497669, 9.871928676992896]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"57\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.616678201974231, 9.873281631515944]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"58\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.613244974435169, 9.860766590107316]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"59\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.61822315436681, 9.858906205532225]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"60\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.621656381905872, 9.854339762525496]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"61\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.62096973639806, 9.851464562270667]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"62\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.618909799874622, 9.849773256298489]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"63\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.614618265450794, 9.848420205279472]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"64\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.609811746896106, 9.848420205279472]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"65\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.603288614571888, 9.85044977972763]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"66\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.602945291817981, 9.853155859573075]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"67\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.609296762765247, 9.855185404889882]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"68\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.614789926827747, 9.855185404889882]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"69\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.613073313058216, 9.85501627659046]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"70\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.605005228341419, 9.859075331836523]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"71\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6039752600797, 9.8631343371077]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"72\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.602601969064075, 9.86059746467071]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"73\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.598310434640247, 9.858398826098787]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"74\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.594533884347278, 9.856200172865066]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"75\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.592817270577747, 9.852479341692579]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"76\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.594190561593372, 9.848589336960218]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"77\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.597108805001575, 9.84520668687933]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"78\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.598653757394153, 9.841824002140536]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"79\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.603288614571888, 9.840809189962322]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"80\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.605691873849231, 9.84317708019428]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"81\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.597108805001575, 9.840978325541894]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"82\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.592302286446888, 9.845037553465422]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"83\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.590585672677356, 9.851633692391072]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"84\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.589899027169544, 9.856707555681723]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"85\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.58474918586095, 9.85653842816291]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"86\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.618394815743763, 9.84351534884146]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"87\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.618738138497669, 9.841147461034842]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"88\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.622343027413685, 9.839117829403516]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"89\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.623544657052356, 9.843853617142127]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"90\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.625776254952747, 9.846559751071275]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"91\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.628351175607044, 9.850788040922096]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"92\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.629381143868763, 9.853663247072985]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"93\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.628007852853138, 9.857722318972954]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"94\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.630754434884388, 9.852648471292772]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"95\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.631784403146106, 9.848251073512062]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"96\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.635389292062122, 9.851802822424787]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"97\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.621656381905872, 9.862119590476139]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"98\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.613244974435169, 9.846390618350565]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"99\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.61221500617345, 9.841824002140536]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"100\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.612043344796497, 9.838948692871343]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"101\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.647062265694935, 9.837933871859953]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"102\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.644315683663685, 9.842838811200574]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"103\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.642770731271106, 9.839117829403516]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"104\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.63744922858556, 9.844868419964866]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"105\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.657876932442981, 9.858737079141173]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"106\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.662511789620716, 9.858567952663368]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"107\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.706800424874622, 9.85535453310259]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"108\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.70611377936681, 9.852986730233013]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"109\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.70559879523595, 9.850618910368206]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"110\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.701135599435169, 9.85501627659046]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"111\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.70010563117345, 9.864656451196232]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"112\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.69787403327306, 9.870913957452]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"113\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.51410768826411, 9.628911414362962]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"114\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.512734397248485, 9.626711248582774]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"115\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.507241233185985, 9.62518804849386]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"116\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.506897910432079, 9.623664841537515]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"117\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.502263053254344, 9.62620351598291]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"118\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.513936026887157, 9.62011066527207]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"119\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.516167624787547, 9.618248938979898]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"120\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.510331137971141, 9.614356205426008]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"121\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.515137656525829, 9.609955670070063]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"122\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.509987815217235, 9.605385822784951]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"123\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.507756217316844, 9.603354759745566]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"124\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.505009635285594, 9.599292597123075]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"125\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.50363634426997, 9.59573816487159]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"126\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.50363634426997, 9.591675910937065]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"127\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.504494651154735, 9.58744434466681]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"128\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.507241233185985, 9.584228318994764]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"129\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.509644492463329, 9.581858596362853]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"130\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.511189444855907, 9.57965812481821]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"131\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.510502799348094, 9.574749329210274]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"132\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.509987815217235, 9.572040997815119]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"133\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.50861452420161, 9.568317006897123]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"134\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.509301169709422, 9.56391587411893]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"135\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.527497275666454, 9.559514684378756]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"136\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.530415519074657, 9.555959835714257]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"137\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.531960471467235, 9.553082073885204]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"138\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.538140281037547, 9.554774877907569]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"139\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.542603476838329, 9.55511343770186]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"140\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.547924979523875, 9.555282717472718]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"141\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.550843222932079, 9.558668295208136]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"142\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.554276450471141, 9.562053839256034]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"143\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.554276450471141, 9.560191794199206]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"144\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.54157350857661, 9.564085149510012]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"145\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.539856894807079, 9.56069962568011]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"146\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53934191067622, 9.564931525201379]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"147\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.542603476838329, 9.561038179579535]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"148\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.548954947785594, 9.566116447629842]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"149\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.554104789094188, 9.56899409919021]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"150\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.55753801663325, 9.568655553212261]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"151\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.560112937287547, 9.57068682402128]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"152\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.587150488427461, 9.588802244505368]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"153\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.570670996239961, 9.591510442157333]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"154\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.575820837548555, 9.59591121720367]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"155\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.575820837548555, 9.607082158693155]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"156\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.57994071059543, 9.608436187164969]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"157\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.566894445946993, 9.610128715137005]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"158\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.56071463637668, 9.613513745683104]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"159\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.55796805434543, 9.615206248254303]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"160\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.562774572900118, 9.610128715137005]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"161\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.562087927392305, 9.60437408550142]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"162\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.559341345361055, 9.599296389893185]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"163\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.558998022607149, 9.594895658802585]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"164\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.558654699853243, 9.589817821159402]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"165\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.560371313622774, 9.586094025227984]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"166\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.564147863915743, 9.59320305470555]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"167\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.568611059716524, 9.590494870572455]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"168\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.525695715478243, 9.592526010700317]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"169\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52775565200168, 9.595234178607734]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"170\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52775565200168, 9.588802244505368]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"171\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.529815588525118, 9.584739907481588]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"172\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.525695715478243, 9.581693122794402]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"173\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53324881606418, 9.595234178607734]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"174\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.51402274184543, 9.608436187164969]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"175\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.498229895165743, 9.649731449891549]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"176\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.49754324965793, 9.656839140978562]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"177\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.502693090966524, 9.670377185054937]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"178\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.43711844497043, 9.683237822077341]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"179\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.435745153954805, 9.682560958718609]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"180\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.436088476708711, 9.678499749919098]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"181\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.43986502700168, 9.672069402255028]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"182\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.464240942529024, 9.658869882308721]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"183\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.447418127587618, 9.609620957634213]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"184\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.457374487450899, 9.61622174573161]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"185\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.455314550927461, 9.613682996321328]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"186\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.45308295302707, 9.613175244152618]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"187\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.45685950332004, 9.607589920004852]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"188\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.456687841943086, 9.601835247213083]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"189\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.459949408105196, 9.59997342037242]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"190\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.46235266738254, 9.601665990650465]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"191\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.487586889794649, 9.647362186207621]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"192\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.477115545800508, 9.669700295790179]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"193\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.500118170312227, 9.668684959338288]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"194\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.516597662499727, 9.616390995014688]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"195\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.49256506972629, 9.621637680767956]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"196\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.495998297265352, 9.622991650968471]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"197\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.488616858056368, 9.618083483186357]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"198\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.517627630761446, 9.640254295246155]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"199\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.521575842431368, 9.643131316780002]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"200\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.520202551415743, 9.639577345436397]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"201\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52003089003879, 9.638054203397656]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"202\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.531360540917696, 9.756500193416775]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"203\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.529815588525118, 9.752947423648195]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"204\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.527583990624727, 9.74939461601333]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"205\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52500906997043, 9.752270701303399]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"206\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.521232519677461, 9.756161836022985]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"207\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.518829260400118, 9.759037862917843]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"208\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52449408583957, 9.759037862917843]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"209\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.527583990624727, 9.756838550466977]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"210\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.528098974755586, 9.760560455339853]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"211\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.530158911279024, 9.76495901656875]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"212\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.528785620263399, 9.766481581917269]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"213\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.525867376855196, 9.769019175354734]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"214\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.524150763085665, 9.770710893563262]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"215\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52552405410129, 9.767496621613954]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"216\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.522434149316133, 9.769188347562617]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"217\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.519344244530977, 9.76698910215254]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"218\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.519344244530977, 9.765635713138927]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"219\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.515567694238008, 9.76326726912586]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"220\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.51453772597629, 9.760898808266235]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"221\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.511447821191133, 9.76242139218114]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"222\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.512134466698946, 9.764789842211282]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"223\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.51127615981418, 9.768004140301493]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"224\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.514194403222383, 9.77054172212945]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"225\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.516940985253633, 9.768680830680962]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"226\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.518142614892305, 9.77240260317031]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"227\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.521575842431368, 9.774094304174467]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"228\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.520202551415743, 9.773925134461207]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"229\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.526382360986055, 9.766650755415005]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"230\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.531360540917696, 9.763774794261284]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"231\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.525180731347383, 9.75819197523183]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"232\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.522434149316133, 9.756161836022985]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"233\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.524150763085665, 9.75210152050255]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"234\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.536167059472383, 9.74973298027629]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"235\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.537025366357149, 9.746010954502083]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"236\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.538055334618868, 9.74347318584398]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"237\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.538913641503633, 9.741273770727341]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"238\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.536682043603243, 9.740935397884376]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"239\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53548041396457, 9.743811556113686]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"240\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.534450445702852, 9.747026056559818]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"241\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.532562170556368, 9.74550340231482]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"242\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52998724990207, 9.744149926040262]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"243\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.526897345116915, 9.744319110874857]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"244\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.524322424462618, 9.74465748028668]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"245\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.523807440331758, 9.742458072976037]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"246\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.523807440331758, 9.740258651169293]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"247\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.528613958886446, 9.735521385749621]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"248\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.532562170556368, 9.73670570840598]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"249\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.533077154687227, 9.740766211334252]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"250\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.532390509179415, 9.742458072976037]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"251\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.529472265771211, 9.742119701333845]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"252\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.527412329247774, 9.741950515384083]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"253\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52998724990207, 9.740597024698355]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"254\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.526725683739961, 9.740597024698355]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"255\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.581828985741915, 9.75430086421618]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"256\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.581828985741915, 9.753116604019736]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"257\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.585090551904024, 9.753285784305413]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"258\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.585262213280977, 9.7510864338945]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"259\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.584747229150118, 9.750240526026937]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"260\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.55470648818332, 9.730276477790866]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"261\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.553333197167696, 9.727400202985306]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"262\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.554534826806368, 9.72587745924342]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"263\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.541316900780977, 9.72587745924342]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"264\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.542861853173555, 9.729430517182633]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"265\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.542346869042696, 9.731968392581692]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"266\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53874198012668, 9.731968392581692]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"267\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.537883673241915, 9.728753747154048]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"268\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.535308752587618, 9.727400202985306]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"269\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.534450445702852, 9.731460819044104]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"270\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.534622107079805, 9.734167868999362]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"271\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.540115271142305, 9.737720838768078]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"272\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.543205175927461, 9.73941271584591]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"273\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.551444922021211, 9.76512819084024]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"274\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.556423101952852, 9.762252216534353]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"275\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.55195990615207, 9.76326726912586]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"276\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.548355017236055, 9.768004140301493]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"277\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.54749671035129, 9.77240260317031]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"278\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.545608435204805, 9.764451493238456]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"279\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.538398657372774, 9.759037862917843]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"280\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.539085302880586, 9.75700772886324]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"281\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.544921789696993, 9.74837952116449]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"282\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.54749671035129, 9.74550340231482]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"283\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.552303228905977, 9.74465748028668]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"284\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.555908117821993, 9.747026056559818]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"285\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.654785070946993, 9.909740584973962]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"286\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.650321875146211, 9.90940238439265]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"287\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.652381811669649, 9.908049578580023]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"288\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.671951208642305, 9.897903357197523]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"289\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.674011145165743, 9.893168346572097]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"290\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.675727758935274, 9.889786154339548]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"291\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.670234594872774, 9.886065702680298]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"292\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.67057791762668, 9.88302166546021]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"293\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.674011145165743, 9.880315830943365]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"294\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.67057791762668, 9.876933506499089]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"295\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.672981176904024, 9.873551147289685]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"296\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.687400732568086, 9.874904095144537]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"297\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.649388511149061, 9.835897848162661]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"298\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.643637855021131, 9.837504656559055]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"299\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.65016098734535, 9.832853347671694]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"300\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.651105124918592, 9.82913225343917]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"301\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.64767189737953, 9.824988258312377]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"302\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.644496161905897, 9.822789382675966]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"303\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.643981177775037, 9.824988258312377]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"304\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.644238669840467, 9.822451092819612]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"305\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.645096976725233, 9.826172262217474]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"306\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.635655600992811, 9.82676426258091]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"307\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.633338172403944, 9.825411117336346]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"308\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.630763251749647, 9.82591854745168]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"309\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.631020743815077, 9.82388882232074]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"310\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.629046637980116, 9.82591854745168]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"311\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.623725135294569, 9.835982417220407]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"312\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.623639304606092, 9.834206462463124]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"313\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.618746955362928, 9.832937917508435]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"314\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.614283759562147, 9.835644140859554]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"315\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.610678870646131, 9.837420087890889]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"316\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.599435050455702, 9.832599638031681]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"317\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.602009971109998, 9.831838507943388]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"318\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.605185706583631, 9.831753937825424]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"319\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.60844727274574, 9.831500227341687]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"320\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.610249717203748, 9.830739094722384]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"321\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.611022193400037, 9.82955510716544]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"322\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.612052161661756, 9.827948260129261]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"323\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.612652976481092, 9.825749404166388]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"324\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.611365516153944, 9.822958527474464]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"325\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.607159812418592, 9.82092878418678]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"326\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.606558997599256, 9.82371967799777]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"327\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.608876426188123, 9.826510548269171]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"328\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.606558997599256, 9.829470536463448]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"329\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.60295410868324, 9.828709399172217]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"330\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.60123749491371, 9.830400812995848]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"331\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.601838309733045, 9.827863689016356]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"332\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.599778373209608, 9.831161946393877]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"333\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.601151664225233, 9.827440833127513]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"334\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.605099875895155, 9.820167627244706]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"335\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.557979365634356, 9.739303420698274]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"336\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.531028529452716, 9.733720191979573]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"337\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.530856868075762, 9.731520712614177]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"338\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.526050349521075, 9.736596412372151]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"339\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.999500577660426, 10.035249558065319]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"340\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.995724027367457, 10.039644440416982]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"341\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.000530545922144, 10.0437012019244]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"342\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.993320768090113, 10.056209229570396]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"343\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.990574186058863, 10.06060382706283]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"344\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.965854947777613, 10.049448193638165]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"345\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.954525296898707, 10.051138465880086]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"346\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.946628873558863, 10.066012480342117]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"347\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.93598586818777, 10.064998364754487]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"348\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.964824979515894, 10.049448193638165]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"349\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.96619827053152, 10.045391504205845]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"350\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.955898587914332, 10.044039263087305]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"351\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.947315519066676, 10.041334763892895]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"352\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.947315519066676, 10.036939904492623]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"353\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.9431956460198, 10.028488084121358]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"354\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.938045804711207, 10.021050299807792]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"355\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.935642545433863, 10.027135772396795]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"356\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.932552640648707, 10.033221130703813]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"357\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.0200999428948, 10.093730404886111]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"358\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.020786588402613, 10.084604034450745]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"359\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.021473233910426, 10.077505567574326]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"360\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.024906461449488, 10.067364629502437]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"361\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.026279752465113, 10.055871181133208]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"362\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.030056302758082, 10.051814572302199]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"363\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.0255931069573, 10.043025078538774]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"364\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.030399625511988, 10.042687016316068]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"365\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.023533170433863, 10.03896830855453]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"366\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.022503202172144, 10.054518983847622]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"367\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.027309720726832, 10.053842883082915]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"368\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.034519498558863, 10.05722337275972]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"369\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.040699308129176, 10.06060382706283]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"370\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.042759244652613, 10.051814572302199]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"371\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.042415921898707, 10.07277316948383]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"372\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.039669339867457, 10.079533716921128]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"373\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.036922757836207, 10.081899875029649]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"374\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.03383285305105, 10.075477405468384]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"375\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.035206144066676, 10.072435138391462]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"376\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.032802884789332, 10.070068910826576]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"377\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.029026334496363, 10.068378737654886]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"378\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.0255931069573, 10.091026322094907]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"379\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.042415921898707, 10.10927843988686]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"380\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.046879117699488, 10.108264460521394]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"381\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.051685636254176, 10.106574487803298]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"382\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.057865445824488, 10.10454650881349]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"383\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.059925382347926, 10.123473814924237]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"384\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.06232864162527, 10.117728143481251]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"385\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.064731900902613, 10.114348288716734]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"386\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.06507522365652, 10.110968398385992]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"387\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.060268705101832, 10.115362248881063]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"388\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.054432218285426, 10.115700234891127]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"389\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.052028959008082, 10.117052175374186]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"390\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.0365794350823, 10.126853573603118]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"391\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.035892789574488, 10.122797858916474]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"392\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.030742948265894, 10.12752952106626]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"393\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.023189847679957, 10.12482572266808]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"394\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.0200999428948, 10.125501674403939]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"395\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.040012662621363, 10.12482572266808]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"396\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.041729276390894, 10.130233296673653]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"397\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.025249784203394, 10.117052175374186]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"398\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.020786588402613, 10.120094020648413]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"399\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.017696683617457, 10.11265834799643]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"400\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.005337064476832, 10.108264460521394]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"401\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.003277127953394, 10.108602453998687]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"402\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.005337064476832, 10.094068413637778]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"403\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.003277127953394, 10.092040355803496]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"404\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.001217191429957, 10.088322216591616]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"405\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.958988492699488, 10.07277316948383]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"406\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.95521194240652, 10.067364629502437]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"407\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.958645169945582, 10.064660325517268]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"408\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.94697219631277, 10.082913937472131]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"409\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.121380155297144, 10.071421042988929]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"410\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.132366483422144, 10.071759075144007]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"411\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.139919584008082, 10.097110476427376]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"412\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.132023160668238, 10.101842516928926]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"413\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.130649869652613, 10.108264460521394]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"414\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.123096769066676, 10.12752952106626]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"415\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.108333890648707, 10.125501674403939]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"416\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.092197721215113, 10.125839649737824]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"417\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.088421170922144, 10.114686275793847]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"418\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.099064176293238, 10.114010301283944]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"419\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.093914334984644, 10.102180517157963]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"420\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.093914334984644, 10.095082437762859]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"421\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.104900663109644, 10.086632139121175]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"422\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.09528762600027, 10.150172937371915]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"423\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.091167752953394, 10.155580083537874]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"424\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.097690885277613, 10.160311261454012]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"425\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.104214017601832, 10.159635383180365]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"426\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.11073714992605, 10.154566250592843]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"427\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.116916959496363, 10.175180221816479]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"428\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.126186673851832, 10.185655664472218]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"429\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.132023160668238, 10.186331487669804]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"430\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.130649869652613, 10.181262778780816]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"431\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.145756070824488, 10.186669398731471]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"432\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.14369613430105, 10.17653191116013]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"433\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.138546292992457, 10.166394101608132]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"434\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.142666166039332, 10.162338887701564]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"435\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.145412748070582, 10.160311261454012]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"436\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.135799710961207, 10.159973322495789]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"437\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.172878568383082, 10.151524732480077]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"438\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.17768508693777, 10.151524732480077]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"439\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.181804959984644, 10.14848318545724]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"440\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.182834928246363, 10.141048171078742]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"441\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.182491605492457, 10.137330599166003]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"442\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.180774991722926, 10.199847650708099]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"443\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.182491605492457, 10.204578172280252]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"444\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.184551542015894, 10.200185547437004]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"445\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.187298124047144, 10.204240280213417]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"446\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.18764144680105, 10.200861339819124]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"447\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.189701383324488, 10.204916063988373]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"448\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.1903880288323, 10.202888708359332]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"449\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.192791288109644, 10.205591846328486]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"450\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.195537870140894, 10.204240280213417]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"451\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.172535245629176, 10.204240280213417]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"452\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.172535245629176, 10.199847650708099]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"453\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.175625150414332, 10.19646866370126]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"454\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.17493850490652, 10.193427544749241]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"455\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.170131986351832, 10.197820262805768]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"456\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.162235563011988, 10.185317752336328]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"457\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.152279203148707, 10.195454960609357]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"458\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.149532621117457, 10.199509753620669]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"459\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.150905912133082, 10.190724303536632]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"460\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.137173001976832, 10.202212920280374]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"461\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.140262906761988, 10.204578172280252]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"462\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.135113065453394, 10.200861339819124]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"463\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.134083097191676, 10.205591846328486]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"464\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.127903287621363, 10.20322660186085]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"465\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.126186673851832, 10.201537130766951]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"466\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.122410123558863, 10.197820262805768]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"467\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.117603605004176, 10.194779156756098]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"468\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.114170377465113, 10.192075927009176]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"469\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.10902053615652, 10.195792861998385]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"470\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.110050504418238, 10.191400115989413]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"471\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.106960599633082, 10.187345219780514]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"472\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.09528762600027, 10.194441254291904]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"473\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.096317594261988, 10.190048489650911]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"474\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.091854398461207, 10.187345219780514]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"475\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.09803420803152, 10.185993576250045]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"476\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.094600980492457, 10.184979839842379]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"477\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.091167752953394, 10.181938611286409]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"478\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.08430129787527, 10.184304013780388]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"479\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.085674588890894, 10.180586944843554]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"480\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.089107816429957, 10.176869832601675]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"481\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.214420621605738, 10.1403722521214]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"482\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.218540494652613, 10.13597874414021]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"483\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.220943753929957, 10.139020409928333]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"484\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.214763944359644, 10.137668562031386]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"485\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.224720304222926, 10.137668562031386]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"486\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.227466886254176, 10.143413876197156]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"487\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.234676664086207, 10.212349590792996]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"488\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.234676664086207, 10.207619184738817]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"489\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.236393277855738, 10.204240280213417]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"490\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.239483182640894, 10.21099805338396]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"491\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.241543119164332, 10.219107191672828]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"492\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.285488431664332, 10.228567591509108]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"493\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.28651839992605, 10.2278918580079]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"494\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.288921659203394, 10.2278918580079]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"495\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.195194547386988, 10.222148065200006]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"496\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.19313461086355, 10.220120819414998]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"497\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.1958811928948, 10.217755682988003]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"498\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.198971097679957, 10.216404168556885]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"499\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.52315168974187, 9.621012255759489],\n", + " [-13.524095827315112, 9.618727414519354],\n", + " [-13.521950060103197, 9.618727414519354]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"500\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.486244493696947, 9.617542675945005],\n", + " [-13.487016969893237, 9.615596310704088],\n", + " [-13.484098726485033, 9.615511685874274]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"501\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.52801132696572, 9.618896665130736],\n", + " [-13.528526311096579, 9.61568093809527],\n", + " [-13.525779729065329, 9.616188686502388]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"502\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.463294987854391, 9.581660060195713],\n", + " [-13.460205083069235, 9.579628855011359],\n", + " [-13.457630162414938, 9.582337125889376]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"503\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.480976109680563, 9.657990686442465],\n", + " [-13.482006077942282, 9.654775331951527],\n", + " [-13.479431157287985, 9.65528302154379]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"504\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.50775528448525, 9.663405950907341],\n", + " [-13.506896977600485, 9.659175282988585],\n", + " [-13.504493718323141, 9.660359875366272]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"505\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.446472172912985, 9.663405950907341],\n", + " [-13.449905400452048, 9.661882916583096],\n", + " [-13.44733047979775, 9.659344510726331]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"506\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.60766220587197, 9.722291314738907],\n", + " [-13.605430607971579, 9.71958416859477],\n", + " [-13.603199010071188, 9.723137293414952]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"507\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.60714722174111, 9.785902927708433],\n", + " [-13.60714722174111, 9.78133547748043],\n", + " [-13.604057316955954, 9.783534628020057]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"508\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.578308110412985, 9.78065881284821],\n", + " [-13.578308110412985, 9.777275469025232],\n", + " [-13.575389867004782, 9.779474646427087]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"509\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.701560979065329, 9.777275469025232],\n", + " [-13.699672703918845, 9.773722920958017],\n", + " [-13.6972694446415, 9.776937132749193]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"510\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.959463327400387, 10.056802999864853]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"511\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.981779306404293, 10.019108491959036]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"512\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.009416788093747, 10.03787177777399]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"513\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.006670206062497, 10.038209845027112]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"514\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.006155221931637, 10.036857573896196]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"515\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.016969888679684, 10.018601361050132]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"516\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.008730142585934, 10.053422505790016]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"517\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.02005979346484, 10.052746402731378]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"518\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.020918100349606, 10.04699946963806]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"519\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.996713846199215, 10.049534893889792]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"520\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.433250165943592, 9.515253067891168]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"521\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.441661573414295, 9.523548647400151]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"522\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.440116621021717, 9.50661867948395]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"523\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.443721509937733, 9.516776760858239]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"524\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.447154737476795, 9.522532872976543]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"525\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.445953107838124, 9.529473937981358]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"526\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.452647901539295, 9.52913535271861]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"527\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.442004896168202, 9.53793846035774]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"528\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.439944959644764, 9.543524930040505]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"529\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.449729658131092, 9.53759988349555]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"530\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.450072980884999, 9.544202071659186]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"531\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.452819562916249, 9.50407911200358]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"532\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.458484388355702, 9.50255536246944]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"533\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.454192853931874, 9.4998464576609]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"534\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.454364515308827, 9.491719614665294]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"535\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.394283033375233, 9.52913535271861]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"536\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.389991498951405, 9.545048496790354]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"537\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.431361890797108, 9.493582033213793]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"538\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.42758534050414, 9.49307410188631]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"539\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.439944959644764, 9.491719614665294]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"540\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.446639753345936, 9.480883524227751]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"541\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.432906843189686, 9.488671998844872]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"542\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.50946781731078, 9.52168639198262]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"543\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.530582166676014, 9.523379351872673]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"544\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.54568836784789, 9.526765246475557]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"545\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.552726484302967, 9.527442421367]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"546\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.555816389088124, 9.53946205207731]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"547\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.538821912769764, 9.540816350112253]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"548\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.444579816822499, 9.462935496757591]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"549\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.38037846184203, 9.45480777971921]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"550\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.35239765739867, 9.47174030668765]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"551\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.359264112476795, 9.486132298297015]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"552\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.359607435230702, 9.484100524314757]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"553\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.337463117603749, 9.47123234301792]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"554\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.34141132927367, 9.49425927381244]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"555\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.341582990650624, 9.498153381271607]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"556\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.337978101734608, 9.505772159084684]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"557\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.348621107105702, 9.512036360435498]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"558\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.352740980152577, 9.512713564520134]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"559\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.329910017017811, 9.432624908679694]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"560\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.33420155144164, 9.433810289049077]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"561\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.332828260426014, 9.429915452536795]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"562\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.345874525074452, 9.413658269000564]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"563\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.289397932056874, 9.419754802521876]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"564\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.282874799732655, 9.414674365391507]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"565\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.25901386833617, 9.407900333029371]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"566\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.244250989918202, 9.402481011589613]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"567\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.280128217701405, 9.39350507376156]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"568\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.28150150871703, 9.34235473089528]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"569\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.297122694019764, 9.35065447039907]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"570\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.288539625172108, 9.360647771582952]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"571\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.307422376636952, 9.358784635516088]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"572\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.331969953541249, 9.35963151678442]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"573\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.334029890064686, 9.35438081966868]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"574\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.341068006519764, 9.351840131314342]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"575\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.34467289543578, 9.336764998940213]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"576\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.291286207203358, 9.319317683374159]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"577\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.285106397633045, 9.305426964030449]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"578\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.273433424000233, 9.314405175017802]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"579\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.282703138355702, 9.318978891913023]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"580\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.249572492603749, 9.311864195309921]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"581\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.258842206959217, 9.304071742342185]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"582\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.252662397388905, 9.30034485562317]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"583\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.26004383659789, 9.293738004335609]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"584\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.263477064136952, 9.289502777673848]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"585\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.27377674675414, 9.29627911574363]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"586\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.279784894947499, 9.270528333966]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"587\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.25455067253539, 9.256466254018491]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"588\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.21009037590453, 9.264937453931857]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"589\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.205283857349842, 9.260532455463142]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"590\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.24030277824828, 9.232915246293794]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"591\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.259185529713124, 9.244097935622158]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"592\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.262103773121327, 9.239692676146335]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"593\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.27600834465453, 9.234101305928146]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"594\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.29025623894164, 9.216648883114125]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"595\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.29025623894164, 9.206820925471753]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"596\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.294891096119374, 9.20224574851503]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"597\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.305877424244374, 9.201398487027035]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"598\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.22382328606078, 9.209871010547175]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"599\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.192065931324452, 9.215632210520651]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"600\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.190177656177967, 9.218851663690847]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"601\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.187774396900624, 9.212751622278716]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"602\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.206313825611561, 9.193095217068748]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"603\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.19034931755492, 9.189536613174072]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"604\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.19086430168578, 9.184622291871827]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"605\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.18588612175414, 9.18394444910143]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"606\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.22056171989867, 9.209701562066911]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"607\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.237384534840077, 9.212921069296193]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"608\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.248199201588124, 9.214276642509766]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"609\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.283218122486561, 9.196484330379587]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"610\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.279956556324452, 9.192925760551425]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"611\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.289912916187733, 9.193264673504942]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"612\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.295062757496327, 9.194620322074341]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"613\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.281844831470936, 9.176149164076689]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"614\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.282703138355702, 9.17309878850916]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"615\"\n", + " })]),\n", + " NonMangrove =\n", + "\n", + " # shown: False #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([-13.640199652454818, 9.89526389438857]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.64088629796263, 9.8937419219008]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.637453070423568, 9.89526389438857]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6336765201306, 9.895940324341653]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.631273260853256, 9.896109431612254]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.629556647083724, 9.894080138618607]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.628011694691146, 9.892558160646315]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.628011694691146, 9.890528845715746]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6281833560681, 9.888161295791257]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.63539313390013, 9.882918803133371]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6336765201306, 9.879198273770779]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.63264655186888, 9.877337993310382]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.629041662952865, 9.880043852321075]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.62543677403685, 9.883426144785675]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.631273260853256, 9.88934507288544]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.638483038685287, 9.887653961445755]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.638483038685287, 9.886301066029677]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.620458594105209, 9.883933485655257]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.620458594105209, 9.88122765863999]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.620286932728256, 9.878352693047196]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.618226996204818, 9.884779052031762]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.612390509388412, 9.881058543712408]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.609815588734115, 9.879198273770779]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.609472265980209, 9.882580574930365]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.614107123157943, 9.8912052854185]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.594366064808334, 9.865499598598175]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.596254339954818, 9.863639240739971]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.593851080677474, 9.863300992728192]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.592306128284896, 9.867359945951616]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.595567694447006, 9.870742368765931]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.59745596959349, 9.872433567144729]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.59694098546263, 9.870911488994695]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.487671836213329, 9.603185503942363]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.488873465852, 9.602508479883612]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.489045127228954, 9.599969627609893]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.488701804475047, 9.597769273580928]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.490075095490672, 9.591506649300088]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.48389528592036, 9.598107790515527]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.442353232697704, 9.603016248054569]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.440808280305125, 9.604708803125543]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.438233359650829, 9.60572433210698]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.43445680935786, 9.602339223657433]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.43720339138911, 9.600985170803016]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.43668840725825, 9.59472260595197]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.438405021027782, 9.592860740029861]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.438748343781688, 9.590491077703861]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.439606650666454, 9.589644765716853]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.444069846467235, 9.581689329827402]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.446301444367625, 9.58050446171579]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.459862693146922, 9.594384085635884]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"49\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.46243761380122, 9.59472260595197]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"50\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.469132407502391, 9.611817442013729]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"51\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.469475730256297, 9.615033205784563]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"52\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.471364005402782, 9.61621795315115]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"53\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.474282248810985, 9.61621795315115]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"54\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.472222312287547, 9.611817442013729]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"55\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.469304068879344, 9.609447912307623]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"56\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.47016237576411, 9.620787654108952]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"57\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.46964739163325, 9.624511068472138]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"58\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.46964739163325, 9.626372760267671]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"59\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.48938844998286, 9.624341823254763]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"60\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.492478354768016, 9.624341823254763]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"61\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.495568259553172, 9.62620351598291]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"62\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.496083243684032, 9.630434597660521]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"63\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.423127158478954, 9.615371705455658]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"64\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.411797507600047, 9.610801931314386]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"65\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.41248415310786, 9.606570603931203]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"66\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.408879264191844, 9.615202455662457]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"67\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.409050925568797, 9.621972381310744]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"68\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.414887412385204, 9.625865027159046]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"69\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.419693930939891, 9.63331170291934]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"70\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.413685782746532, 9.634665626321135]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"71\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.403557761506297, 9.632296256804214]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"72\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.405446036652782, 9.63128080763471]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"73\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.40750597317622, 9.634665626321135]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"74\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.409565909699657, 9.636527262130242]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"75\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.431023581818797, 9.63331170291934]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"76\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.532562170556368, 9.62265315892689]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"77\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.534278784325899, 9.62400712505879]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"78\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.531875525048555, 9.626376552734179]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"79\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53050223403293, 9.628407477514115]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"80\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.551101599267305, 9.632130807889933]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"81\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.553504858544649, 9.628407477514115]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"82\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.561057959130586, 9.635854097202463]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"83\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.566894445946993, 9.630099905501739]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"84\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.569641027978243, 9.627053529017628]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"85\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.572387610009493, 9.624345615744067]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"86\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.576164160302461, 9.6209606936336]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"87\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.579597387841524, 9.617914234750414]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"88\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.581314001611055, 9.614190747727863]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"89\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.586463842919649, 9.611144227856878]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"90\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.590583715966524, 9.608436187164969]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"91\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.592643652489961, 9.60437408550142]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"92\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.597793493798555, 9.600650449498545]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"93\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.601570044091524, 9.595234178607734]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"94\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.599510107568086, 9.587786664810263]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"95\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.347854528954805, 9.631453841784552]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"96\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.353347693017305, 9.629084449726962]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"97\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.345451269677461, 9.657177598717503]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"98\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.348541174462618, 9.663608231103328]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"99\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.350257788232149, 9.672069402255028]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"100\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.346137915185274, 9.67477693205716]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"101\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.369140539696993, 9.638561918174645]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"102\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.418922339013399, 9.682899390568524]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"103\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.454284582665743, 9.670715629176321]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"104\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.451538000634493, 9.678499749919098]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"105\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.451538000634493, 9.682899390568524]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"106\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.454284582665743, 9.683237822077341]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"107\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.447418127587618, 9.679515056722407]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"108\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.44535819106418, 9.672069402255028]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"109\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.439178381493868, 9.643639023914613]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"110\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.441924963525118, 9.641946663826616]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"111\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.446388159325899, 9.643639023914613]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"112\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.452224646142305, 9.637884964968881]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"113\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.45909110122043, 9.642285136523668]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"114\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.458747778466524, 9.634161698060968]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"115\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.45909110122043, 9.626376552734179]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"116\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.44535819106418, 9.628745963790163]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"117\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.430938635400118, 9.610128715137005]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"118\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.417549047997774, 9.599634905301931]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"119\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.415489111474336, 9.591510442157333]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"120\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.417549047997774, 9.59117191863368]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"121\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.413429174950899, 9.583047252699105]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"122\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.413085852196993, 9.580000452816348]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"123\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.404502783349336, 9.582370188422113]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"124\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.411025915673555, 9.604712595834995]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"125\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.407249365380586, 9.601327477271484]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"126\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.47831717543918, 9.686622118403308]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"127\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.484153662255586, 9.683237822077341]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"128\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.477630529931368, 9.681545661122474]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"129\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.480033789208711, 9.676130688779114]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"130\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.398322973779024, 9.663946682035794]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"131\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.392829809716524, 9.664285132627802]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"132\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.381843481591524, 9.664962032790449]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"133\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.384246740868868, 9.663269779830442]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"134\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.427333746484102, 9.621129940544316]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"135\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.441581640771211, 9.628407477514115]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"136\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.450679693749727, 9.623837879588994]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"137\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.463382635644258, 9.619606715297124]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"138\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.430423651269258, 9.625361085765237]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"139\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.429908667138399, 9.631284600046119]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"140\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.434028540185274, 9.634669418694504]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"141\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.439006720116915, 9.629761420582756]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"142\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.424587164452852, 9.626376552734179]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"143\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.43437186293918, 9.622822404990066]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"144\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.54200354628879, 9.771725920359758]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"145\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.540115271142305, 9.772233432596723]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"146\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.540801916650118, 9.770710893563262]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"147\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.538055334618868, 9.772571773657894]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"148\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.538055334618868, 9.77054172212945]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"149\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53822699599582, 9.768511658215099]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"150\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.538570318749727, 9.76698910215254]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"151\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.539600287011446, 9.765974060908194]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"152\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53822699599582, 9.765297365025766]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"153\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.535308752587618, 9.770034207311948]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"154\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53376380019504, 9.772064261937096]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"155\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.531703863671602, 9.77240260317031]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"156\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.533420477441133, 9.771049236172841]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"157\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.533420477441133, 9.769865035534101]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"158\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53548041396457, 9.768680830680962]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"159\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.536167059472383, 9.76698910215254]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"160\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.536853704980196, 9.765297365025766]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"161\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.536853704980196, 9.763943969134523]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"162\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.497199926904024, 9.76326726912586]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"163\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.495654974511446, 9.764451493238456]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"164\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.49702826552707, 9.763098093908816]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"165\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.49754324965793, 9.76242139218114]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"166\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.496341620019258, 9.76242139218114]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"167\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.55745307021457, 9.72384712346435]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"168\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.558139715722383, 9.722324363538974]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"169\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.560542974999727, 9.721139989914178]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"170\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.559856329491915, 9.718432834451587]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"171\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.560886297753633, 9.717079248504964]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"172\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.562087927392305, 9.719786414921563]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"173\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.564319525292696, 9.720632399933873]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"174\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.56346121840793, 9.71826363650775]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"175\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.566379461816133, 9.72080159667957]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"176\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.566036139062227, 9.717756042162808]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"177\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.567237768700899, 9.718771230082542]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"178\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.569641027978243, 9.722324363538974]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"179\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.573245916894258, 9.724693098204092]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"180\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.57170096450168, 9.72012480918325]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"181\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.570156012109102, 9.717756042162808]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"182\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.571357641747774, 9.716402453478146]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"183\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.575134192040743, 9.719109625371203]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"184\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.575305853417696, 9.72080159667957]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"185\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.576507483056368, 9.717586843876692]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"186\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.574619207909883, 9.71741764550502]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"187\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.573245916894258, 9.71741764550502]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"188\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.54372016005832, 9.70574275130077]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"189\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.548183355859102, 9.703712293368184]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"190\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.547840033105196, 9.70692717941152]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"191\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.545780096581758, 9.708280806409537]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"192\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.546295080712618, 9.703881498665897]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"193\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.54200354628879, 9.70692717941152]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"194\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.54200354628879, 9.710311236647977]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"195\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.54200354628879, 9.712172453550373]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"196\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.540801916650118, 9.715048859317944]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"197\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53822699599582, 9.715218058887388]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"198\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.537197027734102, 9.717586843876692]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"199\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.535308752587618, 9.715048859317944]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"200\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.535823736718477, 9.711834051246822]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"201\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.538570318749727, 9.713864459936698]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"202\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.53651038222629, 9.710142034598336]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"203\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.540630255273165, 9.707434790176865]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"204\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.531188879540743, 9.717586843876692]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"205\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.530330572655977, 9.72130918640309]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"206\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.529815588525118, 9.723001146584146]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"207\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.527583990624727, 9.724693098204092]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"208\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.526725683739961, 9.725200682020445]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"209\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.526554022363008, 9.722324363538974]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"210\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.528098974755586, 9.721647579124117]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"211\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.526897345116915, 9.720970793339673]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"212\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52174750380832, 9.726046653335084]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"213\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52277747207004, 9.727738589541413]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"214\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.52277747207004, 9.730276477790866]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"215\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.521404181054415, 9.732137583589529]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"216\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.517970953515352, 9.733321918244974]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"217\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.517970953515352, 9.731799201488183]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"218\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.519859228661836, 9.732137583589529]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"219\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.50852957778293, 9.740766211334252]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"220\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.509731207421602, 9.737213273972818]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"221\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.510246191552461, 9.736198142067588]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"222\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.511447821191133, 9.737720838768078]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"223\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.51453772597629, 9.737720838768078]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"224\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.51076117568332, 9.741950515384083]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"225\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.50028983168918, 9.754808403012264]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"226\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.497714911034883, 9.756500193416775]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"227\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.495483313134493, 9.758530330563973]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"228\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.501148138573946, 9.752947423648195]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"229\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.501834784081758, 9.749563798187735]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"230\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.507842932275118, 9.74770278954872]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"231\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.509216223290743, 9.749056251407033]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"232\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.510417852929415, 9.747533606430212]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"233\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.508872900536836, 9.747364423225903]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"234\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.661651526025118, 10.022341913400517]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"235\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.660964880517305, 10.028765438852059]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"236\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.661308203271211, 10.020989576032427]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"237\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.658561621239961, 10.020989576032427]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"238\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.655471716454805, 10.024370408875624]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"239\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.652038488915743, 10.024370408875624]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"240\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.655471716454805, 10.020989576032427]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"241\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.652725134423555, 10.018284884376252]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"242\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.658904943993868, 10.012537339724123]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"243\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.655471716454805, 10.009156383550605]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"244\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.658218298486055, 10.00780399122132]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"245\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.654441748193086, 10.005775392165521]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"246\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.656501684716524, 10.003408677251185]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"247\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.65409842543918, 10.00239436558026]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"248\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.657874975732149, 10.000365732737786]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"249\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.655471716454805, 9.999689518975616]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"250\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.645515356591524, 10.003070573712783]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"251\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.645172033837618, 10.000703839091145]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"252\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.643798742821993, 9.999689518975616]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"253\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.668517981103243, 9.988193669793844]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"254\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.669204626611055, 9.984136214247286]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"255\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.669204626611055, 9.981093089391116]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"256\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.669204626611055, 9.976697414383944]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"257\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.666458044579805, 9.974330487883972]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"258\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.66508475356418, 9.973316085548204]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"259\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.666458044579805, 9.969596583299666]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"260\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.669204626611055, 9.966553322616255]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"261\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.671951208642305, 9.962833743207232]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"262\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.676757727196993, 9.961143011271028]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"263\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.681907568505586, 9.960128567903281]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"264\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.68431082778293, 9.956408915238322]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"265\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.683624182275118, 9.952689220182753]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"266\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.682937536767305, 9.949307642450698]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"267\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.676414404443086, 9.958099671705611]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"268\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.671951208642305, 9.960128567903281]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"269\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.668174658349336, 9.96046671604301]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"270\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.667584617106092, 9.953089708729708]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"271\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.667241294352186, 9.951145308196883]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"272\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.667241294352186, 9.950215373414666]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"273\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.666468818155897, 9.945734741445749]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"274\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.666726310221327, 9.944551168024388]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"275\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.666726310221327, 9.942691258273008]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"276\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.665696341959608, 9.940746795853128]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"277\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.664580543009412, 9.938633236626876]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"278\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.662434775797498, 9.938633236626876]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"279\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.661748130289686, 9.93990137380219]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"280\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.662692267862928, 9.942860341415056]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"281\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.66440888163246, 9.944466626901695]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"282\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.664494712320936, 9.946326526548747]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"283\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6638938975016, 9.947848254748799]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"284\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.662434775797498, 9.947763714479182]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"285\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.661919791666639, 9.946411067190247]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"286\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.66088982340492, 9.944889332296516]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"287\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.66088982340492, 9.942860341415056]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"288\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.659945685831678, 9.947256472402119]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"289\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.659173209635389, 9.94962359535643]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"290\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6584007334391, 9.95199070115553]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"291\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.657542426554334, 9.950722610896857]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"292\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.653680045572889, 9.949454515714292]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"293\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.653250892130506, 9.950553531823656]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"294\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.657027442423475, 9.95833107856939]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"295\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.658057410685194, 9.960867195046598]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"296\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.658572394816053, 9.96272700126694]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"297\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.659001548258436, 9.965263083568694]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"298\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.659173209635389, 9.966953794146162]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"299\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.660117347208631, 9.96500947622598]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"300\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.660203177897108, 9.963403291808957]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"301\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.661061484781873, 9.961036268777496]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"302\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.661061484781873, 9.959937287960484]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"303\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.661748130289686, 9.958246541014008]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"304\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.660289008585584, 9.959260990233174]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"305\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.659602363077772, 9.96230431896613]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"306\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.663293082682264, 9.966192975471168]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"307\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.663550574747694, 9.964755868686034]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"308\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.66440888163246, 9.963656900400698]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"309\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.665181357828748, 9.962135245892433]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"310\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.666039664713514, 9.960613584285971]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"311\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.660718162027967, 9.973970149337196]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"312\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.660289008585584, 9.972110407252433]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"313\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.659516532389295, 9.970842395200114]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"314\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.658057410685194, 9.969658912833557]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"315\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.655825812784803, 9.968475426169892]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"316\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.655482490030897, 9.96982798200615]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"317\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.653851706949842, 9.972448542966447]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"318\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.653079230753553, 9.973801082313564]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"319\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.649560172526014, 9.973209347040036]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"320\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.649731833902967, 9.971434134771844]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"321\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.649216849772108, 9.970081585600642]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"322\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.647843558756483, 9.968559961074066]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"323\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.645783622233045, 9.967122864721723]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"324\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.643466193644178, 9.965516690714173]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"325\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.638058860270155, 9.969320774225237]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"326\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.635226447550428, 9.969405308910208]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"327\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.634110648600233, 9.970673326553726]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"328\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.631106574503553, 9.969912516559571]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"329\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.629990775553358, 9.967122864721723]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"330\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.63891716715492, 9.973547481613643]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"331\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.642522056070936, 9.972617610691863]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"332\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.645783622233045, 9.97498454963648]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"333\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.643981177775037, 9.977351471383914]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"334\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.643981177775037, 9.979380247762634]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"335\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.644753653971327, 9.980310099378729]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"336\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.648272712198866, 9.979887439882406]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"337\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.650075156656873, 9.982000731877168]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"338\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.65067597147621, 9.979549311890345]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"339\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.649302680460584, 9.977266938760529]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"340\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.641062934366834, 9.979887439882406]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"341\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.640462119547498, 9.982761513637067]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"342\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.638144690958631, 9.979718375930274]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"343\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.634797294108045, 9.975829880806362]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"344\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.646212775675428, 9.98783334659046]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"345\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.646212775675428, 9.99020017491354]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"346\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.648530204264295, 9.991045466569636]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"347\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.651105124918592, 9.992482457343009]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"348\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.64715691324867, 9.994173026593714]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"349\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.643466193644178, 9.99518736392491]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"350\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.642607886759412, 9.98741069686363]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"351\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.646727759806287, 9.986480865532018]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"352\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.64964600321449, 9.99036923342051]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"353\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.657370765177381, 9.981916200460754]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"354\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.654624183146131, 9.980732758326381]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"355\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.652821738688123, 9.979295715665872]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"356\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.653250892130506, 9.984283071822539]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"357\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.648186881510389, 9.975153616045933]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"358\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.646384437052381, 9.973124813341814]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"359\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.643380362955702, 9.97278667832957]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"360\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.641320426432264, 9.970081585600642]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"361\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.639775474039686, 9.973040279621646]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"362\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.640290458170545, 9.976421611320037]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"363\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.640118796793592, 9.977943199133255]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"364\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.637114722696912, 9.976337078455325]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"365\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.636256415812147, 9.974477349881646]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"366\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.63617058512367, 9.973378414370707]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"367\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6364280771891, 9.971856805236678]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"368\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.636256415812147, 9.969658912833557]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"369\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.636256415812147, 9.9673764704207]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"370\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.634453971354139, 9.968306356295757]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"371\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.631879050699842, 9.968052751320142]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"372\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.631020743815077, 9.966784723482908]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"373\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.629132468668592, 9.96500947622598]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"374\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.627244193522108, 9.962642464850603]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"375\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.626385886637342, 9.960698121228079]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"376\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.624411780802381, 9.958415616102878]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"377\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.624240119425428, 9.961036268777496]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"378\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.625270087687147, 9.962811537661368]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"379\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.627587516276014, 9.966869258825502]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"380\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.626643378702772, 9.966108439953251]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"381\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.624583442179334, 9.965770297662408]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"382\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.62321015116371, 9.964671332795572]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"383\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.621751029459608, 9.9651785478097]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"384\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.618575293985975, 9.965770297662408]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"385\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.619776923624647, 9.9650940120288]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"386\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.62818833109535, 9.97134960061309]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"387\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.628359992472303, 9.96957437821436]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"388\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.633252341715467, 9.975407215495617]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"389\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.63316651102699, 9.973378414370707]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"390\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.631621558634412, 9.976844275314518]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"391\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.637887198893202, 9.984283071822539]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"392\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.6364280771891, 9.986058214048352]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"393\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.637715537516248, 9.98369135559561]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"394\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.640719611612928, 9.98250791991466]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"395\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.642007071940077, 9.982846044833973]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"396\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.642779548136366, 9.98090182175181]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"397\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.659945685831678, 9.970250654554006]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"398\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.66415138956703, 9.970504257819616]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"399\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.665782172648084, 9.967630075922393]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"400\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.667756278483045, 9.96923623951836]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"401\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.66887207743324, 9.97253307684012]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"402\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.679171760050428, 9.97718240611521]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"403\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.683978278605116, 9.976506144162817]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"404\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.685179908243787, 9.973970149337196]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"405\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.688527305094373, 9.97523814921776]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"406\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.692303855387342, 9.97413921627307]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"407\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.691531379191053, 9.971603203023564]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"408\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.689385611979139, 9.970250654554006]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"409\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.686209876505506, 9.970081585600642]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"410\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.687668998209608, 9.969151704789562]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"411\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.688441474405897, 9.96813728633393]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"412\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.691016395060194, 9.96881356565509]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"413\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.608361442057264, 9.874374531391176]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"414\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.607245643107069, 9.871584065858906]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"415\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.607331473795545, 9.869892863116872]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"416\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.605014045206678, 9.869723742364956]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"417\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.60321160074867, 9.87090758580443]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"418\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.60398407694496, 9.869554621526174]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"419\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.598147590128553, 9.86811709089016]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"420\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.596259314982069, 9.86777884747573]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"421\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.576775748697889, 9.853826004088361]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"422\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.576861579386366, 9.851627320370765]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"423\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.578578193155897, 9.84883666224464]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"424\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.576432425943983, 9.849259490750422]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"425\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.575659949747694, 9.849174925092612]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"426\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.585530478922498, 9.841225656527765]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"427\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.586302955118787, 9.839872570479478]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"428\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.584157187906873, 9.83995713851988]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"429\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.630505759684217, 9.831669367685807]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"430\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.631879050699842, 9.833699045065439]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"431\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.574458857821856, 9.69531181961584]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"432\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.57737710123006, 9.69565023860672]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"433\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.578578730868731, 9.697849953722374]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"434\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.581325312899981, 9.701403309189935]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"435\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.58287026529256, 9.704449012462995]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"436\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.58458687906209, 9.704956626983607]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"437\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.584758540439044, 9.702756958506706]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"438\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.58458687906209, 9.701234102640901]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"439\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.582698603915606, 9.701234102640901]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"440\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.579437037753497, 9.698188370151598]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"441\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.578750392245684, 9.695988657256075]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"442\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.578063746737872, 9.694634980609585]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"443\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.575660487460528, 9.694634980609585]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"444\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.573085566806231, 9.694973400283457]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"445\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.56810738687459, 9.692604455395546]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"446\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.56639077310506, 9.693112087851434]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"447\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.56639077310506, 9.692096822171477]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"448\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.579780360507403, 9.686005163578422]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"449\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.582526942538653, 9.69192761092609]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"450\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.583556910800372, 9.693619719539091]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"451\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.59282662515584, 9.676529030508604]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"452\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.597461482333575, 9.67686746843577]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"453\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.5988347733492, 9.68075948009447]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"454\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.601409694003497, 9.680251828957084]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"455\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.603126307773028, 9.67483683575991]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"456\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.601924678134356, 9.671452420702959]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"457\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.602439662265216, 9.669083309890828]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"458\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.605529567050372, 9.668237194841453]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"459\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.606731196689044, 9.665868061379152]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"460\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.60209633951131, 9.664683488390903]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"461\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.592483302401934, 9.665021938241727]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"462\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.583385249423419, 9.667391077663392]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"463\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.582183619784747, 9.672467748797905]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"464\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.576690455722247, 9.673990735190353]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"465\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.571025630282794, 9.68363615537873]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"466\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.570682307528887, 9.687528088592995]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"467\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.570338984774981, 9.69192761092609]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"468\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.566905757235919, 9.691081553418952]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"469\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.56261422281209, 9.691081553418952]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"470\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.560554286288653, 9.69565023860672]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"471\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.9981272866448, 10.157269797971763]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"472\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-14.0475657632073, 10.1680837588802]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"473\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.86903793117605, 10.008879012049832]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"474\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.863888089867457, 10.008879012049832]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"475\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.865261380883082, 10.010231399900807]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"476\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.868351285668238, 10.008879012049832]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"477\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.877621000023707, 10.01225997111249]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"478\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.873157804222926, 10.0048218146976]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"479\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.874874417992457, 9.997721597385633]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"480\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.876591031761988, 9.994002374025342]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"481\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.8662913491448, 9.992988032997298]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"482\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.862858121605738, 9.998059706490045]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"483\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.86457473537527, 9.984873190890044]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"484\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.869724576683863, 9.975743751659701]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"485\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.877621000023707, 9.97540561936557]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"486\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.875904386254176, 9.982168198547233]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"487\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.88105422756277, 9.982844448740403]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"488\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.886204068871363, 9.981830072923847]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"489\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.890667264672144, 9.988592518649739]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"490\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.89478713771902, 9.987578160749882]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"491\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.893413846703394, 9.994340486998162]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"492\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.893413846703394, 10.0011026726001]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"493\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.897877042504176, 9.998059706490045]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"494\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.90028030178152, 9.995354823806883]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"495\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.8992503335198, 10.005498017776539]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"496\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.878994291039332, 9.992988032997298]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"497\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.896160428734644, 10.014964713003298]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"498\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.90199691555105, 10.01834560865809]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"499\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.5434608508915, 9.634974841301608],\n", + " [-13.545349126037985, 9.632266991548065],\n", + " [-13.54174423712197, 9.632436232794046]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"500\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.483379368957907, 9.632436232794046],\n", + " [-13.484924321350485, 9.629897605196554],\n", + " [-13.48131943243447, 9.629389877386695]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"501\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.435829167541891, 9.591646642167026],\n", + " [-13.433940892395407, 9.586568755869056],\n", + " [-13.431537633118063, 9.589446234106036]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"502\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.438919072327048, 9.66560587720521],\n", + " [-13.439777379211813, 9.662559821578215],\n", + " [-13.435657506164938, 9.664590528393632]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"503\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.52801132696572, 9.802649707720889],\n", + " [-13.531272893127829, 9.798420802628165],\n", + " [-13.525608067688376, 9.799266587959883]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"504\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.700941293708981, 9.913100953593409]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"505\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.703344552986325, 9.910057166995815]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"506\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.707636087410153, 9.905660536482868]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"507\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.709009378425778, 9.902109368825391]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"508\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.710725992195309, 9.897543525381757]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"509\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.712099283210934, 9.892977618451745]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"510\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.713300912849606, 9.889426313632375]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"511\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.715532510749997, 9.885198519765332]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"512\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.717420785896481, 9.88249270315871]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"513\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.720854013435543, 9.877926587157914]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"514\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.724802225105465, 9.873360407791562]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"515\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.678281991951168, 9.891962963848515]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"516\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.626096933357418, 9.910902666107052]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"517\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.625581949226559, 9.908873464578067]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"518\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.625581949226559, 9.906167843010932]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"519\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.625581949226559, 9.903462199130923]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"520\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.626611917488278, 9.90177116037774]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"521\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.621633737556637, 9.913946444855837]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"522\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.621633737556637, 9.91242455901354]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"523\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.747289865486325, 9.918850251170033]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"524\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.748319833748043, 9.916821098835793]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"525\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.749349802009762, 9.91360824861252]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"526\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.751581399910153, 9.911071765667707]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"527\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.752611368171872, 9.909888066911998]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"528\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.759992807380856, 9.912086361200327]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"529\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.736818521492184, 9.893146727247624]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"530\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.731497018806637, 9.890948306111866]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"531\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.72669050025195, 9.889595424255967]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"532\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.719137399666012, 9.90109474243695]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"533\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.719824045173825, 9.906675148754557]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"534\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.723600595466793, 9.91360824861252]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"535\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.7294370822832, 9.920033917561932]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"536\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.730982034675778, 9.924599447866193]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"537\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.738878458015622, 9.914453738566584]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"538\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.744714944832028, 9.910902666107052]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"539\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.746774881355465, 9.905660536482868]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"540\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.747976510994137, 9.89889637450345]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"541\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.74265500830859, 9.895006918256664]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"542\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.741110055916012, 9.88722786760753]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"543\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.744543283455075, 9.889595424255967]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"544\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.774927347175778, 9.920710296437226]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"545\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.774927347175778, 9.914115542846634]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"546\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.775957315437497, 9.91191726216291]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"547\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.780420511238278, 9.91293185507927]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"548\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.783682077400387, 9.907182453713716]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"549\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.780420511238278, 9.906844250494784]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"550\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.775442331306637, 9.90971896674098]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"551\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.769090860359372, 9.9147919339376]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"552\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.764456003181637, 9.920203012411678]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"553\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.755014627449215, 9.921555768067503]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"554\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.747118204109372, 9.927135826088241]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"555\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.760507791511715, 9.930348543625744]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"556\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.794668405525387, 9.923415797972327]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"557\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.796213357917965, 9.917497484343334]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"558\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.794496744148434, 9.913439150360041]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"559\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.797071664802731, 9.905998740922067]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"560\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.801191537849606, 9.899572796973985]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"561\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.808057992927731, 9.910057166995815]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"562\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.799474924080075, 9.920033917561932]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"563\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.802736490242184, 9.92493763276433]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"564\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.804968088142575, 9.941339180848713]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"565\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.813551156990231, 9.93846474216451]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"566\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.817842691414059, 9.930517633148913]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"567\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.827627389900387, 9.920203012411678]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"568\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.823679178230465, 9.912762756477909]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"569\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.820932596199215, 9.90904256518501]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"570\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.822992532722653, 9.904138612192435]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"571\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.821619241707028, 9.900249218050838]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"572\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.825395791999997, 9.892470291541834]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"573\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.828657358162106, 9.887904314104395]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"574\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.835867135994137, 9.886213195252276]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"575\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.842218606941403, 9.894330486381278]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"576\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.846510141365231, 9.901263847052817]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"577\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.751238077156247, 9.897205312230422]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"578\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.751924722664059, 9.893484944578221]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"579\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.751753061287106, 9.890102755604609]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"580\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.749864786140622, 9.88773520261068]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"581\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.744199960701168, 9.885705857900248]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"582\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.743684976570309, 9.88249270315871]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"583\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.744886606208981, 9.878264820146166]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"584\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.735960214607418, 9.875220710736242]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"585\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.732698648445309, 9.874036882806081]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"586\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.755529611580075, 9.876742768961105]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"587\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.761537759773434, 9.874036882806081]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"588\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.765657632820309, 9.870147132490299]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"589\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.772352426521481, 9.873191288820733]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"590\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.78162214087695, 9.888242536830802]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"591\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.783510416023434, 9.892301182397773]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"592\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.788316934578122, 9.891793854443343]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"593\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.810804574958981, 9.88164713090347]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"594\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.826940744392575, 9.862367494036468]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"595\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.801019876472653, 9.868625043771626]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"596\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.879640787117184, 9.97025124536242]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"597\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.870714395515622, 9.973294471519242]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"598\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.934229104988278, 10.045140145886094]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"599\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.930795877449215, 10.051225165678396]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"600\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.933714120857418, 10.054436657725878]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"601\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.940065591804684, 10.05494373250028]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"602\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.941267221443356, 10.052746402731378]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"603\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-13.940752237312497, 10.051056138897241]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"604\"\n", + " })]),\n", + " MangroveTraining =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " },\n", + " {\n", + " \"type\": \"polygon\"\n", + " }\n", + " ] #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.772867907259272, 10.831865509758982],\n", + " [-14.772867907259272, 10.829800117522154],\n", + " [-14.769735087129877, 10.829800117522154],\n", + " [-14.769735087129877, 10.831865509758982]]], None, False),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.765529383394526, 10.838525248913346],\n", + " [-14.766130198213862, 10.835743350576333],\n", + " [-14.763641108248041, 10.837724402042513]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.913246520634662, 10.88669795665154],\n", + " [-14.913589843388568, 10.88475937330651],\n", + " [-14.911658652897845, 10.886192240473294]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.895136245366107, 10.88551795090026],\n", + " [-14.89530790674306, 10.884000793781476],\n", + " [-14.893848785038958, 10.884464370387377]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.050952041676988, 10.935378624515092],\n", + " [-15.051295364430894, 10.933018994799562],\n", + " [-15.048548782399644, 10.934030266976446]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.056273544362535, 10.927794033632864],\n", + " [-15.05738934331273, 10.924675867811173],\n", + " [-15.052840316823472, 10.926361366917918]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.033013427785386, 10.937738235455122],\n", + " [-15.033270919850816, 10.934198812004023],\n", + " [-15.030266845754136, 10.93613707293644]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.024859512380113, 10.944058529371569],\n", + " [-15.024516189626206, 10.940940534549906],\n", + " [-15.022112930348863, 10.943805720202793]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.033528411916246, 10.968495730093942],\n", + " [-15.034987533620347, 10.965546519857721],\n", + " [-15.031554306081285, 10.96563078341557]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.984546455644416, 10.987837291653708],\n", + " [-14.98471811702137, 10.985056790571315],\n", + " [-14.982143196367073, 10.985899369423139]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.970813545488166, 10.976293827966234],\n", + " [-14.97124269893055, 10.973007649961247],\n", + " [-14.968753608964729, 10.974440091021131],\n", + " [-14.970899376176643, 10.97688365091855]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.913425310937384, 11.025767991764447],\n", + " [-14.913854464379767, 11.023156342914417],\n", + " [-14.911365374413947, 11.023830319031457]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.906121064559587, 10.955341109815576],\n", + " [-14.907837678329118, 10.949610933953918],\n", + " [-14.9013145460049, 10.949610933953918]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.96670177455577, 10.846156206496804],\n", + " [-14.967130927998152, 10.844133061873753],\n", + " [-14.965070991474715, 10.844638849312554]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.743433698959846, 10.875987708548102],\n", + " [-14.743691191025276, 10.874723371063938],\n", + " [-14.74257539207508, 10.875229106700816]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.758668646164436, 10.881424298639294],\n", + " [-14.758754476852912, 10.87990712068018],\n", + " [-14.75755284721424, 10.880497135248563]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.581574563265484, 10.84536404443417],\n", + " [-14.581832055330914, 10.841570626993633],\n", + " [-14.57942879605357, 10.842582209681508]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.603118066073101, 10.845279746791512],\n", + " [-14.603976372957867, 10.842160717310577],\n", + " [-14.600457314730328, 10.842413612804403]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.544370475152173, 10.714539815401963],\n", + " [-14.544713797906079, 10.712009776250197],\n", + " [-14.542653861382641, 10.71335913309481]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.555700126031079, 10.620070724737218],\n", + " [-14.557245078423657, 10.617033732301914],\n", + " [-14.554841819146313, 10.616696286835134]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.49149877105061, 10.606741478020858],\n", + " [-14.492700400689282, 10.602860702077397],\n", + " [-14.489782157281079, 10.60353562316791]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.525144400933423, 10.557468847876851],\n", + " [-14.525659385064282, 10.554262478003922],\n", + " [-14.522397818902173, 10.554768749154126]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.547632041314282, 10.528104002109169],\n", + " [-14.549005332329907, 10.525572418817276],\n", + " [-14.546087088921704, 10.525572418817276],\n", + " [-14.547460379937329, 10.529285400531567]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.502835338713801, 10.41292156162942],\n", + " [-14.503178661467707, 10.408700677058924],\n", + " [-14.499402111174739, 10.409544858543237]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.494767253997004, 10.393842709127481],\n", + " [-14.495968883635676, 10.390128106675817],\n", + " [-14.492707317473567, 10.390634645974284]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.47914606869427, 10.369359288904414],\n", + " [-14.47914606869427, 10.365644395693769],\n", + " [-14.476227825286067, 10.366319834100443]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.576993053557551, 10.460191559812422],\n", + " [-14.577679699065364, 10.457490610691979],\n", + " [-14.575104778411067, 10.458672278824194]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.627633159758723, 10.477747155867581],\n", + " [-14.628663128020442, 10.475552760727757],\n", + " [-14.625058239104426, 10.476059160985555]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.458669826688668, 10.353920649385334],\n", + " [-14.459699794950387, 10.351049912543393],\n", + " [-14.457296535673043, 10.351387647653238]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.139551326932809, 10.164877141176504],\n", + " [-14.14126794070234, 10.16115984608325],\n", + " [-14.13852135867109, 10.16115984608325]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.092859432401559, 10.157611478625247],\n", + " [-14.09457604617109, 10.154907934134476],\n", + " [-14.092001125516793, 10.154738961845052]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.0758649560832, 10.146121256763173],\n", + " [-14.077066585721871, 10.143755571644597],\n", + " [-14.07483498782148, 10.14392454973268]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.086507961454293, 10.137841282399306],\n", + " [-14.086679622831246, 10.135644518587286],\n", + " [-14.083933040799996, 10.135644518587286]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.114660427274606, 10.118069866300507],\n", + " [-14.114660427274606, 10.114183034389438],\n", + " [-14.11157052248945, 10.115028001850106]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.108137294950387, 10.096607207508624],\n", + " [-14.108223125638863, 10.09398765106267],\n", + " [-14.10607735842695, 10.095339682858716]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.100927517118356, 10.095170679194851],\n", + " [-14.101270839872262, 10.09288912104627],\n", + " [-14.09809510439863, 10.093311633034737]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.021705791654488, 10.082326141150112],\n", + " [-14.021877453031442, 10.080636032223616],\n", + " [-14.020075008573434, 10.081058560286214]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.9989606592082, 10.0360984726324],\n", + " [-13.99921815127363, 10.03390101484509],\n", + " [-13.997158214750192, 10.034915227984722]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.982309505643746, 10.021899251579727],\n", + " [-13.982652828397653, 10.019025524007592],\n", + " [-13.980592891874215, 10.020377869566946]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.02342240542402, 10.024603913085619],\n", + " [-14.024624035062692, 10.021392125035309],\n", + " [-14.021448299589059, 10.021899251579727]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.835067067440528, 9.863594689892103],\n", + " [-13.834895406063575, 9.86190344613282],\n", + " [-13.833951268490333, 9.8628336312745]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.78159454851963, 9.855138384324128],\n", + " [-13.78434113055088, 9.852686015145009],\n", + " [-13.780650410946388, 9.852686015145009],\n", + " [-13.78210953265049, 9.856068588553256]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.730782780941505, 9.849895365972753],\n", + " [-13.732327733334083, 9.84795035410826],\n", + " [-13.72992447405674, 9.8484577496128]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.690013203915138, 9.850402758486885],\n", + " [-13.690528188045997, 9.84795035410826],\n", + " [-13.68821075945713, 9.848288617864625]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.681773457821388, 9.867822761312134],\n", + " [-13.682030949886817, 9.865285924971385],\n", + " [-13.67971352129795, 9.865708732384784]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.656796727474708, 9.882536026645745],\n", + " [-13.65748337298252, 9.879745630321658],\n", + " [-13.65473679095127, 9.880252976868517]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.658856663998145, 9.860635007617953],\n", + " [-13.659371648129005, 9.857844425704632],\n", + " [-13.656367574032325, 9.858859185497039]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.65525177508213, 9.812684457771793],\n", + " [-13.656281743343849, 9.809893470949143],\n", + " [-13.653449330624122, 9.810400924847407]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.572682652767677, 9.778006894151861],\n", + " [-13.57311180621006, 9.77445435389848],\n", + " [-13.569163594540138, 9.776738134132595]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.532513890560645, 9.73579688260377],\n", + " [-13.532599721249122, 9.732413083234764],\n", + " [-13.529853139217872, 9.73410498720453]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"49\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.543843541439552, 9.590008806122597],\n", + " [-13.543929372128028, 9.587131332658355],\n", + " [-13.540324483212013, 9.588908598563034]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"50\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.50891045122959, 9.585861851311003],\n", + " [-13.508996281918067, 9.583153608560922],\n", + " [-13.50616386919834, 9.58518479265003]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"51\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.542556081112403, 9.577059983359076],\n", + " [-13.543242726620216, 9.574605575646206],\n", + " [-13.540238652523536, 9.574605575646206]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"52\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.530389026199542, 9.527893347398814],\n", + " [-13.530303195511065, 9.525523232532972],\n", + " [-13.52867241243001, 9.526792938971614]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"53\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.451424792801104, 9.537796863571655],\n", + " [-13.452454761062823, 9.535257527857542],\n", + " [-13.450738147293292, 9.535426817493349]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"54\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.454943851028643, 9.544737618029338],\n", + " [-13.455630496536456, 9.542282977117766],\n", + " [-13.453570560013018, 9.542875478266838]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"55\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.404647067581378, 9.536019330556984],\n", + " [-13.404904559646807, 9.533395336318703],\n", + " [-13.402758792434893, 9.533733917354596]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"56\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.35263367036458, 9.463471170308926],\n", + " [-13.352376178299151, 9.46186257739953],\n", + " [-13.350058749710284, 9.462709206184886]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"57\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.281136706863604, 9.376427045404881],\n", + " [-13.279935077224932, 9.373293725915216],\n", + " [-13.277875140701495, 9.37549552094412]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"58\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.258134082351885, 9.403016779052459],\n", + " [-13.25701828340169, 9.400899836835583],\n", + " [-13.253499225174151, 9.402339358952185]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"59\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.2767593417513, 9.352206597362429],\n", + " [-13.2767593417513, 9.348226152497125],\n", + " [-13.27324028352376, 9.351020937696008]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"60\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.319159701858721, 9.36406297170052],\n", + " [-13.32345123628255, 9.362962039686883],\n", + " [-13.31993217805501, 9.359743910725987]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"61\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.276330188308917, 9.28597285948887],\n", + " [-13.276587680374346, 9.282076366483075],\n", + " [-13.273411944900714, 9.284109324760125]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"62\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.22035537324127, 9.227099179359078],\n", + " [-13.221042018749083, 9.223879801424738],\n", + " [-13.217952113963927, 9.224472846935972]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"63\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.282496791698302, 9.227014459263557],\n", + " [-13.281981807567442, 9.223795080556025],\n", + " [-13.279578548290099, 9.225828375789598]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"64\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.201730113841856, 9.201512786400121],\n", + " [-13.200614314891661, 9.198293175278035],\n", + " [-13.198554378368224, 9.201343333913732]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"65\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.184306484081114, 9.042107056466508],\n", + " [-13.184993129588927, 9.039987948233751],\n", + " [-13.183019023753966, 9.040072712802496]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"66\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.260438304759825, 9.024984305436146],\n", + " [-13.259408336498106, 9.023458476277755],\n", + " [-13.257691722728575, 9.024560464650595]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"67\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.642733884742919, 9.878367396851779],\n", + " [-13.643291784218016, 9.876929904698706],\n", + " [-13.641231847694579, 9.877352697160317]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"68\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.637626958778563, 9.870714792841605],\n", + " [-13.637498212745848, 9.869150426476896],\n", + " [-13.635996175697509, 9.869869190324037]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"69\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.71767956322163, 9.790239249343115],\n", + " [-13.71793705528706, 9.788293886948836],\n", + " [-13.716048780140575, 9.788801373889488]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"70\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.722228589710888, 9.789647183733882],\n", + " [-13.721713605580028, 9.788124724462955],\n", + " [-13.71991116112202, 9.78905511706901]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"71\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.718709531483348, 9.787532655083849],\n", + " [-13.71793705528706, 9.786686839854307],\n", + " [-13.716735425648388, 9.787194329250488]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"72\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.72566181724995, 9.785502694914687],\n", + " [-13.724717679676708, 9.784233963509804],\n", + " [-13.723258557972606, 9.785248949021314]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"73\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.702487531361278, 9.789308860054645],\n", + " [-13.702830854115184, 9.787278910741135],\n", + " [-13.701028409657177, 9.788463049348552],\n", + " [-13.70317417686909, 9.789985507068423]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"74\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.697509351429638, 9.80064251559769],\n", + " [-13.697337690052684, 9.798866371277441],\n", + " [-13.695535245594677, 9.799965890311366]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"75\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.487795754889769, 9.654477745850699],\n", + " [-13.487967416266722, 9.65312390200053],\n", + " [-13.485478326300901, 9.65312390200053]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"76\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.439584340971981, 9.671575492304996],\n", + " [-13.43936976425079, 9.669967883805594],\n", + " [-13.43786772720245, 9.670898605452638]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"77\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.448296155852352, 9.662183565542307],\n", + " [-13.448553647917782, 9.66057591215856],\n", + " [-13.446794118804013, 9.661083593004093]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"78\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.451471891325985, 9.66599113502486],\n", + " [-13.451471891325985, 9.664425806120096],\n", + " [-13.45009860031036, 9.66506039979714]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"79\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.471642103117977, 9.675932918788158],\n", + " [-13.471599187773739, 9.674494551243551],\n", + " [-13.470526304167782, 9.67538295545391]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"80\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.493915166777645, 9.681347894319272],\n", + " [-13.494430150908505, 9.679951854290938],\n", + " [-13.492498960417782, 9.679571115094394]]]),\n", + " {\n", + " \"landcover\": 1,\n", + " \"system:index\": \"81\"\n", + " })]),\n", + " NonMangroveTraining =\n", + "\n", + " # shown: False #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.016362274220933, 10.95631951504912],\n", + " [-15.01670559697484, 10.954465652887245],\n", + " [-15.014988983205308, 10.955729651075279]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.028464401296128, 10.951853372862459],\n", + " [-15.028893554738511, 10.9499573487322],\n", + " [-15.026318634084214, 10.950589358124523]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.030567253163804, 10.957794169840307],\n", + " [-15.03091057591771, 10.955687517889313],\n", + " [-15.028464401296128, 10.954760586280573],\n", + " [-15.028121078542222, 10.956193115725121]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.064427459767808, 10.939929285941478],\n", + " [-15.062968338063706, 10.936811247682382],\n", + " [-15.05962094121312, 10.939339389326674],\n", + " [-15.061766708425035, 10.942457400993268]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.01115396907215, 10.978358203146746],\n", + " [-15.011497291826057, 10.976041046340452],\n", + " [-15.008707794450569, 10.976672999999328]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.018235000871467, 10.979242930950159],\n", + " [-15.01866415431385, 10.976462348929923],\n", + " [-15.016303810380744, 10.978189683264663]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-15.023599418901252, 10.982697556991285],\n", + " [-15.023685249589729, 10.980717471399375],\n", + " [-15.021453651689338, 10.981812839538087]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.94775758632801, 11.03259186797311],\n", + " [-14.947929247704963, 11.029306317720359],\n", + " [-14.94501100429676, 11.031243954363834]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.92827402004383, 11.037225273846428],\n", + " [-14.929046496240119, 11.034866458168958],\n", + " [-14.926729067651252, 11.035119189326004]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.931449755517463, 11.018101472815468],\n", + " [-14.932393893090705, 11.015826752939146],\n", + " [-14.930076464501838, 11.016163749585782]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.717083677597541, 10.887661504655835],\n", + " [-14.717169508286018, 10.88547006877135],\n", + " [-14.715281233139534, 10.886818646608011]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.707556471176643, 10.873501173067645],\n", + " [-14.707985624619026, 10.871309633085449],\n", + " [-14.705839857407112, 10.872236825042815]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.564665917635601, 10.855985357241925],\n", + " [-14.56492340970103, 10.851686299903761],\n", + " [-14.560889367342632, 10.85396227913996]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.501528172847433, 10.829671752536575],\n", + " [-14.50358810937087, 10.826299651525124],\n", + " [-14.498953252193136, 10.82646825747719]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.49586334740798, 10.843328373277828],\n", + " [-14.498438268062277, 10.838439037462708],\n", + " [-14.492258458491964, 10.839282032096412]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.456994834283032, 10.749958141773662],\n", + " [-14.460428061822094, 10.746922447900886],\n", + " [-14.456136527398266, 10.746585146697118]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.442231955865063, 10.732418155960152],\n", + " [-14.442918601372876, 10.728538983147049],\n", + " [-14.438798728326, 10.729382285818327]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.604451957085766, 10.529960483311568],\n", + " [-14.605310263970532, 10.52692259915962],\n", + " [-14.60136205230061, 10.52894785858715]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.48600560698811, 10.471222760291694],\n", + " [-14.486177268365063, 10.466833862095141],\n", + " [-14.48325902495686, 10.468353103116165]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.500432079436457, 10.441284422659384],\n", + " [-14.500432079436457, 10.438245668318906],\n", + " [-14.496998851897395, 10.439089769725399]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.549012249114192, 10.45462082650194],\n", + " [-14.549870555998957, 10.452257454900492],\n", + " [-14.546952312590754, 10.452257454900492]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.534936016204036, 10.443647877725367],\n", + " [-14.534936016204036, 10.439427409646498],\n", + " [-14.530129497649348, 10.44111560375287]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.356874630155465, 10.29244737636023],\n", + " [-14.357389614286324, 10.289069376182145],\n", + " [-14.354471370878121, 10.2909272807549]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.315847561063668, 10.324198808708294],\n", + " [-14.316362545194528, 10.32115891654387],\n", + " [-14.314130947294137, 10.322003333980634]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.15851990908613, 10.089339998450072],\n", + " [-14.159635708036324, 10.087058398980245],\n", + " [-14.157318279447457, 10.088072445184688]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.039730236234567, 10.046493936082012],\n", + " [-14.040245220365426, 10.044550094321767],\n", + " [-14.038786098661324, 10.045648788926059]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-14.001278087797067, 10.069734616761512],\n", + " [-14.00170724123945, 10.06762189672479],\n", + " [-13.999990627469918, 10.068213459729401]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.967031643094918, 10.078100852215877],\n", + " [-13.968061611356637, 10.07590368008197],\n", + " [-13.9660016748332, 10.076410721134172]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.96900574892988, 10.101846256417112],\n", + " [-13.970035717191598, 10.100240750496802],\n", + " [-13.967804119291207, 10.100494251964397]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.947118923368356, 10.008291081164497],\n", + " [-13.947633907499215, 10.005924384584203],\n", + " [-13.945144817533395, 10.006685110366224]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.936304256620309, 10.017419606331591],\n", + " [-13.938364193143746, 10.01454583906799],\n", + " [-13.935617611112496, 10.015052976317214]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.865245156545589, 10.011587522650414],\n", + " [-13.865931802053401, 10.008967277018833],\n", + " [-13.862241082448909, 10.008967277018833]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.849194817800472, 10.015222021890791],\n", + " [-13.849366479177425, 10.012939899216223],\n", + " [-13.847392373342464, 10.01378513170792]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.871596627492854, 9.977522681370168],\n", + " [-13.872884087820003, 9.97473309468144],\n", + " [-13.868678384084651, 9.975493893420309],\n", + " [-13.87219744231219, 9.977860811466533]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.885329537649104, 9.931449178193983],\n", + " [-13.885844521779964, 9.928067380758433],\n", + " [-13.882582955617854, 9.92891283339319]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.719195637997169, 9.885749180963948],\n", + " [-13.719367299374122, 9.883550710348658],\n", + " [-13.716792378719825, 9.885072730032563]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.712758336361427, 9.899785223586706],\n", + " [-13.71292999773838, 9.897164080446853],\n", + " [-13.710097585018653, 9.898516931131878]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.585042271908302, 9.704664636543379],\n", + " [-13.585643086727638, 9.70153433202078],\n", + " [-13.582982335384864, 9.70280337791928]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.603495869930763, 9.704072419011773],\n", + " [-13.604697499569435, 9.699334641080256],\n", + " [-13.60032013445713, 9.699673056010699]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.568047795589942, 9.681736594181228],\n", + " [-13.568047795589942, 9.678775293678653],\n", + " [-13.565472874935645, 9.680298251483626]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.579463277157325, 9.671498844445082],\n", + " [-13.580149922665138, 9.667945172458403],\n", + " [-13.577145848568458, 9.66929895669111]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.550280843075294, 9.648314689092652],\n", + " [-13.551053319271583, 9.645353094436604],\n", + " [-13.548306737240333, 9.645860798225591]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.53637627154209, 9.6554224100717],\n", + " [-13.537577901180763, 9.65296857096865],\n", + " [-13.535174641903419, 9.653053186407726]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.354779437576495, 9.451194876126811],\n", + " [-13.356066897903643, 9.448231567078778],\n", + " [-13.35289116243001, 9.448824230929024]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.30122108796712, 9.458137385977457],\n", + " [-13.301993564163409, 9.455766788608837],\n", + " [-13.299161151443682, 9.456698096666363]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.380013659988604, 9.43282194906301],\n", + " [-13.379327014480792, 9.430197165246152],\n", + " [-13.376837924514971, 9.431636565296552]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.292037204300128, 9.406827242400094],\n", + " [-13.290663913284503, 9.402508714101591],\n", + " [-13.2877456698763, 9.405387738957764]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.245417934276427, 9.18405875410957],\n", + " [-13.243443828441466, 9.181432101976078],\n", + " [-13.241383891918028, 9.18388929326906]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.066632610179747, 9.154740824313496],\n", + " [-13.06731925568756, 9.152113955250934],\n", + " [-13.064915996410216, 9.152791858802239]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.074958186961974, 9.158977668998714],\n", + " [-13.075129848338927, 9.15618135717263],\n", + " [-13.073155742503966, 9.157028726715863]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"49\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.729721799006377, 9.85583516805335],\n", + " [-13.729721799006377, 9.85245259225134],\n", + " [-13.727490201105987, 9.853974755654882]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"50\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.717018857111846, 9.87917399489423],\n", + " [-13.717877163996612, 9.877144597357086],\n", + " [-13.714958920588408, 9.877482831149154]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"51\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.728520169367705, 9.83097242702757],\n", + " [-13.729206814875518, 9.828266165435217],\n", + " [-13.726288571467315, 9.828266165435217]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"52\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.514183618018233, 9.825400785383925],\n", + " [-13.51401195664128, 9.82408992060949],\n", + " [-13.512552834937178, 9.824935640413306]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"53\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.518603898474776, 9.822229329432322],\n", + " [-13.518560983130538, 9.82117217069405],\n", + " [-13.517616845557296, 9.821595034594583]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"54\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.525341607520186, 9.831320755143555],\n", + " [-13.526028253027999, 9.830009913831383],\n", + " [-13.524440385291182, 9.830179054937869]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"55\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.543580628821456, 9.823836204246815],\n", + " [-13.54323730606755, 9.822398474517083],\n", + " [-13.542035676428878, 9.822652191982112]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"56\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.708849929637964, 9.918043253117057],\n", + " [-13.708849929637964, 9.916690482958893],\n", + " [-13.707304977245386, 9.917113224233205]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"57\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.704386733837183, 9.911025697281337],\n", + " [-13.704644225902612, 9.909588348034493],\n", + " [-13.703356765575464, 9.910095648488015]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"58\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.640357040233667, 9.89622915380466],\n", + " [-13.640700362987573, 9.894199861550709],\n", + " [-13.638983749218042, 9.894622631804186]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"59\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.64160671314408, 9.893653002898159],\n", + " [-13.641563797799842, 9.893124538436428],\n", + " [-13.640962982980506, 9.893261939278268]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"60\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.638013196876708, 9.880523623305505],\n", + " [-13.63797028153247, 9.879339814453012],\n", + " [-13.636983228614989, 9.87972032490587]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"61\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.61247856705493, 9.877437255587456],\n", + " [-13.61273605912036, 9.876168876898934],\n", + " [-13.611620260170165, 9.876507111693881]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"62\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.605569196632567, 9.87041883220746],\n", + " [-13.605526281288329, 9.86906586592114],\n", + " [-13.604152990272704, 9.869742349759118]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"63\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.598144842079344, 9.869150426476896],\n", + " [-13.598316503456298, 9.867628333151876],\n", + " [-13.597114873817626, 9.867628333151876]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"64\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.705663266834911, 9.8058863147593],\n", + " [-13.705234113392528, 9.803941044100654],\n", + " [-13.70420414513081, 9.8052097001726]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"65\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Polygon(\n", + " [[[-13.438532915038143, 9.665229624575522],\n", + " [-13.438897695464169, 9.664129661994533],\n", + " [-13.43763169280914, 9.664489265541672]]]),\n", + " {\n", + " \"landcover\": 2,\n", + " \"system:index\": \"66\"\n", + " })]),\n", + " nationalborder = ee.FeatureCollection(\"projects/gee-book/assets/A3-3/Border5km\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.3 Mangroves\n", + "# Section: Supplemental (Assignment 1)\n", + "# Author: Celio de Sousa, David Lagomasino, and Lola Fatoyinbo\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + " #****************************************\n", + "#STEP 1 - TEMPORAL AND SPATIAL PARAMETERS\n", + "#****************************************\n", + "\n", + "#Temporal\n", + "year = 2020; # Year\n", + "startDay = (year)+'-01-01'; # beginning of date filter | month-day\n", + "endDay = (year)+'-12-30'; # end of date filter | month-day\n", + "\n", + "#Spatial\n", + "aoi = ee.FeatureCollection('projects/gee-book/assets/A3-3/CoastalPrefectures5k')\n", + "\n", + "#****************************\n", + "#STEP 2 - AUXILIARY FUNCTIONS\n", + "#****************************\n", + "\n", + "def maskL8sr (image):\n", + " cloudShadowBitMask = 1 << 3\n", + " cloudsBitMask = 1 << 5\n", + " qa = image.select('pixel_qa')\n", + " mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0) \\\n", + " .And(qa.bitwiseAnd(cloudsBitMask).eq(0))\n", + " return image.updateMask(mask).divide(10000) \\\n", + " .select(\"B[0-9]*\") \\\n", + " .copyProperties(image, [\"system:time_start\"])\n", + "\n", + "\n", + "\n", + "def addIndicesL8(img):\n", + " # NDVI (Normalized Difference Vegetation Index)\n", + " ndvi = img.normalizedDifference(['B5','B4']).rename('NDVI')\n", + "\n", + " # NDMI (Normalized Difference Mangrove Index - Shi et al 2016 )\n", + " ndmi = img.normalizedDifference(['B7','B3']).rename('NDMI')\n", + "\n", + " # MNDWI (Modified Normalized Difference Water Index - Hanqiu Xu, 2006)\n", + " mndwi = img.normalizedDifference(['B3','B6']).rename('MNDWI')\n", + "\n", + " # SR (Simple Ratio)\n", + " sr = img.select('B5').divide(img.select('B4')).rename('SR')\n", + "\n", + " # Band Ratio 6/5\n", + " ratio65 = img.select('B6').divide(img.select('B5')).rename('R65')\n", + "\n", + " # Band Ratio 4/6\n", + " ratio46 = img.select('B4').divide(img.select('B6')).rename('R46')\n", + "\n", + " # GCVI (Green Chlorophyll Vegetation Index)\n", + " gcvi = img.expression('(NIR/GREEN)-1',{\n", + " 'NIR':img.select('B5'),\n", + " 'GREEN':img.select('B3')\n", + " }).rename('GCVI')\n", + "\n", + " return img \\\n", + " .addBands(ndvi) \\\n", + " .addBands(ndmi) \\\n", + " .addBands(mndwi) \\\n", + " .addBands(sr) \\\n", + " .addBands(ratio65) \\\n", + " .addBands(ratio46) \\\n", + " .addBands(gcvi)\n", + "\n", + "\n", + "\n", + "#**************************************************************\n", + "#STEP 3 - CREATE AUXILIARY MASKS AND BANDS FOR MANGROVE MAPPING\n", + "#**************************************************************\n", + "\n", + "# WATER MASK\n", + "# The objective of this mask is to remove water pixels from the Landsat composite as we are only focusing on Mangroves\n", + "\n", + "# We will create a Water Mask using the Global Surface Water dataset\n", + "\n", + "globalwater = ee.Image('JRC/GSW1_0/GlobalSurfaceWater'); # Load the dataset\n", + "\n", + "# The Global Water Dataset has different bands. One of them is the the frequency with which water was present (occurrence).\n", + "# Esentially, this band shows how many times a given pixel was classified as water relative to the total time span of the dataset\n", + "\n", + "occurrence = globalwater.select('occurrence'); # Select the occurrence band.\n", + "\n", + "# Masks are composed by zeros and non-zero values. When you set or apply a mask to an image, the output image will keep it's original values where the mask\n", + "# has non zero values whereas the it will be masked where the mask has zero values.\n", + "# For this example, we want to create a watermask. Thus Watermask has to have zero where there is water and non zero values\n", + "# For our mask, we want to make sure we are selecting permanent water. We want to filter the dataset for water pixels that occurred more than 50% of the time over the 35 years time spam.\n", + "\n", + "waterMask = occurrence.lt(50) # Selects lower than 50%. Automatically, values above 90% are set to 0 \\\n", + " .unmask(1); \n", + "\n", + "Map.addLayer(waterMask, {}, 'Water Mask')\n", + "\n", + "\n", + "\n", + "# ELEVATION/SLOPE MASK\n", + "\n", + "# The objective of this mask is to remove pixels that are unlikely to be mangrove based on the slope. Generally, it will occur near shore where\n", + "# elevation and slope is very low.\n", + "\n", + "# We will create a mask using the SRTM Elevation Data\n", + "srtm = ee.Image('USGS/SRTMGL1_003')\n", + "\n", + "elevation = srtm.select('elevation')\n", + "\n", + "# In this case, we want to create a mask where pixels that have higher altitude values are removed\n", + "# Hence, we select everything that is UNDER 25 meters; everything else will be set to 0 automatically.\n", + "elevMask = elevation.lte(25)\n", + "Map.addLayer(elevMask, {}, 'Elevation Mask')\n", + "Map.addLayer(ee.Image().paint(aoi, 0, 2), {'palette':['red']}, 'StudyArea')\n", + "\n", + "#*********************************************************\n", + "#STEP 4 - LANDSAT 8 IMAGE COLLECTION AND CLOUD-FREE MOSAIC\n", + "#*********************************************************\n", + "\n", + "# Map the function over one year of data.\n", + "collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR') \\\n", + " .filterDate(startDay, endDay) \\\n", + " .map(maskL8sr) \\\n", + " .map(addIndicesL8)\n", + "\n", + "\n", + "composite = collection \\\n", + " .median() \\\n", + " .mask(waterMask) \\\n", + " .updateMask(elevMask) \\\n", + " .clip(aoi)\n", + "\n", + "# Display the results.\n", + "#Map.centerObject(Mangroves2016,9)\n", + "Map.addLayer(composite, {'bands': ['B5', 'B6', 'B4'], 'min': 0, 'max': 0.3}, 'Composite')\n", + "\n", + "#************************************************************\n", + "#STEP 5 - CREATE STRATIFICATION MAP BASED ON MANGROVE DATASET\n", + "#************************************************************\n", + "\n", + "#Mangrove Strata\n", + "\n", + "#First, let's load the global mangrove dataset for the year 2000\n", + "dataset = ee.FeatureCollection('projects/gee-book/assets/A3-3/Mangroves2000')\n", + "mangrove = ee.Image(1).clip(dataset)\n", + "\n", + "#All other classes Strata\n", + "\n", + "# First we create an image of zeros where values 1 will be added where there is a pixel from the composite, including the mangrove areas\n", + "nonmangrove = ee.Image(0).where(composite.select('B1'),2).selfMask()\n", + "# Now we have an image of values of 1 where there is composite. Now we set this image to zero where there is pixel of mangrove\n", + "strata = nonmangrove.where(mangrove,1).rename('landcover')\n", + "\n", + "Map.addLayer (strata, {'palette':['#B3E283', '#E8E46E'], 'min':1, 'max':2}, 'Strata')\n", + "\n", + "# Selecting samples based on the strata created above\n", + "\n", + "stratified = strata.addBands(ee.Image.pixelLonLat()).stratifiedSample({\n", + " 'numPoints': 1,\n", + " 'classBand': 'landcover',\n", + " 'scale': 30,\n", + " 'region': aoi,\n", + " 'classValues':[1,2], #\n", + " 'classPoints':[1000,1000] # Insert the number of points per class.\n", + "\n", + "def func_wep(f) # set these points to geometry and get their coordinates:\n", + " return f.setGeometry(ee.Geometry.Point([f.get('longitude'), f.get('latitude')]))\n", + "\n", + " }).map(func_wep)\n", + "\n", + "\n", + "\n", + "\n", + "paletteSamples = ee.List([\n", + " 'FFFFFF', #NULL\n", + " '01937C', # Mangrove\n", + " 'B6C867', # Non-Mangrove\n", + " ])\n", + "\n", + "# We use this function to colorize the samples based on the palette\n", + "\n", + "def func_jzm(f):\n", + " landcover = f.get('landcover')\n", + " return ee.Feature(ee.Geometry.Point([f.get('longitude'), f.get('latitude')]), f.toDictionary()) \\\n", + " .set({style: {color: paletteSamples.get(landcover) }})\n", + "\n", + "features = stratified.map(func_jzm)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Add the features / sample location into the map with the style set above\n", + "Map.addLayer(features.style(**{'styleProperty': \"style\"}),{}, 'Samples/Location')\n", + "\n", + "#************************************************************\n", + "#STEP 6 - CLASSIFICATION\n", + "#************************************************************\n", + "\n", + "# First, we will select the predictors to assign to each sample point in the sample sets\n", + "bands = ['B5','B6','B7','NDVI','MNDWI','SR']\n", + "\n", + "# Create the sample sets\n", + "# Automatic\n", + "samplesAutomatic = composite.select(bands).sampleRegions({\n", + " 'collection': stratified,\n", + " 'properties': ['landcover'],\n", + " 'scale': 30,\n", + " 'geometries': True,\n", + "})\n", + "\n", + "# Create the sample set with the samples you selected manually via geometry\n", + "manualpoints = MangroveTraining.merge(NonMangroveTraining)\n", + "samplesManual = composite.select(bands).sampleRegions({\n", + " 'collection': manualpoints,\n", + " 'properties': ['landcover'],\n", + " 'scale': 30,\n", + " 'geometries': True,\n", + "})\n", + "\n", + "# Create the Ground Truth sample set that will be used to validate the land cover classification maps\n", + "groundtruth = ee.FeatureCollection('users/celiohelder/TutorialAssets/GroundTruth')\n", + "Map.addLayer(groundtruth)\n", + "\n", + "samplesgroundtruth = composite.select(bands).sampleRegions({\n", + " 'collection': groundtruth, # Set of geometries selected in 4.1\n", + " 'properties': ['landcover'], # Label from each geometry\n", + " 'scale': 30,\n", + " 'geometries': True,\n", + "})\n", + "\n", + "\n", + "# Train two classifiers: one with the samples collected automatically via stratification and one with the samples you selected manually\n", + "RandomForest1 = ee.Classifier.smileRandomForest(200,5).train({\n", + " 'features': samplesAutomatic,\n", + " 'classProperty': 'landcover',\n", + " 'inputProperties': bands\n", + "})\n", + "\n", + "RandomForest2 = ee.Classifier.smileRandomForest(200,5).train({\n", + " 'features': samplesManual,\n", + " 'classProperty': 'landcover',\n", + " 'inputProperties': bands\n", + "})\n", + "\n", + "\n", + "# Classify the Landsat 8 Composite using the two classifiers to produce 2 land cover maps\n", + "\n", + "classifiedrf1 = composite.select(bands) # select the predictors \\\n", + " .classify(RandomForest1); \n", + "\n", + "classifiedrf2 = composite.select(bands) # select the predictors \\\n", + " .classify(RandomForest2); \n", + "\n", + "# Color palette for the classification outputs\n", + "paletteMAP = [\n", + " '01937C', # Mangrove\n", + " 'B6C867', # Non-Mangrove\n", + "]\n", + "\n", + "# Add the classifications to the map editor\n", + "Map.addLayer (classifiedrf1, {'min': 1, 'max': 2, 'palette':paletteMAP}, 'Classification Automatic Samples')\n", + "Map.addLayer (classifiedrf2, {'min': 1, 'max': 2, 'palette':paletteMAP}, 'Classification Manual Samples')\n", + "\n", + "\n", + "validation1 = samplesgroundtruth.classify(RandomForest1)\n", + "validation2 = samplesgroundtruth.classify(RandomForest2)\n", + "testAccuracy1 = validation1.errorMatrix('landcover', 'classification')\n", + "testAccuracy2 = validation2.errorMatrix('landcover', 'classification')\n", + "kappa1 = testAccuracy1.kappa()\n", + "kappa2 = testAccuracy2.kappa()\n", + "\n", + "print('Overall Accuracy Map 1: ', testAccuracy1.accuracy())\n", + "print('Overall Accuracy Map 2: ', testAccuracy2.accuracy())\n", + "print('Kappa: ', kappa1)\n", + "print('Kappa: ', kappa2)\n", + "\n", + "print('Validation error matrix Map1: ', testAccuracy1)\n", + "print('Validation error matrix Map2: ', testAccuracy2)\n", + "\n", + "legend = ui.Panel({\n", + " 'style': {\n", + " 'position': 'bottom-left', # Position in the map\n", + " 'padding': '8px 15px' # Padding (border) size\n", + " }\n", + "})\n", + "def makeRow(color, name):\n", + " # Create the label that is actually the colored boxes that represent each class\n", + " colorBox = ui.Label({\n", + " 'style': {\n", + " 'backgroundColor': '#' + color,\n", + " # Use padding to give the label color box height and width.\n", + " 'padding': '8px',\n", + " 'margin': '0 0 4px 0'\n", + " }\n", + " })\n", + " # Create the label filled with the description text.\n", + " description = ui.Label({\n", + " 'value': name,\n", + " 'style': '{margin': '0 0 4px 6px'}\n", + " })\n", + " return ui.Panel({\n", + " 'widgets': [colorBox, description],\n", + " 'layout': ui.Panel.Layout.Flow('horizontal')\n", + " })\n", + "\n", + "legend.add(makeRow('01937C', 'Mangrove'))\n", + "legend.add(makeRow('B6C867', 'Non-mangrove'))\n", + "\n", + "#Map.add (legend)\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33s1 - Supplemental.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33s1 - Supplemental.js new file mode 100644 index 0000000..f156875 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33s1 - Supplemental.js @@ -0,0 +1,9292 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var imageCollection = ee.ImageCollection("LANDSAT/MANGROVE_FORESTS"), + Mangrove = + /* color: #01937c */ + /* shown: false */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([-13.661310159982044, 9.863979956913798]), + { + "landcover": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([-13.662340128243763, 9.860766590107316]), + { + "landcover": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([-13.666974985421497, 9.860428339147328]), + { + "landcover": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([-13.671094858468372, 9.857891445884547]), + { + "landcover": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([-13.670579874337513, 9.852310212005683]), + { + "landcover": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([-13.671953165353138, 9.847405413374954]), + { + "landcover": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([-13.66165348273595, 9.847236281087548]), + { + "landcover": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([-13.661481821358997, 9.851295432063562]), + { + "landcover": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([-13.658563577950794, 9.848251073512062]), + { + "landcover": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([-13.659936868966419, 9.84317708019428]), + { + "landcover": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([-13.671609842599231, 9.844361018943362]), + { + "landcover": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([-13.680021250069935, 9.842500541860387]), + { + "landcover": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([-13.681222879708606, 9.84520668687933]), + { + "landcover": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([-13.686201059640247, 9.847067148713466]), + { + "landcover": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([-13.690149271310169, 9.849096731482412]), + { + "landcover": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([-13.690492594064075, 9.851802822424787]), + { + "landcover": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([-13.684999430001575, 9.854508891171829]), + { + "landcover": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([-13.682767832101185, 9.864318204228617]), + { + "landcover": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([-13.68139454108556, 9.870237476020813]), + { + "landcover": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([-13.677789652169544, 9.864149080614622]), + { + "landcover": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([-13.67864795905431, 9.861950465733774]), + { + "landcover": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([-13.651010477364856, 9.872943393406452]), + { + "landcover": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([-13.655130350411731, 9.876833110681515]), + { + "landcover": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([-13.654443704903919, 9.884950633398141]), + { + "landcover": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([-13.648950540841419, 9.880553666792991]), + { + "landcover": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([-13.646375620187122, 9.87564928855102]), + { + "landcover": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([-13.638822519601185, 9.871083077592651]), + { + "landcover": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([-13.63744922858556, 9.868038901772325]), + { + "landcover": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([-13.633157694161731, 9.86753153639998]), + { + "landcover": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([-13.633501016915638, 9.864149080614622]), + { + "landcover": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([-13.63470264655431, 9.860428339147328]), + { + "landcover": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([-13.626806223214466, 9.862288715131701]), + { + "landcover": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([-13.630239450753528, 9.866685925709453]), + { + "landcover": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([-13.625261270821888, 9.868038901772325]), + { + "landcover": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([-13.621828043282825, 9.867024170246147]), + { + "landcover": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([-13.616678201974231, 9.865163820996548]), + { + "landcover": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([-13.623029672921497, 9.862457839700498]), + { + "landcover": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([-13.6204547522672, 9.865163820996548]), + { + "landcover": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([-13.618394815743763, 9.862119590476139]), + { + "landcover": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([-13.627321207345325, 9.861273965896487]), + { + "landcover": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([-13.630754434884388, 9.858567952663368]), + { + "landcover": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([-13.632814371407825, 9.854508891171829]), + { + "landcover": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([-13.630067789376575, 9.865163820996548]), + { + "landcover": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([-13.637792551339466, 9.866685925709453]), + { + "landcover": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([-13.645002329171497, 9.8715904374934]), + { + "landcover": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([-13.649637186349231, 9.872436035590608]), + { + "landcover": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([-13.654100382150013, 9.873281631515944]), + { + "landcover": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([-13.65289875251134, 9.879200742165947]), + { + "landcover": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([-13.653242075265247, 9.882921271500603]), + { + "landcover": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([-13.657876932442981, 9.882921271500603]), + { + "landcover": 1, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([-13.648778879464466, 9.886134422054315]), + { + "landcover": 1, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([-13.642255747140247, 9.880046320709882]), + { + "landcover": 1, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([-13.6424274085172, 9.877171344793748]), + { + "landcover": 1, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([-13.644830667794544, 9.88089189708034]), + { + "landcover": 1, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([-13.646032297433216, 9.884443294097883]), + { + "landcover": 1, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([-13.625261270821888, 9.876325758861322]), + { + "landcover": 1, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([-13.625261270821888, 9.873281631515944]), + { + "landcover": 1, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([-13.618738138497669, 9.871928676992896]), + { + "landcover": 1, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([-13.616678201974231, 9.873281631515944]), + { + "landcover": 1, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([-13.613244974435169, 9.860766590107316]), + { + "landcover": 1, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([-13.61822315436681, 9.858906205532225]), + { + "landcover": 1, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([-13.621656381905872, 9.854339762525496]), + { + "landcover": 1, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([-13.62096973639806, 9.851464562270667]), + { + "landcover": 1, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([-13.618909799874622, 9.849773256298489]), + { + "landcover": 1, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([-13.614618265450794, 9.848420205279472]), + { + "landcover": 1, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([-13.609811746896106, 9.848420205279472]), + { + "landcover": 1, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([-13.603288614571888, 9.85044977972763]), + { + "landcover": 1, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([-13.602945291817981, 9.853155859573075]), + { + "landcover": 1, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([-13.609296762765247, 9.855185404889882]), + { + "landcover": 1, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([-13.614789926827747, 9.855185404889882]), + { + "landcover": 1, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([-13.613073313058216, 9.85501627659046]), + { + "landcover": 1, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([-13.605005228341419, 9.859075331836523]), + { + "landcover": 1, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([-13.6039752600797, 9.8631343371077]), + { + "landcover": 1, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([-13.602601969064075, 9.86059746467071]), + { + "landcover": 1, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([-13.598310434640247, 9.858398826098787]), + { + "landcover": 1, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([-13.594533884347278, 9.856200172865066]), + { + "landcover": 1, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([-13.592817270577747, 9.852479341692579]), + { + "landcover": 1, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([-13.594190561593372, 9.848589336960218]), + { + "landcover": 1, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([-13.597108805001575, 9.84520668687933]), + { + "landcover": 1, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([-13.598653757394153, 9.841824002140536]), + { + "landcover": 1, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([-13.603288614571888, 9.840809189962322]), + { + "landcover": 1, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([-13.605691873849231, 9.84317708019428]), + { + "landcover": 1, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([-13.597108805001575, 9.840978325541894]), + { + "landcover": 1, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([-13.592302286446888, 9.845037553465422]), + { + "landcover": 1, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([-13.590585672677356, 9.851633692391072]), + { + "landcover": 1, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([-13.589899027169544, 9.856707555681723]), + { + "landcover": 1, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([-13.58474918586095, 9.85653842816291]), + { + "landcover": 1, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([-13.618394815743763, 9.84351534884146]), + { + "landcover": 1, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([-13.618738138497669, 9.841147461034842]), + { + "landcover": 1, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([-13.622343027413685, 9.839117829403516]), + { + "landcover": 1, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([-13.623544657052356, 9.843853617142127]), + { + "landcover": 1, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([-13.625776254952747, 9.846559751071275]), + { + "landcover": 1, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([-13.628351175607044, 9.850788040922096]), + { + "landcover": 1, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([-13.629381143868763, 9.853663247072985]), + { + "landcover": 1, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([-13.628007852853138, 9.857722318972954]), + { + "landcover": 1, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([-13.630754434884388, 9.852648471292772]), + { + "landcover": 1, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([-13.631784403146106, 9.848251073512062]), + { + "landcover": 1, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([-13.635389292062122, 9.851802822424787]), + { + "landcover": 1, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([-13.621656381905872, 9.862119590476139]), + { + "landcover": 1, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([-13.613244974435169, 9.846390618350565]), + { + "landcover": 1, + "system:index": "99" + }), + ee.Feature( + ee.Geometry.Point([-13.61221500617345, 9.841824002140536]), + { + "landcover": 1, + "system:index": "100" + }), + ee.Feature( + ee.Geometry.Point([-13.612043344796497, 9.838948692871343]), + { + "landcover": 1, + "system:index": "101" + }), + ee.Feature( + ee.Geometry.Point([-13.647062265694935, 9.837933871859953]), + { + "landcover": 1, + "system:index": "102" + }), + ee.Feature( + ee.Geometry.Point([-13.644315683663685, 9.842838811200574]), + { + "landcover": 1, + "system:index": "103" + }), + ee.Feature( + ee.Geometry.Point([-13.642770731271106, 9.839117829403516]), + { + "landcover": 1, + "system:index": "104" + }), + ee.Feature( + ee.Geometry.Point([-13.63744922858556, 9.844868419964866]), + { + "landcover": 1, + "system:index": "105" + }), + ee.Feature( + ee.Geometry.Point([-13.657876932442981, 9.858737079141173]), + { + "landcover": 1, + "system:index": "106" + }), + ee.Feature( + ee.Geometry.Point([-13.662511789620716, 9.858567952663368]), + { + "landcover": 1, + "system:index": "107" + }), + ee.Feature( + ee.Geometry.Point([-13.706800424874622, 9.85535453310259]), + { + "landcover": 1, + "system:index": "108" + }), + ee.Feature( + ee.Geometry.Point([-13.70611377936681, 9.852986730233013]), + { + "landcover": 1, + "system:index": "109" + }), + ee.Feature( + ee.Geometry.Point([-13.70559879523595, 9.850618910368206]), + { + "landcover": 1, + "system:index": "110" + }), + ee.Feature( + ee.Geometry.Point([-13.701135599435169, 9.85501627659046]), + { + "landcover": 1, + "system:index": "111" + }), + ee.Feature( + ee.Geometry.Point([-13.70010563117345, 9.864656451196232]), + { + "landcover": 1, + "system:index": "112" + }), + ee.Feature( + ee.Geometry.Point([-13.69787403327306, 9.870913957452]), + { + "landcover": 1, + "system:index": "113" + }), + ee.Feature( + ee.Geometry.Point([-13.51410768826411, 9.628911414362962]), + { + "landcover": 1, + "system:index": "114" + }), + ee.Feature( + ee.Geometry.Point([-13.512734397248485, 9.626711248582774]), + { + "landcover": 1, + "system:index": "115" + }), + ee.Feature( + ee.Geometry.Point([-13.507241233185985, 9.62518804849386]), + { + "landcover": 1, + "system:index": "116" + }), + ee.Feature( + ee.Geometry.Point([-13.506897910432079, 9.623664841537515]), + { + "landcover": 1, + "system:index": "117" + }), + ee.Feature( + ee.Geometry.Point([-13.502263053254344, 9.62620351598291]), + { + "landcover": 1, + "system:index": "118" + }), + ee.Feature( + ee.Geometry.Point([-13.513936026887157, 9.62011066527207]), + { + "landcover": 1, + "system:index": "119" + }), + ee.Feature( + ee.Geometry.Point([-13.516167624787547, 9.618248938979898]), + { + "landcover": 1, + "system:index": "120" + }), + ee.Feature( + ee.Geometry.Point([-13.510331137971141, 9.614356205426008]), + { + "landcover": 1, + "system:index": "121" + }), + ee.Feature( + ee.Geometry.Point([-13.515137656525829, 9.609955670070063]), + { + "landcover": 1, + "system:index": "122" + }), + ee.Feature( + ee.Geometry.Point([-13.509987815217235, 9.605385822784951]), + { + "landcover": 1, + "system:index": "123" + }), + ee.Feature( + ee.Geometry.Point([-13.507756217316844, 9.603354759745566]), + { + "landcover": 1, + "system:index": "124" + }), + ee.Feature( + ee.Geometry.Point([-13.505009635285594, 9.599292597123075]), + { + "landcover": 1, + "system:index": "125" + }), + ee.Feature( + ee.Geometry.Point([-13.50363634426997, 9.59573816487159]), + { + "landcover": 1, + "system:index": "126" + }), + ee.Feature( + ee.Geometry.Point([-13.50363634426997, 9.591675910937065]), + { + "landcover": 1, + "system:index": "127" + }), + ee.Feature( + ee.Geometry.Point([-13.504494651154735, 9.58744434466681]), + { + "landcover": 1, + "system:index": "128" + }), + ee.Feature( + ee.Geometry.Point([-13.507241233185985, 9.584228318994764]), + { + "landcover": 1, + "system:index": "129" + }), + ee.Feature( + ee.Geometry.Point([-13.509644492463329, 9.581858596362853]), + { + "landcover": 1, + "system:index": "130" + }), + ee.Feature( + ee.Geometry.Point([-13.511189444855907, 9.57965812481821]), + { + "landcover": 1, + "system:index": "131" + }), + ee.Feature( + ee.Geometry.Point([-13.510502799348094, 9.574749329210274]), + { + "landcover": 1, + "system:index": "132" + }), + ee.Feature( + ee.Geometry.Point([-13.509987815217235, 9.572040997815119]), + { + "landcover": 1, + "system:index": "133" + }), + ee.Feature( + ee.Geometry.Point([-13.50861452420161, 9.568317006897123]), + { + "landcover": 1, + "system:index": "134" + }), + ee.Feature( + ee.Geometry.Point([-13.509301169709422, 9.56391587411893]), + { + "landcover": 1, + "system:index": "135" + }), + ee.Feature( + ee.Geometry.Point([-13.527497275666454, 9.559514684378756]), + { + "landcover": 1, + "system:index": "136" + }), + ee.Feature( + ee.Geometry.Point([-13.530415519074657, 9.555959835714257]), + { + "landcover": 1, + "system:index": "137" + }), + ee.Feature( + ee.Geometry.Point([-13.531960471467235, 9.553082073885204]), + { + "landcover": 1, + "system:index": "138" + }), + ee.Feature( + ee.Geometry.Point([-13.538140281037547, 9.554774877907569]), + { + "landcover": 1, + "system:index": "139" + }), + ee.Feature( + ee.Geometry.Point([-13.542603476838329, 9.55511343770186]), + { + "landcover": 1, + "system:index": "140" + }), + ee.Feature( + ee.Geometry.Point([-13.547924979523875, 9.555282717472718]), + { + "landcover": 1, + "system:index": "141" + }), + ee.Feature( + ee.Geometry.Point([-13.550843222932079, 9.558668295208136]), + { + "landcover": 1, + "system:index": "142" + }), + ee.Feature( + ee.Geometry.Point([-13.554276450471141, 9.562053839256034]), + { + "landcover": 1, + "system:index": "143" + }), + ee.Feature( + ee.Geometry.Point([-13.554276450471141, 9.560191794199206]), + { + "landcover": 1, + "system:index": "144" + }), + ee.Feature( + ee.Geometry.Point([-13.54157350857661, 9.564085149510012]), + { + "landcover": 1, + "system:index": "145" + }), + ee.Feature( + ee.Geometry.Point([-13.539856894807079, 9.56069962568011]), + { + "landcover": 1, + "system:index": "146" + }), + ee.Feature( + ee.Geometry.Point([-13.53934191067622, 9.564931525201379]), + { + "landcover": 1, + "system:index": "147" + }), + ee.Feature( + ee.Geometry.Point([-13.542603476838329, 9.561038179579535]), + { + "landcover": 1, + "system:index": "148" + }), + ee.Feature( + ee.Geometry.Point([-13.548954947785594, 9.566116447629842]), + { + "landcover": 1, + "system:index": "149" + }), + ee.Feature( + ee.Geometry.Point([-13.554104789094188, 9.56899409919021]), + { + "landcover": 1, + "system:index": "150" + }), + ee.Feature( + ee.Geometry.Point([-13.55753801663325, 9.568655553212261]), + { + "landcover": 1, + "system:index": "151" + }), + ee.Feature( + ee.Geometry.Point([-13.560112937287547, 9.57068682402128]), + { + "landcover": 1, + "system:index": "152" + }), + ee.Feature( + ee.Geometry.Point([-13.587150488427461, 9.588802244505368]), + { + "landcover": 1, + "system:index": "153" + }), + ee.Feature( + ee.Geometry.Point([-13.570670996239961, 9.591510442157333]), + { + "landcover": 1, + "system:index": "154" + }), + ee.Feature( + ee.Geometry.Point([-13.575820837548555, 9.59591121720367]), + { + "landcover": 1, + "system:index": "155" + }), + ee.Feature( + ee.Geometry.Point([-13.575820837548555, 9.607082158693155]), + { + "landcover": 1, + "system:index": "156" + }), + ee.Feature( + ee.Geometry.Point([-13.57994071059543, 9.608436187164969]), + { + "landcover": 1, + "system:index": "157" + }), + ee.Feature( + ee.Geometry.Point([-13.566894445946993, 9.610128715137005]), + { + "landcover": 1, + "system:index": "158" + }), + ee.Feature( + ee.Geometry.Point([-13.56071463637668, 9.613513745683104]), + { + "landcover": 1, + "system:index": "159" + }), + ee.Feature( + ee.Geometry.Point([-13.55796805434543, 9.615206248254303]), + { + "landcover": 1, + "system:index": "160" + }), + ee.Feature( + ee.Geometry.Point([-13.562774572900118, 9.610128715137005]), + { + "landcover": 1, + "system:index": "161" + }), + ee.Feature( + ee.Geometry.Point([-13.562087927392305, 9.60437408550142]), + { + "landcover": 1, + "system:index": "162" + }), + ee.Feature( + ee.Geometry.Point([-13.559341345361055, 9.599296389893185]), + { + "landcover": 1, + "system:index": "163" + }), + ee.Feature( + ee.Geometry.Point([-13.558998022607149, 9.594895658802585]), + { + "landcover": 1, + "system:index": "164" + }), + ee.Feature( + ee.Geometry.Point([-13.558654699853243, 9.589817821159402]), + { + "landcover": 1, + "system:index": "165" + }), + ee.Feature( + ee.Geometry.Point([-13.560371313622774, 9.586094025227984]), + { + "landcover": 1, + "system:index": "166" + }), + ee.Feature( + ee.Geometry.Point([-13.564147863915743, 9.59320305470555]), + { + "landcover": 1, + "system:index": "167" + }), + ee.Feature( + ee.Geometry.Point([-13.568611059716524, 9.590494870572455]), + { + "landcover": 1, + "system:index": "168" + }), + ee.Feature( + ee.Geometry.Point([-13.525695715478243, 9.592526010700317]), + { + "landcover": 1, + "system:index": "169" + }), + ee.Feature( + ee.Geometry.Point([-13.52775565200168, 9.595234178607734]), + { + "landcover": 1, + "system:index": "170" + }), + ee.Feature( + ee.Geometry.Point([-13.52775565200168, 9.588802244505368]), + { + "landcover": 1, + "system:index": "171" + }), + ee.Feature( + ee.Geometry.Point([-13.529815588525118, 9.584739907481588]), + { + "landcover": 1, + "system:index": "172" + }), + ee.Feature( + ee.Geometry.Point([-13.525695715478243, 9.581693122794402]), + { + "landcover": 1, + "system:index": "173" + }), + ee.Feature( + ee.Geometry.Point([-13.53324881606418, 9.595234178607734]), + { + "landcover": 1, + "system:index": "174" + }), + ee.Feature( + ee.Geometry.Point([-13.51402274184543, 9.608436187164969]), + { + "landcover": 1, + "system:index": "175" + }), + ee.Feature( + ee.Geometry.Point([-13.498229895165743, 9.649731449891549]), + { + "landcover": 1, + "system:index": "176" + }), + ee.Feature( + ee.Geometry.Point([-13.49754324965793, 9.656839140978562]), + { + "landcover": 1, + "system:index": "177" + }), + ee.Feature( + ee.Geometry.Point([-13.502693090966524, 9.670377185054937]), + { + "landcover": 1, + "system:index": "178" + }), + ee.Feature( + ee.Geometry.Point([-13.43711844497043, 9.683237822077341]), + { + "landcover": 1, + "system:index": "179" + }), + ee.Feature( + ee.Geometry.Point([-13.435745153954805, 9.682560958718609]), + { + "landcover": 1, + "system:index": "180" + }), + ee.Feature( + ee.Geometry.Point([-13.436088476708711, 9.678499749919098]), + { + "landcover": 1, + "system:index": "181" + }), + ee.Feature( + ee.Geometry.Point([-13.43986502700168, 9.672069402255028]), + { + "landcover": 1, + "system:index": "182" + }), + ee.Feature( + ee.Geometry.Point([-13.464240942529024, 9.658869882308721]), + { + "landcover": 1, + "system:index": "183" + }), + ee.Feature( + ee.Geometry.Point([-13.447418127587618, 9.609620957634213]), + { + "landcover": 1, + "system:index": "184" + }), + ee.Feature( + ee.Geometry.Point([-13.457374487450899, 9.61622174573161]), + { + "landcover": 1, + "system:index": "185" + }), + ee.Feature( + ee.Geometry.Point([-13.455314550927461, 9.613682996321328]), + { + "landcover": 1, + "system:index": "186" + }), + ee.Feature( + ee.Geometry.Point([-13.45308295302707, 9.613175244152618]), + { + "landcover": 1, + "system:index": "187" + }), + ee.Feature( + ee.Geometry.Point([-13.45685950332004, 9.607589920004852]), + { + "landcover": 1, + "system:index": "188" + }), + ee.Feature( + ee.Geometry.Point([-13.456687841943086, 9.601835247213083]), + { + "landcover": 1, + "system:index": "189" + }), + ee.Feature( + ee.Geometry.Point([-13.459949408105196, 9.59997342037242]), + { + "landcover": 1, + "system:index": "190" + }), + ee.Feature( + ee.Geometry.Point([-13.46235266738254, 9.601665990650465]), + { + "landcover": 1, + "system:index": "191" + }), + ee.Feature( + ee.Geometry.Point([-13.487586889794649, 9.647362186207621]), + { + "landcover": 1, + "system:index": "192" + }), + ee.Feature( + ee.Geometry.Point([-13.477115545800508, 9.669700295790179]), + { + "landcover": 1, + "system:index": "193" + }), + ee.Feature( + ee.Geometry.Point([-13.500118170312227, 9.668684959338288]), + { + "landcover": 1, + "system:index": "194" + }), + ee.Feature( + ee.Geometry.Point([-13.516597662499727, 9.616390995014688]), + { + "landcover": 1, + "system:index": "195" + }), + ee.Feature( + ee.Geometry.Point([-13.49256506972629, 9.621637680767956]), + { + "landcover": 1, + "system:index": "196" + }), + ee.Feature( + ee.Geometry.Point([-13.495998297265352, 9.622991650968471]), + { + "landcover": 1, + "system:index": "197" + }), + ee.Feature( + ee.Geometry.Point([-13.488616858056368, 9.618083483186357]), + { + "landcover": 1, + "system:index": "198" + }), + ee.Feature( + ee.Geometry.Point([-13.517627630761446, 9.640254295246155]), + { + "landcover": 1, + "system:index": "199" + }), + ee.Feature( + ee.Geometry.Point([-13.521575842431368, 9.643131316780002]), + { + "landcover": 1, + "system:index": "200" + }), + ee.Feature( + ee.Geometry.Point([-13.520202551415743, 9.639577345436397]), + { + "landcover": 1, + "system:index": "201" + }), + ee.Feature( + ee.Geometry.Point([-13.52003089003879, 9.638054203397656]), + { + "landcover": 1, + "system:index": "202" + }), + ee.Feature( + ee.Geometry.Point([-13.531360540917696, 9.756500193416775]), + { + "landcover": 1, + "system:index": "203" + }), + ee.Feature( + ee.Geometry.Point([-13.529815588525118, 9.752947423648195]), + { + "landcover": 1, + "system:index": "204" + }), + ee.Feature( + ee.Geometry.Point([-13.527583990624727, 9.74939461601333]), + { + "landcover": 1, + "system:index": "205" + }), + ee.Feature( + ee.Geometry.Point([-13.52500906997043, 9.752270701303399]), + { + "landcover": 1, + "system:index": "206" + }), + ee.Feature( + ee.Geometry.Point([-13.521232519677461, 9.756161836022985]), + { + "landcover": 1, + "system:index": "207" + }), + ee.Feature( + ee.Geometry.Point([-13.518829260400118, 9.759037862917843]), + { + "landcover": 1, + "system:index": "208" + }), + ee.Feature( + ee.Geometry.Point([-13.52449408583957, 9.759037862917843]), + { + "landcover": 1, + "system:index": "209" + }), + ee.Feature( + ee.Geometry.Point([-13.527583990624727, 9.756838550466977]), + { + "landcover": 1, + "system:index": "210" + }), + ee.Feature( + ee.Geometry.Point([-13.528098974755586, 9.760560455339853]), + { + "landcover": 1, + "system:index": "211" + }), + ee.Feature( + ee.Geometry.Point([-13.530158911279024, 9.76495901656875]), + { + "landcover": 1, + "system:index": "212" + }), + ee.Feature( + ee.Geometry.Point([-13.528785620263399, 9.766481581917269]), + { + "landcover": 1, + "system:index": "213" + }), + ee.Feature( + ee.Geometry.Point([-13.525867376855196, 9.769019175354734]), + { + "landcover": 1, + "system:index": "214" + }), + ee.Feature( + ee.Geometry.Point([-13.524150763085665, 9.770710893563262]), + { + "landcover": 1, + "system:index": "215" + }), + ee.Feature( + ee.Geometry.Point([-13.52552405410129, 9.767496621613954]), + { + "landcover": 1, + "system:index": "216" + }), + ee.Feature( + ee.Geometry.Point([-13.522434149316133, 9.769188347562617]), + { + "landcover": 1, + "system:index": "217" + }), + ee.Feature( + ee.Geometry.Point([-13.519344244530977, 9.76698910215254]), + { + "landcover": 1, + "system:index": "218" + }), + ee.Feature( + ee.Geometry.Point([-13.519344244530977, 9.765635713138927]), + { + "landcover": 1, + "system:index": "219" + }), + ee.Feature( + ee.Geometry.Point([-13.515567694238008, 9.76326726912586]), + { + "landcover": 1, + "system:index": "220" + }), + ee.Feature( + ee.Geometry.Point([-13.51453772597629, 9.760898808266235]), + { + "landcover": 1, + "system:index": "221" + }), + ee.Feature( + ee.Geometry.Point([-13.511447821191133, 9.76242139218114]), + { + "landcover": 1, + "system:index": "222" + }), + ee.Feature( + ee.Geometry.Point([-13.512134466698946, 9.764789842211282]), + { + "landcover": 1, + "system:index": "223" + }), + ee.Feature( + ee.Geometry.Point([-13.51127615981418, 9.768004140301493]), + { + "landcover": 1, + "system:index": "224" + }), + ee.Feature( + ee.Geometry.Point([-13.514194403222383, 9.77054172212945]), + { + "landcover": 1, + "system:index": "225" + }), + ee.Feature( + ee.Geometry.Point([-13.516940985253633, 9.768680830680962]), + { + "landcover": 1, + "system:index": "226" + }), + ee.Feature( + ee.Geometry.Point([-13.518142614892305, 9.77240260317031]), + { + "landcover": 1, + "system:index": "227" + }), + ee.Feature( + ee.Geometry.Point([-13.521575842431368, 9.774094304174467]), + { + "landcover": 1, + "system:index": "228" + }), + ee.Feature( + ee.Geometry.Point([-13.520202551415743, 9.773925134461207]), + { + "landcover": 1, + "system:index": "229" + }), + ee.Feature( + ee.Geometry.Point([-13.526382360986055, 9.766650755415005]), + { + "landcover": 1, + "system:index": "230" + }), + ee.Feature( + ee.Geometry.Point([-13.531360540917696, 9.763774794261284]), + { + "landcover": 1, + "system:index": "231" + }), + ee.Feature( + ee.Geometry.Point([-13.525180731347383, 9.75819197523183]), + { + "landcover": 1, + "system:index": "232" + }), + ee.Feature( + ee.Geometry.Point([-13.522434149316133, 9.756161836022985]), + { + "landcover": 1, + "system:index": "233" + }), + ee.Feature( + ee.Geometry.Point([-13.524150763085665, 9.75210152050255]), + { + "landcover": 1, + "system:index": "234" + }), + ee.Feature( + ee.Geometry.Point([-13.536167059472383, 9.74973298027629]), + { + "landcover": 1, + "system:index": "235" + }), + ee.Feature( + ee.Geometry.Point([-13.537025366357149, 9.746010954502083]), + { + "landcover": 1, + "system:index": "236" + }), + ee.Feature( + ee.Geometry.Point([-13.538055334618868, 9.74347318584398]), + { + "landcover": 1, + "system:index": "237" + }), + ee.Feature( + ee.Geometry.Point([-13.538913641503633, 9.741273770727341]), + { + "landcover": 1, + "system:index": "238" + }), + ee.Feature( + ee.Geometry.Point([-13.536682043603243, 9.740935397884376]), + { + "landcover": 1, + "system:index": "239" + }), + ee.Feature( + ee.Geometry.Point([-13.53548041396457, 9.743811556113686]), + { + "landcover": 1, + "system:index": "240" + }), + ee.Feature( + ee.Geometry.Point([-13.534450445702852, 9.747026056559818]), + { + "landcover": 1, + "system:index": "241" + }), + ee.Feature( + ee.Geometry.Point([-13.532562170556368, 9.74550340231482]), + { + "landcover": 1, + "system:index": "242" + }), + ee.Feature( + ee.Geometry.Point([-13.52998724990207, 9.744149926040262]), + { + "landcover": 1, + "system:index": "243" + }), + ee.Feature( + ee.Geometry.Point([-13.526897345116915, 9.744319110874857]), + { + "landcover": 1, + "system:index": "244" + }), + ee.Feature( + ee.Geometry.Point([-13.524322424462618, 9.74465748028668]), + { + "landcover": 1, + "system:index": "245" + }), + ee.Feature( + ee.Geometry.Point([-13.523807440331758, 9.742458072976037]), + { + "landcover": 1, + "system:index": "246" + }), + ee.Feature( + ee.Geometry.Point([-13.523807440331758, 9.740258651169293]), + { + "landcover": 1, + "system:index": "247" + }), + ee.Feature( + ee.Geometry.Point([-13.528613958886446, 9.735521385749621]), + { + "landcover": 1, + "system:index": "248" + }), + ee.Feature( + ee.Geometry.Point([-13.532562170556368, 9.73670570840598]), + { + "landcover": 1, + "system:index": "249" + }), + ee.Feature( + ee.Geometry.Point([-13.533077154687227, 9.740766211334252]), + { + "landcover": 1, + "system:index": "250" + }), + ee.Feature( + ee.Geometry.Point([-13.532390509179415, 9.742458072976037]), + { + "landcover": 1, + "system:index": "251" + }), + ee.Feature( + ee.Geometry.Point([-13.529472265771211, 9.742119701333845]), + { + "landcover": 1, + "system:index": "252" + }), + ee.Feature( + ee.Geometry.Point([-13.527412329247774, 9.741950515384083]), + { + "landcover": 1, + "system:index": "253" + }), + ee.Feature( + ee.Geometry.Point([-13.52998724990207, 9.740597024698355]), + { + "landcover": 1, + "system:index": "254" + }), + ee.Feature( + ee.Geometry.Point([-13.526725683739961, 9.740597024698355]), + { + "landcover": 1, + "system:index": "255" + }), + ee.Feature( + ee.Geometry.Point([-13.581828985741915, 9.75430086421618]), + { + "landcover": 1, + "system:index": "256" + }), + ee.Feature( + ee.Geometry.Point([-13.581828985741915, 9.753116604019736]), + { + "landcover": 1, + "system:index": "257" + }), + ee.Feature( + ee.Geometry.Point([-13.585090551904024, 9.753285784305413]), + { + "landcover": 1, + "system:index": "258" + }), + ee.Feature( + ee.Geometry.Point([-13.585262213280977, 9.7510864338945]), + { + "landcover": 1, + "system:index": "259" + }), + ee.Feature( + ee.Geometry.Point([-13.584747229150118, 9.750240526026937]), + { + "landcover": 1, + "system:index": "260" + }), + ee.Feature( + ee.Geometry.Point([-13.55470648818332, 9.730276477790866]), + { + "landcover": 1, + "system:index": "261" + }), + ee.Feature( + ee.Geometry.Point([-13.553333197167696, 9.727400202985306]), + { + "landcover": 1, + "system:index": "262" + }), + ee.Feature( + ee.Geometry.Point([-13.554534826806368, 9.72587745924342]), + { + "landcover": 1, + "system:index": "263" + }), + ee.Feature( + ee.Geometry.Point([-13.541316900780977, 9.72587745924342]), + { + "landcover": 1, + "system:index": "264" + }), + ee.Feature( + ee.Geometry.Point([-13.542861853173555, 9.729430517182633]), + { + "landcover": 1, + "system:index": "265" + }), + ee.Feature( + ee.Geometry.Point([-13.542346869042696, 9.731968392581692]), + { + "landcover": 1, + "system:index": "266" + }), + ee.Feature( + ee.Geometry.Point([-13.53874198012668, 9.731968392581692]), + { + "landcover": 1, + "system:index": "267" + }), + ee.Feature( + ee.Geometry.Point([-13.537883673241915, 9.728753747154048]), + { + "landcover": 1, + "system:index": "268" + }), + ee.Feature( + ee.Geometry.Point([-13.535308752587618, 9.727400202985306]), + { + "landcover": 1, + "system:index": "269" + }), + ee.Feature( + ee.Geometry.Point([-13.534450445702852, 9.731460819044104]), + { + "landcover": 1, + "system:index": "270" + }), + ee.Feature( + ee.Geometry.Point([-13.534622107079805, 9.734167868999362]), + { + "landcover": 1, + "system:index": "271" + }), + ee.Feature( + ee.Geometry.Point([-13.540115271142305, 9.737720838768078]), + { + "landcover": 1, + "system:index": "272" + }), + ee.Feature( + ee.Geometry.Point([-13.543205175927461, 9.73941271584591]), + { + "landcover": 1, + "system:index": "273" + }), + ee.Feature( + ee.Geometry.Point([-13.551444922021211, 9.76512819084024]), + { + "landcover": 1, + "system:index": "274" + }), + ee.Feature( + ee.Geometry.Point([-13.556423101952852, 9.762252216534353]), + { + "landcover": 1, + "system:index": "275" + }), + ee.Feature( + ee.Geometry.Point([-13.55195990615207, 9.76326726912586]), + { + "landcover": 1, + "system:index": "276" + }), + ee.Feature( + ee.Geometry.Point([-13.548355017236055, 9.768004140301493]), + { + "landcover": 1, + "system:index": "277" + }), + ee.Feature( + ee.Geometry.Point([-13.54749671035129, 9.77240260317031]), + { + "landcover": 1, + "system:index": "278" + }), + ee.Feature( + ee.Geometry.Point([-13.545608435204805, 9.764451493238456]), + { + "landcover": 1, + "system:index": "279" + }), + ee.Feature( + ee.Geometry.Point([-13.538398657372774, 9.759037862917843]), + { + "landcover": 1, + "system:index": "280" + }), + ee.Feature( + ee.Geometry.Point([-13.539085302880586, 9.75700772886324]), + { + "landcover": 1, + "system:index": "281" + }), + ee.Feature( + ee.Geometry.Point([-13.544921789696993, 9.74837952116449]), + { + "landcover": 1, + "system:index": "282" + }), + ee.Feature( + ee.Geometry.Point([-13.54749671035129, 9.74550340231482]), + { + "landcover": 1, + "system:index": "283" + }), + ee.Feature( + ee.Geometry.Point([-13.552303228905977, 9.74465748028668]), + { + "landcover": 1, + "system:index": "284" + }), + ee.Feature( + ee.Geometry.Point([-13.555908117821993, 9.747026056559818]), + { + "landcover": 1, + "system:index": "285" + }), + ee.Feature( + ee.Geometry.Point([-13.654785070946993, 9.909740584973962]), + { + "landcover": 1, + "system:index": "286" + }), + ee.Feature( + ee.Geometry.Point([-13.650321875146211, 9.90940238439265]), + { + "landcover": 1, + "system:index": "287" + }), + ee.Feature( + ee.Geometry.Point([-13.652381811669649, 9.908049578580023]), + { + "landcover": 1, + "system:index": "288" + }), + ee.Feature( + ee.Geometry.Point([-13.671951208642305, 9.897903357197523]), + { + "landcover": 1, + "system:index": "289" + }), + ee.Feature( + ee.Geometry.Point([-13.674011145165743, 9.893168346572097]), + { + "landcover": 1, + "system:index": "290" + }), + ee.Feature( + ee.Geometry.Point([-13.675727758935274, 9.889786154339548]), + { + "landcover": 1, + "system:index": "291" + }), + ee.Feature( + ee.Geometry.Point([-13.670234594872774, 9.886065702680298]), + { + "landcover": 1, + "system:index": "292" + }), + ee.Feature( + ee.Geometry.Point([-13.67057791762668, 9.88302166546021]), + { + "landcover": 1, + "system:index": "293" + }), + ee.Feature( + ee.Geometry.Point([-13.674011145165743, 9.880315830943365]), + { + "landcover": 1, + "system:index": "294" + }), + ee.Feature( + ee.Geometry.Point([-13.67057791762668, 9.876933506499089]), + { + "landcover": 1, + "system:index": "295" + }), + ee.Feature( + ee.Geometry.Point([-13.672981176904024, 9.873551147289685]), + { + "landcover": 1, + "system:index": "296" + }), + ee.Feature( + ee.Geometry.Point([-13.687400732568086, 9.874904095144537]), + { + "landcover": 1, + "system:index": "297" + }), + ee.Feature( + ee.Geometry.Point([-13.649388511149061, 9.835897848162661]), + { + "landcover": 1, + "system:index": "298" + }), + ee.Feature( + ee.Geometry.Point([-13.643637855021131, 9.837504656559055]), + { + "landcover": 1, + "system:index": "299" + }), + ee.Feature( + ee.Geometry.Point([-13.65016098734535, 9.832853347671694]), + { + "landcover": 1, + "system:index": "300" + }), + ee.Feature( + ee.Geometry.Point([-13.651105124918592, 9.82913225343917]), + { + "landcover": 1, + "system:index": "301" + }), + ee.Feature( + ee.Geometry.Point([-13.64767189737953, 9.824988258312377]), + { + "landcover": 1, + "system:index": "302" + }), + ee.Feature( + ee.Geometry.Point([-13.644496161905897, 9.822789382675966]), + { + "landcover": 1, + "system:index": "303" + }), + ee.Feature( + ee.Geometry.Point([-13.643981177775037, 9.824988258312377]), + { + "landcover": 1, + "system:index": "304" + }), + ee.Feature( + ee.Geometry.Point([-13.644238669840467, 9.822451092819612]), + { + "landcover": 1, + "system:index": "305" + }), + ee.Feature( + ee.Geometry.Point([-13.645096976725233, 9.826172262217474]), + { + "landcover": 1, + "system:index": "306" + }), + ee.Feature( + ee.Geometry.Point([-13.635655600992811, 9.82676426258091]), + { + "landcover": 1, + "system:index": "307" + }), + ee.Feature( + ee.Geometry.Point([-13.633338172403944, 9.825411117336346]), + { + "landcover": 1, + "system:index": "308" + }), + ee.Feature( + ee.Geometry.Point([-13.630763251749647, 9.82591854745168]), + { + "landcover": 1, + "system:index": "309" + }), + ee.Feature( + ee.Geometry.Point([-13.631020743815077, 9.82388882232074]), + { + "landcover": 1, + "system:index": "310" + }), + ee.Feature( + ee.Geometry.Point([-13.629046637980116, 9.82591854745168]), + { + "landcover": 1, + "system:index": "311" + }), + ee.Feature( + ee.Geometry.Point([-13.623725135294569, 9.835982417220407]), + { + "landcover": 1, + "system:index": "312" + }), + ee.Feature( + ee.Geometry.Point([-13.623639304606092, 9.834206462463124]), + { + "landcover": 1, + "system:index": "313" + }), + ee.Feature( + ee.Geometry.Point([-13.618746955362928, 9.832937917508435]), + { + "landcover": 1, + "system:index": "314" + }), + ee.Feature( + ee.Geometry.Point([-13.614283759562147, 9.835644140859554]), + { + "landcover": 1, + "system:index": "315" + }), + ee.Feature( + ee.Geometry.Point([-13.610678870646131, 9.837420087890889]), + { + "landcover": 1, + "system:index": "316" + }), + ee.Feature( + ee.Geometry.Point([-13.599435050455702, 9.832599638031681]), + { + "landcover": 1, + "system:index": "317" + }), + ee.Feature( + ee.Geometry.Point([-13.602009971109998, 9.831838507943388]), + { + "landcover": 1, + "system:index": "318" + }), + ee.Feature( + ee.Geometry.Point([-13.605185706583631, 9.831753937825424]), + { + "landcover": 1, + "system:index": "319" + }), + ee.Feature( + ee.Geometry.Point([-13.60844727274574, 9.831500227341687]), + { + "landcover": 1, + "system:index": "320" + }), + ee.Feature( + ee.Geometry.Point([-13.610249717203748, 9.830739094722384]), + { + "landcover": 1, + "system:index": "321" + }), + ee.Feature( + ee.Geometry.Point([-13.611022193400037, 9.82955510716544]), + { + "landcover": 1, + "system:index": "322" + }), + ee.Feature( + ee.Geometry.Point([-13.612052161661756, 9.827948260129261]), + { + "landcover": 1, + "system:index": "323" + }), + ee.Feature( + ee.Geometry.Point([-13.612652976481092, 9.825749404166388]), + { + "landcover": 1, + "system:index": "324" + }), + ee.Feature( + ee.Geometry.Point([-13.611365516153944, 9.822958527474464]), + { + "landcover": 1, + "system:index": "325" + }), + ee.Feature( + ee.Geometry.Point([-13.607159812418592, 9.82092878418678]), + { + "landcover": 1, + "system:index": "326" + }), + ee.Feature( + ee.Geometry.Point([-13.606558997599256, 9.82371967799777]), + { + "landcover": 1, + "system:index": "327" + }), + ee.Feature( + ee.Geometry.Point([-13.608876426188123, 9.826510548269171]), + { + "landcover": 1, + "system:index": "328" + }), + ee.Feature( + ee.Geometry.Point([-13.606558997599256, 9.829470536463448]), + { + "landcover": 1, + "system:index": "329" + }), + ee.Feature( + ee.Geometry.Point([-13.60295410868324, 9.828709399172217]), + { + "landcover": 1, + "system:index": "330" + }), + ee.Feature( + ee.Geometry.Point([-13.60123749491371, 9.830400812995848]), + { + "landcover": 1, + "system:index": "331" + }), + ee.Feature( + ee.Geometry.Point([-13.601838309733045, 9.827863689016356]), + { + "landcover": 1, + "system:index": "332" + }), + ee.Feature( + ee.Geometry.Point([-13.599778373209608, 9.831161946393877]), + { + "landcover": 1, + "system:index": "333" + }), + ee.Feature( + ee.Geometry.Point([-13.601151664225233, 9.827440833127513]), + { + "landcover": 1, + "system:index": "334" + }), + ee.Feature( + ee.Geometry.Point([-13.605099875895155, 9.820167627244706]), + { + "landcover": 1, + "system:index": "335" + }), + ee.Feature( + ee.Geometry.Point([-13.557979365634356, 9.739303420698274]), + { + "landcover": 1, + "system:index": "336" + }), + ee.Feature( + ee.Geometry.Point([-13.531028529452716, 9.733720191979573]), + { + "landcover": 1, + "system:index": "337" + }), + ee.Feature( + ee.Geometry.Point([-13.530856868075762, 9.731520712614177]), + { + "landcover": 1, + "system:index": "338" + }), + ee.Feature( + ee.Geometry.Point([-13.526050349521075, 9.736596412372151]), + { + "landcover": 1, + "system:index": "339" + }), + ee.Feature( + ee.Geometry.Point([-13.999500577660426, 10.035249558065319]), + { + "landcover": 1, + "system:index": "340" + }), + ee.Feature( + ee.Geometry.Point([-13.995724027367457, 10.039644440416982]), + { + "landcover": 1, + "system:index": "341" + }), + ee.Feature( + ee.Geometry.Point([-14.000530545922144, 10.0437012019244]), + { + "landcover": 1, + "system:index": "342" + }), + ee.Feature( + ee.Geometry.Point([-13.993320768090113, 10.056209229570396]), + { + "landcover": 1, + "system:index": "343" + }), + ee.Feature( + ee.Geometry.Point([-13.990574186058863, 10.06060382706283]), + { + "landcover": 1, + "system:index": "344" + }), + ee.Feature( + ee.Geometry.Point([-13.965854947777613, 10.049448193638165]), + { + "landcover": 1, + "system:index": "345" + }), + ee.Feature( + ee.Geometry.Point([-13.954525296898707, 10.051138465880086]), + { + "landcover": 1, + "system:index": "346" + }), + ee.Feature( + ee.Geometry.Point([-13.946628873558863, 10.066012480342117]), + { + "landcover": 1, + "system:index": "347" + }), + ee.Feature( + ee.Geometry.Point([-13.93598586818777, 10.064998364754487]), + { + "landcover": 1, + "system:index": "348" + }), + ee.Feature( + ee.Geometry.Point([-13.964824979515894, 10.049448193638165]), + { + "landcover": 1, + "system:index": "349" + }), + ee.Feature( + ee.Geometry.Point([-13.96619827053152, 10.045391504205845]), + { + "landcover": 1, + "system:index": "350" + }), + ee.Feature( + ee.Geometry.Point([-13.955898587914332, 10.044039263087305]), + { + "landcover": 1, + "system:index": "351" + }), + ee.Feature( + ee.Geometry.Point([-13.947315519066676, 10.041334763892895]), + { + "landcover": 1, + "system:index": "352" + }), + ee.Feature( + ee.Geometry.Point([-13.947315519066676, 10.036939904492623]), + { + "landcover": 1, + "system:index": "353" + }), + ee.Feature( + ee.Geometry.Point([-13.9431956460198, 10.028488084121358]), + { + "landcover": 1, + "system:index": "354" + }), + ee.Feature( + ee.Geometry.Point([-13.938045804711207, 10.021050299807792]), + { + "landcover": 1, + "system:index": "355" + }), + ee.Feature( + ee.Geometry.Point([-13.935642545433863, 10.027135772396795]), + { + "landcover": 1, + "system:index": "356" + }), + ee.Feature( + ee.Geometry.Point([-13.932552640648707, 10.033221130703813]), + { + "landcover": 1, + "system:index": "357" + }), + ee.Feature( + ee.Geometry.Point([-14.0200999428948, 10.093730404886111]), + { + "landcover": 1, + "system:index": "358" + }), + ee.Feature( + ee.Geometry.Point([-14.020786588402613, 10.084604034450745]), + { + "landcover": 1, + "system:index": "359" + }), + ee.Feature( + ee.Geometry.Point([-14.021473233910426, 10.077505567574326]), + { + "landcover": 1, + "system:index": "360" + }), + ee.Feature( + ee.Geometry.Point([-14.024906461449488, 10.067364629502437]), + { + "landcover": 1, + "system:index": "361" + }), + ee.Feature( + ee.Geometry.Point([-14.026279752465113, 10.055871181133208]), + { + "landcover": 1, + "system:index": "362" + }), + ee.Feature( + ee.Geometry.Point([-14.030056302758082, 10.051814572302199]), + { + "landcover": 1, + "system:index": "363" + }), + ee.Feature( + ee.Geometry.Point([-14.0255931069573, 10.043025078538774]), + { + "landcover": 1, + "system:index": "364" + }), + ee.Feature( + ee.Geometry.Point([-14.030399625511988, 10.042687016316068]), + { + "landcover": 1, + "system:index": "365" + }), + ee.Feature( + ee.Geometry.Point([-14.023533170433863, 10.03896830855453]), + { + "landcover": 1, + "system:index": "366" + }), + ee.Feature( + ee.Geometry.Point([-14.022503202172144, 10.054518983847622]), + { + "landcover": 1, + "system:index": "367" + }), + ee.Feature( + ee.Geometry.Point([-14.027309720726832, 10.053842883082915]), + { + "landcover": 1, + "system:index": "368" + }), + ee.Feature( + ee.Geometry.Point([-14.034519498558863, 10.05722337275972]), + { + "landcover": 1, + "system:index": "369" + }), + ee.Feature( + ee.Geometry.Point([-14.040699308129176, 10.06060382706283]), + { + "landcover": 1, + "system:index": "370" + }), + ee.Feature( + ee.Geometry.Point([-14.042759244652613, 10.051814572302199]), + { + "landcover": 1, + "system:index": "371" + }), + ee.Feature( + ee.Geometry.Point([-14.042415921898707, 10.07277316948383]), + { + "landcover": 1, + "system:index": "372" + }), + ee.Feature( + ee.Geometry.Point([-14.039669339867457, 10.079533716921128]), + { + "landcover": 1, + "system:index": "373" + }), + ee.Feature( + ee.Geometry.Point([-14.036922757836207, 10.081899875029649]), + { + "landcover": 1, + "system:index": "374" + }), + ee.Feature( + ee.Geometry.Point([-14.03383285305105, 10.075477405468384]), + { + "landcover": 1, + "system:index": "375" + }), + ee.Feature( + ee.Geometry.Point([-14.035206144066676, 10.072435138391462]), + { + "landcover": 1, + "system:index": "376" + }), + ee.Feature( + ee.Geometry.Point([-14.032802884789332, 10.070068910826576]), + { + "landcover": 1, + "system:index": "377" + }), + ee.Feature( + ee.Geometry.Point([-14.029026334496363, 10.068378737654886]), + { + "landcover": 1, + "system:index": "378" + }), + ee.Feature( + ee.Geometry.Point([-14.0255931069573, 10.091026322094907]), + { + "landcover": 1, + "system:index": "379" + }), + ee.Feature( + ee.Geometry.Point([-14.042415921898707, 10.10927843988686]), + { + "landcover": 1, + "system:index": "380" + }), + ee.Feature( + ee.Geometry.Point([-14.046879117699488, 10.108264460521394]), + { + "landcover": 1, + "system:index": "381" + }), + ee.Feature( + ee.Geometry.Point([-14.051685636254176, 10.106574487803298]), + { + "landcover": 1, + "system:index": "382" + }), + ee.Feature( + ee.Geometry.Point([-14.057865445824488, 10.10454650881349]), + { + "landcover": 1, + "system:index": "383" + }), + ee.Feature( + ee.Geometry.Point([-14.059925382347926, 10.123473814924237]), + { + "landcover": 1, + "system:index": "384" + }), + ee.Feature( + ee.Geometry.Point([-14.06232864162527, 10.117728143481251]), + { + "landcover": 1, + "system:index": "385" + }), + ee.Feature( + ee.Geometry.Point([-14.064731900902613, 10.114348288716734]), + { + "landcover": 1, + "system:index": "386" + }), + ee.Feature( + ee.Geometry.Point([-14.06507522365652, 10.110968398385992]), + { + "landcover": 1, + "system:index": "387" + }), + ee.Feature( + ee.Geometry.Point([-14.060268705101832, 10.115362248881063]), + { + "landcover": 1, + "system:index": "388" + }), + ee.Feature( + ee.Geometry.Point([-14.054432218285426, 10.115700234891127]), + { + "landcover": 1, + "system:index": "389" + }), + ee.Feature( + ee.Geometry.Point([-14.052028959008082, 10.117052175374186]), + { + "landcover": 1, + "system:index": "390" + }), + ee.Feature( + ee.Geometry.Point([-14.0365794350823, 10.126853573603118]), + { + "landcover": 1, + "system:index": "391" + }), + ee.Feature( + ee.Geometry.Point([-14.035892789574488, 10.122797858916474]), + { + "landcover": 1, + "system:index": "392" + }), + ee.Feature( + ee.Geometry.Point([-14.030742948265894, 10.12752952106626]), + { + "landcover": 1, + "system:index": "393" + }), + ee.Feature( + ee.Geometry.Point([-14.023189847679957, 10.12482572266808]), + { + "landcover": 1, + "system:index": "394" + }), + ee.Feature( + ee.Geometry.Point([-14.0200999428948, 10.125501674403939]), + { + "landcover": 1, + "system:index": "395" + }), + ee.Feature( + ee.Geometry.Point([-14.040012662621363, 10.12482572266808]), + { + "landcover": 1, + "system:index": "396" + }), + ee.Feature( + ee.Geometry.Point([-14.041729276390894, 10.130233296673653]), + { + "landcover": 1, + "system:index": "397" + }), + ee.Feature( + ee.Geometry.Point([-14.025249784203394, 10.117052175374186]), + { + "landcover": 1, + "system:index": "398" + }), + ee.Feature( + ee.Geometry.Point([-14.020786588402613, 10.120094020648413]), + { + "landcover": 1, + "system:index": "399" + }), + ee.Feature( + ee.Geometry.Point([-14.017696683617457, 10.11265834799643]), + { + "landcover": 1, + "system:index": "400" + }), + ee.Feature( + ee.Geometry.Point([-14.005337064476832, 10.108264460521394]), + { + "landcover": 1, + "system:index": "401" + }), + ee.Feature( + ee.Geometry.Point([-14.003277127953394, 10.108602453998687]), + { + "landcover": 1, + "system:index": "402" + }), + ee.Feature( + ee.Geometry.Point([-14.005337064476832, 10.094068413637778]), + { + "landcover": 1, + "system:index": "403" + }), + ee.Feature( + ee.Geometry.Point([-14.003277127953394, 10.092040355803496]), + { + "landcover": 1, + "system:index": "404" + }), + ee.Feature( + ee.Geometry.Point([-14.001217191429957, 10.088322216591616]), + { + "landcover": 1, + "system:index": "405" + }), + ee.Feature( + ee.Geometry.Point([-13.958988492699488, 10.07277316948383]), + { + "landcover": 1, + "system:index": "406" + }), + ee.Feature( + ee.Geometry.Point([-13.95521194240652, 10.067364629502437]), + { + "landcover": 1, + "system:index": "407" + }), + ee.Feature( + ee.Geometry.Point([-13.958645169945582, 10.064660325517268]), + { + "landcover": 1, + "system:index": "408" + }), + ee.Feature( + ee.Geometry.Point([-13.94697219631277, 10.082913937472131]), + { + "landcover": 1, + "system:index": "409" + }), + ee.Feature( + ee.Geometry.Point([-14.121380155297144, 10.071421042988929]), + { + "landcover": 1, + "system:index": "410" + }), + ee.Feature( + ee.Geometry.Point([-14.132366483422144, 10.071759075144007]), + { + "landcover": 1, + "system:index": "411" + }), + ee.Feature( + ee.Geometry.Point([-14.139919584008082, 10.097110476427376]), + { + "landcover": 1, + "system:index": "412" + }), + ee.Feature( + ee.Geometry.Point([-14.132023160668238, 10.101842516928926]), + { + "landcover": 1, + "system:index": "413" + }), + ee.Feature( + ee.Geometry.Point([-14.130649869652613, 10.108264460521394]), + { + "landcover": 1, + "system:index": "414" + }), + ee.Feature( + ee.Geometry.Point([-14.123096769066676, 10.12752952106626]), + { + "landcover": 1, + "system:index": "415" + }), + ee.Feature( + ee.Geometry.Point([-14.108333890648707, 10.125501674403939]), + { + "landcover": 1, + "system:index": "416" + }), + ee.Feature( + ee.Geometry.Point([-14.092197721215113, 10.125839649737824]), + { + "landcover": 1, + "system:index": "417" + }), + ee.Feature( + ee.Geometry.Point([-14.088421170922144, 10.114686275793847]), + { + "landcover": 1, + "system:index": "418" + }), + ee.Feature( + ee.Geometry.Point([-14.099064176293238, 10.114010301283944]), + { + "landcover": 1, + "system:index": "419" + }), + ee.Feature( + ee.Geometry.Point([-14.093914334984644, 10.102180517157963]), + { + "landcover": 1, + "system:index": "420" + }), + ee.Feature( + ee.Geometry.Point([-14.093914334984644, 10.095082437762859]), + { + "landcover": 1, + "system:index": "421" + }), + ee.Feature( + ee.Geometry.Point([-14.104900663109644, 10.086632139121175]), + { + "landcover": 1, + "system:index": "422" + }), + ee.Feature( + ee.Geometry.Point([-14.09528762600027, 10.150172937371915]), + { + "landcover": 1, + "system:index": "423" + }), + ee.Feature( + ee.Geometry.Point([-14.091167752953394, 10.155580083537874]), + { + "landcover": 1, + "system:index": "424" + }), + ee.Feature( + ee.Geometry.Point([-14.097690885277613, 10.160311261454012]), + { + "landcover": 1, + "system:index": "425" + }), + ee.Feature( + ee.Geometry.Point([-14.104214017601832, 10.159635383180365]), + { + "landcover": 1, + "system:index": "426" + }), + ee.Feature( + ee.Geometry.Point([-14.11073714992605, 10.154566250592843]), + { + "landcover": 1, + "system:index": "427" + }), + ee.Feature( + ee.Geometry.Point([-14.116916959496363, 10.175180221816479]), + { + "landcover": 1, + "system:index": "428" + }), + ee.Feature( + ee.Geometry.Point([-14.126186673851832, 10.185655664472218]), + { + "landcover": 1, + "system:index": "429" + }), + ee.Feature( + ee.Geometry.Point([-14.132023160668238, 10.186331487669804]), + { + "landcover": 1, + "system:index": "430" + }), + ee.Feature( + ee.Geometry.Point([-14.130649869652613, 10.181262778780816]), + { + "landcover": 1, + "system:index": "431" + }), + ee.Feature( + ee.Geometry.Point([-14.145756070824488, 10.186669398731471]), + { + "landcover": 1, + "system:index": "432" + }), + ee.Feature( + ee.Geometry.Point([-14.14369613430105, 10.17653191116013]), + { + "landcover": 1, + "system:index": "433" + }), + ee.Feature( + ee.Geometry.Point([-14.138546292992457, 10.166394101608132]), + { + "landcover": 1, + "system:index": "434" + }), + ee.Feature( + ee.Geometry.Point([-14.142666166039332, 10.162338887701564]), + { + "landcover": 1, + "system:index": "435" + }), + ee.Feature( + ee.Geometry.Point([-14.145412748070582, 10.160311261454012]), + { + "landcover": 1, + "system:index": "436" + }), + ee.Feature( + ee.Geometry.Point([-14.135799710961207, 10.159973322495789]), + { + "landcover": 1, + "system:index": "437" + }), + ee.Feature( + ee.Geometry.Point([-14.172878568383082, 10.151524732480077]), + { + "landcover": 1, + "system:index": "438" + }), + ee.Feature( + ee.Geometry.Point([-14.17768508693777, 10.151524732480077]), + { + "landcover": 1, + "system:index": "439" + }), + ee.Feature( + ee.Geometry.Point([-14.181804959984644, 10.14848318545724]), + { + "landcover": 1, + "system:index": "440" + }), + ee.Feature( + ee.Geometry.Point([-14.182834928246363, 10.141048171078742]), + { + "landcover": 1, + "system:index": "441" + }), + ee.Feature( + ee.Geometry.Point([-14.182491605492457, 10.137330599166003]), + { + "landcover": 1, + "system:index": "442" + }), + ee.Feature( + ee.Geometry.Point([-14.180774991722926, 10.199847650708099]), + { + "landcover": 1, + "system:index": "443" + }), + ee.Feature( + ee.Geometry.Point([-14.182491605492457, 10.204578172280252]), + { + "landcover": 1, + "system:index": "444" + }), + ee.Feature( + ee.Geometry.Point([-14.184551542015894, 10.200185547437004]), + { + "landcover": 1, + "system:index": "445" + }), + ee.Feature( + ee.Geometry.Point([-14.187298124047144, 10.204240280213417]), + { + "landcover": 1, + "system:index": "446" + }), + ee.Feature( + ee.Geometry.Point([-14.18764144680105, 10.200861339819124]), + { + "landcover": 1, + "system:index": "447" + }), + ee.Feature( + ee.Geometry.Point([-14.189701383324488, 10.204916063988373]), + { + "landcover": 1, + "system:index": "448" + }), + ee.Feature( + ee.Geometry.Point([-14.1903880288323, 10.202888708359332]), + { + "landcover": 1, + "system:index": "449" + }), + ee.Feature( + ee.Geometry.Point([-14.192791288109644, 10.205591846328486]), + { + "landcover": 1, + "system:index": "450" + }), + ee.Feature( + ee.Geometry.Point([-14.195537870140894, 10.204240280213417]), + { + "landcover": 1, + "system:index": "451" + }), + ee.Feature( + ee.Geometry.Point([-14.172535245629176, 10.204240280213417]), + { + "landcover": 1, + "system:index": "452" + }), + ee.Feature( + ee.Geometry.Point([-14.172535245629176, 10.199847650708099]), + { + "landcover": 1, + "system:index": "453" + }), + ee.Feature( + ee.Geometry.Point([-14.175625150414332, 10.19646866370126]), + { + "landcover": 1, + "system:index": "454" + }), + ee.Feature( + ee.Geometry.Point([-14.17493850490652, 10.193427544749241]), + { + "landcover": 1, + "system:index": "455" + }), + ee.Feature( + ee.Geometry.Point([-14.170131986351832, 10.197820262805768]), + { + "landcover": 1, + "system:index": "456" + }), + ee.Feature( + ee.Geometry.Point([-14.162235563011988, 10.185317752336328]), + { + "landcover": 1, + "system:index": "457" + }), + ee.Feature( + ee.Geometry.Point([-14.152279203148707, 10.195454960609357]), + { + "landcover": 1, + "system:index": "458" + }), + ee.Feature( + ee.Geometry.Point([-14.149532621117457, 10.199509753620669]), + { + "landcover": 1, + "system:index": "459" + }), + ee.Feature( + ee.Geometry.Point([-14.150905912133082, 10.190724303536632]), + { + "landcover": 1, + "system:index": "460" + }), + ee.Feature( + ee.Geometry.Point([-14.137173001976832, 10.202212920280374]), + { + "landcover": 1, + "system:index": "461" + }), + ee.Feature( + ee.Geometry.Point([-14.140262906761988, 10.204578172280252]), + { + "landcover": 1, + "system:index": "462" + }), + ee.Feature( + ee.Geometry.Point([-14.135113065453394, 10.200861339819124]), + { + "landcover": 1, + "system:index": "463" + }), + ee.Feature( + ee.Geometry.Point([-14.134083097191676, 10.205591846328486]), + { + "landcover": 1, + "system:index": "464" + }), + ee.Feature( + ee.Geometry.Point([-14.127903287621363, 10.20322660186085]), + { + "landcover": 1, + "system:index": "465" + }), + ee.Feature( + ee.Geometry.Point([-14.126186673851832, 10.201537130766951]), + { + "landcover": 1, + "system:index": "466" + }), + ee.Feature( + ee.Geometry.Point([-14.122410123558863, 10.197820262805768]), + { + "landcover": 1, + "system:index": "467" + }), + ee.Feature( + ee.Geometry.Point([-14.117603605004176, 10.194779156756098]), + { + "landcover": 1, + "system:index": "468" + }), + ee.Feature( + ee.Geometry.Point([-14.114170377465113, 10.192075927009176]), + { + "landcover": 1, + "system:index": "469" + }), + ee.Feature( + ee.Geometry.Point([-14.10902053615652, 10.195792861998385]), + { + "landcover": 1, + "system:index": "470" + }), + ee.Feature( + ee.Geometry.Point([-14.110050504418238, 10.191400115989413]), + { + "landcover": 1, + "system:index": "471" + }), + ee.Feature( + ee.Geometry.Point([-14.106960599633082, 10.187345219780514]), + { + "landcover": 1, + "system:index": "472" + }), + ee.Feature( + ee.Geometry.Point([-14.09528762600027, 10.194441254291904]), + { + "landcover": 1, + "system:index": "473" + }), + ee.Feature( + ee.Geometry.Point([-14.096317594261988, 10.190048489650911]), + { + "landcover": 1, + "system:index": "474" + }), + ee.Feature( + ee.Geometry.Point([-14.091854398461207, 10.187345219780514]), + { + "landcover": 1, + "system:index": "475" + }), + ee.Feature( + ee.Geometry.Point([-14.09803420803152, 10.185993576250045]), + { + "landcover": 1, + "system:index": "476" + }), + ee.Feature( + ee.Geometry.Point([-14.094600980492457, 10.184979839842379]), + { + "landcover": 1, + "system:index": "477" + }), + ee.Feature( + ee.Geometry.Point([-14.091167752953394, 10.181938611286409]), + { + "landcover": 1, + "system:index": "478" + }), + ee.Feature( + ee.Geometry.Point([-14.08430129787527, 10.184304013780388]), + { + "landcover": 1, + "system:index": "479" + }), + ee.Feature( + ee.Geometry.Point([-14.085674588890894, 10.180586944843554]), + { + "landcover": 1, + "system:index": "480" + }), + ee.Feature( + ee.Geometry.Point([-14.089107816429957, 10.176869832601675]), + { + "landcover": 1, + "system:index": "481" + }), + ee.Feature( + ee.Geometry.Point([-14.214420621605738, 10.1403722521214]), + { + "landcover": 1, + "system:index": "482" + }), + ee.Feature( + ee.Geometry.Point([-14.218540494652613, 10.13597874414021]), + { + "landcover": 1, + "system:index": "483" + }), + ee.Feature( + ee.Geometry.Point([-14.220943753929957, 10.139020409928333]), + { + "landcover": 1, + "system:index": "484" + }), + ee.Feature( + ee.Geometry.Point([-14.214763944359644, 10.137668562031386]), + { + "landcover": 1, + "system:index": "485" + }), + ee.Feature( + ee.Geometry.Point([-14.224720304222926, 10.137668562031386]), + { + "landcover": 1, + "system:index": "486" + }), + ee.Feature( + ee.Geometry.Point([-14.227466886254176, 10.143413876197156]), + { + "landcover": 1, + "system:index": "487" + }), + ee.Feature( + ee.Geometry.Point([-14.234676664086207, 10.212349590792996]), + { + "landcover": 1, + "system:index": "488" + }), + ee.Feature( + ee.Geometry.Point([-14.234676664086207, 10.207619184738817]), + { + "landcover": 1, + "system:index": "489" + }), + ee.Feature( + ee.Geometry.Point([-14.236393277855738, 10.204240280213417]), + { + "landcover": 1, + "system:index": "490" + }), + ee.Feature( + ee.Geometry.Point([-14.239483182640894, 10.21099805338396]), + { + "landcover": 1, + "system:index": "491" + }), + ee.Feature( + ee.Geometry.Point([-14.241543119164332, 10.219107191672828]), + { + "landcover": 1, + "system:index": "492" + }), + ee.Feature( + ee.Geometry.Point([-14.285488431664332, 10.228567591509108]), + { + "landcover": 1, + "system:index": "493" + }), + ee.Feature( + ee.Geometry.Point([-14.28651839992605, 10.2278918580079]), + { + "landcover": 1, + "system:index": "494" + }), + ee.Feature( + ee.Geometry.Point([-14.288921659203394, 10.2278918580079]), + { + "landcover": 1, + "system:index": "495" + }), + ee.Feature( + ee.Geometry.Point([-14.195194547386988, 10.222148065200006]), + { + "landcover": 1, + "system:index": "496" + }), + ee.Feature( + ee.Geometry.Point([-14.19313461086355, 10.220120819414998]), + { + "landcover": 1, + "system:index": "497" + }), + ee.Feature( + ee.Geometry.Point([-14.1958811928948, 10.217755682988003]), + { + "landcover": 1, + "system:index": "498" + }), + ee.Feature( + ee.Geometry.Point([-14.198971097679957, 10.216404168556885]), + { + "landcover": 1, + "system:index": "499" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.52315168974187, 9.621012255759489], + [-13.524095827315112, 9.618727414519354], + [-13.521950060103197, 9.618727414519354]]]), + { + "landcover": 1, + "system:index": "500" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.486244493696947, 9.617542675945005], + [-13.487016969893237, 9.615596310704088], + [-13.484098726485033, 9.615511685874274]]]), + { + "landcover": 1, + "system:index": "501" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.52801132696572, 9.618896665130736], + [-13.528526311096579, 9.61568093809527], + [-13.525779729065329, 9.616188686502388]]]), + { + "landcover": 1, + "system:index": "502" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.463294987854391, 9.581660060195713], + [-13.460205083069235, 9.579628855011359], + [-13.457630162414938, 9.582337125889376]]]), + { + "landcover": 1, + "system:index": "503" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.480976109680563, 9.657990686442465], + [-13.482006077942282, 9.654775331951527], + [-13.479431157287985, 9.65528302154379]]]), + { + "landcover": 1, + "system:index": "504" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.50775528448525, 9.663405950907341], + [-13.506896977600485, 9.659175282988585], + [-13.504493718323141, 9.660359875366272]]]), + { + "landcover": 1, + "system:index": "505" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.446472172912985, 9.663405950907341], + [-13.449905400452048, 9.661882916583096], + [-13.44733047979775, 9.659344510726331]]]), + { + "landcover": 1, + "system:index": "506" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.60766220587197, 9.722291314738907], + [-13.605430607971579, 9.71958416859477], + [-13.603199010071188, 9.723137293414952]]]), + { + "landcover": 1, + "system:index": "507" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.60714722174111, 9.785902927708433], + [-13.60714722174111, 9.78133547748043], + [-13.604057316955954, 9.783534628020057]]]), + { + "landcover": 1, + "system:index": "508" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.578308110412985, 9.78065881284821], + [-13.578308110412985, 9.777275469025232], + [-13.575389867004782, 9.779474646427087]]]), + { + "landcover": 1, + "system:index": "509" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.701560979065329, 9.777275469025232], + [-13.699672703918845, 9.773722920958017], + [-13.6972694446415, 9.776937132749193]]]), + { + "landcover": 1, + "system:index": "510" + }), + ee.Feature( + ee.Geometry.Point([-13.959463327400387, 10.056802999864853]), + { + "landcover": 1, + "system:index": "511" + }), + ee.Feature( + ee.Geometry.Point([-13.981779306404293, 10.019108491959036]), + { + "landcover": 1, + "system:index": "512" + }), + ee.Feature( + ee.Geometry.Point([-14.009416788093747, 10.03787177777399]), + { + "landcover": 1, + "system:index": "513" + }), + ee.Feature( + ee.Geometry.Point([-14.006670206062497, 10.038209845027112]), + { + "landcover": 1, + "system:index": "514" + }), + ee.Feature( + ee.Geometry.Point([-14.006155221931637, 10.036857573896196]), + { + "landcover": 1, + "system:index": "515" + }), + ee.Feature( + ee.Geometry.Point([-14.016969888679684, 10.018601361050132]), + { + "landcover": 1, + "system:index": "516" + }), + ee.Feature( + ee.Geometry.Point([-14.008730142585934, 10.053422505790016]), + { + "landcover": 1, + "system:index": "517" + }), + ee.Feature( + ee.Geometry.Point([-14.02005979346484, 10.052746402731378]), + { + "landcover": 1, + "system:index": "518" + }), + ee.Feature( + ee.Geometry.Point([-14.020918100349606, 10.04699946963806]), + { + "landcover": 1, + "system:index": "519" + }), + ee.Feature( + ee.Geometry.Point([-13.996713846199215, 10.049534893889792]), + { + "landcover": 1, + "system:index": "520" + }), + ee.Feature( + ee.Geometry.Point([-13.433250165943592, 9.515253067891168]), + { + "landcover": 1, + "system:index": "521" + }), + ee.Feature( + ee.Geometry.Point([-13.441661573414295, 9.523548647400151]), + { + "landcover": 1, + "system:index": "522" + }), + ee.Feature( + ee.Geometry.Point([-13.440116621021717, 9.50661867948395]), + { + "landcover": 1, + "system:index": "523" + }), + ee.Feature( + ee.Geometry.Point([-13.443721509937733, 9.516776760858239]), + { + "landcover": 1, + "system:index": "524" + }), + ee.Feature( + ee.Geometry.Point([-13.447154737476795, 9.522532872976543]), + { + "landcover": 1, + "system:index": "525" + }), + ee.Feature( + ee.Geometry.Point([-13.445953107838124, 9.529473937981358]), + { + "landcover": 1, + "system:index": "526" + }), + ee.Feature( + ee.Geometry.Point([-13.452647901539295, 9.52913535271861]), + { + "landcover": 1, + "system:index": "527" + }), + ee.Feature( + ee.Geometry.Point([-13.442004896168202, 9.53793846035774]), + { + "landcover": 1, + "system:index": "528" + }), + ee.Feature( + ee.Geometry.Point([-13.439944959644764, 9.543524930040505]), + { + "landcover": 1, + "system:index": "529" + }), + ee.Feature( + ee.Geometry.Point([-13.449729658131092, 9.53759988349555]), + { + "landcover": 1, + "system:index": "530" + }), + ee.Feature( + ee.Geometry.Point([-13.450072980884999, 9.544202071659186]), + { + "landcover": 1, + "system:index": "531" + }), + ee.Feature( + ee.Geometry.Point([-13.452819562916249, 9.50407911200358]), + { + "landcover": 1, + "system:index": "532" + }), + ee.Feature( + ee.Geometry.Point([-13.458484388355702, 9.50255536246944]), + { + "landcover": 1, + "system:index": "533" + }), + ee.Feature( + ee.Geometry.Point([-13.454192853931874, 9.4998464576609]), + { + "landcover": 1, + "system:index": "534" + }), + ee.Feature( + ee.Geometry.Point([-13.454364515308827, 9.491719614665294]), + { + "landcover": 1, + "system:index": "535" + }), + ee.Feature( + ee.Geometry.Point([-13.394283033375233, 9.52913535271861]), + { + "landcover": 1, + "system:index": "536" + }), + ee.Feature( + ee.Geometry.Point([-13.389991498951405, 9.545048496790354]), + { + "landcover": 1, + "system:index": "537" + }), + ee.Feature( + ee.Geometry.Point([-13.431361890797108, 9.493582033213793]), + { + "landcover": 1, + "system:index": "538" + }), + ee.Feature( + ee.Geometry.Point([-13.42758534050414, 9.49307410188631]), + { + "landcover": 1, + "system:index": "539" + }), + ee.Feature( + ee.Geometry.Point([-13.439944959644764, 9.491719614665294]), + { + "landcover": 1, + "system:index": "540" + }), + ee.Feature( + ee.Geometry.Point([-13.446639753345936, 9.480883524227751]), + { + "landcover": 1, + "system:index": "541" + }), + ee.Feature( + ee.Geometry.Point([-13.432906843189686, 9.488671998844872]), + { + "landcover": 1, + "system:index": "542" + }), + ee.Feature( + ee.Geometry.Point([-13.50946781731078, 9.52168639198262]), + { + "landcover": 1, + "system:index": "543" + }), + ee.Feature( + ee.Geometry.Point([-13.530582166676014, 9.523379351872673]), + { + "landcover": 1, + "system:index": "544" + }), + ee.Feature( + ee.Geometry.Point([-13.54568836784789, 9.526765246475557]), + { + "landcover": 1, + "system:index": "545" + }), + ee.Feature( + ee.Geometry.Point([-13.552726484302967, 9.527442421367]), + { + "landcover": 1, + "system:index": "546" + }), + ee.Feature( + ee.Geometry.Point([-13.555816389088124, 9.53946205207731]), + { + "landcover": 1, + "system:index": "547" + }), + ee.Feature( + ee.Geometry.Point([-13.538821912769764, 9.540816350112253]), + { + "landcover": 1, + "system:index": "548" + }), + ee.Feature( + ee.Geometry.Point([-13.444579816822499, 9.462935496757591]), + { + "landcover": 1, + "system:index": "549" + }), + ee.Feature( + ee.Geometry.Point([-13.38037846184203, 9.45480777971921]), + { + "landcover": 1, + "system:index": "550" + }), + ee.Feature( + ee.Geometry.Point([-13.35239765739867, 9.47174030668765]), + { + "landcover": 1, + "system:index": "551" + }), + ee.Feature( + ee.Geometry.Point([-13.359264112476795, 9.486132298297015]), + { + "landcover": 1, + "system:index": "552" + }), + ee.Feature( + ee.Geometry.Point([-13.359607435230702, 9.484100524314757]), + { + "landcover": 1, + "system:index": "553" + }), + ee.Feature( + ee.Geometry.Point([-13.337463117603749, 9.47123234301792]), + { + "landcover": 1, + "system:index": "554" + }), + ee.Feature( + ee.Geometry.Point([-13.34141132927367, 9.49425927381244]), + { + "landcover": 1, + "system:index": "555" + }), + ee.Feature( + ee.Geometry.Point([-13.341582990650624, 9.498153381271607]), + { + "landcover": 1, + "system:index": "556" + }), + ee.Feature( + ee.Geometry.Point([-13.337978101734608, 9.505772159084684]), + { + "landcover": 1, + "system:index": "557" + }), + ee.Feature( + ee.Geometry.Point([-13.348621107105702, 9.512036360435498]), + { + "landcover": 1, + "system:index": "558" + }), + ee.Feature( + ee.Geometry.Point([-13.352740980152577, 9.512713564520134]), + { + "landcover": 1, + "system:index": "559" + }), + ee.Feature( + ee.Geometry.Point([-13.329910017017811, 9.432624908679694]), + { + "landcover": 1, + "system:index": "560" + }), + ee.Feature( + ee.Geometry.Point([-13.33420155144164, 9.433810289049077]), + { + "landcover": 1, + "system:index": "561" + }), + ee.Feature( + ee.Geometry.Point([-13.332828260426014, 9.429915452536795]), + { + "landcover": 1, + "system:index": "562" + }), + ee.Feature( + ee.Geometry.Point([-13.345874525074452, 9.413658269000564]), + { + "landcover": 1, + "system:index": "563" + }), + ee.Feature( + ee.Geometry.Point([-13.289397932056874, 9.419754802521876]), + { + "landcover": 1, + "system:index": "564" + }), + ee.Feature( + ee.Geometry.Point([-13.282874799732655, 9.414674365391507]), + { + "landcover": 1, + "system:index": "565" + }), + ee.Feature( + ee.Geometry.Point([-13.25901386833617, 9.407900333029371]), + { + "landcover": 1, + "system:index": "566" + }), + ee.Feature( + ee.Geometry.Point([-13.244250989918202, 9.402481011589613]), + { + "landcover": 1, + "system:index": "567" + }), + ee.Feature( + ee.Geometry.Point([-13.280128217701405, 9.39350507376156]), + { + "landcover": 1, + "system:index": "568" + }), + ee.Feature( + ee.Geometry.Point([-13.28150150871703, 9.34235473089528]), + { + "landcover": 1, + "system:index": "569" + }), + ee.Feature( + ee.Geometry.Point([-13.297122694019764, 9.35065447039907]), + { + "landcover": 1, + "system:index": "570" + }), + ee.Feature( + ee.Geometry.Point([-13.288539625172108, 9.360647771582952]), + { + "landcover": 1, + "system:index": "571" + }), + ee.Feature( + ee.Geometry.Point([-13.307422376636952, 9.358784635516088]), + { + "landcover": 1, + "system:index": "572" + }), + ee.Feature( + ee.Geometry.Point([-13.331969953541249, 9.35963151678442]), + { + "landcover": 1, + "system:index": "573" + }), + ee.Feature( + ee.Geometry.Point([-13.334029890064686, 9.35438081966868]), + { + "landcover": 1, + "system:index": "574" + }), + ee.Feature( + ee.Geometry.Point([-13.341068006519764, 9.351840131314342]), + { + "landcover": 1, + "system:index": "575" + }), + ee.Feature( + ee.Geometry.Point([-13.34467289543578, 9.336764998940213]), + { + "landcover": 1, + "system:index": "576" + }), + ee.Feature( + ee.Geometry.Point([-13.291286207203358, 9.319317683374159]), + { + "landcover": 1, + "system:index": "577" + }), + ee.Feature( + ee.Geometry.Point([-13.285106397633045, 9.305426964030449]), + { + "landcover": 1, + "system:index": "578" + }), + ee.Feature( + ee.Geometry.Point([-13.273433424000233, 9.314405175017802]), + { + "landcover": 1, + "system:index": "579" + }), + ee.Feature( + ee.Geometry.Point([-13.282703138355702, 9.318978891913023]), + { + "landcover": 1, + "system:index": "580" + }), + ee.Feature( + ee.Geometry.Point([-13.249572492603749, 9.311864195309921]), + { + "landcover": 1, + "system:index": "581" + }), + ee.Feature( + ee.Geometry.Point([-13.258842206959217, 9.304071742342185]), + { + "landcover": 1, + "system:index": "582" + }), + ee.Feature( + ee.Geometry.Point([-13.252662397388905, 9.30034485562317]), + { + "landcover": 1, + "system:index": "583" + }), + ee.Feature( + ee.Geometry.Point([-13.26004383659789, 9.293738004335609]), + { + "landcover": 1, + "system:index": "584" + }), + ee.Feature( + ee.Geometry.Point([-13.263477064136952, 9.289502777673848]), + { + "landcover": 1, + "system:index": "585" + }), + ee.Feature( + ee.Geometry.Point([-13.27377674675414, 9.29627911574363]), + { + "landcover": 1, + "system:index": "586" + }), + ee.Feature( + ee.Geometry.Point([-13.279784894947499, 9.270528333966]), + { + "landcover": 1, + "system:index": "587" + }), + ee.Feature( + ee.Geometry.Point([-13.25455067253539, 9.256466254018491]), + { + "landcover": 1, + "system:index": "588" + }), + ee.Feature( + ee.Geometry.Point([-13.21009037590453, 9.264937453931857]), + { + "landcover": 1, + "system:index": "589" + }), + ee.Feature( + ee.Geometry.Point([-13.205283857349842, 9.260532455463142]), + { + "landcover": 1, + "system:index": "590" + }), + ee.Feature( + ee.Geometry.Point([-13.24030277824828, 9.232915246293794]), + { + "landcover": 1, + "system:index": "591" + }), + ee.Feature( + ee.Geometry.Point([-13.259185529713124, 9.244097935622158]), + { + "landcover": 1, + "system:index": "592" + }), + ee.Feature( + ee.Geometry.Point([-13.262103773121327, 9.239692676146335]), + { + "landcover": 1, + "system:index": "593" + }), + ee.Feature( + ee.Geometry.Point([-13.27600834465453, 9.234101305928146]), + { + "landcover": 1, + "system:index": "594" + }), + ee.Feature( + ee.Geometry.Point([-13.29025623894164, 9.216648883114125]), + { + "landcover": 1, + "system:index": "595" + }), + ee.Feature( + ee.Geometry.Point([-13.29025623894164, 9.206820925471753]), + { + "landcover": 1, + "system:index": "596" + }), + ee.Feature( + ee.Geometry.Point([-13.294891096119374, 9.20224574851503]), + { + "landcover": 1, + "system:index": "597" + }), + ee.Feature( + ee.Geometry.Point([-13.305877424244374, 9.201398487027035]), + { + "landcover": 1, + "system:index": "598" + }), + ee.Feature( + ee.Geometry.Point([-13.22382328606078, 9.209871010547175]), + { + "landcover": 1, + "system:index": "599" + }), + ee.Feature( + ee.Geometry.Point([-13.192065931324452, 9.215632210520651]), + { + "landcover": 1, + "system:index": "600" + }), + ee.Feature( + ee.Geometry.Point([-13.190177656177967, 9.218851663690847]), + { + "landcover": 1, + "system:index": "601" + }), + ee.Feature( + ee.Geometry.Point([-13.187774396900624, 9.212751622278716]), + { + "landcover": 1, + "system:index": "602" + }), + ee.Feature( + ee.Geometry.Point([-13.206313825611561, 9.193095217068748]), + { + "landcover": 1, + "system:index": "603" + }), + ee.Feature( + ee.Geometry.Point([-13.19034931755492, 9.189536613174072]), + { + "landcover": 1, + "system:index": "604" + }), + ee.Feature( + ee.Geometry.Point([-13.19086430168578, 9.184622291871827]), + { + "landcover": 1, + "system:index": "605" + }), + ee.Feature( + ee.Geometry.Point([-13.18588612175414, 9.18394444910143]), + { + "landcover": 1, + "system:index": "606" + }), + ee.Feature( + ee.Geometry.Point([-13.22056171989867, 9.209701562066911]), + { + "landcover": 1, + "system:index": "607" + }), + ee.Feature( + ee.Geometry.Point([-13.237384534840077, 9.212921069296193]), + { + "landcover": 1, + "system:index": "608" + }), + ee.Feature( + ee.Geometry.Point([-13.248199201588124, 9.214276642509766]), + { + "landcover": 1, + "system:index": "609" + }), + ee.Feature( + ee.Geometry.Point([-13.283218122486561, 9.196484330379587]), + { + "landcover": 1, + "system:index": "610" + }), + ee.Feature( + ee.Geometry.Point([-13.279956556324452, 9.192925760551425]), + { + "landcover": 1, + "system:index": "611" + }), + ee.Feature( + ee.Geometry.Point([-13.289912916187733, 9.193264673504942]), + { + "landcover": 1, + "system:index": "612" + }), + ee.Feature( + ee.Geometry.Point([-13.295062757496327, 9.194620322074341]), + { + "landcover": 1, + "system:index": "613" + }), + ee.Feature( + ee.Geometry.Point([-13.281844831470936, 9.176149164076689]), + { + "landcover": 1, + "system:index": "614" + }), + ee.Feature( + ee.Geometry.Point([-13.282703138355702, 9.17309878850916]), + { + "landcover": 1, + "system:index": "615" + })]), + NonMangrove = + /* color: #b6c867 */ + /* shown: false */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([-13.640199652454818, 9.89526389438857]), + { + "landcover": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([-13.64088629796263, 9.8937419219008]), + { + "landcover": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([-13.637453070423568, 9.89526389438857]), + { + "landcover": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([-13.6336765201306, 9.895940324341653]), + { + "landcover": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([-13.631273260853256, 9.896109431612254]), + { + "landcover": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([-13.629556647083724, 9.894080138618607]), + { + "landcover": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([-13.628011694691146, 9.892558160646315]), + { + "landcover": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([-13.628011694691146, 9.890528845715746]), + { + "landcover": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([-13.6281833560681, 9.888161295791257]), + { + "landcover": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([-13.63539313390013, 9.882918803133371]), + { + "landcover": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([-13.6336765201306, 9.879198273770779]), + { + "landcover": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([-13.63264655186888, 9.877337993310382]), + { + "landcover": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([-13.629041662952865, 9.880043852321075]), + { + "landcover": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([-13.62543677403685, 9.883426144785675]), + { + "landcover": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([-13.631273260853256, 9.88934507288544]), + { + "landcover": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([-13.638483038685287, 9.887653961445755]), + { + "landcover": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([-13.638483038685287, 9.886301066029677]), + { + "landcover": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([-13.620458594105209, 9.883933485655257]), + { + "landcover": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([-13.620458594105209, 9.88122765863999]), + { + "landcover": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([-13.620286932728256, 9.878352693047196]), + { + "landcover": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([-13.618226996204818, 9.884779052031762]), + { + "landcover": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([-13.612390509388412, 9.881058543712408]), + { + "landcover": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([-13.609815588734115, 9.879198273770779]), + { + "landcover": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([-13.609472265980209, 9.882580574930365]), + { + "landcover": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([-13.614107123157943, 9.8912052854185]), + { + "landcover": 2, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([-13.594366064808334, 9.865499598598175]), + { + "landcover": 2, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([-13.596254339954818, 9.863639240739971]), + { + "landcover": 2, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([-13.593851080677474, 9.863300992728192]), + { + "landcover": 2, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([-13.592306128284896, 9.867359945951616]), + { + "landcover": 2, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([-13.595567694447006, 9.870742368765931]), + { + "landcover": 2, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([-13.59745596959349, 9.872433567144729]), + { + "landcover": 2, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([-13.59694098546263, 9.870911488994695]), + { + "landcover": 2, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([-13.487671836213329, 9.603185503942363]), + { + "landcover": 2, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([-13.488873465852, 9.602508479883612]), + { + "landcover": 2, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([-13.489045127228954, 9.599969627609893]), + { + "landcover": 2, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([-13.488701804475047, 9.597769273580928]), + { + "landcover": 2, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([-13.490075095490672, 9.591506649300088]), + { + "landcover": 2, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([-13.48389528592036, 9.598107790515527]), + { + "landcover": 2, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([-13.442353232697704, 9.603016248054569]), + { + "landcover": 2, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([-13.440808280305125, 9.604708803125543]), + { + "landcover": 2, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([-13.438233359650829, 9.60572433210698]), + { + "landcover": 2, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([-13.43445680935786, 9.602339223657433]), + { + "landcover": 2, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([-13.43720339138911, 9.600985170803016]), + { + "landcover": 2, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([-13.43668840725825, 9.59472260595197]), + { + "landcover": 2, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([-13.438405021027782, 9.592860740029861]), + { + "landcover": 2, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([-13.438748343781688, 9.590491077703861]), + { + "landcover": 2, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([-13.439606650666454, 9.589644765716853]), + { + "landcover": 2, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([-13.444069846467235, 9.581689329827402]), + { + "landcover": 2, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([-13.446301444367625, 9.58050446171579]), + { + "landcover": 2, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([-13.459862693146922, 9.594384085635884]), + { + "landcover": 2, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([-13.46243761380122, 9.59472260595197]), + { + "landcover": 2, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([-13.469132407502391, 9.611817442013729]), + { + "landcover": 2, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([-13.469475730256297, 9.615033205784563]), + { + "landcover": 2, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([-13.471364005402782, 9.61621795315115]), + { + "landcover": 2, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([-13.474282248810985, 9.61621795315115]), + { + "landcover": 2, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([-13.472222312287547, 9.611817442013729]), + { + "landcover": 2, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([-13.469304068879344, 9.609447912307623]), + { + "landcover": 2, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([-13.47016237576411, 9.620787654108952]), + { + "landcover": 2, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([-13.46964739163325, 9.624511068472138]), + { + "landcover": 2, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([-13.46964739163325, 9.626372760267671]), + { + "landcover": 2, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([-13.48938844998286, 9.624341823254763]), + { + "landcover": 2, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([-13.492478354768016, 9.624341823254763]), + { + "landcover": 2, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([-13.495568259553172, 9.62620351598291]), + { + "landcover": 2, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([-13.496083243684032, 9.630434597660521]), + { + "landcover": 2, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([-13.423127158478954, 9.615371705455658]), + { + "landcover": 2, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([-13.411797507600047, 9.610801931314386]), + { + "landcover": 2, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([-13.41248415310786, 9.606570603931203]), + { + "landcover": 2, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([-13.408879264191844, 9.615202455662457]), + { + "landcover": 2, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([-13.409050925568797, 9.621972381310744]), + { + "landcover": 2, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([-13.414887412385204, 9.625865027159046]), + { + "landcover": 2, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([-13.419693930939891, 9.63331170291934]), + { + "landcover": 2, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([-13.413685782746532, 9.634665626321135]), + { + "landcover": 2, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([-13.403557761506297, 9.632296256804214]), + { + "landcover": 2, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([-13.405446036652782, 9.63128080763471]), + { + "landcover": 2, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([-13.40750597317622, 9.634665626321135]), + { + "landcover": 2, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([-13.409565909699657, 9.636527262130242]), + { + "landcover": 2, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([-13.431023581818797, 9.63331170291934]), + { + "landcover": 2, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([-13.532562170556368, 9.62265315892689]), + { + "landcover": 2, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([-13.534278784325899, 9.62400712505879]), + { + "landcover": 2, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([-13.531875525048555, 9.626376552734179]), + { + "landcover": 2, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([-13.53050223403293, 9.628407477514115]), + { + "landcover": 2, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([-13.551101599267305, 9.632130807889933]), + { + "landcover": 2, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([-13.553504858544649, 9.628407477514115]), + { + "landcover": 2, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([-13.561057959130586, 9.635854097202463]), + { + "landcover": 2, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([-13.566894445946993, 9.630099905501739]), + { + "landcover": 2, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([-13.569641027978243, 9.627053529017628]), + { + "landcover": 2, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([-13.572387610009493, 9.624345615744067]), + { + "landcover": 2, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([-13.576164160302461, 9.6209606936336]), + { + "landcover": 2, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([-13.579597387841524, 9.617914234750414]), + { + "landcover": 2, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([-13.581314001611055, 9.614190747727863]), + { + "landcover": 2, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([-13.586463842919649, 9.611144227856878]), + { + "landcover": 2, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([-13.590583715966524, 9.608436187164969]), + { + "landcover": 2, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([-13.592643652489961, 9.60437408550142]), + { + "landcover": 2, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([-13.597793493798555, 9.600650449498545]), + { + "landcover": 2, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([-13.601570044091524, 9.595234178607734]), + { + "landcover": 2, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([-13.599510107568086, 9.587786664810263]), + { + "landcover": 2, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([-13.347854528954805, 9.631453841784552]), + { + "landcover": 2, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([-13.353347693017305, 9.629084449726962]), + { + "landcover": 2, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([-13.345451269677461, 9.657177598717503]), + { + "landcover": 2, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([-13.348541174462618, 9.663608231103328]), + { + "landcover": 2, + "system:index": "99" + }), + ee.Feature( + ee.Geometry.Point([-13.350257788232149, 9.672069402255028]), + { + "landcover": 2, + "system:index": "100" + }), + ee.Feature( + ee.Geometry.Point([-13.346137915185274, 9.67477693205716]), + { + "landcover": 2, + "system:index": "101" + }), + ee.Feature( + ee.Geometry.Point([-13.369140539696993, 9.638561918174645]), + { + "landcover": 2, + "system:index": "102" + }), + ee.Feature( + ee.Geometry.Point([-13.418922339013399, 9.682899390568524]), + { + "landcover": 2, + "system:index": "103" + }), + ee.Feature( + ee.Geometry.Point([-13.454284582665743, 9.670715629176321]), + { + "landcover": 2, + "system:index": "104" + }), + ee.Feature( + ee.Geometry.Point([-13.451538000634493, 9.678499749919098]), + { + "landcover": 2, + "system:index": "105" + }), + ee.Feature( + ee.Geometry.Point([-13.451538000634493, 9.682899390568524]), + { + "landcover": 2, + "system:index": "106" + }), + ee.Feature( + ee.Geometry.Point([-13.454284582665743, 9.683237822077341]), + { + "landcover": 2, + "system:index": "107" + }), + ee.Feature( + ee.Geometry.Point([-13.447418127587618, 9.679515056722407]), + { + "landcover": 2, + "system:index": "108" + }), + ee.Feature( + ee.Geometry.Point([-13.44535819106418, 9.672069402255028]), + { + "landcover": 2, + "system:index": "109" + }), + ee.Feature( + ee.Geometry.Point([-13.439178381493868, 9.643639023914613]), + { + "landcover": 2, + "system:index": "110" + }), + ee.Feature( + ee.Geometry.Point([-13.441924963525118, 9.641946663826616]), + { + "landcover": 2, + "system:index": "111" + }), + ee.Feature( + ee.Geometry.Point([-13.446388159325899, 9.643639023914613]), + { + "landcover": 2, + "system:index": "112" + }), + ee.Feature( + ee.Geometry.Point([-13.452224646142305, 9.637884964968881]), + { + "landcover": 2, + "system:index": "113" + }), + ee.Feature( + ee.Geometry.Point([-13.45909110122043, 9.642285136523668]), + { + "landcover": 2, + "system:index": "114" + }), + ee.Feature( + ee.Geometry.Point([-13.458747778466524, 9.634161698060968]), + { + "landcover": 2, + "system:index": "115" + }), + ee.Feature( + ee.Geometry.Point([-13.45909110122043, 9.626376552734179]), + { + "landcover": 2, + "system:index": "116" + }), + ee.Feature( + ee.Geometry.Point([-13.44535819106418, 9.628745963790163]), + { + "landcover": 2, + "system:index": "117" + }), + ee.Feature( + ee.Geometry.Point([-13.430938635400118, 9.610128715137005]), + { + "landcover": 2, + "system:index": "118" + }), + ee.Feature( + ee.Geometry.Point([-13.417549047997774, 9.599634905301931]), + { + "landcover": 2, + "system:index": "119" + }), + ee.Feature( + ee.Geometry.Point([-13.415489111474336, 9.591510442157333]), + { + "landcover": 2, + "system:index": "120" + }), + ee.Feature( + ee.Geometry.Point([-13.417549047997774, 9.59117191863368]), + { + "landcover": 2, + "system:index": "121" + }), + ee.Feature( + ee.Geometry.Point([-13.413429174950899, 9.583047252699105]), + { + "landcover": 2, + "system:index": "122" + }), + ee.Feature( + ee.Geometry.Point([-13.413085852196993, 9.580000452816348]), + { + "landcover": 2, + "system:index": "123" + }), + ee.Feature( + ee.Geometry.Point([-13.404502783349336, 9.582370188422113]), + { + "landcover": 2, + "system:index": "124" + }), + ee.Feature( + ee.Geometry.Point([-13.411025915673555, 9.604712595834995]), + { + "landcover": 2, + "system:index": "125" + }), + ee.Feature( + ee.Geometry.Point([-13.407249365380586, 9.601327477271484]), + { + "landcover": 2, + "system:index": "126" + }), + ee.Feature( + ee.Geometry.Point([-13.47831717543918, 9.686622118403308]), + { + "landcover": 2, + "system:index": "127" + }), + ee.Feature( + ee.Geometry.Point([-13.484153662255586, 9.683237822077341]), + { + "landcover": 2, + "system:index": "128" + }), + ee.Feature( + ee.Geometry.Point([-13.477630529931368, 9.681545661122474]), + { + "landcover": 2, + "system:index": "129" + }), + ee.Feature( + ee.Geometry.Point([-13.480033789208711, 9.676130688779114]), + { + "landcover": 2, + "system:index": "130" + }), + ee.Feature( + ee.Geometry.Point([-13.398322973779024, 9.663946682035794]), + { + "landcover": 2, + "system:index": "131" + }), + ee.Feature( + ee.Geometry.Point([-13.392829809716524, 9.664285132627802]), + { + "landcover": 2, + "system:index": "132" + }), + ee.Feature( + ee.Geometry.Point([-13.381843481591524, 9.664962032790449]), + { + "landcover": 2, + "system:index": "133" + }), + ee.Feature( + ee.Geometry.Point([-13.384246740868868, 9.663269779830442]), + { + "landcover": 2, + "system:index": "134" + }), + ee.Feature( + ee.Geometry.Point([-13.427333746484102, 9.621129940544316]), + { + "landcover": 2, + "system:index": "135" + }), + ee.Feature( + ee.Geometry.Point([-13.441581640771211, 9.628407477514115]), + { + "landcover": 2, + "system:index": "136" + }), + ee.Feature( + ee.Geometry.Point([-13.450679693749727, 9.623837879588994]), + { + "landcover": 2, + "system:index": "137" + }), + ee.Feature( + ee.Geometry.Point([-13.463382635644258, 9.619606715297124]), + { + "landcover": 2, + "system:index": "138" + }), + ee.Feature( + ee.Geometry.Point([-13.430423651269258, 9.625361085765237]), + { + "landcover": 2, + "system:index": "139" + }), + ee.Feature( + ee.Geometry.Point([-13.429908667138399, 9.631284600046119]), + { + "landcover": 2, + "system:index": "140" + }), + ee.Feature( + ee.Geometry.Point([-13.434028540185274, 9.634669418694504]), + { + "landcover": 2, + "system:index": "141" + }), + ee.Feature( + ee.Geometry.Point([-13.439006720116915, 9.629761420582756]), + { + "landcover": 2, + "system:index": "142" + }), + ee.Feature( + ee.Geometry.Point([-13.424587164452852, 9.626376552734179]), + { + "landcover": 2, + "system:index": "143" + }), + ee.Feature( + ee.Geometry.Point([-13.43437186293918, 9.622822404990066]), + { + "landcover": 2, + "system:index": "144" + }), + ee.Feature( + ee.Geometry.Point([-13.54200354628879, 9.771725920359758]), + { + "landcover": 2, + "system:index": "145" + }), + ee.Feature( + ee.Geometry.Point([-13.540115271142305, 9.772233432596723]), + { + "landcover": 2, + "system:index": "146" + }), + ee.Feature( + ee.Geometry.Point([-13.540801916650118, 9.770710893563262]), + { + "landcover": 2, + "system:index": "147" + }), + ee.Feature( + ee.Geometry.Point([-13.538055334618868, 9.772571773657894]), + { + "landcover": 2, + "system:index": "148" + }), + ee.Feature( + ee.Geometry.Point([-13.538055334618868, 9.77054172212945]), + { + "landcover": 2, + "system:index": "149" + }), + ee.Feature( + ee.Geometry.Point([-13.53822699599582, 9.768511658215099]), + { + "landcover": 2, + "system:index": "150" + }), + ee.Feature( + ee.Geometry.Point([-13.538570318749727, 9.76698910215254]), + { + "landcover": 2, + "system:index": "151" + }), + ee.Feature( + ee.Geometry.Point([-13.539600287011446, 9.765974060908194]), + { + "landcover": 2, + "system:index": "152" + }), + ee.Feature( + ee.Geometry.Point([-13.53822699599582, 9.765297365025766]), + { + "landcover": 2, + "system:index": "153" + }), + ee.Feature( + ee.Geometry.Point([-13.535308752587618, 9.770034207311948]), + { + "landcover": 2, + "system:index": "154" + }), + ee.Feature( + ee.Geometry.Point([-13.53376380019504, 9.772064261937096]), + { + "landcover": 2, + "system:index": "155" + }), + ee.Feature( + ee.Geometry.Point([-13.531703863671602, 9.77240260317031]), + { + "landcover": 2, + "system:index": "156" + }), + ee.Feature( + ee.Geometry.Point([-13.533420477441133, 9.771049236172841]), + { + "landcover": 2, + "system:index": "157" + }), + ee.Feature( + ee.Geometry.Point([-13.533420477441133, 9.769865035534101]), + { + "landcover": 2, + "system:index": "158" + }), + ee.Feature( + ee.Geometry.Point([-13.53548041396457, 9.768680830680962]), + { + "landcover": 2, + "system:index": "159" + }), + ee.Feature( + ee.Geometry.Point([-13.536167059472383, 9.76698910215254]), + { + "landcover": 2, + "system:index": "160" + }), + ee.Feature( + ee.Geometry.Point([-13.536853704980196, 9.765297365025766]), + { + "landcover": 2, + "system:index": "161" + }), + ee.Feature( + ee.Geometry.Point([-13.536853704980196, 9.763943969134523]), + { + "landcover": 2, + "system:index": "162" + }), + ee.Feature( + ee.Geometry.Point([-13.497199926904024, 9.76326726912586]), + { + "landcover": 2, + "system:index": "163" + }), + ee.Feature( + ee.Geometry.Point([-13.495654974511446, 9.764451493238456]), + { + "landcover": 2, + "system:index": "164" + }), + ee.Feature( + ee.Geometry.Point([-13.49702826552707, 9.763098093908816]), + { + "landcover": 2, + "system:index": "165" + }), + ee.Feature( + ee.Geometry.Point([-13.49754324965793, 9.76242139218114]), + { + "landcover": 2, + "system:index": "166" + }), + ee.Feature( + ee.Geometry.Point([-13.496341620019258, 9.76242139218114]), + { + "landcover": 2, + "system:index": "167" + }), + ee.Feature( + ee.Geometry.Point([-13.55745307021457, 9.72384712346435]), + { + "landcover": 2, + "system:index": "168" + }), + ee.Feature( + ee.Geometry.Point([-13.558139715722383, 9.722324363538974]), + { + "landcover": 2, + "system:index": "169" + }), + ee.Feature( + ee.Geometry.Point([-13.560542974999727, 9.721139989914178]), + { + "landcover": 2, + "system:index": "170" + }), + ee.Feature( + ee.Geometry.Point([-13.559856329491915, 9.718432834451587]), + { + "landcover": 2, + "system:index": "171" + }), + ee.Feature( + ee.Geometry.Point([-13.560886297753633, 9.717079248504964]), + { + "landcover": 2, + "system:index": "172" + }), + ee.Feature( + ee.Geometry.Point([-13.562087927392305, 9.719786414921563]), + { + "landcover": 2, + "system:index": "173" + }), + ee.Feature( + ee.Geometry.Point([-13.564319525292696, 9.720632399933873]), + { + "landcover": 2, + "system:index": "174" + }), + ee.Feature( + ee.Geometry.Point([-13.56346121840793, 9.71826363650775]), + { + "landcover": 2, + "system:index": "175" + }), + ee.Feature( + ee.Geometry.Point([-13.566379461816133, 9.72080159667957]), + { + "landcover": 2, + "system:index": "176" + }), + ee.Feature( + ee.Geometry.Point([-13.566036139062227, 9.717756042162808]), + { + "landcover": 2, + "system:index": "177" + }), + ee.Feature( + ee.Geometry.Point([-13.567237768700899, 9.718771230082542]), + { + "landcover": 2, + "system:index": "178" + }), + ee.Feature( + ee.Geometry.Point([-13.569641027978243, 9.722324363538974]), + { + "landcover": 2, + "system:index": "179" + }), + ee.Feature( + ee.Geometry.Point([-13.573245916894258, 9.724693098204092]), + { + "landcover": 2, + "system:index": "180" + }), + ee.Feature( + ee.Geometry.Point([-13.57170096450168, 9.72012480918325]), + { + "landcover": 2, + "system:index": "181" + }), + ee.Feature( + ee.Geometry.Point([-13.570156012109102, 9.717756042162808]), + { + "landcover": 2, + "system:index": "182" + }), + ee.Feature( + ee.Geometry.Point([-13.571357641747774, 9.716402453478146]), + { + "landcover": 2, + "system:index": "183" + }), + ee.Feature( + ee.Geometry.Point([-13.575134192040743, 9.719109625371203]), + { + "landcover": 2, + "system:index": "184" + }), + ee.Feature( + ee.Geometry.Point([-13.575305853417696, 9.72080159667957]), + { + "landcover": 2, + "system:index": "185" + }), + ee.Feature( + ee.Geometry.Point([-13.576507483056368, 9.717586843876692]), + { + "landcover": 2, + "system:index": "186" + }), + ee.Feature( + ee.Geometry.Point([-13.574619207909883, 9.71741764550502]), + { + "landcover": 2, + "system:index": "187" + }), + ee.Feature( + ee.Geometry.Point([-13.573245916894258, 9.71741764550502]), + { + "landcover": 2, + "system:index": "188" + }), + ee.Feature( + ee.Geometry.Point([-13.54372016005832, 9.70574275130077]), + { + "landcover": 2, + "system:index": "189" + }), + ee.Feature( + ee.Geometry.Point([-13.548183355859102, 9.703712293368184]), + { + "landcover": 2, + "system:index": "190" + }), + ee.Feature( + ee.Geometry.Point([-13.547840033105196, 9.70692717941152]), + { + "landcover": 2, + "system:index": "191" + }), + ee.Feature( + ee.Geometry.Point([-13.545780096581758, 9.708280806409537]), + { + "landcover": 2, + "system:index": "192" + }), + ee.Feature( + ee.Geometry.Point([-13.546295080712618, 9.703881498665897]), + { + "landcover": 2, + "system:index": "193" + }), + ee.Feature( + ee.Geometry.Point([-13.54200354628879, 9.70692717941152]), + { + "landcover": 2, + "system:index": "194" + }), + ee.Feature( + ee.Geometry.Point([-13.54200354628879, 9.710311236647977]), + { + "landcover": 2, + "system:index": "195" + }), + ee.Feature( + ee.Geometry.Point([-13.54200354628879, 9.712172453550373]), + { + "landcover": 2, + "system:index": "196" + }), + ee.Feature( + ee.Geometry.Point([-13.540801916650118, 9.715048859317944]), + { + "landcover": 2, + "system:index": "197" + }), + ee.Feature( + ee.Geometry.Point([-13.53822699599582, 9.715218058887388]), + { + "landcover": 2, + "system:index": "198" + }), + ee.Feature( + ee.Geometry.Point([-13.537197027734102, 9.717586843876692]), + { + "landcover": 2, + "system:index": "199" + }), + ee.Feature( + ee.Geometry.Point([-13.535308752587618, 9.715048859317944]), + { + "landcover": 2, + "system:index": "200" + }), + ee.Feature( + ee.Geometry.Point([-13.535823736718477, 9.711834051246822]), + { + "landcover": 2, + "system:index": "201" + }), + ee.Feature( + ee.Geometry.Point([-13.538570318749727, 9.713864459936698]), + { + "landcover": 2, + "system:index": "202" + }), + ee.Feature( + ee.Geometry.Point([-13.53651038222629, 9.710142034598336]), + { + "landcover": 2, + "system:index": "203" + }), + ee.Feature( + ee.Geometry.Point([-13.540630255273165, 9.707434790176865]), + { + "landcover": 2, + "system:index": "204" + }), + ee.Feature( + ee.Geometry.Point([-13.531188879540743, 9.717586843876692]), + { + "landcover": 2, + "system:index": "205" + }), + ee.Feature( + ee.Geometry.Point([-13.530330572655977, 9.72130918640309]), + { + "landcover": 2, + "system:index": "206" + }), + ee.Feature( + ee.Geometry.Point([-13.529815588525118, 9.723001146584146]), + { + "landcover": 2, + "system:index": "207" + }), + ee.Feature( + ee.Geometry.Point([-13.527583990624727, 9.724693098204092]), + { + "landcover": 2, + "system:index": "208" + }), + ee.Feature( + ee.Geometry.Point([-13.526725683739961, 9.725200682020445]), + { + "landcover": 2, + "system:index": "209" + }), + ee.Feature( + ee.Geometry.Point([-13.526554022363008, 9.722324363538974]), + { + "landcover": 2, + "system:index": "210" + }), + ee.Feature( + ee.Geometry.Point([-13.528098974755586, 9.721647579124117]), + { + "landcover": 2, + "system:index": "211" + }), + ee.Feature( + ee.Geometry.Point([-13.526897345116915, 9.720970793339673]), + { + "landcover": 2, + "system:index": "212" + }), + ee.Feature( + ee.Geometry.Point([-13.52174750380832, 9.726046653335084]), + { + "landcover": 2, + "system:index": "213" + }), + ee.Feature( + ee.Geometry.Point([-13.52277747207004, 9.727738589541413]), + { + "landcover": 2, + "system:index": "214" + }), + ee.Feature( + ee.Geometry.Point([-13.52277747207004, 9.730276477790866]), + { + "landcover": 2, + "system:index": "215" + }), + ee.Feature( + ee.Geometry.Point([-13.521404181054415, 9.732137583589529]), + { + "landcover": 2, + "system:index": "216" + }), + ee.Feature( + ee.Geometry.Point([-13.517970953515352, 9.733321918244974]), + { + "landcover": 2, + "system:index": "217" + }), + ee.Feature( + ee.Geometry.Point([-13.517970953515352, 9.731799201488183]), + { + "landcover": 2, + "system:index": "218" + }), + ee.Feature( + ee.Geometry.Point([-13.519859228661836, 9.732137583589529]), + { + "landcover": 2, + "system:index": "219" + }), + ee.Feature( + ee.Geometry.Point([-13.50852957778293, 9.740766211334252]), + { + "landcover": 2, + "system:index": "220" + }), + ee.Feature( + ee.Geometry.Point([-13.509731207421602, 9.737213273972818]), + { + "landcover": 2, + "system:index": "221" + }), + ee.Feature( + ee.Geometry.Point([-13.510246191552461, 9.736198142067588]), + { + "landcover": 2, + "system:index": "222" + }), + ee.Feature( + ee.Geometry.Point([-13.511447821191133, 9.737720838768078]), + { + "landcover": 2, + "system:index": "223" + }), + ee.Feature( + ee.Geometry.Point([-13.51453772597629, 9.737720838768078]), + { + "landcover": 2, + "system:index": "224" + }), + ee.Feature( + ee.Geometry.Point([-13.51076117568332, 9.741950515384083]), + { + "landcover": 2, + "system:index": "225" + }), + ee.Feature( + ee.Geometry.Point([-13.50028983168918, 9.754808403012264]), + { + "landcover": 2, + "system:index": "226" + }), + ee.Feature( + ee.Geometry.Point([-13.497714911034883, 9.756500193416775]), + { + "landcover": 2, + "system:index": "227" + }), + ee.Feature( + ee.Geometry.Point([-13.495483313134493, 9.758530330563973]), + { + "landcover": 2, + "system:index": "228" + }), + ee.Feature( + ee.Geometry.Point([-13.501148138573946, 9.752947423648195]), + { + "landcover": 2, + "system:index": "229" + }), + ee.Feature( + ee.Geometry.Point([-13.501834784081758, 9.749563798187735]), + { + "landcover": 2, + "system:index": "230" + }), + ee.Feature( + ee.Geometry.Point([-13.507842932275118, 9.74770278954872]), + { + "landcover": 2, + "system:index": "231" + }), + ee.Feature( + ee.Geometry.Point([-13.509216223290743, 9.749056251407033]), + { + "landcover": 2, + "system:index": "232" + }), + ee.Feature( + ee.Geometry.Point([-13.510417852929415, 9.747533606430212]), + { + "landcover": 2, + "system:index": "233" + }), + ee.Feature( + ee.Geometry.Point([-13.508872900536836, 9.747364423225903]), + { + "landcover": 2, + "system:index": "234" + }), + ee.Feature( + ee.Geometry.Point([-13.661651526025118, 10.022341913400517]), + { + "landcover": 2, + "system:index": "235" + }), + ee.Feature( + ee.Geometry.Point([-13.660964880517305, 10.028765438852059]), + { + "landcover": 2, + "system:index": "236" + }), + ee.Feature( + ee.Geometry.Point([-13.661308203271211, 10.020989576032427]), + { + "landcover": 2, + "system:index": "237" + }), + ee.Feature( + ee.Geometry.Point([-13.658561621239961, 10.020989576032427]), + { + "landcover": 2, + "system:index": "238" + }), + ee.Feature( + ee.Geometry.Point([-13.655471716454805, 10.024370408875624]), + { + "landcover": 2, + "system:index": "239" + }), + ee.Feature( + ee.Geometry.Point([-13.652038488915743, 10.024370408875624]), + { + "landcover": 2, + "system:index": "240" + }), + ee.Feature( + ee.Geometry.Point([-13.655471716454805, 10.020989576032427]), + { + "landcover": 2, + "system:index": "241" + }), + ee.Feature( + ee.Geometry.Point([-13.652725134423555, 10.018284884376252]), + { + "landcover": 2, + "system:index": "242" + }), + ee.Feature( + ee.Geometry.Point([-13.658904943993868, 10.012537339724123]), + { + "landcover": 2, + "system:index": "243" + }), + ee.Feature( + ee.Geometry.Point([-13.655471716454805, 10.009156383550605]), + { + "landcover": 2, + "system:index": "244" + }), + ee.Feature( + ee.Geometry.Point([-13.658218298486055, 10.00780399122132]), + { + "landcover": 2, + "system:index": "245" + }), + ee.Feature( + ee.Geometry.Point([-13.654441748193086, 10.005775392165521]), + { + "landcover": 2, + "system:index": "246" + }), + ee.Feature( + ee.Geometry.Point([-13.656501684716524, 10.003408677251185]), + { + "landcover": 2, + "system:index": "247" + }), + ee.Feature( + ee.Geometry.Point([-13.65409842543918, 10.00239436558026]), + { + "landcover": 2, + "system:index": "248" + }), + ee.Feature( + ee.Geometry.Point([-13.657874975732149, 10.000365732737786]), + { + "landcover": 2, + "system:index": "249" + }), + ee.Feature( + ee.Geometry.Point([-13.655471716454805, 9.999689518975616]), + { + "landcover": 2, + "system:index": "250" + }), + ee.Feature( + ee.Geometry.Point([-13.645515356591524, 10.003070573712783]), + { + "landcover": 2, + "system:index": "251" + }), + ee.Feature( + ee.Geometry.Point([-13.645172033837618, 10.000703839091145]), + { + "landcover": 2, + "system:index": "252" + }), + ee.Feature( + ee.Geometry.Point([-13.643798742821993, 9.999689518975616]), + { + "landcover": 2, + "system:index": "253" + }), + ee.Feature( + ee.Geometry.Point([-13.668517981103243, 9.988193669793844]), + { + "landcover": 2, + "system:index": "254" + }), + ee.Feature( + ee.Geometry.Point([-13.669204626611055, 9.984136214247286]), + { + "landcover": 2, + "system:index": "255" + }), + ee.Feature( + ee.Geometry.Point([-13.669204626611055, 9.981093089391116]), + { + "landcover": 2, + "system:index": "256" + }), + ee.Feature( + ee.Geometry.Point([-13.669204626611055, 9.976697414383944]), + { + "landcover": 2, + "system:index": "257" + }), + ee.Feature( + ee.Geometry.Point([-13.666458044579805, 9.974330487883972]), + { + "landcover": 2, + "system:index": "258" + }), + ee.Feature( + ee.Geometry.Point([-13.66508475356418, 9.973316085548204]), + { + "landcover": 2, + "system:index": "259" + }), + ee.Feature( + ee.Geometry.Point([-13.666458044579805, 9.969596583299666]), + { + "landcover": 2, + "system:index": "260" + }), + ee.Feature( + ee.Geometry.Point([-13.669204626611055, 9.966553322616255]), + { + "landcover": 2, + "system:index": "261" + }), + ee.Feature( + ee.Geometry.Point([-13.671951208642305, 9.962833743207232]), + { + "landcover": 2, + "system:index": "262" + }), + ee.Feature( + ee.Geometry.Point([-13.676757727196993, 9.961143011271028]), + { + "landcover": 2, + "system:index": "263" + }), + ee.Feature( + ee.Geometry.Point([-13.681907568505586, 9.960128567903281]), + { + "landcover": 2, + "system:index": "264" + }), + ee.Feature( + ee.Geometry.Point([-13.68431082778293, 9.956408915238322]), + { + "landcover": 2, + "system:index": "265" + }), + ee.Feature( + ee.Geometry.Point([-13.683624182275118, 9.952689220182753]), + { + "landcover": 2, + "system:index": "266" + }), + ee.Feature( + ee.Geometry.Point([-13.682937536767305, 9.949307642450698]), + { + "landcover": 2, + "system:index": "267" + }), + ee.Feature( + ee.Geometry.Point([-13.676414404443086, 9.958099671705611]), + { + "landcover": 2, + "system:index": "268" + }), + ee.Feature( + ee.Geometry.Point([-13.671951208642305, 9.960128567903281]), + { + "landcover": 2, + "system:index": "269" + }), + ee.Feature( + ee.Geometry.Point([-13.668174658349336, 9.96046671604301]), + { + "landcover": 2, + "system:index": "270" + }), + ee.Feature( + ee.Geometry.Point([-13.667584617106092, 9.953089708729708]), + { + "landcover": 2, + "system:index": "271" + }), + ee.Feature( + ee.Geometry.Point([-13.667241294352186, 9.951145308196883]), + { + "landcover": 2, + "system:index": "272" + }), + ee.Feature( + ee.Geometry.Point([-13.667241294352186, 9.950215373414666]), + { + "landcover": 2, + "system:index": "273" + }), + ee.Feature( + ee.Geometry.Point([-13.666468818155897, 9.945734741445749]), + { + "landcover": 2, + "system:index": "274" + }), + ee.Feature( + ee.Geometry.Point([-13.666726310221327, 9.944551168024388]), + { + "landcover": 2, + "system:index": "275" + }), + ee.Feature( + ee.Geometry.Point([-13.666726310221327, 9.942691258273008]), + { + "landcover": 2, + "system:index": "276" + }), + ee.Feature( + ee.Geometry.Point([-13.665696341959608, 9.940746795853128]), + { + "landcover": 2, + "system:index": "277" + }), + ee.Feature( + ee.Geometry.Point([-13.664580543009412, 9.938633236626876]), + { + "landcover": 2, + "system:index": "278" + }), + ee.Feature( + ee.Geometry.Point([-13.662434775797498, 9.938633236626876]), + { + "landcover": 2, + "system:index": "279" + }), + ee.Feature( + ee.Geometry.Point([-13.661748130289686, 9.93990137380219]), + { + "landcover": 2, + "system:index": "280" + }), + ee.Feature( + ee.Geometry.Point([-13.662692267862928, 9.942860341415056]), + { + "landcover": 2, + "system:index": "281" + }), + ee.Feature( + ee.Geometry.Point([-13.66440888163246, 9.944466626901695]), + { + "landcover": 2, + "system:index": "282" + }), + ee.Feature( + ee.Geometry.Point([-13.664494712320936, 9.946326526548747]), + { + "landcover": 2, + "system:index": "283" + }), + ee.Feature( + ee.Geometry.Point([-13.6638938975016, 9.947848254748799]), + { + "landcover": 2, + "system:index": "284" + }), + ee.Feature( + ee.Geometry.Point([-13.662434775797498, 9.947763714479182]), + { + "landcover": 2, + "system:index": "285" + }), + ee.Feature( + ee.Geometry.Point([-13.661919791666639, 9.946411067190247]), + { + "landcover": 2, + "system:index": "286" + }), + ee.Feature( + ee.Geometry.Point([-13.66088982340492, 9.944889332296516]), + { + "landcover": 2, + "system:index": "287" + }), + ee.Feature( + ee.Geometry.Point([-13.66088982340492, 9.942860341415056]), + { + "landcover": 2, + "system:index": "288" + }), + ee.Feature( + ee.Geometry.Point([-13.659945685831678, 9.947256472402119]), + { + "landcover": 2, + "system:index": "289" + }), + ee.Feature( + ee.Geometry.Point([-13.659173209635389, 9.94962359535643]), + { + "landcover": 2, + "system:index": "290" + }), + ee.Feature( + ee.Geometry.Point([-13.6584007334391, 9.95199070115553]), + { + "landcover": 2, + "system:index": "291" + }), + ee.Feature( + ee.Geometry.Point([-13.657542426554334, 9.950722610896857]), + { + "landcover": 2, + "system:index": "292" + }), + ee.Feature( + ee.Geometry.Point([-13.653680045572889, 9.949454515714292]), + { + "landcover": 2, + "system:index": "293" + }), + ee.Feature( + ee.Geometry.Point([-13.653250892130506, 9.950553531823656]), + { + "landcover": 2, + "system:index": "294" + }), + ee.Feature( + ee.Geometry.Point([-13.657027442423475, 9.95833107856939]), + { + "landcover": 2, + "system:index": "295" + }), + ee.Feature( + ee.Geometry.Point([-13.658057410685194, 9.960867195046598]), + { + "landcover": 2, + "system:index": "296" + }), + ee.Feature( + ee.Geometry.Point([-13.658572394816053, 9.96272700126694]), + { + "landcover": 2, + "system:index": "297" + }), + ee.Feature( + ee.Geometry.Point([-13.659001548258436, 9.965263083568694]), + { + "landcover": 2, + "system:index": "298" + }), + ee.Feature( + ee.Geometry.Point([-13.659173209635389, 9.966953794146162]), + { + "landcover": 2, + "system:index": "299" + }), + ee.Feature( + ee.Geometry.Point([-13.660117347208631, 9.96500947622598]), + { + "landcover": 2, + "system:index": "300" + }), + ee.Feature( + ee.Geometry.Point([-13.660203177897108, 9.963403291808957]), + { + "landcover": 2, + "system:index": "301" + }), + ee.Feature( + ee.Geometry.Point([-13.661061484781873, 9.961036268777496]), + { + "landcover": 2, + "system:index": "302" + }), + ee.Feature( + ee.Geometry.Point([-13.661061484781873, 9.959937287960484]), + { + "landcover": 2, + "system:index": "303" + }), + ee.Feature( + ee.Geometry.Point([-13.661748130289686, 9.958246541014008]), + { + "landcover": 2, + "system:index": "304" + }), + ee.Feature( + ee.Geometry.Point([-13.660289008585584, 9.959260990233174]), + { + "landcover": 2, + "system:index": "305" + }), + ee.Feature( + ee.Geometry.Point([-13.659602363077772, 9.96230431896613]), + { + "landcover": 2, + "system:index": "306" + }), + ee.Feature( + ee.Geometry.Point([-13.663293082682264, 9.966192975471168]), + { + "landcover": 2, + "system:index": "307" + }), + ee.Feature( + ee.Geometry.Point([-13.663550574747694, 9.964755868686034]), + { + "landcover": 2, + "system:index": "308" + }), + ee.Feature( + ee.Geometry.Point([-13.66440888163246, 9.963656900400698]), + { + "landcover": 2, + "system:index": "309" + }), + ee.Feature( + ee.Geometry.Point([-13.665181357828748, 9.962135245892433]), + { + "landcover": 2, + "system:index": "310" + }), + ee.Feature( + ee.Geometry.Point([-13.666039664713514, 9.960613584285971]), + { + "landcover": 2, + "system:index": "311" + }), + ee.Feature( + ee.Geometry.Point([-13.660718162027967, 9.973970149337196]), + { + "landcover": 2, + "system:index": "312" + }), + ee.Feature( + ee.Geometry.Point([-13.660289008585584, 9.972110407252433]), + { + "landcover": 2, + "system:index": "313" + }), + ee.Feature( + ee.Geometry.Point([-13.659516532389295, 9.970842395200114]), + { + "landcover": 2, + "system:index": "314" + }), + ee.Feature( + ee.Geometry.Point([-13.658057410685194, 9.969658912833557]), + { + "landcover": 2, + "system:index": "315" + }), + ee.Feature( + ee.Geometry.Point([-13.655825812784803, 9.968475426169892]), + { + "landcover": 2, + "system:index": "316" + }), + ee.Feature( + ee.Geometry.Point([-13.655482490030897, 9.96982798200615]), + { + "landcover": 2, + "system:index": "317" + }), + ee.Feature( + ee.Geometry.Point([-13.653851706949842, 9.972448542966447]), + { + "landcover": 2, + "system:index": "318" + }), + ee.Feature( + ee.Geometry.Point([-13.653079230753553, 9.973801082313564]), + { + "landcover": 2, + "system:index": "319" + }), + ee.Feature( + ee.Geometry.Point([-13.649560172526014, 9.973209347040036]), + { + "landcover": 2, + "system:index": "320" + }), + ee.Feature( + ee.Geometry.Point([-13.649731833902967, 9.971434134771844]), + { + "landcover": 2, + "system:index": "321" + }), + ee.Feature( + ee.Geometry.Point([-13.649216849772108, 9.970081585600642]), + { + "landcover": 2, + "system:index": "322" + }), + ee.Feature( + ee.Geometry.Point([-13.647843558756483, 9.968559961074066]), + { + "landcover": 2, + "system:index": "323" + }), + ee.Feature( + ee.Geometry.Point([-13.645783622233045, 9.967122864721723]), + { + "landcover": 2, + "system:index": "324" + }), + ee.Feature( + ee.Geometry.Point([-13.643466193644178, 9.965516690714173]), + { + "landcover": 2, + "system:index": "325" + }), + ee.Feature( + ee.Geometry.Point([-13.638058860270155, 9.969320774225237]), + { + "landcover": 2, + "system:index": "326" + }), + ee.Feature( + ee.Geometry.Point([-13.635226447550428, 9.969405308910208]), + { + "landcover": 2, + "system:index": "327" + }), + ee.Feature( + ee.Geometry.Point([-13.634110648600233, 9.970673326553726]), + { + "landcover": 2, + "system:index": "328" + }), + ee.Feature( + ee.Geometry.Point([-13.631106574503553, 9.969912516559571]), + { + "landcover": 2, + "system:index": "329" + }), + ee.Feature( + ee.Geometry.Point([-13.629990775553358, 9.967122864721723]), + { + "landcover": 2, + "system:index": "330" + }), + ee.Feature( + ee.Geometry.Point([-13.63891716715492, 9.973547481613643]), + { + "landcover": 2, + "system:index": "331" + }), + ee.Feature( + ee.Geometry.Point([-13.642522056070936, 9.972617610691863]), + { + "landcover": 2, + "system:index": "332" + }), + ee.Feature( + ee.Geometry.Point([-13.645783622233045, 9.97498454963648]), + { + "landcover": 2, + "system:index": "333" + }), + ee.Feature( + ee.Geometry.Point([-13.643981177775037, 9.977351471383914]), + { + "landcover": 2, + "system:index": "334" + }), + ee.Feature( + ee.Geometry.Point([-13.643981177775037, 9.979380247762634]), + { + "landcover": 2, + "system:index": "335" + }), + ee.Feature( + ee.Geometry.Point([-13.644753653971327, 9.980310099378729]), + { + "landcover": 2, + "system:index": "336" + }), + ee.Feature( + ee.Geometry.Point([-13.648272712198866, 9.979887439882406]), + { + "landcover": 2, + "system:index": "337" + }), + ee.Feature( + ee.Geometry.Point([-13.650075156656873, 9.982000731877168]), + { + "landcover": 2, + "system:index": "338" + }), + ee.Feature( + ee.Geometry.Point([-13.65067597147621, 9.979549311890345]), + { + "landcover": 2, + "system:index": "339" + }), + ee.Feature( + ee.Geometry.Point([-13.649302680460584, 9.977266938760529]), + { + "landcover": 2, + "system:index": "340" + }), + ee.Feature( + ee.Geometry.Point([-13.641062934366834, 9.979887439882406]), + { + "landcover": 2, + "system:index": "341" + }), + ee.Feature( + ee.Geometry.Point([-13.640462119547498, 9.982761513637067]), + { + "landcover": 2, + "system:index": "342" + }), + ee.Feature( + ee.Geometry.Point([-13.638144690958631, 9.979718375930274]), + { + "landcover": 2, + "system:index": "343" + }), + ee.Feature( + ee.Geometry.Point([-13.634797294108045, 9.975829880806362]), + { + "landcover": 2, + "system:index": "344" + }), + ee.Feature( + ee.Geometry.Point([-13.646212775675428, 9.98783334659046]), + { + "landcover": 2, + "system:index": "345" + }), + ee.Feature( + ee.Geometry.Point([-13.646212775675428, 9.99020017491354]), + { + "landcover": 2, + "system:index": "346" + }), + ee.Feature( + ee.Geometry.Point([-13.648530204264295, 9.991045466569636]), + { + "landcover": 2, + "system:index": "347" + }), + ee.Feature( + ee.Geometry.Point([-13.651105124918592, 9.992482457343009]), + { + "landcover": 2, + "system:index": "348" + }), + ee.Feature( + ee.Geometry.Point([-13.64715691324867, 9.994173026593714]), + { + "landcover": 2, + "system:index": "349" + }), + ee.Feature( + ee.Geometry.Point([-13.643466193644178, 9.99518736392491]), + { + "landcover": 2, + "system:index": "350" + }), + ee.Feature( + ee.Geometry.Point([-13.642607886759412, 9.98741069686363]), + { + "landcover": 2, + "system:index": "351" + }), + ee.Feature( + ee.Geometry.Point([-13.646727759806287, 9.986480865532018]), + { + "landcover": 2, + "system:index": "352" + }), + ee.Feature( + ee.Geometry.Point([-13.64964600321449, 9.99036923342051]), + { + "landcover": 2, + "system:index": "353" + }), + ee.Feature( + ee.Geometry.Point([-13.657370765177381, 9.981916200460754]), + { + "landcover": 2, + "system:index": "354" + }), + ee.Feature( + ee.Geometry.Point([-13.654624183146131, 9.980732758326381]), + { + "landcover": 2, + "system:index": "355" + }), + ee.Feature( + ee.Geometry.Point([-13.652821738688123, 9.979295715665872]), + { + "landcover": 2, + "system:index": "356" + }), + ee.Feature( + ee.Geometry.Point([-13.653250892130506, 9.984283071822539]), + { + "landcover": 2, + "system:index": "357" + }), + ee.Feature( + ee.Geometry.Point([-13.648186881510389, 9.975153616045933]), + { + "landcover": 2, + "system:index": "358" + }), + ee.Feature( + ee.Geometry.Point([-13.646384437052381, 9.973124813341814]), + { + "landcover": 2, + "system:index": "359" + }), + ee.Feature( + ee.Geometry.Point([-13.643380362955702, 9.97278667832957]), + { + "landcover": 2, + "system:index": "360" + }), + ee.Feature( + ee.Geometry.Point([-13.641320426432264, 9.970081585600642]), + { + "landcover": 2, + "system:index": "361" + }), + ee.Feature( + ee.Geometry.Point([-13.639775474039686, 9.973040279621646]), + { + "landcover": 2, + "system:index": "362" + }), + ee.Feature( + ee.Geometry.Point([-13.640290458170545, 9.976421611320037]), + { + "landcover": 2, + "system:index": "363" + }), + ee.Feature( + ee.Geometry.Point([-13.640118796793592, 9.977943199133255]), + { + "landcover": 2, + "system:index": "364" + }), + ee.Feature( + ee.Geometry.Point([-13.637114722696912, 9.976337078455325]), + { + "landcover": 2, + "system:index": "365" + }), + ee.Feature( + ee.Geometry.Point([-13.636256415812147, 9.974477349881646]), + { + "landcover": 2, + "system:index": "366" + }), + ee.Feature( + ee.Geometry.Point([-13.63617058512367, 9.973378414370707]), + { + "landcover": 2, + "system:index": "367" + }), + ee.Feature( + ee.Geometry.Point([-13.6364280771891, 9.971856805236678]), + { + "landcover": 2, + "system:index": "368" + }), + ee.Feature( + ee.Geometry.Point([-13.636256415812147, 9.969658912833557]), + { + "landcover": 2, + "system:index": "369" + }), + ee.Feature( + ee.Geometry.Point([-13.636256415812147, 9.9673764704207]), + { + "landcover": 2, + "system:index": "370" + }), + ee.Feature( + ee.Geometry.Point([-13.634453971354139, 9.968306356295757]), + { + "landcover": 2, + "system:index": "371" + }), + ee.Feature( + ee.Geometry.Point([-13.631879050699842, 9.968052751320142]), + { + "landcover": 2, + "system:index": "372" + }), + ee.Feature( + ee.Geometry.Point([-13.631020743815077, 9.966784723482908]), + { + "landcover": 2, + "system:index": "373" + }), + ee.Feature( + ee.Geometry.Point([-13.629132468668592, 9.96500947622598]), + { + "landcover": 2, + "system:index": "374" + }), + ee.Feature( + ee.Geometry.Point([-13.627244193522108, 9.962642464850603]), + { + "landcover": 2, + "system:index": "375" + }), + ee.Feature( + ee.Geometry.Point([-13.626385886637342, 9.960698121228079]), + { + "landcover": 2, + "system:index": "376" + }), + ee.Feature( + ee.Geometry.Point([-13.624411780802381, 9.958415616102878]), + { + "landcover": 2, + "system:index": "377" + }), + ee.Feature( + ee.Geometry.Point([-13.624240119425428, 9.961036268777496]), + { + "landcover": 2, + "system:index": "378" + }), + ee.Feature( + ee.Geometry.Point([-13.625270087687147, 9.962811537661368]), + { + "landcover": 2, + "system:index": "379" + }), + ee.Feature( + ee.Geometry.Point([-13.627587516276014, 9.966869258825502]), + { + "landcover": 2, + "system:index": "380" + }), + ee.Feature( + ee.Geometry.Point([-13.626643378702772, 9.966108439953251]), + { + "landcover": 2, + "system:index": "381" + }), + ee.Feature( + ee.Geometry.Point([-13.624583442179334, 9.965770297662408]), + { + "landcover": 2, + "system:index": "382" + }), + ee.Feature( + ee.Geometry.Point([-13.62321015116371, 9.964671332795572]), + { + "landcover": 2, + "system:index": "383" + }), + ee.Feature( + ee.Geometry.Point([-13.621751029459608, 9.9651785478097]), + { + "landcover": 2, + "system:index": "384" + }), + ee.Feature( + ee.Geometry.Point([-13.618575293985975, 9.965770297662408]), + { + "landcover": 2, + "system:index": "385" + }), + ee.Feature( + ee.Geometry.Point([-13.619776923624647, 9.9650940120288]), + { + "landcover": 2, + "system:index": "386" + }), + ee.Feature( + ee.Geometry.Point([-13.62818833109535, 9.97134960061309]), + { + "landcover": 2, + "system:index": "387" + }), + ee.Feature( + ee.Geometry.Point([-13.628359992472303, 9.96957437821436]), + { + "landcover": 2, + "system:index": "388" + }), + ee.Feature( + ee.Geometry.Point([-13.633252341715467, 9.975407215495617]), + { + "landcover": 2, + "system:index": "389" + }), + ee.Feature( + ee.Geometry.Point([-13.63316651102699, 9.973378414370707]), + { + "landcover": 2, + "system:index": "390" + }), + ee.Feature( + ee.Geometry.Point([-13.631621558634412, 9.976844275314518]), + { + "landcover": 2, + "system:index": "391" + }), + ee.Feature( + ee.Geometry.Point([-13.637887198893202, 9.984283071822539]), + { + "landcover": 2, + "system:index": "392" + }), + ee.Feature( + ee.Geometry.Point([-13.6364280771891, 9.986058214048352]), + { + "landcover": 2, + "system:index": "393" + }), + ee.Feature( + ee.Geometry.Point([-13.637715537516248, 9.98369135559561]), + { + "landcover": 2, + "system:index": "394" + }), + ee.Feature( + ee.Geometry.Point([-13.640719611612928, 9.98250791991466]), + { + "landcover": 2, + "system:index": "395" + }), + ee.Feature( + ee.Geometry.Point([-13.642007071940077, 9.982846044833973]), + { + "landcover": 2, + "system:index": "396" + }), + ee.Feature( + ee.Geometry.Point([-13.642779548136366, 9.98090182175181]), + { + "landcover": 2, + "system:index": "397" + }), + ee.Feature( + ee.Geometry.Point([-13.659945685831678, 9.970250654554006]), + { + "landcover": 2, + "system:index": "398" + }), + ee.Feature( + ee.Geometry.Point([-13.66415138956703, 9.970504257819616]), + { + "landcover": 2, + "system:index": "399" + }), + ee.Feature( + ee.Geometry.Point([-13.665782172648084, 9.967630075922393]), + { + "landcover": 2, + "system:index": "400" + }), + ee.Feature( + ee.Geometry.Point([-13.667756278483045, 9.96923623951836]), + { + "landcover": 2, + "system:index": "401" + }), + ee.Feature( + ee.Geometry.Point([-13.66887207743324, 9.97253307684012]), + { + "landcover": 2, + "system:index": "402" + }), + ee.Feature( + ee.Geometry.Point([-13.679171760050428, 9.97718240611521]), + { + "landcover": 2, + "system:index": "403" + }), + ee.Feature( + ee.Geometry.Point([-13.683978278605116, 9.976506144162817]), + { + "landcover": 2, + "system:index": "404" + }), + ee.Feature( + ee.Geometry.Point([-13.685179908243787, 9.973970149337196]), + { + "landcover": 2, + "system:index": "405" + }), + ee.Feature( + ee.Geometry.Point([-13.688527305094373, 9.97523814921776]), + { + "landcover": 2, + "system:index": "406" + }), + ee.Feature( + ee.Geometry.Point([-13.692303855387342, 9.97413921627307]), + { + "landcover": 2, + "system:index": "407" + }), + ee.Feature( + ee.Geometry.Point([-13.691531379191053, 9.971603203023564]), + { + "landcover": 2, + "system:index": "408" + }), + ee.Feature( + ee.Geometry.Point([-13.689385611979139, 9.970250654554006]), + { + "landcover": 2, + "system:index": "409" + }), + ee.Feature( + ee.Geometry.Point([-13.686209876505506, 9.970081585600642]), + { + "landcover": 2, + "system:index": "410" + }), + ee.Feature( + ee.Geometry.Point([-13.687668998209608, 9.969151704789562]), + { + "landcover": 2, + "system:index": "411" + }), + ee.Feature( + ee.Geometry.Point([-13.688441474405897, 9.96813728633393]), + { + "landcover": 2, + "system:index": "412" + }), + ee.Feature( + ee.Geometry.Point([-13.691016395060194, 9.96881356565509]), + { + "landcover": 2, + "system:index": "413" + }), + ee.Feature( + ee.Geometry.Point([-13.608361442057264, 9.874374531391176]), + { + "landcover": 2, + "system:index": "414" + }), + ee.Feature( + ee.Geometry.Point([-13.607245643107069, 9.871584065858906]), + { + "landcover": 2, + "system:index": "415" + }), + ee.Feature( + ee.Geometry.Point([-13.607331473795545, 9.869892863116872]), + { + "landcover": 2, + "system:index": "416" + }), + ee.Feature( + ee.Geometry.Point([-13.605014045206678, 9.869723742364956]), + { + "landcover": 2, + "system:index": "417" + }), + ee.Feature( + ee.Geometry.Point([-13.60321160074867, 9.87090758580443]), + { + "landcover": 2, + "system:index": "418" + }), + ee.Feature( + ee.Geometry.Point([-13.60398407694496, 9.869554621526174]), + { + "landcover": 2, + "system:index": "419" + }), + ee.Feature( + ee.Geometry.Point([-13.598147590128553, 9.86811709089016]), + { + "landcover": 2, + "system:index": "420" + }), + ee.Feature( + ee.Geometry.Point([-13.596259314982069, 9.86777884747573]), + { + "landcover": 2, + "system:index": "421" + }), + ee.Feature( + ee.Geometry.Point([-13.576775748697889, 9.853826004088361]), + { + "landcover": 2, + "system:index": "422" + }), + ee.Feature( + ee.Geometry.Point([-13.576861579386366, 9.851627320370765]), + { + "landcover": 2, + "system:index": "423" + }), + ee.Feature( + ee.Geometry.Point([-13.578578193155897, 9.84883666224464]), + { + "landcover": 2, + "system:index": "424" + }), + ee.Feature( + ee.Geometry.Point([-13.576432425943983, 9.849259490750422]), + { + "landcover": 2, + "system:index": "425" + }), + ee.Feature( + ee.Geometry.Point([-13.575659949747694, 9.849174925092612]), + { + "landcover": 2, + "system:index": "426" + }), + ee.Feature( + ee.Geometry.Point([-13.585530478922498, 9.841225656527765]), + { + "landcover": 2, + "system:index": "427" + }), + ee.Feature( + ee.Geometry.Point([-13.586302955118787, 9.839872570479478]), + { + "landcover": 2, + "system:index": "428" + }), + ee.Feature( + ee.Geometry.Point([-13.584157187906873, 9.83995713851988]), + { + "landcover": 2, + "system:index": "429" + }), + ee.Feature( + ee.Geometry.Point([-13.630505759684217, 9.831669367685807]), + { + "landcover": 2, + "system:index": "430" + }), + ee.Feature( + ee.Geometry.Point([-13.631879050699842, 9.833699045065439]), + { + "landcover": 2, + "system:index": "431" + }), + ee.Feature( + ee.Geometry.Point([-13.574458857821856, 9.69531181961584]), + { + "landcover": 2, + "system:index": "432" + }), + ee.Feature( + ee.Geometry.Point([-13.57737710123006, 9.69565023860672]), + { + "landcover": 2, + "system:index": "433" + }), + ee.Feature( + ee.Geometry.Point([-13.578578730868731, 9.697849953722374]), + { + "landcover": 2, + "system:index": "434" + }), + ee.Feature( + ee.Geometry.Point([-13.581325312899981, 9.701403309189935]), + { + "landcover": 2, + "system:index": "435" + }), + ee.Feature( + ee.Geometry.Point([-13.58287026529256, 9.704449012462995]), + { + "landcover": 2, + "system:index": "436" + }), + ee.Feature( + ee.Geometry.Point([-13.58458687906209, 9.704956626983607]), + { + "landcover": 2, + "system:index": "437" + }), + ee.Feature( + ee.Geometry.Point([-13.584758540439044, 9.702756958506706]), + { + "landcover": 2, + "system:index": "438" + }), + ee.Feature( + ee.Geometry.Point([-13.58458687906209, 9.701234102640901]), + { + "landcover": 2, + "system:index": "439" + }), + ee.Feature( + ee.Geometry.Point([-13.582698603915606, 9.701234102640901]), + { + "landcover": 2, + "system:index": "440" + }), + ee.Feature( + ee.Geometry.Point([-13.579437037753497, 9.698188370151598]), + { + "landcover": 2, + "system:index": "441" + }), + ee.Feature( + ee.Geometry.Point([-13.578750392245684, 9.695988657256075]), + { + "landcover": 2, + "system:index": "442" + }), + ee.Feature( + ee.Geometry.Point([-13.578063746737872, 9.694634980609585]), + { + "landcover": 2, + "system:index": "443" + }), + ee.Feature( + ee.Geometry.Point([-13.575660487460528, 9.694634980609585]), + { + "landcover": 2, + "system:index": "444" + }), + ee.Feature( + ee.Geometry.Point([-13.573085566806231, 9.694973400283457]), + { + "landcover": 2, + "system:index": "445" + }), + ee.Feature( + ee.Geometry.Point([-13.56810738687459, 9.692604455395546]), + { + "landcover": 2, + "system:index": "446" + }), + ee.Feature( + ee.Geometry.Point([-13.56639077310506, 9.693112087851434]), + { + "landcover": 2, + "system:index": "447" + }), + ee.Feature( + ee.Geometry.Point([-13.56639077310506, 9.692096822171477]), + { + "landcover": 2, + "system:index": "448" + }), + ee.Feature( + ee.Geometry.Point([-13.579780360507403, 9.686005163578422]), + { + "landcover": 2, + "system:index": "449" + }), + ee.Feature( + ee.Geometry.Point([-13.582526942538653, 9.69192761092609]), + { + "landcover": 2, + "system:index": "450" + }), + ee.Feature( + ee.Geometry.Point([-13.583556910800372, 9.693619719539091]), + { + "landcover": 2, + "system:index": "451" + }), + ee.Feature( + ee.Geometry.Point([-13.59282662515584, 9.676529030508604]), + { + "landcover": 2, + "system:index": "452" + }), + ee.Feature( + ee.Geometry.Point([-13.597461482333575, 9.67686746843577]), + { + "landcover": 2, + "system:index": "453" + }), + ee.Feature( + ee.Geometry.Point([-13.5988347733492, 9.68075948009447]), + { + "landcover": 2, + "system:index": "454" + }), + ee.Feature( + ee.Geometry.Point([-13.601409694003497, 9.680251828957084]), + { + "landcover": 2, + "system:index": "455" + }), + ee.Feature( + ee.Geometry.Point([-13.603126307773028, 9.67483683575991]), + { + "landcover": 2, + "system:index": "456" + }), + ee.Feature( + ee.Geometry.Point([-13.601924678134356, 9.671452420702959]), + { + "landcover": 2, + "system:index": "457" + }), + ee.Feature( + ee.Geometry.Point([-13.602439662265216, 9.669083309890828]), + { + "landcover": 2, + "system:index": "458" + }), + ee.Feature( + ee.Geometry.Point([-13.605529567050372, 9.668237194841453]), + { + "landcover": 2, + "system:index": "459" + }), + ee.Feature( + ee.Geometry.Point([-13.606731196689044, 9.665868061379152]), + { + "landcover": 2, + "system:index": "460" + }), + ee.Feature( + ee.Geometry.Point([-13.60209633951131, 9.664683488390903]), + { + "landcover": 2, + "system:index": "461" + }), + ee.Feature( + ee.Geometry.Point([-13.592483302401934, 9.665021938241727]), + { + "landcover": 2, + "system:index": "462" + }), + ee.Feature( + ee.Geometry.Point([-13.583385249423419, 9.667391077663392]), + { + "landcover": 2, + "system:index": "463" + }), + ee.Feature( + ee.Geometry.Point([-13.582183619784747, 9.672467748797905]), + { + "landcover": 2, + "system:index": "464" + }), + ee.Feature( + ee.Geometry.Point([-13.576690455722247, 9.673990735190353]), + { + "landcover": 2, + "system:index": "465" + }), + ee.Feature( + ee.Geometry.Point([-13.571025630282794, 9.68363615537873]), + { + "landcover": 2, + "system:index": "466" + }), + ee.Feature( + ee.Geometry.Point([-13.570682307528887, 9.687528088592995]), + { + "landcover": 2, + "system:index": "467" + }), + ee.Feature( + ee.Geometry.Point([-13.570338984774981, 9.69192761092609]), + { + "landcover": 2, + "system:index": "468" + }), + ee.Feature( + ee.Geometry.Point([-13.566905757235919, 9.691081553418952]), + { + "landcover": 2, + "system:index": "469" + }), + ee.Feature( + ee.Geometry.Point([-13.56261422281209, 9.691081553418952]), + { + "landcover": 2, + "system:index": "470" + }), + ee.Feature( + ee.Geometry.Point([-13.560554286288653, 9.69565023860672]), + { + "landcover": 2, + "system:index": "471" + }), + ee.Feature( + ee.Geometry.Point([-13.9981272866448, 10.157269797971763]), + { + "landcover": 2, + "system:index": "472" + }), + ee.Feature( + ee.Geometry.Point([-14.0475657632073, 10.1680837588802]), + { + "landcover": 2, + "system:index": "473" + }), + ee.Feature( + ee.Geometry.Point([-13.86903793117605, 10.008879012049832]), + { + "landcover": 2, + "system:index": "474" + }), + ee.Feature( + ee.Geometry.Point([-13.863888089867457, 10.008879012049832]), + { + "landcover": 2, + "system:index": "475" + }), + ee.Feature( + ee.Geometry.Point([-13.865261380883082, 10.010231399900807]), + { + "landcover": 2, + "system:index": "476" + }), + ee.Feature( + ee.Geometry.Point([-13.868351285668238, 10.008879012049832]), + { + "landcover": 2, + "system:index": "477" + }), + ee.Feature( + ee.Geometry.Point([-13.877621000023707, 10.01225997111249]), + { + "landcover": 2, + "system:index": "478" + }), + ee.Feature( + ee.Geometry.Point([-13.873157804222926, 10.0048218146976]), + { + "landcover": 2, + "system:index": "479" + }), + ee.Feature( + ee.Geometry.Point([-13.874874417992457, 9.997721597385633]), + { + "landcover": 2, + "system:index": "480" + }), + ee.Feature( + ee.Geometry.Point([-13.876591031761988, 9.994002374025342]), + { + "landcover": 2, + "system:index": "481" + }), + ee.Feature( + ee.Geometry.Point([-13.8662913491448, 9.992988032997298]), + { + "landcover": 2, + "system:index": "482" + }), + ee.Feature( + ee.Geometry.Point([-13.862858121605738, 9.998059706490045]), + { + "landcover": 2, + "system:index": "483" + }), + ee.Feature( + ee.Geometry.Point([-13.86457473537527, 9.984873190890044]), + { + "landcover": 2, + "system:index": "484" + }), + ee.Feature( + ee.Geometry.Point([-13.869724576683863, 9.975743751659701]), + { + "landcover": 2, + "system:index": "485" + }), + ee.Feature( + ee.Geometry.Point([-13.877621000023707, 9.97540561936557]), + { + "landcover": 2, + "system:index": "486" + }), + ee.Feature( + ee.Geometry.Point([-13.875904386254176, 9.982168198547233]), + { + "landcover": 2, + "system:index": "487" + }), + ee.Feature( + ee.Geometry.Point([-13.88105422756277, 9.982844448740403]), + { + "landcover": 2, + "system:index": "488" + }), + ee.Feature( + ee.Geometry.Point([-13.886204068871363, 9.981830072923847]), + { + "landcover": 2, + "system:index": "489" + }), + ee.Feature( + ee.Geometry.Point([-13.890667264672144, 9.988592518649739]), + { + "landcover": 2, + "system:index": "490" + }), + ee.Feature( + ee.Geometry.Point([-13.89478713771902, 9.987578160749882]), + { + "landcover": 2, + "system:index": "491" + }), + ee.Feature( + ee.Geometry.Point([-13.893413846703394, 9.994340486998162]), + { + "landcover": 2, + "system:index": "492" + }), + ee.Feature( + ee.Geometry.Point([-13.893413846703394, 10.0011026726001]), + { + "landcover": 2, + "system:index": "493" + }), + ee.Feature( + ee.Geometry.Point([-13.897877042504176, 9.998059706490045]), + { + "landcover": 2, + "system:index": "494" + }), + ee.Feature( + ee.Geometry.Point([-13.90028030178152, 9.995354823806883]), + { + "landcover": 2, + "system:index": "495" + }), + ee.Feature( + ee.Geometry.Point([-13.8992503335198, 10.005498017776539]), + { + "landcover": 2, + "system:index": "496" + }), + ee.Feature( + ee.Geometry.Point([-13.878994291039332, 9.992988032997298]), + { + "landcover": 2, + "system:index": "497" + }), + ee.Feature( + ee.Geometry.Point([-13.896160428734644, 10.014964713003298]), + { + "landcover": 2, + "system:index": "498" + }), + ee.Feature( + ee.Geometry.Point([-13.90199691555105, 10.01834560865809]), + { + "landcover": 2, + "system:index": "499" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.5434608508915, 9.634974841301608], + [-13.545349126037985, 9.632266991548065], + [-13.54174423712197, 9.632436232794046]]]), + { + "landcover": 2, + "system:index": "500" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.483379368957907, 9.632436232794046], + [-13.484924321350485, 9.629897605196554], + [-13.48131943243447, 9.629389877386695]]]), + { + "landcover": 2, + "system:index": "501" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.435829167541891, 9.591646642167026], + [-13.433940892395407, 9.586568755869056], + [-13.431537633118063, 9.589446234106036]]]), + { + "landcover": 2, + "system:index": "502" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.438919072327048, 9.66560587720521], + [-13.439777379211813, 9.662559821578215], + [-13.435657506164938, 9.664590528393632]]]), + { + "landcover": 2, + "system:index": "503" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.52801132696572, 9.802649707720889], + [-13.531272893127829, 9.798420802628165], + [-13.525608067688376, 9.799266587959883]]]), + { + "landcover": 2, + "system:index": "504" + }), + ee.Feature( + ee.Geometry.Point([-13.700941293708981, 9.913100953593409]), + { + "landcover": 2, + "system:index": "505" + }), + ee.Feature( + ee.Geometry.Point([-13.703344552986325, 9.910057166995815]), + { + "landcover": 2, + "system:index": "506" + }), + ee.Feature( + ee.Geometry.Point([-13.707636087410153, 9.905660536482868]), + { + "landcover": 2, + "system:index": "507" + }), + ee.Feature( + ee.Geometry.Point([-13.709009378425778, 9.902109368825391]), + { + "landcover": 2, + "system:index": "508" + }), + ee.Feature( + ee.Geometry.Point([-13.710725992195309, 9.897543525381757]), + { + "landcover": 2, + "system:index": "509" + }), + ee.Feature( + ee.Geometry.Point([-13.712099283210934, 9.892977618451745]), + { + "landcover": 2, + "system:index": "510" + }), + ee.Feature( + ee.Geometry.Point([-13.713300912849606, 9.889426313632375]), + { + "landcover": 2, + "system:index": "511" + }), + ee.Feature( + ee.Geometry.Point([-13.715532510749997, 9.885198519765332]), + { + "landcover": 2, + "system:index": "512" + }), + ee.Feature( + ee.Geometry.Point([-13.717420785896481, 9.88249270315871]), + { + "landcover": 2, + "system:index": "513" + }), + ee.Feature( + ee.Geometry.Point([-13.720854013435543, 9.877926587157914]), + { + "landcover": 2, + "system:index": "514" + }), + ee.Feature( + ee.Geometry.Point([-13.724802225105465, 9.873360407791562]), + { + "landcover": 2, + "system:index": "515" + }), + ee.Feature( + ee.Geometry.Point([-13.678281991951168, 9.891962963848515]), + { + "landcover": 2, + "system:index": "516" + }), + ee.Feature( + ee.Geometry.Point([-13.626096933357418, 9.910902666107052]), + { + "landcover": 2, + "system:index": "517" + }), + ee.Feature( + ee.Geometry.Point([-13.625581949226559, 9.908873464578067]), + { + "landcover": 2, + "system:index": "518" + }), + ee.Feature( + ee.Geometry.Point([-13.625581949226559, 9.906167843010932]), + { + "landcover": 2, + "system:index": "519" + }), + ee.Feature( + ee.Geometry.Point([-13.625581949226559, 9.903462199130923]), + { + "landcover": 2, + "system:index": "520" + }), + ee.Feature( + ee.Geometry.Point([-13.626611917488278, 9.90177116037774]), + { + "landcover": 2, + "system:index": "521" + }), + ee.Feature( + ee.Geometry.Point([-13.621633737556637, 9.913946444855837]), + { + "landcover": 2, + "system:index": "522" + }), + ee.Feature( + ee.Geometry.Point([-13.621633737556637, 9.91242455901354]), + { + "landcover": 2, + "system:index": "523" + }), + ee.Feature( + ee.Geometry.Point([-13.747289865486325, 9.918850251170033]), + { + "landcover": 2, + "system:index": "524" + }), + ee.Feature( + ee.Geometry.Point([-13.748319833748043, 9.916821098835793]), + { + "landcover": 2, + "system:index": "525" + }), + ee.Feature( + ee.Geometry.Point([-13.749349802009762, 9.91360824861252]), + { + "landcover": 2, + "system:index": "526" + }), + ee.Feature( + ee.Geometry.Point([-13.751581399910153, 9.911071765667707]), + { + "landcover": 2, + "system:index": "527" + }), + ee.Feature( + ee.Geometry.Point([-13.752611368171872, 9.909888066911998]), + { + "landcover": 2, + "system:index": "528" + }), + ee.Feature( + ee.Geometry.Point([-13.759992807380856, 9.912086361200327]), + { + "landcover": 2, + "system:index": "529" + }), + ee.Feature( + ee.Geometry.Point([-13.736818521492184, 9.893146727247624]), + { + "landcover": 2, + "system:index": "530" + }), + ee.Feature( + ee.Geometry.Point([-13.731497018806637, 9.890948306111866]), + { + "landcover": 2, + "system:index": "531" + }), + ee.Feature( + ee.Geometry.Point([-13.72669050025195, 9.889595424255967]), + { + "landcover": 2, + "system:index": "532" + }), + ee.Feature( + ee.Geometry.Point([-13.719137399666012, 9.90109474243695]), + { + "landcover": 2, + "system:index": "533" + }), + ee.Feature( + ee.Geometry.Point([-13.719824045173825, 9.906675148754557]), + { + "landcover": 2, + "system:index": "534" + }), + ee.Feature( + ee.Geometry.Point([-13.723600595466793, 9.91360824861252]), + { + "landcover": 2, + "system:index": "535" + }), + ee.Feature( + ee.Geometry.Point([-13.7294370822832, 9.920033917561932]), + { + "landcover": 2, + "system:index": "536" + }), + ee.Feature( + ee.Geometry.Point([-13.730982034675778, 9.924599447866193]), + { + "landcover": 2, + "system:index": "537" + }), + ee.Feature( + ee.Geometry.Point([-13.738878458015622, 9.914453738566584]), + { + "landcover": 2, + "system:index": "538" + }), + ee.Feature( + ee.Geometry.Point([-13.744714944832028, 9.910902666107052]), + { + "landcover": 2, + "system:index": "539" + }), + ee.Feature( + ee.Geometry.Point([-13.746774881355465, 9.905660536482868]), + { + "landcover": 2, + "system:index": "540" + }), + ee.Feature( + ee.Geometry.Point([-13.747976510994137, 9.89889637450345]), + { + "landcover": 2, + "system:index": "541" + }), + ee.Feature( + ee.Geometry.Point([-13.74265500830859, 9.895006918256664]), + { + "landcover": 2, + "system:index": "542" + }), + ee.Feature( + ee.Geometry.Point([-13.741110055916012, 9.88722786760753]), + { + "landcover": 2, + "system:index": "543" + }), + ee.Feature( + ee.Geometry.Point([-13.744543283455075, 9.889595424255967]), + { + "landcover": 2, + "system:index": "544" + }), + ee.Feature( + ee.Geometry.Point([-13.774927347175778, 9.920710296437226]), + { + "landcover": 2, + "system:index": "545" + }), + ee.Feature( + ee.Geometry.Point([-13.774927347175778, 9.914115542846634]), + { + "landcover": 2, + "system:index": "546" + }), + ee.Feature( + ee.Geometry.Point([-13.775957315437497, 9.91191726216291]), + { + "landcover": 2, + "system:index": "547" + }), + ee.Feature( + ee.Geometry.Point([-13.780420511238278, 9.91293185507927]), + { + "landcover": 2, + "system:index": "548" + }), + ee.Feature( + ee.Geometry.Point([-13.783682077400387, 9.907182453713716]), + { + "landcover": 2, + "system:index": "549" + }), + ee.Feature( + ee.Geometry.Point([-13.780420511238278, 9.906844250494784]), + { + "landcover": 2, + "system:index": "550" + }), + ee.Feature( + ee.Geometry.Point([-13.775442331306637, 9.90971896674098]), + { + "landcover": 2, + "system:index": "551" + }), + ee.Feature( + ee.Geometry.Point([-13.769090860359372, 9.9147919339376]), + { + "landcover": 2, + "system:index": "552" + }), + ee.Feature( + ee.Geometry.Point([-13.764456003181637, 9.920203012411678]), + { + "landcover": 2, + "system:index": "553" + }), + ee.Feature( + ee.Geometry.Point([-13.755014627449215, 9.921555768067503]), + { + "landcover": 2, + "system:index": "554" + }), + ee.Feature( + ee.Geometry.Point([-13.747118204109372, 9.927135826088241]), + { + "landcover": 2, + "system:index": "555" + }), + ee.Feature( + ee.Geometry.Point([-13.760507791511715, 9.930348543625744]), + { + "landcover": 2, + "system:index": "556" + }), + ee.Feature( + ee.Geometry.Point([-13.794668405525387, 9.923415797972327]), + { + "landcover": 2, + "system:index": "557" + }), + ee.Feature( + ee.Geometry.Point([-13.796213357917965, 9.917497484343334]), + { + "landcover": 2, + "system:index": "558" + }), + ee.Feature( + ee.Geometry.Point([-13.794496744148434, 9.913439150360041]), + { + "landcover": 2, + "system:index": "559" + }), + ee.Feature( + ee.Geometry.Point([-13.797071664802731, 9.905998740922067]), + { + "landcover": 2, + "system:index": "560" + }), + ee.Feature( + ee.Geometry.Point([-13.801191537849606, 9.899572796973985]), + { + "landcover": 2, + "system:index": "561" + }), + ee.Feature( + ee.Geometry.Point([-13.808057992927731, 9.910057166995815]), + { + "landcover": 2, + "system:index": "562" + }), + ee.Feature( + ee.Geometry.Point([-13.799474924080075, 9.920033917561932]), + { + "landcover": 2, + "system:index": "563" + }), + ee.Feature( + ee.Geometry.Point([-13.802736490242184, 9.92493763276433]), + { + "landcover": 2, + "system:index": "564" + }), + ee.Feature( + ee.Geometry.Point([-13.804968088142575, 9.941339180848713]), + { + "landcover": 2, + "system:index": "565" + }), + ee.Feature( + ee.Geometry.Point([-13.813551156990231, 9.93846474216451]), + { + "landcover": 2, + "system:index": "566" + }), + ee.Feature( + ee.Geometry.Point([-13.817842691414059, 9.930517633148913]), + { + "landcover": 2, + "system:index": "567" + }), + ee.Feature( + ee.Geometry.Point([-13.827627389900387, 9.920203012411678]), + { + "landcover": 2, + "system:index": "568" + }), + ee.Feature( + ee.Geometry.Point([-13.823679178230465, 9.912762756477909]), + { + "landcover": 2, + "system:index": "569" + }), + ee.Feature( + ee.Geometry.Point([-13.820932596199215, 9.90904256518501]), + { + "landcover": 2, + "system:index": "570" + }), + ee.Feature( + ee.Geometry.Point([-13.822992532722653, 9.904138612192435]), + { + "landcover": 2, + "system:index": "571" + }), + ee.Feature( + ee.Geometry.Point([-13.821619241707028, 9.900249218050838]), + { + "landcover": 2, + "system:index": "572" + }), + ee.Feature( + ee.Geometry.Point([-13.825395791999997, 9.892470291541834]), + { + "landcover": 2, + "system:index": "573" + }), + ee.Feature( + ee.Geometry.Point([-13.828657358162106, 9.887904314104395]), + { + "landcover": 2, + "system:index": "574" + }), + ee.Feature( + ee.Geometry.Point([-13.835867135994137, 9.886213195252276]), + { + "landcover": 2, + "system:index": "575" + }), + ee.Feature( + ee.Geometry.Point([-13.842218606941403, 9.894330486381278]), + { + "landcover": 2, + "system:index": "576" + }), + ee.Feature( + ee.Geometry.Point([-13.846510141365231, 9.901263847052817]), + { + "landcover": 2, + "system:index": "577" + }), + ee.Feature( + ee.Geometry.Point([-13.751238077156247, 9.897205312230422]), + { + "landcover": 2, + "system:index": "578" + }), + ee.Feature( + ee.Geometry.Point([-13.751924722664059, 9.893484944578221]), + { + "landcover": 2, + "system:index": "579" + }), + ee.Feature( + ee.Geometry.Point([-13.751753061287106, 9.890102755604609]), + { + "landcover": 2, + "system:index": "580" + }), + ee.Feature( + ee.Geometry.Point([-13.749864786140622, 9.88773520261068]), + { + "landcover": 2, + "system:index": "581" + }), + ee.Feature( + ee.Geometry.Point([-13.744199960701168, 9.885705857900248]), + { + "landcover": 2, + "system:index": "582" + }), + ee.Feature( + ee.Geometry.Point([-13.743684976570309, 9.88249270315871]), + { + "landcover": 2, + "system:index": "583" + }), + ee.Feature( + ee.Geometry.Point([-13.744886606208981, 9.878264820146166]), + { + "landcover": 2, + "system:index": "584" + }), + ee.Feature( + ee.Geometry.Point([-13.735960214607418, 9.875220710736242]), + { + "landcover": 2, + "system:index": "585" + }), + ee.Feature( + ee.Geometry.Point([-13.732698648445309, 9.874036882806081]), + { + "landcover": 2, + "system:index": "586" + }), + ee.Feature( + ee.Geometry.Point([-13.755529611580075, 9.876742768961105]), + { + "landcover": 2, + "system:index": "587" + }), + ee.Feature( + ee.Geometry.Point([-13.761537759773434, 9.874036882806081]), + { + "landcover": 2, + "system:index": "588" + }), + ee.Feature( + ee.Geometry.Point([-13.765657632820309, 9.870147132490299]), + { + "landcover": 2, + "system:index": "589" + }), + ee.Feature( + ee.Geometry.Point([-13.772352426521481, 9.873191288820733]), + { + "landcover": 2, + "system:index": "590" + }), + ee.Feature( + ee.Geometry.Point([-13.78162214087695, 9.888242536830802]), + { + "landcover": 2, + "system:index": "591" + }), + ee.Feature( + ee.Geometry.Point([-13.783510416023434, 9.892301182397773]), + { + "landcover": 2, + "system:index": "592" + }), + ee.Feature( + ee.Geometry.Point([-13.788316934578122, 9.891793854443343]), + { + "landcover": 2, + "system:index": "593" + }), + ee.Feature( + ee.Geometry.Point([-13.810804574958981, 9.88164713090347]), + { + "landcover": 2, + "system:index": "594" + }), + ee.Feature( + ee.Geometry.Point([-13.826940744392575, 9.862367494036468]), + { + "landcover": 2, + "system:index": "595" + }), + ee.Feature( + ee.Geometry.Point([-13.801019876472653, 9.868625043771626]), + { + "landcover": 2, + "system:index": "596" + }), + ee.Feature( + ee.Geometry.Point([-13.879640787117184, 9.97025124536242]), + { + "landcover": 2, + "system:index": "597" + }), + ee.Feature( + ee.Geometry.Point([-13.870714395515622, 9.973294471519242]), + { + "landcover": 2, + "system:index": "598" + }), + ee.Feature( + ee.Geometry.Point([-13.934229104988278, 10.045140145886094]), + { + "landcover": 2, + "system:index": "599" + }), + ee.Feature( + ee.Geometry.Point([-13.930795877449215, 10.051225165678396]), + { + "landcover": 2, + "system:index": "600" + }), + ee.Feature( + ee.Geometry.Point([-13.933714120857418, 10.054436657725878]), + { + "landcover": 2, + "system:index": "601" + }), + ee.Feature( + ee.Geometry.Point([-13.940065591804684, 10.05494373250028]), + { + "landcover": 2, + "system:index": "602" + }), + ee.Feature( + ee.Geometry.Point([-13.941267221443356, 10.052746402731378]), + { + "landcover": 2, + "system:index": "603" + }), + ee.Feature( + ee.Geometry.Point([-13.940752237312497, 10.051056138897241]), + { + "landcover": 2, + "system:index": "604" + })]), + MangroveTraining = + /* color: #cf11d6 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + } + ] */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[-14.772867907259272, 10.831865509758982], + [-14.772867907259272, 10.829800117522154], + [-14.769735087129877, 10.829800117522154], + [-14.769735087129877, 10.831865509758982]]], null, false), + { + "landcover": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.765529383394526, 10.838525248913346], + [-14.766130198213862, 10.835743350576333], + [-14.763641108248041, 10.837724402042513]]]), + { + "landcover": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.913246520634662, 10.88669795665154], + [-14.913589843388568, 10.88475937330651], + [-14.911658652897845, 10.886192240473294]]]), + { + "landcover": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.895136245366107, 10.88551795090026], + [-14.89530790674306, 10.884000793781476], + [-14.893848785038958, 10.884464370387377]]]), + { + "landcover": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.050952041676988, 10.935378624515092], + [-15.051295364430894, 10.933018994799562], + [-15.048548782399644, 10.934030266976446]]]), + { + "landcover": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.056273544362535, 10.927794033632864], + [-15.05738934331273, 10.924675867811173], + [-15.052840316823472, 10.926361366917918]]]), + { + "landcover": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.033013427785386, 10.937738235455122], + [-15.033270919850816, 10.934198812004023], + [-15.030266845754136, 10.93613707293644]]]), + { + "landcover": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.024859512380113, 10.944058529371569], + [-15.024516189626206, 10.940940534549906], + [-15.022112930348863, 10.943805720202793]]]), + { + "landcover": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.033528411916246, 10.968495730093942], + [-15.034987533620347, 10.965546519857721], + [-15.031554306081285, 10.96563078341557]]]), + { + "landcover": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.984546455644416, 10.987837291653708], + [-14.98471811702137, 10.985056790571315], + [-14.982143196367073, 10.985899369423139]]]), + { + "landcover": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.970813545488166, 10.976293827966234], + [-14.97124269893055, 10.973007649961247], + [-14.968753608964729, 10.974440091021131], + [-14.970899376176643, 10.97688365091855]]]), + { + "landcover": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.913425310937384, 11.025767991764447], + [-14.913854464379767, 11.023156342914417], + [-14.911365374413947, 11.023830319031457]]]), + { + "landcover": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.906121064559587, 10.955341109815576], + [-14.907837678329118, 10.949610933953918], + [-14.9013145460049, 10.949610933953918]]]), + { + "landcover": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.96670177455577, 10.846156206496804], + [-14.967130927998152, 10.844133061873753], + [-14.965070991474715, 10.844638849312554]]]), + { + "landcover": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.743433698959846, 10.875987708548102], + [-14.743691191025276, 10.874723371063938], + [-14.74257539207508, 10.875229106700816]]]), + { + "landcover": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.758668646164436, 10.881424298639294], + [-14.758754476852912, 10.87990712068018], + [-14.75755284721424, 10.880497135248563]]]), + { + "landcover": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.581574563265484, 10.84536404443417], + [-14.581832055330914, 10.841570626993633], + [-14.57942879605357, 10.842582209681508]]]), + { + "landcover": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.603118066073101, 10.845279746791512], + [-14.603976372957867, 10.842160717310577], + [-14.600457314730328, 10.842413612804403]]]), + { + "landcover": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.544370475152173, 10.714539815401963], + [-14.544713797906079, 10.712009776250197], + [-14.542653861382641, 10.71335913309481]]]), + { + "landcover": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.555700126031079, 10.620070724737218], + [-14.557245078423657, 10.617033732301914], + [-14.554841819146313, 10.616696286835134]]]), + { + "landcover": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.49149877105061, 10.606741478020858], + [-14.492700400689282, 10.602860702077397], + [-14.489782157281079, 10.60353562316791]]]), + { + "landcover": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.525144400933423, 10.557468847876851], + [-14.525659385064282, 10.554262478003922], + [-14.522397818902173, 10.554768749154126]]]), + { + "landcover": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.547632041314282, 10.528104002109169], + [-14.549005332329907, 10.525572418817276], + [-14.546087088921704, 10.525572418817276], + [-14.547460379937329, 10.529285400531567]]]), + { + "landcover": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.502835338713801, 10.41292156162942], + [-14.503178661467707, 10.408700677058924], + [-14.499402111174739, 10.409544858543237]]]), + { + "landcover": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.494767253997004, 10.393842709127481], + [-14.495968883635676, 10.390128106675817], + [-14.492707317473567, 10.390634645974284]]]), + { + "landcover": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.47914606869427, 10.369359288904414], + [-14.47914606869427, 10.365644395693769], + [-14.476227825286067, 10.366319834100443]]]), + { + "landcover": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.576993053557551, 10.460191559812422], + [-14.577679699065364, 10.457490610691979], + [-14.575104778411067, 10.458672278824194]]]), + { + "landcover": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.627633159758723, 10.477747155867581], + [-14.628663128020442, 10.475552760727757], + [-14.625058239104426, 10.476059160985555]]]), + { + "landcover": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.458669826688668, 10.353920649385334], + [-14.459699794950387, 10.351049912543393], + [-14.457296535673043, 10.351387647653238]]]), + { + "landcover": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.139551326932809, 10.164877141176504], + [-14.14126794070234, 10.16115984608325], + [-14.13852135867109, 10.16115984608325]]]), + { + "landcover": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.092859432401559, 10.157611478625247], + [-14.09457604617109, 10.154907934134476], + [-14.092001125516793, 10.154738961845052]]]), + { + "landcover": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.0758649560832, 10.146121256763173], + [-14.077066585721871, 10.143755571644597], + [-14.07483498782148, 10.14392454973268]]]), + { + "landcover": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.086507961454293, 10.137841282399306], + [-14.086679622831246, 10.135644518587286], + [-14.083933040799996, 10.135644518587286]]]), + { + "landcover": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.114660427274606, 10.118069866300507], + [-14.114660427274606, 10.114183034389438], + [-14.11157052248945, 10.115028001850106]]]), + { + "landcover": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.108137294950387, 10.096607207508624], + [-14.108223125638863, 10.09398765106267], + [-14.10607735842695, 10.095339682858716]]]), + { + "landcover": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.100927517118356, 10.095170679194851], + [-14.101270839872262, 10.09288912104627], + [-14.09809510439863, 10.093311633034737]]]), + { + "landcover": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.021705791654488, 10.082326141150112], + [-14.021877453031442, 10.080636032223616], + [-14.020075008573434, 10.081058560286214]]]), + { + "landcover": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.9989606592082, 10.0360984726324], + [-13.99921815127363, 10.03390101484509], + [-13.997158214750192, 10.034915227984722]]]), + { + "landcover": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.982309505643746, 10.021899251579727], + [-13.982652828397653, 10.019025524007592], + [-13.980592891874215, 10.020377869566946]]]), + { + "landcover": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.02342240542402, 10.024603913085619], + [-14.024624035062692, 10.021392125035309], + [-14.021448299589059, 10.021899251579727]]]), + { + "landcover": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.835067067440528, 9.863594689892103], + [-13.834895406063575, 9.86190344613282], + [-13.833951268490333, 9.8628336312745]]]), + { + "landcover": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.78159454851963, 9.855138384324128], + [-13.78434113055088, 9.852686015145009], + [-13.780650410946388, 9.852686015145009], + [-13.78210953265049, 9.856068588553256]]]), + { + "landcover": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.730782780941505, 9.849895365972753], + [-13.732327733334083, 9.84795035410826], + [-13.72992447405674, 9.8484577496128]]]), + { + "landcover": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.690013203915138, 9.850402758486885], + [-13.690528188045997, 9.84795035410826], + [-13.68821075945713, 9.848288617864625]]]), + { + "landcover": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.681773457821388, 9.867822761312134], + [-13.682030949886817, 9.865285924971385], + [-13.67971352129795, 9.865708732384784]]]), + { + "landcover": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.656796727474708, 9.882536026645745], + [-13.65748337298252, 9.879745630321658], + [-13.65473679095127, 9.880252976868517]]]), + { + "landcover": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.658856663998145, 9.860635007617953], + [-13.659371648129005, 9.857844425704632], + [-13.656367574032325, 9.858859185497039]]]), + { + "landcover": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.65525177508213, 9.812684457771793], + [-13.656281743343849, 9.809893470949143], + [-13.653449330624122, 9.810400924847407]]]), + { + "landcover": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.572682652767677, 9.778006894151861], + [-13.57311180621006, 9.77445435389848], + [-13.569163594540138, 9.776738134132595]]]), + { + "landcover": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.532513890560645, 9.73579688260377], + [-13.532599721249122, 9.732413083234764], + [-13.529853139217872, 9.73410498720453]]]), + { + "landcover": 1, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.543843541439552, 9.590008806122597], + [-13.543929372128028, 9.587131332658355], + [-13.540324483212013, 9.588908598563034]]]), + { + "landcover": 1, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.50891045122959, 9.585861851311003], + [-13.508996281918067, 9.583153608560922], + [-13.50616386919834, 9.58518479265003]]]), + { + "landcover": 1, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.542556081112403, 9.577059983359076], + [-13.543242726620216, 9.574605575646206], + [-13.540238652523536, 9.574605575646206]]]), + { + "landcover": 1, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.530389026199542, 9.527893347398814], + [-13.530303195511065, 9.525523232532972], + [-13.52867241243001, 9.526792938971614]]]), + { + "landcover": 1, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.451424792801104, 9.537796863571655], + [-13.452454761062823, 9.535257527857542], + [-13.450738147293292, 9.535426817493349]]]), + { + "landcover": 1, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.454943851028643, 9.544737618029338], + [-13.455630496536456, 9.542282977117766], + [-13.453570560013018, 9.542875478266838]]]), + { + "landcover": 1, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.404647067581378, 9.536019330556984], + [-13.404904559646807, 9.533395336318703], + [-13.402758792434893, 9.533733917354596]]]), + { + "landcover": 1, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.35263367036458, 9.463471170308926], + [-13.352376178299151, 9.46186257739953], + [-13.350058749710284, 9.462709206184886]]]), + { + "landcover": 1, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.281136706863604, 9.376427045404881], + [-13.279935077224932, 9.373293725915216], + [-13.277875140701495, 9.37549552094412]]]), + { + "landcover": 1, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.258134082351885, 9.403016779052459], + [-13.25701828340169, 9.400899836835583], + [-13.253499225174151, 9.402339358952185]]]), + { + "landcover": 1, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.2767593417513, 9.352206597362429], + [-13.2767593417513, 9.348226152497125], + [-13.27324028352376, 9.351020937696008]]]), + { + "landcover": 1, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.319159701858721, 9.36406297170052], + [-13.32345123628255, 9.362962039686883], + [-13.31993217805501, 9.359743910725987]]]), + { + "landcover": 1, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.276330188308917, 9.28597285948887], + [-13.276587680374346, 9.282076366483075], + [-13.273411944900714, 9.284109324760125]]]), + { + "landcover": 1, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.22035537324127, 9.227099179359078], + [-13.221042018749083, 9.223879801424738], + [-13.217952113963927, 9.224472846935972]]]), + { + "landcover": 1, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.282496791698302, 9.227014459263557], + [-13.281981807567442, 9.223795080556025], + [-13.279578548290099, 9.225828375789598]]]), + { + "landcover": 1, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.201730113841856, 9.201512786400121], + [-13.200614314891661, 9.198293175278035], + [-13.198554378368224, 9.201343333913732]]]), + { + "landcover": 1, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.184306484081114, 9.042107056466508], + [-13.184993129588927, 9.039987948233751], + [-13.183019023753966, 9.040072712802496]]]), + { + "landcover": 1, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.260438304759825, 9.024984305436146], + [-13.259408336498106, 9.023458476277755], + [-13.257691722728575, 9.024560464650595]]]), + { + "landcover": 1, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.642733884742919, 9.878367396851779], + [-13.643291784218016, 9.876929904698706], + [-13.641231847694579, 9.877352697160317]]]), + { + "landcover": 1, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.637626958778563, 9.870714792841605], + [-13.637498212745848, 9.869150426476896], + [-13.635996175697509, 9.869869190324037]]]), + { + "landcover": 1, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.71767956322163, 9.790239249343115], + [-13.71793705528706, 9.788293886948836], + [-13.716048780140575, 9.788801373889488]]]), + { + "landcover": 1, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.722228589710888, 9.789647183733882], + [-13.721713605580028, 9.788124724462955], + [-13.71991116112202, 9.78905511706901]]]), + { + "landcover": 1, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.718709531483348, 9.787532655083849], + [-13.71793705528706, 9.786686839854307], + [-13.716735425648388, 9.787194329250488]]]), + { + "landcover": 1, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.72566181724995, 9.785502694914687], + [-13.724717679676708, 9.784233963509804], + [-13.723258557972606, 9.785248949021314]]]), + { + "landcover": 1, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.702487531361278, 9.789308860054645], + [-13.702830854115184, 9.787278910741135], + [-13.701028409657177, 9.788463049348552], + [-13.70317417686909, 9.789985507068423]]]), + { + "landcover": 1, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.697509351429638, 9.80064251559769], + [-13.697337690052684, 9.798866371277441], + [-13.695535245594677, 9.799965890311366]]]), + { + "landcover": 1, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.487795754889769, 9.654477745850699], + [-13.487967416266722, 9.65312390200053], + [-13.485478326300901, 9.65312390200053]]]), + { + "landcover": 1, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.439584340971981, 9.671575492304996], + [-13.43936976425079, 9.669967883805594], + [-13.43786772720245, 9.670898605452638]]]), + { + "landcover": 1, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.448296155852352, 9.662183565542307], + [-13.448553647917782, 9.66057591215856], + [-13.446794118804013, 9.661083593004093]]]), + { + "landcover": 1, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.451471891325985, 9.66599113502486], + [-13.451471891325985, 9.664425806120096], + [-13.45009860031036, 9.66506039979714]]]), + { + "landcover": 1, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.471642103117977, 9.675932918788158], + [-13.471599187773739, 9.674494551243551], + [-13.470526304167782, 9.67538295545391]]]), + { + "landcover": 1, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.493915166777645, 9.681347894319272], + [-13.494430150908505, 9.679951854290938], + [-13.492498960417782, 9.679571115094394]]]), + { + "landcover": 1, + "system:index": "81" + })]), + NonMangroveTraining = + /* color: #0d3bff */ + /* shown: false */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[-15.016362274220933, 10.95631951504912], + [-15.01670559697484, 10.954465652887245], + [-15.014988983205308, 10.955729651075279]]]), + { + "landcover": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.028464401296128, 10.951853372862459], + [-15.028893554738511, 10.9499573487322], + [-15.026318634084214, 10.950589358124523]]]), + { + "landcover": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.030567253163804, 10.957794169840307], + [-15.03091057591771, 10.955687517889313], + [-15.028464401296128, 10.954760586280573], + [-15.028121078542222, 10.956193115725121]]]), + { + "landcover": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.064427459767808, 10.939929285941478], + [-15.062968338063706, 10.936811247682382], + [-15.05962094121312, 10.939339389326674], + [-15.061766708425035, 10.942457400993268]]]), + { + "landcover": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.01115396907215, 10.978358203146746], + [-15.011497291826057, 10.976041046340452], + [-15.008707794450569, 10.976672999999328]]]), + { + "landcover": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.018235000871467, 10.979242930950159], + [-15.01866415431385, 10.976462348929923], + [-15.016303810380744, 10.978189683264663]]]), + { + "landcover": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.023599418901252, 10.982697556991285], + [-15.023685249589729, 10.980717471399375], + [-15.021453651689338, 10.981812839538087]]]), + { + "landcover": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.94775758632801, 11.03259186797311], + [-14.947929247704963, 11.029306317720359], + [-14.94501100429676, 11.031243954363834]]]), + { + "landcover": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.92827402004383, 11.037225273846428], + [-14.929046496240119, 11.034866458168958], + [-14.926729067651252, 11.035119189326004]]]), + { + "landcover": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.931449755517463, 11.018101472815468], + [-14.932393893090705, 11.015826752939146], + [-14.930076464501838, 11.016163749585782]]]), + { + "landcover": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.717083677597541, 10.887661504655835], + [-14.717169508286018, 10.88547006877135], + [-14.715281233139534, 10.886818646608011]]]), + { + "landcover": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.707556471176643, 10.873501173067645], + [-14.707985624619026, 10.871309633085449], + [-14.705839857407112, 10.872236825042815]]]), + { + "landcover": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.564665917635601, 10.855985357241925], + [-14.56492340970103, 10.851686299903761], + [-14.560889367342632, 10.85396227913996]]]), + { + "landcover": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.501528172847433, 10.829671752536575], + [-14.50358810937087, 10.826299651525124], + [-14.498953252193136, 10.82646825747719]]]), + { + "landcover": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.49586334740798, 10.843328373277828], + [-14.498438268062277, 10.838439037462708], + [-14.492258458491964, 10.839282032096412]]]), + { + "landcover": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.456994834283032, 10.749958141773662], + [-14.460428061822094, 10.746922447900886], + [-14.456136527398266, 10.746585146697118]]]), + { + "landcover": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.442231955865063, 10.732418155960152], + [-14.442918601372876, 10.728538983147049], + [-14.438798728326, 10.729382285818327]]]), + { + "landcover": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.604451957085766, 10.529960483311568], + [-14.605310263970532, 10.52692259915962], + [-14.60136205230061, 10.52894785858715]]]), + { + "landcover": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.48600560698811, 10.471222760291694], + [-14.486177268365063, 10.466833862095141], + [-14.48325902495686, 10.468353103116165]]]), + { + "landcover": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.500432079436457, 10.441284422659384], + [-14.500432079436457, 10.438245668318906], + [-14.496998851897395, 10.439089769725399]]]), + { + "landcover": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.549012249114192, 10.45462082650194], + [-14.549870555998957, 10.452257454900492], + [-14.546952312590754, 10.452257454900492]]]), + { + "landcover": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.534936016204036, 10.443647877725367], + [-14.534936016204036, 10.439427409646498], + [-14.530129497649348, 10.44111560375287]]]), + { + "landcover": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.356874630155465, 10.29244737636023], + [-14.357389614286324, 10.289069376182145], + [-14.354471370878121, 10.2909272807549]]]), + { + "landcover": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.315847561063668, 10.324198808708294], + [-14.316362545194528, 10.32115891654387], + [-14.314130947294137, 10.322003333980634]]]), + { + "landcover": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.15851990908613, 10.089339998450072], + [-14.159635708036324, 10.087058398980245], + [-14.157318279447457, 10.088072445184688]]]), + { + "landcover": 2, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.039730236234567, 10.046493936082012], + [-14.040245220365426, 10.044550094321767], + [-14.038786098661324, 10.045648788926059]]]), + { + "landcover": 2, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.001278087797067, 10.069734616761512], + [-14.00170724123945, 10.06762189672479], + [-13.999990627469918, 10.068213459729401]]]), + { + "landcover": 2, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.967031643094918, 10.078100852215877], + [-13.968061611356637, 10.07590368008197], + [-13.9660016748332, 10.076410721134172]]]), + { + "landcover": 2, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.96900574892988, 10.101846256417112], + [-13.970035717191598, 10.100240750496802], + [-13.967804119291207, 10.100494251964397]]]), + { + "landcover": 2, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.947118923368356, 10.008291081164497], + [-13.947633907499215, 10.005924384584203], + [-13.945144817533395, 10.006685110366224]]]), + { + "landcover": 2, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.936304256620309, 10.017419606331591], + [-13.938364193143746, 10.01454583906799], + [-13.935617611112496, 10.015052976317214]]]), + { + "landcover": 2, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.865245156545589, 10.011587522650414], + [-13.865931802053401, 10.008967277018833], + [-13.862241082448909, 10.008967277018833]]]), + { + "landcover": 2, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.849194817800472, 10.015222021890791], + [-13.849366479177425, 10.012939899216223], + [-13.847392373342464, 10.01378513170792]]]), + { + "landcover": 2, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.871596627492854, 9.977522681370168], + [-13.872884087820003, 9.97473309468144], + [-13.868678384084651, 9.975493893420309], + [-13.87219744231219, 9.977860811466533]]]), + { + "landcover": 2, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.885329537649104, 9.931449178193983], + [-13.885844521779964, 9.928067380758433], + [-13.882582955617854, 9.92891283339319]]]), + { + "landcover": 2, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.719195637997169, 9.885749180963948], + [-13.719367299374122, 9.883550710348658], + [-13.716792378719825, 9.885072730032563]]]), + { + "landcover": 2, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.712758336361427, 9.899785223586706], + [-13.71292999773838, 9.897164080446853], + [-13.710097585018653, 9.898516931131878]]]), + { + "landcover": 2, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.585042271908302, 9.704664636543379], + [-13.585643086727638, 9.70153433202078], + [-13.582982335384864, 9.70280337791928]]]), + { + "landcover": 2, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.603495869930763, 9.704072419011773], + [-13.604697499569435, 9.699334641080256], + [-13.60032013445713, 9.699673056010699]]]), + { + "landcover": 2, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.568047795589942, 9.681736594181228], + [-13.568047795589942, 9.678775293678653], + [-13.565472874935645, 9.680298251483626]]]), + { + "landcover": 2, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.579463277157325, 9.671498844445082], + [-13.580149922665138, 9.667945172458403], + [-13.577145848568458, 9.66929895669111]]]), + { + "landcover": 2, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.550280843075294, 9.648314689092652], + [-13.551053319271583, 9.645353094436604], + [-13.548306737240333, 9.645860798225591]]]), + { + "landcover": 2, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.53637627154209, 9.6554224100717], + [-13.537577901180763, 9.65296857096865], + [-13.535174641903419, 9.653053186407726]]]), + { + "landcover": 2, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.354779437576495, 9.451194876126811], + [-13.356066897903643, 9.448231567078778], + [-13.35289116243001, 9.448824230929024]]]), + { + "landcover": 2, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.30122108796712, 9.458137385977457], + [-13.301993564163409, 9.455766788608837], + [-13.299161151443682, 9.456698096666363]]]), + { + "landcover": 2, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.380013659988604, 9.43282194906301], + [-13.379327014480792, 9.430197165246152], + [-13.376837924514971, 9.431636565296552]]]), + { + "landcover": 2, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.292037204300128, 9.406827242400094], + [-13.290663913284503, 9.402508714101591], + [-13.2877456698763, 9.405387738957764]]]), + { + "landcover": 2, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.245417934276427, 9.18405875410957], + [-13.243443828441466, 9.181432101976078], + [-13.241383891918028, 9.18388929326906]]]), + { + "landcover": 2, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.066632610179747, 9.154740824313496], + [-13.06731925568756, 9.152113955250934], + [-13.064915996410216, 9.152791858802239]]]), + { + "landcover": 2, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.074958186961974, 9.158977668998714], + [-13.075129848338927, 9.15618135717263], + [-13.073155742503966, 9.157028726715863]]]), + { + "landcover": 2, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.729721799006377, 9.85583516805335], + [-13.729721799006377, 9.85245259225134], + [-13.727490201105987, 9.853974755654882]]]), + { + "landcover": 2, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.717018857111846, 9.87917399489423], + [-13.717877163996612, 9.877144597357086], + [-13.714958920588408, 9.877482831149154]]]), + { + "landcover": 2, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.728520169367705, 9.83097242702757], + [-13.729206814875518, 9.828266165435217], + [-13.726288571467315, 9.828266165435217]]]), + { + "landcover": 2, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.514183618018233, 9.825400785383925], + [-13.51401195664128, 9.82408992060949], + [-13.512552834937178, 9.824935640413306]]]), + { + "landcover": 2, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.518603898474776, 9.822229329432322], + [-13.518560983130538, 9.82117217069405], + [-13.517616845557296, 9.821595034594583]]]), + { + "landcover": 2, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.525341607520186, 9.831320755143555], + [-13.526028253027999, 9.830009913831383], + [-13.524440385291182, 9.830179054937869]]]), + { + "landcover": 2, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.543580628821456, 9.823836204246815], + [-13.54323730606755, 9.822398474517083], + [-13.542035676428878, 9.822652191982112]]]), + { + "landcover": 2, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.708849929637964, 9.918043253117057], + [-13.708849929637964, 9.916690482958893], + [-13.707304977245386, 9.917113224233205]]]), + { + "landcover": 2, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.704386733837183, 9.911025697281337], + [-13.704644225902612, 9.909588348034493], + [-13.703356765575464, 9.910095648488015]]]), + { + "landcover": 2, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.640357040233667, 9.89622915380466], + [-13.640700362987573, 9.894199861550709], + [-13.638983749218042, 9.894622631804186]]]), + { + "landcover": 2, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.64160671314408, 9.893653002898159], + [-13.641563797799842, 9.893124538436428], + [-13.640962982980506, 9.893261939278268]]]), + { + "landcover": 2, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.638013196876708, 9.880523623305505], + [-13.63797028153247, 9.879339814453012], + [-13.636983228614989, 9.87972032490587]]]), + { + "landcover": 2, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.61247856705493, 9.877437255587456], + [-13.61273605912036, 9.876168876898934], + [-13.611620260170165, 9.876507111693881]]]), + { + "landcover": 2, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.605569196632567, 9.87041883220746], + [-13.605526281288329, 9.86906586592114], + [-13.604152990272704, 9.869742349759118]]]), + { + "landcover": 2, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.598144842079344, 9.869150426476896], + [-13.598316503456298, 9.867628333151876], + [-13.597114873817626, 9.867628333151876]]]), + { + "landcover": 2, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.705663266834911, 9.8058863147593], + [-13.705234113392528, 9.803941044100654], + [-13.70420414513081, 9.8052097001726]]]), + { + "landcover": 2, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.438532915038143, 9.665229624575522], + [-13.438897695464169, 9.664129661994533], + [-13.43763169280914, 9.664489265541672]]]), + { + "landcover": 2, + "system:index": "66" + })]), + nationalborder = ee.FeatureCollection("projects/gee-book/assets/A3-3/Border5km"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.3 Mangroves +// Section: Supplemental (Assignment 1) +// Author: Celio de Sousa, David Lagomasino, and Lola Fatoyinbo +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + //**************************************** +//STEP 1 - TEMPORAL AND SPATIAL PARAMETERS +//**************************************** + +//Temporal +var year = 2020; // Year +var startDay = (year)+'-01-01'; // beginning of date filter | month-day +var endDay = (year)+'-12-30'; // end of date filter | month-day + +//Spatial +var aoi = ee.FeatureCollection('projects/gee-book/assets/A3-3/CoastalPrefectures5k'); + +//**************************** +//STEP 2 - AUXILIARY FUNCTIONS +//**************************** + +var maskL8sr = function (image) { + var cloudShadowBitMask = 1 << 3; + var cloudsBitMask = 1 << 5; + var qa = image.select('pixel_qa'); + var mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0) + .and(qa.bitwiseAnd(cloudsBitMask).eq(0)); + return image.updateMask(mask).divide(10000) + .select("B[0-9]*") + .copyProperties(image, ["system:time_start"]); +}; + + +var addIndicesL8 = function(img) { + // NDVI (Normalized Difference Vegetation Index) + var ndvi = img.normalizedDifference(['B5','B4']).rename('NDVI'); + + // NDMI (Normalized Difference Mangrove Index - Shi et al 2016 ) + var ndmi = img.normalizedDifference(['B7','B3']).rename('NDMI'); + + // MNDWI (Modified Normalized Difference Water Index - Hanqiu Xu, 2006) + var mndwi = img.normalizedDifference(['B3','B6']).rename('MNDWI'); + + // SR (Simple Ratio) + var sr = img.select('B5').divide(img.select('B4')).rename('SR'); + + // Band Ratio 6/5 + var ratio65 = img.select('B6').divide(img.select('B5')).rename('R65'); + + // Band Ratio 4/6 + var ratio46 = img.select('B4').divide(img.select('B6')).rename('R46'); + + // GCVI (Green Chlorophyll Vegetation Index) + var gcvi = img.expression('(NIR/GREEN)-1',{ + 'NIR':img.select('B5'), + 'GREEN':img.select('B3') + }).rename('GCVI'); + + return img + .addBands(ndvi) // This will add each spectral index to each Landsat scene + .addBands(ndmi) + .addBands(mndwi) + .addBands(sr) + .addBands(ratio65) + .addBands(ratio46) + .addBands(gcvi); +}; + + +//************************************************************** +//STEP 3 - CREATE AUXILIARY MASKS AND BANDS FOR MANGROVE MAPPING +//************************************************************** + +// WATER MASK +// The objective of this mask is to remove water pixels from the Landsat composite as we are only focusing on Mangroves + +// We will create a Water Mask using the Global Surface Water dataset + +var globalwater = ee.Image('JRC/GSW1_0/GlobalSurfaceWater'); // Load the dataset + +// The Global Water Dataset has different bands. One of them is the the frequency with which water was present (occurrence). +// Esentially, this band shows how many times a given pixel was classified as water relative to the total time span of the dataset + +var occurrence = globalwater.select('occurrence'); // Select the occurrence band. + +// Masks are composed by zeros and non-zero values. When you set or apply a mask to an image, the output image will keep it's original values where the mask +// has non zero values whereas the it will be masked where the mask has zero values. +// For this example, we want to create a watermask. Thus Watermask has to have zero where there is water and non zero values +// For our mask, we want to make sure we are selecting permanent water. We want to filter the dataset for water pixels that occurred more than 50% of the time over the 35 years time spam. + +var waterMask = occurrence.lt(50) // Selects lower than 50%. Automatically, values above 90% are set to 0 + .unmask(1); // Since the water dataset only includes water, set other areas to 1 + +Map.addLayer(waterMask, {}, 'Water Mask'); + + + +// ELEVATION/SLOPE MASK + +// The objective of this mask is to remove pixels that are unlikely to be mangrove based on the slope. Generally, it will occur near shore where +// elevation and slope is very low. + +// We will create a mask using the SRTM Elevation Data +var srtm = ee.Image('USGS/SRTMGL1_003'); + +var elevation = srtm.select('elevation'); + +// In this case, we want to create a mask where pixels that have higher altitude values are removed +// Hence, we select everything that is UNDER 25 meters; everything else will be set to 0 automatically. +var elevMask = elevation.lte(25); +Map.addLayer(elevMask, {}, 'Elevation Mask'); +Map.addLayer(ee.Image().paint(aoi, 0, 2), {palette:['red']}, 'StudyArea'); + +//********************************************************* +//STEP 4 - LANDSAT 8 IMAGE COLLECTION AND CLOUD-FREE MOSAIC +//********************************************************* + +// Map the function over one year of data. +var collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR') + .filterDate(startDay, endDay) + .map(maskL8sr) + .map(addIndicesL8); + + +var composite = collection + .median() + .mask(waterMask) + .updateMask(elevMask) + .clip(aoi); + +// Display the results. +//Map.centerObject(Mangroves2016,9); +Map.addLayer(composite, {bands: ['B5', 'B6', 'B4'], min: 0, max: 0.3}, 'Composite'); + +//************************************************************ +//STEP 5 - CREATE STRATIFICATION MAP BASED ON MANGROVE DATASET +//************************************************************ + +//Mangrove Strata + +//First, let's load the global mangrove dataset for the year 2000 +var dataset = ee.FeatureCollection('projects/gee-book/assets/A3-3/Mangroves2000'); +var mangrove = ee.Image(1).clip(dataset); + +//All other classes Strata + +// First we create an image of zeros where values 1 will be added where there is a pixel from the composite, including the mangrove areas +var nonmangrove = ee.Image(0).where(composite.select('B1'),2).selfMask() +// Now we have an image of values of 1 where there is composite. Now we set this image to zero where there is pixel of mangrove +var strata = nonmangrove.where(mangrove,1).rename('landcover'); + +Map.addLayer (strata, {palette:['#B3E283','#E8E46E'], min:1, max:2}, 'Strata') + +// Selecting samples based on the strata created above + +var stratified = strata.addBands(ee.Image.pixelLonLat()).stratifiedSample({ + numPoints: 1, + classBand: 'landcover', + scale: 30, + region: aoi, + classValues:[1,2], // + classPoints:[1000,1000] // Insert the number of points per class. + }).map(function(f) { // set these points to geometry and get their coordinates + return f.setGeometry(ee.Geometry.Point([f.get('longitude'), f.get('latitude')])) + }); + +var paletteSamples = ee.List([ + 'FFFFFF', //NULL + '01937C', // Mangrove + 'B6C867', // Non-Mangrove + ]); + +// We use this function to colorize the samples based on the palette +var features = stratified.map(function(f) { + var landcover = f.get('landcover'); + return ee.Feature(ee.Geometry.Point([f.get('longitude'), f.get('latitude')]), f.toDictionary()) + .set({style: {color: paletteSamples.get(landcover) }}); +}); + +// Add the features / sample location into the map with the style set above +Map.addLayer(features.style({styleProperty: "style"}),{}, 'Samples/Location') + +//************************************************************ +//STEP 6 - CLASSIFICATION +//************************************************************ + +// First, we will select the predictors to assign to each sample point in the sample sets +var bands = ['B5','B6','B7','NDVI','MNDWI','SR']; + +// Create the sample sets +// Automatic +var samplesAutomatic = composite.select(bands).sampleRegions({ + collection: stratified, + properties: ['landcover'], + scale: 30, + geometries: true, +}); + +// Create the sample set with the samples you selected manually via geometry +var manualpoints = MangroveTraining.merge(NonMangroveTraining); +var samplesManual = composite.select(bands).sampleRegions({ + collection: manualpoints, + properties: ['landcover'], + scale: 30, + geometries: true, +}); + +// Create the Ground Truth sample set that will be used to validate the land cover classification maps +var groundtruth = ee.FeatureCollection('users/celiohelder/TutorialAssets/GroundTruth'); +Map.addLayer(groundtruth) + +var samplesgroundtruth = composite.select(bands).sampleRegions({ + collection: groundtruth, // Set of geometries selected in 4.1 + properties: ['landcover'], // Label from each geometry + scale: 30, + geometries: true, +}); + + +// Train two classifiers: one with the samples collected automatically via stratification and one with the samples you selected manually +var RandomForest1 = ee.Classifier.smileRandomForest(200,5).train({ + features: samplesAutomatic, + classProperty: 'landcover', + inputProperties: bands +}); + +var RandomForest2 = ee.Classifier.smileRandomForest(200,5).train({ + features: samplesManual, + classProperty: 'landcover', + inputProperties: bands +}); + + +// Classify the Landsat 8 Composite using the two classifiers to produce 2 land cover maps + +var classifiedrf1 = composite.select(bands) // select the predictors + .classify(RandomForest1); // apply the Random Forest trained with the automatically selected samples + +var classifiedrf2 = composite.select(bands) // select the predictors + .classify(RandomForest2); // apply the Random Forest classifier trained with mannually selected samples + +// Color palette for the classification outputs +var paletteMAP = [ + '01937C', // Mangrove + 'B6C867', // Non-Mangrove +]; + +// Add the classifications to the map editor +Map.addLayer (classifiedrf1, {min: 1, max: 2, palette:paletteMAP}, 'Classification Automatic Samples'); +Map.addLayer (classifiedrf2, {min: 1, max: 2, palette:paletteMAP}, 'Classification Manual Samples'); + + +var validation1 = samplesgroundtruth.classify(RandomForest1); +var validation2 = samplesgroundtruth.classify(RandomForest2); +var testAccuracy1 = validation1.errorMatrix('landcover', 'classification'); +var testAccuracy2 = validation2.errorMatrix('landcover', 'classification'); +var kappa1 = testAccuracy1.kappa(); +var kappa2 = testAccuracy2.kappa(); + +print('Overall Accuracy Map 1: ', testAccuracy1.accuracy()); +print('Overall Accuracy Map 2: ', testAccuracy2.accuracy()); +print('Kappa: ', kappa1); +print('Kappa: ', kappa2); + +print('Validation error matrix Map1: ', testAccuracy1); +print('Validation error matrix Map2: ', testAccuracy2); + +var legend = ui.Panel({ + style: { + position: 'bottom-left', // Position in the map + padding: '8px 15px' // Padding (border) size + } +}); +var makeRow = function(color, name) { + // Create the label that is actually the colored boxes that represent each class + var colorBox = ui.Label({ + style: { + backgroundColor: '#' + color, + // Use padding to give the label color box height and width. + padding: '8px', + margin: '0 0 4px 0' + } + }); + // Create the label filled with the description text. + var description = ui.Label({ + value: name, + style: {margin: '0 0 4px 6px'} + }); + return ui.Panel({ + widgets: [colorBox, description], + layout: ui.Panel.Layout.Flow('horizontal') + }); +}; +legend.add(makeRow('01937C', 'Mangrove')); +legend.add(makeRow('B6C867', 'Non-mangrove')); + +//Map.add (legend); + + + diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33s1 - Supplemental.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33s1 - Supplemental.py new file mode 100644 index 0000000..e3278d2 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.3 Mangroves II - Change/A33s1 - Supplemental.py @@ -0,0 +1,9310 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +imageCollection = ee.ImageCollection("LANDSAT/MANGROVE_FORESTS"), + Mangrove = + + # shown: False # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([-13.661310159982044, 9.863979956913798]), + { + "landcover": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([-13.662340128243763, 9.860766590107316]), + { + "landcover": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([-13.666974985421497, 9.860428339147328]), + { + "landcover": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([-13.671094858468372, 9.857891445884547]), + { + "landcover": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([-13.670579874337513, 9.852310212005683]), + { + "landcover": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([-13.671953165353138, 9.847405413374954]), + { + "landcover": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([-13.66165348273595, 9.847236281087548]), + { + "landcover": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([-13.661481821358997, 9.851295432063562]), + { + "landcover": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([-13.658563577950794, 9.848251073512062]), + { + "landcover": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([-13.659936868966419, 9.84317708019428]), + { + "landcover": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([-13.671609842599231, 9.844361018943362]), + { + "landcover": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([-13.680021250069935, 9.842500541860387]), + { + "landcover": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([-13.681222879708606, 9.84520668687933]), + { + "landcover": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([-13.686201059640247, 9.847067148713466]), + { + "landcover": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([-13.690149271310169, 9.849096731482412]), + { + "landcover": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([-13.690492594064075, 9.851802822424787]), + { + "landcover": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([-13.684999430001575, 9.854508891171829]), + { + "landcover": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([-13.682767832101185, 9.864318204228617]), + { + "landcover": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([-13.68139454108556, 9.870237476020813]), + { + "landcover": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([-13.677789652169544, 9.864149080614622]), + { + "landcover": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([-13.67864795905431, 9.861950465733774]), + { + "landcover": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([-13.651010477364856, 9.872943393406452]), + { + "landcover": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([-13.655130350411731, 9.876833110681515]), + { + "landcover": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([-13.654443704903919, 9.884950633398141]), + { + "landcover": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([-13.648950540841419, 9.880553666792991]), + { + "landcover": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([-13.646375620187122, 9.87564928855102]), + { + "landcover": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([-13.638822519601185, 9.871083077592651]), + { + "landcover": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([-13.63744922858556, 9.868038901772325]), + { + "landcover": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([-13.633157694161731, 9.86753153639998]), + { + "landcover": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([-13.633501016915638, 9.864149080614622]), + { + "landcover": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([-13.63470264655431, 9.860428339147328]), + { + "landcover": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([-13.626806223214466, 9.862288715131701]), + { + "landcover": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([-13.630239450753528, 9.866685925709453]), + { + "landcover": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([-13.625261270821888, 9.868038901772325]), + { + "landcover": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([-13.621828043282825, 9.867024170246147]), + { + "landcover": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([-13.616678201974231, 9.865163820996548]), + { + "landcover": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([-13.623029672921497, 9.862457839700498]), + { + "landcover": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([-13.6204547522672, 9.865163820996548]), + { + "landcover": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([-13.618394815743763, 9.862119590476139]), + { + "landcover": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([-13.627321207345325, 9.861273965896487]), + { + "landcover": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([-13.630754434884388, 9.858567952663368]), + { + "landcover": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([-13.632814371407825, 9.854508891171829]), + { + "landcover": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([-13.630067789376575, 9.865163820996548]), + { + "landcover": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([-13.637792551339466, 9.866685925709453]), + { + "landcover": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([-13.645002329171497, 9.8715904374934]), + { + "landcover": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([-13.649637186349231, 9.872436035590608]), + { + "landcover": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([-13.654100382150013, 9.873281631515944]), + { + "landcover": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([-13.65289875251134, 9.879200742165947]), + { + "landcover": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([-13.653242075265247, 9.882921271500603]), + { + "landcover": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([-13.657876932442981, 9.882921271500603]), + { + "landcover": 1, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([-13.648778879464466, 9.886134422054315]), + { + "landcover": 1, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([-13.642255747140247, 9.880046320709882]), + { + "landcover": 1, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([-13.6424274085172, 9.877171344793748]), + { + "landcover": 1, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([-13.644830667794544, 9.88089189708034]), + { + "landcover": 1, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([-13.646032297433216, 9.884443294097883]), + { + "landcover": 1, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([-13.625261270821888, 9.876325758861322]), + { + "landcover": 1, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([-13.625261270821888, 9.873281631515944]), + { + "landcover": 1, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([-13.618738138497669, 9.871928676992896]), + { + "landcover": 1, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([-13.616678201974231, 9.873281631515944]), + { + "landcover": 1, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([-13.613244974435169, 9.860766590107316]), + { + "landcover": 1, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([-13.61822315436681, 9.858906205532225]), + { + "landcover": 1, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([-13.621656381905872, 9.854339762525496]), + { + "landcover": 1, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([-13.62096973639806, 9.851464562270667]), + { + "landcover": 1, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([-13.618909799874622, 9.849773256298489]), + { + "landcover": 1, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([-13.614618265450794, 9.848420205279472]), + { + "landcover": 1, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([-13.609811746896106, 9.848420205279472]), + { + "landcover": 1, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([-13.603288614571888, 9.85044977972763]), + { + "landcover": 1, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([-13.602945291817981, 9.853155859573075]), + { + "landcover": 1, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([-13.609296762765247, 9.855185404889882]), + { + "landcover": 1, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([-13.614789926827747, 9.855185404889882]), + { + "landcover": 1, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([-13.613073313058216, 9.85501627659046]), + { + "landcover": 1, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([-13.605005228341419, 9.859075331836523]), + { + "landcover": 1, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([-13.6039752600797, 9.8631343371077]), + { + "landcover": 1, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([-13.602601969064075, 9.86059746467071]), + { + "landcover": 1, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([-13.598310434640247, 9.858398826098787]), + { + "landcover": 1, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([-13.594533884347278, 9.856200172865066]), + { + "landcover": 1, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([-13.592817270577747, 9.852479341692579]), + { + "landcover": 1, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([-13.594190561593372, 9.848589336960218]), + { + "landcover": 1, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([-13.597108805001575, 9.84520668687933]), + { + "landcover": 1, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([-13.598653757394153, 9.841824002140536]), + { + "landcover": 1, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([-13.603288614571888, 9.840809189962322]), + { + "landcover": 1, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([-13.605691873849231, 9.84317708019428]), + { + "landcover": 1, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([-13.597108805001575, 9.840978325541894]), + { + "landcover": 1, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([-13.592302286446888, 9.845037553465422]), + { + "landcover": 1, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([-13.590585672677356, 9.851633692391072]), + { + "landcover": 1, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([-13.589899027169544, 9.856707555681723]), + { + "landcover": 1, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([-13.58474918586095, 9.85653842816291]), + { + "landcover": 1, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([-13.618394815743763, 9.84351534884146]), + { + "landcover": 1, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([-13.618738138497669, 9.841147461034842]), + { + "landcover": 1, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([-13.622343027413685, 9.839117829403516]), + { + "landcover": 1, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([-13.623544657052356, 9.843853617142127]), + { + "landcover": 1, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([-13.625776254952747, 9.846559751071275]), + { + "landcover": 1, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([-13.628351175607044, 9.850788040922096]), + { + "landcover": 1, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([-13.629381143868763, 9.853663247072985]), + { + "landcover": 1, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([-13.628007852853138, 9.857722318972954]), + { + "landcover": 1, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([-13.630754434884388, 9.852648471292772]), + { + "landcover": 1, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([-13.631784403146106, 9.848251073512062]), + { + "landcover": 1, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([-13.635389292062122, 9.851802822424787]), + { + "landcover": 1, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([-13.621656381905872, 9.862119590476139]), + { + "landcover": 1, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([-13.613244974435169, 9.846390618350565]), + { + "landcover": 1, + "system:index": "99" + }), + ee.Feature( + ee.Geometry.Point([-13.61221500617345, 9.841824002140536]), + { + "landcover": 1, + "system:index": "100" + }), + ee.Feature( + ee.Geometry.Point([-13.612043344796497, 9.838948692871343]), + { + "landcover": 1, + "system:index": "101" + }), + ee.Feature( + ee.Geometry.Point([-13.647062265694935, 9.837933871859953]), + { + "landcover": 1, + "system:index": "102" + }), + ee.Feature( + ee.Geometry.Point([-13.644315683663685, 9.842838811200574]), + { + "landcover": 1, + "system:index": "103" + }), + ee.Feature( + ee.Geometry.Point([-13.642770731271106, 9.839117829403516]), + { + "landcover": 1, + "system:index": "104" + }), + ee.Feature( + ee.Geometry.Point([-13.63744922858556, 9.844868419964866]), + { + "landcover": 1, + "system:index": "105" + }), + ee.Feature( + ee.Geometry.Point([-13.657876932442981, 9.858737079141173]), + { + "landcover": 1, + "system:index": "106" + }), + ee.Feature( + ee.Geometry.Point([-13.662511789620716, 9.858567952663368]), + { + "landcover": 1, + "system:index": "107" + }), + ee.Feature( + ee.Geometry.Point([-13.706800424874622, 9.85535453310259]), + { + "landcover": 1, + "system:index": "108" + }), + ee.Feature( + ee.Geometry.Point([-13.70611377936681, 9.852986730233013]), + { + "landcover": 1, + "system:index": "109" + }), + ee.Feature( + ee.Geometry.Point([-13.70559879523595, 9.850618910368206]), + { + "landcover": 1, + "system:index": "110" + }), + ee.Feature( + ee.Geometry.Point([-13.701135599435169, 9.85501627659046]), + { + "landcover": 1, + "system:index": "111" + }), + ee.Feature( + ee.Geometry.Point([-13.70010563117345, 9.864656451196232]), + { + "landcover": 1, + "system:index": "112" + }), + ee.Feature( + ee.Geometry.Point([-13.69787403327306, 9.870913957452]), + { + "landcover": 1, + "system:index": "113" + }), + ee.Feature( + ee.Geometry.Point([-13.51410768826411, 9.628911414362962]), + { + "landcover": 1, + "system:index": "114" + }), + ee.Feature( + ee.Geometry.Point([-13.512734397248485, 9.626711248582774]), + { + "landcover": 1, + "system:index": "115" + }), + ee.Feature( + ee.Geometry.Point([-13.507241233185985, 9.62518804849386]), + { + "landcover": 1, + "system:index": "116" + }), + ee.Feature( + ee.Geometry.Point([-13.506897910432079, 9.623664841537515]), + { + "landcover": 1, + "system:index": "117" + }), + ee.Feature( + ee.Geometry.Point([-13.502263053254344, 9.62620351598291]), + { + "landcover": 1, + "system:index": "118" + }), + ee.Feature( + ee.Geometry.Point([-13.513936026887157, 9.62011066527207]), + { + "landcover": 1, + "system:index": "119" + }), + ee.Feature( + ee.Geometry.Point([-13.516167624787547, 9.618248938979898]), + { + "landcover": 1, + "system:index": "120" + }), + ee.Feature( + ee.Geometry.Point([-13.510331137971141, 9.614356205426008]), + { + "landcover": 1, + "system:index": "121" + }), + ee.Feature( + ee.Geometry.Point([-13.515137656525829, 9.609955670070063]), + { + "landcover": 1, + "system:index": "122" + }), + ee.Feature( + ee.Geometry.Point([-13.509987815217235, 9.605385822784951]), + { + "landcover": 1, + "system:index": "123" + }), + ee.Feature( + ee.Geometry.Point([-13.507756217316844, 9.603354759745566]), + { + "landcover": 1, + "system:index": "124" + }), + ee.Feature( + ee.Geometry.Point([-13.505009635285594, 9.599292597123075]), + { + "landcover": 1, + "system:index": "125" + }), + ee.Feature( + ee.Geometry.Point([-13.50363634426997, 9.59573816487159]), + { + "landcover": 1, + "system:index": "126" + }), + ee.Feature( + ee.Geometry.Point([-13.50363634426997, 9.591675910937065]), + { + "landcover": 1, + "system:index": "127" + }), + ee.Feature( + ee.Geometry.Point([-13.504494651154735, 9.58744434466681]), + { + "landcover": 1, + "system:index": "128" + }), + ee.Feature( + ee.Geometry.Point([-13.507241233185985, 9.584228318994764]), + { + "landcover": 1, + "system:index": "129" + }), + ee.Feature( + ee.Geometry.Point([-13.509644492463329, 9.581858596362853]), + { + "landcover": 1, + "system:index": "130" + }), + ee.Feature( + ee.Geometry.Point([-13.511189444855907, 9.57965812481821]), + { + "landcover": 1, + "system:index": "131" + }), + ee.Feature( + ee.Geometry.Point([-13.510502799348094, 9.574749329210274]), + { + "landcover": 1, + "system:index": "132" + }), + ee.Feature( + ee.Geometry.Point([-13.509987815217235, 9.572040997815119]), + { + "landcover": 1, + "system:index": "133" + }), + ee.Feature( + ee.Geometry.Point([-13.50861452420161, 9.568317006897123]), + { + "landcover": 1, + "system:index": "134" + }), + ee.Feature( + ee.Geometry.Point([-13.509301169709422, 9.56391587411893]), + { + "landcover": 1, + "system:index": "135" + }), + ee.Feature( + ee.Geometry.Point([-13.527497275666454, 9.559514684378756]), + { + "landcover": 1, + "system:index": "136" + }), + ee.Feature( + ee.Geometry.Point([-13.530415519074657, 9.555959835714257]), + { + "landcover": 1, + "system:index": "137" + }), + ee.Feature( + ee.Geometry.Point([-13.531960471467235, 9.553082073885204]), + { + "landcover": 1, + "system:index": "138" + }), + ee.Feature( + ee.Geometry.Point([-13.538140281037547, 9.554774877907569]), + { + "landcover": 1, + "system:index": "139" + }), + ee.Feature( + ee.Geometry.Point([-13.542603476838329, 9.55511343770186]), + { + "landcover": 1, + "system:index": "140" + }), + ee.Feature( + ee.Geometry.Point([-13.547924979523875, 9.555282717472718]), + { + "landcover": 1, + "system:index": "141" + }), + ee.Feature( + ee.Geometry.Point([-13.550843222932079, 9.558668295208136]), + { + "landcover": 1, + "system:index": "142" + }), + ee.Feature( + ee.Geometry.Point([-13.554276450471141, 9.562053839256034]), + { + "landcover": 1, + "system:index": "143" + }), + ee.Feature( + ee.Geometry.Point([-13.554276450471141, 9.560191794199206]), + { + "landcover": 1, + "system:index": "144" + }), + ee.Feature( + ee.Geometry.Point([-13.54157350857661, 9.564085149510012]), + { + "landcover": 1, + "system:index": "145" + }), + ee.Feature( + ee.Geometry.Point([-13.539856894807079, 9.56069962568011]), + { + "landcover": 1, + "system:index": "146" + }), + ee.Feature( + ee.Geometry.Point([-13.53934191067622, 9.564931525201379]), + { + "landcover": 1, + "system:index": "147" + }), + ee.Feature( + ee.Geometry.Point([-13.542603476838329, 9.561038179579535]), + { + "landcover": 1, + "system:index": "148" + }), + ee.Feature( + ee.Geometry.Point([-13.548954947785594, 9.566116447629842]), + { + "landcover": 1, + "system:index": "149" + }), + ee.Feature( + ee.Geometry.Point([-13.554104789094188, 9.56899409919021]), + { + "landcover": 1, + "system:index": "150" + }), + ee.Feature( + ee.Geometry.Point([-13.55753801663325, 9.568655553212261]), + { + "landcover": 1, + "system:index": "151" + }), + ee.Feature( + ee.Geometry.Point([-13.560112937287547, 9.57068682402128]), + { + "landcover": 1, + "system:index": "152" + }), + ee.Feature( + ee.Geometry.Point([-13.587150488427461, 9.588802244505368]), + { + "landcover": 1, + "system:index": "153" + }), + ee.Feature( + ee.Geometry.Point([-13.570670996239961, 9.591510442157333]), + { + "landcover": 1, + "system:index": "154" + }), + ee.Feature( + ee.Geometry.Point([-13.575820837548555, 9.59591121720367]), + { + "landcover": 1, + "system:index": "155" + }), + ee.Feature( + ee.Geometry.Point([-13.575820837548555, 9.607082158693155]), + { + "landcover": 1, + "system:index": "156" + }), + ee.Feature( + ee.Geometry.Point([-13.57994071059543, 9.608436187164969]), + { + "landcover": 1, + "system:index": "157" + }), + ee.Feature( + ee.Geometry.Point([-13.566894445946993, 9.610128715137005]), + { + "landcover": 1, + "system:index": "158" + }), + ee.Feature( + ee.Geometry.Point([-13.56071463637668, 9.613513745683104]), + { + "landcover": 1, + "system:index": "159" + }), + ee.Feature( + ee.Geometry.Point([-13.55796805434543, 9.615206248254303]), + { + "landcover": 1, + "system:index": "160" + }), + ee.Feature( + ee.Geometry.Point([-13.562774572900118, 9.610128715137005]), + { + "landcover": 1, + "system:index": "161" + }), + ee.Feature( + ee.Geometry.Point([-13.562087927392305, 9.60437408550142]), + { + "landcover": 1, + "system:index": "162" + }), + ee.Feature( + ee.Geometry.Point([-13.559341345361055, 9.599296389893185]), + { + "landcover": 1, + "system:index": "163" + }), + ee.Feature( + ee.Geometry.Point([-13.558998022607149, 9.594895658802585]), + { + "landcover": 1, + "system:index": "164" + }), + ee.Feature( + ee.Geometry.Point([-13.558654699853243, 9.589817821159402]), + { + "landcover": 1, + "system:index": "165" + }), + ee.Feature( + ee.Geometry.Point([-13.560371313622774, 9.586094025227984]), + { + "landcover": 1, + "system:index": "166" + }), + ee.Feature( + ee.Geometry.Point([-13.564147863915743, 9.59320305470555]), + { + "landcover": 1, + "system:index": "167" + }), + ee.Feature( + ee.Geometry.Point([-13.568611059716524, 9.590494870572455]), + { + "landcover": 1, + "system:index": "168" + }), + ee.Feature( + ee.Geometry.Point([-13.525695715478243, 9.592526010700317]), + { + "landcover": 1, + "system:index": "169" + }), + ee.Feature( + ee.Geometry.Point([-13.52775565200168, 9.595234178607734]), + { + "landcover": 1, + "system:index": "170" + }), + ee.Feature( + ee.Geometry.Point([-13.52775565200168, 9.588802244505368]), + { + "landcover": 1, + "system:index": "171" + }), + ee.Feature( + ee.Geometry.Point([-13.529815588525118, 9.584739907481588]), + { + "landcover": 1, + "system:index": "172" + }), + ee.Feature( + ee.Geometry.Point([-13.525695715478243, 9.581693122794402]), + { + "landcover": 1, + "system:index": "173" + }), + ee.Feature( + ee.Geometry.Point([-13.53324881606418, 9.595234178607734]), + { + "landcover": 1, + "system:index": "174" + }), + ee.Feature( + ee.Geometry.Point([-13.51402274184543, 9.608436187164969]), + { + "landcover": 1, + "system:index": "175" + }), + ee.Feature( + ee.Geometry.Point([-13.498229895165743, 9.649731449891549]), + { + "landcover": 1, + "system:index": "176" + }), + ee.Feature( + ee.Geometry.Point([-13.49754324965793, 9.656839140978562]), + { + "landcover": 1, + "system:index": "177" + }), + ee.Feature( + ee.Geometry.Point([-13.502693090966524, 9.670377185054937]), + { + "landcover": 1, + "system:index": "178" + }), + ee.Feature( + ee.Geometry.Point([-13.43711844497043, 9.683237822077341]), + { + "landcover": 1, + "system:index": "179" + }), + ee.Feature( + ee.Geometry.Point([-13.435745153954805, 9.682560958718609]), + { + "landcover": 1, + "system:index": "180" + }), + ee.Feature( + ee.Geometry.Point([-13.436088476708711, 9.678499749919098]), + { + "landcover": 1, + "system:index": "181" + }), + ee.Feature( + ee.Geometry.Point([-13.43986502700168, 9.672069402255028]), + { + "landcover": 1, + "system:index": "182" + }), + ee.Feature( + ee.Geometry.Point([-13.464240942529024, 9.658869882308721]), + { + "landcover": 1, + "system:index": "183" + }), + ee.Feature( + ee.Geometry.Point([-13.447418127587618, 9.609620957634213]), + { + "landcover": 1, + "system:index": "184" + }), + ee.Feature( + ee.Geometry.Point([-13.457374487450899, 9.61622174573161]), + { + "landcover": 1, + "system:index": "185" + }), + ee.Feature( + ee.Geometry.Point([-13.455314550927461, 9.613682996321328]), + { + "landcover": 1, + "system:index": "186" + }), + ee.Feature( + ee.Geometry.Point([-13.45308295302707, 9.613175244152618]), + { + "landcover": 1, + "system:index": "187" + }), + ee.Feature( + ee.Geometry.Point([-13.45685950332004, 9.607589920004852]), + { + "landcover": 1, + "system:index": "188" + }), + ee.Feature( + ee.Geometry.Point([-13.456687841943086, 9.601835247213083]), + { + "landcover": 1, + "system:index": "189" + }), + ee.Feature( + ee.Geometry.Point([-13.459949408105196, 9.59997342037242]), + { + "landcover": 1, + "system:index": "190" + }), + ee.Feature( + ee.Geometry.Point([-13.46235266738254, 9.601665990650465]), + { + "landcover": 1, + "system:index": "191" + }), + ee.Feature( + ee.Geometry.Point([-13.487586889794649, 9.647362186207621]), + { + "landcover": 1, + "system:index": "192" + }), + ee.Feature( + ee.Geometry.Point([-13.477115545800508, 9.669700295790179]), + { + "landcover": 1, + "system:index": "193" + }), + ee.Feature( + ee.Geometry.Point([-13.500118170312227, 9.668684959338288]), + { + "landcover": 1, + "system:index": "194" + }), + ee.Feature( + ee.Geometry.Point([-13.516597662499727, 9.616390995014688]), + { + "landcover": 1, + "system:index": "195" + }), + ee.Feature( + ee.Geometry.Point([-13.49256506972629, 9.621637680767956]), + { + "landcover": 1, + "system:index": "196" + }), + ee.Feature( + ee.Geometry.Point([-13.495998297265352, 9.622991650968471]), + { + "landcover": 1, + "system:index": "197" + }), + ee.Feature( + ee.Geometry.Point([-13.488616858056368, 9.618083483186357]), + { + "landcover": 1, + "system:index": "198" + }), + ee.Feature( + ee.Geometry.Point([-13.517627630761446, 9.640254295246155]), + { + "landcover": 1, + "system:index": "199" + }), + ee.Feature( + ee.Geometry.Point([-13.521575842431368, 9.643131316780002]), + { + "landcover": 1, + "system:index": "200" + }), + ee.Feature( + ee.Geometry.Point([-13.520202551415743, 9.639577345436397]), + { + "landcover": 1, + "system:index": "201" + }), + ee.Feature( + ee.Geometry.Point([-13.52003089003879, 9.638054203397656]), + { + "landcover": 1, + "system:index": "202" + }), + ee.Feature( + ee.Geometry.Point([-13.531360540917696, 9.756500193416775]), + { + "landcover": 1, + "system:index": "203" + }), + ee.Feature( + ee.Geometry.Point([-13.529815588525118, 9.752947423648195]), + { + "landcover": 1, + "system:index": "204" + }), + ee.Feature( + ee.Geometry.Point([-13.527583990624727, 9.74939461601333]), + { + "landcover": 1, + "system:index": "205" + }), + ee.Feature( + ee.Geometry.Point([-13.52500906997043, 9.752270701303399]), + { + "landcover": 1, + "system:index": "206" + }), + ee.Feature( + ee.Geometry.Point([-13.521232519677461, 9.756161836022985]), + { + "landcover": 1, + "system:index": "207" + }), + ee.Feature( + ee.Geometry.Point([-13.518829260400118, 9.759037862917843]), + { + "landcover": 1, + "system:index": "208" + }), + ee.Feature( + ee.Geometry.Point([-13.52449408583957, 9.759037862917843]), + { + "landcover": 1, + "system:index": "209" + }), + ee.Feature( + ee.Geometry.Point([-13.527583990624727, 9.756838550466977]), + { + "landcover": 1, + "system:index": "210" + }), + ee.Feature( + ee.Geometry.Point([-13.528098974755586, 9.760560455339853]), + { + "landcover": 1, + "system:index": "211" + }), + ee.Feature( + ee.Geometry.Point([-13.530158911279024, 9.76495901656875]), + { + "landcover": 1, + "system:index": "212" + }), + ee.Feature( + ee.Geometry.Point([-13.528785620263399, 9.766481581917269]), + { + "landcover": 1, + "system:index": "213" + }), + ee.Feature( + ee.Geometry.Point([-13.525867376855196, 9.769019175354734]), + { + "landcover": 1, + "system:index": "214" + }), + ee.Feature( + ee.Geometry.Point([-13.524150763085665, 9.770710893563262]), + { + "landcover": 1, + "system:index": "215" + }), + ee.Feature( + ee.Geometry.Point([-13.52552405410129, 9.767496621613954]), + { + "landcover": 1, + "system:index": "216" + }), + ee.Feature( + ee.Geometry.Point([-13.522434149316133, 9.769188347562617]), + { + "landcover": 1, + "system:index": "217" + }), + ee.Feature( + ee.Geometry.Point([-13.519344244530977, 9.76698910215254]), + { + "landcover": 1, + "system:index": "218" + }), + ee.Feature( + ee.Geometry.Point([-13.519344244530977, 9.765635713138927]), + { + "landcover": 1, + "system:index": "219" + }), + ee.Feature( + ee.Geometry.Point([-13.515567694238008, 9.76326726912586]), + { + "landcover": 1, + "system:index": "220" + }), + ee.Feature( + ee.Geometry.Point([-13.51453772597629, 9.760898808266235]), + { + "landcover": 1, + "system:index": "221" + }), + ee.Feature( + ee.Geometry.Point([-13.511447821191133, 9.76242139218114]), + { + "landcover": 1, + "system:index": "222" + }), + ee.Feature( + ee.Geometry.Point([-13.512134466698946, 9.764789842211282]), + { + "landcover": 1, + "system:index": "223" + }), + ee.Feature( + ee.Geometry.Point([-13.51127615981418, 9.768004140301493]), + { + "landcover": 1, + "system:index": "224" + }), + ee.Feature( + ee.Geometry.Point([-13.514194403222383, 9.77054172212945]), + { + "landcover": 1, + "system:index": "225" + }), + ee.Feature( + ee.Geometry.Point([-13.516940985253633, 9.768680830680962]), + { + "landcover": 1, + "system:index": "226" + }), + ee.Feature( + ee.Geometry.Point([-13.518142614892305, 9.77240260317031]), + { + "landcover": 1, + "system:index": "227" + }), + ee.Feature( + ee.Geometry.Point([-13.521575842431368, 9.774094304174467]), + { + "landcover": 1, + "system:index": "228" + }), + ee.Feature( + ee.Geometry.Point([-13.520202551415743, 9.773925134461207]), + { + "landcover": 1, + "system:index": "229" + }), + ee.Feature( + ee.Geometry.Point([-13.526382360986055, 9.766650755415005]), + { + "landcover": 1, + "system:index": "230" + }), + ee.Feature( + ee.Geometry.Point([-13.531360540917696, 9.763774794261284]), + { + "landcover": 1, + "system:index": "231" + }), + ee.Feature( + ee.Geometry.Point([-13.525180731347383, 9.75819197523183]), + { + "landcover": 1, + "system:index": "232" + }), + ee.Feature( + ee.Geometry.Point([-13.522434149316133, 9.756161836022985]), + { + "landcover": 1, + "system:index": "233" + }), + ee.Feature( + ee.Geometry.Point([-13.524150763085665, 9.75210152050255]), + { + "landcover": 1, + "system:index": "234" + }), + ee.Feature( + ee.Geometry.Point([-13.536167059472383, 9.74973298027629]), + { + "landcover": 1, + "system:index": "235" + }), + ee.Feature( + ee.Geometry.Point([-13.537025366357149, 9.746010954502083]), + { + "landcover": 1, + "system:index": "236" + }), + ee.Feature( + ee.Geometry.Point([-13.538055334618868, 9.74347318584398]), + { + "landcover": 1, + "system:index": "237" + }), + ee.Feature( + ee.Geometry.Point([-13.538913641503633, 9.741273770727341]), + { + "landcover": 1, + "system:index": "238" + }), + ee.Feature( + ee.Geometry.Point([-13.536682043603243, 9.740935397884376]), + { + "landcover": 1, + "system:index": "239" + }), + ee.Feature( + ee.Geometry.Point([-13.53548041396457, 9.743811556113686]), + { + "landcover": 1, + "system:index": "240" + }), + ee.Feature( + ee.Geometry.Point([-13.534450445702852, 9.747026056559818]), + { + "landcover": 1, + "system:index": "241" + }), + ee.Feature( + ee.Geometry.Point([-13.532562170556368, 9.74550340231482]), + { + "landcover": 1, + "system:index": "242" + }), + ee.Feature( + ee.Geometry.Point([-13.52998724990207, 9.744149926040262]), + { + "landcover": 1, + "system:index": "243" + }), + ee.Feature( + ee.Geometry.Point([-13.526897345116915, 9.744319110874857]), + { + "landcover": 1, + "system:index": "244" + }), + ee.Feature( + ee.Geometry.Point([-13.524322424462618, 9.74465748028668]), + { + "landcover": 1, + "system:index": "245" + }), + ee.Feature( + ee.Geometry.Point([-13.523807440331758, 9.742458072976037]), + { + "landcover": 1, + "system:index": "246" + }), + ee.Feature( + ee.Geometry.Point([-13.523807440331758, 9.740258651169293]), + { + "landcover": 1, + "system:index": "247" + }), + ee.Feature( + ee.Geometry.Point([-13.528613958886446, 9.735521385749621]), + { + "landcover": 1, + "system:index": "248" + }), + ee.Feature( + ee.Geometry.Point([-13.532562170556368, 9.73670570840598]), + { + "landcover": 1, + "system:index": "249" + }), + ee.Feature( + ee.Geometry.Point([-13.533077154687227, 9.740766211334252]), + { + "landcover": 1, + "system:index": "250" + }), + ee.Feature( + ee.Geometry.Point([-13.532390509179415, 9.742458072976037]), + { + "landcover": 1, + "system:index": "251" + }), + ee.Feature( + ee.Geometry.Point([-13.529472265771211, 9.742119701333845]), + { + "landcover": 1, + "system:index": "252" + }), + ee.Feature( + ee.Geometry.Point([-13.527412329247774, 9.741950515384083]), + { + "landcover": 1, + "system:index": "253" + }), + ee.Feature( + ee.Geometry.Point([-13.52998724990207, 9.740597024698355]), + { + "landcover": 1, + "system:index": "254" + }), + ee.Feature( + ee.Geometry.Point([-13.526725683739961, 9.740597024698355]), + { + "landcover": 1, + "system:index": "255" + }), + ee.Feature( + ee.Geometry.Point([-13.581828985741915, 9.75430086421618]), + { + "landcover": 1, + "system:index": "256" + }), + ee.Feature( + ee.Geometry.Point([-13.581828985741915, 9.753116604019736]), + { + "landcover": 1, + "system:index": "257" + }), + ee.Feature( + ee.Geometry.Point([-13.585090551904024, 9.753285784305413]), + { + "landcover": 1, + "system:index": "258" + }), + ee.Feature( + ee.Geometry.Point([-13.585262213280977, 9.7510864338945]), + { + "landcover": 1, + "system:index": "259" + }), + ee.Feature( + ee.Geometry.Point([-13.584747229150118, 9.750240526026937]), + { + "landcover": 1, + "system:index": "260" + }), + ee.Feature( + ee.Geometry.Point([-13.55470648818332, 9.730276477790866]), + { + "landcover": 1, + "system:index": "261" + }), + ee.Feature( + ee.Geometry.Point([-13.553333197167696, 9.727400202985306]), + { + "landcover": 1, + "system:index": "262" + }), + ee.Feature( + ee.Geometry.Point([-13.554534826806368, 9.72587745924342]), + { + "landcover": 1, + "system:index": "263" + }), + ee.Feature( + ee.Geometry.Point([-13.541316900780977, 9.72587745924342]), + { + "landcover": 1, + "system:index": "264" + }), + ee.Feature( + ee.Geometry.Point([-13.542861853173555, 9.729430517182633]), + { + "landcover": 1, + "system:index": "265" + }), + ee.Feature( + ee.Geometry.Point([-13.542346869042696, 9.731968392581692]), + { + "landcover": 1, + "system:index": "266" + }), + ee.Feature( + ee.Geometry.Point([-13.53874198012668, 9.731968392581692]), + { + "landcover": 1, + "system:index": "267" + }), + ee.Feature( + ee.Geometry.Point([-13.537883673241915, 9.728753747154048]), + { + "landcover": 1, + "system:index": "268" + }), + ee.Feature( + ee.Geometry.Point([-13.535308752587618, 9.727400202985306]), + { + "landcover": 1, + "system:index": "269" + }), + ee.Feature( + ee.Geometry.Point([-13.534450445702852, 9.731460819044104]), + { + "landcover": 1, + "system:index": "270" + }), + ee.Feature( + ee.Geometry.Point([-13.534622107079805, 9.734167868999362]), + { + "landcover": 1, + "system:index": "271" + }), + ee.Feature( + ee.Geometry.Point([-13.540115271142305, 9.737720838768078]), + { + "landcover": 1, + "system:index": "272" + }), + ee.Feature( + ee.Geometry.Point([-13.543205175927461, 9.73941271584591]), + { + "landcover": 1, + "system:index": "273" + }), + ee.Feature( + ee.Geometry.Point([-13.551444922021211, 9.76512819084024]), + { + "landcover": 1, + "system:index": "274" + }), + ee.Feature( + ee.Geometry.Point([-13.556423101952852, 9.762252216534353]), + { + "landcover": 1, + "system:index": "275" + }), + ee.Feature( + ee.Geometry.Point([-13.55195990615207, 9.76326726912586]), + { + "landcover": 1, + "system:index": "276" + }), + ee.Feature( + ee.Geometry.Point([-13.548355017236055, 9.768004140301493]), + { + "landcover": 1, + "system:index": "277" + }), + ee.Feature( + ee.Geometry.Point([-13.54749671035129, 9.77240260317031]), + { + "landcover": 1, + "system:index": "278" + }), + ee.Feature( + ee.Geometry.Point([-13.545608435204805, 9.764451493238456]), + { + "landcover": 1, + "system:index": "279" + }), + ee.Feature( + ee.Geometry.Point([-13.538398657372774, 9.759037862917843]), + { + "landcover": 1, + "system:index": "280" + }), + ee.Feature( + ee.Geometry.Point([-13.539085302880586, 9.75700772886324]), + { + "landcover": 1, + "system:index": "281" + }), + ee.Feature( + ee.Geometry.Point([-13.544921789696993, 9.74837952116449]), + { + "landcover": 1, + "system:index": "282" + }), + ee.Feature( + ee.Geometry.Point([-13.54749671035129, 9.74550340231482]), + { + "landcover": 1, + "system:index": "283" + }), + ee.Feature( + ee.Geometry.Point([-13.552303228905977, 9.74465748028668]), + { + "landcover": 1, + "system:index": "284" + }), + ee.Feature( + ee.Geometry.Point([-13.555908117821993, 9.747026056559818]), + { + "landcover": 1, + "system:index": "285" + }), + ee.Feature( + ee.Geometry.Point([-13.654785070946993, 9.909740584973962]), + { + "landcover": 1, + "system:index": "286" + }), + ee.Feature( + ee.Geometry.Point([-13.650321875146211, 9.90940238439265]), + { + "landcover": 1, + "system:index": "287" + }), + ee.Feature( + ee.Geometry.Point([-13.652381811669649, 9.908049578580023]), + { + "landcover": 1, + "system:index": "288" + }), + ee.Feature( + ee.Geometry.Point([-13.671951208642305, 9.897903357197523]), + { + "landcover": 1, + "system:index": "289" + }), + ee.Feature( + ee.Geometry.Point([-13.674011145165743, 9.893168346572097]), + { + "landcover": 1, + "system:index": "290" + }), + ee.Feature( + ee.Geometry.Point([-13.675727758935274, 9.889786154339548]), + { + "landcover": 1, + "system:index": "291" + }), + ee.Feature( + ee.Geometry.Point([-13.670234594872774, 9.886065702680298]), + { + "landcover": 1, + "system:index": "292" + }), + ee.Feature( + ee.Geometry.Point([-13.67057791762668, 9.88302166546021]), + { + "landcover": 1, + "system:index": "293" + }), + ee.Feature( + ee.Geometry.Point([-13.674011145165743, 9.880315830943365]), + { + "landcover": 1, + "system:index": "294" + }), + ee.Feature( + ee.Geometry.Point([-13.67057791762668, 9.876933506499089]), + { + "landcover": 1, + "system:index": "295" + }), + ee.Feature( + ee.Geometry.Point([-13.672981176904024, 9.873551147289685]), + { + "landcover": 1, + "system:index": "296" + }), + ee.Feature( + ee.Geometry.Point([-13.687400732568086, 9.874904095144537]), + { + "landcover": 1, + "system:index": "297" + }), + ee.Feature( + ee.Geometry.Point([-13.649388511149061, 9.835897848162661]), + { + "landcover": 1, + "system:index": "298" + }), + ee.Feature( + ee.Geometry.Point([-13.643637855021131, 9.837504656559055]), + { + "landcover": 1, + "system:index": "299" + }), + ee.Feature( + ee.Geometry.Point([-13.65016098734535, 9.832853347671694]), + { + "landcover": 1, + "system:index": "300" + }), + ee.Feature( + ee.Geometry.Point([-13.651105124918592, 9.82913225343917]), + { + "landcover": 1, + "system:index": "301" + }), + ee.Feature( + ee.Geometry.Point([-13.64767189737953, 9.824988258312377]), + { + "landcover": 1, + "system:index": "302" + }), + ee.Feature( + ee.Geometry.Point([-13.644496161905897, 9.822789382675966]), + { + "landcover": 1, + "system:index": "303" + }), + ee.Feature( + ee.Geometry.Point([-13.643981177775037, 9.824988258312377]), + { + "landcover": 1, + "system:index": "304" + }), + ee.Feature( + ee.Geometry.Point([-13.644238669840467, 9.822451092819612]), + { + "landcover": 1, + "system:index": "305" + }), + ee.Feature( + ee.Geometry.Point([-13.645096976725233, 9.826172262217474]), + { + "landcover": 1, + "system:index": "306" + }), + ee.Feature( + ee.Geometry.Point([-13.635655600992811, 9.82676426258091]), + { + "landcover": 1, + "system:index": "307" + }), + ee.Feature( + ee.Geometry.Point([-13.633338172403944, 9.825411117336346]), + { + "landcover": 1, + "system:index": "308" + }), + ee.Feature( + ee.Geometry.Point([-13.630763251749647, 9.82591854745168]), + { + "landcover": 1, + "system:index": "309" + }), + ee.Feature( + ee.Geometry.Point([-13.631020743815077, 9.82388882232074]), + { + "landcover": 1, + "system:index": "310" + }), + ee.Feature( + ee.Geometry.Point([-13.629046637980116, 9.82591854745168]), + { + "landcover": 1, + "system:index": "311" + }), + ee.Feature( + ee.Geometry.Point([-13.623725135294569, 9.835982417220407]), + { + "landcover": 1, + "system:index": "312" + }), + ee.Feature( + ee.Geometry.Point([-13.623639304606092, 9.834206462463124]), + { + "landcover": 1, + "system:index": "313" + }), + ee.Feature( + ee.Geometry.Point([-13.618746955362928, 9.832937917508435]), + { + "landcover": 1, + "system:index": "314" + }), + ee.Feature( + ee.Geometry.Point([-13.614283759562147, 9.835644140859554]), + { + "landcover": 1, + "system:index": "315" + }), + ee.Feature( + ee.Geometry.Point([-13.610678870646131, 9.837420087890889]), + { + "landcover": 1, + "system:index": "316" + }), + ee.Feature( + ee.Geometry.Point([-13.599435050455702, 9.832599638031681]), + { + "landcover": 1, + "system:index": "317" + }), + ee.Feature( + ee.Geometry.Point([-13.602009971109998, 9.831838507943388]), + { + "landcover": 1, + "system:index": "318" + }), + ee.Feature( + ee.Geometry.Point([-13.605185706583631, 9.831753937825424]), + { + "landcover": 1, + "system:index": "319" + }), + ee.Feature( + ee.Geometry.Point([-13.60844727274574, 9.831500227341687]), + { + "landcover": 1, + "system:index": "320" + }), + ee.Feature( + ee.Geometry.Point([-13.610249717203748, 9.830739094722384]), + { + "landcover": 1, + "system:index": "321" + }), + ee.Feature( + ee.Geometry.Point([-13.611022193400037, 9.82955510716544]), + { + "landcover": 1, + "system:index": "322" + }), + ee.Feature( + ee.Geometry.Point([-13.612052161661756, 9.827948260129261]), + { + "landcover": 1, + "system:index": "323" + }), + ee.Feature( + ee.Geometry.Point([-13.612652976481092, 9.825749404166388]), + { + "landcover": 1, + "system:index": "324" + }), + ee.Feature( + ee.Geometry.Point([-13.611365516153944, 9.822958527474464]), + { + "landcover": 1, + "system:index": "325" + }), + ee.Feature( + ee.Geometry.Point([-13.607159812418592, 9.82092878418678]), + { + "landcover": 1, + "system:index": "326" + }), + ee.Feature( + ee.Geometry.Point([-13.606558997599256, 9.82371967799777]), + { + "landcover": 1, + "system:index": "327" + }), + ee.Feature( + ee.Geometry.Point([-13.608876426188123, 9.826510548269171]), + { + "landcover": 1, + "system:index": "328" + }), + ee.Feature( + ee.Geometry.Point([-13.606558997599256, 9.829470536463448]), + { + "landcover": 1, + "system:index": "329" + }), + ee.Feature( + ee.Geometry.Point([-13.60295410868324, 9.828709399172217]), + { + "landcover": 1, + "system:index": "330" + }), + ee.Feature( + ee.Geometry.Point([-13.60123749491371, 9.830400812995848]), + { + "landcover": 1, + "system:index": "331" + }), + ee.Feature( + ee.Geometry.Point([-13.601838309733045, 9.827863689016356]), + { + "landcover": 1, + "system:index": "332" + }), + ee.Feature( + ee.Geometry.Point([-13.599778373209608, 9.831161946393877]), + { + "landcover": 1, + "system:index": "333" + }), + ee.Feature( + ee.Geometry.Point([-13.601151664225233, 9.827440833127513]), + { + "landcover": 1, + "system:index": "334" + }), + ee.Feature( + ee.Geometry.Point([-13.605099875895155, 9.820167627244706]), + { + "landcover": 1, + "system:index": "335" + }), + ee.Feature( + ee.Geometry.Point([-13.557979365634356, 9.739303420698274]), + { + "landcover": 1, + "system:index": "336" + }), + ee.Feature( + ee.Geometry.Point([-13.531028529452716, 9.733720191979573]), + { + "landcover": 1, + "system:index": "337" + }), + ee.Feature( + ee.Geometry.Point([-13.530856868075762, 9.731520712614177]), + { + "landcover": 1, + "system:index": "338" + }), + ee.Feature( + ee.Geometry.Point([-13.526050349521075, 9.736596412372151]), + { + "landcover": 1, + "system:index": "339" + }), + ee.Feature( + ee.Geometry.Point([-13.999500577660426, 10.035249558065319]), + { + "landcover": 1, + "system:index": "340" + }), + ee.Feature( + ee.Geometry.Point([-13.995724027367457, 10.039644440416982]), + { + "landcover": 1, + "system:index": "341" + }), + ee.Feature( + ee.Geometry.Point([-14.000530545922144, 10.0437012019244]), + { + "landcover": 1, + "system:index": "342" + }), + ee.Feature( + ee.Geometry.Point([-13.993320768090113, 10.056209229570396]), + { + "landcover": 1, + "system:index": "343" + }), + ee.Feature( + ee.Geometry.Point([-13.990574186058863, 10.06060382706283]), + { + "landcover": 1, + "system:index": "344" + }), + ee.Feature( + ee.Geometry.Point([-13.965854947777613, 10.049448193638165]), + { + "landcover": 1, + "system:index": "345" + }), + ee.Feature( + ee.Geometry.Point([-13.954525296898707, 10.051138465880086]), + { + "landcover": 1, + "system:index": "346" + }), + ee.Feature( + ee.Geometry.Point([-13.946628873558863, 10.066012480342117]), + { + "landcover": 1, + "system:index": "347" + }), + ee.Feature( + ee.Geometry.Point([-13.93598586818777, 10.064998364754487]), + { + "landcover": 1, + "system:index": "348" + }), + ee.Feature( + ee.Geometry.Point([-13.964824979515894, 10.049448193638165]), + { + "landcover": 1, + "system:index": "349" + }), + ee.Feature( + ee.Geometry.Point([-13.96619827053152, 10.045391504205845]), + { + "landcover": 1, + "system:index": "350" + }), + ee.Feature( + ee.Geometry.Point([-13.955898587914332, 10.044039263087305]), + { + "landcover": 1, + "system:index": "351" + }), + ee.Feature( + ee.Geometry.Point([-13.947315519066676, 10.041334763892895]), + { + "landcover": 1, + "system:index": "352" + }), + ee.Feature( + ee.Geometry.Point([-13.947315519066676, 10.036939904492623]), + { + "landcover": 1, + "system:index": "353" + }), + ee.Feature( + ee.Geometry.Point([-13.9431956460198, 10.028488084121358]), + { + "landcover": 1, + "system:index": "354" + }), + ee.Feature( + ee.Geometry.Point([-13.938045804711207, 10.021050299807792]), + { + "landcover": 1, + "system:index": "355" + }), + ee.Feature( + ee.Geometry.Point([-13.935642545433863, 10.027135772396795]), + { + "landcover": 1, + "system:index": "356" + }), + ee.Feature( + ee.Geometry.Point([-13.932552640648707, 10.033221130703813]), + { + "landcover": 1, + "system:index": "357" + }), + ee.Feature( + ee.Geometry.Point([-14.0200999428948, 10.093730404886111]), + { + "landcover": 1, + "system:index": "358" + }), + ee.Feature( + ee.Geometry.Point([-14.020786588402613, 10.084604034450745]), + { + "landcover": 1, + "system:index": "359" + }), + ee.Feature( + ee.Geometry.Point([-14.021473233910426, 10.077505567574326]), + { + "landcover": 1, + "system:index": "360" + }), + ee.Feature( + ee.Geometry.Point([-14.024906461449488, 10.067364629502437]), + { + "landcover": 1, + "system:index": "361" + }), + ee.Feature( + ee.Geometry.Point([-14.026279752465113, 10.055871181133208]), + { + "landcover": 1, + "system:index": "362" + }), + ee.Feature( + ee.Geometry.Point([-14.030056302758082, 10.051814572302199]), + { + "landcover": 1, + "system:index": "363" + }), + ee.Feature( + ee.Geometry.Point([-14.0255931069573, 10.043025078538774]), + { + "landcover": 1, + "system:index": "364" + }), + ee.Feature( + ee.Geometry.Point([-14.030399625511988, 10.042687016316068]), + { + "landcover": 1, + "system:index": "365" + }), + ee.Feature( + ee.Geometry.Point([-14.023533170433863, 10.03896830855453]), + { + "landcover": 1, + "system:index": "366" + }), + ee.Feature( + ee.Geometry.Point([-14.022503202172144, 10.054518983847622]), + { + "landcover": 1, + "system:index": "367" + }), + ee.Feature( + ee.Geometry.Point([-14.027309720726832, 10.053842883082915]), + { + "landcover": 1, + "system:index": "368" + }), + ee.Feature( + ee.Geometry.Point([-14.034519498558863, 10.05722337275972]), + { + "landcover": 1, + "system:index": "369" + }), + ee.Feature( + ee.Geometry.Point([-14.040699308129176, 10.06060382706283]), + { + "landcover": 1, + "system:index": "370" + }), + ee.Feature( + ee.Geometry.Point([-14.042759244652613, 10.051814572302199]), + { + "landcover": 1, + "system:index": "371" + }), + ee.Feature( + ee.Geometry.Point([-14.042415921898707, 10.07277316948383]), + { + "landcover": 1, + "system:index": "372" + }), + ee.Feature( + ee.Geometry.Point([-14.039669339867457, 10.079533716921128]), + { + "landcover": 1, + "system:index": "373" + }), + ee.Feature( + ee.Geometry.Point([-14.036922757836207, 10.081899875029649]), + { + "landcover": 1, + "system:index": "374" + }), + ee.Feature( + ee.Geometry.Point([-14.03383285305105, 10.075477405468384]), + { + "landcover": 1, + "system:index": "375" + }), + ee.Feature( + ee.Geometry.Point([-14.035206144066676, 10.072435138391462]), + { + "landcover": 1, + "system:index": "376" + }), + ee.Feature( + ee.Geometry.Point([-14.032802884789332, 10.070068910826576]), + { + "landcover": 1, + "system:index": "377" + }), + ee.Feature( + ee.Geometry.Point([-14.029026334496363, 10.068378737654886]), + { + "landcover": 1, + "system:index": "378" + }), + ee.Feature( + ee.Geometry.Point([-14.0255931069573, 10.091026322094907]), + { + "landcover": 1, + "system:index": "379" + }), + ee.Feature( + ee.Geometry.Point([-14.042415921898707, 10.10927843988686]), + { + "landcover": 1, + "system:index": "380" + }), + ee.Feature( + ee.Geometry.Point([-14.046879117699488, 10.108264460521394]), + { + "landcover": 1, + "system:index": "381" + }), + ee.Feature( + ee.Geometry.Point([-14.051685636254176, 10.106574487803298]), + { + "landcover": 1, + "system:index": "382" + }), + ee.Feature( + ee.Geometry.Point([-14.057865445824488, 10.10454650881349]), + { + "landcover": 1, + "system:index": "383" + }), + ee.Feature( + ee.Geometry.Point([-14.059925382347926, 10.123473814924237]), + { + "landcover": 1, + "system:index": "384" + }), + ee.Feature( + ee.Geometry.Point([-14.06232864162527, 10.117728143481251]), + { + "landcover": 1, + "system:index": "385" + }), + ee.Feature( + ee.Geometry.Point([-14.064731900902613, 10.114348288716734]), + { + "landcover": 1, + "system:index": "386" + }), + ee.Feature( + ee.Geometry.Point([-14.06507522365652, 10.110968398385992]), + { + "landcover": 1, + "system:index": "387" + }), + ee.Feature( + ee.Geometry.Point([-14.060268705101832, 10.115362248881063]), + { + "landcover": 1, + "system:index": "388" + }), + ee.Feature( + ee.Geometry.Point([-14.054432218285426, 10.115700234891127]), + { + "landcover": 1, + "system:index": "389" + }), + ee.Feature( + ee.Geometry.Point([-14.052028959008082, 10.117052175374186]), + { + "landcover": 1, + "system:index": "390" + }), + ee.Feature( + ee.Geometry.Point([-14.0365794350823, 10.126853573603118]), + { + "landcover": 1, + "system:index": "391" + }), + ee.Feature( + ee.Geometry.Point([-14.035892789574488, 10.122797858916474]), + { + "landcover": 1, + "system:index": "392" + }), + ee.Feature( + ee.Geometry.Point([-14.030742948265894, 10.12752952106626]), + { + "landcover": 1, + "system:index": "393" + }), + ee.Feature( + ee.Geometry.Point([-14.023189847679957, 10.12482572266808]), + { + "landcover": 1, + "system:index": "394" + }), + ee.Feature( + ee.Geometry.Point([-14.0200999428948, 10.125501674403939]), + { + "landcover": 1, + "system:index": "395" + }), + ee.Feature( + ee.Geometry.Point([-14.040012662621363, 10.12482572266808]), + { + "landcover": 1, + "system:index": "396" + }), + ee.Feature( + ee.Geometry.Point([-14.041729276390894, 10.130233296673653]), + { + "landcover": 1, + "system:index": "397" + }), + ee.Feature( + ee.Geometry.Point([-14.025249784203394, 10.117052175374186]), + { + "landcover": 1, + "system:index": "398" + }), + ee.Feature( + ee.Geometry.Point([-14.020786588402613, 10.120094020648413]), + { + "landcover": 1, + "system:index": "399" + }), + ee.Feature( + ee.Geometry.Point([-14.017696683617457, 10.11265834799643]), + { + "landcover": 1, + "system:index": "400" + }), + ee.Feature( + ee.Geometry.Point([-14.005337064476832, 10.108264460521394]), + { + "landcover": 1, + "system:index": "401" + }), + ee.Feature( + ee.Geometry.Point([-14.003277127953394, 10.108602453998687]), + { + "landcover": 1, + "system:index": "402" + }), + ee.Feature( + ee.Geometry.Point([-14.005337064476832, 10.094068413637778]), + { + "landcover": 1, + "system:index": "403" + }), + ee.Feature( + ee.Geometry.Point([-14.003277127953394, 10.092040355803496]), + { + "landcover": 1, + "system:index": "404" + }), + ee.Feature( + ee.Geometry.Point([-14.001217191429957, 10.088322216591616]), + { + "landcover": 1, + "system:index": "405" + }), + ee.Feature( + ee.Geometry.Point([-13.958988492699488, 10.07277316948383]), + { + "landcover": 1, + "system:index": "406" + }), + ee.Feature( + ee.Geometry.Point([-13.95521194240652, 10.067364629502437]), + { + "landcover": 1, + "system:index": "407" + }), + ee.Feature( + ee.Geometry.Point([-13.958645169945582, 10.064660325517268]), + { + "landcover": 1, + "system:index": "408" + }), + ee.Feature( + ee.Geometry.Point([-13.94697219631277, 10.082913937472131]), + { + "landcover": 1, + "system:index": "409" + }), + ee.Feature( + ee.Geometry.Point([-14.121380155297144, 10.071421042988929]), + { + "landcover": 1, + "system:index": "410" + }), + ee.Feature( + ee.Geometry.Point([-14.132366483422144, 10.071759075144007]), + { + "landcover": 1, + "system:index": "411" + }), + ee.Feature( + ee.Geometry.Point([-14.139919584008082, 10.097110476427376]), + { + "landcover": 1, + "system:index": "412" + }), + ee.Feature( + ee.Geometry.Point([-14.132023160668238, 10.101842516928926]), + { + "landcover": 1, + "system:index": "413" + }), + ee.Feature( + ee.Geometry.Point([-14.130649869652613, 10.108264460521394]), + { + "landcover": 1, + "system:index": "414" + }), + ee.Feature( + ee.Geometry.Point([-14.123096769066676, 10.12752952106626]), + { + "landcover": 1, + "system:index": "415" + }), + ee.Feature( + ee.Geometry.Point([-14.108333890648707, 10.125501674403939]), + { + "landcover": 1, + "system:index": "416" + }), + ee.Feature( + ee.Geometry.Point([-14.092197721215113, 10.125839649737824]), + { + "landcover": 1, + "system:index": "417" + }), + ee.Feature( + ee.Geometry.Point([-14.088421170922144, 10.114686275793847]), + { + "landcover": 1, + "system:index": "418" + }), + ee.Feature( + ee.Geometry.Point([-14.099064176293238, 10.114010301283944]), + { + "landcover": 1, + "system:index": "419" + }), + ee.Feature( + ee.Geometry.Point([-14.093914334984644, 10.102180517157963]), + { + "landcover": 1, + "system:index": "420" + }), + ee.Feature( + ee.Geometry.Point([-14.093914334984644, 10.095082437762859]), + { + "landcover": 1, + "system:index": "421" + }), + ee.Feature( + ee.Geometry.Point([-14.104900663109644, 10.086632139121175]), + { + "landcover": 1, + "system:index": "422" + }), + ee.Feature( + ee.Geometry.Point([-14.09528762600027, 10.150172937371915]), + { + "landcover": 1, + "system:index": "423" + }), + ee.Feature( + ee.Geometry.Point([-14.091167752953394, 10.155580083537874]), + { + "landcover": 1, + "system:index": "424" + }), + ee.Feature( + ee.Geometry.Point([-14.097690885277613, 10.160311261454012]), + { + "landcover": 1, + "system:index": "425" + }), + ee.Feature( + ee.Geometry.Point([-14.104214017601832, 10.159635383180365]), + { + "landcover": 1, + "system:index": "426" + }), + ee.Feature( + ee.Geometry.Point([-14.11073714992605, 10.154566250592843]), + { + "landcover": 1, + "system:index": "427" + }), + ee.Feature( + ee.Geometry.Point([-14.116916959496363, 10.175180221816479]), + { + "landcover": 1, + "system:index": "428" + }), + ee.Feature( + ee.Geometry.Point([-14.126186673851832, 10.185655664472218]), + { + "landcover": 1, + "system:index": "429" + }), + ee.Feature( + ee.Geometry.Point([-14.132023160668238, 10.186331487669804]), + { + "landcover": 1, + "system:index": "430" + }), + ee.Feature( + ee.Geometry.Point([-14.130649869652613, 10.181262778780816]), + { + "landcover": 1, + "system:index": "431" + }), + ee.Feature( + ee.Geometry.Point([-14.145756070824488, 10.186669398731471]), + { + "landcover": 1, + "system:index": "432" + }), + ee.Feature( + ee.Geometry.Point([-14.14369613430105, 10.17653191116013]), + { + "landcover": 1, + "system:index": "433" + }), + ee.Feature( + ee.Geometry.Point([-14.138546292992457, 10.166394101608132]), + { + "landcover": 1, + "system:index": "434" + }), + ee.Feature( + ee.Geometry.Point([-14.142666166039332, 10.162338887701564]), + { + "landcover": 1, + "system:index": "435" + }), + ee.Feature( + ee.Geometry.Point([-14.145412748070582, 10.160311261454012]), + { + "landcover": 1, + "system:index": "436" + }), + ee.Feature( + ee.Geometry.Point([-14.135799710961207, 10.159973322495789]), + { + "landcover": 1, + "system:index": "437" + }), + ee.Feature( + ee.Geometry.Point([-14.172878568383082, 10.151524732480077]), + { + "landcover": 1, + "system:index": "438" + }), + ee.Feature( + ee.Geometry.Point([-14.17768508693777, 10.151524732480077]), + { + "landcover": 1, + "system:index": "439" + }), + ee.Feature( + ee.Geometry.Point([-14.181804959984644, 10.14848318545724]), + { + "landcover": 1, + "system:index": "440" + }), + ee.Feature( + ee.Geometry.Point([-14.182834928246363, 10.141048171078742]), + { + "landcover": 1, + "system:index": "441" + }), + ee.Feature( + ee.Geometry.Point([-14.182491605492457, 10.137330599166003]), + { + "landcover": 1, + "system:index": "442" + }), + ee.Feature( + ee.Geometry.Point([-14.180774991722926, 10.199847650708099]), + { + "landcover": 1, + "system:index": "443" + }), + ee.Feature( + ee.Geometry.Point([-14.182491605492457, 10.204578172280252]), + { + "landcover": 1, + "system:index": "444" + }), + ee.Feature( + ee.Geometry.Point([-14.184551542015894, 10.200185547437004]), + { + "landcover": 1, + "system:index": "445" + }), + ee.Feature( + ee.Geometry.Point([-14.187298124047144, 10.204240280213417]), + { + "landcover": 1, + "system:index": "446" + }), + ee.Feature( + ee.Geometry.Point([-14.18764144680105, 10.200861339819124]), + { + "landcover": 1, + "system:index": "447" + }), + ee.Feature( + ee.Geometry.Point([-14.189701383324488, 10.204916063988373]), + { + "landcover": 1, + "system:index": "448" + }), + ee.Feature( + ee.Geometry.Point([-14.1903880288323, 10.202888708359332]), + { + "landcover": 1, + "system:index": "449" + }), + ee.Feature( + ee.Geometry.Point([-14.192791288109644, 10.205591846328486]), + { + "landcover": 1, + "system:index": "450" + }), + ee.Feature( + ee.Geometry.Point([-14.195537870140894, 10.204240280213417]), + { + "landcover": 1, + "system:index": "451" + }), + ee.Feature( + ee.Geometry.Point([-14.172535245629176, 10.204240280213417]), + { + "landcover": 1, + "system:index": "452" + }), + ee.Feature( + ee.Geometry.Point([-14.172535245629176, 10.199847650708099]), + { + "landcover": 1, + "system:index": "453" + }), + ee.Feature( + ee.Geometry.Point([-14.175625150414332, 10.19646866370126]), + { + "landcover": 1, + "system:index": "454" + }), + ee.Feature( + ee.Geometry.Point([-14.17493850490652, 10.193427544749241]), + { + "landcover": 1, + "system:index": "455" + }), + ee.Feature( + ee.Geometry.Point([-14.170131986351832, 10.197820262805768]), + { + "landcover": 1, + "system:index": "456" + }), + ee.Feature( + ee.Geometry.Point([-14.162235563011988, 10.185317752336328]), + { + "landcover": 1, + "system:index": "457" + }), + ee.Feature( + ee.Geometry.Point([-14.152279203148707, 10.195454960609357]), + { + "landcover": 1, + "system:index": "458" + }), + ee.Feature( + ee.Geometry.Point([-14.149532621117457, 10.199509753620669]), + { + "landcover": 1, + "system:index": "459" + }), + ee.Feature( + ee.Geometry.Point([-14.150905912133082, 10.190724303536632]), + { + "landcover": 1, + "system:index": "460" + }), + ee.Feature( + ee.Geometry.Point([-14.137173001976832, 10.202212920280374]), + { + "landcover": 1, + "system:index": "461" + }), + ee.Feature( + ee.Geometry.Point([-14.140262906761988, 10.204578172280252]), + { + "landcover": 1, + "system:index": "462" + }), + ee.Feature( + ee.Geometry.Point([-14.135113065453394, 10.200861339819124]), + { + "landcover": 1, + "system:index": "463" + }), + ee.Feature( + ee.Geometry.Point([-14.134083097191676, 10.205591846328486]), + { + "landcover": 1, + "system:index": "464" + }), + ee.Feature( + ee.Geometry.Point([-14.127903287621363, 10.20322660186085]), + { + "landcover": 1, + "system:index": "465" + }), + ee.Feature( + ee.Geometry.Point([-14.126186673851832, 10.201537130766951]), + { + "landcover": 1, + "system:index": "466" + }), + ee.Feature( + ee.Geometry.Point([-14.122410123558863, 10.197820262805768]), + { + "landcover": 1, + "system:index": "467" + }), + ee.Feature( + ee.Geometry.Point([-14.117603605004176, 10.194779156756098]), + { + "landcover": 1, + "system:index": "468" + }), + ee.Feature( + ee.Geometry.Point([-14.114170377465113, 10.192075927009176]), + { + "landcover": 1, + "system:index": "469" + }), + ee.Feature( + ee.Geometry.Point([-14.10902053615652, 10.195792861998385]), + { + "landcover": 1, + "system:index": "470" + }), + ee.Feature( + ee.Geometry.Point([-14.110050504418238, 10.191400115989413]), + { + "landcover": 1, + "system:index": "471" + }), + ee.Feature( + ee.Geometry.Point([-14.106960599633082, 10.187345219780514]), + { + "landcover": 1, + "system:index": "472" + }), + ee.Feature( + ee.Geometry.Point([-14.09528762600027, 10.194441254291904]), + { + "landcover": 1, + "system:index": "473" + }), + ee.Feature( + ee.Geometry.Point([-14.096317594261988, 10.190048489650911]), + { + "landcover": 1, + "system:index": "474" + }), + ee.Feature( + ee.Geometry.Point([-14.091854398461207, 10.187345219780514]), + { + "landcover": 1, + "system:index": "475" + }), + ee.Feature( + ee.Geometry.Point([-14.09803420803152, 10.185993576250045]), + { + "landcover": 1, + "system:index": "476" + }), + ee.Feature( + ee.Geometry.Point([-14.094600980492457, 10.184979839842379]), + { + "landcover": 1, + "system:index": "477" + }), + ee.Feature( + ee.Geometry.Point([-14.091167752953394, 10.181938611286409]), + { + "landcover": 1, + "system:index": "478" + }), + ee.Feature( + ee.Geometry.Point([-14.08430129787527, 10.184304013780388]), + { + "landcover": 1, + "system:index": "479" + }), + ee.Feature( + ee.Geometry.Point([-14.085674588890894, 10.180586944843554]), + { + "landcover": 1, + "system:index": "480" + }), + ee.Feature( + ee.Geometry.Point([-14.089107816429957, 10.176869832601675]), + { + "landcover": 1, + "system:index": "481" + }), + ee.Feature( + ee.Geometry.Point([-14.214420621605738, 10.1403722521214]), + { + "landcover": 1, + "system:index": "482" + }), + ee.Feature( + ee.Geometry.Point([-14.218540494652613, 10.13597874414021]), + { + "landcover": 1, + "system:index": "483" + }), + ee.Feature( + ee.Geometry.Point([-14.220943753929957, 10.139020409928333]), + { + "landcover": 1, + "system:index": "484" + }), + ee.Feature( + ee.Geometry.Point([-14.214763944359644, 10.137668562031386]), + { + "landcover": 1, + "system:index": "485" + }), + ee.Feature( + ee.Geometry.Point([-14.224720304222926, 10.137668562031386]), + { + "landcover": 1, + "system:index": "486" + }), + ee.Feature( + ee.Geometry.Point([-14.227466886254176, 10.143413876197156]), + { + "landcover": 1, + "system:index": "487" + }), + ee.Feature( + ee.Geometry.Point([-14.234676664086207, 10.212349590792996]), + { + "landcover": 1, + "system:index": "488" + }), + ee.Feature( + ee.Geometry.Point([-14.234676664086207, 10.207619184738817]), + { + "landcover": 1, + "system:index": "489" + }), + ee.Feature( + ee.Geometry.Point([-14.236393277855738, 10.204240280213417]), + { + "landcover": 1, + "system:index": "490" + }), + ee.Feature( + ee.Geometry.Point([-14.239483182640894, 10.21099805338396]), + { + "landcover": 1, + "system:index": "491" + }), + ee.Feature( + ee.Geometry.Point([-14.241543119164332, 10.219107191672828]), + { + "landcover": 1, + "system:index": "492" + }), + ee.Feature( + ee.Geometry.Point([-14.285488431664332, 10.228567591509108]), + { + "landcover": 1, + "system:index": "493" + }), + ee.Feature( + ee.Geometry.Point([-14.28651839992605, 10.2278918580079]), + { + "landcover": 1, + "system:index": "494" + }), + ee.Feature( + ee.Geometry.Point([-14.288921659203394, 10.2278918580079]), + { + "landcover": 1, + "system:index": "495" + }), + ee.Feature( + ee.Geometry.Point([-14.195194547386988, 10.222148065200006]), + { + "landcover": 1, + "system:index": "496" + }), + ee.Feature( + ee.Geometry.Point([-14.19313461086355, 10.220120819414998]), + { + "landcover": 1, + "system:index": "497" + }), + ee.Feature( + ee.Geometry.Point([-14.1958811928948, 10.217755682988003]), + { + "landcover": 1, + "system:index": "498" + }), + ee.Feature( + ee.Geometry.Point([-14.198971097679957, 10.216404168556885]), + { + "landcover": 1, + "system:index": "499" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.52315168974187, 9.621012255759489], + [-13.524095827315112, 9.618727414519354], + [-13.521950060103197, 9.618727414519354]]]), + { + "landcover": 1, + "system:index": "500" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.486244493696947, 9.617542675945005], + [-13.487016969893237, 9.615596310704088], + [-13.484098726485033, 9.615511685874274]]]), + { + "landcover": 1, + "system:index": "501" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.52801132696572, 9.618896665130736], + [-13.528526311096579, 9.61568093809527], + [-13.525779729065329, 9.616188686502388]]]), + { + "landcover": 1, + "system:index": "502" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.463294987854391, 9.581660060195713], + [-13.460205083069235, 9.579628855011359], + [-13.457630162414938, 9.582337125889376]]]), + { + "landcover": 1, + "system:index": "503" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.480976109680563, 9.657990686442465], + [-13.482006077942282, 9.654775331951527], + [-13.479431157287985, 9.65528302154379]]]), + { + "landcover": 1, + "system:index": "504" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.50775528448525, 9.663405950907341], + [-13.506896977600485, 9.659175282988585], + [-13.504493718323141, 9.660359875366272]]]), + { + "landcover": 1, + "system:index": "505" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.446472172912985, 9.663405950907341], + [-13.449905400452048, 9.661882916583096], + [-13.44733047979775, 9.659344510726331]]]), + { + "landcover": 1, + "system:index": "506" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.60766220587197, 9.722291314738907], + [-13.605430607971579, 9.71958416859477], + [-13.603199010071188, 9.723137293414952]]]), + { + "landcover": 1, + "system:index": "507" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.60714722174111, 9.785902927708433], + [-13.60714722174111, 9.78133547748043], + [-13.604057316955954, 9.783534628020057]]]), + { + "landcover": 1, + "system:index": "508" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.578308110412985, 9.78065881284821], + [-13.578308110412985, 9.777275469025232], + [-13.575389867004782, 9.779474646427087]]]), + { + "landcover": 1, + "system:index": "509" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.701560979065329, 9.777275469025232], + [-13.699672703918845, 9.773722920958017], + [-13.6972694446415, 9.776937132749193]]]), + { + "landcover": 1, + "system:index": "510" + }), + ee.Feature( + ee.Geometry.Point([-13.959463327400387, 10.056802999864853]), + { + "landcover": 1, + "system:index": "511" + }), + ee.Feature( + ee.Geometry.Point([-13.981779306404293, 10.019108491959036]), + { + "landcover": 1, + "system:index": "512" + }), + ee.Feature( + ee.Geometry.Point([-14.009416788093747, 10.03787177777399]), + { + "landcover": 1, + "system:index": "513" + }), + ee.Feature( + ee.Geometry.Point([-14.006670206062497, 10.038209845027112]), + { + "landcover": 1, + "system:index": "514" + }), + ee.Feature( + ee.Geometry.Point([-14.006155221931637, 10.036857573896196]), + { + "landcover": 1, + "system:index": "515" + }), + ee.Feature( + ee.Geometry.Point([-14.016969888679684, 10.018601361050132]), + { + "landcover": 1, + "system:index": "516" + }), + ee.Feature( + ee.Geometry.Point([-14.008730142585934, 10.053422505790016]), + { + "landcover": 1, + "system:index": "517" + }), + ee.Feature( + ee.Geometry.Point([-14.02005979346484, 10.052746402731378]), + { + "landcover": 1, + "system:index": "518" + }), + ee.Feature( + ee.Geometry.Point([-14.020918100349606, 10.04699946963806]), + { + "landcover": 1, + "system:index": "519" + }), + ee.Feature( + ee.Geometry.Point([-13.996713846199215, 10.049534893889792]), + { + "landcover": 1, + "system:index": "520" + }), + ee.Feature( + ee.Geometry.Point([-13.433250165943592, 9.515253067891168]), + { + "landcover": 1, + "system:index": "521" + }), + ee.Feature( + ee.Geometry.Point([-13.441661573414295, 9.523548647400151]), + { + "landcover": 1, + "system:index": "522" + }), + ee.Feature( + ee.Geometry.Point([-13.440116621021717, 9.50661867948395]), + { + "landcover": 1, + "system:index": "523" + }), + ee.Feature( + ee.Geometry.Point([-13.443721509937733, 9.516776760858239]), + { + "landcover": 1, + "system:index": "524" + }), + ee.Feature( + ee.Geometry.Point([-13.447154737476795, 9.522532872976543]), + { + "landcover": 1, + "system:index": "525" + }), + ee.Feature( + ee.Geometry.Point([-13.445953107838124, 9.529473937981358]), + { + "landcover": 1, + "system:index": "526" + }), + ee.Feature( + ee.Geometry.Point([-13.452647901539295, 9.52913535271861]), + { + "landcover": 1, + "system:index": "527" + }), + ee.Feature( + ee.Geometry.Point([-13.442004896168202, 9.53793846035774]), + { + "landcover": 1, + "system:index": "528" + }), + ee.Feature( + ee.Geometry.Point([-13.439944959644764, 9.543524930040505]), + { + "landcover": 1, + "system:index": "529" + }), + ee.Feature( + ee.Geometry.Point([-13.449729658131092, 9.53759988349555]), + { + "landcover": 1, + "system:index": "530" + }), + ee.Feature( + ee.Geometry.Point([-13.450072980884999, 9.544202071659186]), + { + "landcover": 1, + "system:index": "531" + }), + ee.Feature( + ee.Geometry.Point([-13.452819562916249, 9.50407911200358]), + { + "landcover": 1, + "system:index": "532" + }), + ee.Feature( + ee.Geometry.Point([-13.458484388355702, 9.50255536246944]), + { + "landcover": 1, + "system:index": "533" + }), + ee.Feature( + ee.Geometry.Point([-13.454192853931874, 9.4998464576609]), + { + "landcover": 1, + "system:index": "534" + }), + ee.Feature( + ee.Geometry.Point([-13.454364515308827, 9.491719614665294]), + { + "landcover": 1, + "system:index": "535" + }), + ee.Feature( + ee.Geometry.Point([-13.394283033375233, 9.52913535271861]), + { + "landcover": 1, + "system:index": "536" + }), + ee.Feature( + ee.Geometry.Point([-13.389991498951405, 9.545048496790354]), + { + "landcover": 1, + "system:index": "537" + }), + ee.Feature( + ee.Geometry.Point([-13.431361890797108, 9.493582033213793]), + { + "landcover": 1, + "system:index": "538" + }), + ee.Feature( + ee.Geometry.Point([-13.42758534050414, 9.49307410188631]), + { + "landcover": 1, + "system:index": "539" + }), + ee.Feature( + ee.Geometry.Point([-13.439944959644764, 9.491719614665294]), + { + "landcover": 1, + "system:index": "540" + }), + ee.Feature( + ee.Geometry.Point([-13.446639753345936, 9.480883524227751]), + { + "landcover": 1, + "system:index": "541" + }), + ee.Feature( + ee.Geometry.Point([-13.432906843189686, 9.488671998844872]), + { + "landcover": 1, + "system:index": "542" + }), + ee.Feature( + ee.Geometry.Point([-13.50946781731078, 9.52168639198262]), + { + "landcover": 1, + "system:index": "543" + }), + ee.Feature( + ee.Geometry.Point([-13.530582166676014, 9.523379351872673]), + { + "landcover": 1, + "system:index": "544" + }), + ee.Feature( + ee.Geometry.Point([-13.54568836784789, 9.526765246475557]), + { + "landcover": 1, + "system:index": "545" + }), + ee.Feature( + ee.Geometry.Point([-13.552726484302967, 9.527442421367]), + { + "landcover": 1, + "system:index": "546" + }), + ee.Feature( + ee.Geometry.Point([-13.555816389088124, 9.53946205207731]), + { + "landcover": 1, + "system:index": "547" + }), + ee.Feature( + ee.Geometry.Point([-13.538821912769764, 9.540816350112253]), + { + "landcover": 1, + "system:index": "548" + }), + ee.Feature( + ee.Geometry.Point([-13.444579816822499, 9.462935496757591]), + { + "landcover": 1, + "system:index": "549" + }), + ee.Feature( + ee.Geometry.Point([-13.38037846184203, 9.45480777971921]), + { + "landcover": 1, + "system:index": "550" + }), + ee.Feature( + ee.Geometry.Point([-13.35239765739867, 9.47174030668765]), + { + "landcover": 1, + "system:index": "551" + }), + ee.Feature( + ee.Geometry.Point([-13.359264112476795, 9.486132298297015]), + { + "landcover": 1, + "system:index": "552" + }), + ee.Feature( + ee.Geometry.Point([-13.359607435230702, 9.484100524314757]), + { + "landcover": 1, + "system:index": "553" + }), + ee.Feature( + ee.Geometry.Point([-13.337463117603749, 9.47123234301792]), + { + "landcover": 1, + "system:index": "554" + }), + ee.Feature( + ee.Geometry.Point([-13.34141132927367, 9.49425927381244]), + { + "landcover": 1, + "system:index": "555" + }), + ee.Feature( + ee.Geometry.Point([-13.341582990650624, 9.498153381271607]), + { + "landcover": 1, + "system:index": "556" + }), + ee.Feature( + ee.Geometry.Point([-13.337978101734608, 9.505772159084684]), + { + "landcover": 1, + "system:index": "557" + }), + ee.Feature( + ee.Geometry.Point([-13.348621107105702, 9.512036360435498]), + { + "landcover": 1, + "system:index": "558" + }), + ee.Feature( + ee.Geometry.Point([-13.352740980152577, 9.512713564520134]), + { + "landcover": 1, + "system:index": "559" + }), + ee.Feature( + ee.Geometry.Point([-13.329910017017811, 9.432624908679694]), + { + "landcover": 1, + "system:index": "560" + }), + ee.Feature( + ee.Geometry.Point([-13.33420155144164, 9.433810289049077]), + { + "landcover": 1, + "system:index": "561" + }), + ee.Feature( + ee.Geometry.Point([-13.332828260426014, 9.429915452536795]), + { + "landcover": 1, + "system:index": "562" + }), + ee.Feature( + ee.Geometry.Point([-13.345874525074452, 9.413658269000564]), + { + "landcover": 1, + "system:index": "563" + }), + ee.Feature( + ee.Geometry.Point([-13.289397932056874, 9.419754802521876]), + { + "landcover": 1, + "system:index": "564" + }), + ee.Feature( + ee.Geometry.Point([-13.282874799732655, 9.414674365391507]), + { + "landcover": 1, + "system:index": "565" + }), + ee.Feature( + ee.Geometry.Point([-13.25901386833617, 9.407900333029371]), + { + "landcover": 1, + "system:index": "566" + }), + ee.Feature( + ee.Geometry.Point([-13.244250989918202, 9.402481011589613]), + { + "landcover": 1, + "system:index": "567" + }), + ee.Feature( + ee.Geometry.Point([-13.280128217701405, 9.39350507376156]), + { + "landcover": 1, + "system:index": "568" + }), + ee.Feature( + ee.Geometry.Point([-13.28150150871703, 9.34235473089528]), + { + "landcover": 1, + "system:index": "569" + }), + ee.Feature( + ee.Geometry.Point([-13.297122694019764, 9.35065447039907]), + { + "landcover": 1, + "system:index": "570" + }), + ee.Feature( + ee.Geometry.Point([-13.288539625172108, 9.360647771582952]), + { + "landcover": 1, + "system:index": "571" + }), + ee.Feature( + ee.Geometry.Point([-13.307422376636952, 9.358784635516088]), + { + "landcover": 1, + "system:index": "572" + }), + ee.Feature( + ee.Geometry.Point([-13.331969953541249, 9.35963151678442]), + { + "landcover": 1, + "system:index": "573" + }), + ee.Feature( + ee.Geometry.Point([-13.334029890064686, 9.35438081966868]), + { + "landcover": 1, + "system:index": "574" + }), + ee.Feature( + ee.Geometry.Point([-13.341068006519764, 9.351840131314342]), + { + "landcover": 1, + "system:index": "575" + }), + ee.Feature( + ee.Geometry.Point([-13.34467289543578, 9.336764998940213]), + { + "landcover": 1, + "system:index": "576" + }), + ee.Feature( + ee.Geometry.Point([-13.291286207203358, 9.319317683374159]), + { + "landcover": 1, + "system:index": "577" + }), + ee.Feature( + ee.Geometry.Point([-13.285106397633045, 9.305426964030449]), + { + "landcover": 1, + "system:index": "578" + }), + ee.Feature( + ee.Geometry.Point([-13.273433424000233, 9.314405175017802]), + { + "landcover": 1, + "system:index": "579" + }), + ee.Feature( + ee.Geometry.Point([-13.282703138355702, 9.318978891913023]), + { + "landcover": 1, + "system:index": "580" + }), + ee.Feature( + ee.Geometry.Point([-13.249572492603749, 9.311864195309921]), + { + "landcover": 1, + "system:index": "581" + }), + ee.Feature( + ee.Geometry.Point([-13.258842206959217, 9.304071742342185]), + { + "landcover": 1, + "system:index": "582" + }), + ee.Feature( + ee.Geometry.Point([-13.252662397388905, 9.30034485562317]), + { + "landcover": 1, + "system:index": "583" + }), + ee.Feature( + ee.Geometry.Point([-13.26004383659789, 9.293738004335609]), + { + "landcover": 1, + "system:index": "584" + }), + ee.Feature( + ee.Geometry.Point([-13.263477064136952, 9.289502777673848]), + { + "landcover": 1, + "system:index": "585" + }), + ee.Feature( + ee.Geometry.Point([-13.27377674675414, 9.29627911574363]), + { + "landcover": 1, + "system:index": "586" + }), + ee.Feature( + ee.Geometry.Point([-13.279784894947499, 9.270528333966]), + { + "landcover": 1, + "system:index": "587" + }), + ee.Feature( + ee.Geometry.Point([-13.25455067253539, 9.256466254018491]), + { + "landcover": 1, + "system:index": "588" + }), + ee.Feature( + ee.Geometry.Point([-13.21009037590453, 9.264937453931857]), + { + "landcover": 1, + "system:index": "589" + }), + ee.Feature( + ee.Geometry.Point([-13.205283857349842, 9.260532455463142]), + { + "landcover": 1, + "system:index": "590" + }), + ee.Feature( + ee.Geometry.Point([-13.24030277824828, 9.232915246293794]), + { + "landcover": 1, + "system:index": "591" + }), + ee.Feature( + ee.Geometry.Point([-13.259185529713124, 9.244097935622158]), + { + "landcover": 1, + "system:index": "592" + }), + ee.Feature( + ee.Geometry.Point([-13.262103773121327, 9.239692676146335]), + { + "landcover": 1, + "system:index": "593" + }), + ee.Feature( + ee.Geometry.Point([-13.27600834465453, 9.234101305928146]), + { + "landcover": 1, + "system:index": "594" + }), + ee.Feature( + ee.Geometry.Point([-13.29025623894164, 9.216648883114125]), + { + "landcover": 1, + "system:index": "595" + }), + ee.Feature( + ee.Geometry.Point([-13.29025623894164, 9.206820925471753]), + { + "landcover": 1, + "system:index": "596" + }), + ee.Feature( + ee.Geometry.Point([-13.294891096119374, 9.20224574851503]), + { + "landcover": 1, + "system:index": "597" + }), + ee.Feature( + ee.Geometry.Point([-13.305877424244374, 9.201398487027035]), + { + "landcover": 1, + "system:index": "598" + }), + ee.Feature( + ee.Geometry.Point([-13.22382328606078, 9.209871010547175]), + { + "landcover": 1, + "system:index": "599" + }), + ee.Feature( + ee.Geometry.Point([-13.192065931324452, 9.215632210520651]), + { + "landcover": 1, + "system:index": "600" + }), + ee.Feature( + ee.Geometry.Point([-13.190177656177967, 9.218851663690847]), + { + "landcover": 1, + "system:index": "601" + }), + ee.Feature( + ee.Geometry.Point([-13.187774396900624, 9.212751622278716]), + { + "landcover": 1, + "system:index": "602" + }), + ee.Feature( + ee.Geometry.Point([-13.206313825611561, 9.193095217068748]), + { + "landcover": 1, + "system:index": "603" + }), + ee.Feature( + ee.Geometry.Point([-13.19034931755492, 9.189536613174072]), + { + "landcover": 1, + "system:index": "604" + }), + ee.Feature( + ee.Geometry.Point([-13.19086430168578, 9.184622291871827]), + { + "landcover": 1, + "system:index": "605" + }), + ee.Feature( + ee.Geometry.Point([-13.18588612175414, 9.18394444910143]), + { + "landcover": 1, + "system:index": "606" + }), + ee.Feature( + ee.Geometry.Point([-13.22056171989867, 9.209701562066911]), + { + "landcover": 1, + "system:index": "607" + }), + ee.Feature( + ee.Geometry.Point([-13.237384534840077, 9.212921069296193]), + { + "landcover": 1, + "system:index": "608" + }), + ee.Feature( + ee.Geometry.Point([-13.248199201588124, 9.214276642509766]), + { + "landcover": 1, + "system:index": "609" + }), + ee.Feature( + ee.Geometry.Point([-13.283218122486561, 9.196484330379587]), + { + "landcover": 1, + "system:index": "610" + }), + ee.Feature( + ee.Geometry.Point([-13.279956556324452, 9.192925760551425]), + { + "landcover": 1, + "system:index": "611" + }), + ee.Feature( + ee.Geometry.Point([-13.289912916187733, 9.193264673504942]), + { + "landcover": 1, + "system:index": "612" + }), + ee.Feature( + ee.Geometry.Point([-13.295062757496327, 9.194620322074341]), + { + "landcover": 1, + "system:index": "613" + }), + ee.Feature( + ee.Geometry.Point([-13.281844831470936, 9.176149164076689]), + { + "landcover": 1, + "system:index": "614" + }), + ee.Feature( + ee.Geometry.Point([-13.282703138355702, 9.17309878850916]), + { + "landcover": 1, + "system:index": "615" + })]), + NonMangrove = + + # shown: False # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([-13.640199652454818, 9.89526389438857]), + { + "landcover": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([-13.64088629796263, 9.8937419219008]), + { + "landcover": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([-13.637453070423568, 9.89526389438857]), + { + "landcover": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([-13.6336765201306, 9.895940324341653]), + { + "landcover": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([-13.631273260853256, 9.896109431612254]), + { + "landcover": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([-13.629556647083724, 9.894080138618607]), + { + "landcover": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([-13.628011694691146, 9.892558160646315]), + { + "landcover": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([-13.628011694691146, 9.890528845715746]), + { + "landcover": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([-13.6281833560681, 9.888161295791257]), + { + "landcover": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([-13.63539313390013, 9.882918803133371]), + { + "landcover": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([-13.6336765201306, 9.879198273770779]), + { + "landcover": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([-13.63264655186888, 9.877337993310382]), + { + "landcover": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([-13.629041662952865, 9.880043852321075]), + { + "landcover": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([-13.62543677403685, 9.883426144785675]), + { + "landcover": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([-13.631273260853256, 9.88934507288544]), + { + "landcover": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([-13.638483038685287, 9.887653961445755]), + { + "landcover": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([-13.638483038685287, 9.886301066029677]), + { + "landcover": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([-13.620458594105209, 9.883933485655257]), + { + "landcover": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([-13.620458594105209, 9.88122765863999]), + { + "landcover": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([-13.620286932728256, 9.878352693047196]), + { + "landcover": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([-13.618226996204818, 9.884779052031762]), + { + "landcover": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([-13.612390509388412, 9.881058543712408]), + { + "landcover": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([-13.609815588734115, 9.879198273770779]), + { + "landcover": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([-13.609472265980209, 9.882580574930365]), + { + "landcover": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([-13.614107123157943, 9.8912052854185]), + { + "landcover": 2, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([-13.594366064808334, 9.865499598598175]), + { + "landcover": 2, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([-13.596254339954818, 9.863639240739971]), + { + "landcover": 2, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([-13.593851080677474, 9.863300992728192]), + { + "landcover": 2, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([-13.592306128284896, 9.867359945951616]), + { + "landcover": 2, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([-13.595567694447006, 9.870742368765931]), + { + "landcover": 2, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([-13.59745596959349, 9.872433567144729]), + { + "landcover": 2, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([-13.59694098546263, 9.870911488994695]), + { + "landcover": 2, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([-13.487671836213329, 9.603185503942363]), + { + "landcover": 2, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([-13.488873465852, 9.602508479883612]), + { + "landcover": 2, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([-13.489045127228954, 9.599969627609893]), + { + "landcover": 2, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([-13.488701804475047, 9.597769273580928]), + { + "landcover": 2, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([-13.490075095490672, 9.591506649300088]), + { + "landcover": 2, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([-13.48389528592036, 9.598107790515527]), + { + "landcover": 2, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([-13.442353232697704, 9.603016248054569]), + { + "landcover": 2, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([-13.440808280305125, 9.604708803125543]), + { + "landcover": 2, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([-13.438233359650829, 9.60572433210698]), + { + "landcover": 2, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([-13.43445680935786, 9.602339223657433]), + { + "landcover": 2, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([-13.43720339138911, 9.600985170803016]), + { + "landcover": 2, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([-13.43668840725825, 9.59472260595197]), + { + "landcover": 2, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([-13.438405021027782, 9.592860740029861]), + { + "landcover": 2, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([-13.438748343781688, 9.590491077703861]), + { + "landcover": 2, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([-13.439606650666454, 9.589644765716853]), + { + "landcover": 2, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([-13.444069846467235, 9.581689329827402]), + { + "landcover": 2, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([-13.446301444367625, 9.58050446171579]), + { + "landcover": 2, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([-13.459862693146922, 9.594384085635884]), + { + "landcover": 2, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([-13.46243761380122, 9.59472260595197]), + { + "landcover": 2, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([-13.469132407502391, 9.611817442013729]), + { + "landcover": 2, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([-13.469475730256297, 9.615033205784563]), + { + "landcover": 2, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([-13.471364005402782, 9.61621795315115]), + { + "landcover": 2, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([-13.474282248810985, 9.61621795315115]), + { + "landcover": 2, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([-13.472222312287547, 9.611817442013729]), + { + "landcover": 2, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([-13.469304068879344, 9.609447912307623]), + { + "landcover": 2, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([-13.47016237576411, 9.620787654108952]), + { + "landcover": 2, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([-13.46964739163325, 9.624511068472138]), + { + "landcover": 2, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([-13.46964739163325, 9.626372760267671]), + { + "landcover": 2, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([-13.48938844998286, 9.624341823254763]), + { + "landcover": 2, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([-13.492478354768016, 9.624341823254763]), + { + "landcover": 2, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([-13.495568259553172, 9.62620351598291]), + { + "landcover": 2, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([-13.496083243684032, 9.630434597660521]), + { + "landcover": 2, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([-13.423127158478954, 9.615371705455658]), + { + "landcover": 2, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([-13.411797507600047, 9.610801931314386]), + { + "landcover": 2, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([-13.41248415310786, 9.606570603931203]), + { + "landcover": 2, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([-13.408879264191844, 9.615202455662457]), + { + "landcover": 2, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([-13.409050925568797, 9.621972381310744]), + { + "landcover": 2, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([-13.414887412385204, 9.625865027159046]), + { + "landcover": 2, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([-13.419693930939891, 9.63331170291934]), + { + "landcover": 2, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([-13.413685782746532, 9.634665626321135]), + { + "landcover": 2, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([-13.403557761506297, 9.632296256804214]), + { + "landcover": 2, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([-13.405446036652782, 9.63128080763471]), + { + "landcover": 2, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([-13.40750597317622, 9.634665626321135]), + { + "landcover": 2, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([-13.409565909699657, 9.636527262130242]), + { + "landcover": 2, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([-13.431023581818797, 9.63331170291934]), + { + "landcover": 2, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([-13.532562170556368, 9.62265315892689]), + { + "landcover": 2, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([-13.534278784325899, 9.62400712505879]), + { + "landcover": 2, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([-13.531875525048555, 9.626376552734179]), + { + "landcover": 2, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([-13.53050223403293, 9.628407477514115]), + { + "landcover": 2, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([-13.551101599267305, 9.632130807889933]), + { + "landcover": 2, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([-13.553504858544649, 9.628407477514115]), + { + "landcover": 2, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([-13.561057959130586, 9.635854097202463]), + { + "landcover": 2, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([-13.566894445946993, 9.630099905501739]), + { + "landcover": 2, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([-13.569641027978243, 9.627053529017628]), + { + "landcover": 2, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([-13.572387610009493, 9.624345615744067]), + { + "landcover": 2, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([-13.576164160302461, 9.6209606936336]), + { + "landcover": 2, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([-13.579597387841524, 9.617914234750414]), + { + "landcover": 2, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([-13.581314001611055, 9.614190747727863]), + { + "landcover": 2, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([-13.586463842919649, 9.611144227856878]), + { + "landcover": 2, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([-13.590583715966524, 9.608436187164969]), + { + "landcover": 2, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([-13.592643652489961, 9.60437408550142]), + { + "landcover": 2, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([-13.597793493798555, 9.600650449498545]), + { + "landcover": 2, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([-13.601570044091524, 9.595234178607734]), + { + "landcover": 2, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([-13.599510107568086, 9.587786664810263]), + { + "landcover": 2, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([-13.347854528954805, 9.631453841784552]), + { + "landcover": 2, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([-13.353347693017305, 9.629084449726962]), + { + "landcover": 2, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([-13.345451269677461, 9.657177598717503]), + { + "landcover": 2, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([-13.348541174462618, 9.663608231103328]), + { + "landcover": 2, + "system:index": "99" + }), + ee.Feature( + ee.Geometry.Point([-13.350257788232149, 9.672069402255028]), + { + "landcover": 2, + "system:index": "100" + }), + ee.Feature( + ee.Geometry.Point([-13.346137915185274, 9.67477693205716]), + { + "landcover": 2, + "system:index": "101" + }), + ee.Feature( + ee.Geometry.Point([-13.369140539696993, 9.638561918174645]), + { + "landcover": 2, + "system:index": "102" + }), + ee.Feature( + ee.Geometry.Point([-13.418922339013399, 9.682899390568524]), + { + "landcover": 2, + "system:index": "103" + }), + ee.Feature( + ee.Geometry.Point([-13.454284582665743, 9.670715629176321]), + { + "landcover": 2, + "system:index": "104" + }), + ee.Feature( + ee.Geometry.Point([-13.451538000634493, 9.678499749919098]), + { + "landcover": 2, + "system:index": "105" + }), + ee.Feature( + ee.Geometry.Point([-13.451538000634493, 9.682899390568524]), + { + "landcover": 2, + "system:index": "106" + }), + ee.Feature( + ee.Geometry.Point([-13.454284582665743, 9.683237822077341]), + { + "landcover": 2, + "system:index": "107" + }), + ee.Feature( + ee.Geometry.Point([-13.447418127587618, 9.679515056722407]), + { + "landcover": 2, + "system:index": "108" + }), + ee.Feature( + ee.Geometry.Point([-13.44535819106418, 9.672069402255028]), + { + "landcover": 2, + "system:index": "109" + }), + ee.Feature( + ee.Geometry.Point([-13.439178381493868, 9.643639023914613]), + { + "landcover": 2, + "system:index": "110" + }), + ee.Feature( + ee.Geometry.Point([-13.441924963525118, 9.641946663826616]), + { + "landcover": 2, + "system:index": "111" + }), + ee.Feature( + ee.Geometry.Point([-13.446388159325899, 9.643639023914613]), + { + "landcover": 2, + "system:index": "112" + }), + ee.Feature( + ee.Geometry.Point([-13.452224646142305, 9.637884964968881]), + { + "landcover": 2, + "system:index": "113" + }), + ee.Feature( + ee.Geometry.Point([-13.45909110122043, 9.642285136523668]), + { + "landcover": 2, + "system:index": "114" + }), + ee.Feature( + ee.Geometry.Point([-13.458747778466524, 9.634161698060968]), + { + "landcover": 2, + "system:index": "115" + }), + ee.Feature( + ee.Geometry.Point([-13.45909110122043, 9.626376552734179]), + { + "landcover": 2, + "system:index": "116" + }), + ee.Feature( + ee.Geometry.Point([-13.44535819106418, 9.628745963790163]), + { + "landcover": 2, + "system:index": "117" + }), + ee.Feature( + ee.Geometry.Point([-13.430938635400118, 9.610128715137005]), + { + "landcover": 2, + "system:index": "118" + }), + ee.Feature( + ee.Geometry.Point([-13.417549047997774, 9.599634905301931]), + { + "landcover": 2, + "system:index": "119" + }), + ee.Feature( + ee.Geometry.Point([-13.415489111474336, 9.591510442157333]), + { + "landcover": 2, + "system:index": "120" + }), + ee.Feature( + ee.Geometry.Point([-13.417549047997774, 9.59117191863368]), + { + "landcover": 2, + "system:index": "121" + }), + ee.Feature( + ee.Geometry.Point([-13.413429174950899, 9.583047252699105]), + { + "landcover": 2, + "system:index": "122" + }), + ee.Feature( + ee.Geometry.Point([-13.413085852196993, 9.580000452816348]), + { + "landcover": 2, + "system:index": "123" + }), + ee.Feature( + ee.Geometry.Point([-13.404502783349336, 9.582370188422113]), + { + "landcover": 2, + "system:index": "124" + }), + ee.Feature( + ee.Geometry.Point([-13.411025915673555, 9.604712595834995]), + { + "landcover": 2, + "system:index": "125" + }), + ee.Feature( + ee.Geometry.Point([-13.407249365380586, 9.601327477271484]), + { + "landcover": 2, + "system:index": "126" + }), + ee.Feature( + ee.Geometry.Point([-13.47831717543918, 9.686622118403308]), + { + "landcover": 2, + "system:index": "127" + }), + ee.Feature( + ee.Geometry.Point([-13.484153662255586, 9.683237822077341]), + { + "landcover": 2, + "system:index": "128" + }), + ee.Feature( + ee.Geometry.Point([-13.477630529931368, 9.681545661122474]), + { + "landcover": 2, + "system:index": "129" + }), + ee.Feature( + ee.Geometry.Point([-13.480033789208711, 9.676130688779114]), + { + "landcover": 2, + "system:index": "130" + }), + ee.Feature( + ee.Geometry.Point([-13.398322973779024, 9.663946682035794]), + { + "landcover": 2, + "system:index": "131" + }), + ee.Feature( + ee.Geometry.Point([-13.392829809716524, 9.664285132627802]), + { + "landcover": 2, + "system:index": "132" + }), + ee.Feature( + ee.Geometry.Point([-13.381843481591524, 9.664962032790449]), + { + "landcover": 2, + "system:index": "133" + }), + ee.Feature( + ee.Geometry.Point([-13.384246740868868, 9.663269779830442]), + { + "landcover": 2, + "system:index": "134" + }), + ee.Feature( + ee.Geometry.Point([-13.427333746484102, 9.621129940544316]), + { + "landcover": 2, + "system:index": "135" + }), + ee.Feature( + ee.Geometry.Point([-13.441581640771211, 9.628407477514115]), + { + "landcover": 2, + "system:index": "136" + }), + ee.Feature( + ee.Geometry.Point([-13.450679693749727, 9.623837879588994]), + { + "landcover": 2, + "system:index": "137" + }), + ee.Feature( + ee.Geometry.Point([-13.463382635644258, 9.619606715297124]), + { + "landcover": 2, + "system:index": "138" + }), + ee.Feature( + ee.Geometry.Point([-13.430423651269258, 9.625361085765237]), + { + "landcover": 2, + "system:index": "139" + }), + ee.Feature( + ee.Geometry.Point([-13.429908667138399, 9.631284600046119]), + { + "landcover": 2, + "system:index": "140" + }), + ee.Feature( + ee.Geometry.Point([-13.434028540185274, 9.634669418694504]), + { + "landcover": 2, + "system:index": "141" + }), + ee.Feature( + ee.Geometry.Point([-13.439006720116915, 9.629761420582756]), + { + "landcover": 2, + "system:index": "142" + }), + ee.Feature( + ee.Geometry.Point([-13.424587164452852, 9.626376552734179]), + { + "landcover": 2, + "system:index": "143" + }), + ee.Feature( + ee.Geometry.Point([-13.43437186293918, 9.622822404990066]), + { + "landcover": 2, + "system:index": "144" + }), + ee.Feature( + ee.Geometry.Point([-13.54200354628879, 9.771725920359758]), + { + "landcover": 2, + "system:index": "145" + }), + ee.Feature( + ee.Geometry.Point([-13.540115271142305, 9.772233432596723]), + { + "landcover": 2, + "system:index": "146" + }), + ee.Feature( + ee.Geometry.Point([-13.540801916650118, 9.770710893563262]), + { + "landcover": 2, + "system:index": "147" + }), + ee.Feature( + ee.Geometry.Point([-13.538055334618868, 9.772571773657894]), + { + "landcover": 2, + "system:index": "148" + }), + ee.Feature( + ee.Geometry.Point([-13.538055334618868, 9.77054172212945]), + { + "landcover": 2, + "system:index": "149" + }), + ee.Feature( + ee.Geometry.Point([-13.53822699599582, 9.768511658215099]), + { + "landcover": 2, + "system:index": "150" + }), + ee.Feature( + ee.Geometry.Point([-13.538570318749727, 9.76698910215254]), + { + "landcover": 2, + "system:index": "151" + }), + ee.Feature( + ee.Geometry.Point([-13.539600287011446, 9.765974060908194]), + { + "landcover": 2, + "system:index": "152" + }), + ee.Feature( + ee.Geometry.Point([-13.53822699599582, 9.765297365025766]), + { + "landcover": 2, + "system:index": "153" + }), + ee.Feature( + ee.Geometry.Point([-13.535308752587618, 9.770034207311948]), + { + "landcover": 2, + "system:index": "154" + }), + ee.Feature( + ee.Geometry.Point([-13.53376380019504, 9.772064261937096]), + { + "landcover": 2, + "system:index": "155" + }), + ee.Feature( + ee.Geometry.Point([-13.531703863671602, 9.77240260317031]), + { + "landcover": 2, + "system:index": "156" + }), + ee.Feature( + ee.Geometry.Point([-13.533420477441133, 9.771049236172841]), + { + "landcover": 2, + "system:index": "157" + }), + ee.Feature( + ee.Geometry.Point([-13.533420477441133, 9.769865035534101]), + { + "landcover": 2, + "system:index": "158" + }), + ee.Feature( + ee.Geometry.Point([-13.53548041396457, 9.768680830680962]), + { + "landcover": 2, + "system:index": "159" + }), + ee.Feature( + ee.Geometry.Point([-13.536167059472383, 9.76698910215254]), + { + "landcover": 2, + "system:index": "160" + }), + ee.Feature( + ee.Geometry.Point([-13.536853704980196, 9.765297365025766]), + { + "landcover": 2, + "system:index": "161" + }), + ee.Feature( + ee.Geometry.Point([-13.536853704980196, 9.763943969134523]), + { + "landcover": 2, + "system:index": "162" + }), + ee.Feature( + ee.Geometry.Point([-13.497199926904024, 9.76326726912586]), + { + "landcover": 2, + "system:index": "163" + }), + ee.Feature( + ee.Geometry.Point([-13.495654974511446, 9.764451493238456]), + { + "landcover": 2, + "system:index": "164" + }), + ee.Feature( + ee.Geometry.Point([-13.49702826552707, 9.763098093908816]), + { + "landcover": 2, + "system:index": "165" + }), + ee.Feature( + ee.Geometry.Point([-13.49754324965793, 9.76242139218114]), + { + "landcover": 2, + "system:index": "166" + }), + ee.Feature( + ee.Geometry.Point([-13.496341620019258, 9.76242139218114]), + { + "landcover": 2, + "system:index": "167" + }), + ee.Feature( + ee.Geometry.Point([-13.55745307021457, 9.72384712346435]), + { + "landcover": 2, + "system:index": "168" + }), + ee.Feature( + ee.Geometry.Point([-13.558139715722383, 9.722324363538974]), + { + "landcover": 2, + "system:index": "169" + }), + ee.Feature( + ee.Geometry.Point([-13.560542974999727, 9.721139989914178]), + { + "landcover": 2, + "system:index": "170" + }), + ee.Feature( + ee.Geometry.Point([-13.559856329491915, 9.718432834451587]), + { + "landcover": 2, + "system:index": "171" + }), + ee.Feature( + ee.Geometry.Point([-13.560886297753633, 9.717079248504964]), + { + "landcover": 2, + "system:index": "172" + }), + ee.Feature( + ee.Geometry.Point([-13.562087927392305, 9.719786414921563]), + { + "landcover": 2, + "system:index": "173" + }), + ee.Feature( + ee.Geometry.Point([-13.564319525292696, 9.720632399933873]), + { + "landcover": 2, + "system:index": "174" + }), + ee.Feature( + ee.Geometry.Point([-13.56346121840793, 9.71826363650775]), + { + "landcover": 2, + "system:index": "175" + }), + ee.Feature( + ee.Geometry.Point([-13.566379461816133, 9.72080159667957]), + { + "landcover": 2, + "system:index": "176" + }), + ee.Feature( + ee.Geometry.Point([-13.566036139062227, 9.717756042162808]), + { + "landcover": 2, + "system:index": "177" + }), + ee.Feature( + ee.Geometry.Point([-13.567237768700899, 9.718771230082542]), + { + "landcover": 2, + "system:index": "178" + }), + ee.Feature( + ee.Geometry.Point([-13.569641027978243, 9.722324363538974]), + { + "landcover": 2, + "system:index": "179" + }), + ee.Feature( + ee.Geometry.Point([-13.573245916894258, 9.724693098204092]), + { + "landcover": 2, + "system:index": "180" + }), + ee.Feature( + ee.Geometry.Point([-13.57170096450168, 9.72012480918325]), + { + "landcover": 2, + "system:index": "181" + }), + ee.Feature( + ee.Geometry.Point([-13.570156012109102, 9.717756042162808]), + { + "landcover": 2, + "system:index": "182" + }), + ee.Feature( + ee.Geometry.Point([-13.571357641747774, 9.716402453478146]), + { + "landcover": 2, + "system:index": "183" + }), + ee.Feature( + ee.Geometry.Point([-13.575134192040743, 9.719109625371203]), + { + "landcover": 2, + "system:index": "184" + }), + ee.Feature( + ee.Geometry.Point([-13.575305853417696, 9.72080159667957]), + { + "landcover": 2, + "system:index": "185" + }), + ee.Feature( + ee.Geometry.Point([-13.576507483056368, 9.717586843876692]), + { + "landcover": 2, + "system:index": "186" + }), + ee.Feature( + ee.Geometry.Point([-13.574619207909883, 9.71741764550502]), + { + "landcover": 2, + "system:index": "187" + }), + ee.Feature( + ee.Geometry.Point([-13.573245916894258, 9.71741764550502]), + { + "landcover": 2, + "system:index": "188" + }), + ee.Feature( + ee.Geometry.Point([-13.54372016005832, 9.70574275130077]), + { + "landcover": 2, + "system:index": "189" + }), + ee.Feature( + ee.Geometry.Point([-13.548183355859102, 9.703712293368184]), + { + "landcover": 2, + "system:index": "190" + }), + ee.Feature( + ee.Geometry.Point([-13.547840033105196, 9.70692717941152]), + { + "landcover": 2, + "system:index": "191" + }), + ee.Feature( + ee.Geometry.Point([-13.545780096581758, 9.708280806409537]), + { + "landcover": 2, + "system:index": "192" + }), + ee.Feature( + ee.Geometry.Point([-13.546295080712618, 9.703881498665897]), + { + "landcover": 2, + "system:index": "193" + }), + ee.Feature( + ee.Geometry.Point([-13.54200354628879, 9.70692717941152]), + { + "landcover": 2, + "system:index": "194" + }), + ee.Feature( + ee.Geometry.Point([-13.54200354628879, 9.710311236647977]), + { + "landcover": 2, + "system:index": "195" + }), + ee.Feature( + ee.Geometry.Point([-13.54200354628879, 9.712172453550373]), + { + "landcover": 2, + "system:index": "196" + }), + ee.Feature( + ee.Geometry.Point([-13.540801916650118, 9.715048859317944]), + { + "landcover": 2, + "system:index": "197" + }), + ee.Feature( + ee.Geometry.Point([-13.53822699599582, 9.715218058887388]), + { + "landcover": 2, + "system:index": "198" + }), + ee.Feature( + ee.Geometry.Point([-13.537197027734102, 9.717586843876692]), + { + "landcover": 2, + "system:index": "199" + }), + ee.Feature( + ee.Geometry.Point([-13.535308752587618, 9.715048859317944]), + { + "landcover": 2, + "system:index": "200" + }), + ee.Feature( + ee.Geometry.Point([-13.535823736718477, 9.711834051246822]), + { + "landcover": 2, + "system:index": "201" + }), + ee.Feature( + ee.Geometry.Point([-13.538570318749727, 9.713864459936698]), + { + "landcover": 2, + "system:index": "202" + }), + ee.Feature( + ee.Geometry.Point([-13.53651038222629, 9.710142034598336]), + { + "landcover": 2, + "system:index": "203" + }), + ee.Feature( + ee.Geometry.Point([-13.540630255273165, 9.707434790176865]), + { + "landcover": 2, + "system:index": "204" + }), + ee.Feature( + ee.Geometry.Point([-13.531188879540743, 9.717586843876692]), + { + "landcover": 2, + "system:index": "205" + }), + ee.Feature( + ee.Geometry.Point([-13.530330572655977, 9.72130918640309]), + { + "landcover": 2, + "system:index": "206" + }), + ee.Feature( + ee.Geometry.Point([-13.529815588525118, 9.723001146584146]), + { + "landcover": 2, + "system:index": "207" + }), + ee.Feature( + ee.Geometry.Point([-13.527583990624727, 9.724693098204092]), + { + "landcover": 2, + "system:index": "208" + }), + ee.Feature( + ee.Geometry.Point([-13.526725683739961, 9.725200682020445]), + { + "landcover": 2, + "system:index": "209" + }), + ee.Feature( + ee.Geometry.Point([-13.526554022363008, 9.722324363538974]), + { + "landcover": 2, + "system:index": "210" + }), + ee.Feature( + ee.Geometry.Point([-13.528098974755586, 9.721647579124117]), + { + "landcover": 2, + "system:index": "211" + }), + ee.Feature( + ee.Geometry.Point([-13.526897345116915, 9.720970793339673]), + { + "landcover": 2, + "system:index": "212" + }), + ee.Feature( + ee.Geometry.Point([-13.52174750380832, 9.726046653335084]), + { + "landcover": 2, + "system:index": "213" + }), + ee.Feature( + ee.Geometry.Point([-13.52277747207004, 9.727738589541413]), + { + "landcover": 2, + "system:index": "214" + }), + ee.Feature( + ee.Geometry.Point([-13.52277747207004, 9.730276477790866]), + { + "landcover": 2, + "system:index": "215" + }), + ee.Feature( + ee.Geometry.Point([-13.521404181054415, 9.732137583589529]), + { + "landcover": 2, + "system:index": "216" + }), + ee.Feature( + ee.Geometry.Point([-13.517970953515352, 9.733321918244974]), + { + "landcover": 2, + "system:index": "217" + }), + ee.Feature( + ee.Geometry.Point([-13.517970953515352, 9.731799201488183]), + { + "landcover": 2, + "system:index": "218" + }), + ee.Feature( + ee.Geometry.Point([-13.519859228661836, 9.732137583589529]), + { + "landcover": 2, + "system:index": "219" + }), + ee.Feature( + ee.Geometry.Point([-13.50852957778293, 9.740766211334252]), + { + "landcover": 2, + "system:index": "220" + }), + ee.Feature( + ee.Geometry.Point([-13.509731207421602, 9.737213273972818]), + { + "landcover": 2, + "system:index": "221" + }), + ee.Feature( + ee.Geometry.Point([-13.510246191552461, 9.736198142067588]), + { + "landcover": 2, + "system:index": "222" + }), + ee.Feature( + ee.Geometry.Point([-13.511447821191133, 9.737720838768078]), + { + "landcover": 2, + "system:index": "223" + }), + ee.Feature( + ee.Geometry.Point([-13.51453772597629, 9.737720838768078]), + { + "landcover": 2, + "system:index": "224" + }), + ee.Feature( + ee.Geometry.Point([-13.51076117568332, 9.741950515384083]), + { + "landcover": 2, + "system:index": "225" + }), + ee.Feature( + ee.Geometry.Point([-13.50028983168918, 9.754808403012264]), + { + "landcover": 2, + "system:index": "226" + }), + ee.Feature( + ee.Geometry.Point([-13.497714911034883, 9.756500193416775]), + { + "landcover": 2, + "system:index": "227" + }), + ee.Feature( + ee.Geometry.Point([-13.495483313134493, 9.758530330563973]), + { + "landcover": 2, + "system:index": "228" + }), + ee.Feature( + ee.Geometry.Point([-13.501148138573946, 9.752947423648195]), + { + "landcover": 2, + "system:index": "229" + }), + ee.Feature( + ee.Geometry.Point([-13.501834784081758, 9.749563798187735]), + { + "landcover": 2, + "system:index": "230" + }), + ee.Feature( + ee.Geometry.Point([-13.507842932275118, 9.74770278954872]), + { + "landcover": 2, + "system:index": "231" + }), + ee.Feature( + ee.Geometry.Point([-13.509216223290743, 9.749056251407033]), + { + "landcover": 2, + "system:index": "232" + }), + ee.Feature( + ee.Geometry.Point([-13.510417852929415, 9.747533606430212]), + { + "landcover": 2, + "system:index": "233" + }), + ee.Feature( + ee.Geometry.Point([-13.508872900536836, 9.747364423225903]), + { + "landcover": 2, + "system:index": "234" + }), + ee.Feature( + ee.Geometry.Point([-13.661651526025118, 10.022341913400517]), + { + "landcover": 2, + "system:index": "235" + }), + ee.Feature( + ee.Geometry.Point([-13.660964880517305, 10.028765438852059]), + { + "landcover": 2, + "system:index": "236" + }), + ee.Feature( + ee.Geometry.Point([-13.661308203271211, 10.020989576032427]), + { + "landcover": 2, + "system:index": "237" + }), + ee.Feature( + ee.Geometry.Point([-13.658561621239961, 10.020989576032427]), + { + "landcover": 2, + "system:index": "238" + }), + ee.Feature( + ee.Geometry.Point([-13.655471716454805, 10.024370408875624]), + { + "landcover": 2, + "system:index": "239" + }), + ee.Feature( + ee.Geometry.Point([-13.652038488915743, 10.024370408875624]), + { + "landcover": 2, + "system:index": "240" + }), + ee.Feature( + ee.Geometry.Point([-13.655471716454805, 10.020989576032427]), + { + "landcover": 2, + "system:index": "241" + }), + ee.Feature( + ee.Geometry.Point([-13.652725134423555, 10.018284884376252]), + { + "landcover": 2, + "system:index": "242" + }), + ee.Feature( + ee.Geometry.Point([-13.658904943993868, 10.012537339724123]), + { + "landcover": 2, + "system:index": "243" + }), + ee.Feature( + ee.Geometry.Point([-13.655471716454805, 10.009156383550605]), + { + "landcover": 2, + "system:index": "244" + }), + ee.Feature( + ee.Geometry.Point([-13.658218298486055, 10.00780399122132]), + { + "landcover": 2, + "system:index": "245" + }), + ee.Feature( + ee.Geometry.Point([-13.654441748193086, 10.005775392165521]), + { + "landcover": 2, + "system:index": "246" + }), + ee.Feature( + ee.Geometry.Point([-13.656501684716524, 10.003408677251185]), + { + "landcover": 2, + "system:index": "247" + }), + ee.Feature( + ee.Geometry.Point([-13.65409842543918, 10.00239436558026]), + { + "landcover": 2, + "system:index": "248" + }), + ee.Feature( + ee.Geometry.Point([-13.657874975732149, 10.000365732737786]), + { + "landcover": 2, + "system:index": "249" + }), + ee.Feature( + ee.Geometry.Point([-13.655471716454805, 9.999689518975616]), + { + "landcover": 2, + "system:index": "250" + }), + ee.Feature( + ee.Geometry.Point([-13.645515356591524, 10.003070573712783]), + { + "landcover": 2, + "system:index": "251" + }), + ee.Feature( + ee.Geometry.Point([-13.645172033837618, 10.000703839091145]), + { + "landcover": 2, + "system:index": "252" + }), + ee.Feature( + ee.Geometry.Point([-13.643798742821993, 9.999689518975616]), + { + "landcover": 2, + "system:index": "253" + }), + ee.Feature( + ee.Geometry.Point([-13.668517981103243, 9.988193669793844]), + { + "landcover": 2, + "system:index": "254" + }), + ee.Feature( + ee.Geometry.Point([-13.669204626611055, 9.984136214247286]), + { + "landcover": 2, + "system:index": "255" + }), + ee.Feature( + ee.Geometry.Point([-13.669204626611055, 9.981093089391116]), + { + "landcover": 2, + "system:index": "256" + }), + ee.Feature( + ee.Geometry.Point([-13.669204626611055, 9.976697414383944]), + { + "landcover": 2, + "system:index": "257" + }), + ee.Feature( + ee.Geometry.Point([-13.666458044579805, 9.974330487883972]), + { + "landcover": 2, + "system:index": "258" + }), + ee.Feature( + ee.Geometry.Point([-13.66508475356418, 9.973316085548204]), + { + "landcover": 2, + "system:index": "259" + }), + ee.Feature( + ee.Geometry.Point([-13.666458044579805, 9.969596583299666]), + { + "landcover": 2, + "system:index": "260" + }), + ee.Feature( + ee.Geometry.Point([-13.669204626611055, 9.966553322616255]), + { + "landcover": 2, + "system:index": "261" + }), + ee.Feature( + ee.Geometry.Point([-13.671951208642305, 9.962833743207232]), + { + "landcover": 2, + "system:index": "262" + }), + ee.Feature( + ee.Geometry.Point([-13.676757727196993, 9.961143011271028]), + { + "landcover": 2, + "system:index": "263" + }), + ee.Feature( + ee.Geometry.Point([-13.681907568505586, 9.960128567903281]), + { + "landcover": 2, + "system:index": "264" + }), + ee.Feature( + ee.Geometry.Point([-13.68431082778293, 9.956408915238322]), + { + "landcover": 2, + "system:index": "265" + }), + ee.Feature( + ee.Geometry.Point([-13.683624182275118, 9.952689220182753]), + { + "landcover": 2, + "system:index": "266" + }), + ee.Feature( + ee.Geometry.Point([-13.682937536767305, 9.949307642450698]), + { + "landcover": 2, + "system:index": "267" + }), + ee.Feature( + ee.Geometry.Point([-13.676414404443086, 9.958099671705611]), + { + "landcover": 2, + "system:index": "268" + }), + ee.Feature( + ee.Geometry.Point([-13.671951208642305, 9.960128567903281]), + { + "landcover": 2, + "system:index": "269" + }), + ee.Feature( + ee.Geometry.Point([-13.668174658349336, 9.96046671604301]), + { + "landcover": 2, + "system:index": "270" + }), + ee.Feature( + ee.Geometry.Point([-13.667584617106092, 9.953089708729708]), + { + "landcover": 2, + "system:index": "271" + }), + ee.Feature( + ee.Geometry.Point([-13.667241294352186, 9.951145308196883]), + { + "landcover": 2, + "system:index": "272" + }), + ee.Feature( + ee.Geometry.Point([-13.667241294352186, 9.950215373414666]), + { + "landcover": 2, + "system:index": "273" + }), + ee.Feature( + ee.Geometry.Point([-13.666468818155897, 9.945734741445749]), + { + "landcover": 2, + "system:index": "274" + }), + ee.Feature( + ee.Geometry.Point([-13.666726310221327, 9.944551168024388]), + { + "landcover": 2, + "system:index": "275" + }), + ee.Feature( + ee.Geometry.Point([-13.666726310221327, 9.942691258273008]), + { + "landcover": 2, + "system:index": "276" + }), + ee.Feature( + ee.Geometry.Point([-13.665696341959608, 9.940746795853128]), + { + "landcover": 2, + "system:index": "277" + }), + ee.Feature( + ee.Geometry.Point([-13.664580543009412, 9.938633236626876]), + { + "landcover": 2, + "system:index": "278" + }), + ee.Feature( + ee.Geometry.Point([-13.662434775797498, 9.938633236626876]), + { + "landcover": 2, + "system:index": "279" + }), + ee.Feature( + ee.Geometry.Point([-13.661748130289686, 9.93990137380219]), + { + "landcover": 2, + "system:index": "280" + }), + ee.Feature( + ee.Geometry.Point([-13.662692267862928, 9.942860341415056]), + { + "landcover": 2, + "system:index": "281" + }), + ee.Feature( + ee.Geometry.Point([-13.66440888163246, 9.944466626901695]), + { + "landcover": 2, + "system:index": "282" + }), + ee.Feature( + ee.Geometry.Point([-13.664494712320936, 9.946326526548747]), + { + "landcover": 2, + "system:index": "283" + }), + ee.Feature( + ee.Geometry.Point([-13.6638938975016, 9.947848254748799]), + { + "landcover": 2, + "system:index": "284" + }), + ee.Feature( + ee.Geometry.Point([-13.662434775797498, 9.947763714479182]), + { + "landcover": 2, + "system:index": "285" + }), + ee.Feature( + ee.Geometry.Point([-13.661919791666639, 9.946411067190247]), + { + "landcover": 2, + "system:index": "286" + }), + ee.Feature( + ee.Geometry.Point([-13.66088982340492, 9.944889332296516]), + { + "landcover": 2, + "system:index": "287" + }), + ee.Feature( + ee.Geometry.Point([-13.66088982340492, 9.942860341415056]), + { + "landcover": 2, + "system:index": "288" + }), + ee.Feature( + ee.Geometry.Point([-13.659945685831678, 9.947256472402119]), + { + "landcover": 2, + "system:index": "289" + }), + ee.Feature( + ee.Geometry.Point([-13.659173209635389, 9.94962359535643]), + { + "landcover": 2, + "system:index": "290" + }), + ee.Feature( + ee.Geometry.Point([-13.6584007334391, 9.95199070115553]), + { + "landcover": 2, + "system:index": "291" + }), + ee.Feature( + ee.Geometry.Point([-13.657542426554334, 9.950722610896857]), + { + "landcover": 2, + "system:index": "292" + }), + ee.Feature( + ee.Geometry.Point([-13.653680045572889, 9.949454515714292]), + { + "landcover": 2, + "system:index": "293" + }), + ee.Feature( + ee.Geometry.Point([-13.653250892130506, 9.950553531823656]), + { + "landcover": 2, + "system:index": "294" + }), + ee.Feature( + ee.Geometry.Point([-13.657027442423475, 9.95833107856939]), + { + "landcover": 2, + "system:index": "295" + }), + ee.Feature( + ee.Geometry.Point([-13.658057410685194, 9.960867195046598]), + { + "landcover": 2, + "system:index": "296" + }), + ee.Feature( + ee.Geometry.Point([-13.658572394816053, 9.96272700126694]), + { + "landcover": 2, + "system:index": "297" + }), + ee.Feature( + ee.Geometry.Point([-13.659001548258436, 9.965263083568694]), + { + "landcover": 2, + "system:index": "298" + }), + ee.Feature( + ee.Geometry.Point([-13.659173209635389, 9.966953794146162]), + { + "landcover": 2, + "system:index": "299" + }), + ee.Feature( + ee.Geometry.Point([-13.660117347208631, 9.96500947622598]), + { + "landcover": 2, + "system:index": "300" + }), + ee.Feature( + ee.Geometry.Point([-13.660203177897108, 9.963403291808957]), + { + "landcover": 2, + "system:index": "301" + }), + ee.Feature( + ee.Geometry.Point([-13.661061484781873, 9.961036268777496]), + { + "landcover": 2, + "system:index": "302" + }), + ee.Feature( + ee.Geometry.Point([-13.661061484781873, 9.959937287960484]), + { + "landcover": 2, + "system:index": "303" + }), + ee.Feature( + ee.Geometry.Point([-13.661748130289686, 9.958246541014008]), + { + "landcover": 2, + "system:index": "304" + }), + ee.Feature( + ee.Geometry.Point([-13.660289008585584, 9.959260990233174]), + { + "landcover": 2, + "system:index": "305" + }), + ee.Feature( + ee.Geometry.Point([-13.659602363077772, 9.96230431896613]), + { + "landcover": 2, + "system:index": "306" + }), + ee.Feature( + ee.Geometry.Point([-13.663293082682264, 9.966192975471168]), + { + "landcover": 2, + "system:index": "307" + }), + ee.Feature( + ee.Geometry.Point([-13.663550574747694, 9.964755868686034]), + { + "landcover": 2, + "system:index": "308" + }), + ee.Feature( + ee.Geometry.Point([-13.66440888163246, 9.963656900400698]), + { + "landcover": 2, + "system:index": "309" + }), + ee.Feature( + ee.Geometry.Point([-13.665181357828748, 9.962135245892433]), + { + "landcover": 2, + "system:index": "310" + }), + ee.Feature( + ee.Geometry.Point([-13.666039664713514, 9.960613584285971]), + { + "landcover": 2, + "system:index": "311" + }), + ee.Feature( + ee.Geometry.Point([-13.660718162027967, 9.973970149337196]), + { + "landcover": 2, + "system:index": "312" + }), + ee.Feature( + ee.Geometry.Point([-13.660289008585584, 9.972110407252433]), + { + "landcover": 2, + "system:index": "313" + }), + ee.Feature( + ee.Geometry.Point([-13.659516532389295, 9.970842395200114]), + { + "landcover": 2, + "system:index": "314" + }), + ee.Feature( + ee.Geometry.Point([-13.658057410685194, 9.969658912833557]), + { + "landcover": 2, + "system:index": "315" + }), + ee.Feature( + ee.Geometry.Point([-13.655825812784803, 9.968475426169892]), + { + "landcover": 2, + "system:index": "316" + }), + ee.Feature( + ee.Geometry.Point([-13.655482490030897, 9.96982798200615]), + { + "landcover": 2, + "system:index": "317" + }), + ee.Feature( + ee.Geometry.Point([-13.653851706949842, 9.972448542966447]), + { + "landcover": 2, + "system:index": "318" + }), + ee.Feature( + ee.Geometry.Point([-13.653079230753553, 9.973801082313564]), + { + "landcover": 2, + "system:index": "319" + }), + ee.Feature( + ee.Geometry.Point([-13.649560172526014, 9.973209347040036]), + { + "landcover": 2, + "system:index": "320" + }), + ee.Feature( + ee.Geometry.Point([-13.649731833902967, 9.971434134771844]), + { + "landcover": 2, + "system:index": "321" + }), + ee.Feature( + ee.Geometry.Point([-13.649216849772108, 9.970081585600642]), + { + "landcover": 2, + "system:index": "322" + }), + ee.Feature( + ee.Geometry.Point([-13.647843558756483, 9.968559961074066]), + { + "landcover": 2, + "system:index": "323" + }), + ee.Feature( + ee.Geometry.Point([-13.645783622233045, 9.967122864721723]), + { + "landcover": 2, + "system:index": "324" + }), + ee.Feature( + ee.Geometry.Point([-13.643466193644178, 9.965516690714173]), + { + "landcover": 2, + "system:index": "325" + }), + ee.Feature( + ee.Geometry.Point([-13.638058860270155, 9.969320774225237]), + { + "landcover": 2, + "system:index": "326" + }), + ee.Feature( + ee.Geometry.Point([-13.635226447550428, 9.969405308910208]), + { + "landcover": 2, + "system:index": "327" + }), + ee.Feature( + ee.Geometry.Point([-13.634110648600233, 9.970673326553726]), + { + "landcover": 2, + "system:index": "328" + }), + ee.Feature( + ee.Geometry.Point([-13.631106574503553, 9.969912516559571]), + { + "landcover": 2, + "system:index": "329" + }), + ee.Feature( + ee.Geometry.Point([-13.629990775553358, 9.967122864721723]), + { + "landcover": 2, + "system:index": "330" + }), + ee.Feature( + ee.Geometry.Point([-13.63891716715492, 9.973547481613643]), + { + "landcover": 2, + "system:index": "331" + }), + ee.Feature( + ee.Geometry.Point([-13.642522056070936, 9.972617610691863]), + { + "landcover": 2, + "system:index": "332" + }), + ee.Feature( + ee.Geometry.Point([-13.645783622233045, 9.97498454963648]), + { + "landcover": 2, + "system:index": "333" + }), + ee.Feature( + ee.Geometry.Point([-13.643981177775037, 9.977351471383914]), + { + "landcover": 2, + "system:index": "334" + }), + ee.Feature( + ee.Geometry.Point([-13.643981177775037, 9.979380247762634]), + { + "landcover": 2, + "system:index": "335" + }), + ee.Feature( + ee.Geometry.Point([-13.644753653971327, 9.980310099378729]), + { + "landcover": 2, + "system:index": "336" + }), + ee.Feature( + ee.Geometry.Point([-13.648272712198866, 9.979887439882406]), + { + "landcover": 2, + "system:index": "337" + }), + ee.Feature( + ee.Geometry.Point([-13.650075156656873, 9.982000731877168]), + { + "landcover": 2, + "system:index": "338" + }), + ee.Feature( + ee.Geometry.Point([-13.65067597147621, 9.979549311890345]), + { + "landcover": 2, + "system:index": "339" + }), + ee.Feature( + ee.Geometry.Point([-13.649302680460584, 9.977266938760529]), + { + "landcover": 2, + "system:index": "340" + }), + ee.Feature( + ee.Geometry.Point([-13.641062934366834, 9.979887439882406]), + { + "landcover": 2, + "system:index": "341" + }), + ee.Feature( + ee.Geometry.Point([-13.640462119547498, 9.982761513637067]), + { + "landcover": 2, + "system:index": "342" + }), + ee.Feature( + ee.Geometry.Point([-13.638144690958631, 9.979718375930274]), + { + "landcover": 2, + "system:index": "343" + }), + ee.Feature( + ee.Geometry.Point([-13.634797294108045, 9.975829880806362]), + { + "landcover": 2, + "system:index": "344" + }), + ee.Feature( + ee.Geometry.Point([-13.646212775675428, 9.98783334659046]), + { + "landcover": 2, + "system:index": "345" + }), + ee.Feature( + ee.Geometry.Point([-13.646212775675428, 9.99020017491354]), + { + "landcover": 2, + "system:index": "346" + }), + ee.Feature( + ee.Geometry.Point([-13.648530204264295, 9.991045466569636]), + { + "landcover": 2, + "system:index": "347" + }), + ee.Feature( + ee.Geometry.Point([-13.651105124918592, 9.992482457343009]), + { + "landcover": 2, + "system:index": "348" + }), + ee.Feature( + ee.Geometry.Point([-13.64715691324867, 9.994173026593714]), + { + "landcover": 2, + "system:index": "349" + }), + ee.Feature( + ee.Geometry.Point([-13.643466193644178, 9.99518736392491]), + { + "landcover": 2, + "system:index": "350" + }), + ee.Feature( + ee.Geometry.Point([-13.642607886759412, 9.98741069686363]), + { + "landcover": 2, + "system:index": "351" + }), + ee.Feature( + ee.Geometry.Point([-13.646727759806287, 9.986480865532018]), + { + "landcover": 2, + "system:index": "352" + }), + ee.Feature( + ee.Geometry.Point([-13.64964600321449, 9.99036923342051]), + { + "landcover": 2, + "system:index": "353" + }), + ee.Feature( + ee.Geometry.Point([-13.657370765177381, 9.981916200460754]), + { + "landcover": 2, + "system:index": "354" + }), + ee.Feature( + ee.Geometry.Point([-13.654624183146131, 9.980732758326381]), + { + "landcover": 2, + "system:index": "355" + }), + ee.Feature( + ee.Geometry.Point([-13.652821738688123, 9.979295715665872]), + { + "landcover": 2, + "system:index": "356" + }), + ee.Feature( + ee.Geometry.Point([-13.653250892130506, 9.984283071822539]), + { + "landcover": 2, + "system:index": "357" + }), + ee.Feature( + ee.Geometry.Point([-13.648186881510389, 9.975153616045933]), + { + "landcover": 2, + "system:index": "358" + }), + ee.Feature( + ee.Geometry.Point([-13.646384437052381, 9.973124813341814]), + { + "landcover": 2, + "system:index": "359" + }), + ee.Feature( + ee.Geometry.Point([-13.643380362955702, 9.97278667832957]), + { + "landcover": 2, + "system:index": "360" + }), + ee.Feature( + ee.Geometry.Point([-13.641320426432264, 9.970081585600642]), + { + "landcover": 2, + "system:index": "361" + }), + ee.Feature( + ee.Geometry.Point([-13.639775474039686, 9.973040279621646]), + { + "landcover": 2, + "system:index": "362" + }), + ee.Feature( + ee.Geometry.Point([-13.640290458170545, 9.976421611320037]), + { + "landcover": 2, + "system:index": "363" + }), + ee.Feature( + ee.Geometry.Point([-13.640118796793592, 9.977943199133255]), + { + "landcover": 2, + "system:index": "364" + }), + ee.Feature( + ee.Geometry.Point([-13.637114722696912, 9.976337078455325]), + { + "landcover": 2, + "system:index": "365" + }), + ee.Feature( + ee.Geometry.Point([-13.636256415812147, 9.974477349881646]), + { + "landcover": 2, + "system:index": "366" + }), + ee.Feature( + ee.Geometry.Point([-13.63617058512367, 9.973378414370707]), + { + "landcover": 2, + "system:index": "367" + }), + ee.Feature( + ee.Geometry.Point([-13.6364280771891, 9.971856805236678]), + { + "landcover": 2, + "system:index": "368" + }), + ee.Feature( + ee.Geometry.Point([-13.636256415812147, 9.969658912833557]), + { + "landcover": 2, + "system:index": "369" + }), + ee.Feature( + ee.Geometry.Point([-13.636256415812147, 9.9673764704207]), + { + "landcover": 2, + "system:index": "370" + }), + ee.Feature( + ee.Geometry.Point([-13.634453971354139, 9.968306356295757]), + { + "landcover": 2, + "system:index": "371" + }), + ee.Feature( + ee.Geometry.Point([-13.631879050699842, 9.968052751320142]), + { + "landcover": 2, + "system:index": "372" + }), + ee.Feature( + ee.Geometry.Point([-13.631020743815077, 9.966784723482908]), + { + "landcover": 2, + "system:index": "373" + }), + ee.Feature( + ee.Geometry.Point([-13.629132468668592, 9.96500947622598]), + { + "landcover": 2, + "system:index": "374" + }), + ee.Feature( + ee.Geometry.Point([-13.627244193522108, 9.962642464850603]), + { + "landcover": 2, + "system:index": "375" + }), + ee.Feature( + ee.Geometry.Point([-13.626385886637342, 9.960698121228079]), + { + "landcover": 2, + "system:index": "376" + }), + ee.Feature( + ee.Geometry.Point([-13.624411780802381, 9.958415616102878]), + { + "landcover": 2, + "system:index": "377" + }), + ee.Feature( + ee.Geometry.Point([-13.624240119425428, 9.961036268777496]), + { + "landcover": 2, + "system:index": "378" + }), + ee.Feature( + ee.Geometry.Point([-13.625270087687147, 9.962811537661368]), + { + "landcover": 2, + "system:index": "379" + }), + ee.Feature( + ee.Geometry.Point([-13.627587516276014, 9.966869258825502]), + { + "landcover": 2, + "system:index": "380" + }), + ee.Feature( + ee.Geometry.Point([-13.626643378702772, 9.966108439953251]), + { + "landcover": 2, + "system:index": "381" + }), + ee.Feature( + ee.Geometry.Point([-13.624583442179334, 9.965770297662408]), + { + "landcover": 2, + "system:index": "382" + }), + ee.Feature( + ee.Geometry.Point([-13.62321015116371, 9.964671332795572]), + { + "landcover": 2, + "system:index": "383" + }), + ee.Feature( + ee.Geometry.Point([-13.621751029459608, 9.9651785478097]), + { + "landcover": 2, + "system:index": "384" + }), + ee.Feature( + ee.Geometry.Point([-13.618575293985975, 9.965770297662408]), + { + "landcover": 2, + "system:index": "385" + }), + ee.Feature( + ee.Geometry.Point([-13.619776923624647, 9.9650940120288]), + { + "landcover": 2, + "system:index": "386" + }), + ee.Feature( + ee.Geometry.Point([-13.62818833109535, 9.97134960061309]), + { + "landcover": 2, + "system:index": "387" + }), + ee.Feature( + ee.Geometry.Point([-13.628359992472303, 9.96957437821436]), + { + "landcover": 2, + "system:index": "388" + }), + ee.Feature( + ee.Geometry.Point([-13.633252341715467, 9.975407215495617]), + { + "landcover": 2, + "system:index": "389" + }), + ee.Feature( + ee.Geometry.Point([-13.63316651102699, 9.973378414370707]), + { + "landcover": 2, + "system:index": "390" + }), + ee.Feature( + ee.Geometry.Point([-13.631621558634412, 9.976844275314518]), + { + "landcover": 2, + "system:index": "391" + }), + ee.Feature( + ee.Geometry.Point([-13.637887198893202, 9.984283071822539]), + { + "landcover": 2, + "system:index": "392" + }), + ee.Feature( + ee.Geometry.Point([-13.6364280771891, 9.986058214048352]), + { + "landcover": 2, + "system:index": "393" + }), + ee.Feature( + ee.Geometry.Point([-13.637715537516248, 9.98369135559561]), + { + "landcover": 2, + "system:index": "394" + }), + ee.Feature( + ee.Geometry.Point([-13.640719611612928, 9.98250791991466]), + { + "landcover": 2, + "system:index": "395" + }), + ee.Feature( + ee.Geometry.Point([-13.642007071940077, 9.982846044833973]), + { + "landcover": 2, + "system:index": "396" + }), + ee.Feature( + ee.Geometry.Point([-13.642779548136366, 9.98090182175181]), + { + "landcover": 2, + "system:index": "397" + }), + ee.Feature( + ee.Geometry.Point([-13.659945685831678, 9.970250654554006]), + { + "landcover": 2, + "system:index": "398" + }), + ee.Feature( + ee.Geometry.Point([-13.66415138956703, 9.970504257819616]), + { + "landcover": 2, + "system:index": "399" + }), + ee.Feature( + ee.Geometry.Point([-13.665782172648084, 9.967630075922393]), + { + "landcover": 2, + "system:index": "400" + }), + ee.Feature( + ee.Geometry.Point([-13.667756278483045, 9.96923623951836]), + { + "landcover": 2, + "system:index": "401" + }), + ee.Feature( + ee.Geometry.Point([-13.66887207743324, 9.97253307684012]), + { + "landcover": 2, + "system:index": "402" + }), + ee.Feature( + ee.Geometry.Point([-13.679171760050428, 9.97718240611521]), + { + "landcover": 2, + "system:index": "403" + }), + ee.Feature( + ee.Geometry.Point([-13.683978278605116, 9.976506144162817]), + { + "landcover": 2, + "system:index": "404" + }), + ee.Feature( + ee.Geometry.Point([-13.685179908243787, 9.973970149337196]), + { + "landcover": 2, + "system:index": "405" + }), + ee.Feature( + ee.Geometry.Point([-13.688527305094373, 9.97523814921776]), + { + "landcover": 2, + "system:index": "406" + }), + ee.Feature( + ee.Geometry.Point([-13.692303855387342, 9.97413921627307]), + { + "landcover": 2, + "system:index": "407" + }), + ee.Feature( + ee.Geometry.Point([-13.691531379191053, 9.971603203023564]), + { + "landcover": 2, + "system:index": "408" + }), + ee.Feature( + ee.Geometry.Point([-13.689385611979139, 9.970250654554006]), + { + "landcover": 2, + "system:index": "409" + }), + ee.Feature( + ee.Geometry.Point([-13.686209876505506, 9.970081585600642]), + { + "landcover": 2, + "system:index": "410" + }), + ee.Feature( + ee.Geometry.Point([-13.687668998209608, 9.969151704789562]), + { + "landcover": 2, + "system:index": "411" + }), + ee.Feature( + ee.Geometry.Point([-13.688441474405897, 9.96813728633393]), + { + "landcover": 2, + "system:index": "412" + }), + ee.Feature( + ee.Geometry.Point([-13.691016395060194, 9.96881356565509]), + { + "landcover": 2, + "system:index": "413" + }), + ee.Feature( + ee.Geometry.Point([-13.608361442057264, 9.874374531391176]), + { + "landcover": 2, + "system:index": "414" + }), + ee.Feature( + ee.Geometry.Point([-13.607245643107069, 9.871584065858906]), + { + "landcover": 2, + "system:index": "415" + }), + ee.Feature( + ee.Geometry.Point([-13.607331473795545, 9.869892863116872]), + { + "landcover": 2, + "system:index": "416" + }), + ee.Feature( + ee.Geometry.Point([-13.605014045206678, 9.869723742364956]), + { + "landcover": 2, + "system:index": "417" + }), + ee.Feature( + ee.Geometry.Point([-13.60321160074867, 9.87090758580443]), + { + "landcover": 2, + "system:index": "418" + }), + ee.Feature( + ee.Geometry.Point([-13.60398407694496, 9.869554621526174]), + { + "landcover": 2, + "system:index": "419" + }), + ee.Feature( + ee.Geometry.Point([-13.598147590128553, 9.86811709089016]), + { + "landcover": 2, + "system:index": "420" + }), + ee.Feature( + ee.Geometry.Point([-13.596259314982069, 9.86777884747573]), + { + "landcover": 2, + "system:index": "421" + }), + ee.Feature( + ee.Geometry.Point([-13.576775748697889, 9.853826004088361]), + { + "landcover": 2, + "system:index": "422" + }), + ee.Feature( + ee.Geometry.Point([-13.576861579386366, 9.851627320370765]), + { + "landcover": 2, + "system:index": "423" + }), + ee.Feature( + ee.Geometry.Point([-13.578578193155897, 9.84883666224464]), + { + "landcover": 2, + "system:index": "424" + }), + ee.Feature( + ee.Geometry.Point([-13.576432425943983, 9.849259490750422]), + { + "landcover": 2, + "system:index": "425" + }), + ee.Feature( + ee.Geometry.Point([-13.575659949747694, 9.849174925092612]), + { + "landcover": 2, + "system:index": "426" + }), + ee.Feature( + ee.Geometry.Point([-13.585530478922498, 9.841225656527765]), + { + "landcover": 2, + "system:index": "427" + }), + ee.Feature( + ee.Geometry.Point([-13.586302955118787, 9.839872570479478]), + { + "landcover": 2, + "system:index": "428" + }), + ee.Feature( + ee.Geometry.Point([-13.584157187906873, 9.83995713851988]), + { + "landcover": 2, + "system:index": "429" + }), + ee.Feature( + ee.Geometry.Point([-13.630505759684217, 9.831669367685807]), + { + "landcover": 2, + "system:index": "430" + }), + ee.Feature( + ee.Geometry.Point([-13.631879050699842, 9.833699045065439]), + { + "landcover": 2, + "system:index": "431" + }), + ee.Feature( + ee.Geometry.Point([-13.574458857821856, 9.69531181961584]), + { + "landcover": 2, + "system:index": "432" + }), + ee.Feature( + ee.Geometry.Point([-13.57737710123006, 9.69565023860672]), + { + "landcover": 2, + "system:index": "433" + }), + ee.Feature( + ee.Geometry.Point([-13.578578730868731, 9.697849953722374]), + { + "landcover": 2, + "system:index": "434" + }), + ee.Feature( + ee.Geometry.Point([-13.581325312899981, 9.701403309189935]), + { + "landcover": 2, + "system:index": "435" + }), + ee.Feature( + ee.Geometry.Point([-13.58287026529256, 9.704449012462995]), + { + "landcover": 2, + "system:index": "436" + }), + ee.Feature( + ee.Geometry.Point([-13.58458687906209, 9.704956626983607]), + { + "landcover": 2, + "system:index": "437" + }), + ee.Feature( + ee.Geometry.Point([-13.584758540439044, 9.702756958506706]), + { + "landcover": 2, + "system:index": "438" + }), + ee.Feature( + ee.Geometry.Point([-13.58458687906209, 9.701234102640901]), + { + "landcover": 2, + "system:index": "439" + }), + ee.Feature( + ee.Geometry.Point([-13.582698603915606, 9.701234102640901]), + { + "landcover": 2, + "system:index": "440" + }), + ee.Feature( + ee.Geometry.Point([-13.579437037753497, 9.698188370151598]), + { + "landcover": 2, + "system:index": "441" + }), + ee.Feature( + ee.Geometry.Point([-13.578750392245684, 9.695988657256075]), + { + "landcover": 2, + "system:index": "442" + }), + ee.Feature( + ee.Geometry.Point([-13.578063746737872, 9.694634980609585]), + { + "landcover": 2, + "system:index": "443" + }), + ee.Feature( + ee.Geometry.Point([-13.575660487460528, 9.694634980609585]), + { + "landcover": 2, + "system:index": "444" + }), + ee.Feature( + ee.Geometry.Point([-13.573085566806231, 9.694973400283457]), + { + "landcover": 2, + "system:index": "445" + }), + ee.Feature( + ee.Geometry.Point([-13.56810738687459, 9.692604455395546]), + { + "landcover": 2, + "system:index": "446" + }), + ee.Feature( + ee.Geometry.Point([-13.56639077310506, 9.693112087851434]), + { + "landcover": 2, + "system:index": "447" + }), + ee.Feature( + ee.Geometry.Point([-13.56639077310506, 9.692096822171477]), + { + "landcover": 2, + "system:index": "448" + }), + ee.Feature( + ee.Geometry.Point([-13.579780360507403, 9.686005163578422]), + { + "landcover": 2, + "system:index": "449" + }), + ee.Feature( + ee.Geometry.Point([-13.582526942538653, 9.69192761092609]), + { + "landcover": 2, + "system:index": "450" + }), + ee.Feature( + ee.Geometry.Point([-13.583556910800372, 9.693619719539091]), + { + "landcover": 2, + "system:index": "451" + }), + ee.Feature( + ee.Geometry.Point([-13.59282662515584, 9.676529030508604]), + { + "landcover": 2, + "system:index": "452" + }), + ee.Feature( + ee.Geometry.Point([-13.597461482333575, 9.67686746843577]), + { + "landcover": 2, + "system:index": "453" + }), + ee.Feature( + ee.Geometry.Point([-13.5988347733492, 9.68075948009447]), + { + "landcover": 2, + "system:index": "454" + }), + ee.Feature( + ee.Geometry.Point([-13.601409694003497, 9.680251828957084]), + { + "landcover": 2, + "system:index": "455" + }), + ee.Feature( + ee.Geometry.Point([-13.603126307773028, 9.67483683575991]), + { + "landcover": 2, + "system:index": "456" + }), + ee.Feature( + ee.Geometry.Point([-13.601924678134356, 9.671452420702959]), + { + "landcover": 2, + "system:index": "457" + }), + ee.Feature( + ee.Geometry.Point([-13.602439662265216, 9.669083309890828]), + { + "landcover": 2, + "system:index": "458" + }), + ee.Feature( + ee.Geometry.Point([-13.605529567050372, 9.668237194841453]), + { + "landcover": 2, + "system:index": "459" + }), + ee.Feature( + ee.Geometry.Point([-13.606731196689044, 9.665868061379152]), + { + "landcover": 2, + "system:index": "460" + }), + ee.Feature( + ee.Geometry.Point([-13.60209633951131, 9.664683488390903]), + { + "landcover": 2, + "system:index": "461" + }), + ee.Feature( + ee.Geometry.Point([-13.592483302401934, 9.665021938241727]), + { + "landcover": 2, + "system:index": "462" + }), + ee.Feature( + ee.Geometry.Point([-13.583385249423419, 9.667391077663392]), + { + "landcover": 2, + "system:index": "463" + }), + ee.Feature( + ee.Geometry.Point([-13.582183619784747, 9.672467748797905]), + { + "landcover": 2, + "system:index": "464" + }), + ee.Feature( + ee.Geometry.Point([-13.576690455722247, 9.673990735190353]), + { + "landcover": 2, + "system:index": "465" + }), + ee.Feature( + ee.Geometry.Point([-13.571025630282794, 9.68363615537873]), + { + "landcover": 2, + "system:index": "466" + }), + ee.Feature( + ee.Geometry.Point([-13.570682307528887, 9.687528088592995]), + { + "landcover": 2, + "system:index": "467" + }), + ee.Feature( + ee.Geometry.Point([-13.570338984774981, 9.69192761092609]), + { + "landcover": 2, + "system:index": "468" + }), + ee.Feature( + ee.Geometry.Point([-13.566905757235919, 9.691081553418952]), + { + "landcover": 2, + "system:index": "469" + }), + ee.Feature( + ee.Geometry.Point([-13.56261422281209, 9.691081553418952]), + { + "landcover": 2, + "system:index": "470" + }), + ee.Feature( + ee.Geometry.Point([-13.560554286288653, 9.69565023860672]), + { + "landcover": 2, + "system:index": "471" + }), + ee.Feature( + ee.Geometry.Point([-13.9981272866448, 10.157269797971763]), + { + "landcover": 2, + "system:index": "472" + }), + ee.Feature( + ee.Geometry.Point([-14.0475657632073, 10.1680837588802]), + { + "landcover": 2, + "system:index": "473" + }), + ee.Feature( + ee.Geometry.Point([-13.86903793117605, 10.008879012049832]), + { + "landcover": 2, + "system:index": "474" + }), + ee.Feature( + ee.Geometry.Point([-13.863888089867457, 10.008879012049832]), + { + "landcover": 2, + "system:index": "475" + }), + ee.Feature( + ee.Geometry.Point([-13.865261380883082, 10.010231399900807]), + { + "landcover": 2, + "system:index": "476" + }), + ee.Feature( + ee.Geometry.Point([-13.868351285668238, 10.008879012049832]), + { + "landcover": 2, + "system:index": "477" + }), + ee.Feature( + ee.Geometry.Point([-13.877621000023707, 10.01225997111249]), + { + "landcover": 2, + "system:index": "478" + }), + ee.Feature( + ee.Geometry.Point([-13.873157804222926, 10.0048218146976]), + { + "landcover": 2, + "system:index": "479" + }), + ee.Feature( + ee.Geometry.Point([-13.874874417992457, 9.997721597385633]), + { + "landcover": 2, + "system:index": "480" + }), + ee.Feature( + ee.Geometry.Point([-13.876591031761988, 9.994002374025342]), + { + "landcover": 2, + "system:index": "481" + }), + ee.Feature( + ee.Geometry.Point([-13.8662913491448, 9.992988032997298]), + { + "landcover": 2, + "system:index": "482" + }), + ee.Feature( + ee.Geometry.Point([-13.862858121605738, 9.998059706490045]), + { + "landcover": 2, + "system:index": "483" + }), + ee.Feature( + ee.Geometry.Point([-13.86457473537527, 9.984873190890044]), + { + "landcover": 2, + "system:index": "484" + }), + ee.Feature( + ee.Geometry.Point([-13.869724576683863, 9.975743751659701]), + { + "landcover": 2, + "system:index": "485" + }), + ee.Feature( + ee.Geometry.Point([-13.877621000023707, 9.97540561936557]), + { + "landcover": 2, + "system:index": "486" + }), + ee.Feature( + ee.Geometry.Point([-13.875904386254176, 9.982168198547233]), + { + "landcover": 2, + "system:index": "487" + }), + ee.Feature( + ee.Geometry.Point([-13.88105422756277, 9.982844448740403]), + { + "landcover": 2, + "system:index": "488" + }), + ee.Feature( + ee.Geometry.Point([-13.886204068871363, 9.981830072923847]), + { + "landcover": 2, + "system:index": "489" + }), + ee.Feature( + ee.Geometry.Point([-13.890667264672144, 9.988592518649739]), + { + "landcover": 2, + "system:index": "490" + }), + ee.Feature( + ee.Geometry.Point([-13.89478713771902, 9.987578160749882]), + { + "landcover": 2, + "system:index": "491" + }), + ee.Feature( + ee.Geometry.Point([-13.893413846703394, 9.994340486998162]), + { + "landcover": 2, + "system:index": "492" + }), + ee.Feature( + ee.Geometry.Point([-13.893413846703394, 10.0011026726001]), + { + "landcover": 2, + "system:index": "493" + }), + ee.Feature( + ee.Geometry.Point([-13.897877042504176, 9.998059706490045]), + { + "landcover": 2, + "system:index": "494" + }), + ee.Feature( + ee.Geometry.Point([-13.90028030178152, 9.995354823806883]), + { + "landcover": 2, + "system:index": "495" + }), + ee.Feature( + ee.Geometry.Point([-13.8992503335198, 10.005498017776539]), + { + "landcover": 2, + "system:index": "496" + }), + ee.Feature( + ee.Geometry.Point([-13.878994291039332, 9.992988032997298]), + { + "landcover": 2, + "system:index": "497" + }), + ee.Feature( + ee.Geometry.Point([-13.896160428734644, 10.014964713003298]), + { + "landcover": 2, + "system:index": "498" + }), + ee.Feature( + ee.Geometry.Point([-13.90199691555105, 10.01834560865809]), + { + "landcover": 2, + "system:index": "499" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.5434608508915, 9.634974841301608], + [-13.545349126037985, 9.632266991548065], + [-13.54174423712197, 9.632436232794046]]]), + { + "landcover": 2, + "system:index": "500" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.483379368957907, 9.632436232794046], + [-13.484924321350485, 9.629897605196554], + [-13.48131943243447, 9.629389877386695]]]), + { + "landcover": 2, + "system:index": "501" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.435829167541891, 9.591646642167026], + [-13.433940892395407, 9.586568755869056], + [-13.431537633118063, 9.589446234106036]]]), + { + "landcover": 2, + "system:index": "502" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.438919072327048, 9.66560587720521], + [-13.439777379211813, 9.662559821578215], + [-13.435657506164938, 9.664590528393632]]]), + { + "landcover": 2, + "system:index": "503" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.52801132696572, 9.802649707720889], + [-13.531272893127829, 9.798420802628165], + [-13.525608067688376, 9.799266587959883]]]), + { + "landcover": 2, + "system:index": "504" + }), + ee.Feature( + ee.Geometry.Point([-13.700941293708981, 9.913100953593409]), + { + "landcover": 2, + "system:index": "505" + }), + ee.Feature( + ee.Geometry.Point([-13.703344552986325, 9.910057166995815]), + { + "landcover": 2, + "system:index": "506" + }), + ee.Feature( + ee.Geometry.Point([-13.707636087410153, 9.905660536482868]), + { + "landcover": 2, + "system:index": "507" + }), + ee.Feature( + ee.Geometry.Point([-13.709009378425778, 9.902109368825391]), + { + "landcover": 2, + "system:index": "508" + }), + ee.Feature( + ee.Geometry.Point([-13.710725992195309, 9.897543525381757]), + { + "landcover": 2, + "system:index": "509" + }), + ee.Feature( + ee.Geometry.Point([-13.712099283210934, 9.892977618451745]), + { + "landcover": 2, + "system:index": "510" + }), + ee.Feature( + ee.Geometry.Point([-13.713300912849606, 9.889426313632375]), + { + "landcover": 2, + "system:index": "511" + }), + ee.Feature( + ee.Geometry.Point([-13.715532510749997, 9.885198519765332]), + { + "landcover": 2, + "system:index": "512" + }), + ee.Feature( + ee.Geometry.Point([-13.717420785896481, 9.88249270315871]), + { + "landcover": 2, + "system:index": "513" + }), + ee.Feature( + ee.Geometry.Point([-13.720854013435543, 9.877926587157914]), + { + "landcover": 2, + "system:index": "514" + }), + ee.Feature( + ee.Geometry.Point([-13.724802225105465, 9.873360407791562]), + { + "landcover": 2, + "system:index": "515" + }), + ee.Feature( + ee.Geometry.Point([-13.678281991951168, 9.891962963848515]), + { + "landcover": 2, + "system:index": "516" + }), + ee.Feature( + ee.Geometry.Point([-13.626096933357418, 9.910902666107052]), + { + "landcover": 2, + "system:index": "517" + }), + ee.Feature( + ee.Geometry.Point([-13.625581949226559, 9.908873464578067]), + { + "landcover": 2, + "system:index": "518" + }), + ee.Feature( + ee.Geometry.Point([-13.625581949226559, 9.906167843010932]), + { + "landcover": 2, + "system:index": "519" + }), + ee.Feature( + ee.Geometry.Point([-13.625581949226559, 9.903462199130923]), + { + "landcover": 2, + "system:index": "520" + }), + ee.Feature( + ee.Geometry.Point([-13.626611917488278, 9.90177116037774]), + { + "landcover": 2, + "system:index": "521" + }), + ee.Feature( + ee.Geometry.Point([-13.621633737556637, 9.913946444855837]), + { + "landcover": 2, + "system:index": "522" + }), + ee.Feature( + ee.Geometry.Point([-13.621633737556637, 9.91242455901354]), + { + "landcover": 2, + "system:index": "523" + }), + ee.Feature( + ee.Geometry.Point([-13.747289865486325, 9.918850251170033]), + { + "landcover": 2, + "system:index": "524" + }), + ee.Feature( + ee.Geometry.Point([-13.748319833748043, 9.916821098835793]), + { + "landcover": 2, + "system:index": "525" + }), + ee.Feature( + ee.Geometry.Point([-13.749349802009762, 9.91360824861252]), + { + "landcover": 2, + "system:index": "526" + }), + ee.Feature( + ee.Geometry.Point([-13.751581399910153, 9.911071765667707]), + { + "landcover": 2, + "system:index": "527" + }), + ee.Feature( + ee.Geometry.Point([-13.752611368171872, 9.909888066911998]), + { + "landcover": 2, + "system:index": "528" + }), + ee.Feature( + ee.Geometry.Point([-13.759992807380856, 9.912086361200327]), + { + "landcover": 2, + "system:index": "529" + }), + ee.Feature( + ee.Geometry.Point([-13.736818521492184, 9.893146727247624]), + { + "landcover": 2, + "system:index": "530" + }), + ee.Feature( + ee.Geometry.Point([-13.731497018806637, 9.890948306111866]), + { + "landcover": 2, + "system:index": "531" + }), + ee.Feature( + ee.Geometry.Point([-13.72669050025195, 9.889595424255967]), + { + "landcover": 2, + "system:index": "532" + }), + ee.Feature( + ee.Geometry.Point([-13.719137399666012, 9.90109474243695]), + { + "landcover": 2, + "system:index": "533" + }), + ee.Feature( + ee.Geometry.Point([-13.719824045173825, 9.906675148754557]), + { + "landcover": 2, + "system:index": "534" + }), + ee.Feature( + ee.Geometry.Point([-13.723600595466793, 9.91360824861252]), + { + "landcover": 2, + "system:index": "535" + }), + ee.Feature( + ee.Geometry.Point([-13.7294370822832, 9.920033917561932]), + { + "landcover": 2, + "system:index": "536" + }), + ee.Feature( + ee.Geometry.Point([-13.730982034675778, 9.924599447866193]), + { + "landcover": 2, + "system:index": "537" + }), + ee.Feature( + ee.Geometry.Point([-13.738878458015622, 9.914453738566584]), + { + "landcover": 2, + "system:index": "538" + }), + ee.Feature( + ee.Geometry.Point([-13.744714944832028, 9.910902666107052]), + { + "landcover": 2, + "system:index": "539" + }), + ee.Feature( + ee.Geometry.Point([-13.746774881355465, 9.905660536482868]), + { + "landcover": 2, + "system:index": "540" + }), + ee.Feature( + ee.Geometry.Point([-13.747976510994137, 9.89889637450345]), + { + "landcover": 2, + "system:index": "541" + }), + ee.Feature( + ee.Geometry.Point([-13.74265500830859, 9.895006918256664]), + { + "landcover": 2, + "system:index": "542" + }), + ee.Feature( + ee.Geometry.Point([-13.741110055916012, 9.88722786760753]), + { + "landcover": 2, + "system:index": "543" + }), + ee.Feature( + ee.Geometry.Point([-13.744543283455075, 9.889595424255967]), + { + "landcover": 2, + "system:index": "544" + }), + ee.Feature( + ee.Geometry.Point([-13.774927347175778, 9.920710296437226]), + { + "landcover": 2, + "system:index": "545" + }), + ee.Feature( + ee.Geometry.Point([-13.774927347175778, 9.914115542846634]), + { + "landcover": 2, + "system:index": "546" + }), + ee.Feature( + ee.Geometry.Point([-13.775957315437497, 9.91191726216291]), + { + "landcover": 2, + "system:index": "547" + }), + ee.Feature( + ee.Geometry.Point([-13.780420511238278, 9.91293185507927]), + { + "landcover": 2, + "system:index": "548" + }), + ee.Feature( + ee.Geometry.Point([-13.783682077400387, 9.907182453713716]), + { + "landcover": 2, + "system:index": "549" + }), + ee.Feature( + ee.Geometry.Point([-13.780420511238278, 9.906844250494784]), + { + "landcover": 2, + "system:index": "550" + }), + ee.Feature( + ee.Geometry.Point([-13.775442331306637, 9.90971896674098]), + { + "landcover": 2, + "system:index": "551" + }), + ee.Feature( + ee.Geometry.Point([-13.769090860359372, 9.9147919339376]), + { + "landcover": 2, + "system:index": "552" + }), + ee.Feature( + ee.Geometry.Point([-13.764456003181637, 9.920203012411678]), + { + "landcover": 2, + "system:index": "553" + }), + ee.Feature( + ee.Geometry.Point([-13.755014627449215, 9.921555768067503]), + { + "landcover": 2, + "system:index": "554" + }), + ee.Feature( + ee.Geometry.Point([-13.747118204109372, 9.927135826088241]), + { + "landcover": 2, + "system:index": "555" + }), + ee.Feature( + ee.Geometry.Point([-13.760507791511715, 9.930348543625744]), + { + "landcover": 2, + "system:index": "556" + }), + ee.Feature( + ee.Geometry.Point([-13.794668405525387, 9.923415797972327]), + { + "landcover": 2, + "system:index": "557" + }), + ee.Feature( + ee.Geometry.Point([-13.796213357917965, 9.917497484343334]), + { + "landcover": 2, + "system:index": "558" + }), + ee.Feature( + ee.Geometry.Point([-13.794496744148434, 9.913439150360041]), + { + "landcover": 2, + "system:index": "559" + }), + ee.Feature( + ee.Geometry.Point([-13.797071664802731, 9.905998740922067]), + { + "landcover": 2, + "system:index": "560" + }), + ee.Feature( + ee.Geometry.Point([-13.801191537849606, 9.899572796973985]), + { + "landcover": 2, + "system:index": "561" + }), + ee.Feature( + ee.Geometry.Point([-13.808057992927731, 9.910057166995815]), + { + "landcover": 2, + "system:index": "562" + }), + ee.Feature( + ee.Geometry.Point([-13.799474924080075, 9.920033917561932]), + { + "landcover": 2, + "system:index": "563" + }), + ee.Feature( + ee.Geometry.Point([-13.802736490242184, 9.92493763276433]), + { + "landcover": 2, + "system:index": "564" + }), + ee.Feature( + ee.Geometry.Point([-13.804968088142575, 9.941339180848713]), + { + "landcover": 2, + "system:index": "565" + }), + ee.Feature( + ee.Geometry.Point([-13.813551156990231, 9.93846474216451]), + { + "landcover": 2, + "system:index": "566" + }), + ee.Feature( + ee.Geometry.Point([-13.817842691414059, 9.930517633148913]), + { + "landcover": 2, + "system:index": "567" + }), + ee.Feature( + ee.Geometry.Point([-13.827627389900387, 9.920203012411678]), + { + "landcover": 2, + "system:index": "568" + }), + ee.Feature( + ee.Geometry.Point([-13.823679178230465, 9.912762756477909]), + { + "landcover": 2, + "system:index": "569" + }), + ee.Feature( + ee.Geometry.Point([-13.820932596199215, 9.90904256518501]), + { + "landcover": 2, + "system:index": "570" + }), + ee.Feature( + ee.Geometry.Point([-13.822992532722653, 9.904138612192435]), + { + "landcover": 2, + "system:index": "571" + }), + ee.Feature( + ee.Geometry.Point([-13.821619241707028, 9.900249218050838]), + { + "landcover": 2, + "system:index": "572" + }), + ee.Feature( + ee.Geometry.Point([-13.825395791999997, 9.892470291541834]), + { + "landcover": 2, + "system:index": "573" + }), + ee.Feature( + ee.Geometry.Point([-13.828657358162106, 9.887904314104395]), + { + "landcover": 2, + "system:index": "574" + }), + ee.Feature( + ee.Geometry.Point([-13.835867135994137, 9.886213195252276]), + { + "landcover": 2, + "system:index": "575" + }), + ee.Feature( + ee.Geometry.Point([-13.842218606941403, 9.894330486381278]), + { + "landcover": 2, + "system:index": "576" + }), + ee.Feature( + ee.Geometry.Point([-13.846510141365231, 9.901263847052817]), + { + "landcover": 2, + "system:index": "577" + }), + ee.Feature( + ee.Geometry.Point([-13.751238077156247, 9.897205312230422]), + { + "landcover": 2, + "system:index": "578" + }), + ee.Feature( + ee.Geometry.Point([-13.751924722664059, 9.893484944578221]), + { + "landcover": 2, + "system:index": "579" + }), + ee.Feature( + ee.Geometry.Point([-13.751753061287106, 9.890102755604609]), + { + "landcover": 2, + "system:index": "580" + }), + ee.Feature( + ee.Geometry.Point([-13.749864786140622, 9.88773520261068]), + { + "landcover": 2, + "system:index": "581" + }), + ee.Feature( + ee.Geometry.Point([-13.744199960701168, 9.885705857900248]), + { + "landcover": 2, + "system:index": "582" + }), + ee.Feature( + ee.Geometry.Point([-13.743684976570309, 9.88249270315871]), + { + "landcover": 2, + "system:index": "583" + }), + ee.Feature( + ee.Geometry.Point([-13.744886606208981, 9.878264820146166]), + { + "landcover": 2, + "system:index": "584" + }), + ee.Feature( + ee.Geometry.Point([-13.735960214607418, 9.875220710736242]), + { + "landcover": 2, + "system:index": "585" + }), + ee.Feature( + ee.Geometry.Point([-13.732698648445309, 9.874036882806081]), + { + "landcover": 2, + "system:index": "586" + }), + ee.Feature( + ee.Geometry.Point([-13.755529611580075, 9.876742768961105]), + { + "landcover": 2, + "system:index": "587" + }), + ee.Feature( + ee.Geometry.Point([-13.761537759773434, 9.874036882806081]), + { + "landcover": 2, + "system:index": "588" + }), + ee.Feature( + ee.Geometry.Point([-13.765657632820309, 9.870147132490299]), + { + "landcover": 2, + "system:index": "589" + }), + ee.Feature( + ee.Geometry.Point([-13.772352426521481, 9.873191288820733]), + { + "landcover": 2, + "system:index": "590" + }), + ee.Feature( + ee.Geometry.Point([-13.78162214087695, 9.888242536830802]), + { + "landcover": 2, + "system:index": "591" + }), + ee.Feature( + ee.Geometry.Point([-13.783510416023434, 9.892301182397773]), + { + "landcover": 2, + "system:index": "592" + }), + ee.Feature( + ee.Geometry.Point([-13.788316934578122, 9.891793854443343]), + { + "landcover": 2, + "system:index": "593" + }), + ee.Feature( + ee.Geometry.Point([-13.810804574958981, 9.88164713090347]), + { + "landcover": 2, + "system:index": "594" + }), + ee.Feature( + ee.Geometry.Point([-13.826940744392575, 9.862367494036468]), + { + "landcover": 2, + "system:index": "595" + }), + ee.Feature( + ee.Geometry.Point([-13.801019876472653, 9.868625043771626]), + { + "landcover": 2, + "system:index": "596" + }), + ee.Feature( + ee.Geometry.Point([-13.879640787117184, 9.97025124536242]), + { + "landcover": 2, + "system:index": "597" + }), + ee.Feature( + ee.Geometry.Point([-13.870714395515622, 9.973294471519242]), + { + "landcover": 2, + "system:index": "598" + }), + ee.Feature( + ee.Geometry.Point([-13.934229104988278, 10.045140145886094]), + { + "landcover": 2, + "system:index": "599" + }), + ee.Feature( + ee.Geometry.Point([-13.930795877449215, 10.051225165678396]), + { + "landcover": 2, + "system:index": "600" + }), + ee.Feature( + ee.Geometry.Point([-13.933714120857418, 10.054436657725878]), + { + "landcover": 2, + "system:index": "601" + }), + ee.Feature( + ee.Geometry.Point([-13.940065591804684, 10.05494373250028]), + { + "landcover": 2, + "system:index": "602" + }), + ee.Feature( + ee.Geometry.Point([-13.941267221443356, 10.052746402731378]), + { + "landcover": 2, + "system:index": "603" + }), + ee.Feature( + ee.Geometry.Point([-13.940752237312497, 10.051056138897241]), + { + "landcover": 2, + "system:index": "604" + })]), + MangroveTraining = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + }, + { + "type": "polygon" + } + ] # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[-14.772867907259272, 10.831865509758982], + [-14.772867907259272, 10.829800117522154], + [-14.769735087129877, 10.829800117522154], + [-14.769735087129877, 10.831865509758982]]], None, False), + { + "landcover": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.765529383394526, 10.838525248913346], + [-14.766130198213862, 10.835743350576333], + [-14.763641108248041, 10.837724402042513]]]), + { + "landcover": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.913246520634662, 10.88669795665154], + [-14.913589843388568, 10.88475937330651], + [-14.911658652897845, 10.886192240473294]]]), + { + "landcover": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.895136245366107, 10.88551795090026], + [-14.89530790674306, 10.884000793781476], + [-14.893848785038958, 10.884464370387377]]]), + { + "landcover": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.050952041676988, 10.935378624515092], + [-15.051295364430894, 10.933018994799562], + [-15.048548782399644, 10.934030266976446]]]), + { + "landcover": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.056273544362535, 10.927794033632864], + [-15.05738934331273, 10.924675867811173], + [-15.052840316823472, 10.926361366917918]]]), + { + "landcover": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.033013427785386, 10.937738235455122], + [-15.033270919850816, 10.934198812004023], + [-15.030266845754136, 10.93613707293644]]]), + { + "landcover": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.024859512380113, 10.944058529371569], + [-15.024516189626206, 10.940940534549906], + [-15.022112930348863, 10.943805720202793]]]), + { + "landcover": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.033528411916246, 10.968495730093942], + [-15.034987533620347, 10.965546519857721], + [-15.031554306081285, 10.96563078341557]]]), + { + "landcover": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.984546455644416, 10.987837291653708], + [-14.98471811702137, 10.985056790571315], + [-14.982143196367073, 10.985899369423139]]]), + { + "landcover": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.970813545488166, 10.976293827966234], + [-14.97124269893055, 10.973007649961247], + [-14.968753608964729, 10.974440091021131], + [-14.970899376176643, 10.97688365091855]]]), + { + "landcover": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.913425310937384, 11.025767991764447], + [-14.913854464379767, 11.023156342914417], + [-14.911365374413947, 11.023830319031457]]]), + { + "landcover": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.906121064559587, 10.955341109815576], + [-14.907837678329118, 10.949610933953918], + [-14.9013145460049, 10.949610933953918]]]), + { + "landcover": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.96670177455577, 10.846156206496804], + [-14.967130927998152, 10.844133061873753], + [-14.965070991474715, 10.844638849312554]]]), + { + "landcover": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.743433698959846, 10.875987708548102], + [-14.743691191025276, 10.874723371063938], + [-14.74257539207508, 10.875229106700816]]]), + { + "landcover": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.758668646164436, 10.881424298639294], + [-14.758754476852912, 10.87990712068018], + [-14.75755284721424, 10.880497135248563]]]), + { + "landcover": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.581574563265484, 10.84536404443417], + [-14.581832055330914, 10.841570626993633], + [-14.57942879605357, 10.842582209681508]]]), + { + "landcover": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.603118066073101, 10.845279746791512], + [-14.603976372957867, 10.842160717310577], + [-14.600457314730328, 10.842413612804403]]]), + { + "landcover": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.544370475152173, 10.714539815401963], + [-14.544713797906079, 10.712009776250197], + [-14.542653861382641, 10.71335913309481]]]), + { + "landcover": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.555700126031079, 10.620070724737218], + [-14.557245078423657, 10.617033732301914], + [-14.554841819146313, 10.616696286835134]]]), + { + "landcover": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.49149877105061, 10.606741478020858], + [-14.492700400689282, 10.602860702077397], + [-14.489782157281079, 10.60353562316791]]]), + { + "landcover": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.525144400933423, 10.557468847876851], + [-14.525659385064282, 10.554262478003922], + [-14.522397818902173, 10.554768749154126]]]), + { + "landcover": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.547632041314282, 10.528104002109169], + [-14.549005332329907, 10.525572418817276], + [-14.546087088921704, 10.525572418817276], + [-14.547460379937329, 10.529285400531567]]]), + { + "landcover": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.502835338713801, 10.41292156162942], + [-14.503178661467707, 10.408700677058924], + [-14.499402111174739, 10.409544858543237]]]), + { + "landcover": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.494767253997004, 10.393842709127481], + [-14.495968883635676, 10.390128106675817], + [-14.492707317473567, 10.390634645974284]]]), + { + "landcover": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.47914606869427, 10.369359288904414], + [-14.47914606869427, 10.365644395693769], + [-14.476227825286067, 10.366319834100443]]]), + { + "landcover": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.576993053557551, 10.460191559812422], + [-14.577679699065364, 10.457490610691979], + [-14.575104778411067, 10.458672278824194]]]), + { + "landcover": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.627633159758723, 10.477747155867581], + [-14.628663128020442, 10.475552760727757], + [-14.625058239104426, 10.476059160985555]]]), + { + "landcover": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.458669826688668, 10.353920649385334], + [-14.459699794950387, 10.351049912543393], + [-14.457296535673043, 10.351387647653238]]]), + { + "landcover": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.139551326932809, 10.164877141176504], + [-14.14126794070234, 10.16115984608325], + [-14.13852135867109, 10.16115984608325]]]), + { + "landcover": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.092859432401559, 10.157611478625247], + [-14.09457604617109, 10.154907934134476], + [-14.092001125516793, 10.154738961845052]]]), + { + "landcover": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.0758649560832, 10.146121256763173], + [-14.077066585721871, 10.143755571644597], + [-14.07483498782148, 10.14392454973268]]]), + { + "landcover": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.086507961454293, 10.137841282399306], + [-14.086679622831246, 10.135644518587286], + [-14.083933040799996, 10.135644518587286]]]), + { + "landcover": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.114660427274606, 10.118069866300507], + [-14.114660427274606, 10.114183034389438], + [-14.11157052248945, 10.115028001850106]]]), + { + "landcover": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.108137294950387, 10.096607207508624], + [-14.108223125638863, 10.09398765106267], + [-14.10607735842695, 10.095339682858716]]]), + { + "landcover": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.100927517118356, 10.095170679194851], + [-14.101270839872262, 10.09288912104627], + [-14.09809510439863, 10.093311633034737]]]), + { + "landcover": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.021705791654488, 10.082326141150112], + [-14.021877453031442, 10.080636032223616], + [-14.020075008573434, 10.081058560286214]]]), + { + "landcover": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.9989606592082, 10.0360984726324], + [-13.99921815127363, 10.03390101484509], + [-13.997158214750192, 10.034915227984722]]]), + { + "landcover": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.982309505643746, 10.021899251579727], + [-13.982652828397653, 10.019025524007592], + [-13.980592891874215, 10.020377869566946]]]), + { + "landcover": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.02342240542402, 10.024603913085619], + [-14.024624035062692, 10.021392125035309], + [-14.021448299589059, 10.021899251579727]]]), + { + "landcover": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.835067067440528, 9.863594689892103], + [-13.834895406063575, 9.86190344613282], + [-13.833951268490333, 9.8628336312745]]]), + { + "landcover": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.78159454851963, 9.855138384324128], + [-13.78434113055088, 9.852686015145009], + [-13.780650410946388, 9.852686015145009], + [-13.78210953265049, 9.856068588553256]]]), + { + "landcover": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.730782780941505, 9.849895365972753], + [-13.732327733334083, 9.84795035410826], + [-13.72992447405674, 9.8484577496128]]]), + { + "landcover": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.690013203915138, 9.850402758486885], + [-13.690528188045997, 9.84795035410826], + [-13.68821075945713, 9.848288617864625]]]), + { + "landcover": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.681773457821388, 9.867822761312134], + [-13.682030949886817, 9.865285924971385], + [-13.67971352129795, 9.865708732384784]]]), + { + "landcover": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.656796727474708, 9.882536026645745], + [-13.65748337298252, 9.879745630321658], + [-13.65473679095127, 9.880252976868517]]]), + { + "landcover": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.658856663998145, 9.860635007617953], + [-13.659371648129005, 9.857844425704632], + [-13.656367574032325, 9.858859185497039]]]), + { + "landcover": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.65525177508213, 9.812684457771793], + [-13.656281743343849, 9.809893470949143], + [-13.653449330624122, 9.810400924847407]]]), + { + "landcover": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.572682652767677, 9.778006894151861], + [-13.57311180621006, 9.77445435389848], + [-13.569163594540138, 9.776738134132595]]]), + { + "landcover": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.532513890560645, 9.73579688260377], + [-13.532599721249122, 9.732413083234764], + [-13.529853139217872, 9.73410498720453]]]), + { + "landcover": 1, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.543843541439552, 9.590008806122597], + [-13.543929372128028, 9.587131332658355], + [-13.540324483212013, 9.588908598563034]]]), + { + "landcover": 1, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.50891045122959, 9.585861851311003], + [-13.508996281918067, 9.583153608560922], + [-13.50616386919834, 9.58518479265003]]]), + { + "landcover": 1, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.542556081112403, 9.577059983359076], + [-13.543242726620216, 9.574605575646206], + [-13.540238652523536, 9.574605575646206]]]), + { + "landcover": 1, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.530389026199542, 9.527893347398814], + [-13.530303195511065, 9.525523232532972], + [-13.52867241243001, 9.526792938971614]]]), + { + "landcover": 1, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.451424792801104, 9.537796863571655], + [-13.452454761062823, 9.535257527857542], + [-13.450738147293292, 9.535426817493349]]]), + { + "landcover": 1, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.454943851028643, 9.544737618029338], + [-13.455630496536456, 9.542282977117766], + [-13.453570560013018, 9.542875478266838]]]), + { + "landcover": 1, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.404647067581378, 9.536019330556984], + [-13.404904559646807, 9.533395336318703], + [-13.402758792434893, 9.533733917354596]]]), + { + "landcover": 1, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.35263367036458, 9.463471170308926], + [-13.352376178299151, 9.46186257739953], + [-13.350058749710284, 9.462709206184886]]]), + { + "landcover": 1, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.281136706863604, 9.376427045404881], + [-13.279935077224932, 9.373293725915216], + [-13.277875140701495, 9.37549552094412]]]), + { + "landcover": 1, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.258134082351885, 9.403016779052459], + [-13.25701828340169, 9.400899836835583], + [-13.253499225174151, 9.402339358952185]]]), + { + "landcover": 1, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.2767593417513, 9.352206597362429], + [-13.2767593417513, 9.348226152497125], + [-13.27324028352376, 9.351020937696008]]]), + { + "landcover": 1, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.319159701858721, 9.36406297170052], + [-13.32345123628255, 9.362962039686883], + [-13.31993217805501, 9.359743910725987]]]), + { + "landcover": 1, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.276330188308917, 9.28597285948887], + [-13.276587680374346, 9.282076366483075], + [-13.273411944900714, 9.284109324760125]]]), + { + "landcover": 1, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.22035537324127, 9.227099179359078], + [-13.221042018749083, 9.223879801424738], + [-13.217952113963927, 9.224472846935972]]]), + { + "landcover": 1, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.282496791698302, 9.227014459263557], + [-13.281981807567442, 9.223795080556025], + [-13.279578548290099, 9.225828375789598]]]), + { + "landcover": 1, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.201730113841856, 9.201512786400121], + [-13.200614314891661, 9.198293175278035], + [-13.198554378368224, 9.201343333913732]]]), + { + "landcover": 1, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.184306484081114, 9.042107056466508], + [-13.184993129588927, 9.039987948233751], + [-13.183019023753966, 9.040072712802496]]]), + { + "landcover": 1, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.260438304759825, 9.024984305436146], + [-13.259408336498106, 9.023458476277755], + [-13.257691722728575, 9.024560464650595]]]), + { + "landcover": 1, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.642733884742919, 9.878367396851779], + [-13.643291784218016, 9.876929904698706], + [-13.641231847694579, 9.877352697160317]]]), + { + "landcover": 1, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.637626958778563, 9.870714792841605], + [-13.637498212745848, 9.869150426476896], + [-13.635996175697509, 9.869869190324037]]]), + { + "landcover": 1, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.71767956322163, 9.790239249343115], + [-13.71793705528706, 9.788293886948836], + [-13.716048780140575, 9.788801373889488]]]), + { + "landcover": 1, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.722228589710888, 9.789647183733882], + [-13.721713605580028, 9.788124724462955], + [-13.71991116112202, 9.78905511706901]]]), + { + "landcover": 1, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.718709531483348, 9.787532655083849], + [-13.71793705528706, 9.786686839854307], + [-13.716735425648388, 9.787194329250488]]]), + { + "landcover": 1, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.72566181724995, 9.785502694914687], + [-13.724717679676708, 9.784233963509804], + [-13.723258557972606, 9.785248949021314]]]), + { + "landcover": 1, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.702487531361278, 9.789308860054645], + [-13.702830854115184, 9.787278910741135], + [-13.701028409657177, 9.788463049348552], + [-13.70317417686909, 9.789985507068423]]]), + { + "landcover": 1, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.697509351429638, 9.80064251559769], + [-13.697337690052684, 9.798866371277441], + [-13.695535245594677, 9.799965890311366]]]), + { + "landcover": 1, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.487795754889769, 9.654477745850699], + [-13.487967416266722, 9.65312390200053], + [-13.485478326300901, 9.65312390200053]]]), + { + "landcover": 1, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.439584340971981, 9.671575492304996], + [-13.43936976425079, 9.669967883805594], + [-13.43786772720245, 9.670898605452638]]]), + { + "landcover": 1, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.448296155852352, 9.662183565542307], + [-13.448553647917782, 9.66057591215856], + [-13.446794118804013, 9.661083593004093]]]), + { + "landcover": 1, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.451471891325985, 9.66599113502486], + [-13.451471891325985, 9.664425806120096], + [-13.45009860031036, 9.66506039979714]]]), + { + "landcover": 1, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.471642103117977, 9.675932918788158], + [-13.471599187773739, 9.674494551243551], + [-13.470526304167782, 9.67538295545391]]]), + { + "landcover": 1, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.493915166777645, 9.681347894319272], + [-13.494430150908505, 9.679951854290938], + [-13.492498960417782, 9.679571115094394]]]), + { + "landcover": 1, + "system:index": "81" + })]), + NonMangroveTraining = + + # shown: False # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Polygon( + [[[-15.016362274220933, 10.95631951504912], + [-15.01670559697484, 10.954465652887245], + [-15.014988983205308, 10.955729651075279]]]), + { + "landcover": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.028464401296128, 10.951853372862459], + [-15.028893554738511, 10.9499573487322], + [-15.026318634084214, 10.950589358124523]]]), + { + "landcover": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.030567253163804, 10.957794169840307], + [-15.03091057591771, 10.955687517889313], + [-15.028464401296128, 10.954760586280573], + [-15.028121078542222, 10.956193115725121]]]), + { + "landcover": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.064427459767808, 10.939929285941478], + [-15.062968338063706, 10.936811247682382], + [-15.05962094121312, 10.939339389326674], + [-15.061766708425035, 10.942457400993268]]]), + { + "landcover": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.01115396907215, 10.978358203146746], + [-15.011497291826057, 10.976041046340452], + [-15.008707794450569, 10.976672999999328]]]), + { + "landcover": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.018235000871467, 10.979242930950159], + [-15.01866415431385, 10.976462348929923], + [-15.016303810380744, 10.978189683264663]]]), + { + "landcover": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-15.023599418901252, 10.982697556991285], + [-15.023685249589729, 10.980717471399375], + [-15.021453651689338, 10.981812839538087]]]), + { + "landcover": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.94775758632801, 11.03259186797311], + [-14.947929247704963, 11.029306317720359], + [-14.94501100429676, 11.031243954363834]]]), + { + "landcover": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.92827402004383, 11.037225273846428], + [-14.929046496240119, 11.034866458168958], + [-14.926729067651252, 11.035119189326004]]]), + { + "landcover": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.931449755517463, 11.018101472815468], + [-14.932393893090705, 11.015826752939146], + [-14.930076464501838, 11.016163749585782]]]), + { + "landcover": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.717083677597541, 10.887661504655835], + [-14.717169508286018, 10.88547006877135], + [-14.715281233139534, 10.886818646608011]]]), + { + "landcover": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.707556471176643, 10.873501173067645], + [-14.707985624619026, 10.871309633085449], + [-14.705839857407112, 10.872236825042815]]]), + { + "landcover": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.564665917635601, 10.855985357241925], + [-14.56492340970103, 10.851686299903761], + [-14.560889367342632, 10.85396227913996]]]), + { + "landcover": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.501528172847433, 10.829671752536575], + [-14.50358810937087, 10.826299651525124], + [-14.498953252193136, 10.82646825747719]]]), + { + "landcover": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.49586334740798, 10.843328373277828], + [-14.498438268062277, 10.838439037462708], + [-14.492258458491964, 10.839282032096412]]]), + { + "landcover": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.456994834283032, 10.749958141773662], + [-14.460428061822094, 10.746922447900886], + [-14.456136527398266, 10.746585146697118]]]), + { + "landcover": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.442231955865063, 10.732418155960152], + [-14.442918601372876, 10.728538983147049], + [-14.438798728326, 10.729382285818327]]]), + { + "landcover": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.604451957085766, 10.529960483311568], + [-14.605310263970532, 10.52692259915962], + [-14.60136205230061, 10.52894785858715]]]), + { + "landcover": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.48600560698811, 10.471222760291694], + [-14.486177268365063, 10.466833862095141], + [-14.48325902495686, 10.468353103116165]]]), + { + "landcover": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.500432079436457, 10.441284422659384], + [-14.500432079436457, 10.438245668318906], + [-14.496998851897395, 10.439089769725399]]]), + { + "landcover": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.549012249114192, 10.45462082650194], + [-14.549870555998957, 10.452257454900492], + [-14.546952312590754, 10.452257454900492]]]), + { + "landcover": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.534936016204036, 10.443647877725367], + [-14.534936016204036, 10.439427409646498], + [-14.530129497649348, 10.44111560375287]]]), + { + "landcover": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.356874630155465, 10.29244737636023], + [-14.357389614286324, 10.289069376182145], + [-14.354471370878121, 10.2909272807549]]]), + { + "landcover": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.315847561063668, 10.324198808708294], + [-14.316362545194528, 10.32115891654387], + [-14.314130947294137, 10.322003333980634]]]), + { + "landcover": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.15851990908613, 10.089339998450072], + [-14.159635708036324, 10.087058398980245], + [-14.157318279447457, 10.088072445184688]]]), + { + "landcover": 2, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.039730236234567, 10.046493936082012], + [-14.040245220365426, 10.044550094321767], + [-14.038786098661324, 10.045648788926059]]]), + { + "landcover": 2, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-14.001278087797067, 10.069734616761512], + [-14.00170724123945, 10.06762189672479], + [-13.999990627469918, 10.068213459729401]]]), + { + "landcover": 2, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.967031643094918, 10.078100852215877], + [-13.968061611356637, 10.07590368008197], + [-13.9660016748332, 10.076410721134172]]]), + { + "landcover": 2, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.96900574892988, 10.101846256417112], + [-13.970035717191598, 10.100240750496802], + [-13.967804119291207, 10.100494251964397]]]), + { + "landcover": 2, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.947118923368356, 10.008291081164497], + [-13.947633907499215, 10.005924384584203], + [-13.945144817533395, 10.006685110366224]]]), + { + "landcover": 2, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.936304256620309, 10.017419606331591], + [-13.938364193143746, 10.01454583906799], + [-13.935617611112496, 10.015052976317214]]]), + { + "landcover": 2, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.865245156545589, 10.011587522650414], + [-13.865931802053401, 10.008967277018833], + [-13.862241082448909, 10.008967277018833]]]), + { + "landcover": 2, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.849194817800472, 10.015222021890791], + [-13.849366479177425, 10.012939899216223], + [-13.847392373342464, 10.01378513170792]]]), + { + "landcover": 2, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.871596627492854, 9.977522681370168], + [-13.872884087820003, 9.97473309468144], + [-13.868678384084651, 9.975493893420309], + [-13.87219744231219, 9.977860811466533]]]), + { + "landcover": 2, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.885329537649104, 9.931449178193983], + [-13.885844521779964, 9.928067380758433], + [-13.882582955617854, 9.92891283339319]]]), + { + "landcover": 2, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.719195637997169, 9.885749180963948], + [-13.719367299374122, 9.883550710348658], + [-13.716792378719825, 9.885072730032563]]]), + { + "landcover": 2, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.712758336361427, 9.899785223586706], + [-13.71292999773838, 9.897164080446853], + [-13.710097585018653, 9.898516931131878]]]), + { + "landcover": 2, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.585042271908302, 9.704664636543379], + [-13.585643086727638, 9.70153433202078], + [-13.582982335384864, 9.70280337791928]]]), + { + "landcover": 2, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.603495869930763, 9.704072419011773], + [-13.604697499569435, 9.699334641080256], + [-13.60032013445713, 9.699673056010699]]]), + { + "landcover": 2, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.568047795589942, 9.681736594181228], + [-13.568047795589942, 9.678775293678653], + [-13.565472874935645, 9.680298251483626]]]), + { + "landcover": 2, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.579463277157325, 9.671498844445082], + [-13.580149922665138, 9.667945172458403], + [-13.577145848568458, 9.66929895669111]]]), + { + "landcover": 2, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.550280843075294, 9.648314689092652], + [-13.551053319271583, 9.645353094436604], + [-13.548306737240333, 9.645860798225591]]]), + { + "landcover": 2, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.53637627154209, 9.6554224100717], + [-13.537577901180763, 9.65296857096865], + [-13.535174641903419, 9.653053186407726]]]), + { + "landcover": 2, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.354779437576495, 9.451194876126811], + [-13.356066897903643, 9.448231567078778], + [-13.35289116243001, 9.448824230929024]]]), + { + "landcover": 2, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.30122108796712, 9.458137385977457], + [-13.301993564163409, 9.455766788608837], + [-13.299161151443682, 9.456698096666363]]]), + { + "landcover": 2, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.380013659988604, 9.43282194906301], + [-13.379327014480792, 9.430197165246152], + [-13.376837924514971, 9.431636565296552]]]), + { + "landcover": 2, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.292037204300128, 9.406827242400094], + [-13.290663913284503, 9.402508714101591], + [-13.2877456698763, 9.405387738957764]]]), + { + "landcover": 2, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.245417934276427, 9.18405875410957], + [-13.243443828441466, 9.181432101976078], + [-13.241383891918028, 9.18388929326906]]]), + { + "landcover": 2, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.066632610179747, 9.154740824313496], + [-13.06731925568756, 9.152113955250934], + [-13.064915996410216, 9.152791858802239]]]), + { + "landcover": 2, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.074958186961974, 9.158977668998714], + [-13.075129848338927, 9.15618135717263], + [-13.073155742503966, 9.157028726715863]]]), + { + "landcover": 2, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.729721799006377, 9.85583516805335], + [-13.729721799006377, 9.85245259225134], + [-13.727490201105987, 9.853974755654882]]]), + { + "landcover": 2, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.717018857111846, 9.87917399489423], + [-13.717877163996612, 9.877144597357086], + [-13.714958920588408, 9.877482831149154]]]), + { + "landcover": 2, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.728520169367705, 9.83097242702757], + [-13.729206814875518, 9.828266165435217], + [-13.726288571467315, 9.828266165435217]]]), + { + "landcover": 2, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.514183618018233, 9.825400785383925], + [-13.51401195664128, 9.82408992060949], + [-13.512552834937178, 9.824935640413306]]]), + { + "landcover": 2, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.518603898474776, 9.822229329432322], + [-13.518560983130538, 9.82117217069405], + [-13.517616845557296, 9.821595034594583]]]), + { + "landcover": 2, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.525341607520186, 9.831320755143555], + [-13.526028253027999, 9.830009913831383], + [-13.524440385291182, 9.830179054937869]]]), + { + "landcover": 2, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.543580628821456, 9.823836204246815], + [-13.54323730606755, 9.822398474517083], + [-13.542035676428878, 9.822652191982112]]]), + { + "landcover": 2, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.708849929637964, 9.918043253117057], + [-13.708849929637964, 9.916690482958893], + [-13.707304977245386, 9.917113224233205]]]), + { + "landcover": 2, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.704386733837183, 9.911025697281337], + [-13.704644225902612, 9.909588348034493], + [-13.703356765575464, 9.910095648488015]]]), + { + "landcover": 2, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.640357040233667, 9.89622915380466], + [-13.640700362987573, 9.894199861550709], + [-13.638983749218042, 9.894622631804186]]]), + { + "landcover": 2, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.64160671314408, 9.893653002898159], + [-13.641563797799842, 9.893124538436428], + [-13.640962982980506, 9.893261939278268]]]), + { + "landcover": 2, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.638013196876708, 9.880523623305505], + [-13.63797028153247, 9.879339814453012], + [-13.636983228614989, 9.87972032490587]]]), + { + "landcover": 2, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.61247856705493, 9.877437255587456], + [-13.61273605912036, 9.876168876898934], + [-13.611620260170165, 9.876507111693881]]]), + { + "landcover": 2, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.605569196632567, 9.87041883220746], + [-13.605526281288329, 9.86906586592114], + [-13.604152990272704, 9.869742349759118]]]), + { + "landcover": 2, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.598144842079344, 9.869150426476896], + [-13.598316503456298, 9.867628333151876], + [-13.597114873817626, 9.867628333151876]]]), + { + "landcover": 2, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.705663266834911, 9.8058863147593], + [-13.705234113392528, 9.803941044100654], + [-13.70420414513081, 9.8052097001726]]]), + { + "landcover": 2, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Polygon( + [[[-13.438532915038143, 9.665229624575522], + [-13.438897695464169, 9.664129661994533], + [-13.43763169280914, 9.664489265541672]]]), + { + "landcover": 2, + "system:index": "66" + })]), + nationalborder = ee.FeatureCollection("projects/gee-book/assets/A3-3/Border5km") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.3 Mangroves +# Section: Supplemental (Assignment 1) +# Author: Celio de Sousa, David Lagomasino, and Lola Fatoyinbo +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + #**************************************** +#STEP 1 - TEMPORAL AND SPATIAL PARAMETERS +#**************************************** + +#Temporal +year = 2020; # Year +startDay = (year)+'-01-01'; # beginning of date filter | month-day +endDay = (year)+'-12-30'; # end of date filter | month-day + +#Spatial +aoi = ee.FeatureCollection('projects/gee-book/assets/A3-3/CoastalPrefectures5k') + +#**************************** +#STEP 2 - AUXILIARY FUNCTIONS +#**************************** + +def maskL8sr (image): + cloudShadowBitMask = 1 << 3 + cloudsBitMask = 1 << 5 + qa = image.select('pixel_qa') + mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0) \ + .And(qa.bitwiseAnd(cloudsBitMask).eq(0)) + return image.updateMask(mask).divide(10000) \ + .select("B[0-9]*") \ + .copyProperties(image, ["system:time_start"]) + + + +def addIndicesL8(img): + # NDVI (Normalized Difference Vegetation Index) + ndvi = img.normalizedDifference(['B5','B4']).rename('NDVI') + + # NDMI (Normalized Difference Mangrove Index - Shi et al 2016 ) + ndmi = img.normalizedDifference(['B7','B3']).rename('NDMI') + + # MNDWI (Modified Normalized Difference Water Index - Hanqiu Xu, 2006) + mndwi = img.normalizedDifference(['B3','B6']).rename('MNDWI') + + # SR (Simple Ratio) + sr = img.select('B5').divide(img.select('B4')).rename('SR') + + # Band Ratio 6/5 + ratio65 = img.select('B6').divide(img.select('B5')).rename('R65') + + # Band Ratio 4/6 + ratio46 = img.select('B4').divide(img.select('B6')).rename('R46') + + # GCVI (Green Chlorophyll Vegetation Index) + gcvi = img.expression('(NIR/GREEN)-1',{ + 'NIR':img.select('B5'), + 'GREEN':img.select('B3') + }).rename('GCVI') + + return img \ + .addBands(ndvi) \ + .addBands(ndmi) \ + .addBands(mndwi) \ + .addBands(sr) \ + .addBands(ratio65) \ + .addBands(ratio46) \ + .addBands(gcvi) + + + +#************************************************************** +#STEP 3 - CREATE AUXILIARY MASKS AND BANDS FOR MANGROVE MAPPING +#************************************************************** + +# WATER MASK +# The objective of this mask is to remove water pixels from the Landsat composite as we are only focusing on Mangroves + +# We will create a Water Mask using the Global Surface Water dataset + +globalwater = ee.Image('JRC/GSW1_0/GlobalSurfaceWater'); # Load the dataset + +# The Global Water Dataset has different bands. One of them is the the frequency with which water was present (occurrence). +# Esentially, this band shows how many times a given pixel was classified as water relative to the total time span of the dataset + +occurrence = globalwater.select('occurrence'); # Select the occurrence band. + +# Masks are composed by zeros and non-zero values. When you set or apply a mask to an image, the output image will keep it's original values where the mask +# has non zero values whereas the it will be masked where the mask has zero values. +# For this example, we want to create a watermask. Thus Watermask has to have zero where there is water and non zero values +# For our mask, we want to make sure we are selecting permanent water. We want to filter the dataset for water pixels that occurred more than 50% of the time over the 35 years time spam. + +waterMask = occurrence.lt(50) # Selects lower than 50%. Automatically, values above 90% are set to 0 \ + .unmask(1); + +Map.addLayer(waterMask, {}, 'Water Mask') + + + +# ELEVATION/SLOPE MASK + +# The objective of this mask is to remove pixels that are unlikely to be mangrove based on the slope. Generally, it will occur near shore where +# elevation and slope is very low. + +# We will create a mask using the SRTM Elevation Data +srtm = ee.Image('USGS/SRTMGL1_003') + +elevation = srtm.select('elevation') + +# In this case, we want to create a mask where pixels that have higher altitude values are removed +# Hence, we select everything that is UNDER 25 meters; everything else will be set to 0 automatically. +elevMask = elevation.lte(25) +Map.addLayer(elevMask, {}, 'Elevation Mask') +Map.addLayer(ee.Image().paint(aoi, 0, 2), {'palette':['red']}, 'StudyArea') + +#********************************************************* +#STEP 4 - LANDSAT 8 IMAGE COLLECTION AND CLOUD-FREE MOSAIC +#********************************************************* + +# Map the function over one year of data. +collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR') \ + .filterDate(startDay, endDay) \ + .map(maskL8sr) \ + .map(addIndicesL8) + + +composite = collection \ + .median() \ + .mask(waterMask) \ + .updateMask(elevMask) \ + .clip(aoi) + +# Display the results. +#Map.centerObject(Mangroves2016,9) +Map.addLayer(composite, {'bands': ['B5', 'B6', 'B4'], 'min': 0, 'max': 0.3}, 'Composite') + +#************************************************************ +#STEP 5 - CREATE STRATIFICATION MAP BASED ON MANGROVE DATASET +#************************************************************ + +#Mangrove Strata + +#First, let's load the global mangrove dataset for the year 2000 +dataset = ee.FeatureCollection('projects/gee-book/assets/A3-3/Mangroves2000') +mangrove = ee.Image(1).clip(dataset) + +#All other classes Strata + +# First we create an image of zeros where values 1 will be added where there is a pixel from the composite, including the mangrove areas +nonmangrove = ee.Image(0).where(composite.select('B1'),2).selfMask() +# Now we have an image of values of 1 where there is composite. Now we set this image to zero where there is pixel of mangrove +strata = nonmangrove.where(mangrove,1).rename('landcover') + +Map.addLayer (strata, {'palette':['#B3E283', '#E8E46E'], 'min':1, 'max':2}, 'Strata') + +# Selecting samples based on the strata created above + +stratified = strata.addBands(ee.Image.pixelLonLat()).stratifiedSample({ + 'numPoints': 1, + 'classBand': 'landcover', + 'scale': 30, + 'region': aoi, + 'classValues':[1,2], # + 'classPoints':[1000,1000] # Insert the number of points per class. + +def func_wep(f) # set these points to geometry and get their coordinates: + return f.setGeometry(ee.Geometry.Point([f.get('longitude'), f.get('latitude')])) + + }).map(func_wep) + + + + +paletteSamples = ee.List([ + 'FFFFFF', #NULL + '01937C', # Mangrove + 'B6C867', # Non-Mangrove + ]) + +# We use this function to colorize the samples based on the palette + +def func_jzm(f): + landcover = f.get('landcover') + return ee.Feature(ee.Geometry.Point([f.get('longitude'), f.get('latitude')]), f.toDictionary()) \ + .set({style: {color: paletteSamples.get(landcover) }}) + +features = stratified.map(func_jzm) + + + + + + +# Add the features / sample location into the map with the style set above +Map.addLayer(features.style(**{'styleProperty': "style"}),{}, 'Samples/Location') + +#************************************************************ +#STEP 6 - CLASSIFICATION +#************************************************************ + +# First, we will select the predictors to assign to each sample point in the sample sets +bands = ['B5','B6','B7','NDVI','MNDWI','SR'] + +# Create the sample sets +# Automatic +samplesAutomatic = composite.select(bands).sampleRegions({ + 'collection': stratified, + 'properties': ['landcover'], + 'scale': 30, + 'geometries': True, +}) + +# Create the sample set with the samples you selected manually via geometry +manualpoints = MangroveTraining.merge(NonMangroveTraining) +samplesManual = composite.select(bands).sampleRegions({ + 'collection': manualpoints, + 'properties': ['landcover'], + 'scale': 30, + 'geometries': True, +}) + +# Create the Ground Truth sample set that will be used to validate the land cover classification maps +groundtruth = ee.FeatureCollection('users/celiohelder/TutorialAssets/GroundTruth') +Map.addLayer(groundtruth) + +samplesgroundtruth = composite.select(bands).sampleRegions({ + 'collection': groundtruth, # Set of geometries selected in 4.1 + 'properties': ['landcover'], # Label from each geometry + 'scale': 30, + 'geometries': True, +}) + + +# Train two classifiers: one with the samples collected automatically via stratification and one with the samples you selected manually +RandomForest1 = ee.Classifier.smileRandomForest(200,5).train({ + 'features': samplesAutomatic, + 'classProperty': 'landcover', + 'inputProperties': bands +}) + +RandomForest2 = ee.Classifier.smileRandomForest(200,5).train({ + 'features': samplesManual, + 'classProperty': 'landcover', + 'inputProperties': bands +}) + + +# Classify the Landsat 8 Composite using the two classifiers to produce 2 land cover maps + +classifiedrf1 = composite.select(bands) # select the predictors \ + .classify(RandomForest1); + +classifiedrf2 = composite.select(bands) # select the predictors \ + .classify(RandomForest2); + +# Color palette for the classification outputs +paletteMAP = [ + '01937C', # Mangrove + 'B6C867', # Non-Mangrove +] + +# Add the classifications to the map editor +Map.addLayer (classifiedrf1, {'min': 1, 'max': 2, 'palette':paletteMAP}, 'Classification Automatic Samples') +Map.addLayer (classifiedrf2, {'min': 1, 'max': 2, 'palette':paletteMAP}, 'Classification Manual Samples') + + +validation1 = samplesgroundtruth.classify(RandomForest1) +validation2 = samplesgroundtruth.classify(RandomForest2) +testAccuracy1 = validation1.errorMatrix('landcover', 'classification') +testAccuracy2 = validation2.errorMatrix('landcover', 'classification') +kappa1 = testAccuracy1.kappa() +kappa2 = testAccuracy2.kappa() + +print('Overall Accuracy Map 1: ', testAccuracy1.accuracy()) +print('Overall Accuracy Map 2: ', testAccuracy2.accuracy()) +print('Kappa: ', kappa1) +print('Kappa: ', kappa2) + +print('Validation error matrix Map1: ', testAccuracy1) +print('Validation error matrix Map2: ', testAccuracy2) + +legend = ui.Panel({ + 'style': { + 'position': 'bottom-left', # Position in the map + 'padding': '8px 15px' # Padding (border) size + } +}) +def makeRow(color, name): + # Create the label that is actually the colored boxes that represent each class + colorBox = ui.Label({ + 'style': { + 'backgroundColor': '#' + color, + # Use padding to give the label color box height and width. + 'padding': '8px', + 'margin': '0 0 4px 0' + } + }) + # Create the label filled with the description text. + description = ui.Label({ + 'value': name, + 'style': '{margin': '0 0 4px 6px'} + }) + return ui.Panel({ + 'widgets': [colorBox, description], + 'layout': ui.Panel.Layout.Flow('horizontal') + }) + +legend.add(makeRow('01937C', 'Mangrove')) +legend.add(makeRow('B6C867', 'Non-mangrove')) + +#Map.add (legend) + + + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34a Checkpoint.ipynb new file mode 100644 index 0000000..7a01211 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34a Checkpoint.ipynb @@ -0,0 +1,238 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.4 Forest Degradation and Deforestation\n", + "# Checkpoint: A34a\n", + "# Author: Carlos Souza Jr., Karis Tenneson, John Dilger,\n", + "# Crystal Wespestad, Eric Bullock\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# SMA Model - Section 1\n", + "\n", + "# Define the Landsat endmembers (source: Souza et al. 2005)\n", + "# They can be applied to Landsat 5, 7, 8, and potentially 9.\n", + "endmembers = [\n", + " [0.0119,0.0475,0.0169,0.625,0.2399,0.0675], # GV\n", + " [0.1514,0.1597,0.1421,0.3053,0.7707,0.1975], # NPV\n", + " [0.1799,0.2479,0.3158,0.5437,0.7707,0.6646], # Soil\n", + " [0.4031,0.8714,0.79,0.8989,0.7002,0.6607] # Cloud\n", + "]\n", + "\n", + "# Select a Landsat 5 scene on which to apply the SMA model.\n", + "image = ee.Image('LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') \\\n", + " .multiply(0.0000275).add(-0.2)\n", + "\n", + "# Center the map on the image object.\n", + "Map.centerObject(image, 10)\n", + "\n", + "# Define and select the Landsat bands to apply the SMA model.\n", + "# use ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] for Landsat 5 and 7.\n", + "# use ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'] for Landsat 8.\n", + "bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']\n", + "image = image.select(bands)\n", + "\n", + "# Unmixing image using Singular Value Decomposition.\n", + "def getSMAFractions(image, endmembers):\n", + " unmixed = ee.Image(image) \\\n", + " .select([0, 1, 2, 3, 4,\n", + " 5]) # Use the visible, NIR, and SWIR bands only! \\\n", + " .unmix(endmembers) \\\n", + " .max(0) \\\n", + " .rename('GV', 'NPV', 'Soil', 'Cloud')\n", + " return ee.Image(unmixed.copyProperties(image))\n", + "\n", + "\n", + "# Calculate GVS and NDFI and add them to image fractions.\n", + "# Run the SMA model passing the Landsat image and the endmembers.\n", + "sma = getSMAFractions(image, endmembers)\n", + "\n", + "Map.addLayer(sma, {\n", + " 'bands': ['NPV', 'GV', 'Soil'],\n", + " 'min': 0,\n", + " 'max': 0.45\n", + "}, 'sma')\n", + "\n", + "# Calculate the Shade and GV shade-normalized (GVs) fractions from the SMA bands.\n", + "Shade = sma.reduce(ee.Reducer.sum()) \\\n", + " .subtract(1.0) \\\n", + " .abs() \\\n", + " .rename('Shade')\n", + "\n", + "GVs = sma.select('GV') \\\n", + " .divide(Shade.subtract(1.0).abs()) \\\n", + " .rename('GVs')\n", + "\n", + "# Add the new bands to the SMA image variable.\n", + "sma = sma.addBands([Shade, GVs])\n", + "\n", + "# Calculate the NDFI using image expression.\n", + "NDFI = sma.expression(\n", + " '(GVs - (NPV + Soil)) / (GVs + NPV + Soil)', {\n", + " 'GVs': sma.select('GVs'),\n", + " 'NPV': sma.select('NPV'),\n", + " 'Soil': sma.select('Soil')\n", + " }).rename('NDFI')\n", + "\n", + "# Add the NDFI band to the SMA image.\n", + "sma = sma.addBands(NDFI)\n", + "\n", + "# Define NDFI color table.\n", + "palettes = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes'\n", + ")\n", + "ndfiColors = palettes.ndfiColors\n", + "\n", + "imageVis = {\n", + " 'bands': ['SR_B5', 'SR_B4', 'SR_B3'],\n", + " 'min': 0,\n", + " 'max': 0.4\n", + "}\n", + "\n", + "# Add the Landsat color composite to the map.\n", + "Map.addLayer(image, imageVis, 'Landsat 5 RGB-543', True)\n", + "\n", + "# Add the fraction images to the map.\n", + "Map.addLayer(sma.select('Soil'), {\n", + " 'min': 0,\n", + " 'max': 0.2\n", + "}, 'Soil')\n", + "Map.addLayer(sma.select('GV'), {\n", + " 'min': 0,\n", + " 'max': 0.6\n", + "}, 'GV')\n", + "Map.addLayer(sma.select('NPV'), {\n", + " 'min': 0,\n", + " 'max': 0.2\n", + "}, 'NPV')\n", + "Map.addLayer(sma.select('Shade'), {\n", + " 'min': 0,\n", + " 'max': 0.8\n", + "}, 'Shade')\n", + "Map.addLayer(sma.select('GVs'), {\n", + " 'min': 0,\n", + " 'max': 0.9\n", + "}, 'GVs')\n", + "Map.addLayer(sma.select('NDFI'), {\n", + " 'palette': ndfiColors\n", + "}, 'NDFI')\n", + "\n", + "def getWaterMask(sma):\n", + " waterMask = (sma.select('Shade').gte(0.65)) \\\n", + " .And(sma.select('GV').lte(0.15)) \\\n", + " .And(sma.select('Soil').lte(0.05))\n", + " return waterMask.rename('Water')\n", + "\n", + "\n", + "# You can use the variable below to get the cloud mask.\n", + "cloud = sma.select('Cloud').gte(0.1)\n", + "water = getWaterMask(sma)\n", + "\n", + "cloudWaterMask = cloud.max(water)\n", + "Map.addLayer(cloudWaterMask.selfMask(),\n", + " {\n", + " 'min': 1,\n", + " 'max': 1,\n", + " 'palette': 'blue'\n", + " },\n", + " 'Cloud and water mask')\n", + "\n", + "# Mask NDFI.\n", + "maskedNDFI = sma.select('NDFI').updateMask(cloudWaterMask.Not())\n", + "Map.addLayer(maskedNDFI, {\n", + " 'palette': ndfiColors\n", + "}, 'NDFI')\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34a Checkpoint.js new file mode 100644 index 0000000..38dc688 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34a Checkpoint.js @@ -0,0 +1,145 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.4 Forest Degradation and Deforestation +// Checkpoint: A34a +// Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +// Crystal Wespestad, Eric Bullock +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// SMA Model - Section 1 + +// Define the Landsat endmembers (source: Souza et al. 2005) +// They can be applied to Landsat 5, 7, 8, and potentially 9. +var endmembers = [ + [0.0119,0.0475,0.0169,0.625,0.2399,0.0675], // GV + [0.1514,0.1597,0.1421,0.3053,0.7707,0.1975], // NPV + [0.1799,0.2479,0.3158,0.5437,0.7707,0.6646], // Soil + [0.4031,0.8714,0.79,0.8989,0.7002,0.6607] // Cloud +]; + +// Select a Landsat 5 scene on which to apply the SMA model. +var image = ee.Image('LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') + .multiply(0.0000275).add(-0.2); + +// Center the map on the image object. +Map.centerObject(image, 10); + +// Define and select the Landsat bands to apply the SMA model. +// use ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] for Landsat 5 and 7. +// use ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'] for Landsat 8. +var bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']; +image = image.select(bands); + +// Unmixing image using Singular Value Decomposition. +var getSMAFractions = function(image, endmembers) { + var unmixed = ee.Image(image) + .select([0, 1, 2, 3, 4, + 5]) // Use the visible, NIR, and SWIR bands only! + .unmix(endmembers) + .max(0) // Remove negative fractions, mostly Soil. + .rename('GV', 'NPV', 'Soil', 'Cloud'); + return ee.Image(unmixed.copyProperties(image)); +}; + +// Calculate GVS and NDFI and add them to image fractions. +// Run the SMA model passing the Landsat image and the endmembers. +var sma = getSMAFractions(image, endmembers); + +Map.addLayer(sma, { + bands: ['NPV', 'GV', 'Soil'], + min: 0, + max: 0.45 +}, 'sma'); + +// Calculate the Shade and GV shade-normalized (GVs) fractions from the SMA bands. +var Shade = sma.reduce(ee.Reducer.sum()) + .subtract(1.0) + .abs() + .rename('Shade'); + +var GVs = sma.select('GV') + .divide(Shade.subtract(1.0).abs()) + .rename('GVs'); + +// Add the new bands to the SMA image variable. +sma = sma.addBands([Shade, GVs]); + +// Calculate the NDFI using image expression. +var NDFI = sma.expression( + '(GVs - (NPV + Soil)) / (GVs + NPV + Soil)', { + 'GVs': sma.select('GVs'), + 'NPV': sma.select('NPV'), + 'Soil': sma.select('Soil') + }).rename('NDFI'); + +// Add the NDFI band to the SMA image. +sma = sma.addBands(NDFI); + +// Define NDFI color table. +var palettes = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes' +); +var ndfiColors = palettes.ndfiColors; + +var imageVis = { + 'bands': ['SR_B5', 'SR_B4', 'SR_B3'], + 'min': 0, + 'max': 0.4 +}; + +// Add the Landsat color composite to the map. +Map.addLayer(image, imageVis, 'Landsat 5 RGB-543', true); + +// Add the fraction images to the map. +Map.addLayer(sma.select('Soil'), { + min: 0, + max: 0.2 +}, 'Soil'); +Map.addLayer(sma.select('GV'), { + min: 0, + max: 0.6 +}, 'GV'); +Map.addLayer(sma.select('NPV'), { + min: 0, + max: 0.2 +}, 'NPV'); +Map.addLayer(sma.select('Shade'), { + min: 0, + max: 0.8 +}, 'Shade'); +Map.addLayer(sma.select('GVs'), { + min: 0, + max: 0.9 +}, 'GVs'); +Map.addLayer(sma.select('NDFI'), { + palette: ndfiColors +}, 'NDFI'); + +var getWaterMask = function(sma) { + var waterMask = (sma.select('Shade').gte(0.65)) + .and(sma.select('GV').lte(0.15)) + .and(sma.select('Soil').lte(0.05)); + return waterMask.rename('Water'); +}; + +// You can use the variable below to get the cloud mask. +var cloud = sma.select('Cloud').gte(0.1); +var water = getWaterMask(sma); + +var cloudWaterMask = cloud.max(water); +Map.addLayer(cloudWaterMask.selfMask(), + { + min: 1, + max: 1, + palette: 'blue' + }, + 'Cloud and water mask'); + +// Mask NDFI. +var maskedNDFI = sma.select('NDFI').updateMask(cloudWaterMask.not()); +Map.addLayer(maskedNDFI, { + palette: ndfiColors +}, 'NDFI'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34a Checkpoint.py new file mode 100644 index 0000000..0e30b1e --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34a Checkpoint.py @@ -0,0 +1,151 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.4 Forest Degradation and Deforestation +# Checkpoint: A34a +# Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +# Crystal Wespestad, Eric Bullock +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# SMA Model - Section 1 + +# Define the Landsat endmembers (source: Souza et al. 2005) +# They can be applied to Landsat 5, 7, 8, and potentially 9. +endmembers = [ + [0.0119,0.0475,0.0169,0.625,0.2399,0.0675], # GV + [0.1514,0.1597,0.1421,0.3053,0.7707,0.1975], # NPV + [0.1799,0.2479,0.3158,0.5437,0.7707,0.6646], # Soil + [0.4031,0.8714,0.79,0.8989,0.7002,0.6607] # Cloud +] + +# Select a Landsat 5 scene on which to apply the SMA model. +image = ee.Image('LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') \ + .multiply(0.0000275).add(-0.2) + +# Center the map on the image object. +Map.centerObject(image, 10) + +# Define and select the Landsat bands to apply the SMA model. +# use ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] for Landsat 5 and 7. +# use ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'] for Landsat 8. +bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] +image = image.select(bands) + +# Unmixing image using Singular Value Decomposition. +def getSMAFractions(image, endmembers): + unmixed = ee.Image(image) \ + .select([0, 1, 2, 3, 4, + 5]) # Use the visible, NIR, and SWIR bands only! \ + .unmix(endmembers) \ + .max(0) \ + .rename('GV', 'NPV', 'Soil', 'Cloud') + return ee.Image(unmixed.copyProperties(image)) + + +# Calculate GVS and NDFI and add them to image fractions. +# Run the SMA model passing the Landsat image and the endmembers. +sma = getSMAFractions(image, endmembers) + +Map.addLayer(sma, { + 'bands': ['NPV', 'GV', 'Soil'], + 'min': 0, + 'max': 0.45 +}, 'sma') + +# Calculate the Shade and GV shade-normalized (GVs) fractions from the SMA bands. +Shade = sma.reduce(ee.Reducer.sum()) \ + .subtract(1.0) \ + .abs() \ + .rename('Shade') + +GVs = sma.select('GV') \ + .divide(Shade.subtract(1.0).abs()) \ + .rename('GVs') + +# Add the new bands to the SMA image variable. +sma = sma.addBands([Shade, GVs]) + +# Calculate the NDFI using image expression. +NDFI = sma.expression( + '(GVs - (NPV + Soil)) / (GVs + NPV + Soil)', { + 'GVs': sma.select('GVs'), + 'NPV': sma.select('NPV'), + 'Soil': sma.select('Soil') + }).rename('NDFI') + +# Add the NDFI band to the SMA image. +sma = sma.addBands(NDFI) + +# Define NDFI color table. +palettes = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes' +) +ndfiColors = palettes.ndfiColors + +imageVis = { + 'bands': ['SR_B5', 'SR_B4', 'SR_B3'], + 'min': 0, + 'max': 0.4 +} + +# Add the Landsat color composite to the map. +Map.addLayer(image, imageVis, 'Landsat 5 RGB-543', True) + +# Add the fraction images to the map. +Map.addLayer(sma.select('Soil'), { + 'min': 0, + 'max': 0.2 +}, 'Soil') +Map.addLayer(sma.select('GV'), { + 'min': 0, + 'max': 0.6 +}, 'GV') +Map.addLayer(sma.select('NPV'), { + 'min': 0, + 'max': 0.2 +}, 'NPV') +Map.addLayer(sma.select('Shade'), { + 'min': 0, + 'max': 0.8 +}, 'Shade') +Map.addLayer(sma.select('GVs'), { + 'min': 0, + 'max': 0.9 +}, 'GVs') +Map.addLayer(sma.select('NDFI'), { + 'palette': ndfiColors +}, 'NDFI') + +def getWaterMask(sma): + waterMask = (sma.select('Shade').gte(0.65)) \ + .And(sma.select('GV').lte(0.15)) \ + .And(sma.select('Soil').lte(0.05)) + return waterMask.rename('Water') + + +# You can use the variable below to get the cloud mask. +cloud = sma.select('Cloud').gte(0.1) +water = getWaterMask(sma) + +cloudWaterMask = cloud.max(water) +Map.addLayer(cloudWaterMask.selfMask(), + { + 'min': 1, + 'max': 1, + 'palette': 'blue' + }, + 'Cloud and water mask') + +# Mask NDFI. +maskedNDFI = sma.select('NDFI').updateMask(cloudWaterMask.Not()) +Map.addLayer(maskedNDFI, { + 'palette': ndfiColors +}, 'NDFI') + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34b Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34b Checkpoint.ipynb new file mode 100644 index 0000000..4e3e30a --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34b Checkpoint.ipynb @@ -0,0 +1,415 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "region =\n", + "\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-55.34261539064037, -11.129685463388977],\n", + " [-55.34261539064037, -11.351258284899552],\n", + " [-54.79879214845287, -11.351258284899552],\n", + " [-54.79879214845287, -11.129685463388977]]], None, False)\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.4 Forest Degradation and Deforestation\n", + "# Checkpoint: A34b\n", + "# Author: Carlos Souza Jr., Karis Tenneson, John Dilger,\n", + "# Crystal Wespestad, Eric Bullock\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# SMA Model - Section 1\n", + "\n", + "# Define the Landsat endmembers (source: Souza et al. 2005)\n", + "# They can be applied to Landsat 5, 7, 8, and potentially 9.\n", + "endmembers = [\n", + " [0.0119, 0.0475, 0.0169, 0.625, 0.2399, 0.0675], # GV\n", + " [0.1514, 0.1597, 0.1421, 0.3053, 0.7707, 0.1975], # NPV\n", + " [0.1799, 0.2479, 0.3158, 0.5437, 0.7707, 0.6646], # Soil\n", + " [0.4031, 0.8714, 0.79, 0.8989, 0.7002, 0.6607] # Cloud\n", + "]\n", + "\n", + "# Select a Landsat 5 scene on which to apply the SMA model.\n", + "image = ee.Image('LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') \\\n", + " .multiply(0.0000275).add(-0.2)\n", + "\n", + "# Center the map on the image object.\n", + "Map.centerObject(image, 10)\n", + "\n", + "# Define and select the Landsat bands to apply the SMA model.\n", + "# use ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] for Landsat 5 and 7.\n", + "# use ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'] for Landsat 8.\n", + "bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']\n", + "image = image.select(bands)\n", + "\n", + "# Unmixing image using Singular Value Decomposition.\n", + "def getSMAFractions(image, endmembers):\n", + " unmixed = ee.Image(image) \\\n", + " .select([0, 1, 2, 3, 4,\n", + " 5\n", + " ]) # Use the visible, NIR, and SWIR bands only! \\\n", + " .unmix(endmembers) \\\n", + " .max(0) \\\n", + " .rename('GV', 'NPV', 'Soil', 'Cloud')\n", + " return ee.Image(unmixed.copyProperties(image))\n", + "\n", + "\n", + "# Calculate GVS and NDFI and add them to image fractions.\n", + "# Run the SMA model passing the Landsat image and the endmembers.\n", + "sma = getSMAFractions(image, endmembers)\n", + "\n", + "Map.addLayer(sma, {\n", + " 'bands': ['NPV', 'GV', 'Soil'],\n", + " 'min': 0,\n", + " 'max': 0.45\n", + "}, 'sma')\n", + "\n", + "# Calculate the Shade and GV shade-normalized (GVs) fractions from the SMA bands.\n", + "Shade = sma.reduce(ee.Reducer.sum()) \\\n", + " .subtract(1.0) \\\n", + " .abs() \\\n", + " .rename('Shade')\n", + "\n", + "GVs = sma.select('GV') \\\n", + " .divide(Shade.subtract(1.0).abs()) \\\n", + " .rename('GVs')\n", + "\n", + "# Add the new bands to the SMA image variable.\n", + "sma = sma.addBands([Shade, GVs])\n", + "\n", + "# Calculate the NDFI using image expression.\n", + "NDFI = sma.expression(\n", + " '(GVs - (NPV + Soil)) / (GVs + NPV + Soil)', {\n", + " 'GVs': sma.select('GVs'),\n", + " 'NPV': sma.select('NPV'),\n", + " 'Soil': sma.select('Soil')\n", + " }).rename('NDFI')\n", + "\n", + "# Add the NDFI band to the SMA image.\n", + "sma = sma.addBands(NDFI)\n", + "\n", + "# Define NDFI color table.\n", + "palettes = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes'\n", + ")\n", + "ndfiColors = palettes.ndfiColors\n", + "\n", + "imageVis = {\n", + " 'bands': ['SR_B5', 'SR_B4', 'SR_B3'],\n", + " 'min': 0,\n", + " 'max': 0.4\n", + "}\n", + "\n", + "# Add the Landsat color composite to the map.\n", + "Map.addLayer(image, imageVis, 'Landsat 5 RGB-543', True)\n", + "\n", + "# Add the fraction images to the map.\n", + "Map.addLayer(sma.select('Soil'), {\n", + " 'min': 0,\n", + " 'max': 0.2\n", + "}, 'Soil')\n", + "Map.addLayer(sma.select('GV'), {\n", + " 'min': 0,\n", + " 'max': 0.6\n", + "}, 'GV')\n", + "Map.addLayer(sma.select('NPV'), {\n", + " 'min': 0,\n", + " 'max': 0.2\n", + "}, 'NPV')\n", + "Map.addLayer(sma.select('Shade'), {\n", + " 'min': 0,\n", + " 'max': 0.8\n", + "}, 'Shade')\n", + "Map.addLayer(sma.select('GVs'), {\n", + " 'min': 0,\n", + " 'max': 0.9\n", + "}, 'GVs')\n", + "Map.addLayer(sma.select('NDFI'), {\n", + " 'palette': ndfiColors\n", + "}, 'NDFI')\n", + "\n", + "def getWaterMask(sma):\n", + " waterMask = (sma.select('Shade').gte(0.65)) \\\n", + " .And(sma.select('GV').lte(0.15)) \\\n", + " .And(sma.select('Soil').lte(0.05))\n", + " return waterMask.rename('Water')\n", + "\n", + "\n", + "# You can use the variable below to get the cloud mask.\n", + "cloud = sma.select('Cloud').gte(0.1)\n", + "water = getWaterMask(sma)\n", + "\n", + "cloudWaterMask = cloud.max(water)\n", + "Map.addLayer(cloudWaterMask.selfMask(),\n", + " {\n", + " 'min': 1,\n", + " 'max': 1,\n", + " 'palette': 'blue'\n", + " },\n", + " 'Cloud and water mask')\n", + "\n", + "# Mask NDFI.\n", + "maskedNDFI = sma.select('NDFI').updateMask(cloudWaterMask.Not())\n", + "Map.addLayer(maskedNDFI, {\n", + " 'palette': ndfiColors\n", + "}, 'NDFI')\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "# Select two Landsat 5 scenes on which to apply the SMA model.\n", + "\n", + "# Select Landsat bands used for forest change detection.\n", + "imageTime0 = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_226068_20000509') \\\n", + " .multiply(0.0000275).add(-0.2)\n", + "bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']\n", + "imageTime0 = imageTime0.select(bands)\n", + "\n", + "# Run the SMA model.\n", + "smaTime0 = getSMAFractions(imageTime0, endmembers)\n", + "\n", + "# Center the image object.\n", + "Map.centerObject(imageTime0, 10)\n", + "\n", + "# Define the visualization parameters.\n", + "imageVis = {\n", + " 'opacity': 1,\n", + " 'bands': ['SR_B5', 'SR_B4', 'SR_B3'],\n", + " 'min': 0,\n", + " 'max': 0.4,\n", + " 'gamma': 1\n", + "}\n", + "# Scale to the expected maximum fraction values.\n", + "fractionVis = {\n", + " 'opacity': 1,\n", + " 'min': 0.0,\n", + " 'max': 0.5\n", + "}\n", + "\n", + "# Add the Landsat color composite to the map.\n", + "Map.addLayer(imageTime0, imageVis, 'Landsat 5 RGB 543', True)\n", + "\n", + "# Add the fraction images to the map.\n", + "Map.addLayer(smaTime0.select('Soil'), fractionVis, 'Soil Fraction')\n", + "Map.addLayer(smaTime0.select('GV'), fractionVis, 'GV Fraction')\n", + "Map.addLayer(smaTime0.select('NPV'), fractionVis, 'NPV Fraction')\n", + "\n", + "def getNDFI(smaImage):\n", + " # Calculate the Shade and GV shade-normalized (GVs) fractions\n", + " # from the SMA bands.\n", + " Shade = smaImage.reduce(ee.Reducer.sum()) \\\n", + " .subtract(1.0) \\\n", + " .abs() \\\n", + " .rename('Shade')\n", + "\n", + " GVs = smaImage.select('GV') \\\n", + " .divide(Shade.subtract(1.0).abs()) \\\n", + " .rename('GVs')\n", + "\n", + " # Add the new bands to the SMA image variable.\n", + " smaImage = smaImage.addBands([Shade, GVs])\n", + "\n", + " ndfi = smaImage.expression(\n", + " '(GVs - (NPV + Soil)) / (GVs + NPV + Soil)', {\n", + " 'GVs': smaImage.select('GVs'),\n", + " 'NPV': smaImage.select('NPV'),\n", + " 'Soil': smaImage.select('Soil')\n", + " }\n", + " ).rename('NDFI')\n", + "\n", + " return ndfi\n", + "\n", + "\n", + "# Create the initial NDFI image and add it to the map.\n", + "ndfiTime0 = getNDFI(smaTime0)\n", + "Map.addLayer(ndfiTime0,\n", + " {\n", + " 'bands': ['NDFI'],\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': ndfiColors\n", + " },\n", + " 'NDFI t0',\n", + " False)\n", + "\n", + "# Select a second Landsat 5 scene on which to apply the SMA model.\n", + "imageTime1 = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_226068_20010629') \\\n", + " .multiply(0.0000275).add(-0.2) \\\n", + " .select(['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'])\n", + "smaTime1 = getSMAFractions(imageTime1, endmembers)\n", + "\n", + "# Create the second NDFI image and add it to the map.\n", + "ndfiTime1 = getNDFI(smaTime1)\n", + "\n", + "Map.addLayer(imageTime1, imageVis, 'Landsat 5 t1 RGB-5', True)\n", + "Map.addLayer(ndfiTime1,\n", + " {\n", + " 'bands': ['NDFI'],\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': ndfiColors\n", + " },\n", + " 'NDFI_t1',\n", + " False)\n", + "\n", + "# Combine the two NDFI images in a single variable.\n", + "ndfi = ndfiTime0.select('NDFI') \\\n", + " .addBands(ndfiTime1.select('NDFI')) \\\n", + " .rename('NDFI_t0', 'NDFI_t1')\n", + "\n", + "# Calculate the NDFI change.\n", + "ndfiChange = ndfi.select('NDFI_t1') \\\n", + " .subtract(ndfi.select('NDFI_t0')) \\\n", + " .rename('NDFI Change')\n", + "\n", + "options = {\n", + " 'title': 'NDFI Difference Histogram',\n", + " 'fontSize': 20,\n", + " 'hAxis': {\n", + " 'title': 'Change'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Frequency'\n", + " },\n", + " 'series': {\n", + " '0': {\n", + " 'color': 'green'\n", + " }\n", + " }\n", + "}\n", + "\n", + "# Inspect the histogram of the NDFI change image to define threshold\n", + "# values for classification. Make the histogram, set the options.\n", + "histNDFIChange = ui.Chart.image.histogram(\n", + " ndfiChange.select('NDFI Change'), region, 30) \\\n", + " .setSeriesNames(['NDFI Change']) \\\n", + " .setOptions(options)\n", + "\n", + "print(histNDFIChange)\n", + "\n", + "# Classify the NDFI difference image based on thresholds\n", + "# obtained from its histogram.\n", + "changeClassification = ndfiChange.expression(\n", + " '(b(0) >= -0.095 && b(0) <= 0.095) ? 1 :' + \\\n", + " # No forest change\n", + " '(b(0) >= -0.250 && b(0) <= -0.095) ? 2 :' + # Logging\n", + " '(b(0) <= -0.250) ? 3 :' + # Deforestation\n", + " '(b(0) >= 0.095) ? 4 : 0') # Vegetation regrowth \\\n", + " .updateMask(ndfi.select('NDFI_t0').gt(\n", + " 0.60)); # mask out no forest\n", + "\n", + "# Use a simple threshold to get forest in the first image date.\n", + "forest = ndfi.select('NDFI_t0').gt(0.60)\n", + "\n", + "# Add layers to map\n", + "Map.addLayer(ndfi, {\n", + " 'bands': ['NDFI_t0', 'NDFI_t1', 'NDFI_t1']\n", + "}, 'NDFI Change')\n", + "Map.addLayer(ndfiChange, {}, 'NDFI Difference')\n", + "Map.addLayer(forest, {}, 'Forest t0 ')\n", + "Map.addLayer(changeClassification, {\n", + " 'palette': ['000000', '1eaf0c', 'ffc239', 'ff422f',\n", + " '74fff9']\n", + " },\n", + " 'Change Classification')\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34b Checkpoint.js new file mode 100644 index 0000000..18a39e5 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34b Checkpoint.js @@ -0,0 +1,322 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var region = + /* color: #0b4a8b */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-55.34261539064037, -11.129685463388977], + [-55.34261539064037, -11.351258284899552], + [-54.79879214845287, -11.351258284899552], + [-54.79879214845287, -11.129685463388977]]], null, false); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.4 Forest Degradation and Deforestation +// Checkpoint: A34b +// Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +// Crystal Wespestad, Eric Bullock +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// SMA Model - Section 1 + +// Define the Landsat endmembers (source: Souza et al. 2005) +// They can be applied to Landsat 5, 7, 8, and potentially 9. +var endmembers = [ + [0.0119, 0.0475, 0.0169, 0.625, 0.2399, 0.0675], // GV + [0.1514, 0.1597, 0.1421, 0.3053, 0.7707, 0.1975], // NPV + [0.1799, 0.2479, 0.3158, 0.5437, 0.7707, 0.6646], // Soil + [0.4031, 0.8714, 0.79, 0.8989, 0.7002, 0.6607] // Cloud +]; + +// Select a Landsat 5 scene on which to apply the SMA model. +var image = ee.Image('LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') + .multiply(0.0000275).add(-0.2); + +// Center the map on the image object. +Map.centerObject(image, 10); + +// Define and select the Landsat bands to apply the SMA model. +// use ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] for Landsat 5 and 7. +// use ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'] for Landsat 8. +var bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']; +image = image.select(bands); + +// Unmixing image using Singular Value Decomposition. +var getSMAFractions = function(image, endmembers) { + var unmixed = ee.Image(image) + .select([0, 1, 2, 3, 4, + 5 + ]) // Use the visible, NIR, and SWIR bands only! + .unmix(endmembers) + .max(0) // Remove negative fractions, mostly Soil. + .rename('GV', 'NPV', 'Soil', 'Cloud'); + return ee.Image(unmixed.copyProperties(image)); +}; + +// Calculate GVS and NDFI and add them to image fractions. +// Run the SMA model passing the Landsat image and the endmembers. +var sma = getSMAFractions(image, endmembers); + +Map.addLayer(sma, { + bands: ['NPV', 'GV', 'Soil'], + min: 0, + max: 0.45 +}, 'sma'); + +// Calculate the Shade and GV shade-normalized (GVs) fractions from the SMA bands. +var Shade = sma.reduce(ee.Reducer.sum()) + .subtract(1.0) + .abs() + .rename('Shade'); + +var GVs = sma.select('GV') + .divide(Shade.subtract(1.0).abs()) + .rename('GVs'); + +// Add the new bands to the SMA image variable. +sma = sma.addBands([Shade, GVs]); + +// Calculate the NDFI using image expression. +var NDFI = sma.expression( + '(GVs - (NPV + Soil)) / (GVs + NPV + Soil)', { + 'GVs': sma.select('GVs'), + 'NPV': sma.select('NPV'), + 'Soil': sma.select('Soil') + }).rename('NDFI'); + +// Add the NDFI band to the SMA image. +sma = sma.addBands(NDFI); + +// Define NDFI color table. +var palettes = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes' +); +var ndfiColors = palettes.ndfiColors; + +var imageVis = { + 'bands': ['SR_B5', 'SR_B4', 'SR_B3'], + 'min': 0, + 'max': 0.4 +}; + +// Add the Landsat color composite to the map. +Map.addLayer(image, imageVis, 'Landsat 5 RGB-543', true); + +// Add the fraction images to the map. +Map.addLayer(sma.select('Soil'), { + min: 0, + max: 0.2 +}, 'Soil'); +Map.addLayer(sma.select('GV'), { + min: 0, + max: 0.6 +}, 'GV'); +Map.addLayer(sma.select('NPV'), { + min: 0, + max: 0.2 +}, 'NPV'); +Map.addLayer(sma.select('Shade'), { + min: 0, + max: 0.8 +}, 'Shade'); +Map.addLayer(sma.select('GVs'), { + min: 0, + max: 0.9 +}, 'GVs'); +Map.addLayer(sma.select('NDFI'), { + palette: ndfiColors +}, 'NDFI'); + +var getWaterMask = function(sma) { + var waterMask = (sma.select('Shade').gte(0.65)) + .and(sma.select('GV').lte(0.15)) + .and(sma.select('Soil').lte(0.05)); + return waterMask.rename('Water'); +}; + +// You can use the variable below to get the cloud mask. +var cloud = sma.select('Cloud').gte(0.1); +var water = getWaterMask(sma); + +var cloudWaterMask = cloud.max(water); +Map.addLayer(cloudWaterMask.selfMask(), + { + min: 1, + max: 1, + palette: 'blue' + }, + 'Cloud and water mask'); + +// Mask NDFI. +var maskedNDFI = sma.select('NDFI').updateMask(cloudWaterMask.not()); +Map.addLayer(maskedNDFI, { + palette: ndfiColors +}, 'NDFI'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +// Select two Landsat 5 scenes on which to apply the SMA model. + +// Select Landsat bands used for forest change detection. +var imageTime0 = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_226068_20000509') + .multiply(0.0000275).add(-0.2); +var bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']; +imageTime0 = imageTime0.select(bands); + +// Run the SMA model. +var smaTime0 = getSMAFractions(imageTime0, endmembers); + +// Center the image object. +Map.centerObject(imageTime0, 10); + +// Define the visualization parameters. +var imageVis = { + 'opacity': 1, + 'bands': ['SR_B5', 'SR_B4', 'SR_B3'], + 'min': 0, + 'max': 0.4, + 'gamma': 1 +}; +// Scale to the expected maximum fraction values. +var fractionVis = { + 'opacity': 1, + 'min': 0.0, + 'max': 0.5 +}; + +// Add the Landsat color composite to the map. +Map.addLayer(imageTime0, imageVis, 'Landsat 5 RGB 543', true); + +// Add the fraction images to the map. +Map.addLayer(smaTime0.select('Soil'), fractionVis, 'Soil Fraction'); +Map.addLayer(smaTime0.select('GV'), fractionVis, 'GV Fraction'); +Map.addLayer(smaTime0.select('NPV'), fractionVis, 'NPV Fraction'); + +function getNDFI(smaImage) { + // Calculate the Shade and GV shade-normalized (GVs) fractions + // from the SMA bands. + var Shade = smaImage.reduce(ee.Reducer.sum()) + .subtract(1.0) + .abs() + .rename('Shade'); + + var GVs = smaImage.select('GV') + .divide(Shade.subtract(1.0).abs()) + .rename('GVs'); + + // Add the new bands to the SMA image variable. + smaImage = smaImage.addBands([Shade, GVs]); + + var ndfi = smaImage.expression( + '(GVs - (NPV + Soil)) / (GVs + NPV + Soil)', { + 'GVs': smaImage.select('GVs'), + 'NPV': smaImage.select('NPV'), + 'Soil': smaImage.select('Soil') + } + ).rename('NDFI'); + + return ndfi; +} + +// Create the initial NDFI image and add it to the map. +var ndfiTime0 = getNDFI(smaTime0); +Map.addLayer(ndfiTime0, + { + bands: ['NDFI'], + min: -1, + max: 1, + palette: ndfiColors + }, + 'NDFI t0', + false); + +// Select a second Landsat 5 scene on which to apply the SMA model. +var imageTime1 = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_226068_20010629') + .multiply(0.0000275).add(-0.2) + .select(['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']); +var smaTime1 = getSMAFractions(imageTime1, endmembers); + +// Create the second NDFI image and add it to the map. +var ndfiTime1 = getNDFI(smaTime1); + +Map.addLayer(imageTime1, imageVis, 'Landsat 5 t1 RGB-5', true); +Map.addLayer(ndfiTime1, + { + bands: ['NDFI'], + min: -1, + max: 1, + palette: ndfiColors + }, + 'NDFI_t1', + false); + +// Combine the two NDFI images in a single variable. +var ndfi = ndfiTime0.select('NDFI') + .addBands(ndfiTime1.select('NDFI')) + .rename('NDFI_t0', 'NDFI_t1'); + +// Calculate the NDFI change. +var ndfiChange = ndfi.select('NDFI_t1') + .subtract(ndfi.select('NDFI_t0')) + .rename('NDFI Change'); + +var options = { + title: 'NDFI Difference Histogram', + fontSize: 20, + hAxis: { + title: 'Change' + }, + vAxis: { + title: 'Frequency' + }, + series: { + 0: { + color: 'green' + } + } +}; + +// Inspect the histogram of the NDFI change image to define threshold +// values for classification. Make the histogram, set the options. +var histNDFIChange = ui.Chart.image.histogram( + ndfiChange.select('NDFI Change'), region, 30) + .setSeriesNames(['NDFI Change']) + .setOptions(options); + +print(histNDFIChange); + +// Classify the NDFI difference image based on thresholds +// obtained from its histogram. +var changeClassification = ndfiChange.expression( + '(b(0) >= -0.095 && b(0) <= 0.095) ? 1 :' + + // No forest change + '(b(0) >= -0.250 && b(0) <= -0.095) ? 2 :' + // Logging + '(b(0) <= -0.250) ? 3 :' + // Deforestation + '(b(0) >= 0.095) ? 4 : 0') // Vegetation regrowth + .updateMask(ndfi.select('NDFI_t0').gt( + 0.60)); // mask out no forest + +// Use a simple threshold to get forest in the first image date. +var forest = ndfi.select('NDFI_t0').gt(0.60); + +// Add layers to map +Map.addLayer(ndfi, { + 'bands': ['NDFI_t0', 'NDFI_t1', 'NDFI_t1'] +}, 'NDFI Change'); +Map.addLayer(ndfiChange, {}, 'NDFI Difference'); +Map.addLayer(forest, {}, 'Forest t0 '); +Map.addLayer(changeClassification, { + palette: ['000000', '1eaf0c', 'ffc239', 'ff422f', + '74fff9'] + }, + 'Change Classification'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34b Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34b Checkpoint.py new file mode 100644 index 0000000..edddcaa --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34b Checkpoint.py @@ -0,0 +1,328 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +region = + + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-55.34261539064037, -11.129685463388977], + [-55.34261539064037, -11.351258284899552], + [-54.79879214845287, -11.351258284899552], + [-54.79879214845287, -11.129685463388977]]], None, False) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.4 Forest Degradation and Deforestation +# Checkpoint: A34b +# Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +# Crystal Wespestad, Eric Bullock +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# SMA Model - Section 1 + +# Define the Landsat endmembers (source: Souza et al. 2005) +# They can be applied to Landsat 5, 7, 8, and potentially 9. +endmembers = [ + [0.0119, 0.0475, 0.0169, 0.625, 0.2399, 0.0675], # GV + [0.1514, 0.1597, 0.1421, 0.3053, 0.7707, 0.1975], # NPV + [0.1799, 0.2479, 0.3158, 0.5437, 0.7707, 0.6646], # Soil + [0.4031, 0.8714, 0.79, 0.8989, 0.7002, 0.6607] # Cloud +] + +# Select a Landsat 5 scene on which to apply the SMA model. +image = ee.Image('LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') \ + .multiply(0.0000275).add(-0.2) + +# Center the map on the image object. +Map.centerObject(image, 10) + +# Define and select the Landsat bands to apply the SMA model. +# use ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] for Landsat 5 and 7. +# use ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'] for Landsat 8. +bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] +image = image.select(bands) + +# Unmixing image using Singular Value Decomposition. +def getSMAFractions(image, endmembers): + unmixed = ee.Image(image) \ + .select([0, 1, 2, 3, 4, + 5 + ]) # Use the visible, NIR, and SWIR bands only! \ + .unmix(endmembers) \ + .max(0) \ + .rename('GV', 'NPV', 'Soil', 'Cloud') + return ee.Image(unmixed.copyProperties(image)) + + +# Calculate GVS and NDFI and add them to image fractions. +# Run the SMA model passing the Landsat image and the endmembers. +sma = getSMAFractions(image, endmembers) + +Map.addLayer(sma, { + 'bands': ['NPV', 'GV', 'Soil'], + 'min': 0, + 'max': 0.45 +}, 'sma') + +# Calculate the Shade and GV shade-normalized (GVs) fractions from the SMA bands. +Shade = sma.reduce(ee.Reducer.sum()) \ + .subtract(1.0) \ + .abs() \ + .rename('Shade') + +GVs = sma.select('GV') \ + .divide(Shade.subtract(1.0).abs()) \ + .rename('GVs') + +# Add the new bands to the SMA image variable. +sma = sma.addBands([Shade, GVs]) + +# Calculate the NDFI using image expression. +NDFI = sma.expression( + '(GVs - (NPV + Soil)) / (GVs + NPV + Soil)', { + 'GVs': sma.select('GVs'), + 'NPV': sma.select('NPV'), + 'Soil': sma.select('Soil') + }).rename('NDFI') + +# Add the NDFI band to the SMA image. +sma = sma.addBands(NDFI) + +# Define NDFI color table. +palettes = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes' +) +ndfiColors = palettes.ndfiColors + +imageVis = { + 'bands': ['SR_B5', 'SR_B4', 'SR_B3'], + 'min': 0, + 'max': 0.4 +} + +# Add the Landsat color composite to the map. +Map.addLayer(image, imageVis, 'Landsat 5 RGB-543', True) + +# Add the fraction images to the map. +Map.addLayer(sma.select('Soil'), { + 'min': 0, + 'max': 0.2 +}, 'Soil') +Map.addLayer(sma.select('GV'), { + 'min': 0, + 'max': 0.6 +}, 'GV') +Map.addLayer(sma.select('NPV'), { + 'min': 0, + 'max': 0.2 +}, 'NPV') +Map.addLayer(sma.select('Shade'), { + 'min': 0, + 'max': 0.8 +}, 'Shade') +Map.addLayer(sma.select('GVs'), { + 'min': 0, + 'max': 0.9 +}, 'GVs') +Map.addLayer(sma.select('NDFI'), { + 'palette': ndfiColors +}, 'NDFI') + +def getWaterMask(sma): + waterMask = (sma.select('Shade').gte(0.65)) \ + .And(sma.select('GV').lte(0.15)) \ + .And(sma.select('Soil').lte(0.05)) + return waterMask.rename('Water') + + +# You can use the variable below to get the cloud mask. +cloud = sma.select('Cloud').gte(0.1) +water = getWaterMask(sma) + +cloudWaterMask = cloud.max(water) +Map.addLayer(cloudWaterMask.selfMask(), + { + 'min': 1, + 'max': 1, + 'palette': 'blue' + }, + 'Cloud and water mask') + +# Mask NDFI. +maskedNDFI = sma.select('NDFI').updateMask(cloudWaterMask.Not()) +Map.addLayer(maskedNDFI, { + 'palette': ndfiColors +}, 'NDFI') + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +# Select two Landsat 5 scenes on which to apply the SMA model. + +# Select Landsat bands used for forest change detection. +imageTime0 = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_226068_20000509') \ + .multiply(0.0000275).add(-0.2) +bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] +imageTime0 = imageTime0.select(bands) + +# Run the SMA model. +smaTime0 = getSMAFractions(imageTime0, endmembers) + +# Center the image object. +Map.centerObject(imageTime0, 10) + +# Define the visualization parameters. +imageVis = { + 'opacity': 1, + 'bands': ['SR_B5', 'SR_B4', 'SR_B3'], + 'min': 0, + 'max': 0.4, + 'gamma': 1 +} +# Scale to the expected maximum fraction values. +fractionVis = { + 'opacity': 1, + 'min': 0.0, + 'max': 0.5 +} + +# Add the Landsat color composite to the map. +Map.addLayer(imageTime0, imageVis, 'Landsat 5 RGB 543', True) + +# Add the fraction images to the map. +Map.addLayer(smaTime0.select('Soil'), fractionVis, 'Soil Fraction') +Map.addLayer(smaTime0.select('GV'), fractionVis, 'GV Fraction') +Map.addLayer(smaTime0.select('NPV'), fractionVis, 'NPV Fraction') + +def getNDFI(smaImage): + # Calculate the Shade and GV shade-normalized (GVs) fractions + # from the SMA bands. + Shade = smaImage.reduce(ee.Reducer.sum()) \ + .subtract(1.0) \ + .abs() \ + .rename('Shade') + + GVs = smaImage.select('GV') \ + .divide(Shade.subtract(1.0).abs()) \ + .rename('GVs') + + # Add the new bands to the SMA image variable. + smaImage = smaImage.addBands([Shade, GVs]) + + ndfi = smaImage.expression( + '(GVs - (NPV + Soil)) / (GVs + NPV + Soil)', { + 'GVs': smaImage.select('GVs'), + 'NPV': smaImage.select('NPV'), + 'Soil': smaImage.select('Soil') + } + ).rename('NDFI') + + return ndfi + + +# Create the initial NDFI image and add it to the map. +ndfiTime0 = getNDFI(smaTime0) +Map.addLayer(ndfiTime0, + { + 'bands': ['NDFI'], + 'min': -1, + 'max': 1, + 'palette': ndfiColors + }, + 'NDFI t0', + False) + +# Select a second Landsat 5 scene on which to apply the SMA model. +imageTime1 = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_226068_20010629') \ + .multiply(0.0000275).add(-0.2) \ + .select(['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']) +smaTime1 = getSMAFractions(imageTime1, endmembers) + +# Create the second NDFI image and add it to the map. +ndfiTime1 = getNDFI(smaTime1) + +Map.addLayer(imageTime1, imageVis, 'Landsat 5 t1 RGB-5', True) +Map.addLayer(ndfiTime1, + { + 'bands': ['NDFI'], + 'min': -1, + 'max': 1, + 'palette': ndfiColors + }, + 'NDFI_t1', + False) + +# Combine the two NDFI images in a single variable. +ndfi = ndfiTime0.select('NDFI') \ + .addBands(ndfiTime1.select('NDFI')) \ + .rename('NDFI_t0', 'NDFI_t1') + +# Calculate the NDFI change. +ndfiChange = ndfi.select('NDFI_t1') \ + .subtract(ndfi.select('NDFI_t0')) \ + .rename('NDFI Change') + +options = { + 'title': 'NDFI Difference Histogram', + 'fontSize': 20, + 'hAxis': { + 'title': 'Change' + }, + 'vAxis': { + 'title': 'Frequency' + }, + 'series': { + '0': { + 'color': 'green' + } + } +} + +# Inspect the histogram of the NDFI change image to define threshold +# values for classification. Make the histogram, set the options. +histNDFIChange = ui.Chart.image.histogram( + ndfiChange.select('NDFI Change'), region, 30) \ + .setSeriesNames(['NDFI Change']) \ + .setOptions(options) + +print(histNDFIChange) + +# Classify the NDFI difference image based on thresholds +# obtained from its histogram. +changeClassification = ndfiChange.expression( + '(b(0) >= -0.095 && b(0) <= 0.095) ? 1 :' + \ + # No forest change + '(b(0) >= -0.250 && b(0) <= -0.095) ? 2 :' + # Logging + '(b(0) <= -0.250) ? 3 :' + # Deforestation + '(b(0) >= 0.095) ? 4 : 0') # Vegetation regrowth \ + .updateMask(ndfi.select('NDFI_t0').gt( + 0.60)); # mask out no forest + +# Use a simple threshold to get forest in the first image date. +forest = ndfi.select('NDFI_t0').gt(0.60) + +# Add layers to map +Map.addLayer(ndfi, { + 'bands': ['NDFI_t0', 'NDFI_t1', 'NDFI_t1'] +}, 'NDFI Change') +Map.addLayer(ndfiChange, {}, 'NDFI Difference') +Map.addLayer(forest, {}, 'Forest t0 ') +Map.addLayer(changeClassification, { + 'palette': ['000000', '1eaf0c', 'ffc239', 'ff422f', + '74fff9'] + }, + 'Change Classification') + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34c Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34c Checkpoint.ipynb new file mode 100644 index 0000000..488f33e --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34c Checkpoint.ipynb @@ -0,0 +1,106 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.4 Forest Degradation and Deforestation\n", + "# Checkpoint: A34c\n", + "# Author: Carlos Souza Jr., Karis Tenneson, John Dilger,\n", + "# Crystal Wespestad, Eric Bullock\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "api = require('users/bullocke/coded:CODED/api')\n", + "utils = require('projects/GLANCE:ccdcUtilities/api')\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34c Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34c Checkpoint.js new file mode 100644 index 0000000..202a545 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34c Checkpoint.js @@ -0,0 +1,13 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.4 Forest Degradation and Deforestation +// Checkpoint: A34c +// Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +// Crystal Wespestad, Eric Bullock +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var api = require('users/bullocke/coded:CODED/api'); +var utils = require('projects/GLANCE:ccdcUtilities/api'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34c Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34c Checkpoint.py new file mode 100644 index 0000000..5c40e63 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34c Checkpoint.py @@ -0,0 +1,19 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.4 Forest Degradation and Deforestation +# Checkpoint: A34c +# Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +# Crystal Wespestad, Eric Bullock +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +api = require('users/bullocke/coded:CODED/api') +utils = require('projects/GLANCE:ccdcUtilities/api') + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34d Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34d Checkpoint.ipynb new file mode 100644 index 0000000..293cb48 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34d Checkpoint.ipynb @@ -0,0 +1,161 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.4 Forest Degradation and Deforestation\n", + "# Checkpoint: A34d\n", + "# Author: Carlos Souza Jr., Karis Tenneson, John Dilger,\n", + "# Crystal Wespestad, Eric Bullock\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "api = require('users/bullocke/coded:CODED/api')\n", + "utils = require('projects/GLANCE:ccdcUtilities/api')\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "# We will use the geometry of the image from the previous section as\n", + "# the study area.\n", + "studyArea = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') \\\n", + " .geometry()\n", + "\n", + "# Get cloud masked (Fmask) Landsat imagery.\n", + "landsat = utils.Inputs.getLandsat() \\\n", + " .filterBounds(studyArea) \\\n", + " .filterDate('1984-01-01', '2021-01-01')\n", + "\n", + "# Make a forest mask\n", + "gfwImage = ee.Image('UMD/hansen/global_forest_change_2019_v1_7')\n", + "\n", + "# Get areas of forest cover above the threshold\n", + "treeCover = 40\n", + "forestMask = gfwImage.select('treecover2000') \\\n", + " .gte(treeCover) \\\n", + " .rename('landcover')\n", + "\n", + "samples = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-4/sample_with_pred_hansen_2010')\n", + "\n", + "minObservations = 4\n", + "chiSquareProbability = 0.97\n", + "training = samples\n", + "forestValue = 1\n", + "startYear = 1990\n", + "endYear = 2020\n", + "classBands = ['NDFI', 'GV', 'Shade', 'NPV', 'Soil']\n", + "prepTraining = False\n", + "\n", + "#---------------- CODED parameters\n", + "codedParams = {\n", + " 'minObservations': minObservations,\n", + " 'chiSquareProbability': chiSquareProbability,\n", + " 'training': training,\n", + " 'studyArea': studyArea,\n", + " forestValue: forestValue,\n", + " forestMask: forestMask,\n", + " 'classBands': classBands,\n", + " 'collection': landsat,\n", + " 'startYear': startYear,\n", + " 'endYear': endYear,\n", + " 'prepTraining': prepTraining\n", + "}\n", + "\n", + "# -------------- Run CODED\n", + "results = api.ChangeDetection.coded(codedParams)\n", + "print(results)\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34d Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34d Checkpoint.js new file mode 100644 index 0000000..a6902e0 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34d Checkpoint.js @@ -0,0 +1,68 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.4 Forest Degradation and Deforestation +// Checkpoint: A34d +// Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +// Crystal Wespestad, Eric Bullock +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var api = require('users/bullocke/coded:CODED/api'); +var utils = require('projects/GLANCE:ccdcUtilities/api'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +// We will use the geometry of the image from the previous section as +// the study area. +var studyArea = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') + .geometry(); + +// Get cloud masked (Fmask) Landsat imagery. +var landsat = utils.Inputs.getLandsat() + .filterBounds(studyArea) + .filterDate('1984-01-01', '2021-01-01'); + +// Make a forest mask +var gfwImage = ee.Image('UMD/hansen/global_forest_change_2019_v1_7'); + +// Get areas of forest cover above the threshold +var treeCover = 40; +var forestMask = gfwImage.select('treecover2000') + .gte(treeCover) + .rename('landcover'); + +var samples = ee.FeatureCollection( + 'projects/gee-book/assets/A3-4/sample_with_pred_hansen_2010'); + +var minObservations = 4; +var chiSquareProbability = 0.97; +var training = samples; +var forestValue = 1; +var startYear = 1990; +var endYear = 2020; +var classBands = ['NDFI', 'GV', 'Shade', 'NPV', 'Soil']; +var prepTraining = false; + +//---------------- CODED parameters +var codedParams = { + minObservations: minObservations, + chiSquareProbability: chiSquareProbability, + training: training, + studyArea: studyArea, + forestValue: forestValue, + forestMask: forestMask, + classBands: classBands, + collection: landsat, + startYear: startYear, + endYear: endYear, + prepTraining: prepTraining +}; + +// -------------- Run CODED +var results = api.ChangeDetection.coded(codedParams); +print(results); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34d Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34d Checkpoint.py new file mode 100644 index 0000000..6b909c1 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34d Checkpoint.py @@ -0,0 +1,74 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.4 Forest Degradation and Deforestation +# Checkpoint: A34d +# Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +# Crystal Wespestad, Eric Bullock +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +api = require('users/bullocke/coded:CODED/api') +utils = require('projects/GLANCE:ccdcUtilities/api') + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +# We will use the geometry of the image from the previous section as +# the study area. +studyArea = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') \ + .geometry() + +# Get cloud masked (Fmask) Landsat imagery. +landsat = utils.Inputs.getLandsat() \ + .filterBounds(studyArea) \ + .filterDate('1984-01-01', '2021-01-01') + +# Make a forest mask +gfwImage = ee.Image('UMD/hansen/global_forest_change_2019_v1_7') + +# Get areas of forest cover above the threshold +treeCover = 40 +forestMask = gfwImage.select('treecover2000') \ + .gte(treeCover) \ + .rename('landcover') + +samples = ee.FeatureCollection( + 'projects/gee-book/assets/A3-4/sample_with_pred_hansen_2010') + +minObservations = 4 +chiSquareProbability = 0.97 +training = samples +forestValue = 1 +startYear = 1990 +endYear = 2020 +classBands = ['NDFI', 'GV', 'Shade', 'NPV', 'Soil'] +prepTraining = False + +#---------------- CODED parameters +codedParams = { + 'minObservations': minObservations, + 'chiSquareProbability': chiSquareProbability, + 'training': training, + 'studyArea': studyArea, + forestValue: forestValue, + forestMask: forestMask, + 'classBands': classBands, + 'collection': landsat, + 'startYear': startYear, + 'endYear': endYear, + 'prepTraining': prepTraining +} + +# -------------- Run CODED +results = api.ChangeDetection.coded(codedParams) +print(results) + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34e Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34e Checkpoint.ipynb new file mode 100644 index 0000000..36c63da --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34e Checkpoint.ipynb @@ -0,0 +1,216 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.4 Forest Degradation and Deforestation\n", + "# Checkpoint: A34e\n", + "# Author: Carlos Souza Jr., Karis Tenneson, John Dilger,\n", + "# Crystal Wespestad, Eric Bullock\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "api = require('users/bullocke/coded:CODED/api')\n", + "utils = require('projects/GLANCE:ccdcUtilities/api')\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "# We will use the geometry of the image from the previous section as\n", + "# the study area.\n", + "studyArea = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') \\\n", + " .geometry()\n", + "\n", + "# Get cloud masked (Fmask) Landsat imagery.\n", + "landsat = utils.Inputs.getLandsat() \\\n", + " .filterBounds(studyArea) \\\n", + " .filterDate('1984-01-01', '2021-01-01')\n", + "\n", + "# Make a forest mask\n", + "gfwImage = ee.Image('UMD/hansen/global_forest_change_2019_v1_7')\n", + "\n", + "# Get areas of forest cover above the threshold\n", + "treeCover = 40\n", + "forestMask = gfwImage.select('treecover2000') \\\n", + " .gte(treeCover) \\\n", + " .rename('landcover')\n", + "\n", + "samples = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-4/sample_with_pred_hansen_2010')\n", + "\n", + "minObservations = 4\n", + "chiSquareProbability = 0.97\n", + "training = samples\n", + "forestValue = 1\n", + "startYear = 1990\n", + "endYear = 2020\n", + "classBands = ['NDFI', 'GV', 'Shade', 'NPV', 'Soil']\n", + "prepTraining = False\n", + "\n", + "#---------------- CODED parameters\n", + "codedParams = {\n", + " 'minObservations': minObservations,\n", + " 'chiSquareProbability': chiSquareProbability,\n", + " 'training': training,\n", + " 'studyArea': studyArea,\n", + " forestValue: forestValue,\n", + " forestMask: forestMask,\n", + " 'classBands': classBands,\n", + " 'collection': landsat,\n", + " 'startYear': startYear,\n", + " 'endYear': endYear,\n", + " 'prepTraining': prepTraining\n", + "}\n", + "\n", + "# -------------- Run CODED\n", + "results = api.ChangeDetection.coded(codedParams)\n", + "print(results)\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "# Format the results for exporting.\n", + "degradation = results.Layers.DatesOfDegradation \\\n", + " .rename(['degradation_1', 'degradation_2',\n", + " 'degradation_3', 'degradation_4'\n", + " ])\n", + "deforestation = results.Layers.DatesOfDeforestation \\\n", + " .rename(['deforestation_1', 'deforestation_2',\n", + " 'deforestation_3', 'deforestation_4'\n", + " ])\n", + "mask = results.Layers.mask.rename('mask')\n", + "change = ee.Image.cat([degradation, deforestation]).selfMask() \\\n", + " .toInt32()\n", + "mag = results.Layers.magnitude.reduce(ee.Reducer.min()) \\\n", + " .rename('magnitude')\n", + "\n", + "def makeStrata(img, magThreshold):\n", + " strata = img.select('mask').remap([0, 1], [2, 1])\n", + " mag = img.select('magnitude').lte(magThreshold)\n", + "\n", + " deg = img.select(['deg.*']).gt(0).reduce(ee.Reducer.max()) \\\n", + " .multiply(mag)\n", + " def = img.select(['def.*']).gt(0).reduce(ee.Reducer.max()) \\\n", + " .multiply(mag)\n", + " strata = strata.where(deg, 3).where(def, 4)\n", + "\n", + " return strata.clip(studyArea)\n", + "\n", + "\n", + "fullOutput = ee.Image.cat([mask, change, mag])\n", + "magnitudeThresh = -0.6\n", + "strata = makeStrata(ee.Image(fullOutput), magnitudeThresh) \\\n", + " .rename('strata')\n", + "\n", + "Export.image.toAsset({\n", + " 'image': strata,\n", + " 'description': 'strata',\n", + " 'region': studyArea,\n", + " 'scale': 30,\n", + " 'maxPixels': 1e13,\n", + "})\n", + "\n", + "exportedStrata = ee.Image('projects/gee-book/assets/A3-4/strata')\n", + "Map.addLayer(exportedStrata,\n", + " {\n", + " 'min': 1,\n", + " 'max': 4,\n", + " 'palette': 'green,black,yellow,red'\n", + " },\n", + " 'strata')\n", + "Map.setCenter(-55.0828, -11.24, 11)\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34e Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34e Checkpoint.js new file mode 100644 index 0000000..4920b11 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34e Checkpoint.js @@ -0,0 +1,123 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.4 Forest Degradation and Deforestation +// Checkpoint: A34e +// Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +// Crystal Wespestad, Eric Bullock +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var api = require('users/bullocke/coded:CODED/api'); +var utils = require('projects/GLANCE:ccdcUtilities/api'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +// We will use the geometry of the image from the previous section as +// the study area. +var studyArea = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') + .geometry(); + +// Get cloud masked (Fmask) Landsat imagery. +var landsat = utils.Inputs.getLandsat() + .filterBounds(studyArea) + .filterDate('1984-01-01', '2021-01-01'); + +// Make a forest mask +var gfwImage = ee.Image('UMD/hansen/global_forest_change_2019_v1_7'); + +// Get areas of forest cover above the threshold +var treeCover = 40; +var forestMask = gfwImage.select('treecover2000') + .gte(treeCover) + .rename('landcover'); + +var samples = ee.FeatureCollection( + 'projects/gee-book/assets/A3-4/sample_with_pred_hansen_2010'); + +var minObservations = 4; +var chiSquareProbability = 0.97; +var training = samples; +var forestValue = 1; +var startYear = 1990; +var endYear = 2020; +var classBands = ['NDFI', 'GV', 'Shade', 'NPV', 'Soil']; +var prepTraining = false; + +//---------------- CODED parameters +var codedParams = { + minObservations: minObservations, + chiSquareProbability: chiSquareProbability, + training: training, + studyArea: studyArea, + forestValue: forestValue, + forestMask: forestMask, + classBands: classBands, + collection: landsat, + startYear: startYear, + endYear: endYear, + prepTraining: prepTraining +}; + +// -------------- Run CODED +var results = api.ChangeDetection.coded(codedParams); +print(results); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +// Format the results for exporting. +var degradation = results.Layers.DatesOfDegradation + .rename(['degradation_1', 'degradation_2', + 'degradation_3', 'degradation_4' + ]); +var deforestation = results.Layers.DatesOfDeforestation + .rename(['deforestation_1', 'deforestation_2', + 'deforestation_3', 'deforestation_4' + ]); +var mask = results.Layers.mask.rename('mask'); +var change = ee.Image.cat([degradation, deforestation]).selfMask() + .toInt32(); +var mag = results.Layers.magnitude.reduce(ee.Reducer.min()) + .rename('magnitude'); + +var makeStrata = function(img, magThreshold) { + var strata = img.select('mask').remap([0, 1], [2, 1]); + var mag = img.select('magnitude').lte(magThreshold); + + var deg = img.select(['deg.*']).gt(0).reduce(ee.Reducer.max()) + .multiply(mag); + var def = img.select(['def.*']).gt(0).reduce(ee.Reducer.max()) + .multiply(mag); + strata = strata.where(deg, 3).where(def, 4); + + return strata.clip(studyArea); +}; + +var fullOutput = ee.Image.cat([mask, change, mag]); +var magnitudeThresh = -0.6; +var strata = makeStrata(ee.Image(fullOutput), magnitudeThresh) + .rename('strata'); + +Export.image.toAsset({ + image: strata, + description: 'strata', + region: studyArea, + scale: 30, + maxPixels: 1e13, +}); + +var exportedStrata = ee.Image('projects/gee-book/assets/A3-4/strata'); +Map.addLayer(exportedStrata, + { + min: 1, + max: 4, + palette: 'green,black,yellow,red' + }, + 'strata'); +Map.setCenter(-55.0828, -11.24, 11); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34e Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34e Checkpoint.py new file mode 100644 index 0000000..c175193 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/A34e Checkpoint.py @@ -0,0 +1,129 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.4 Forest Degradation and Deforestation +# Checkpoint: A34e +# Author: Carlos Souza Jr., Karis Tenneson, John Dilger, +# Crystal Wespestad, Eric Bullock +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +api = require('users/bullocke/coded:CODED/api') +utils = require('projects/GLANCE:ccdcUtilities/api') + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +# We will use the geometry of the image from the previous section as +# the study area. +studyArea = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_226068_19840411') \ + .geometry() + +# Get cloud masked (Fmask) Landsat imagery. +landsat = utils.Inputs.getLandsat() \ + .filterBounds(studyArea) \ + .filterDate('1984-01-01', '2021-01-01') + +# Make a forest mask +gfwImage = ee.Image('UMD/hansen/global_forest_change_2019_v1_7') + +# Get areas of forest cover above the threshold +treeCover = 40 +forestMask = gfwImage.select('treecover2000') \ + .gte(treeCover) \ + .rename('landcover') + +samples = ee.FeatureCollection( + 'projects/gee-book/assets/A3-4/sample_with_pred_hansen_2010') + +minObservations = 4 +chiSquareProbability = 0.97 +training = samples +forestValue = 1 +startYear = 1990 +endYear = 2020 +classBands = ['NDFI', 'GV', 'Shade', 'NPV', 'Soil'] +prepTraining = False + +#---------------- CODED parameters +codedParams = { + 'minObservations': minObservations, + 'chiSquareProbability': chiSquareProbability, + 'training': training, + 'studyArea': studyArea, + forestValue: forestValue, + forestMask: forestMask, + 'classBands': classBands, + 'collection': landsat, + 'startYear': startYear, + 'endYear': endYear, + 'prepTraining': prepTraining +} + +# -------------- Run CODED +results = api.ChangeDetection.coded(codedParams) +print(results) + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +# Format the results for exporting. +degradation = results.Layers.DatesOfDegradation \ + .rename(['degradation_1', 'degradation_2', + 'degradation_3', 'degradation_4' + ]) +deforestation = results.Layers.DatesOfDeforestation \ + .rename(['deforestation_1', 'deforestation_2', + 'deforestation_3', 'deforestation_4' + ]) +mask = results.Layers.mask.rename('mask') +change = ee.Image.cat([degradation, deforestation]).selfMask() \ + .toInt32() +mag = results.Layers.magnitude.reduce(ee.Reducer.min()) \ + .rename('magnitude') + +def makeStrata(img, magThreshold): + strata = img.select('mask').remap([0, 1], [2, 1]) + mag = img.select('magnitude').lte(magThreshold) + + deg = img.select(['deg.*']).gt(0).reduce(ee.Reducer.max()) \ + .multiply(mag) + def = img.select(['def.*']).gt(0).reduce(ee.Reducer.max()) \ + .multiply(mag) + strata = strata.where(deg, 3).where(def, 4) + + return strata.clip(studyArea) + + +fullOutput = ee.Image.cat([mask, change, mag]) +magnitudeThresh = -0.6 +strata = makeStrata(ee.Image(fullOutput), magnitudeThresh) \ + .rename('strata') + +Export.image.toAsset({ + 'image': strata, + 'description': 'strata', + 'region': studyArea, + 'scale': 30, + 'maxPixels': 1e13, +}) + +exportedStrata = ee.Image('projects/gee-book/assets/A3-4/strata') +Map.addLayer(exportedStrata, + { + 'min': 1, + 'max': 4, + 'palette': 'green,black,yellow,red' + }, + 'strata') +Map.setCenter(-55.0828, -11.24, 11) + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes.ipynb new file mode 100644 index 0000000..9287988 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes.ipynb @@ -0,0 +1,117 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "ndfiColors =\n", + " 'FFFFFF,FFFCFF,FFF9FF,FFF7FF,FFF4FF,FFF2FF,FFEFFF,FFECFF,FFEAFF,FFE7FF,'+ \\\n", + " 'FFE5FF,FFE2FF,FFE0FF,FFDDFF,FFDAFF,FFD8FF,FFD5FF,FFD3FF,FFD0FF,FFCEFF,'+ \\\n", + " 'FFCBFF,FFC8FF,FFC6FF,FFC3FF,FFC1FF,FFBEFF,FFBCFF,FFB9FF,FFB6FF,FFB4FF,'+ \\\n", + " 'FFB1FF,FFAFFF,FFACFF,FFAAFF,FFA7FF,FFA4FF,FFA2FF,FF9FFF,FF9DFF,FF9AFF,'+ \\\n", + " 'FF97FF,FF95FF,FF92FF,FF90FF,FF8DFF,FF8BFF,FF88FF,FF85FF,FF83FF,FF80FF,'+ \\\n", + " 'FF7EFF,FF7BFF,FF79FF,FF76FF,FF73FF,FF71FF,FF6EFF,FF6CFF,FF69FF,FF67FF,'+ \\\n", + " 'FF64FF,FF61FF,FF5FFF,FF5CFF,FF5AFF,FF57FF,FF55FF,FF52FF,FF4FFF,FF4DFF,'+ \\\n", + " 'FF4AFF,FF48FF,FF45FF,FF42FF,FF40FF,FF3DFF,FF3BFF,FF38FF,FF36FF,FF33FF,'+ \\\n", + " 'FF30FF,FF2EFF,FF2BFF,FF29FF,FF26FF,FF24FF,FF21FF,FF1EFF,FF1CFF,FF19FF,'+ \\\n", + " 'FF17FF,FF14FF,FF12FF,FF0FFF,FF0CFF,FF0AFF,FF07FF,FF05FF,FF02FF,FF00FF,'+ \\\n", + " 'FF00FF,FF0AF4,FF15E9,FF1FDF,FF2AD4,FF35C9,FF3FBF,FF4AB4,FF55AA,FF5F9F,'+ \\\n", + " 'FF6A94,FF748A,FF7F7F,FF8A74,FF946A,FF9F5F,FFAA55,FFB44A,FFBF3F,FFC935,'+ \\\n", + " 'FFD42A,FFDF1F,FFE915,FFF40A,FFFF00,FFFF00,FFFB00,FFF700,FFF300,FFF000,'+ \\\n", + " 'FFEC00,FFE800,FFE400,FFE100,FFDD00,FFD900,FFD500,FFD200,FFCE00,FFCA00,'+ \\\n", + " 'FFC600,FFC300,FFBF00,FFBB00,FFB700,FFB400,FFB000,FFAC00,FFA800,FFA500,'+ \\\n", + " 'FFA500,F7A400,F0A300,E8A200,E1A200,D9A100,D2A000,CA9F00,C39F00,BB9E00,'+ \\\n", + " 'B49D00,AC9C00,A59C00,9D9B00,969A00,8E9900,879900,7F9800,789700,709700,'+ \\\n", + " '699600,619500,5A9400,529400,4B9300,439200,349100,2D9000,258F00,1E8E00,'+ \\\n", + " '168E00,0F8D00,078C00,008C00,008C00,008700,008300,007F00,007A00,007600,'+ \\\n", + " '007200,006E00,006900,006500,006100,005C00,005800,005400,005000,004C00'\n", + "exports = {\n", + " 'ndfiColors' : ndfiColors\n", + "}" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes.js new file mode 100644 index 0000000..206fa41 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes.js @@ -0,0 +1,24 @@ +var ndfiColors = + 'FFFFFF,FFFCFF,FFF9FF,FFF7FF,FFF4FF,FFF2FF,FFEFFF,FFECFF,FFEAFF,FFE7FF,'+ + 'FFE5FF,FFE2FF,FFE0FF,FFDDFF,FFDAFF,FFD8FF,FFD5FF,FFD3FF,FFD0FF,FFCEFF,'+ + 'FFCBFF,FFC8FF,FFC6FF,FFC3FF,FFC1FF,FFBEFF,FFBCFF,FFB9FF,FFB6FF,FFB4FF,'+ + 'FFB1FF,FFAFFF,FFACFF,FFAAFF,FFA7FF,FFA4FF,FFA2FF,FF9FFF,FF9DFF,FF9AFF,'+ + 'FF97FF,FF95FF,FF92FF,FF90FF,FF8DFF,FF8BFF,FF88FF,FF85FF,FF83FF,FF80FF,'+ + 'FF7EFF,FF7BFF,FF79FF,FF76FF,FF73FF,FF71FF,FF6EFF,FF6CFF,FF69FF,FF67FF,'+ + 'FF64FF,FF61FF,FF5FFF,FF5CFF,FF5AFF,FF57FF,FF55FF,FF52FF,FF4FFF,FF4DFF,'+ + 'FF4AFF,FF48FF,FF45FF,FF42FF,FF40FF,FF3DFF,FF3BFF,FF38FF,FF36FF,FF33FF,'+ + 'FF30FF,FF2EFF,FF2BFF,FF29FF,FF26FF,FF24FF,FF21FF,FF1EFF,FF1CFF,FF19FF,'+ + 'FF17FF,FF14FF,FF12FF,FF0FFF,FF0CFF,FF0AFF,FF07FF,FF05FF,FF02FF,FF00FF,'+ + 'FF00FF,FF0AF4,FF15E9,FF1FDF,FF2AD4,FF35C9,FF3FBF,FF4AB4,FF55AA,FF5F9F,'+ + 'FF6A94,FF748A,FF7F7F,FF8A74,FF946A,FF9F5F,FFAA55,FFB44A,FFBF3F,FFC935,'+ + 'FFD42A,FFDF1F,FFE915,FFF40A,FFFF00,FFFF00,FFFB00,FFF700,FFF300,FFF000,'+ + 'FFEC00,FFE800,FFE400,FFE100,FFDD00,FFD900,FFD500,FFD200,FFCE00,FFCA00,'+ + 'FFC600,FFC300,FFBF00,FFBB00,FFB700,FFB400,FFB000,FFAC00,FFA800,FFA500,'+ + 'FFA500,F7A400,F0A300,E8A200,E1A200,D9A100,D2A000,CA9F00,C39F00,BB9E00,'+ + 'B49D00,AC9C00,A59C00,9D9B00,969A00,8E9900,879900,7F9800,789700,709700,'+ + '699600,619500,5A9400,529400,4B9300,439200,349100,2D9000,258F00,1E8E00,'+ + '168E00,0F8D00,078C00,008C00,008C00,008700,008300,007F00,007A00,007600,'+ + '007200,006E00,006900,006500,006100,005C00,005800,005400,005000,004C00'; +exports = { + ndfiColors : ndfiColors +}; \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes.py new file mode 100644 index 0000000..4fd4b81 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.4 Forest Degradation and Deforestation/modules/palettes.py @@ -0,0 +1,30 @@ +import ee +import geemap + +Map = geemap.Map() + +ndfiColors = + 'FFFFFF,FFFCFF,FFF9FF,FFF7FF,FFF4FF,FFF2FF,FFEFFF,FFECFF,FFEAFF,FFE7FF,'+ \ + 'FFE5FF,FFE2FF,FFE0FF,FFDDFF,FFDAFF,FFD8FF,FFD5FF,FFD3FF,FFD0FF,FFCEFF,'+ \ + 'FFCBFF,FFC8FF,FFC6FF,FFC3FF,FFC1FF,FFBEFF,FFBCFF,FFB9FF,FFB6FF,FFB4FF,'+ \ + 'FFB1FF,FFAFFF,FFACFF,FFAAFF,FFA7FF,FFA4FF,FFA2FF,FF9FFF,FF9DFF,FF9AFF,'+ \ + 'FF97FF,FF95FF,FF92FF,FF90FF,FF8DFF,FF8BFF,FF88FF,FF85FF,FF83FF,FF80FF,'+ \ + 'FF7EFF,FF7BFF,FF79FF,FF76FF,FF73FF,FF71FF,FF6EFF,FF6CFF,FF69FF,FF67FF,'+ \ + 'FF64FF,FF61FF,FF5FFF,FF5CFF,FF5AFF,FF57FF,FF55FF,FF52FF,FF4FFF,FF4DFF,'+ \ + 'FF4AFF,FF48FF,FF45FF,FF42FF,FF40FF,FF3DFF,FF3BFF,FF38FF,FF36FF,FF33FF,'+ \ + 'FF30FF,FF2EFF,FF2BFF,FF29FF,FF26FF,FF24FF,FF21FF,FF1EFF,FF1CFF,FF19FF,'+ \ + 'FF17FF,FF14FF,FF12FF,FF0FFF,FF0CFF,FF0AFF,FF07FF,FF05FF,FF02FF,FF00FF,'+ \ + 'FF00FF,FF0AF4,FF15E9,FF1FDF,FF2AD4,FF35C9,FF3FBF,FF4AB4,FF55AA,FF5F9F,'+ \ + 'FF6A94,FF748A,FF7F7F,FF8A74,FF946A,FF9F5F,FFAA55,FFB44A,FFBF3F,FFC935,'+ \ + 'FFD42A,FFDF1F,FFE915,FFF40A,FFFF00,FFFF00,FFFB00,FFF700,FFF300,FFF000,'+ \ + 'FFEC00,FFE800,FFE400,FFE100,FFDD00,FFD900,FFD500,FFD200,FFCE00,FFCA00,'+ \ + 'FFC600,FFC300,FFBF00,FFBB00,FFB700,FFB400,FFB000,FFAC00,FFA800,FFA500,'+ \ + 'FFA500,F7A400,F0A300,E8A200,E1A200,D9A100,D2A000,CA9F00,C39F00,BB9E00,'+ \ + 'B49D00,AC9C00,A59C00,9D9B00,969A00,8E9900,879900,7F9800,789700,709700,'+ \ + '699600,619500,5A9400,529400,4B9300,439200,349100,2D9000,258F00,1E8E00,'+ \ + '168E00,0F8D00,078C00,008C00,008C00,008700,008300,007F00,007A00,007600,'+ \ + '007200,006E00,006900,006500,006100,005C00,005800,005400,005000,004C00' +exports = { + 'ndfiColors' : ndfiColors +} +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35a Checkpoint.ipynb new file mode 100644 index 0000000..da5861c --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35a Checkpoint.ipynb @@ -0,0 +1,107 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.5 Deforestation Viewed from Multiple Sensors\n", + "# Checkpoint: A35a\n", + "# Author: Xiaojing Tang\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Fusion Near Real-time (GUI)\n", + "# Near real-time monitoring of forest disturbance by fusion of\n", + "# multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu).\n", + "\n", + "# To run this interface, please access it by entering the link\n", + "# below in a separate browser window.\n", + "\n", + "'https':#gee-book.earthengine.app/view/fnrt" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35a Checkpoint.js new file mode 100644 index 0000000..cf73c9d --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35a Checkpoint.js @@ -0,0 +1,14 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.5 Deforestation Viewed from Multiple Sensors +// Checkpoint: A35a +// Author: Xiaojing Tang +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Fusion Near Real-time (GUI) +// Near real-time monitoring of forest disturbance by fusion of +// multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu). + +// To run this interface, please access it by entering the link +// below in a separate browser window. + +https://gee-book.earthengine.app/view/fnrt diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35a Checkpoint.py new file mode 100644 index 0000000..86202f7 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35a Checkpoint.py @@ -0,0 +1,20 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.5 Deforestation Viewed from Multiple Sensors +# Checkpoint: A35a +# Author: Xiaojing Tang +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Fusion Near Real-time (GUI) +# Near real-time monitoring of forest disturbance by fusion of +# multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu). + +# To run this interface, please access it by entering the link +# below in a separate browser window. + +'https':#gee-book.earthengine.app/view/fnrt +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35b Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35b Checkpoint.ipynb new file mode 100644 index 0000000..d8ff0e4 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35b Checkpoint.ipynb @@ -0,0 +1,148 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.5 Deforestation Viewed from Multiple Sensors\n", + "# Checkpoint: A35b\n", + "# Author: Xiaojing Tang\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "testArea = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-66.73156878460787, -8.662236005089952],\n", + " [-66.73156878460787, -8.916025640576244],\n", + " [-66.44867083538912, -8.916025640576244],\n", + " [-66.44867083538912, -8.662236005089952]\n", + " ]\n", + " ])\n", + "\n", + "Map.centerObject(testArea)\n", + "\n", + "# Start and end of the training and monitoring period.\n", + "trainPeriod = ee.Dictionary({\n", + " 'start': '2017-01-01',\n", + " 'end': '2020-01-01'\n", + "})\n", + "monitorPeriod = ee.Dictionary({\n", + " 'start': '2020-01-01',\n", + " 'end': '2021-01-01'\n", + "})\n", + "\n", + "# Near-real-time monitoring parameters.\n", + "nrtParam = {\n", + " 'z': 2,\n", + " 'm': 5,\n", + " 'n': 4\n", + "}\n", + "\n", + "# Sensor specific parameters.\n", + "lstParam = {\n", + " 'band': 'NDFI',\n", + " 'minRMSE': 0.05,\n", + " 'strikeOnly': False\n", + "}\n", + "s2Param = {\n", + " 'band': 'NDFI',\n", + " 'minRMSE': 0.05,\n", + " 'strikeOnly': False\n", + "}\n", + "s1Param = {\n", + " 'band': 'VV',\n", + " 'minRMSE': 0.01,\n", + " 'strikeOnly': True\n", + "}\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35b Checkpoint.js new file mode 100644 index 0000000..d4ec1fa --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35b Checkpoint.js @@ -0,0 +1,55 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.5 Deforestation Viewed from Multiple Sensors +// Checkpoint: A35b +// Author: Xiaojing Tang +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]); + +Map.centerObject(testArea); + +// Start and end of the training and monitoring period. +var trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}); +var monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}); + +// Near-real-time monitoring parameters. +var nrtParam = { + z: 2, + m: 5, + n: 4 +}; + +// Sensor specific parameters. +var lstParam = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s2Param = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s1Param = { + band: 'VV', + minRMSE: 0.01, + strikeOnly: true +}; + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35b Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35b Checkpoint.py new file mode 100644 index 0000000..8aed5e4 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35b Checkpoint.py @@ -0,0 +1,61 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.5 Deforestation Viewed from Multiple Sensors +# Checkpoint: A35b +# Author: Xiaojing Tang +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]) + +Map.centerObject(testArea) + +# Start and end of the training and monitoring period. +trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}) +monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}) + +# Near-real-time monitoring parameters. +nrtParam = { + 'z': 2, + 'm': 5, + 'n': 4 +} + +# Sensor specific parameters. +lstParam = { + 'band': 'NDFI', + 'minRMSE': 0.05, + 'strikeOnly': False +} +s2Param = { + 'band': 'NDFI', + 'minRMSE': 0.05, + 'strikeOnly': False +} +s1Param = { + 'band': 'VV', + 'minRMSE': 0.01, + 'strikeOnly': True +} + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35c Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35c Checkpoint.ipynb new file mode 100644 index 0000000..e264017 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35c Checkpoint.ipynb @@ -0,0 +1,297 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.5 Deforestation Viewed from Multiple Sensors\n", + "# Checkpoint: A35c\n", + "# Author: Xiaojing Tang\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "testArea = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-66.73156878460787, -8.662236005089952],\n", + " [-66.73156878460787, -8.916025640576244],\n", + " [-66.44867083538912, -8.916025640576244],\n", + " [-66.44867083538912, -8.662236005089952]\n", + " ]\n", + " ])\n", + "\n", + "Map.centerObject(testArea)\n", + "\n", + "# Start and end of the training and monitoring period.\n", + "trainPeriod = ee.Dictionary({\n", + " 'start': '2017-01-01',\n", + " 'end': '2020-01-01'\n", + "})\n", + "monitorPeriod = ee.Dictionary({\n", + " 'start': '2020-01-01',\n", + " 'end': '2021-01-01'\n", + "})\n", + "\n", + "# Near-real-time monitoring parameters.\n", + "nrtParam = {\n", + " 'z': 2,\n", + " 'm': 5,\n", + " 'n': 4\n", + "}\n", + "\n", + "# Sensor specific parameters.\n", + "lstParam = {\n", + " 'band': 'NDFI',\n", + " 'minRMSE': 0.05,\n", + " 'strikeOnly': False\n", + "}\n", + "s2Param = {\n", + " 'band': 'NDFI',\n", + " 'minRMSE': 0.05,\n", + " 'strikeOnly': False\n", + "}\n", + "s1Param = {\n", + " 'band': 'VV',\n", + " 'minRMSE': 0.01,\n", + " 'strikeOnly': True\n", + "}\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "def unmixing(col):\n", + "\n", + " # Define endmembers and cloud fraction threshold.\n", + " gv = [500, 900, 400, 6100, 3000, 1000]\n", + " npv = [1400, 1700, 2200, 3000, 5500, 3000]\n", + " soil = [2000, 3000, 3400, 5800, 6000, 5800]\n", + " shade = [0, 0, 0, 0, 0, 0]\n", + " cloud = [9000, 9600, 8000, 7800, 7200, 6500]\n", + " cfThreshold = 0.05\n", + "\n", + "\n", + "def func_kvp(img):\n", + " # Select the spectral bands and perform unmixing\n", + " unmixed = img.select(['Blue', 'Green', 'Red',\n", + " 'NIR',\n", + " 'SWIR1', 'SWIR2'\n", + " ]) \\\n", + " .unmix([gv, shade, npv, soil, cloud], True,\n", + " True) \\\n", + " .rename(['GV', 'Shade', 'NPV', 'Soil',\n", + " 'Cloud'\n", + " ])\n", + "\n", + " # Calculate Normalized Difference Fraction Index.+ \\\n", + " NDFI = unmixed.expression(\n", + " '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + \\\n", + " '((GV / (1 - SHADE)) + (NPV + SOIL))', {\n", + " 'GV': unmixed.select('GV'),\n", + " 'SHADE': unmixed.select('Shade'),\n", + " 'NPV': unmixed.select('NPV'),\n", + " 'SOIL': unmixed.select('Soil')\n", + " }).rename('NDFI')\n", + "\n", + " # Mask cloudy pixel.\n", + " maskCloud = unmixed.select('Cloud').lt(\n", + " cfThreshold)\n", + " # Mask all shade pixel.\n", + " maskShade = unmixed.select('Shade').lt(1)\n", + " # Mask pixel where NDFI cannot be calculated.\n", + " maskNDFI = unmixed.expression(\n", + " '(GV / (1 - SHADE)) + (NPV + SOIL)', {\n", + " 'GV': unmixed.select('GV'),\n", + " 'SHADE': unmixed.select('Shade'),\n", + " 'NPV': unmixed.select('NPV'),\n", + " 'SOIL': unmixed.select('Soil')\n", + " }).gt(0)\n", + "\n", + " # Scale fractions to 0-10000 and apply masks.\n", + " return img \\\n", + " .addBands(unmixed.select(['GV', 'Shade',\n", + " 'NPV', 'Soil'\n", + " ]) \\\n", + " .multiply(10000)) \\\n", + " .addBands(NDFI) \\\n", + " .updateMask(maskCloud) \\\n", + " .updateMask(maskNDFI) \\\n", + " .updateMask(maskShade)\n", + "\n", + " return col.map(func_kvp)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs'\n", + ")\n", + "lstTraining = unmixing(input.loadLandsatData(testArea,\n", + " trainPeriod))\n", + "lstMonitoring = unmixing(input.loadLandsatData(testArea,\n", + " monitorPeriod))\n", + "s2Training = unmixing(input.loadS2Data(testArea, trainPeriod))\n", + "s2Monitoring = unmixing(input.loadS2Data(testArea,\n", + " monitorPeriod))\n", + "s1Training = input.loadS1Data(testArea, trainPeriod)\n", + "s1Monitoring = input.loadS1Data(testArea, monitorPeriod)\n", + "\n", + "hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') \\\n", + " .unmask()\n", + "forestMask = hansen.select('treecover2000') \\\n", + " .gt(50) \\\n", + " .add(hansen.select('gain')) \\\n", + " .subtract(hansen.select('loss')) \\\n", + " .add(hansen.select('lossyear') \\\n", + " .eq(20)) \\\n", + " .gt(0) \\\n", + " .clip(testArea)\n", + "\n", + "maskVis = {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'green']\n", + "}\n", + "Map.addLayer(forestMask, maskVis, 'Forest Mask')\n", + "print('lstTraining', lstTraining)\n", + "print('lstMonitoring', lstMonitoring)\n", + "print('s2Training', s2Training)\n", + "print('s2Monitoring', s2Monitoring)\n", + "print('s1Training', s1Training)\n", + "print('s1Monitoring', s1Monitoring)\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35c Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35c Checkpoint.js new file mode 100644 index 0000000..825d22e --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35c Checkpoint.js @@ -0,0 +1,156 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.5 Deforestation Viewed from Multiple Sensors +// Checkpoint: A35c +// Author: Xiaojing Tang +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]); + +Map.centerObject(testArea); + +// Start and end of the training and monitoring period. +var trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}); +var monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}); + +// Near-real-time monitoring parameters. +var nrtParam = { + z: 2, + m: 5, + n: 4 +}; + +// Sensor specific parameters. +var lstParam = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s2Param = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s1Param = { + band: 'VV', + minRMSE: 0.01, + strikeOnly: true +}; + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var unmixing = function(col) { + + // Define endmembers and cloud fraction threshold. + var gv = [500, 900, 400, 6100, 3000, 1000]; + var npv = [1400, 1700, 2200, 3000, 5500, 3000]; + var soil = [2000, 3000, 3400, 5800, 6000, 5800]; + var shade = [0, 0, 0, 0, 0, 0]; + var cloud = [9000, 9600, 8000, 7800, 7200, 6500]; + var cfThreshold = 0.05; + + return col.map(function(img) { + // Select the spectral bands and perform unmixing + var unmixed = img.select(['Blue', 'Green', 'Red', + 'NIR', + 'SWIR1', 'SWIR2' + ]) + .unmix([gv, shade, npv, soil, cloud], true, + true) + .rename(['GV', 'Shade', 'NPV', 'Soil', + 'Cloud' + ]); + + // Calculate Normalized Difference Fraction Index.+ + var NDFI = unmixed.expression( + '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + + '((GV / (1 - SHADE)) + (NPV + SOIL))', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).rename('NDFI'); + + // Mask cloudy pixel. + var maskCloud = unmixed.select('Cloud').lt( + cfThreshold); + // Mask all shade pixel. + var maskShade = unmixed.select('Shade').lt(1); + // Mask pixel where NDFI cannot be calculated. + var maskNDFI = unmixed.expression( + '(GV / (1 - SHADE)) + (NPV + SOIL)', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).gt(0); + + // Scale fractions to 0-10000 and apply masks. + return img + .addBands(unmixed.select(['GV', 'Shade', + 'NPV', 'Soil' + ]) + .multiply(10000)) + .addBands(NDFI) + .updateMask(maskCloud) + .updateMask(maskNDFI) + .updateMask(maskShade); + }); +}; + +var input = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs' +); +var lstTraining = unmixing(input.loadLandsatData(testArea, + trainPeriod)); +var lstMonitoring = unmixing(input.loadLandsatData(testArea, + monitorPeriod)); +var s2Training = unmixing(input.loadS2Data(testArea, trainPeriod)); +var s2Monitoring = unmixing(input.loadS2Data(testArea, + monitorPeriod)); +var s1Training = input.loadS1Data(testArea, trainPeriod); +var s1Monitoring = input.loadS1Data(testArea, monitorPeriod); + +var hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') + .unmask(); +var forestMask = hansen.select('treecover2000') + .gt(50) + .add(hansen.select('gain')) + .subtract(hansen.select('loss')) + .add(hansen.select('lossyear') + .eq(20)) + .gt(0) + .clip(testArea); + +var maskVis = { + min: 0, + max: 1, + palette: ['blue', 'green'] +}; +Map.addLayer(forestMask, maskVis, 'Forest Mask'); +print('lstTraining', lstTraining); +print('lstMonitoring', lstMonitoring); +print('s2Training', s2Training); +print('s2Monitoring', s2Monitoring); +print('s1Training', s1Training); +print('s1Monitoring', s1Monitoring); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35c Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35c Checkpoint.py new file mode 100644 index 0000000..2dbe76d --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35c Checkpoint.py @@ -0,0 +1,211 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.5 Deforestation Viewed from Multiple Sensors +# Checkpoint: A35c +# Author: Xiaojing Tang +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]) + +Map.centerObject(testArea) + +# Start and end of the training and monitoring period. +trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}) +monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}) + +# Near-real-time monitoring parameters. +nrtParam = { + 'z': 2, + 'm': 5, + 'n': 4 +} + +# Sensor specific parameters. +lstParam = { + 'band': 'NDFI', + 'minRMSE': 0.05, + 'strikeOnly': False +} +s2Param = { + 'band': 'NDFI', + 'minRMSE': 0.05, + 'strikeOnly': False +} +s1Param = { + 'band': 'VV', + 'minRMSE': 0.01, + 'strikeOnly': True +} + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +def unmixing(col): + + # Define endmembers and cloud fraction threshold. + gv = [500, 900, 400, 6100, 3000, 1000] + npv = [1400, 1700, 2200, 3000, 5500, 3000] + soil = [2000, 3000, 3400, 5800, 6000, 5800] + shade = [0, 0, 0, 0, 0, 0] + cloud = [9000, 9600, 8000, 7800, 7200, 6500] + cfThreshold = 0.05 + + +def func_kvp(img): + # Select the spectral bands and perform unmixing + unmixed = img.select(['Blue', 'Green', 'Red', + 'NIR', + 'SWIR1', 'SWIR2' + ]) \ + .unmix([gv, shade, npv, soil, cloud], True, + True) \ + .rename(['GV', 'Shade', 'NPV', 'Soil', + 'Cloud' + ]) + + # Calculate Normalized Difference Fraction Index.+ \ + NDFI = unmixed.expression( + '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + \ + '((GV / (1 - SHADE)) + (NPV + SOIL))', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).rename('NDFI') + + # Mask cloudy pixel. + maskCloud = unmixed.select('Cloud').lt( + cfThreshold) + # Mask all shade pixel. + maskShade = unmixed.select('Shade').lt(1) + # Mask pixel where NDFI cannot be calculated. + maskNDFI = unmixed.expression( + '(GV / (1 - SHADE)) + (NPV + SOIL)', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).gt(0) + + # Scale fractions to 0-10000 and apply masks. + return img \ + .addBands(unmixed.select(['GV', 'Shade', + 'NPV', 'Soil' + ]) \ + .multiply(10000)) \ + .addBands(NDFI) \ + .updateMask(maskCloud) \ + .updateMask(maskNDFI) \ + .updateMask(maskShade) + + return col.map(func_kvp) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +input = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs' +) +lstTraining = unmixing(input.loadLandsatData(testArea, + trainPeriod)) +lstMonitoring = unmixing(input.loadLandsatData(testArea, + monitorPeriod)) +s2Training = unmixing(input.loadS2Data(testArea, trainPeriod)) +s2Monitoring = unmixing(input.loadS2Data(testArea, + monitorPeriod)) +s1Training = input.loadS1Data(testArea, trainPeriod) +s1Monitoring = input.loadS1Data(testArea, monitorPeriod) + +hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') \ + .unmask() +forestMask = hansen.select('treecover2000') \ + .gt(50) \ + .add(hansen.select('gain')) \ + .subtract(hansen.select('loss')) \ + .add(hansen.select('lossyear') \ + .eq(20)) \ + .gt(0) \ + .clip(testArea) + +maskVis = { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'green'] +} +Map.addLayer(forestMask, maskVis, 'Forest Mask') +print('lstTraining', lstTraining) +print('lstMonitoring', lstMonitoring) +print('s2Training', s2Training) +print('s2Monitoring', s2Monitoring) +print('s1Training', s1Training) +print('s1Monitoring', s1Monitoring) + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35d Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35d Checkpoint.ipynb new file mode 100644 index 0000000..b4880ba --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35d Checkpoint.ipynb @@ -0,0 +1,408 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.5 Deforestation Viewed from Multiple Sensors\n", + "# Checkpoint: A35d\n", + "# Author: Xiaojing Tang\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "testArea = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-66.73156878460787, -8.662236005089952],\n", + " [-66.73156878460787, -8.916025640576244],\n", + " [-66.44867083538912, -8.916025640576244],\n", + " [-66.44867083538912, -8.662236005089952]\n", + " ]\n", + " ])\n", + "\n", + "Map.centerObject(testArea)\n", + "\n", + "# Start and end of the training and monitoring period.\n", + "trainPeriod = ee.Dictionary({\n", + " 'start': '2017-01-01',\n", + " 'end': '2020-01-01'\n", + "})\n", + "monitorPeriod = ee.Dictionary({\n", + " 'start': '2020-01-01',\n", + " 'end': '2021-01-01'\n", + "})\n", + "\n", + "# Near-real-time monitoring parameters.\n", + "nrtParam = {\n", + " 'z': 2,\n", + " 'm': 5,\n", + " 'n': 4\n", + "}\n", + "\n", + "# Sensor specific parameters.\n", + "lstParam = {\n", + " 'band': 'NDFI',\n", + " 'minRMSE': 0.05,\n", + " 'strikeOnly': False\n", + "}\n", + "s2Param = {\n", + " 'band': 'NDFI',\n", + " 'minRMSE': 0.05,\n", + " 'strikeOnly': False\n", + "}\n", + "s1Param = {\n", + " 'band': 'VV',\n", + " 'minRMSE': 0.01,\n", + " 'strikeOnly': True\n", + "}\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "def unmixing(col):\n", + "\n", + " # Define endmembers and cloud fraction threshold.\n", + " gv = [500, 900, 400, 6100, 3000, 1000]\n", + " npv = [1400, 1700, 2200, 3000, 5500, 3000]\n", + " soil = [2000, 3000, 3400, 5800, 6000, 5800]\n", + " shade = [0, 0, 0, 0, 0, 0]\n", + " cloud = [9000, 9600, 8000, 7800, 7200, 6500]\n", + " cfThreshold = 0.05\n", + "\n", + "\n", + "def func_rlc(img):\n", + " # Select the spectral bands and perform unmixing\n", + " unmixed = img.select(['Blue', 'Green', 'Red',\n", + " 'NIR',\n", + " 'SWIR1', 'SWIR2'\n", + " ]) \\\n", + " .unmix([gv, shade, npv, soil, cloud], True,\n", + " True) \\\n", + " .rename(['GV', 'Shade', 'NPV', 'Soil',\n", + " 'Cloud'\n", + " ])\n", + "\n", + " # Calculate Normalized Difference Fraction Index.+ \\\n", + " NDFI = unmixed.expression(\n", + " '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + \\\n", + " '((GV / (1 - SHADE)) + (NPV + SOIL))', {\n", + " 'GV': unmixed.select('GV'),\n", + " 'SHADE': unmixed.select('Shade'),\n", + " 'NPV': unmixed.select('NPV'),\n", + " 'SOIL': unmixed.select('Soil')\n", + " }).rename('NDFI')\n", + "\n", + " # Mask cloudy pixel.\n", + " maskCloud = unmixed.select('Cloud').lt(\n", + " cfThreshold)\n", + " # Mask all shade pixel.\n", + " maskShade = unmixed.select('Shade').lt(1)\n", + " # Mask pixel where NDFI cannot be calculated.\n", + " maskNDFI = unmixed.expression(\n", + " '(GV / (1 - SHADE)) + (NPV + SOIL)', {\n", + " 'GV': unmixed.select('GV'),\n", + " 'SHADE': unmixed.select('Shade'),\n", + " 'NPV': unmixed.select('NPV'),\n", + " 'SOIL': unmixed.select('Soil')\n", + " }).gt(0)\n", + "\n", + " # Scale fractions to 0-10000 and apply masks.\n", + " return img \\\n", + " .addBands(unmixed.select(['GV', 'Shade',\n", + " 'NPV', 'Soil'\n", + " ]) \\\n", + " .multiply(10000)) \\\n", + " .addBands(NDFI) \\\n", + " .updateMask(maskCloud) \\\n", + " .updateMask(maskNDFI) \\\n", + " .updateMask(maskShade)\n", + "\n", + " return col.map(func_rlc)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs'\n", + ")\n", + "lstTraining = unmixing(input.loadLandsatData(testArea,\n", + " trainPeriod))\n", + "lstMonitoring = unmixing(input.loadLandsatData(testArea,\n", + " monitorPeriod))\n", + "s2Training = unmixing(input.loadS2Data(testArea, trainPeriod))\n", + "s2Monitoring = unmixing(input.loadS2Data(testArea,\n", + " monitorPeriod))\n", + "s1Training = input.loadS1Data(testArea, trainPeriod)\n", + "s1Monitoring = input.loadS1Data(testArea, monitorPeriod)\n", + "\n", + "hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') \\\n", + " .unmask()\n", + "forestMask = hansen.select('treecover2000') \\\n", + " .gt(50) \\\n", + " .add(hansen.select('gain')) \\\n", + " .subtract(hansen.select('loss')) \\\n", + " .add(hansen.select('lossyear') \\\n", + " .eq(20)) \\\n", + " .gt(0) \\\n", + " .clip(testArea)\n", + "\n", + "maskVis = {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'green']\n", + "}\n", + "Map.addLayer(forestMask, maskVis, 'Forest Mask')\n", + "print('lstTraining', lstTraining)\n", + "print('lstMonitoring', lstMonitoring)\n", + "print('s2Training', s2Training)\n", + "print('s2Monitoring', s2Monitoring)\n", + "print('s1Training', s1Training)\n", + "print('s1Monitoring', s1Monitoring)\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "def toFracYear(date):\n", + " year = date.get('year')\n", + " fYear = date.difference(\n", + " ee.Date.fromYMD(year, 1, 1), 'year')\n", + " return year.add(fYear)\n", + "\n", + "\n", + "def fitHarmonicModel(col, band):\n", + " # Function to add dependent variables to an image.\n", + " def addDependents(img):\n", + " # Transform time variable to fractional year.\n", + " t = ee.Number(toFracYear(\n", + " ee.Date(img.get('system:time_start')), 1))\n", + " omega = 2.0 * math.pi\n", + " # Construct dependent variables image.\n", + " dependents = ee.Image.constant([\n", + " 1, t,\n", + " t.multiply(omega).cos(),\n", + " t.multiply(omega).sin(),\n", + " t.multiply(omega * 2).cos(),\n", + " t.multiply(omega * 2).sin(),\n", + " t.multiply(omega * 3).cos(),\n", + " t.multiply(omega * 3).sin()\n", + " ]) \\\n", + " .float() \\\n", + " .rename(['INTP', 'SLP', 'COS', 'SIN',\n", + " 'COS2', 'SIN2', 'COS3', 'SIN3'\n", + " ])\n", + " return img.addBands(dependents)\n", + " \n", + "\n", + " # Function to add dependent variable images to all images.\n", + " def prepareData(col, band):\n", + "\n", + "def func_zth(img):\n", + " return addDependents(img.select(band)) \\\n", + " .select(['INTP', 'SLP', 'COS',\n", + " 'SIN',\n", + " 'COS2', 'SIN2', 'COS3',\n", + " 'SIN3',\n", + " band\n", + " ]) \\\n", + " .updateMask(img.select(band) \\\n", + " .mask())\n", + "\n", + " return ee.ImageCollection(col.map(func_zth\n", + "))\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "))\n", + " \n", + "\n", + " col2 = prepareData(col, band)\n", + " # Fit model to data using robust linear regression.\n", + " ccd = col2 \\\n", + " .reduce(ee.Reducer.robustLinearRegression(8, 1), 4) \\\n", + " .rename([band + '_coefs', band + '_rmse'])\n", + "\n", + " # Return model coefficients and model rmse.\n", + " return ccd.select(band + '_coefs').arrayTranspose() \\\n", + " .addBands(ccd.select(band + '_rmse'))\n", + "\n", + "\n", + "# Fit harmonic models to training data of all sensors.\n", + "lstModel = fitHarmonicModel(lstTraining, lstParam.band) \\\n", + " .set({\n", + " 'region': 'test',\n", + " 'sensor': 'Landsat'\n", + " })\n", + "s2Model = fitHarmonicModel(s2Training, s2Param.band) \\\n", + " .set({\n", + " 'region': 'test',\n", + " 'sensor': 'Sentinel-2'\n", + " })\n", + "s1Model = fitHarmonicModel(s1Training, s2Param.band) \\\n", + " .set({\n", + " 'region': 'test',\n", + " 'sensor': 'Sentinel-1'\n", + " })\n", + "\n", + "# Define function to save the results.\n", + "def saveModel(model, prefix):\n", + " Export.image.toAsset({\n", + " 'image': model,\n", + " 'scale': 30,\n", + " 'assetId': prefix + '_CCD',\n", + " 'description': 'Save_' + prefix + '_CCD',\n", + " 'region': testArea,\n", + " 'maxPixels': 1e13,\n", + " 'pyramidingPolicy': {\n", + " '.default': 'sample'\n", + " }\n", + " })\n", + "\n", + "\n", + "# Run the saving function.\n", + "saveModel(lstModel, 'LST')\n", + "saveModel(s2Model, 'S2')\n", + "saveModel(s1Model, 'S1')\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35d Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35d Checkpoint.js new file mode 100644 index 0000000..01b1fe0 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35d Checkpoint.js @@ -0,0 +1,253 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.5 Deforestation Viewed from Multiple Sensors +// Checkpoint: A35d +// Author: Xiaojing Tang +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]); + +Map.centerObject(testArea); + +// Start and end of the training and monitoring period. +var trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}); +var monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}); + +// Near-real-time monitoring parameters. +var nrtParam = { + z: 2, + m: 5, + n: 4 +}; + +// Sensor specific parameters. +var lstParam = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s2Param = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s1Param = { + band: 'VV', + minRMSE: 0.01, + strikeOnly: true +}; + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var unmixing = function(col) { + + // Define endmembers and cloud fraction threshold. + var gv = [500, 900, 400, 6100, 3000, 1000]; + var npv = [1400, 1700, 2200, 3000, 5500, 3000]; + var soil = [2000, 3000, 3400, 5800, 6000, 5800]; + var shade = [0, 0, 0, 0, 0, 0]; + var cloud = [9000, 9600, 8000, 7800, 7200, 6500]; + var cfThreshold = 0.05; + + return col.map(function(img) { + // Select the spectral bands and perform unmixing + var unmixed = img.select(['Blue', 'Green', 'Red', + 'NIR', + 'SWIR1', 'SWIR2' + ]) + .unmix([gv, shade, npv, soil, cloud], true, + true) + .rename(['GV', 'Shade', 'NPV', 'Soil', + 'Cloud' + ]); + + // Calculate Normalized Difference Fraction Index.+ + var NDFI = unmixed.expression( + '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + + '((GV / (1 - SHADE)) + (NPV + SOIL))', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).rename('NDFI'); + + // Mask cloudy pixel. + var maskCloud = unmixed.select('Cloud').lt( + cfThreshold); + // Mask all shade pixel. + var maskShade = unmixed.select('Shade').lt(1); + // Mask pixel where NDFI cannot be calculated. + var maskNDFI = unmixed.expression( + '(GV / (1 - SHADE)) + (NPV + SOIL)', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).gt(0); + + // Scale fractions to 0-10000 and apply masks. + return img + .addBands(unmixed.select(['GV', 'Shade', + 'NPV', 'Soil' + ]) + .multiply(10000)) + .addBands(NDFI) + .updateMask(maskCloud) + .updateMask(maskNDFI) + .updateMask(maskShade); + }); +}; + +var input = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs' +); +var lstTraining = unmixing(input.loadLandsatData(testArea, + trainPeriod)); +var lstMonitoring = unmixing(input.loadLandsatData(testArea, + monitorPeriod)); +var s2Training = unmixing(input.loadS2Data(testArea, trainPeriod)); +var s2Monitoring = unmixing(input.loadS2Data(testArea, + monitorPeriod)); +var s1Training = input.loadS1Data(testArea, trainPeriod); +var s1Monitoring = input.loadS1Data(testArea, monitorPeriod); + +var hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') + .unmask(); +var forestMask = hansen.select('treecover2000') + .gt(50) + .add(hansen.select('gain')) + .subtract(hansen.select('loss')) + .add(hansen.select('lossyear') + .eq(20)) + .gt(0) + .clip(testArea); + +var maskVis = { + min: 0, + max: 1, + palette: ['blue', 'green'] +}; +Map.addLayer(forestMask, maskVis, 'Forest Mask'); +print('lstTraining', lstTraining); +print('lstMonitoring', lstMonitoring); +print('s2Training', s2Training); +print('s2Monitoring', s2Monitoring); +print('s1Training', s1Training); +print('s1Monitoring', s1Monitoring); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var toFracYear = function(date) { + var year = date.get('year'); + var fYear = date.difference( + ee.Date.fromYMD(year, 1, 1), 'year'); + return year.add(fYear); +}; + +var fitHarmonicModel = function(col, band) { + // Function to add dependent variables to an image. + var addDependents = function(img) { + // Transform time variable to fractional year. + var t = ee.Number(toFracYear( + ee.Date(img.get('system:time_start')), 1)); + var omega = 2.0 * Math.PI; + // Construct dependent variables image. + var dependents = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) + .float() + .rename(['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]); + return img.addBands(dependents); + }; + + // Function to add dependent variable images to all images. + var prepareData = function(col, band) { + return ee.ImageCollection(col.map(function(img) { + return addDependents(img.select(band)) + .select(['INTP', 'SLP', 'COS', + 'SIN', + 'COS2', 'SIN2', 'COS3', + 'SIN3', + band + ]) + .updateMask(img.select(band) + .mask()); + })); + }; + + var col2 = prepareData(col, band); + // Fit model to data using robust linear regression. + var ccd = col2 + .reduce(ee.Reducer.robustLinearRegression(8, 1), 4) + .rename([band + '_coefs', band + '_rmse']); + + // Return model coefficients and model rmse. + return ccd.select(band + '_coefs').arrayTranspose() + .addBands(ccd.select(band + '_rmse')); +}; + +// Fit harmonic models to training data of all sensors. +var lstModel = fitHarmonicModel(lstTraining, lstParam.band) + .set({ + region: 'test', + sensor: 'Landsat' + }); +var s2Model = fitHarmonicModel(s2Training, s2Param.band) + .set({ + region: 'test', + sensor: 'Sentinel-2' + }); +var s1Model = fitHarmonicModel(s1Training, s2Param.band) + .set({ + region: 'test', + sensor: 'Sentinel-1' + }); + +// Define function to save the results. +var saveModel = function(model, prefix) { + Export.image.toAsset({ + image: model, + scale: 30, + assetId: prefix + '_CCD', + description: 'Save_' + prefix + '_CCD', + region: testArea, + maxPixels: 1e13, + pyramidingPolicy: { + '.default': 'sample' + } + }); +}; + +// Run the saving function. +saveModel(lstModel, 'LST'); +saveModel(s2Model, 'S2'); +saveModel(s1Model, 'S1'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35d Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35d Checkpoint.py new file mode 100644 index 0000000..6e9242a --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35d Checkpoint.py @@ -0,0 +1,322 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.5 Deforestation Viewed from Multiple Sensors +# Checkpoint: A35d +# Author: Xiaojing Tang +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]) + +Map.centerObject(testArea) + +# Start and end of the training and monitoring period. +trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}) +monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}) + +# Near-real-time monitoring parameters. +nrtParam = { + 'z': 2, + 'm': 5, + 'n': 4 +} + +# Sensor specific parameters. +lstParam = { + 'band': 'NDFI', + 'minRMSE': 0.05, + 'strikeOnly': False +} +s2Param = { + 'band': 'NDFI', + 'minRMSE': 0.05, + 'strikeOnly': False +} +s1Param = { + 'band': 'VV', + 'minRMSE': 0.01, + 'strikeOnly': True +} + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +def unmixing(col): + + # Define endmembers and cloud fraction threshold. + gv = [500, 900, 400, 6100, 3000, 1000] + npv = [1400, 1700, 2200, 3000, 5500, 3000] + soil = [2000, 3000, 3400, 5800, 6000, 5800] + shade = [0, 0, 0, 0, 0, 0] + cloud = [9000, 9600, 8000, 7800, 7200, 6500] + cfThreshold = 0.05 + + +def func_rlc(img): + # Select the spectral bands and perform unmixing + unmixed = img.select(['Blue', 'Green', 'Red', + 'NIR', + 'SWIR1', 'SWIR2' + ]) \ + .unmix([gv, shade, npv, soil, cloud], True, + True) \ + .rename(['GV', 'Shade', 'NPV', 'Soil', + 'Cloud' + ]) + + # Calculate Normalized Difference Fraction Index.+ \ + NDFI = unmixed.expression( + '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + \ + '((GV / (1 - SHADE)) + (NPV + SOIL))', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).rename('NDFI') + + # Mask cloudy pixel. + maskCloud = unmixed.select('Cloud').lt( + cfThreshold) + # Mask all shade pixel. + maskShade = unmixed.select('Shade').lt(1) + # Mask pixel where NDFI cannot be calculated. + maskNDFI = unmixed.expression( + '(GV / (1 - SHADE)) + (NPV + SOIL)', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).gt(0) + + # Scale fractions to 0-10000 and apply masks. + return img \ + .addBands(unmixed.select(['GV', 'Shade', + 'NPV', 'Soil' + ]) \ + .multiply(10000)) \ + .addBands(NDFI) \ + .updateMask(maskCloud) \ + .updateMask(maskNDFI) \ + .updateMask(maskShade) + + return col.map(func_rlc) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +input = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs' +) +lstTraining = unmixing(input.loadLandsatData(testArea, + trainPeriod)) +lstMonitoring = unmixing(input.loadLandsatData(testArea, + monitorPeriod)) +s2Training = unmixing(input.loadS2Data(testArea, trainPeriod)) +s2Monitoring = unmixing(input.loadS2Data(testArea, + monitorPeriod)) +s1Training = input.loadS1Data(testArea, trainPeriod) +s1Monitoring = input.loadS1Data(testArea, monitorPeriod) + +hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') \ + .unmask() +forestMask = hansen.select('treecover2000') \ + .gt(50) \ + .add(hansen.select('gain')) \ + .subtract(hansen.select('loss')) \ + .add(hansen.select('lossyear') \ + .eq(20)) \ + .gt(0) \ + .clip(testArea) + +maskVis = { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'green'] +} +Map.addLayer(forestMask, maskVis, 'Forest Mask') +print('lstTraining', lstTraining) +print('lstMonitoring', lstMonitoring) +print('s2Training', s2Training) +print('s2Monitoring', s2Monitoring) +print('s1Training', s1Training) +print('s1Monitoring', s1Monitoring) + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +def toFracYear(date): + year = date.get('year') + fYear = date.difference( + ee.Date.fromYMD(year, 1, 1), 'year') + return year.add(fYear) + + +def fitHarmonicModel(col, band): + # Function to add dependent variables to an image. + def addDependents(img): + # Transform time variable to fractional year. + t = ee.Number(toFracYear( + ee.Date(img.get('system:time_start')), 1)) + omega = 2.0 * math.pi + # Construct dependent variables image. + dependents = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) \ + .float() \ + .rename(['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]) + return img.addBands(dependents) + + + # Function to add dependent variable images to all images. + def prepareData(col, band): + +def func_zth(img): + return addDependents(img.select(band)) \ + .select(['INTP', 'SLP', 'COS', + 'SIN', + 'COS2', 'SIN2', 'COS3', + 'SIN3', + band + ]) \ + .updateMask(img.select(band) \ + .mask()) + + return ee.ImageCollection(col.map(func_zth +)) + + + + + + + + + +)) + + + col2 = prepareData(col, band) + # Fit model to data using robust linear regression. + ccd = col2 \ + .reduce(ee.Reducer.robustLinearRegression(8, 1), 4) \ + .rename([band + '_coefs', band + '_rmse']) + + # Return model coefficients and model rmse. + return ccd.select(band + '_coefs').arrayTranspose() \ + .addBands(ccd.select(band + '_rmse')) + + +# Fit harmonic models to training data of all sensors. +lstModel = fitHarmonicModel(lstTraining, lstParam.band) \ + .set({ + 'region': 'test', + 'sensor': 'Landsat' + }) +s2Model = fitHarmonicModel(s2Training, s2Param.band) \ + .set({ + 'region': 'test', + 'sensor': 'Sentinel-2' + }) +s1Model = fitHarmonicModel(s1Training, s2Param.band) \ + .set({ + 'region': 'test', + 'sensor': 'Sentinel-1' + }) + +# Define function to save the results. +def saveModel(model, prefix): + Export.image.toAsset({ + 'image': model, + 'scale': 30, + 'assetId': prefix + '_CCD', + 'description': 'Save_' + prefix + '_CCD', + 'region': testArea, + 'maxPixels': 1e13, + 'pyramidingPolicy': { + '.default': 'sample' + } + }) + + +# Run the saving function. +saveModel(lstModel, 'LST') +saveModel(s2Model, 'S2') +saveModel(s1Model, 'S1') + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35e Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35e Checkpoint.ipynb new file mode 100644 index 0000000..18535f9 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35e Checkpoint.ipynb @@ -0,0 +1,530 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.5 Deforestation Viewed from Multiple Sensors\n", + "# Checkpoint: A35e\n", + "# Author: Xiaojing Tang\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "testArea = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-66.73156878460787, -8.662236005089952],\n", + " [-66.73156878460787, -8.916025640576244],\n", + " [-66.44867083538912, -8.916025640576244],\n", + " [-66.44867083538912, -8.662236005089952]\n", + " ]\n", + " ])\n", + "\n", + "Map.centerObject(testArea)\n", + "\n", + "# Start and end of the training and monitoring period.\n", + "trainPeriod = ee.Dictionary({\n", + " 'start': '2017-01-01',\n", + " 'end': '2020-01-01'\n", + "})\n", + "monitorPeriod = ee.Dictionary({\n", + " 'start': '2020-01-01',\n", + " 'end': '2021-01-01'\n", + "})\n", + "\n", + "# Near-real-time monitoring parameters.\n", + "nrtParam = {\n", + " 'z': 2,\n", + " 'm': 5,\n", + " 'n': 4\n", + "}\n", + "\n", + "# Sensor specific parameters.\n", + "lstParam = {\n", + " 'band': 'NDFI',\n", + " 'minRMSE': 0.05,\n", + " 'strikeOnly': False\n", + "}\n", + "s2Param = {\n", + " 'band': 'NDFI',\n", + " 'minRMSE': 0.05,\n", + " 'strikeOnly': False\n", + "}\n", + "s1Param = {\n", + " 'band': 'VV',\n", + " 'minRMSE': 0.01,\n", + " 'strikeOnly': True\n", + "}\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "def unmixing(col):\n", + "\n", + " # Define endmembers and cloud fraction threshold.\n", + " gv = [500, 900, 400, 6100, 3000, 1000]\n", + " npv = [1400, 1700, 2200, 3000, 5500, 3000]\n", + " soil = [2000, 3000, 3400, 5800, 6000, 5800]\n", + " shade = [0, 0, 0, 0, 0, 0]\n", + " cloud = [9000, 9600, 8000, 7800, 7200, 6500]\n", + " cfThreshold = 0.05\n", + "\n", + "\n", + "def func_hwr(img):\n", + " # Select the spectral bands and perform unmixing\n", + " unmixed = img.select(['Blue', 'Green', 'Red',\n", + " 'NIR',\n", + " 'SWIR1', 'SWIR2'\n", + " ]) \\\n", + " .unmix([gv, shade, npv, soil, cloud], True,\n", + " True) \\\n", + " .rename(['GV', 'Shade', 'NPV', 'Soil',\n", + " 'Cloud'\n", + " ])\n", + "\n", + " # Calculate Normalized Difference Fraction Index.+ \\\n", + " NDFI = unmixed.expression(\n", + " '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + \\\n", + " '((GV / (1 - SHADE)) + (NPV + SOIL))', {\n", + " 'GV': unmixed.select('GV'),\n", + " 'SHADE': unmixed.select('Shade'),\n", + " 'NPV': unmixed.select('NPV'),\n", + " 'SOIL': unmixed.select('Soil')\n", + " }).rename('NDFI')\n", + "\n", + " # Mask cloudy pixel.\n", + " maskCloud = unmixed.select('Cloud').lt(\n", + " cfThreshold)\n", + " # Mask all shade pixel.\n", + " maskShade = unmixed.select('Shade').lt(1)\n", + " # Mask pixel where NDFI cannot be calculated.\n", + " maskNDFI = unmixed.expression(\n", + " '(GV / (1 - SHADE)) + (NPV + SOIL)', {\n", + " 'GV': unmixed.select('GV'),\n", + " 'SHADE': unmixed.select('Shade'),\n", + " 'NPV': unmixed.select('NPV'),\n", + " 'SOIL': unmixed.select('Soil')\n", + " }).gt(0)\n", + "\n", + " # Scale fractions to 0-10000 and apply masks.\n", + " return img \\\n", + " .addBands(unmixed.select(['GV', 'Shade',\n", + " 'NPV', 'Soil'\n", + " ]) \\\n", + " .multiply(10000)) \\\n", + " .addBands(NDFI) \\\n", + " .updateMask(maskCloud) \\\n", + " .updateMask(maskNDFI) \\\n", + " .updateMask(maskShade)\n", + "\n", + " return col.map(func_hwr)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs'\n", + ")\n", + "lstTraining = unmixing(input.loadLandsatData(testArea,\n", + " trainPeriod))\n", + "lstMonitoring = unmixing(input.loadLandsatData(testArea,\n", + " monitorPeriod))\n", + "s2Training = unmixing(input.loadS2Data(testArea, trainPeriod))\n", + "s2Monitoring = unmixing(input.loadS2Data(testArea,\n", + " monitorPeriod))\n", + "s1Training = input.loadS1Data(testArea, trainPeriod)\n", + "s1Monitoring = input.loadS1Data(testArea, monitorPeriod)\n", + "\n", + "hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') \\\n", + " .unmask()\n", + "forestMask = hansen.select('treecover2000') \\\n", + " .gt(50) \\\n", + " .add(hansen.select('gain')) \\\n", + " .subtract(hansen.select('loss')) \\\n", + " .add(hansen.select('lossyear') \\\n", + " .eq(20)) \\\n", + " .gt(0) \\\n", + " .clip(testArea)\n", + "\n", + "maskVis = {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'green']\n", + "}\n", + "Map.addLayer(forestMask, maskVis, 'Forest Mask')\n", + "print('lstTraining', lstTraining)\n", + "print('lstMonitoring', lstMonitoring)\n", + "print('s2Training', s2Training)\n", + "print('s2Monitoring', s2Monitoring)\n", + "print('s1Training', s1Training)\n", + "print('s1Monitoring', s1Monitoring)\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "def toFracYear(date):\n", + " year = date.get('year')\n", + " fYear = date.difference(\n", + " ee.Date.fromYMD(year, 1, 1), 'year')\n", + " return year.add(fYear)\n", + "\n", + "\n", + "def fitHarmonicModel(col, band):\n", + " # Function to add dependent variables to an image.\n", + " def addDependents(img):\n", + " # Transform time variable to fractional year.\n", + " t = ee.Number(toFracYear(\n", + " ee.Date(img.get('system:time_start')), 1))\n", + " omega = 2.0 * math.pi\n", + " # Construct dependent variables image.\n", + " dependents = ee.Image.constant([\n", + " 1, t,\n", + " t.multiply(omega).cos(),\n", + " t.multiply(omega).sin(),\n", + " t.multiply(omega * 2).cos(),\n", + " t.multiply(omega * 2).sin(),\n", + " t.multiply(omega * 3).cos(),\n", + " t.multiply(omega * 3).sin()\n", + " ]) \\\n", + " .float() \\\n", + " .rename(['INTP', 'SLP', 'COS', 'SIN',\n", + " 'COS2', 'SIN2', 'COS3', 'SIN3'\n", + " ])\n", + " return img.addBands(dependents)\n", + " \n", + "\n", + " # Function to add dependent variable images to all images.\n", + " def prepareData(col, band):\n", + "\n", + "def func_lzm(img):\n", + " return addDependents(img.select(band)) \\\n", + " .select(['INTP', 'SLP', 'COS',\n", + " 'SIN',\n", + " 'COS2', 'SIN2', 'COS3',\n", + " 'SIN3',\n", + " band\n", + " ]) \\\n", + " .updateMask(img.select(band) \\\n", + " .mask())\n", + "\n", + " return ee.ImageCollection(col.map(func_lzm\n", + "))\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "))\n", + " \n", + "\n", + " col2 = prepareData(col, band)\n", + " # Fit model to data using robust linear regression.\n", + " ccd = col2 \\\n", + " .reduce(ee.Reducer.robustLinearRegression(8, 1), 4) \\\n", + " .rename([band + '_coefs', band + '_rmse'])\n", + "\n", + " # Return model coefficients and model rmse.\n", + " return ccd.select(band + '_coefs').arrayTranspose() \\\n", + " .addBands(ccd.select(band + '_rmse'))\n", + "\n", + "\n", + "# Fit harmonic models to training data of all sensors.\n", + "lstModel = fitHarmonicModel(lstTraining, lstParam.band) \\\n", + " .set({\n", + " 'region': 'test',\n", + " 'sensor': 'Landsat'\n", + " })\n", + "s2Model = fitHarmonicModel(s2Training, s2Param.band) \\\n", + " .set({\n", + " 'region': 'test',\n", + " 'sensor': 'Sentinel-2'\n", + " })\n", + "s1Model = fitHarmonicModel(s1Training, s2Param.band) \\\n", + " .set({\n", + " 'region': 'test',\n", + " 'sensor': 'Sentinel-1'\n", + " })\n", + "\n", + "# Define function to save the results.\n", + "def saveModel(model, prefix):\n", + " Export.image.toAsset({\n", + " 'image': model,\n", + " 'scale': 30,\n", + " 'assetId': prefix + '_CCD',\n", + " 'description': 'Save_' + prefix + '_CCD',\n", + " 'region': testArea,\n", + " 'maxPixels': 1e13,\n", + " 'pyramidingPolicy': {\n", + " '.default': 'sample'\n", + " }\n", + " })\n", + "\n", + "\n", + "# Run the saving function.\n", + "saveModel(lstModel, 'LST')\n", + "saveModel(s2Model, 'S2')\n", + "saveModel(s1Model, 'S1')\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------\n", + "\n", + "models = ee.ImageCollection('projects/gee-book/assets/A3-5/ccd')\n", + "lstModel = models \\\n", + " .filterMetadata('sensor', 'equals', 'Landsat').first()\n", + "s2Model = models \\\n", + " .filterMetadata('sensor', 'equals', 'Sentinel-2').first()\n", + "s1Model = models \\\n", + " .filterMetadata('sensor', 'equals', 'Sentinel-1').first()\n", + "\n", + "def dearrayModel(model, band):\n", + " band = band + '_'\n", + "\n", + " # Function to extract a non-harmonic coefficients.\n", + " def genCoefImg(model, band, coef):\n", + " zeros = ee.Array(0).repeat(0, 1)\n", + " coefImg = model.select(band + coef) \\\n", + " .arrayCat(zeros, 0).float() \\\n", + " .arraySlice(0, 0, 1)\n", + " return ee.Image(coefImg \\\n", + " .arrayFlatten([\n", + " [ee.String('S1_') \\\n", + " .cat(band).cat(coef)\n", + " ]\n", + " ]))\n", + " \n", + "\n", + " # Function to extract harmonic coefficients.\n", + " def genHarmImg(model, band):\n", + " harms = ['INTP', 'SLP', 'COS', 'SIN',\n", + " 'COS2', 'SIN2', 'COS3', 'SIN3'\n", + " ]\n", + " zeros = ee.Image(ee.Array([\n", + " ee.List.repeat(0, harms.length)\n", + " ])) \\\n", + " .arrayRepeat(0, 1)\n", + " coefImg = model.select(band + 'coefs') \\\n", + " .arrayCat(zeros, 0).float() \\\n", + " .arraySlice(0, 0, 1)\n", + " return ee.Image(coefImg \\\n", + " .arrayFlatten([\n", + " [ee.String(band).cat('coef')], harms\n", + " ]))\n", + " \n", + "\n", + " # Extract harmonic coefficients and rmse.\n", + " rmse = genCoefImg(model, band, 'rmse')\n", + " coef = genHarmImg(model, band)\n", + " return ee.Image.cat(rmse, coef)\n", + "\n", + "\n", + "def createPredImg(modelImg, img, band, sensor):\n", + " # Reformat date.\n", + " date = toFracYear(ee.Date(img.get('system:time_start')))\n", + " dateString = ee.Date(img.get('system:time_start')) \\\n", + " .format('yyyyMMdd')\n", + " # List of coefficients .\n", + " coefs = ['INTP', 'SLP', 'COS', 'SIN',\n", + " 'COS2', 'SIN2', 'COS3', 'SIN3'\n", + " ]\n", + " # Get coefficients images from model image.\n", + "\n", + "def func_lyy(coef):\n", + " return modelImg.select(\".*\".concat(coef))\n", + "\n", + " coef = ee.Image(coefs.map(func_lyy\n", + ")).rename(coefs)\n", + "\n", + ")).rename(coefs)\n", + " t = ee.Number(date)\n", + " omega = 2.0 * math.pi\n", + " # Construct dependent variables.\n", + " pred = ee.Image.constant([\n", + " 1, t,\n", + " t.multiply(omega).cos(),\n", + " t.multiply(omega).sin(),\n", + " t.multiply(omega * 2).cos(),\n", + " t.multiply(omega * 2).sin(),\n", + " t.multiply(omega * 3).cos(),\n", + " t.multiply(omega * 3).sin()\n", + " ]) \\\n", + " .float()\n", + " # Matrix multiply dependent variables with coefficients.\n", + " return pred.multiply(coef).reduce('sum') \\\n", + " .addBands(img, [band]).rename(['predicted', band]) \\\n", + " .set({\n", + " 'sensor': sensor,\n", + " 'system:time_start': img.get('system:time_start'),\n", + " 'dateString': dateString\n", + " })\n", + "\n", + "\n", + "def addPredicted(data, modelImg, band, sensor):\n", + "\n", + "def func_cfe(img):\n", + " return createPredImg(modelImg, img, band,\n", + " sensor)\n", + "\n", + " return ee.ImageCollection(data.map(func_cfe\n", + "))\n", + "\n", + "\n", + "))\n", + "\n", + "\n", + "# Convert models to non-array images.\n", + "lstModelImg = dearrayModel(lstModel, lstParam.band)\n", + "s2ModelImg = dearrayModel(s2Model, s2Param.band)\n", + "s1ModelImg = dearrayModel(s1Model, s1Param.band)\n", + "\n", + "# Add predicted image to each real image.\n", + "lstPredicted = addPredicted(lstMonitoring, lstModelImg,\n", + " lstParam.band, 'Landsat')\n", + "s2Predicted = addPredicted(s2Monitoring, s2ModelImg,\n", + " s2Param.band, 'Sentinel-2')\n", + "s1Predicted = addPredicted(s1Monitoring, s1ModelImg,\n", + " s1Param.band, 'Sentinel-1')\n", + "\n", + "print('lstPredicted', lstPredicted)\n", + "\n", + "# ------------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# ------------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35e Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35e Checkpoint.js new file mode 100644 index 0000000..0198553 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35e Checkpoint.js @@ -0,0 +1,366 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.5 Deforestation Viewed from Multiple Sensors +// Checkpoint: A35e +// Author: Xiaojing Tang +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]); + +Map.centerObject(testArea); + +// Start and end of the training and monitoring period. +var trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}); +var monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}); + +// Near-real-time monitoring parameters. +var nrtParam = { + z: 2, + m: 5, + n: 4 +}; + +// Sensor specific parameters. +var lstParam = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s2Param = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s1Param = { + band: 'VV', + minRMSE: 0.01, + strikeOnly: true +}; + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var unmixing = function(col) { + + // Define endmembers and cloud fraction threshold. + var gv = [500, 900, 400, 6100, 3000, 1000]; + var npv = [1400, 1700, 2200, 3000, 5500, 3000]; + var soil = [2000, 3000, 3400, 5800, 6000, 5800]; + var shade = [0, 0, 0, 0, 0, 0]; + var cloud = [9000, 9600, 8000, 7800, 7200, 6500]; + var cfThreshold = 0.05; + + return col.map(function(img) { + // Select the spectral bands and perform unmixing + var unmixed = img.select(['Blue', 'Green', 'Red', + 'NIR', + 'SWIR1', 'SWIR2' + ]) + .unmix([gv, shade, npv, soil, cloud], true, + true) + .rename(['GV', 'Shade', 'NPV', 'Soil', + 'Cloud' + ]); + + // Calculate Normalized Difference Fraction Index.+ + var NDFI = unmixed.expression( + '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + + '((GV / (1 - SHADE)) + (NPV + SOIL))', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).rename('NDFI'); + + // Mask cloudy pixel. + var maskCloud = unmixed.select('Cloud').lt( + cfThreshold); + // Mask all shade pixel. + var maskShade = unmixed.select('Shade').lt(1); + // Mask pixel where NDFI cannot be calculated. + var maskNDFI = unmixed.expression( + '(GV / (1 - SHADE)) + (NPV + SOIL)', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).gt(0); + + // Scale fractions to 0-10000 and apply masks. + return img + .addBands(unmixed.select(['GV', 'Shade', + 'NPV', 'Soil' + ]) + .multiply(10000)) + .addBands(NDFI) + .updateMask(maskCloud) + .updateMask(maskNDFI) + .updateMask(maskShade); + }); +}; + +var input = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs' +); +var lstTraining = unmixing(input.loadLandsatData(testArea, + trainPeriod)); +var lstMonitoring = unmixing(input.loadLandsatData(testArea, + monitorPeriod)); +var s2Training = unmixing(input.loadS2Data(testArea, trainPeriod)); +var s2Monitoring = unmixing(input.loadS2Data(testArea, + monitorPeriod)); +var s1Training = input.loadS1Data(testArea, trainPeriod); +var s1Monitoring = input.loadS1Data(testArea, monitorPeriod); + +var hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') + .unmask(); +var forestMask = hansen.select('treecover2000') + .gt(50) + .add(hansen.select('gain')) + .subtract(hansen.select('loss')) + .add(hansen.select('lossyear') + .eq(20)) + .gt(0) + .clip(testArea); + +var maskVis = { + min: 0, + max: 1, + palette: ['blue', 'green'] +}; +Map.addLayer(forestMask, maskVis, 'Forest Mask'); +print('lstTraining', lstTraining); +print('lstMonitoring', lstMonitoring); +print('s2Training', s2Training); +print('s2Monitoring', s2Monitoring); +print('s1Training', s1Training); +print('s1Monitoring', s1Monitoring); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var toFracYear = function(date) { + var year = date.get('year'); + var fYear = date.difference( + ee.Date.fromYMD(year, 1, 1), 'year'); + return year.add(fYear); +}; + +var fitHarmonicModel = function(col, band) { + // Function to add dependent variables to an image. + var addDependents = function(img) { + // Transform time variable to fractional year. + var t = ee.Number(toFracYear( + ee.Date(img.get('system:time_start')), 1)); + var omega = 2.0 * Math.PI; + // Construct dependent variables image. + var dependents = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) + .float() + .rename(['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]); + return img.addBands(dependents); + }; + + // Function to add dependent variable images to all images. + var prepareData = function(col, band) { + return ee.ImageCollection(col.map(function(img) { + return addDependents(img.select(band)) + .select(['INTP', 'SLP', 'COS', + 'SIN', + 'COS2', 'SIN2', 'COS3', + 'SIN3', + band + ]) + .updateMask(img.select(band) + .mask()); + })); + }; + + var col2 = prepareData(col, band); + // Fit model to data using robust linear regression. + var ccd = col2 + .reduce(ee.Reducer.robustLinearRegression(8, 1), 4) + .rename([band + '_coefs', band + '_rmse']); + + // Return model coefficients and model rmse. + return ccd.select(band + '_coefs').arrayTranspose() + .addBands(ccd.select(band + '_rmse')); +}; + +// Fit harmonic models to training data of all sensors. +var lstModel = fitHarmonicModel(lstTraining, lstParam.band) + .set({ + region: 'test', + sensor: 'Landsat' + }); +var s2Model = fitHarmonicModel(s2Training, s2Param.band) + .set({ + region: 'test', + sensor: 'Sentinel-2' + }); +var s1Model = fitHarmonicModel(s1Training, s2Param.band) + .set({ + region: 'test', + sensor: 'Sentinel-1' + }); + +// Define function to save the results. +var saveModel = function(model, prefix) { + Export.image.toAsset({ + image: model, + scale: 30, + assetId: prefix + '_CCD', + description: 'Save_' + prefix + '_CCD', + region: testArea, + maxPixels: 1e13, + pyramidingPolicy: { + '.default': 'sample' + } + }); +}; + +// Run the saving function. +saveModel(lstModel, 'LST'); +saveModel(s2Model, 'S2'); +saveModel(s1Model, 'S1'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var models = ee.ImageCollection('projects/gee-book/assets/A3-5/ccd'); +var lstModel = models + .filterMetadata('sensor', 'equals', 'Landsat').first(); +var s2Model = models + .filterMetadata('sensor', 'equals', 'Sentinel-2').first(); +var s1Model = models + .filterMetadata('sensor', 'equals', 'Sentinel-1').first(); + +var dearrayModel = function(model, band) { + band = band + '_'; + + // Function to extract a non-harmonic coefficients. + var genCoefImg = function(model, band, coef) { + var zeros = ee.Array(0).repeat(0, 1); + var coefImg = model.select(band + coef) + .arrayCat(zeros, 0).float() + .arraySlice(0, 0, 1); + return ee.Image(coefImg + .arrayFlatten([ + [ee.String('S1_') + .cat(band).cat(coef) + ] + ])); + }; + + // Function to extract harmonic coefficients. + var genHarmImg = function(model, band) { + var harms = ['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]; + var zeros = ee.Image(ee.Array([ + ee.List.repeat(0, harms.length) + ])) + .arrayRepeat(0, 1); + var coefImg = model.select(band + 'coefs') + .arrayCat(zeros, 0).float() + .arraySlice(0, 0, 1); + return ee.Image(coefImg + .arrayFlatten([ + [ee.String(band).cat('coef')], harms + ])); + }; + + // Extract harmonic coefficients and rmse. + var rmse = genCoefImg(model, band, 'rmse'); + var coef = genHarmImg(model, band); + return ee.Image.cat(rmse, coef); +}; + +var createPredImg = function(modelImg, img, band, sensor) { + // Reformat date. + var date = toFracYear(ee.Date(img.get('system:time_start'))); + var dateString = ee.Date(img.get('system:time_start')) + .format('yyyyMMdd'); + // List of coefficients . + var coefs = ['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]; + // Get coefficients images from model image. + var coef = ee.Image(coefs.map(function(coef) { + return modelImg.select(".*".concat(coef)); + })).rename(coefs); + var t = ee.Number(date); + var omega = 2.0 * Math.PI; + // Construct dependent variables. + var pred = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) + .float(); + // Matrix multiply dependent variables with coefficients. + return pred.multiply(coef).reduce('sum') + // Add original image and rename bands. + .addBands(img, [band]).rename(['predicted', band]) + // Preserve some metadata. + .set({ + 'sensor': sensor, + 'system:time_start': img.get('system:time_start'), + 'dateString': dateString + }); +}; + +var addPredicted = function(data, modelImg, band, sensor) { + return ee.ImageCollection(data.map(function(img) { + return createPredImg(modelImg, img, band, + sensor); + })); +}; + +// Convert models to non-array images. +var lstModelImg = dearrayModel(lstModel, lstParam.band); +var s2ModelImg = dearrayModel(s2Model, s2Param.band); +var s1ModelImg = dearrayModel(s1Model, s1Param.band); + +// Add predicted image to each real image. +var lstPredicted = addPredicted(lstMonitoring, lstModelImg, + lstParam.band, 'Landsat'); +var s2Predicted = addPredicted(s2Monitoring, s2ModelImg, + s2Param.band, 'Sentinel-2'); +var s1Predicted = addPredicted(s1Monitoring, s1ModelImg, + s1Param.band, 'Sentinel-1'); + +print('lstPredicted', lstPredicted); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35e Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35e Checkpoint.py new file mode 100644 index 0000000..0cd362b --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35e Checkpoint.py @@ -0,0 +1,444 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.5 Deforestation Viewed from Multiple Sensors +# Checkpoint: A35e +# Author: Xiaojing Tang +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]) + +Map.centerObject(testArea) + +# Start and end of the training and monitoring period. +trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}) +monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}) + +# Near-real-time monitoring parameters. +nrtParam = { + 'z': 2, + 'm': 5, + 'n': 4 +} + +# Sensor specific parameters. +lstParam = { + 'band': 'NDFI', + 'minRMSE': 0.05, + 'strikeOnly': False +} +s2Param = { + 'band': 'NDFI', + 'minRMSE': 0.05, + 'strikeOnly': False +} +s1Param = { + 'band': 'VV', + 'minRMSE': 0.01, + 'strikeOnly': True +} + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +def unmixing(col): + + # Define endmembers and cloud fraction threshold. + gv = [500, 900, 400, 6100, 3000, 1000] + npv = [1400, 1700, 2200, 3000, 5500, 3000] + soil = [2000, 3000, 3400, 5800, 6000, 5800] + shade = [0, 0, 0, 0, 0, 0] + cloud = [9000, 9600, 8000, 7800, 7200, 6500] + cfThreshold = 0.05 + + +def func_hwr(img): + # Select the spectral bands and perform unmixing + unmixed = img.select(['Blue', 'Green', 'Red', + 'NIR', + 'SWIR1', 'SWIR2' + ]) \ + .unmix([gv, shade, npv, soil, cloud], True, + True) \ + .rename(['GV', 'Shade', 'NPV', 'Soil', + 'Cloud' + ]) + + # Calculate Normalized Difference Fraction Index.+ \ + NDFI = unmixed.expression( + '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + \ + '((GV / (1 - SHADE)) + (NPV + SOIL))', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).rename('NDFI') + + # Mask cloudy pixel. + maskCloud = unmixed.select('Cloud').lt( + cfThreshold) + # Mask all shade pixel. + maskShade = unmixed.select('Shade').lt(1) + # Mask pixel where NDFI cannot be calculated. + maskNDFI = unmixed.expression( + '(GV / (1 - SHADE)) + (NPV + SOIL)', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).gt(0) + + # Scale fractions to 0-10000 and apply masks. + return img \ + .addBands(unmixed.select(['GV', 'Shade', + 'NPV', 'Soil' + ]) \ + .multiply(10000)) \ + .addBands(NDFI) \ + .updateMask(maskCloud) \ + .updateMask(maskNDFI) \ + .updateMask(maskShade) + + return col.map(func_hwr) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +input = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs' +) +lstTraining = unmixing(input.loadLandsatData(testArea, + trainPeriod)) +lstMonitoring = unmixing(input.loadLandsatData(testArea, + monitorPeriod)) +s2Training = unmixing(input.loadS2Data(testArea, trainPeriod)) +s2Monitoring = unmixing(input.loadS2Data(testArea, + monitorPeriod)) +s1Training = input.loadS1Data(testArea, trainPeriod) +s1Monitoring = input.loadS1Data(testArea, monitorPeriod) + +hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') \ + .unmask() +forestMask = hansen.select('treecover2000') \ + .gt(50) \ + .add(hansen.select('gain')) \ + .subtract(hansen.select('loss')) \ + .add(hansen.select('lossyear') \ + .eq(20)) \ + .gt(0) \ + .clip(testArea) + +maskVis = { + 'min': 0, + 'max': 1, + 'palette': ['blue', 'green'] +} +Map.addLayer(forestMask, maskVis, 'Forest Mask') +print('lstTraining', lstTraining) +print('lstMonitoring', lstMonitoring) +print('s2Training', s2Training) +print('s2Monitoring', s2Monitoring) +print('s1Training', s1Training) +print('s1Monitoring', s1Monitoring) + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +def toFracYear(date): + year = date.get('year') + fYear = date.difference( + ee.Date.fromYMD(year, 1, 1), 'year') + return year.add(fYear) + + +def fitHarmonicModel(col, band): + # Function to add dependent variables to an image. + def addDependents(img): + # Transform time variable to fractional year. + t = ee.Number(toFracYear( + ee.Date(img.get('system:time_start')), 1)) + omega = 2.0 * math.pi + # Construct dependent variables image. + dependents = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) \ + .float() \ + .rename(['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]) + return img.addBands(dependents) + + + # Function to add dependent variable images to all images. + def prepareData(col, band): + +def func_lzm(img): + return addDependents(img.select(band)) \ + .select(['INTP', 'SLP', 'COS', + 'SIN', + 'COS2', 'SIN2', 'COS3', + 'SIN3', + band + ]) \ + .updateMask(img.select(band) \ + .mask()) + + return ee.ImageCollection(col.map(func_lzm +)) + + + + + + + + + +)) + + + col2 = prepareData(col, band) + # Fit model to data using robust linear regression. + ccd = col2 \ + .reduce(ee.Reducer.robustLinearRegression(8, 1), 4) \ + .rename([band + '_coefs', band + '_rmse']) + + # Return model coefficients and model rmse. + return ccd.select(band + '_coefs').arrayTranspose() \ + .addBands(ccd.select(band + '_rmse')) + + +# Fit harmonic models to training data of all sensors. +lstModel = fitHarmonicModel(lstTraining, lstParam.band) \ + .set({ + 'region': 'test', + 'sensor': 'Landsat' + }) +s2Model = fitHarmonicModel(s2Training, s2Param.band) \ + .set({ + 'region': 'test', + 'sensor': 'Sentinel-2' + }) +s1Model = fitHarmonicModel(s1Training, s2Param.band) \ + .set({ + 'region': 'test', + 'sensor': 'Sentinel-1' + }) + +# Define function to save the results. +def saveModel(model, prefix): + Export.image.toAsset({ + 'image': model, + 'scale': 30, + 'assetId': prefix + '_CCD', + 'description': 'Save_' + prefix + '_CCD', + 'region': testArea, + 'maxPixels': 1e13, + 'pyramidingPolicy': { + '.default': 'sample' + } + }) + + +# Run the saving function. +saveModel(lstModel, 'LST') +saveModel(s2Model, 'S2') +saveModel(s1Model, 'S1') + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ + +models = ee.ImageCollection('projects/gee-book/assets/A3-5/ccd') +lstModel = models \ + .filterMetadata('sensor', 'equals', 'Landsat').first() +s2Model = models \ + .filterMetadata('sensor', 'equals', 'Sentinel-2').first() +s1Model = models \ + .filterMetadata('sensor', 'equals', 'Sentinel-1').first() + +def dearrayModel(model, band): + band = band + '_' + + # Function to extract a non-harmonic coefficients. + def genCoefImg(model, band, coef): + zeros = ee.Array(0).repeat(0, 1) + coefImg = model.select(band + coef) \ + .arrayCat(zeros, 0).float() \ + .arraySlice(0, 0, 1) + return ee.Image(coefImg \ + .arrayFlatten([ + [ee.String('S1_') \ + .cat(band).cat(coef) + ] + ])) + + + # Function to extract harmonic coefficients. + def genHarmImg(model, band): + harms = ['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ] + zeros = ee.Image(ee.Array([ + ee.List.repeat(0, harms.length) + ])) \ + .arrayRepeat(0, 1) + coefImg = model.select(band + 'coefs') \ + .arrayCat(zeros, 0).float() \ + .arraySlice(0, 0, 1) + return ee.Image(coefImg \ + .arrayFlatten([ + [ee.String(band).cat('coef')], harms + ])) + + + # Extract harmonic coefficients and rmse. + rmse = genCoefImg(model, band, 'rmse') + coef = genHarmImg(model, band) + return ee.Image.cat(rmse, coef) + + +def createPredImg(modelImg, img, band, sensor): + # Reformat date. + date = toFracYear(ee.Date(img.get('system:time_start'))) + dateString = ee.Date(img.get('system:time_start')) \ + .format('yyyyMMdd') + # List of coefficients . + coefs = ['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ] + # Get coefficients images from model image. + +def func_lyy(coef): + return modelImg.select(".*".concat(coef)) + + coef = ee.Image(coefs.map(func_lyy +)).rename(coefs) + +)).rename(coefs) + t = ee.Number(date) + omega = 2.0 * math.pi + # Construct dependent variables. + pred = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) \ + .float() + # Matrix multiply dependent variables with coefficients. + return pred.multiply(coef).reduce('sum') \ + .addBands(img, [band]).rename(['predicted', band]) \ + .set({ + 'sensor': sensor, + 'system:time_start': img.get('system:time_start'), + 'dateString': dateString + }) + + +def addPredicted(data, modelImg, band, sensor): + +def func_cfe(img): + return createPredImg(modelImg, img, band, + sensor) + + return ee.ImageCollection(data.map(func_cfe +)) + + +)) + + +# Convert models to non-array images. +lstModelImg = dearrayModel(lstModel, lstParam.band) +s2ModelImg = dearrayModel(s2Model, s2Param.band) +s1ModelImg = dearrayModel(s1Model, s1Param.band) + +# Add predicted image to each real image. +lstPredicted = addPredicted(lstMonitoring, lstModelImg, + lstParam.band, 'Landsat') +s2Predicted = addPredicted(s2Monitoring, s2ModelImg, + s2Param.band, 'Sentinel-2') +s1Predicted = addPredicted(s1Monitoring, s1ModelImg, + s1Param.band, 'Sentinel-1') + +print('lstPredicted', lstPredicted) + +# ------------------------------------------------------------------------ +# CHECKPOINT +# ------------------------------------------------------------------------ +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35f Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35f Checkpoint.js new file mode 100644 index 0000000..c7c42e8 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35f Checkpoint.js @@ -0,0 +1,444 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.5 Deforestation Viewed from Multiple Sensors +// Checkpoint: A35f +// Author: Xiaojing Tang +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]); + +Map.centerObject(testArea); + +// Start and end of the training and monitoring period. +var trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}); +var monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}); + +// Near-real-time monitoring parameters. +var nrtParam = { + z: 2, + m: 5, + n: 4 +}; + +// Sensor specific parameters. +var lstParam = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s2Param = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s1Param = { + band: 'VV', + minRMSE: 0.01, + strikeOnly: true +}; + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var unmixing = function(col) { + + // Define endmembers and cloud fraction threshold. + var gv = [500, 900, 400, 6100, 3000, 1000]; + var npv = [1400, 1700, 2200, 3000, 5500, 3000]; + var soil = [2000, 3000, 3400, 5800, 6000, 5800]; + var shade = [0, 0, 0, 0, 0, 0]; + var cloud = [9000, 9600, 8000, 7800, 7200, 6500]; + var cfThreshold = 0.05; + + return col.map(function(img) { + // Select the spectral bands and perform unmixing + var unmixed = img.select(['Blue', 'Green', 'Red', + 'NIR', + 'SWIR1', 'SWIR2' + ]) + .unmix([gv, shade, npv, soil, cloud], true, + true) + .rename(['GV', 'Shade', 'NPV', 'Soil', + 'Cloud' + ]); + + // Calculate Normalized Difference Fraction Index.+ + var NDFI = unmixed.expression( + '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + + '((GV / (1 - SHADE)) + (NPV + SOIL))', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).rename('NDFI'); + + // Mask cloudy pixel. + var maskCloud = unmixed.select('Cloud').lt( + cfThreshold); + // Mask all shade pixel. + var maskShade = unmixed.select('Shade').lt(1); + // Mask pixel where NDFI cannot be calculated. + var maskNDFI = unmixed.expression( + '(GV / (1 - SHADE)) + (NPV + SOIL)', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).gt(0); + + // Scale fractions to 0-10000 and apply masks. + return img + .addBands(unmixed.select(['GV', 'Shade', + 'NPV', 'Soil' + ]) + .multiply(10000)) + .addBands(NDFI) + .updateMask(maskCloud) + .updateMask(maskNDFI) + .updateMask(maskShade); + }); +}; + +var input = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs' +); +var lstTraining = unmixing(input.loadLandsatData(testArea, + trainPeriod)); +var lstMonitoring = unmixing(input.loadLandsatData(testArea, + monitorPeriod)); +var s2Training = unmixing(input.loadS2Data(testArea, trainPeriod)); +var s2Monitoring = unmixing(input.loadS2Data(testArea, + monitorPeriod)); +var s1Training = input.loadS1Data(testArea, trainPeriod); +var s1Monitoring = input.loadS1Data(testArea, monitorPeriod); + +var hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') + .unmask(); +var forestMask = hansen.select('treecover2000') + .gt(50) + .add(hansen.select('gain')) + .subtract(hansen.select('loss')) + .add(hansen.select('lossyear') + .eq(20)) + .gt(0) + .clip(testArea); + +var maskVis = { + min: 0, + max: 1, + palette: ['blue', 'green'] +}; +Map.addLayer(forestMask, maskVis, 'Forest Mask'); +print('lstTraining', lstTraining); +print('lstMonitoring', lstMonitoring); +print('s2Training', s2Training); +print('s2Monitoring', s2Monitoring); +print('s1Training', s1Training); +print('s1Monitoring', s1Monitoring); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var toFracYear = function(date) { + var year = date.get('year'); + var fYear = date.difference( + ee.Date.fromYMD(year, 1, 1), 'year'); + return year.add(fYear); +}; + +var fitHarmonicModel = function(col, band) { + // Function to add dependent variables to an image. + var addDependents = function(img) { + // Transform time variable to fractional year. + var t = ee.Number(toFracYear( + ee.Date(img.get('system:time_start')), 1)); + var omega = 2.0 * Math.PI; + // Construct dependent variables image. + var dependents = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) + .float() + .rename(['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]); + return img.addBands(dependents); + }; + + // Function to add dependent variable images to all images. + var prepareData = function(col, band) { + return ee.ImageCollection(col.map(function(img) { + return addDependents(img.select(band)) + .select(['INTP', 'SLP', 'COS', + 'SIN', + 'COS2', 'SIN2', 'COS3', + 'SIN3', + band + ]) + .updateMask(img.select(band) + .mask()); + })); + }; + + var col2 = prepareData(col, band); + // Fit model to data using robust linear regression. + var ccd = col2 + .reduce(ee.Reducer.robustLinearRegression(8, 1), 4) + .rename([band + '_coefs', band + '_rmse']); + + // Return model coefficients and model rmse. + return ccd.select(band + '_coefs').arrayTranspose() + .addBands(ccd.select(band + '_rmse')); +}; + +// Fit harmonic models to training data of all sensors. +var lstModel = fitHarmonicModel(lstTraining, lstParam.band) + .set({ + region: 'test', + sensor: 'Landsat' + }); +var s2Model = fitHarmonicModel(s2Training, s2Param.band) + .set({ + region: 'test', + sensor: 'Sentinel-2' + }); +var s1Model = fitHarmonicModel(s1Training, s2Param.band) + .set({ + region: 'test', + sensor: 'Sentinel-1' + }); + +// Define function to save the results. +var saveModel = function(model, prefix) { + Export.image.toAsset({ + image: model, + scale: 30, + assetId: prefix + '_CCD', + description: 'Save_' + prefix + '_CCD', + region: testArea, + maxPixels: 1e13, + pyramidingPolicy: { + '.default': 'sample' + } + }); +}; + +// Run the saving function. +saveModel(lstModel, 'LST'); +saveModel(s2Model, 'S2'); +saveModel(s1Model, 'S1'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var models = ee.ImageCollection('projects/gee-book/assets/A3-5/ccd'); +var lstModel = models + .filterMetadata('sensor', 'equals', 'Landsat').first(); +var s2Model = models + .filterMetadata('sensor', 'equals', 'Sentinel-2').first(); +var s1Model = models + .filterMetadata('sensor', 'equals', 'Sentinel-1').first(); + +var dearrayModel = function(model, band) { + band = band + '_'; + + // Function to extract a non-harmonic coefficients. + var genCoefImg = function(model, band, coef) { + var zeros = ee.Array(0).repeat(0, 1); + var coefImg = model.select(band + coef) + .arrayCat(zeros, 0).float() + .arraySlice(0, 0, 1); + return ee.Image(coefImg + .arrayFlatten([ + [ee.String('S1_') + .cat(band).cat(coef) + ] + ])); + }; + + // Function to extract harmonic coefficients. + var genHarmImg = function(model, band) { + var harms = ['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]; + var zeros = ee.Image(ee.Array([ + ee.List.repeat(0, harms.length) + ])) + .arrayRepeat(0, 1); + var coefImg = model.select(band + 'coefs') + .arrayCat(zeros, 0).float() + .arraySlice(0, 0, 1); + return ee.Image(coefImg + .arrayFlatten([ + [ee.String(band).cat('coef')], harms + ])); + }; + + // Extract harmonic coefficients and rmse. + var rmse = genCoefImg(model, band, 'rmse'); + var coef = genHarmImg(model, band); + return ee.Image.cat(rmse, coef); +}; + +var createPredImg = function(modelImg, img, band, sensor) { + // Reformat date. + var date = toFracYear(ee.Date(img.get('system:time_start'))); + var dateString = ee.Date(img.get('system:time_start')) + .format('yyyyMMdd'); + // List of coefficients . + var coefs = ['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]; + // Get coefficients images from model image. + var coef = ee.Image(coefs.map(function(coef) { + return modelImg.select(".*".concat(coef)); + })).rename(coefs); + var t = ee.Number(date); + var omega = 2.0 * Math.PI; + // Construct dependent variables. + var pred = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) + .float(); + // Matrix multiply dependent variables with coefficients. + return pred.multiply(coef).reduce('sum') + // Add original image and rename bands. + .addBands(img, [band]).rename(['predicted', band]) + // Preserve some metadata. + .set({ + 'sensor': sensor, + 'system:time_start': img.get('system:time_start'), + 'dateString': dateString + }); +}; + +var addPredicted = function(data, modelImg, band, sensor) { + return ee.ImageCollection(data.map(function(img) { + return createPredImg(modelImg, img, band, + sensor); + })); +}; + +// Convert models to non-array images. +var lstModelImg = dearrayModel(lstModel, lstParam.band); +var s2ModelImg = dearrayModel(s2Model, s2Param.band); +var s1ModelImg = dearrayModel(s1Model, s1Param.band); + +// Add predicted image to each real image. +var lstPredicted = addPredicted(lstMonitoring, lstModelImg, + lstParam.band, 'Landsat'); +var s2Predicted = addPredicted(s2Monitoring, s2ModelImg, + s2Param.band, 'Sentinel-2'); +var s1Predicted = addPredicted(s1Monitoring, s1ModelImg, + s1Param.band, 'Sentinel-1'); + +print('lstPredicted', lstPredicted); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +// Function to calculate residuals. +var addResiduals = function(data, band) { + return ee.ImageCollection(data.map(function(img) { + return img.select('predicted') + // Restrict predicted value to be under 10000 + .where(img.select('predicted').gt(10000), + 10000) + // Calculate the residual + .subtract(img.select(band)) + .rename('residual') + // Save some metadata + .set({ + 'sensor': img.get('sensor'), + 'system:time_start': img.get( + 'system:time_start'), + 'dateString': img.get( + 'dateString') + }); + })); +}; + +// Function to calculate change score and flag change. +var addChangeScores = function(data, rmse, minRMSE, + threshold, strikeOnly) { + // If strikeOnly then we need a mask for balls. + var mask = ee.Image(0); + if (strikeOnly) { + mask = ee.Image(1); + } + + return ee.ImageCollection(data.map(function(img) { + // Calculate change score + var z = img.divide(rmse.max(minRMSE)); + // Check if score is above threshold + var strike = z.multiply(z.gt(threshold)); + // Create the output image. + var zStack = ee.Image.cat(z, strike).rename([ + 'z', 'strike' + ]) + .set({ + 'sensor': img.get('sensor'), + 'system:time_start': img.get( + 'system:time_start') + }); + // Mask balls if strikeOnly. + return zStack.updateMask(strike.gt(0).or( + mask)); + })); +}; + +// Add residuals to collection of predicted images. +var lstResiduals = addResiduals(lstPredicted, lstParam.band); +var s2Residuals = addResiduals(s2Predicted, s2Param.band); +var s1Residuals = addResiduals(s1Predicted, s1Param.band); + +// Add change score to residuals. +var lstScores = addChangeScores( + lstResiduals, lstModelImg.select('.*rmse'), + lstPredicted.select(lstParam.band).mean() + .abs().multiply(lstParam.minRMSE), + nrtParam.z, lstParam.strikeOnly); +var s2Scores = addChangeScores( + s2Residuals, s2ModelImg.select('.*rmse'), + s2Predicted.select(s2Param.band).mean() + .abs().multiply(s2Param.minRMSE), + nrtParam.z, s2Param.strikeOnly); +var s1Scores = addChangeScores( + s1Residuals, s1ModelImg.select('.*rmse'), + s1Predicted.select(s1Param.band).mean() + .abs().multiply(s1Param.minRMSE), + nrtParam.z, s1Param.strikeOnly); + +print('lstScores', lstScores); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35g Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35g Checkpoint.js new file mode 100644 index 0000000..cc9f4de --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/A35g Checkpoint.js @@ -0,0 +1,508 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.5 Deforestation Viewed from Multiple Sensors +// Checkpoint: A35g +// Author: Xiaojing Tang +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var testArea = ee.Geometry.Polygon( + [ + [ + [-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952] + ] + ]); + +Map.centerObject(testArea); + +// Start and end of the training and monitoring period. +var trainPeriod = ee.Dictionary({ + 'start': '2017-01-01', + 'end': '2020-01-01' +}); +var monitorPeriod = ee.Dictionary({ + 'start': '2020-01-01', + 'end': '2021-01-01' +}); + +// Near-real-time monitoring parameters. +var nrtParam = { + z: 2, + m: 5, + n: 4 +}; + +// Sensor specific parameters. +var lstParam = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s2Param = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false +}; +var s1Param = { + band: 'VV', + minRMSE: 0.01, + strikeOnly: true +}; + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var unmixing = function(col) { + + // Define endmembers and cloud fraction threshold. + var gv = [500, 900, 400, 6100, 3000, 1000]; + var npv = [1400, 1700, 2200, 3000, 5500, 3000]; + var soil = [2000, 3000, 3400, 5800, 6000, 5800]; + var shade = [0, 0, 0, 0, 0, 0]; + var cloud = [9000, 9600, 8000, 7800, 7200, 6500]; + var cfThreshold = 0.05; + + return col.map(function(img) { + // Select the spectral bands and perform unmixing + var unmixed = img.select(['Blue', 'Green', 'Red', + 'NIR', + 'SWIR1', 'SWIR2' + ]) + .unmix([gv, shade, npv, soil, cloud], true, + true) + .rename(['GV', 'Shade', 'NPV', 'Soil', + 'Cloud' + ]); + + // Calculate Normalized Difference Fraction Index.+ + var NDFI = unmixed.expression( + '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ' + + '((GV / (1 - SHADE)) + (NPV + SOIL))', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).rename('NDFI'); + + // Mask cloudy pixel. + var maskCloud = unmixed.select('Cloud').lt( + cfThreshold); + // Mask all shade pixel. + var maskShade = unmixed.select('Shade').lt(1); + // Mask pixel where NDFI cannot be calculated. + var maskNDFI = unmixed.expression( + '(GV / (1 - SHADE)) + (NPV + SOIL)', { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).gt(0); + + // Scale fractions to 0-10000 and apply masks. + return img + .addBands(unmixed.select(['GV', 'Shade', + 'NPV', 'Soil' + ]) + .multiply(10000)) + .addBands(NDFI) + .updateMask(maskCloud) + .updateMask(maskNDFI) + .updateMask(maskShade); + }); +}; + +var input = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs' +); +var lstTraining = unmixing(input.loadLandsatData(testArea, + trainPeriod)); +var lstMonitoring = unmixing(input.loadLandsatData(testArea, + monitorPeriod)); +var s2Training = unmixing(input.loadS2Data(testArea, trainPeriod)); +var s2Monitoring = unmixing(input.loadS2Data(testArea, + monitorPeriod)); +var s1Training = input.loadS1Data(testArea, trainPeriod); +var s1Monitoring = input.loadS1Data(testArea, monitorPeriod); + +var hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') + .unmask(); +var forestMask = hansen.select('treecover2000') + .gt(50) + .add(hansen.select('gain')) + .subtract(hansen.select('loss')) + .add(hansen.select('lossyear') + .eq(20)) + .gt(0) + .clip(testArea); + +var maskVis = { + min: 0, + max: 1, + palette: ['blue', 'green'] +}; +Map.addLayer(forestMask, maskVis, 'Forest Mask', false); +print('lstTraining', lstTraining); +print('lstMonitoring', lstMonitoring); +print('s2Training', s2Training); +print('s2Monitoring', s2Monitoring); +print('s1Training', s1Training); +print('s1Monitoring', s1Monitoring); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var toFracYear = function(date) { + var year = date.get('year'); + var fYear = date.difference( + ee.Date.fromYMD(year, 1, 1), 'year'); + return year.add(fYear); +}; + +var fitHarmonicModel = function(col, band) { + // Function to add dependent variables to an image. + var addDependents = function(img) { + // Transform time variable to fractional year. + var t = ee.Number(toFracYear( + ee.Date(img.get('system:time_start')), 1)); + var omega = 2.0 * Math.PI; + // Construct dependent variables image. + var dependents = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) + .float() + .rename(['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]); + return img.addBands(dependents); + }; + + // Function to add dependent variable images to all images. + var prepareData = function(col, band) { + return ee.ImageCollection(col.map(function(img) { + return addDependents(img.select(band)) + .select(['INTP', 'SLP', 'COS', + 'SIN', + 'COS2', 'SIN2', 'COS3', + 'SIN3', + band + ]) + .updateMask(img.select(band) + .mask()); + })); + }; + + var col2 = prepareData(col, band); + // Fit model to data using robust linear regression. + var ccd = col2 + .reduce(ee.Reducer.robustLinearRegression(8, 1), 4) + .rename([band + '_coefs', band + '_rmse']); + + // Return model coefficients and model rmse. + return ccd.select(band + '_coefs').arrayTranspose() + .addBands(ccd.select(band + '_rmse')); +}; + +// Fit harmonic models to training data of all sensors. +var lstModel = fitHarmonicModel(lstTraining, lstParam.band) + .set({ + region: 'test', + sensor: 'Landsat' + }); +var s2Model = fitHarmonicModel(s2Training, s2Param.band) + .set({ + region: 'test', + sensor: 'Sentinel-2' + }); +var s1Model = fitHarmonicModel(s1Training, s2Param.band) + .set({ + region: 'test', + sensor: 'Sentinel-1' + }); + +// Define function to save the results. +var saveModel = function(model, prefix) { + Export.image.toAsset({ + image: model, + scale: 30, + assetId: prefix + '_CCD', + description: 'Save_' + prefix + '_CCD', + region: testArea, + maxPixels: 1e13, + pyramidingPolicy: { + '.default': 'sample' + } + }); +}; + +// Run the saving function. +saveModel(lstModel, 'LST'); +saveModel(s2Model, 'S2'); +saveModel(s1Model, 'S1'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var models = ee.ImageCollection('projects/gee-book/assets/A3-5/ccd'); +var lstModel = models + .filterMetadata('sensor', 'equals', 'Landsat').first(); +var s2Model = models + .filterMetadata('sensor', 'equals', 'Sentinel-2').first(); +var s1Model = models + .filterMetadata('sensor', 'equals', 'Sentinel-1').first(); + +var dearrayModel = function(model, band) { + band = band + '_'; + + // Function to extract a non-harmonic coefficients. + var genCoefImg = function(model, band, coef) { + var zeros = ee.Array(0).repeat(0, 1); + var coefImg = model.select(band + coef) + .arrayCat(zeros, 0).float() + .arraySlice(0, 0, 1); + return ee.Image(coefImg + .arrayFlatten([ + [ee.String('S1_') + .cat(band).cat(coef) + ] + ])); + }; + + // Function to extract harmonic coefficients. + var genHarmImg = function(model, band) { + var harms = ['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]; + var zeros = ee.Image(ee.Array([ + ee.List.repeat(0, harms.length) + ])) + .arrayRepeat(0, 1); + var coefImg = model.select(band + 'coefs') + .arrayCat(zeros, 0).float() + .arraySlice(0, 0, 1); + return ee.Image(coefImg + .arrayFlatten([ + [ee.String(band).cat('coef')], harms + ])); + }; + + // Extract harmonic coefficients and rmse. + var rmse = genCoefImg(model, band, 'rmse'); + var coef = genHarmImg(model, band); + return ee.Image.cat(rmse, coef); +}; + +var createPredImg = function(modelImg, img, band, sensor) { + // Reformat date. + var date = toFracYear(ee.Date(img.get('system:time_start'))); + var dateString = ee.Date(img.get('system:time_start')) + .format('yyyyMMdd'); + // List of coefficients . + var coefs = ['INTP', 'SLP', 'COS', 'SIN', + 'COS2', 'SIN2', 'COS3', 'SIN3' + ]; + // Get coefficients images from model image. + var coef = ee.Image(coefs.map(function(coef) { + return modelImg.select(".*".concat(coef)); + })).rename(coefs); + var t = ee.Number(date); + var omega = 2.0 * Math.PI; + // Construct dependent variables. + var pred = ee.Image.constant([ + 1, t, + t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin() + ]) + .float(); + // Matrix multiply dependent variables with coefficients. + return pred.multiply(coef).reduce('sum') + // Add original image and rename bands. + .addBands(img, [band]).rename(['predicted', band]) + // Preserve some metadata. + .set({ + 'sensor': sensor, + 'system:time_start': img.get('system:time_start'), + 'dateString': dateString + }); +}; + +var addPredicted = function(data, modelImg, band, sensor) { + return ee.ImageCollection(data.map(function(img) { + return createPredImg(modelImg, img, band, + sensor); + })); +}; + +// Convert models to non-array images. +var lstModelImg = dearrayModel(lstModel, lstParam.band); +var s2ModelImg = dearrayModel(s2Model, s2Param.band); +var s1ModelImg = dearrayModel(s1Model, s1Param.band); + +// Add predicted image to each real image. +var lstPredicted = addPredicted(lstMonitoring, lstModelImg, + lstParam.band, 'Landsat'); +var s2Predicted = addPredicted(s2Monitoring, s2ModelImg, + s2Param.band, 'Sentinel-2'); +var s1Predicted = addPredicted(s1Monitoring, s1ModelImg, + s1Param.band, 'Sentinel-1'); + +print('lstPredicted', lstPredicted); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +// Function to calculate residuals. +var addResiduals = function(data, band) { + return ee.ImageCollection(data.map(function(img) { + return img.select('predicted') + // Restrict predicted value to be under 10000 + .where(img.select('predicted').gt(10000), + 10000) + // Calculate the residual + .subtract(img.select(band)) + .rename('residual') + // Save some metadata + .set({ + 'sensor': img.get('sensor'), + 'system:time_start': img.get( + 'system:time_start'), + 'dateString': img.get( + 'dateString') + }); + })); +}; + +// Function to calculate change score and flag change. +var addChangeScores = function(data, rmse, minRMSE, + threshold, strikeOnly) { + // If strikeOnly then we need a mask for balls. + var mask = ee.Image(0); + if (strikeOnly) { + mask = ee.Image(1); + } + + return ee.ImageCollection(data.map(function(img) { + // Calculate change score + var z = img.divide(rmse.max(minRMSE)); + // Check if score is above threshold + var strike = z.multiply(z.gt(threshold)); + // Create the output image. + var zStack = ee.Image.cat(z, strike).rename([ + 'z', 'strike' + ]) + .set({ + 'sensor': img.get('sensor'), + 'system:time_start': img.get( + 'system:time_start') + }); + // Mask balls if strikeOnly. + return zStack.updateMask(strike.gt(0).or( + mask)); + })); +}; + +// Add residuals to collection of predicted images. +var lstResiduals = addResiduals(lstPredicted, lstParam.band); +var s2Residuals = addResiduals(s2Predicted, s2Param.band); +var s1Residuals = addResiduals(s1Predicted, s1Param.band); + +// Add change score to residuals. +var lstScores = addChangeScores( + lstResiduals, lstModelImg.select('.*rmse'), + lstPredicted.select(lstParam.band).mean() + .abs().multiply(lstParam.minRMSE), + nrtParam.z, lstParam.strikeOnly); +var s2Scores = addChangeScores( + s2Residuals, s2ModelImg.select('.*rmse'), + s2Predicted.select(s2Param.band).mean() + .abs().multiply(s2Param.minRMSE), + nrtParam.z, s2Param.strikeOnly); +var s1Scores = addChangeScores( + s1Residuals, s1ModelImg.select('.*rmse'), + s1Predicted.select(s1Param.band).mean() + .abs().multiply(s1Param.minRMSE), + nrtParam.z, s1Param.strikeOnly); + +print('lstScores', lstScores); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ + +var fused = lstScores.merge(s2Scores).merge(s1Scores) + .sort('system:time_start'); + +var monitorChange = function(changeScores, nrtParam) { + // Initialize an empty image. + var zeros = ee.Image(0).addBands(ee.Image(0)) + .rename(['change', 'date']); + // Determine shift size based on size of monitoring window. + var shift = Math.pow(2, nrtParam.m - 1) - 1; + // Function to monitor. + var monitor = function(img, result) { + // Retrieve change image at last step. + var change = ee.Image(result).select('change'); + // Retrieve change date image at last step. + var date = ee.Image(result).select('date'); + // Create a shift image to shift the change binary array + // left for one space so that new one can be appended. + var shiftImg = img.select('z').mask().eq(0) + .multiply(shift + 1).add(shift); + change = change.bitwiseAnd(shiftImg) + .multiply(shiftImg.eq(shift).add(1)) + .add(img.select('strike').unmask().gt(0)); + // Check if there are enough strike in the current + // monitoring window to flag a change. + date = date.add(change.bitCount().gte(nrtParam.n) + // Ignore pixels where change already detected. + .multiply(date.eq(0)) + // Record change date where change is flagged. + .multiply(ee.Number(toFracYear( + ee.Date(img.get( + 'system:time_start')), 1)))); + // Combine change and date layer for next iteration. + return (change.addBands(date)); + }; + + // Iterate through the time series and look for change. + return ee.Image(changeScores.iterate(monitor, zeros)) + // Select change date layer and selfmask. + .select('date').rename('Alerts').selfMask(); +}; + +var alerts = monitorChange(fused, nrtParam).updateMask(forestMask); +print('alerts', alerts); + +// Define a visualization parameter. +var altVisParam = { + min: 2020.4, + max: 2021, + palette: ['FF0080', 'EC1280', 'DA2480', 'C83680', 'B64880', + 'A35B80', '916D80', '7F7F80', '6D9180', '5BA380', + '48B680', '36C880', '24DA80', '12EC80', '00FF80', + '00EB89', '00D793', '00C49D', '00B0A7', '009CB0', + '0089BA', '0075C4', '0062CE', '004ED7', '003AE1', + '0027EB', '0013F5', '0000FF' + ] +}; +Map.centerObject(testArea, 10); +Map.addLayer(alerts, altVisParam, 'Forest Disturbance Map (2020)'); +Map.setOptions('SATELLITE'); + +// ------------------------------------------------------------------------ +// CHECKPOINT +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/FNRT_GUI.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/FNRT_GUI.ipynb new file mode 100644 index 0000000..5717670 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/FNRT_GUI.ipynb @@ -0,0 +1,420 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "testArea =\n", + "\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-66.73156878460787, -8.662236005089952],\n", + " [-66.73156878460787, -8.916025640576244],\n", + " [-66.44867083538912, -8.916025640576244],\n", + " [-66.44867083538912, -8.662236005089952]]], None, False)\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# Fusion Near Real-time (GUI)\n", + "# Near real-time monitoring of forest disturbance by fusion of\n", + "# multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu).\n", + "\n", + "# ---------------------------------------------------------------\n", + "# Model Parameters:\n", + "trainPeriod = ee.Dictionary({'start': '2017-01-01', 'end': '2020-01-01'})\n", + "monitorPeriod = ee.Dictionary({'start': '2020-01-01', 'end': '2021-01-01'})\n", + "fullPeriod = ee.Dictionary({\n", + " 'start': trainPeriod.get('start'),\n", + " 'end': monitorPeriod.get('end')})\n", + "nrtParam = {'z': 2, 'n': 4, 'm': 5, 'maxZ': 10}\n", + "optParam = {\n", + " 'band': 'NDFI',\n", + " 'minRMSE': 0.05,\n", + " 'strikeOnly': False,\n", + " 'vis': '{bands': ['SWIR1', 'NIR', 'Red'], 'min': 0, 'max': 5000}\n", + "}\n", + "radParam = {\n", + " 'band': 'VV',\n", + " 'minRMSE': 0.01,\n", + " 'strikeOnly': True,\n", + " 'vis': '{bands': ['VV', 'VH', 'ratio'], 'min': 10, 'max': 30}\n", + "}\n", + "mskVisParam = {'min': 0, 'max': 1, 'palette': ['blue', 'green']}\n", + "altVisParam = {'min': 2020.4, 'max': 2021,\n", + " 'palette': ['FF0080', 'EC1280', 'DA2480', 'C83680', 'B64880', 'A35B80', '916D80',\n", + " '7F7F80', '6D9180', '5BA380', '48B680', '36C880', '24DA80', '12EC80',\n", + " '00FF80', '00EB89', '00D793', '00C49D', '00B0A7', '009CB0', '0089BA',\n", + " '0075C4', '0062CE', '004ED7', '003AE1', '0027EB', '0013F5', '0000FF']}\n", + "\n", + "# ---------------------------------------------------------------\n", + "# Imports and predefined variables:\n", + "listener = 0\n", + "ut = require('users/xjtang/fnrt:Lite/Utilities')\n", + "hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8').unmask()\n", + "forestMask = hansen.select('treecover2000').gt(50) \\\n", + " .add(hansen.select('gain')) \\\n", + " .subtract(hansen.select('loss')) \\\n", + " .add(hansen.select('lossyear').eq(20)) \\\n", + " .gt(0)\n", + "alerts = None\n", + "ccd = ee.ImageCollection('projects/gee-book/assets/A3-5/ccd')\n", + "\n", + "# ---------------------------------------------------------------\n", + "# Main functions:\n", + " # run and plot CCD result for a pixel\n", + "def chartCCD(coords):\n", + " resetTSPanel()\n", + " sensor = ccdSelect.getValue()\n", + " pixel = ee.Geometry.Point([coords.lon, coords.lat])\n", + " tsPanel.add(ui.Label('Running CCD on ' + sensor + ' data...'))\n", + " addPixel(coords)\n", + " param = None\n", + " if (sensor == 'Sentinel-1') {\n", + " param = radParam\n", + " } else {\n", + " param = optParam\n", + " }\n", + " trainData = ut.getData(pixel, trainPeriod, sensor)\n", + " monitorData = ut.getData(pixel, monitorPeriod, sensor)\n", + " ccdModel = ee.Image(ee.Algorithms.If(\n", + " ccd.filterMetadata('sensor', 'equals', sensor).first(),\n", + " ccd.filterMetadata('sensor', 'equals', sensor).first(),\n", + " ut.runCCD(trainData, trainPeriod, param.band)\n", + " ))\n", + " ccdTS = ut.getTimeSeries(trainData, monitorData, ccdModel, pixel, param.band, 0.1)\n", + " ccdTable = ut.transformToTable(ccdTS, ['dateString', 'train', 'monitor', 'fit'])\n", + " ccdTable.evaluate(function(t, e) {\n", + " chart = ut.createCCDChart(t, param.band, coords.lat, coords.lon)\n", + " chart.onClick(\n", + " def function(date):\n", + " if (date === None) {\n", + " removeLayer('_')\n", + " } else {\n", + " img = ee.Image(ut.getImage(pixel, date, sensor))\n", + " mapPanel.addLayer(img, param.vis, img.get('system:index').getInfo())\n", + " removeLayer('Clicked')\n", + " addPixel(coords)\n", + " }\n", + "\n", + " )\n", + " tsPanel.clear()\n", + " tsPanel.add(chart)\n", + " })\n", + "\n", + "\n", + " # run near-real-time monitoring for one sensor for one pixel\n", + "def runPixelSensorNRT(pixel, sensor):\n", + " trainData = ut.getData(pixel, trainPeriod, sensor)\n", + " monitorData = ut.getData(pixel, monitorPeriod, sensor)\n", + " param = None\n", + " if (sensor == 'Sentinel-1') {\n", + " param = radParam\n", + " } else {\n", + " param = optParam\n", + " }\n", + " ccdModel = ee.Image(ee.Algorithms.If(\n", + " ccd.filterMetadata('sensor', 'equals', sensor).first(),\n", + " ccd.filterMetadata('sensor', 'equals', sensor).first(),\n", + " ut.runCCD(trainData, trainPeriod, param.band)\n", + " ))\n", + " ccdTS = ut.getTimeSeries(trainData, monitorData, ccdModel, pixel, param.band)\n", + " Z = ee.FeatureCollection(ut.addPixelZScore(ccdTS, nrtParam.maxZ, param.minRMSE))\n", + " checked = ut.checkPixelZScore(Z, nrtParam.z)\n", + " if ((S2Check.getValue() | LSTCheck.getValue()) & param.strikeOnly) {\n", + " checked = checked.filterMetadata('Ball', 'equals', None)\n", + " }\n", + " return checked\n", + "\n", + "\n", + " # run and plot NRT for a pixel\n", + "def chartNRT(coords):\n", + " resetTSPanel()\n", + " tsPanel.add(ui.Label('Running NRT...'))\n", + " pixel = ee.Geometry.Point([coords.lon, coords.lat])\n", + " addPixel(coords)\n", + " nrtTS = ee.FeatureCollection([])\n", + " if (S2Check.getValue()) {nrtTS = nrtTS.merge(runPixelSensorNRT(pixel, 'Sentinel-2'))}\n", + " if (S1Check.getValue()) {nrtTS = nrtTS.merge(runPixelSensorNRT(pixel, 'Sentinel-1'))}\n", + " if (LSTCheck.getValue()) {nrtTS = nrtTS.merge(runPixelSensorNRT(pixel, 'Landsat'))}\n", + " nrtTS = nrtTS.filterMetadata('x', 'not_equals', None)\n", + " if (nrtTS.size().gt(0)) {\n", + " nrtMonitor = ee.FeatureCollection(ut.monitorPixelChange(nrtTS.sort('fitTime'), nrtParam))\n", + " nrt = ut.transformToTable(nrtMonitor, ['dateString', 'Z_train', 'Ball', 'Strike', 'StrikeOut'])\n", + " nrt.evaluate(function(t, e) {\n", + " chart = ut.createNRTChart(t, coords.lat, coords.lon)\n", + " tsPanel.clear()\n", + " tsPanel.add(chart)\n", + " })\n", + " } else {\n", + " tsPanel.add(ui.Label('No sensor was selected.'))\n", + " }\n", + "\n", + "\n", + " # run near-real-time monitoring for one sensor for an area\n", + "def runAreaSensorNRT(area, sensor):\n", + " param = None\n", + " if (sensor == 'Sentinel-1') {\n", + " param = radParam\n", + " } else {\n", + " param = optParam\n", + " }\n", + " monitorData = ut.getData(area, monitorPeriod, sensor)\n", + " ccdModel = ccd.filterMetadata('sensor', 'equals', sensor).first().updateMask(forestMask)\n", + " ccdImg = ut.getCCDImage(ccdModel, param.band)\n", + " synthetics = ut.addSynthetic(monitorData, ccdImg, param.band, sensor)\n", + " monitorRes = ut.getResiduals(synthetics, param.band)\n", + " return ut.getChangeScores(monitorRes, ccdImg.select('.*rmse'),\n", + " synthetics.select(param.band).mean(),\n", + " param.minRMSE, nrtParam.z, param.strikeOnly)\n", + "\n", + "\n", + " # run near real time\n", + "def runNRT(area):\n", + " nrtTS = ee.ImageCollection([])\n", + " if (S2Check.getValue()) {nrtTS = nrtTS.merge(runAreaSensorNRT(area, 'Sentinel-2'))}\n", + " if (S1Check.getValue()) {nrtTS = nrtTS.merge(runAreaSensorNRT(area, 'Sentinel-1'))}\n", + " if (LSTCheck.getValue()) {nrtTS = nrtTS.merge(runAreaSensorNRT(area, 'Landsat'))}\n", + " if (nrtTS.size().gt(0)) {\n", + " nrtTS = nrtTS.sort('system:time_start')\n", + " return ut.monitorChange(nrtTS, nrtParam)\n", + " } else {\n", + " print('Nothing was selected.')\n", + " return ee.Image(0)\n", + " }\n", + "\n", + "\n", + " # add pixel location\n", + "def addPixel(coords):\n", + " pSize = 0.000135\n", + " pixel = ee.Geometry.Rectangle([coords.lon - pSize, coords.lat - pSize,\n", + " coords.lon + pSize, coords.lat + pSize])\n", + " mapPanel.addLayer(pixel, {'color': '0000FF'}, 'Clicked')\n", + "\n", + "\n", + " # remove a layer\n", + "def removeLayer(name):\n", + " layers = mapPanel.layers()\n", + " nLayer = layers.length()\n", + " for i in range(nLayer-1, 0, -1):\n", + " layer = layers.get(i)\n", + " if (layer.getName().match(name)) {\n", + " layers.remove(layer)\n", + " }\n", + "\n", + "\n", + "\n", + " # reset the time series panel\n", + "def resetTSPanel():\n", + " tsPanel.clear()\n", + " removeLayer('_')\n", + " removeLayer('Clicked')\n", + "\n", + "\n", + "# ---------------------------------------------------------------\n", + "# UIs:\n", + " # map panel\n", + "mapPanel = ui.Map({'style': '{cursor': 'crosshair'}})\n", + "mapPanel.centerObject(testArea, 10)\n", + "mapPanel.setOptions('SATELLITE')\n", + "mapPanel.addLayer(testArea, {'color': 'red'}, 'Test Area')\n", + "mapPanel.addLayer(forestMask, mskVisParam, 'Forest Mask', False)\n", + "\n", + " # menu panel\n", + "trainButton = ui.Button('Train')\n", + "ccdButton = ui.Button('Fit')\n", + "nrtButton = ui.Button('Monitor')\n", + "runButton = ui.Button('Run')\n", + "saveButton = ui.Button('Save')\n", + "menuSet = ui.Panel([ccdButton, nrtButton, runButton],\n", + " ui.Panel.Layout.Flow('vertical'))\n", + "ccdSelect = ui.Select(['Landsat', 'Sentinel-2', 'Sentinel-1'], 'Select sensor for CCD.', 'Landsat')\n", + "LSTCheck = ui.Checkbox('Landsat', True)\n", + "S2Check = ui.Checkbox('Sentinel-2', True)\n", + "S1Check = ui.Checkbox('Sentinel-1', False)\n", + "selectSet = ui.Panel([ccdSelect, LSTCheck, S2Check, S1Check],\n", + " ui.Panel.Layout.Flow('vertical'))\n", + "menuUISet = ui.Panel([menuSet, selectSet], ui.Panel.Layout.Flow('horizontal'))\n", + "menuPanel = ui.Panel({\n", + " 'widgets': [ui.Label('Menu'), menuUISet],\n", + " 'layout': ui.Panel.Layout.Flow('vertical'),\n", + " 'style': '{width': '20%'}})\n", + "\n", + " # ts panel\n", + "tsPanel = ui.Panel({\n", + " 'widgets': [],\n", + " 'style': '{position': 'bottom-right', 'width': '80%'}})\n", + "\n", + " # ui panel\n", + "controlPanel = ui.Panel({\n", + " 'style': '{height': '30%'},\n", + " 'widgets':[ui.SplitPanel(tsPanel, menuPanel, 'horizontal', False)]})\n", + "mapPanel2 = ui.Panel({\n", + " 'style': '{height': '70%'},\n", + " 'widgets':[mapPanel]})\n", + "uiPanel = ui.SplitPanel(mapPanel2, controlPanel, 'vertical')\n", + "\n", + "# ---------------------------------------------------------------\n", + "# Runtime functions:\n", + "trainButton.onClick(function() {\n", + " def saveCCD(ccd, sensor):\n", + " Export.image.toAsset({\n", + " 'image': ccd,\n", + " 'scale': 30,\n", + " 'assetId': 'projects/bu-nearrealtime/lite/ccd/' + sensor + '_CCD',\n", + " 'description': 'Save_' + sensor + '_CCD',\n", + " 'region': testArea,\n", + " 'maxPixels': 1e13,\n", + " 'pyramidingPolicy': {'.default': 'sample'}\n", + " })\n", + " \n", + " LST = ut.getData(testArea, trainPeriod, 'Landsat')\n", + " saveCCD(ut.runCCD(LST, trainPeriod, 'NDFI').set({'region': 'test', 'sensor': 'Landsat'}), 'LST')\n", + " S2 = ut.getData(testArea, trainPeriod, 'Sentinel-2')\n", + " saveCCD(ut.runCCD(S2, trainPeriod, 'NDFI').set({'region': 'test', 'sensor': 'Sentinel-2'}), 'S2')\n", + " S1 = ut.getData(testArea, trainPeriod, 'Sentinel-1')\n", + " saveCCD(ut.runCCD(S1, trainPeriod, 'VV').set({'region': 'test', 'sensor': 'Sentinel-1'}), 'S1')\n", + "})\n", + "\n", + "ccdButton.onClick(function() {\n", + " if (listener == 1) {\n", + " ccdButton.setLabel('Fit')\n", + " listener = 0\n", + " } else {\n", + " nrtButton.setLabel('Monitor')\n", + " ccdButton.setLabel('Cancel')\n", + " listener = 1\n", + " }\n", + "})\n", + "\n", + "nrtButton.onClick(function() {\n", + " if (listener == 2) {\n", + " nrtButton.setLabel('Monitor')\n", + " listener = 0\n", + " } else {\n", + " nrtButton.setLabel('Cancel')\n", + " ccdButton.setLabel('Fit')\n", + " listener = 2\n", + " }\n", + "})\n", + "\n", + "saveButton.onClick(function() {\n", + " Export.image.toAsset({\n", + " 'image': alerts,\n", + " 'scale': 30,\n", + " 'description': 'SaveAlerts',\n", + " 'assetId': 'Alerts',\n", + " 'region': testArea,\n", + " 'maxPixels': 1e13})\n", + "})\n", + "\n", + "runButton.onClick(function() {\n", + " alerts = runNRT(testArea)\n", + " mapPanel.addLayer(alerts, altVisParam, 'Forest Disturbance Alerts')\n", + " saveButton.setDisabled(False)\n", + "})\n", + "\n", + "mapPanel.onClick(function(coords) {\n", + " if (listener == 1) {\n", + " chartCCD(coords)\n", + " } else if (listener == 2) {\n", + " chartNRT(coords)\n", + " }\n", + "})\n", + "\n", + "# ---------------------------------------------------------------\n", + "# Initialization:\n", + "#saveButton.setDisabled(True)\n", + "ui.root.clear()\n", + "ui.root.add(uiPanel)\n", + "\n", + "# End" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/FNRT_GUI.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/FNRT_GUI.js new file mode 100644 index 0000000..139077f --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/FNRT_GUI.js @@ -0,0 +1,327 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var testArea = + /* color: #d63000 */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952]]], null, false); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// Fusion Near Real-time (GUI) +// Near real-time monitoring of forest disturbance by fusion of +// multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu). + +// --------------------------------------------------------------- +// Model Parameters: +var trainPeriod = ee.Dictionary({'start': '2017-01-01', 'end': '2020-01-01'}); +var monitorPeriod = ee.Dictionary({'start': '2020-01-01', 'end': '2021-01-01'}); +var fullPeriod = ee.Dictionary({ + 'start': trainPeriod.get('start'), + 'end': monitorPeriod.get('end')}); +var nrtParam = {z: 2, n: 4, m: 5, maxZ: 10}; +var optParam = { + band: 'NDFI', + minRMSE: 0.05, + strikeOnly: false, + vis: {bands: ['SWIR1', 'NIR', 'Red'], min: 0, max: 5000} +}; +var radParam = { + band: 'VV', + minRMSE: 0.01, + strikeOnly: true, + vis: {bands: ['VV', 'VH', 'ratio'], min: 10, max: 30} +}; +var mskVisParam = {min: 0, max: 1, palette: ['blue', 'green']}; +var altVisParam = {min: 2020.4, max: 2021, + palette: ['FF0080', 'EC1280', 'DA2480', 'C83680', 'B64880', 'A35B80', '916D80', + '7F7F80', '6D9180', '5BA380', '48B680', '36C880', '24DA80', '12EC80', + '00FF80', '00EB89', '00D793', '00C49D', '00B0A7', '009CB0', '0089BA', + '0075C4', '0062CE', '004ED7', '003AE1', '0027EB', '0013F5', '0000FF']}; + +// --------------------------------------------------------------- +// Imports and predefined variables: +var listener = 0; +var ut = require('users/xjtang/fnrt:Lite/Utilities'); +var hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8').unmask(); +var forestMask = hansen.select('treecover2000').gt(50) + .add(hansen.select('gain')) + .subtract(hansen.select('loss')) + .add(hansen.select('lossyear').eq(20)) + .gt(0); +var alerts = null; +var ccd = ee.ImageCollection('projects/gee-book/assets/A3-5/ccd'); + +// --------------------------------------------------------------- +// Main functions: + // run and plot CCD result for a pixel +var chartCCD = function(coords) { + resetTSPanel(); + var sensor = ccdSelect.getValue(); + var pixel = ee.Geometry.Point([coords.lon, coords.lat]); + tsPanel.add(ui.Label('Running CCD on ' + sensor + ' data...')); + addPixel(coords); + var param = null; + if (sensor == 'Sentinel-1') { + param = radParam; + } else { + param = optParam; + } + var trainData = ut.getData(pixel, trainPeriod, sensor); + var monitorData = ut.getData(pixel, monitorPeriod, sensor); + var ccdModel = ee.Image(ee.Algorithms.If( + ccd.filterMetadata('sensor', 'equals', sensor).first(), + ccd.filterMetadata('sensor', 'equals', sensor).first(), + ut.runCCD(trainData, trainPeriod, param.band) + )); + var ccdTS = ut.getTimeSeries(trainData, monitorData, ccdModel, pixel, param.band, 0.1); + var ccdTable = ut.transformToTable(ccdTS, ['dateString', 'train', 'monitor', 'fit']); + ccdTable.evaluate(function(t, e) { + var chart = ut.createCCDChart(t, param.band, coords.lat, coords.lon); + chart.onClick( + function(date) { + if (date === null) { + removeLayer('_'); + } else { + var img = ee.Image(ut.getImage(pixel, date, sensor)); + mapPanel.addLayer(img, param.vis, img.get('system:index').getInfo()); + removeLayer('Clicked'); + addPixel(coords); + } + } + ); + tsPanel.clear(); + tsPanel.add(chart); + }); +}; + + // run near-real-time monitoring for one sensor for one pixel +var runPixelSensorNRT = function(pixel, sensor) { + var trainData = ut.getData(pixel, trainPeriod, sensor); + var monitorData = ut.getData(pixel, monitorPeriod, sensor); + var param = null; + if (sensor == 'Sentinel-1') { + param = radParam; + } else { + param = optParam; + } + var ccdModel = ee.Image(ee.Algorithms.If( + ccd.filterMetadata('sensor', 'equals', sensor).first(), + ccd.filterMetadata('sensor', 'equals', sensor).first(), + ut.runCCD(trainData, trainPeriod, param.band) + )); + var ccdTS = ut.getTimeSeries(trainData, monitorData, ccdModel, pixel, param.band); + var Z = ee.FeatureCollection(ut.addPixelZScore(ccdTS, nrtParam.maxZ, param.minRMSE)); + var checked = ut.checkPixelZScore(Z, nrtParam.z); + if ((S2Check.getValue() | LSTCheck.getValue()) & param.strikeOnly) { + checked = checked.filterMetadata('Ball', 'equals', null); + } + return checked; +}; + + // run and plot NRT for a pixel +var chartNRT = function(coords) { + resetTSPanel(); + tsPanel.add(ui.Label('Running NRT...')); + var pixel = ee.Geometry.Point([coords.lon, coords.lat]); + addPixel(coords); + var nrtTS = ee.FeatureCollection([]); + if (S2Check.getValue()) {nrtTS = nrtTS.merge(runPixelSensorNRT(pixel, 'Sentinel-2'))} + if (S1Check.getValue()) {nrtTS = nrtTS.merge(runPixelSensorNRT(pixel, 'Sentinel-1'))} + if (LSTCheck.getValue()) {nrtTS = nrtTS.merge(runPixelSensorNRT(pixel, 'Landsat'))} + nrtTS = nrtTS.filterMetadata('x', 'not_equals', null); + if (nrtTS.size().gt(0)) { + var nrtMonitor = ee.FeatureCollection(ut.monitorPixelChange(nrtTS.sort('fitTime'), nrtParam)); + var nrt = ut.transformToTable(nrtMonitor, ['dateString', 'Z_train', 'Ball', 'Strike', 'StrikeOut']); + nrt.evaluate(function(t, e) { + var chart = ut.createNRTChart(t, coords.lat, coords.lon); + tsPanel.clear(); + tsPanel.add(chart); + }); + } else { + tsPanel.add(ui.Label('No sensor was selected.')); + } +}; + + // run near-real-time monitoring for one sensor for an area +var runAreaSensorNRT = function(area, sensor) { + var param = null; + if (sensor == 'Sentinel-1') { + param = radParam; + } else { + param = optParam; + } + var monitorData = ut.getData(area, monitorPeriod, sensor); + var ccdModel = ccd.filterMetadata('sensor', 'equals', sensor).first().updateMask(forestMask); + var ccdImg = ut.getCCDImage(ccdModel, param.band); + var synthetics = ut.addSynthetic(monitorData, ccdImg, param.band, sensor); + var monitorRes = ut.getResiduals(synthetics, param.band); + return ut.getChangeScores(monitorRes, ccdImg.select('.*rmse'), + synthetics.select(param.band).mean(), + param.minRMSE, nrtParam.z, param.strikeOnly); +}; + + // run near real time +var runNRT = function(area) { + var nrtTS = ee.ImageCollection([]); + if (S2Check.getValue()) {nrtTS = nrtTS.merge(runAreaSensorNRT(area, 'Sentinel-2'))} + if (S1Check.getValue()) {nrtTS = nrtTS.merge(runAreaSensorNRT(area, 'Sentinel-1'))} + if (LSTCheck.getValue()) {nrtTS = nrtTS.merge(runAreaSensorNRT(area, 'Landsat'))} + if (nrtTS.size().gt(0)) { + nrtTS = nrtTS.sort('system:time_start'); + return ut.monitorChange(nrtTS, nrtParam); + } else { + print('Nothing was selected.'); + return ee.Image(0); + } +}; + + // add pixel location +var addPixel = function(coords) { + var pSize = 0.000135; + var pixel = ee.Geometry.Rectangle([coords.lon - pSize, coords.lat - pSize, + coords.lon + pSize, coords.lat + pSize]); + mapPanel.addLayer(pixel, {color: '0000FF'}, 'Clicked'); +}; + + // remove a layer +var removeLayer = function(name) { + var layers = mapPanel.layers(); + var nLayer = layers.length(); + for (var i = nLayer-1; i >= 0; i--) { + var layer = layers.get(i); + if (layer.getName().match(name)) { + layers.remove(layer); + } + } +}; + + // reset the time series panel +var resetTSPanel = function() { + tsPanel.clear(); + removeLayer('_'); + removeLayer('Clicked'); +}; + +// --------------------------------------------------------------- +// UIs: + // map panel +var mapPanel = ui.Map({style: {cursor: 'crosshair'}}); +mapPanel.centerObject(testArea, 10); +mapPanel.setOptions('SATELLITE'); +mapPanel.addLayer(testArea, {color: 'red'}, 'Test Area'); +mapPanel.addLayer(forestMask, mskVisParam, 'Forest Mask', false); + + // menu panel +var trainButton = ui.Button('Train'); +var ccdButton = ui.Button('Fit'); +var nrtButton = ui.Button('Monitor'); +var runButton = ui.Button('Run'); +var saveButton = ui.Button('Save'); +var menuSet = ui.Panel([ccdButton, nrtButton, runButton], + ui.Panel.Layout.Flow('vertical')); +var ccdSelect = ui.Select(['Landsat', 'Sentinel-2', 'Sentinel-1'], 'Select sensor for CCD.', 'Landsat'); +var LSTCheck = ui.Checkbox('Landsat', true); +var S2Check = ui.Checkbox('Sentinel-2', true); +var S1Check = ui.Checkbox('Sentinel-1', false); +var selectSet = ui.Panel([ccdSelect, LSTCheck, S2Check, S1Check], + ui.Panel.Layout.Flow('vertical')); +var menuUISet = ui.Panel([menuSet, selectSet], ui.Panel.Layout.Flow('horizontal')); +var menuPanel = ui.Panel({ + widgets: [ui.Label('Menu'), menuUISet], + layout: ui.Panel.Layout.Flow('vertical'), + style: {width: '20%'}}); + + // ts panel +var tsPanel = ui.Panel({ + widgets: [], + style: {position: 'bottom-right', width: '80%'}}); + + // ui panel +var controlPanel = ui.Panel({ + style: {height: '30%'}, + widgets:[ui.SplitPanel(tsPanel, menuPanel, 'horizontal', false)]}); +var mapPanel2 = ui.Panel({ + style: {height: '70%'}, + widgets:[mapPanel]}); +var uiPanel = ui.SplitPanel(mapPanel2, controlPanel, 'vertical'); + +// --------------------------------------------------------------- +// Runtime functions: +trainButton.onClick(function() { + var saveCCD = function(ccd, sensor) { + Export.image.toAsset({ + image: ccd, + scale: 30, + assetId: 'projects/bu-nearrealtime/lite/ccd/' + sensor + '_CCD', + description: 'Save_' + sensor + '_CCD', + region: testArea, + maxPixels: 1e13, + pyramidingPolicy: {'.default': 'sample'} + }); + }; + var LST = ut.getData(testArea, trainPeriod, 'Landsat'); + saveCCD(ut.runCCD(LST, trainPeriod, 'NDFI').set({region: 'test', sensor: 'Landsat'}), 'LST'); + var S2 = ut.getData(testArea, trainPeriod, 'Sentinel-2'); + saveCCD(ut.runCCD(S2, trainPeriod, 'NDFI').set({region: 'test', sensor: 'Sentinel-2'}), 'S2'); + var S1 = ut.getData(testArea, trainPeriod, 'Sentinel-1'); + saveCCD(ut.runCCD(S1, trainPeriod, 'VV').set({region: 'test', sensor: 'Sentinel-1'}), 'S1'); +}); + +ccdButton.onClick(function() { + if (listener == 1) { + ccdButton.setLabel('Fit'); + listener = 0; + } else { + nrtButton.setLabel('Monitor'); + ccdButton.setLabel('Cancel'); + listener = 1; + } +}); + +nrtButton.onClick(function() { + if (listener == 2) { + nrtButton.setLabel('Monitor'); + listener = 0; + } else { + nrtButton.setLabel('Cancel'); + ccdButton.setLabel('Fit'); + listener = 2; + } +}); + +saveButton.onClick(function() { + Export.image.toAsset({ + image: alerts, + scale: 30, + description: 'SaveAlerts', + assetId: 'Alerts', + region: testArea, + maxPixels: 1e13}); +}); + +runButton.onClick(function() { + alerts = runNRT(testArea); + mapPanel.addLayer(alerts, altVisParam, 'Forest Disturbance Alerts'); + saveButton.setDisabled(false); +}); + +mapPanel.onClick(function(coords) { + if (listener == 1) { + chartCCD(coords); + } else if (listener == 2) { + chartNRT(coords); + } +}); + +// --------------------------------------------------------------- +// Initialization: +//saveButton.setDisabled(true); +ui.root.clear(); +ui.root.add(uiPanel); + +// End \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/FNRT_GUI.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/FNRT_GUI.py new file mode 100644 index 0000000..5afe408 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/FNRT_GUI.py @@ -0,0 +1,333 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +testArea = + + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-66.73156878460787, -8.662236005089952], + [-66.73156878460787, -8.916025640576244], + [-66.44867083538912, -8.916025640576244], + [-66.44867083538912, -8.662236005089952]]], None, False) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# Fusion Near Real-time (GUI) +# Near real-time monitoring of forest disturbance by fusion of +# multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu). + +# --------------------------------------------------------------- +# Model Parameters: +trainPeriod = ee.Dictionary({'start': '2017-01-01', 'end': '2020-01-01'}) +monitorPeriod = ee.Dictionary({'start': '2020-01-01', 'end': '2021-01-01'}) +fullPeriod = ee.Dictionary({ + 'start': trainPeriod.get('start'), + 'end': monitorPeriod.get('end')}) +nrtParam = {'z': 2, 'n': 4, 'm': 5, 'maxZ': 10} +optParam = { + 'band': 'NDFI', + 'minRMSE': 0.05, + 'strikeOnly': False, + 'vis': '{bands': ['SWIR1', 'NIR', 'Red'], 'min': 0, 'max': 5000} +} +radParam = { + 'band': 'VV', + 'minRMSE': 0.01, + 'strikeOnly': True, + 'vis': '{bands': ['VV', 'VH', 'ratio'], 'min': 10, 'max': 30} +} +mskVisParam = {'min': 0, 'max': 1, 'palette': ['blue', 'green']} +altVisParam = {'min': 2020.4, 'max': 2021, + 'palette': ['FF0080', 'EC1280', 'DA2480', 'C83680', 'B64880', 'A35B80', '916D80', + '7F7F80', '6D9180', '5BA380', '48B680', '36C880', '24DA80', '12EC80', + '00FF80', '00EB89', '00D793', '00C49D', '00B0A7', '009CB0', '0089BA', + '0075C4', '0062CE', '004ED7', '003AE1', '0027EB', '0013F5', '0000FF']} + +# --------------------------------------------------------------- +# Imports and predefined variables: +listener = 0 +ut = require('users/xjtang/fnrt:Lite/Utilities') +hansen = ee.Image('UMD/hansen/global_forest_change_2020_v1_8').unmask() +forestMask = hansen.select('treecover2000').gt(50) \ + .add(hansen.select('gain')) \ + .subtract(hansen.select('loss')) \ + .add(hansen.select('lossyear').eq(20)) \ + .gt(0) +alerts = None +ccd = ee.ImageCollection('projects/gee-book/assets/A3-5/ccd') + +# --------------------------------------------------------------- +# Main functions: + # run and plot CCD result for a pixel +def chartCCD(coords): + resetTSPanel() + sensor = ccdSelect.getValue() + pixel = ee.Geometry.Point([coords.lon, coords.lat]) + tsPanel.add(ui.Label('Running CCD on ' + sensor + ' data...')) + addPixel(coords) + param = None + if (sensor == 'Sentinel-1') { + param = radParam + } else { + param = optParam + } + trainData = ut.getData(pixel, trainPeriod, sensor) + monitorData = ut.getData(pixel, monitorPeriod, sensor) + ccdModel = ee.Image(ee.Algorithms.If( + ccd.filterMetadata('sensor', 'equals', sensor).first(), + ccd.filterMetadata('sensor', 'equals', sensor).first(), + ut.runCCD(trainData, trainPeriod, param.band) + )) + ccdTS = ut.getTimeSeries(trainData, monitorData, ccdModel, pixel, param.band, 0.1) + ccdTable = ut.transformToTable(ccdTS, ['dateString', 'train', 'monitor', 'fit']) + ccdTable.evaluate(function(t, e) { + chart = ut.createCCDChart(t, param.band, coords.lat, coords.lon) + chart.onClick( + def function(date): + if (date === None) { + removeLayer('_') + } else { + img = ee.Image(ut.getImage(pixel, date, sensor)) + mapPanel.addLayer(img, param.vis, img.get('system:index').getInfo()) + removeLayer('Clicked') + addPixel(coords) + } + + ) + tsPanel.clear() + tsPanel.add(chart) + }) + + + # run near-real-time monitoring for one sensor for one pixel +def runPixelSensorNRT(pixel, sensor): + trainData = ut.getData(pixel, trainPeriod, sensor) + monitorData = ut.getData(pixel, monitorPeriod, sensor) + param = None + if (sensor == 'Sentinel-1') { + param = radParam + } else { + param = optParam + } + ccdModel = ee.Image(ee.Algorithms.If( + ccd.filterMetadata('sensor', 'equals', sensor).first(), + ccd.filterMetadata('sensor', 'equals', sensor).first(), + ut.runCCD(trainData, trainPeriod, param.band) + )) + ccdTS = ut.getTimeSeries(trainData, monitorData, ccdModel, pixel, param.band) + Z = ee.FeatureCollection(ut.addPixelZScore(ccdTS, nrtParam.maxZ, param.minRMSE)) + checked = ut.checkPixelZScore(Z, nrtParam.z) + if ((S2Check.getValue() | LSTCheck.getValue()) & param.strikeOnly) { + checked = checked.filterMetadata('Ball', 'equals', None) + } + return checked + + + # run and plot NRT for a pixel +def chartNRT(coords): + resetTSPanel() + tsPanel.add(ui.Label('Running NRT...')) + pixel = ee.Geometry.Point([coords.lon, coords.lat]) + addPixel(coords) + nrtTS = ee.FeatureCollection([]) + if (S2Check.getValue()) {nrtTS = nrtTS.merge(runPixelSensorNRT(pixel, 'Sentinel-2'))} + if (S1Check.getValue()) {nrtTS = nrtTS.merge(runPixelSensorNRT(pixel, 'Sentinel-1'))} + if (LSTCheck.getValue()) {nrtTS = nrtTS.merge(runPixelSensorNRT(pixel, 'Landsat'))} + nrtTS = nrtTS.filterMetadata('x', 'not_equals', None) + if (nrtTS.size().gt(0)) { + nrtMonitor = ee.FeatureCollection(ut.monitorPixelChange(nrtTS.sort('fitTime'), nrtParam)) + nrt = ut.transformToTable(nrtMonitor, ['dateString', 'Z_train', 'Ball', 'Strike', 'StrikeOut']) + nrt.evaluate(function(t, e) { + chart = ut.createNRTChart(t, coords.lat, coords.lon) + tsPanel.clear() + tsPanel.add(chart) + }) + } else { + tsPanel.add(ui.Label('No sensor was selected.')) + } + + + # run near-real-time monitoring for one sensor for an area +def runAreaSensorNRT(area, sensor): + param = None + if (sensor == 'Sentinel-1') { + param = radParam + } else { + param = optParam + } + monitorData = ut.getData(area, monitorPeriod, sensor) + ccdModel = ccd.filterMetadata('sensor', 'equals', sensor).first().updateMask(forestMask) + ccdImg = ut.getCCDImage(ccdModel, param.band) + synthetics = ut.addSynthetic(monitorData, ccdImg, param.band, sensor) + monitorRes = ut.getResiduals(synthetics, param.band) + return ut.getChangeScores(monitorRes, ccdImg.select('.*rmse'), + synthetics.select(param.band).mean(), + param.minRMSE, nrtParam.z, param.strikeOnly) + + + # run near real time +def runNRT(area): + nrtTS = ee.ImageCollection([]) + if (S2Check.getValue()) {nrtTS = nrtTS.merge(runAreaSensorNRT(area, 'Sentinel-2'))} + if (S1Check.getValue()) {nrtTS = nrtTS.merge(runAreaSensorNRT(area, 'Sentinel-1'))} + if (LSTCheck.getValue()) {nrtTS = nrtTS.merge(runAreaSensorNRT(area, 'Landsat'))} + if (nrtTS.size().gt(0)) { + nrtTS = nrtTS.sort('system:time_start') + return ut.monitorChange(nrtTS, nrtParam) + } else { + print('Nothing was selected.') + return ee.Image(0) + } + + + # add pixel location +def addPixel(coords): + pSize = 0.000135 + pixel = ee.Geometry.Rectangle([coords.lon - pSize, coords.lat - pSize, + coords.lon + pSize, coords.lat + pSize]) + mapPanel.addLayer(pixel, {'color': '0000FF'}, 'Clicked') + + + # remove a layer +def removeLayer(name): + layers = mapPanel.layers() + nLayer = layers.length() + for i in range(nLayer-1, 0, -1): + layer = layers.get(i) + if (layer.getName().match(name)) { + layers.remove(layer) + } + + + + # reset the time series panel +def resetTSPanel(): + tsPanel.clear() + removeLayer('_') + removeLayer('Clicked') + + +# --------------------------------------------------------------- +# UIs: + # map panel +mapPanel = ui.Map({'style': '{cursor': 'crosshair'}}) +mapPanel.centerObject(testArea, 10) +mapPanel.setOptions('SATELLITE') +mapPanel.addLayer(testArea, {'color': 'red'}, 'Test Area') +mapPanel.addLayer(forestMask, mskVisParam, 'Forest Mask', False) + + # menu panel +trainButton = ui.Button('Train') +ccdButton = ui.Button('Fit') +nrtButton = ui.Button('Monitor') +runButton = ui.Button('Run') +saveButton = ui.Button('Save') +menuSet = ui.Panel([ccdButton, nrtButton, runButton], + ui.Panel.Layout.Flow('vertical')) +ccdSelect = ui.Select(['Landsat', 'Sentinel-2', 'Sentinel-1'], 'Select sensor for CCD.', 'Landsat') +LSTCheck = ui.Checkbox('Landsat', True) +S2Check = ui.Checkbox('Sentinel-2', True) +S1Check = ui.Checkbox('Sentinel-1', False) +selectSet = ui.Panel([ccdSelect, LSTCheck, S2Check, S1Check], + ui.Panel.Layout.Flow('vertical')) +menuUISet = ui.Panel([menuSet, selectSet], ui.Panel.Layout.Flow('horizontal')) +menuPanel = ui.Panel({ + 'widgets': [ui.Label('Menu'), menuUISet], + 'layout': ui.Panel.Layout.Flow('vertical'), + 'style': '{width': '20%'}}) + + # ts panel +tsPanel = ui.Panel({ + 'widgets': [], + 'style': '{position': 'bottom-right', 'width': '80%'}}) + + # ui panel +controlPanel = ui.Panel({ + 'style': '{height': '30%'}, + 'widgets':[ui.SplitPanel(tsPanel, menuPanel, 'horizontal', False)]}) +mapPanel2 = ui.Panel({ + 'style': '{height': '70%'}, + 'widgets':[mapPanel]}) +uiPanel = ui.SplitPanel(mapPanel2, controlPanel, 'vertical') + +# --------------------------------------------------------------- +# Runtime functions: +trainButton.onClick(function() { + def saveCCD(ccd, sensor): + Export.image.toAsset({ + 'image': ccd, + 'scale': 30, + 'assetId': 'projects/bu-nearrealtime/lite/ccd/' + sensor + '_CCD', + 'description': 'Save_' + sensor + '_CCD', + 'region': testArea, + 'maxPixels': 1e13, + 'pyramidingPolicy': {'.default': 'sample'} + }) + + LST = ut.getData(testArea, trainPeriod, 'Landsat') + saveCCD(ut.runCCD(LST, trainPeriod, 'NDFI').set({'region': 'test', 'sensor': 'Landsat'}), 'LST') + S2 = ut.getData(testArea, trainPeriod, 'Sentinel-2') + saveCCD(ut.runCCD(S2, trainPeriod, 'NDFI').set({'region': 'test', 'sensor': 'Sentinel-2'}), 'S2') + S1 = ut.getData(testArea, trainPeriod, 'Sentinel-1') + saveCCD(ut.runCCD(S1, trainPeriod, 'VV').set({'region': 'test', 'sensor': 'Sentinel-1'}), 'S1') +}) + +ccdButton.onClick(function() { + if (listener == 1) { + ccdButton.setLabel('Fit') + listener = 0 + } else { + nrtButton.setLabel('Monitor') + ccdButton.setLabel('Cancel') + listener = 1 + } +}) + +nrtButton.onClick(function() { + if (listener == 2) { + nrtButton.setLabel('Monitor') + listener = 0 + } else { + nrtButton.setLabel('Cancel') + ccdButton.setLabel('Fit') + listener = 2 + } +}) + +saveButton.onClick(function() { + Export.image.toAsset({ + 'image': alerts, + 'scale': 30, + 'description': 'SaveAlerts', + 'assetId': 'Alerts', + 'region': testArea, + 'maxPixels': 1e13}) +}) + +runButton.onClick(function() { + alerts = runNRT(testArea) + mapPanel.addLayer(alerts, altVisParam, 'Forest Disturbance Alerts') + saveButton.setDisabled(False) +}) + +mapPanel.onClick(function(coords) { + if (listener == 1) { + chartCCD(coords) + } else if (listener == 2) { + chartNRT(coords) + } +}) + +# --------------------------------------------------------------- +# Initialization: +#saveButton.setDisabled(True) +ui.root.clear() +ui.root.add(uiPanel) + +# End +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs.ipynb new file mode 100644 index 0000000..3779bc2 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs.ipynb @@ -0,0 +1,233 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# Fusion Near Real-time (Lite)\n", + "# Near real-time monitoring of forest disturbance by fusion of\n", + "# multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu).\n", + "\n", + "# Input data functions.\n", + "\n", + "# Load Landsat time series.\n", + "def loadLandsatData(region, period):\n", + " def c2ToSR(img):\n", + " return img.addBands({\n", + " 'srcImg': img.multiply(0.0000275).add(-0.2).multiply(10000),\n", + " 'names': img.bandNames(),\n", + " 'overwrite': True\n", + " })\n", + " \n", + "\n", + " def maskL8(img):\n", + " bands = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7']\n", + " sr = c2ToSR(img.select(bands)) \\\n", + " .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'])\n", + " validQA = [21824, 21888]\n", + " mask1 = img.select(['QA_PIXEL']) \\\n", + " .remap(validQA, ee.List.repeat(1, validQA.length), 0)\n", + " mask2 = sr.reduce(ee.Reducer.min()).gt(0)\n", + " mask3 = sr.reduce(ee.Reducer.max()).lt(10000)\n", + " return sr.updateMask(mask1.And(mask2).And(mask3))\n", + " \n", + "\n", + " def maskL7(img):\n", + " bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']\n", + " sr = c2ToSR(img.select(bands)) \\\n", + " .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'])\n", + " validQA = [5440, 5504]\n", + " mask1 = img.select('QA_PIXEL') \\\n", + " .remap(validQA, ee.List.repeat(1, validQA.length), 0)\n", + " mask2 = sr.reduce(ee.Reducer.min()).gt(0)\n", + " mask3 = sr.reduce(ee.Reducer.max()).lt(10000)\n", + " return sr.updateMask(mask1.And(mask2).And(mask3))\n", + " \n", + "\n", + " collection7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') \\\n", + " .filterBounds(region) \\\n", + " .filterDate(period.get('start'), period.get('end')) \\\n", + " .map(maskL7)\n", + " collection8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(region) \\\n", + " .filterDate(period.get('start'), period.get('end')) \\\n", + " .map(maskL8)\n", + " return ee.ImageCollection(collection7.merge(collection8))\n", + "\n", + "\n", + "# Load Sentinel-2 time series.\n", + "def loadS2Data(region, period):\n", + " def maskS2Img(img):\n", + " qa = img.select('QA60')\n", + " cloud = ee.Image(img.get('cloud_prob')).select('probability')\n", + " cloudProbMask = cloud.lt(65)\n", + " cloudBitMask = 1 << 10\n", + " cirrusBitMask = 1 << 11\n", + " mask = qa.bitwiseAnd(cloudBitMask).eq(0) \\\n", + " .And(qa.bitwiseAnd(cirrusBitMask).eq(0)) \\\n", + " .And(cloudProbMask)\n", + " return img.select(['B2', 'B3', 'B4', 'B8', 'B11', 'B12']) \\\n", + " .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']) \\\n", + " .updateMask(mask)\n", + " \n", + "\n", + " S2 = ee.ImageCollection('COPERNICUS/S2') \\\n", + " .filterBounds(region) \\\n", + " .filterDate(period.get('start'), period.get('end'))\n", + " S2Cloud = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') \\\n", + " .filterBounds(region) \\\n", + " .filterDate(period.get('start'), period.get('end'))\n", + " S2Joined = ee.ImageCollection(ee.Join.saveFirst('cloud_prob').apply({\n", + " 'primary': S2,\n", + " 'secondary': S2Cloud,\n", + " 'condition':\n", + " ee.Filter.equals({'leftField': 'system:index', 'rightField': 'system:index'})\n", + " }))\n", + "\n", + "def func_jwp(img):\n", + " return maskS2Img(img)\n", + "\n", + " masked = ee.ImageCollection(S2Joined.map(func_jwp\n", + "))\n", + "\n", + "))\n", + " return ee.ImageCollection(masked)\n", + "\n", + "\n", + "# Load Sentinel-1 time series.\n", + "def loadS1Data(region, period):\n", + " slopeLib = require('projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.js')\n", + "\n", + " def spatialMean(img):\n", + " st = img.get('system:time_start')\n", + " geom = img.geometry()\n", + " angle = img.select('angle')\n", + " edge = img.select('VV').lt(-30.0)\n", + " fmean = img.select('V.').add(30)\n", + " fmean = fmean.focal_mean(3, 'circle')\n", + " ratio = fmean.select('VH').divide(fmean.select('VV')).rename('ratio').multiply(30)\n", + " return img.select().addBands(fmean).addBands(ratio).addBands(angle).set('timeStamp', st)\n", + " \n", + "\n", + " S1 = ee.ImageCollection('COPERNICUS/S1_GRD') \\\n", + " .filterBounds(region).filterDate(period.get('start'), period.get('end')) \\\n", + " .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV')) \\\n", + " .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH')) \\\n", + " .filter(ee.Filter.eq('instrumentMode', 'IW')) \\\n", + " .select(['V.','angle']).map(spatialMean) \\\n", + " .select(['VH','VV','ratio','angle'])\n", + " passCount = ee.Dictionary(S1.aggregate_histogram('orbitProperties_pass'))\n", + " passValues = passCount.values().sort().reverse()\n", + " higherCount = passValues.get(0)\n", + " maxOrbitalPass = passCount.keys().get(passCount.values().indexOf(higherCount))\n", + " S1Filtered = S1.filter(ee.Filter.eq('orbitProperties_pass', maxOrbitalPass))\n", + " S1Corrected = slopeLib.slope_correction(S1Filtered)\n", + "\n", + "def func_twp(img):\n", + " st = img.get('timeStamp')\n", + " return img.addBands(img.select('VH').divide(img.select('VV')) \\\n", + " .rename('ratio').multiply(10)).set('system:time_start', st)\n", + "\n", + " return ee.ImageCollection(S1Corrected.map(func_twp\n", + "))\n", + "\n", + "\n", + "\n", + "))\n", + "\n", + "\n", + "# Exports.\n", + "exports = {\n", + " 'loadLandsatData': loadLandsatData,\n", + " 'loadS2Data': loadS2Data,\n", + " 'loadS1Data': loadS1Data\n", + "}\n", + "\n", + "# LGTM (nclinton). Reformatted and refactored." + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs.js new file mode 100644 index 0000000..8bc8822 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs.js @@ -0,0 +1,128 @@ +// Fusion Near Real-time (Lite) +// Near real-time monitoring of forest disturbance by fusion of +// multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu). + +// Input data functions. + +// Load Landsat time series. +var loadLandsatData = function(region, period) { + var c2ToSR = function(img) { + return img.addBands({ + srcImg: img.multiply(0.0000275).add(-0.2).multiply(10000), + names: img.bandNames(), + overwrite: true + }); + }; + + var maskL8 = function(img) { + var bands = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7']; + var sr = c2ToSR(img.select(bands)) + .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']); + var validQA = [21824, 21888]; + var mask1 = img.select(['QA_PIXEL']) + .remap(validQA, ee.List.repeat(1, validQA.length), 0); + var mask2 = sr.reduce(ee.Reducer.min()).gt(0); + var mask3 = sr.reduce(ee.Reducer.max()).lt(10000); + return sr.updateMask(mask1.and(mask2).and(mask3)); + }; + + var maskL7 = function(img) { + var bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7']; + var sr = c2ToSR(img.select(bands)) + .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']); + var validQA = [5440, 5504]; + var mask1 = img.select('QA_PIXEL') + .remap(validQA, ee.List.repeat(1, validQA.length), 0); + var mask2 = sr.reduce(ee.Reducer.min()).gt(0); + var mask3 = sr.reduce(ee.Reducer.max()).lt(10000); + return sr.updateMask(mask1.and(mask2).and(mask3)); + }; + + var collection7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') + .filterBounds(region) + .filterDate(period.get('start'), period.get('end')) + .map(maskL7); + var collection8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(region) + .filterDate(period.get('start'), period.get('end')) + .map(maskL8); + return ee.ImageCollection(collection7.merge(collection8)); +}; + +// Load Sentinel-2 time series. +var loadS2Data = function(region, period) { + var maskS2Img = function(img) { + var qa = img.select('QA60'); + var cloud = ee.Image(img.get('cloud_prob')).select('probability'); + var cloudProbMask = cloud.lt(65); + var cloudBitMask = 1 << 10; + var cirrusBitMask = 1 << 11; + var mask = qa.bitwiseAnd(cloudBitMask).eq(0) + .and(qa.bitwiseAnd(cirrusBitMask).eq(0)) + .and(cloudProbMask); + return img.select(['B2', 'B3', 'B4', 'B8', 'B11', 'B12']) + .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']) + .updateMask(mask); + }; + + var S2 = ee.ImageCollection('COPERNICUS/S2') + .filterBounds(region) + .filterDate(period.get('start'), period.get('end')); + var S2Cloud = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') + .filterBounds(region) + .filterDate(period.get('start'), period.get('end')); + var S2Joined = ee.ImageCollection(ee.Join.saveFirst('cloud_prob').apply({ + primary: S2, + secondary: S2Cloud, + condition: + ee.Filter.equals({leftField: 'system:index', rightField: 'system:index'}) + })); + var masked = ee.ImageCollection(S2Joined.map(function(img){ + return maskS2Img(img); + })); + return ee.ImageCollection(masked); +}; + +// Load Sentinel-1 time series. +var loadS1Data = function(region, period) { + var slopeLib = require('projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.js'); + + var spatialMean = function(img) { + var st = img.get('system:time_start'); + var geom = img.geometry(); + var angle = img.select('angle'); + var edge = img.select('VV').lt(-30.0); + var fmean = img.select('V.').add(30); + fmean = fmean.focal_mean(3, 'circle'); + var ratio = fmean.select('VH').divide(fmean.select('VV')).rename('ratio').multiply(30); + return img.select().addBands(fmean).addBands(ratio).addBands(angle).set('timeStamp', st); + }; + + var S1 = ee.ImageCollection('COPERNICUS/S1_GRD') + .filterBounds(region).filterDate(period.get('start'), period.get('end')) + .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV')) + .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH')) + .filter(ee.Filter.eq('instrumentMode', 'IW')) + .select(['V.','angle']).map(spatialMean) + .select(['VH','VV','ratio','angle']); + var passCount = ee.Dictionary(S1.aggregate_histogram('orbitProperties_pass')); + var passValues = passCount.values().sort().reverse(); + var higherCount = passValues.get(0); + var maxOrbitalPass = passCount.keys().get(passCount.values().indexOf(higherCount)); + var S1Filtered = S1.filter(ee.Filter.eq('orbitProperties_pass', maxOrbitalPass)); + var S1Corrected = slopeLib.slope_correction(S1Filtered); + return ee.ImageCollection(S1Corrected.map(function(img) { + var st = img.get('timeStamp'); + return img.addBands(img.select('VH').divide(img.select('VV')) + .rename('ratio').multiply(10)).set('system:time_start', st); + })); +}; + +// Exports. +exports = { + loadLandsatData: loadLandsatData, + loadS2Data: loadS2Data, + loadS1Data: loadS1Data +}; + +// LGTM (nclinton). Reformatted and refactored. \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs.py new file mode 100644 index 0000000..1940392 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Inputs.py @@ -0,0 +1,146 @@ +import ee +import geemap + +Map = geemap.Map() + +# Fusion Near Real-time (Lite) +# Near real-time monitoring of forest disturbance by fusion of +# multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu). + +# Input data functions. + +# Load Landsat time series. +def loadLandsatData(region, period): + def c2ToSR(img): + return img.addBands({ + 'srcImg': img.multiply(0.0000275).add(-0.2).multiply(10000), + 'names': img.bandNames(), + 'overwrite': True + }) + + + def maskL8(img): + bands = ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'] + sr = c2ToSR(img.select(bands)) \ + .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']) + validQA = [21824, 21888] + mask1 = img.select(['QA_PIXEL']) \ + .remap(validQA, ee.List.repeat(1, validQA.length), 0) + mask2 = sr.reduce(ee.Reducer.min()).gt(0) + mask3 = sr.reduce(ee.Reducer.max()).lt(10000) + return sr.updateMask(mask1.And(mask2).And(mask3)) + + + def maskL7(img): + bands = ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'] + sr = c2ToSR(img.select(bands)) \ + .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']) + validQA = [5440, 5504] + mask1 = img.select('QA_PIXEL') \ + .remap(validQA, ee.List.repeat(1, validQA.length), 0) + mask2 = sr.reduce(ee.Reducer.min()).gt(0) + mask3 = sr.reduce(ee.Reducer.max()).lt(10000) + return sr.updateMask(mask1.And(mask2).And(mask3)) + + + collection7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') \ + .filterBounds(region) \ + .filterDate(period.get('start'), period.get('end')) \ + .map(maskL7) + collection8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(region) \ + .filterDate(period.get('start'), period.get('end')) \ + .map(maskL8) + return ee.ImageCollection(collection7.merge(collection8)) + + +# Load Sentinel-2 time series. +def loadS2Data(region, period): + def maskS2Img(img): + qa = img.select('QA60') + cloud = ee.Image(img.get('cloud_prob')).select('probability') + cloudProbMask = cloud.lt(65) + cloudBitMask = 1 << 10 + cirrusBitMask = 1 << 11 + mask = qa.bitwiseAnd(cloudBitMask).eq(0) \ + .And(qa.bitwiseAnd(cirrusBitMask).eq(0)) \ + .And(cloudProbMask) + return img.select(['B2', 'B3', 'B4', 'B8', 'B11', 'B12']) \ + .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']) \ + .updateMask(mask) + + + S2 = ee.ImageCollection('COPERNICUS/S2') \ + .filterBounds(region) \ + .filterDate(period.get('start'), period.get('end')) + S2Cloud = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') \ + .filterBounds(region) \ + .filterDate(period.get('start'), period.get('end')) + S2Joined = ee.ImageCollection(ee.Join.saveFirst('cloud_prob').apply({ + 'primary': S2, + 'secondary': S2Cloud, + 'condition': + ee.Filter.equals({'leftField': 'system:index', 'rightField': 'system:index'}) + })) + +def func_jwp(img): + return maskS2Img(img) + + masked = ee.ImageCollection(S2Joined.map(func_jwp +)) + +)) + return ee.ImageCollection(masked) + + +# Load Sentinel-1 time series. +def loadS1Data(region, period): + slopeLib = require('projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.js') + + def spatialMean(img): + st = img.get('system:time_start') + geom = img.geometry() + angle = img.select('angle') + edge = img.select('VV').lt(-30.0) + fmean = img.select('V.').add(30) + fmean = fmean.focal_mean(3, 'circle') + ratio = fmean.select('VH').divide(fmean.select('VV')).rename('ratio').multiply(30) + return img.select().addBands(fmean).addBands(ratio).addBands(angle).set('timeStamp', st) + + + S1 = ee.ImageCollection('COPERNICUS/S1_GRD') \ + .filterBounds(region).filterDate(period.get('start'), period.get('end')) \ + .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV')) \ + .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH')) \ + .filter(ee.Filter.eq('instrumentMode', 'IW')) \ + .select(['V.','angle']).map(spatialMean) \ + .select(['VH','VV','ratio','angle']) + passCount = ee.Dictionary(S1.aggregate_histogram('orbitProperties_pass')) + passValues = passCount.values().sort().reverse() + higherCount = passValues.get(0) + maxOrbitalPass = passCount.keys().get(passCount.values().indexOf(higherCount)) + S1Filtered = S1.filter(ee.Filter.eq('orbitProperties_pass', maxOrbitalPass)) + S1Corrected = slopeLib.slope_correction(S1Filtered) + +def func_twp(img): + st = img.get('timeStamp') + return img.addBands(img.select('VH').divide(img.select('VV')) \ + .rename('ratio').multiply(10)).set('system:time_start', st) + + return ee.ImageCollection(S1Corrected.map(func_twp +)) + + + +)) + + +# Exports. +exports = { + 'loadLandsatData': loadLandsatData, + 'loadS2Data': loadS2Data, + 'loadS1Data': loadS1Data +} + +# LGTM (nclinton). Reformatted and refactored. +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Utilities.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Utilities.js new file mode 100644 index 0000000..692de2b --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/Utilities.js @@ -0,0 +1,864 @@ +// Fusion Near Real-time (Lite). +// Near real-time monitoring of forest disturbance by fusion of +// multi-sensor data. @author Xiaojing Tang (xjtang@bu.edu). + +// Utility functions. + +// Common utilities. +var runCCD = function(col, period, band) { + var prepareData = function(col, band) { + return ee.ImageCollection(col.map(function(img){ + return addDependents(img + .select(band)) + .select(['INTP', 'SLP', 'COS', 'SIN', 'COS2', 'SIN2', 'COS3', 'SIN3', band]) + .updateMask(img.select(band).mask()); + })); + }; + var addDependents = function(img){ + var t = ee.Number(convertDateFormat(ee.Date(img.get('system:time_start')), 1)); + var omega = 2.0 * Math.PI; + var dependents = ee.Image.constant([1, t, t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin()]).float() + .rename(['INTP', 'SLP', 'COS', 'SIN', 'COS2', 'SIN2', 'COS3', 'SIN3']); + return img.addBands(dependents); + }; + var col2 = prepareData(col, band); + var ccd = col2 + .reduce(ee.Reducer.robustLinearRegression(8, 1), 4) + .rename([band + '_coefs', band + '_rmse']); + return ccd.select(band + '_coefs') + .arrayTranspose() + .addBands(ccd.select(band + '_rmse')); +}; + +var convertDateFormat = function(date, format) { + if (format == 0) { + var epoch = 719529; + var days = date.difference(ee.Date('1970-01-01'), 'day'); + return days.add(epoch); + } else if (format == 1) { + var year = date.get('year'); + var fYear = date.difference(ee.Date.fromYMD(year, 1, 1), 'year'); + return year.add(fYear); + } else { + return date.millis(); + } +}; + +var getData = function(region, params, sensor, endMembers) { + if (sensor == 'Sentinel-2') { + return(getSen2TS(region, params, endMembers)); + } else if (sensor == 'Sentinel-1') { + return(getSen1TS(region, params)); + } else { + return(getLandsatTS(region, params, endMembers)); + } +}; + +var getImage = function(region, date, sensor) { + if (sensor == 'Sentinel-2') { + return(getSen2Img(region, date)); + } else if (sensor == 'Sentinel-1') { + return(getSen1Img(region, date)); + } else { + return(getLandsatImage(region, date)); + } +}; + +var harmonicFit = function(t, coef, dateFormat) { + var PI2 = 2.0 * Math.PI; + var OMEGAS = [PI2 / 365.25, PI2, + PI2 / (1000 * 60 * 60 * 24 * 365.25)]; + var omega = OMEGAS[dateFormat]; + return coef.get([0]) + .add(coef.get([1]).multiply(t)) + .add(coef.get([2]).multiply(t.multiply(omega).cos())) + .add(coef.get([3]).multiply(t.multiply(omega).sin())) + .add(coef.get([4]).multiply(t.multiply(omega * 2).cos())) + .add(coef.get([5]).multiply(t.multiply(omega * 2).sin())) + .add(coef.get([6]).multiply(t.multiply(omega * 3).cos())) + .add(coef.get([7]).multiply(t.multiply(omega * 3).sin())); +}; + +var getCCDImage = function(ccd, band) { + band = band + '_'; + var genCoefImg = function(ccd, band, coef) { + var zeros = ee.Array(0).repeat(0, 1); + var coefImg = ccd + .select(band + coef) + .arrayCat(zeros, 0) + .float() + .arraySlice(0, 0, 1); + return ee.Image(coefImg + .arrayFlatten([[ee.String('S1_').cat(band).cat(coef)]])); + }; + var genHarmImg = function(ccd, band) { + var harms = ['INTP', 'SLP', 'COS', 'SIN', 'COS2', 'SIN2', 'COS3', 'SIN3']; + var zeros = ee.Image(ee.Array([ee.List.repeat(0, harms.length)])) + .arrayRepeat(0, 1); + var coefImg = ccd + .select(band + 'coefs') + .arrayCat(zeros, 0) + .float() + .arraySlice(0, 0, 1); + return ee.Image(coefImg + .arrayFlatten([[ee.String('S1_').cat(band).cat('coef')], harms])); + }; + var rmse = genCoefImg(ccd, band, 'rmse'); + var coef = genHarmImg(ccd, band); + return ee.Image.cat(rmse, coef); +}; + +// Near-real-time utilities. +var addSynthetic = function(data, ccd, band, sensor) { + var genSyntImg = function(ccd, img, band, sensor) { + var date = convertDateFormat(ee.Date(img.get('system:time_start')), 1); + var dateString = ee.Date(img.get('system:time_start')) + .format('yyyyMMdd'); + var coefs = ['INTP', 'SLP', 'COS', 'SIN', 'COS2', 'SIN2', 'COS3', 'SIN3']; + var coef = ee.Image(coefs.map(function(coef){ + return ccd.select('.*'.concat(band).concat('.*').concat(coef)); + })).rename(coefs); + var t = ee.Number(date); + var omega = 2.0 * Math.PI; + var synt = ee.Image.constant([1, t, t.multiply(omega).cos(), + t.multiply(omega).sin(), + t.multiply(omega * 2).cos(), + t.multiply(omega * 2).sin(), + t.multiply(omega * 3).cos(), + t.multiply(omega * 3).sin()]).float(); + return synt + .multiply(coef) + .reduce('sum') + .addBands(img, [band]) + .rename(['synt', band]) + .set({ + 'sensor': sensor, + 'system:time_start': img.get('system:time_start'), + 'dateString': dateString + }); + }; + + return ee.ImageCollection(data.map(function(img){ + return genSyntImg(ccd, img, band, sensor); + })); +}; + +var getResiduals = function(data, band) { + return ee.ImageCollection(data.map(function(img) { + return img + .select('synt') + .where(img.select('synt').gt(10000), 10000) + .subtract(img.select(band)) + .rename('residual') + .set({ + 'sensor': img.get('sensor'), + 'system:time_start': img.get('system:time_start'), + 'dateString': img.get('dateString') + }); + })); +}; + +var getChangeScores = function(data, rmse, mean, + minSTD, threshold, strikeOnly) { + var mask = ee.Image(0); + if (strikeOnly) {mask = ee.Image(1)} + return ee.ImageCollection(data.map(function(img) { + var z = img.divide(rmse.max(mean.abs().multiply(minSTD))); + var strike = z.multiply(z.gt(threshold)); + var zStack = ee.Image.cat(z, strike) + .rename(['z', 'strike']) + .set({ + 'sensor': img.get('sensor'), + 'system:time_start': img.get('system:time_start') + }); + return zStack.updateMask(strike.gt(0).or(mask)); + })); +}; + +var monitorChange = function(zScores, nrtParam) { + var zeros = ee.Image(0) + .addBands(ee.Image(0)) + .rename(['change', 'date']); + var shift = Math.pow(2, nrtParam.m - 1) - 1; + var monitor = function(img, result) { + var change = ee.Image(result).select('change'); + var date = ee.Image(result).select('date'); + var shiftImg = img + .select('z') + .mask() + .eq(0) + .multiply(shift + 1) + .add(shift); + change = change + .bitwiseAnd(shiftImg) + .multiply(shiftImg.eq(shift).add(1)) + .add(img.select('strike').unmask().gt(0)); + date = date + .add(change.bitCount().gte(nrtParam.n) + .multiply(date.eq(0)) + .multiply(ee.Number(convertDateFormat( + ee.Date(img.get('system:time_start')), 1)))); + return(change.addBands(date)); + }; + return ee.Image(zScores.iterate(monitor, zeros)) + .select('date') + .rename('Alerts') + .selfMask(); +}; + +// Landsat utilities. +var getLandsatImage = function(region, date) { + var collection7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') + .filterBounds(region); + var collection8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(region); + var col7NoClouds = collection7.map(maskL7); + var col8NoClouds = collection8.map(maskL8); + var colNoClouds = col7NoClouds.merge(col8NoClouds); + var imDate = ee.Date(date); + var befDate = imDate.advance(-1, 'day'); + var aftDate = imDate.advance(1, 'day'); + var selectedImage = colNoClouds.filterDate(befDate, aftDate); + return ee.Algorithms.If( + selectedImage.size().gt(0), + selectedImage.first(), + null + ); +}; + +var getLandsatTS = function(region, params) { + var collection7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') + .filterBounds(region) + .filterDate(params.get('start'), params.get('end')); + var collection8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(region) + .filterDate(params.get('start'), params.get('end')); + var col7NoClouds = collection7.map(maskL7); + var col8NoClouds = collection8.map(maskL8); + var colNoClouds = col7NoClouds.merge(col8NoClouds); + return ee.ImageCollection(unmixing(colNoClouds)); +}; + +var c2ToSR = function(img) { + return img + .addBands( + img.multiply(0.0000275).add(-0.2).multiply(10000), + img.bandNames(), + true + ); +}; + +var maskL7 = function(img) { + var sr = c2ToSR(img + .select(['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'])) + .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']); + var validQA = [5440, 5504]; + var mask1 = img + .select('QA_PIXEL') + .remap(validQA, ee.List.repeat(1, validQA.length), 0); + var mask2 = sr.reduce(ee.Reducer.min()).gt(0); + var mask3 = sr.reduce(ee.Reducer.max()).lt(10000); + return sr.updateMask(mask1.and(mask2).and(mask3)); +}; + +var maskL8 = function(img) { + var sr = c2ToSR(img + .select(['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'])) + .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']); + var validQA = [21824, 21888]; + var mask1 = img + .select(['QA_PIXEL']) + .remap(validQA, ee.List.repeat(1, validQA.length), 0); + var mask2 = sr.reduce(ee.Reducer.min()).gt(0); + var mask3 = sr.reduce(ee.Reducer.max()).lt(10000); + return sr.updateMask(mask1.and(mask2).and(mask3)); +}; + +var unmixing = function(col) { + var gv = [500, 900, 400, 6100, 3000, 1000]; + var npv = [1400, 1700, 2200, 3000, 5500, 3000]; + var soil = [2000, 3000, 3400, 5800, 6000, 5800]; + var shade = [0, 0, 0, 0, 0, 0]; + var cloud = [9000, 9600, 8000, 7800, 7200, 6500]; + var cfThreshold = 0.05; + return col.map(function(img){ + var unmixed = img + .select(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']) + .unmix([gv, shade, npv, soil, cloud], true, true) + .rename(['GV', 'Shade', 'NPV', 'Soil', 'Cloud']); + var maskCloud = unmixed.select('Cloud').lt(cfThreshold); + var maskShade = unmixed.select('Shade').lt(1); + var NDFI = unmixed.expression( + '10000 * ((GV / (1 - SHADE)) - (NPV + SOIL)) / ((GV / (1 - SHADE)) + (NPV + SOIL))', + { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).rename('NDFI'); + var maskNDFI = unmixed.expression( + '(GV / (1 - SHADE)) + (NPV + SOIL)', + { + 'GV': unmixed.select('GV'), + 'SHADE': unmixed.select('Shade'), + 'NPV': unmixed.select('NPV'), + 'SOIL': unmixed.select('Soil') + }).gt(0); + return img + .addBands(unmixed.select(['GV','Shade','NPV','Soil']) + .multiply(10000)) + .addBands(NDFI) + .updateMask(maskCloud) + .updateMask(maskNDFI) + .updateMask(maskShade); + }); +}; + +var spatialFilter = function(img, minSize) { + var connected = img + .reduceConnectedComponents(ee.Reducer.sum()) + .rename('size'); + return img.updateMask(connected.gte(minSize)); +}; + +// Sentinel-2 utilities. +var getSen2TS = function(region, params) { + var S2 = ee.ImageCollection('COPERNICUS/S2') + .filterBounds(region) + .filterDate(params.get('start'), params.get('end')); + var S2Cloud = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') + .filterBounds(region) + .filterDate(params.get('start'), params.get('end')); + var S2Joined = ee.ImageCollection(ee.Join.saveFirst('cloud_prob') + .apply({ + primary: S2, + secondary: S2Cloud, + condition:ee.Filter.equals({ + leftField: 'system:index', + rightField: 'system:index' + }) + })); + var masked = ee.ImageCollection(S2Joined.map(function(img){ + return maskSen2Img(img); + })); + return ee.ImageCollection(unmixing(masked)); +}; + +var getSen2Img = function(region, date) { + var imDate = ee.Date(date); + var befDate = imDate.advance(-1, 'day'); + var aftDate = imDate.advance(1, 'day'); + var S2 = ee.ImageCollection('COPERNICUS/S2') + .filterBounds(region) + .filterDate(befDate, aftDate); + var S2Cloud = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') + .filterBounds(region) + .filterDate(befDate, aftDate); + var S2Joined = ee.ImageCollection(ee.Join.saveFirst('cloud_prob') + .apply({ + primary: S2, + secondary: S2Cloud, + condition: ee.Filter.equals({ + leftField: 'system:index', + rightField: 'system:index' + }) + })); + return ee.Algorithms.If( + S2Joined.size().gt(0), + maskSen2Img(S2Joined.first()), + null + ); +}; + +var maskSen2Img = function(img) { + var qa = img.select('QA60'); + var cloud = ee.Image(img.get('cloud_prob')) + .select('probability'); + var cloudProbMask = cloud.lt(65); + var cloudBitMask = 1 << 10; + var cirrusBitMask = 1 << 11; + var mask = qa.bitwiseAnd(cloudBitMask).eq(0) + .and(qa.bitwiseAnd(cirrusBitMask).eq(0)) + .and(cloudProbMask); + return img + .select(['B2', 'B3', 'B4', 'B8', 'B11', 'B12']) + .rename(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']) + .updateMask(mask); +}; + +// Sentinel-1 utilities. +var getSen1TS = function(region, params){ + var spatialSmoothing = function(img) { + var st = img.get('system:time_start'); + var geom = img.geometry(); + var angle = img.select('angle'); + var edge = img.select('VV').lt(-30.0); + var fmean = img.select('V.').add(30); + fmean = fmean.focal_mean(3, 'circle'); + var ratio = fmean + .select('VH') + .divide(fmean.select('VV')) + .rename('ratio') + .multiply(30); + return img + .select() + .addBands(fmean) + .addBands(ratio) + .addBands(angle) + .set('timeStamp', st); + }; + + var slopeCorrection = function(col){ + var model = 'volume'; + var elevation = ee.Image('USGS/SRTMGL1_003'); + var buffer = 0; + var ninetyRad = ee.Image.constant(90) + .multiply(Math.PI/180); + + function _volume_model(theta_iRad, alpha_rRad) { + var nominator = (ninetyRad.subtract(theta_iRad) + .add(alpha_rRad)) + .tan(); + var denominator = (ninetyRad.subtract(theta_iRad)) + .tan(); + return nominator.divide(denominator); + } + + function _surface_model(theta_iRad, alpha_rRad, alpha_azRad) { + var nominator = (ninetyRad.subtract(theta_iRad)).cos(); + var denominator = alpha_azRad + .cos() + .multiply((ninetyRad.subtract(theta_iRad) + .add(alpha_rRad)).cos()); + return nominator.divide(denominator); + } + + function _erode(img, distance) { + var d = img + .not() + .unmask(1) + .fastDistanceTransform(30) + .sqrt() + .multiply(ee.Image.pixelArea() + .sqrt()); + return img.updateMask(d.gt(distance)); + } + + function _masking(alpha_rRad, theta_iRad, proj, buffer) { + var layover = alpha_rRad.lt(theta_iRad).rename('layover'); + var shadow = alpha_rRad + .gt(ee.Image.constant(-1).multiply(ninetyRad.subtract(theta_iRad))) + .rename('shadow'); + var mask = layover.and(shadow); + if (buffer > 0) {mask = _erode(mask, buffer)} + return mask.rename('no_data_mask'); + } + + function _correct(image) { + var geom = image.geometry(); + var proj = image.select(1).projection(); + var heading = ee.Terrain.aspect(image.select('angle')) + .reduceRegion(ee.Reducer.mean(), geom, 1000) + .get('aspect'); + var sigma0Pow = ee.Image.constant(10) + .pow(image.divide(10.0)); + var theta_iRad = image.select('angle') + .multiply(Math.PI/180) + .clip(geom); + var phi_iRad = ee.Image.constant(heading) + .multiply(Math.PI/180); + var alpha_sRad = ee.Terrain.slope(elevation) + .select('slope') + .multiply(Math.PI/180) + .setDefaultProjection(proj) + .clip(geom); + var phi_sRad = ee.Terrain.aspect(elevation) + .select('aspect') + .multiply(Math.PI/180) + .setDefaultProjection(proj) + .clip(geom); + var phi_rRad = phi_iRad.subtract(phi_sRad); + var alpha_rRad = (alpha_sRad.tan().multiply(phi_rRad.cos())) + .atan(); + var alpha_azRad = (alpha_sRad.tan().multiply(phi_rRad.sin())) + .atan(); + var gamma0 = sigma0Pow.divide(theta_iRad.cos()); + var corrModel = _volume_model(theta_iRad, alpha_rRad); + var gamma0_flat = gamma0.divide(corrModel); + var gamma0_flatDB = ee.Image.constant(10) + .multiply(gamma0_flat.log10()) + .select(['VV', 'VH']); + var mask = _masking(alpha_rRad, theta_iRad, proj, buffer); + return gamma0_flatDB + .addBands(mask) + .copyProperties(image); + } + return col.map(_correct); + }; + + var S1 = ee.ImageCollection('COPERNICUS/S1_GRD') + .filterBounds(region) + .filterDate(params.get('start'), params.get('end')) + .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV')) + .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH')) + .filter(ee.Filter.eq('instrumentMode', 'IW')) + .select(['V.','angle']) + .map(spatialSmoothing) + .select(['VH','VV','ratio','angle']); + var passCount = ee.Dictionary(S1.aggregate_histogram('orbitProperties_pass')); + var passValues = passCount.values().sort().reverse(); + var higherCount = passValues.get(0); + var maxOrbitalPass = passCount + .keys() + .get(passCount.values().indexOf(higherCount)); + var S1Filtered = S1.filter(ee.Filter.eq( + 'orbitProperties_pass', + maxOrbitalPass + )); + var S1Corrected = slopeCorrection(S1Filtered); + return ee.ImageCollection(S1Corrected.map(function(img) { + var st = img.get('timeStamp'); + return img + .addBands(img.select('VH').divide(img.select('VV')) + .rename('ratio') + .multiply(10)) + .set('system:time_start', st); + })); +}; + +var getSen1Img = function(region, date) { + var addRatio = function(img) { + var img2 = img.add(30); + var ratio = img + .select('VH') + .divide(img.select('VV')) + .rename('ratio') + .multiply(30); + return img + .select() + .addBands(img2) + .addBands(ratio); + }; + var S1 = ee.ImageCollection('COPERNICUS/S1_GRD') + .filterBounds(region); + var imDate = ee.Date(date); + var befDate = imDate.advance(-1, 'day'); + var aftDate = imDate.advance(1, 'day'); + var col = S1.filterDate(befDate, aftDate); + return ee.Algorithms.If( + col.size().gt(0), + addRatio(col.first()), + null + ); +}; + +// Plotting utilities. +var getTimeSeries = function(train, monitor, ccd, geometry, band, padding) { + var dateFormat = 1; + var proj = ee.Projection('EPSG:4326').atScale(10); + var ccdFits = ccd.reduceRegion({ + reducer: ee.Reducer.first(), + geometry: geometry, + crs: proj}); + var coef = ccdFits.getArray(band + '_coefs').project([1]); + var rmse = ccdFits.getArray(band + '_rmse').get([0]); + + function produceTrainSeries(collection, geometry, band) { + if (padding) { + collection = collection.sort('system:time_start'); + var first = collection.first(); + var last = collection.sort('system:time_start', false).first(); + var fakeDates = ee.List.sequence( + first.date().get('year'), + last.date().get('year'), + padding + ).map(function(t) { + var fYear = ee.Number(t); + var year = fYear.floor(); + return ee.Date.fromYMD(year, 1, 1) + .advance(fYear.subtract(year), 'year'); + }); + fakeDates = fakeDates.map(function(d) { + return ee.Image() + .rename(band) + .set('system:time_start', ee.Date(d).millis()); + }); + collection = collection.merge(fakeDates); + } + collection = collection.sort('system:time_start'); + var timeSeries = collection.map(function(img) { + var time = convertDateFormat(img.date(), dateFormat); + var value = img.select(band).reduceRegion({ + reducer: ee.Reducer.first(), + geometry: geometry, + crs: proj + }).getNumber(band); + var fit = harmonicFit(time, ee.Array(coef), dateFormat); + var residual = ee.Algorithms.If( + value, + fit.subtract(value), + value + ); + return ee.Feature(geometry).set({ + train: value, + x: value, + fitTime: time, + fit: fit, + residual: residual, + dateString: img + .date() + .format('YYYY-MM-dd'), + rmse: rmse, + trainFitTime: time + }); + }); + return timeSeries; + } + + function produceMonitorSeries(collection, geometry, band) { + if (padding) { + collection = collection.sort('system:time_start'); + var first = collection.first(); + var last = collection.sort('system:time_start', false).first(); + var fakeDates = ee.List.sequence( + first.date().get('year'), + last.date().get('year'), + padding + ).map(function(t) { + var fYear = ee.Number(t); + var year = fYear.floor(); + return ee.Date.fromYMD(year, 1, 1) + .advance(fYear.subtract(year), 'year')}); + fakeDates = fakeDates.map(function(d) { + return ee.Image() + .rename(band) + .set('system:time_start', ee.Date(d).millis()); + }); + collection = collection.merge(fakeDates); + } + collection = collection.sort('system:time_start'); + return collection.map(function(img) { + var time = convertDateFormat(img.date(), dateFormat); + var value = img.select(band).reduceRegion({ + reducer: ee.Reducer.first(), + geometry: geometry, + crs: proj + }).getNumber(band); + var fit = harmonicFit(time, ee.Array(coef), dateFormat); + var residual = ee.Algorithms.If( + value, + fit.subtract(value), + value + ); + return ee.Feature(geometry).set({ + monitor: value, + fitTime: time, + fit: fit, + x: residual, + rmse: rmse, + dateString: img + .date() + .format('YYYY-MM-dd'), + monitorFitTime: time, + }); + }); + } + + return produceTrainSeries(train, geometry, band) + .merge(produceMonitorSeries(monitor, geometry, band)); +}; + +var transformToTable = function(ccdTS, colNames) { + var listLen = colNames.length; + return ccdTS + .reduceColumns(ee.Reducer.toList(listLen, listLen), colNames) + .get('list'); +}; + +var createCCDChart = function(table, band, lat, lon) { + function formatTable(table) { + var cols = [ + {id: 'A', label: 'Date', type: 'date'}, + {id: 'B', label: 'Training', type: 'number'}, + {id: 'C', label: 'Monitoring', type: 'number'}, + {id: 'D', label: 'Fit', type: 'number'} + ]; + var values = table.map(function(list) { + return {c: list.map(function(item, index) { + return {'v': index == 0 ? new Date(item): item}; + })}; + }); + return {cols: cols, rows: values}; + } + var formatted = formatTable(table); + var chart = ui.Chart(formatted, 'LineChart', { + title: 'Pixel located at ' + lat.toFixed(3) + ', ' + lon.toFixed(3), + pointSize: 0, + series: { + 0: { pointSize: 1.8, lineWidth: 0}, + 1: { pointSize: 1.8, lineWidth: 0} + }, + vAxis: { + title: band, + }, + height: '90%', + stretch: 'both' + }); + return chart; +}; + +var addPixelZScore = function(timeSeries, maxZ, minRMSE){ + var values = timeSeries.aggregate_array('train'); + var minSD = ee.Number( + timeSeries + .aggregate_array('train') + .reduce(ee.Reducer.mean())) + .abs() + .multiply(minRMSE); + var rmse = ee.Number(timeSeries.first().get('rmse')) + .max(minRMSE); + return timeSeries.map(function(img) { + var x = img.get('x'); + var residual = img.get('residual'); + var train = img.get('trainFitTime'); + return ee.Algorithms.If( + train, + img.set({Z_train: ee.Number( + ee.Algorithms.If( + ee.Number(residual).divide(rmse).gt(maxZ), + maxZ, + ee.Number(residual).divide(rmse) + ) + )}), + ee.Algorithms.If( + x, + img.set({Z_monitor: ee.Number( + ee.Algorithms.If( + ee.Number(x).divide(rmse).gt(maxZ), + maxZ, + ee.Number(x).divide(rmse) + ) + )}), + img + ) + ); + }); +}; + +var checkPixelZScore = function(timeSeries, threshold) { + return timeSeries.map(function(img) { + var x = img.get('Z_monitor'); + return ee.Algorithms.If( + x, + ee.Algorithms.If( + ee.Number(x).gt(threshold), + img.set({Strike: x}), + img.set({Ball: x}) + ), + img); + }); +}; + +var monitorPixelChange = function(zScoreSeries, nrtParam) { + var nrtDetect = function(zScores, nrtParam) { + return ee.Number(ee.List(zScores.iterate(function(img, flags){ + flags = ee.List(flags); + return ee.Algorithms.If( + ee.Number(flags.get(-1)).gt(1), + flags, + ee.Algorithms.If( + img.get('Strike'), + ee.Algorithms.If( + flags.slice(1).add(1).frequency(1).gte(nrtParam.n), + flags.add(img.get('fitTime')), + flags.slice(1).add(1) + ), + flags.slice(1).add(0) + ) + ); + }, ee.List.repeat(0, nrtParam.m))).get(-1)); + }; + var flag = nrtDetect(zScoreSeries, nrtParam); + return ee.Algorithms.If( + flag.gt(0), + zScoreSeries.map(function(img){ + var date = img.get('fitTime'); + var z = img.get('Strike'); + return ee.Algorithms.If( + flag.eq(date), + img.set({StrikeOut: z, Strike: null}), + img + ); + }), + zScoreSeries + ); +}; + +var createNRTChart = function(table, lat, lon) { + function formatTable(table) { + var cols = [ + {id: 'A', label: 'Date', type: 'date'}, + {id: 'B', label: 'Training', type: 'number'}, + {id: 'C', label: 'Ball', type: 'number'}, + {id: 'D', label: 'Strike', type: 'number'}, + {id: 'E', label: 'StrikeOut', type: 'number'} + ]; + var values = table.map(function(list) { + return {c: list.map(function(item, index) { + return {'v': index == 0 ? new Date(item): item}; + })}; + }); + return {cols: cols, rows: values}; + } + var formatted = formatTable(table); + var chart = ui.Chart(formatted, 'ScatterChart', { + title: 'Pixel located at ' + lat.toFixed(3) + ', ' + lon.toFixed(3), + pointSize: 1.8, + vAxis: { + title: 'Z Score', + viewWindowMode: 'explicit', + }, + height: '90%', + stretch: 'both' + }); + return chart; +}; + +// --------------------------------------------------------------- +// Exports +exports = { + getData: getData, + getImage: getImage, + getLandsatImage: getLandsatImage, + getLandsatTS: getLandsatTS, + getSen2TS: getSen2TS, + getSen2Img: getSen2Img, + getSen1TS: getSen1TS, + getSen1Img: getSen1Img, + runCCD: runCCD, + transformToTable: transformToTable, + createCCDChart: createCCDChart, + getTimeSeries: getTimeSeries, + addPixelZScore: addPixelZScore, + checkPixelZScore: checkPixelZScore, + monitorPixelChange: monitorPixelChange, + createNRTChart: createNRTChart, + getCCDImage: getCCDImage, + addSynthetic: addSynthetic, + getResiduals: getResiduals, + getChangeScores: getChangeScores, + monitorChange: monitorChange, + spatialFilter: spatialFilter +}; + +// Comments (nclinton). This is too much for me to reformat. +// Please adhere to Google JavaScript stype guidelines as +// described in: +// https://docs.google.com/document/d/19KQBEDA-hYQEg4EizWOXPRNLmeOyc77YqEkqtHH6770/edit?usp=sharing&resourcekey=0-SRpYwdFqCLHgB5rA145AAw + +// LGTM (nclinton) \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.ipynb new file mode 100644 index 0000000..a60bac0 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.ipynb @@ -0,0 +1,391 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# Snapshot of users/andreasvollrath/radar:slope_correction_lib.js\n", + "# on 11/4/2020 (reformated)\n", + "\n", + "def slope_correction (collection, options):\n", + " # Set defaults if undefined.\n", + " options = options || {}\n", + " model = options.model || 'volume'\n", + " elevation = options.elevation || ee.Image('USGS/SRTMGL1_003')\n", + " buffer = options.buffer || 0\n", + "\n", + " # We need a 90 degree in radians\n", + " # image for a couple of calculations.\n", + " ninetyRad = ee.Image.constant(90) \\\n", + " .multiply(math.pi/180)\n", + "\n", + " # Volumetric model Hoekman 1990.\n", + " def _volume_model(theta_iRad, alpha_rRad):\n", + " nominator = (ninetyRad.subtract(theta_iRad).add(alpha_rRad)) \\\n", + " .tan()\n", + " denominator = (ninetyRad.subtract(theta_iRad)) \\\n", + " .tan()\n", + " return nominator.divide(denominator)\n", + "\n", + "\n", + " # Surface model Ulander et al. 1996.\n", + " def _surface_model(theta_iRad, alpha_rRad, alpha_azRad):\n", + " nominator = (ninetyRad.subtract(theta_iRad)) \\\n", + " .cos()\n", + " denominator = alpha_azRad \\\n", + " .cos() \\\n", + " .multiply((ninetyRad \\\n", + " .subtract(theta_iRad) \\\n", + " .add(alpha_rRad)) \\\n", + " .cos()\n", + " )\n", + " return nominator.divide(denominator)\n", + "\n", + "\n", + " # Buffer function (thanks Noel).\n", + " def _erode(img, distance):\n", + " d = img \\\n", + " .Not() \\\n", + " .unmask(1) \\\n", + " .fastDistanceTransform(30) \\\n", + " .sqrt() \\\n", + " .multiply(ee.Image.pixelArea().sqrt())\n", + " return img.updateMask(d.gt(distance))\n", + "\n", + "\n", + " # Calculate masks.\n", + " def _masking(alpha_rRad, theta_iRad, proj, buffer):\n", + " # Layover, where slope > radar viewing angle.\n", + " layover = alpha_rRad.lt(theta_iRad).rename('layover')\n", + " # Shadow.\n", + " shadow = alpha_rRad \\\n", + " .gt(ee.Image.constant(-1) \\\n", + " .multiply(ninetyRad.subtract(theta_iRad))) \\\n", + " .rename('shadow')\n", + " # Combine layover and shadow.\n", + " mask = layover.And(shadow)\n", + " # Add buffer to final mask.\n", + " if (buffer > 0) {mask = _erode(mask, buffer)}\n", + " return mask.rename('no_data_mask')\n", + "\n", + "\n", + " def _correct(image):\n", + " # Get image geometry and projection .\n", + " geom = image.geometry()\n", + " proj = image.select(1).projection()\n", + "\n", + " # Get look direction angle.\n", + " heading = ee.Terrain.aspect(image.select('angle')) \\\n", + " .reduceRegion(ee.Reducer.mean(), geom, 1000) \\\n", + " .get('aspect')\n", + "\n", + " # The numbering follows the article chapters.\n", + " # Sigma0 to Power of input image.\n", + " sigma0Pow = ee.Image.constant(10) \\\n", + " .pow(image.divide(10.0))\n", + "\n", + " # 2.1.1 radar geometry.\n", + " theta_iRad = image \\\n", + " .select('angle') \\\n", + " .multiply(math.pi/180) \\\n", + " .clip(geom)\n", + " phi_iRad = ee.Image.constant(heading) \\\n", + " .multiply(math.pi/180)\n", + "\n", + " # 2.1.2 terrain geometry.\n", + " alpha_sRad = ee.Terrain.slope(elevation) \\\n", + " .select('slope') \\\n", + " .multiply(math.pi/180) \\\n", + " .setDefaultProjection(proj) \\\n", + " .clip(geom)\n", + " phi_sRad = ee.Terrain.aspect(elevation) \\\n", + " .select('aspect') \\\n", + " .multiply(math.pi/180) \\\n", + " .setDefaultProjection(proj) \\\n", + " .clip(geom)\n", + "\n", + " # 2.1.3 model geometry.\n", + " # Reduce to 3 angle.\n", + " phi_rRad = phi_iRad.subtract(phi_sRad)\n", + "\n", + " # Slope steepness in range (eq. 2).\n", + " alpha_rRad = (alpha_sRad.tan().multiply(phi_rRad.cos())) \\\n", + " .atan()\n", + "\n", + " # Slope steepness in azimuth (eq 3).\n", + " alpha_azRad = (alpha_sRad.tan().multiply(phi_rRad.sin())) \\\n", + " .atan()\n", + "\n", + " # 2.2 gamma_nought.\n", + " gamma0 = sigma0Pow.divide(theta_iRad.cos())\n", + "\n", + " # Models.\n", + " if (model == 'volume') {\n", + " corrModel = _volume_model(theta_iRad, alpha_rRad)\n", + " }\n", + " if (model == 'surface') {\n", + " corrModel = _surface_model(theta_iRad, alpha_rRad, alpha_azRad)\n", + " }\n", + " if (model == 'direct') {\n", + " corrModel = _direct_model(theta_iRad, alpha_rRad, alpha_azRad)\n", + " }\n", + "\n", + " # Apply model for Gamm0_f.\n", + " gamma0_flat = gamma0.divide(corrModel)\n", + "\n", + " # Transform to dB-scale.\n", + " gamma0_flatDB = ee.Image.constant(10) \\\n", + " .multiply(gamma0_flat.log10()) \\\n", + " .select(['VV', 'VH'])\n", + "\n", + " # Get layover / shadow mask.\n", + " mask = _masking(alpha_rRad, theta_iRad, proj, buffer)\n", + "\n", + " # Return gamma_flat plus mask.\n", + " return gamma0_flatDB \\\n", + " .addBands(mask) \\\n", + " .copyProperties(image)\n", + "\n", + "\n", + " # Run and return correction.\n", + " return collection.map(_correct)\n", + "\n", + "\n", + "\n", + "def slope_correction_image (image, options):\n", + " # Set defaults if undefined.\n", + " options = options || {}\n", + " model = options.model || 'volume'\n", + " elevation = options.elevation || ee.Image('USGS/SRTMGL1_003')\n", + " buffer = options.buffer || 0\n", + "\n", + " # We need a 90 degree in radians\n", + " # image for a couple of calculations.\n", + " ninetyRad = ee.Image.constant(90) \\\n", + " .multiply(math.pi/180)\n", + "\n", + " # Volumetric Model Hoekman 1990\n", + " def _volume_model(theta_iRad, alpha_rRad):\n", + " nominator = (ninetyRad.subtract(theta_iRad).add(alpha_rRad)) \\\n", + " .tan()\n", + " denominator = (ninetyRad.subtract(theta_iRad)) \\\n", + " .tan()\n", + " return nominator.divide(denominator)\n", + "\n", + "\n", + " # Surface model Ulander et al. 1996.\n", + " def _surface_model(theta_iRad, alpha_rRad, alpha_azRad):\n", + " nominator = (ninetyRad.subtract(theta_iRad)) \\\n", + " .cos()\n", + " denominator = alpha_azRad \\\n", + " .cos() \\\n", + " .multiply((ninetyRad \\\n", + " .subtract(theta_iRad) \\\n", + " .add(alpha_rRad)) \\\n", + " .cos()\n", + " )\n", + " return nominator.divide(denominator)\n", + "\n", + "\n", + " # Buffer function (thanks Noel).\n", + " def _erode(img, distance):\n", + " d = img \\\n", + " .Not() \\\n", + " .unmask(1) \\\n", + " .fastDistanceTransform(30) \\\n", + " .sqrt() \\\n", + " .multiply(ee.Image.pixelArea().sqrt())\n", + " return img.updateMask(d.gt(distance))\n", + "\n", + "\n", + " # Calculate masks.\n", + " def _masking(alpha_rRad, theta_iRad, proj, buffer):\n", + " # Layover where slope > radar viewing angle.\n", + " layover = alpha_rRad \\\n", + " .lt(theta_iRad) \\\n", + " .rename('layover')\n", + " # Shadow.\n", + " shadow = alpha_rRad \\\n", + " .gt(ee.Image.constant(-1).multiply(ninetyRad.subtract(theta_iRad))) \\\n", + " .rename('shadow')\n", + " # Combine layover and shadow.\n", + " mask = layover.And(shadow)\n", + " # Add buffer to final mask.\n", + " if (buffer > 0) {mask = _erode(mask, buffer)}\n", + " return mask.rename('no_data_mask')\n", + "\n", + "\n", + " def _correct(image):\n", + " # Get image geometry and projection.\n", + " geom = image.geometry()\n", + " proj = image.select(1).projection()\n", + "\n", + " # Get look direction angle.\n", + " heading = ee.Terrain.aspect(image.select('angle')) \\\n", + " .reduceRegion(ee.Reducer.mean(), geom, 1000) \\\n", + " .get('aspect')\n", + "\n", + " # The numbering follows the article chapters.\n", + " # 2.1.1 radar geometry.\n", + " theta_iRad = image \\\n", + " .select('angle') \\\n", + " .multiply(math.pi/180) \\\n", + " .clip(geom)\n", + " phi_iRad = ee.Image.constant(heading) \\\n", + " .multiply(math.pi/180)\n", + "\n", + " # 2.1.2 terrain geometry.\n", + " alpha_sRad = ee.Terrain.slope(elevation) \\\n", + " .select('slope') \\\n", + " .multiply(math.pi/180) \\\n", + " .setDefaultProjection(proj) \\\n", + " .clip(geom)\n", + " phi_sRad = ee.Terrain.aspect(elevation) \\\n", + " .select('aspect') \\\n", + " .multiply(math.pi/180) \\\n", + " .setDefaultProjection(proj) \\\n", + " .clip(geom)\n", + "\n", + " # 2.1.3 model geometry.\n", + " # Reduce to 3 angle.\n", + " phi_rRad = phi_iRad.subtract(phi_sRad)\n", + "\n", + " # Slope steepness in range (eq. 2).\n", + " alpha_rRad = (alpha_sRad.tan().multiply(phi_rRad.cos())) \\\n", + " .atan()\n", + "\n", + " # Slope steepness in azimuth (eq 3).\n", + " alpha_azRad = (alpha_sRad.tan().multiply(phi_rRad.sin())) \\\n", + " .atan()\n", + "\n", + " # 2.2 gamma_nought.\n", + " gamma0 = image.divide(theta_iRad.cos())\n", + "\n", + " # Models\n", + " if (model == 'volume') {\n", + " corrModel = _volume_model(theta_iRad, alpha_rRad)\n", + " }\n", + " if (model == 'surface') {\n", + " corrModel = _surface_model(theta_iRad, alpha_rRad, alpha_azRad)\n", + " }\n", + " if (model == 'direct') {\n", + " corrModel = _direct_model(theta_iRad, alpha_rRad, alpha_azRad)\n", + " }\n", + "\n", + " # Apply model for Gamm0_f\n", + " gamma0_flat = gamma0 \\\n", + " .select(['VV', 'VH']) \\\n", + " .divide(corrModel)\n", + "\n", + " # Get layover / shadow mask\n", + " mask = _masking(alpha_rRad, theta_iRad, proj, buffer)\n", + "\n", + " # Return gamma_flat plus mask.\n", + " return gamma0_flat \\\n", + " .addBands(image.select('angle')) \\\n", + " .addBands(mask) \\\n", + " .copyProperties(image) \\\n", + " .set('system:time_start', image.get('system:time_start'))\n", + "\n", + "\n", + " # Run and return correction.\n", + " return ee.Image(_correct(image))\n", + "\n", + "\n", + "# Export function.\n", + "exports.slope_correction = slope_correction\n", + "exports.slope_correction_image = slope_correction_image\n", + "\n", + "# Comments (nclinton). This is too much for me to reformat.\n", + "# Please adhere to Google JavaScript stype guidelines as\n", + "# described in:\n", + "# https:#docs.google.com/document/d/19KQBEDA-hYQEg4EizWOXPRNLmeOyc77YqEkqtHH6770/edit?usp=sharing&resourcekey=0-SRpYwdFqCLHgB5rA145AAw\n", + "\n", + "# LGTM (nclinton)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.js new file mode 100644 index 0000000..0b3dade --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.js @@ -0,0 +1,298 @@ +// Snapshot of users/andreasvollrath/radar:slope_correction_lib.js +// on 11/4/2020 (reformated) + +var slope_correction = function (collection, options) { + // Set defaults if undefined. + options = options || {}; + var model = options.model || 'volume'; + var elevation = options.elevation || ee.Image('USGS/SRTMGL1_003'); + var buffer = options.buffer || 0; + + // We need a 90 degree in radians + // image for a couple of calculations. + var ninetyRad = ee.Image.constant(90) + .multiply(Math.PI/180); + + // Volumetric model Hoekman 1990. + function _volume_model(theta_iRad, alpha_rRad) { + var nominator = (ninetyRad.subtract(theta_iRad).add(alpha_rRad)) + .tan(); + var denominator = (ninetyRad.subtract(theta_iRad)) + .tan(); + return nominator.divide(denominator); + } + + // Surface model Ulander et al. 1996. + function _surface_model(theta_iRad, alpha_rRad, alpha_azRad) { + var nominator = (ninetyRad.subtract(theta_iRad)) + .cos(); + var denominator = alpha_azRad + .cos() + .multiply((ninetyRad + .subtract(theta_iRad) + .add(alpha_rRad)) + .cos() + ); + return nominator.divide(denominator); + } + + // Buffer function (thanks Noel). + function _erode(img, distance) { + var d = img + .not() + .unmask(1) + .fastDistanceTransform(30) + .sqrt() + .multiply(ee.Image.pixelArea().sqrt()); + return img.updateMask(d.gt(distance)); + } + + // Calculate masks. + function _masking(alpha_rRad, theta_iRad, proj, buffer) { + // Layover, where slope > radar viewing angle. + var layover = alpha_rRad.lt(theta_iRad).rename('layover'); + // Shadow. + var shadow = alpha_rRad + .gt(ee.Image.constant(-1) + .multiply(ninetyRad.subtract(theta_iRad))) + .rename('shadow'); + // Combine layover and shadow. + var mask = layover.and(shadow); + // Add buffer to final mask. + if (buffer > 0) {mask = _erode(mask, buffer)} + return mask.rename('no_data_mask'); + } + + function _correct(image) { + // Get image geometry and projection . + var geom = image.geometry(); + var proj = image.select(1).projection(); + + // Get look direction angle. + var heading = ee.Terrain.aspect(image.select('angle')) + .reduceRegion(ee.Reducer.mean(), geom, 1000) + .get('aspect'); + + // The numbering follows the article chapters. + // Sigma0 to Power of input image. + var sigma0Pow = ee.Image.constant(10) + .pow(image.divide(10.0)); + + // 2.1.1 radar geometry. + var theta_iRad = image + .select('angle') + .multiply(Math.PI/180) + .clip(geom); + var phi_iRad = ee.Image.constant(heading) + .multiply(Math.PI/180); + + // 2.1.2 terrain geometry. + var alpha_sRad = ee.Terrain.slope(elevation) + .select('slope') + .multiply(Math.PI/180) + .setDefaultProjection(proj) + .clip(geom); + var phi_sRad = ee.Terrain.aspect(elevation) + .select('aspect') + .multiply(Math.PI/180) + .setDefaultProjection(proj) + .clip(geom); + + // 2.1.3 model geometry. + // Reduce to 3 angle. + var phi_rRad = phi_iRad.subtract(phi_sRad); + + // Slope steepness in range (eq. 2). + var alpha_rRad = (alpha_sRad.tan().multiply(phi_rRad.cos())) + .atan(); + + // Slope steepness in azimuth (eq 3). + var alpha_azRad = (alpha_sRad.tan().multiply(phi_rRad.sin())) + .atan(); + + // 2.2 gamma_nought. + var gamma0 = sigma0Pow.divide(theta_iRad.cos()); + + // Models. + if (model == 'volume') { + var corrModel = _volume_model(theta_iRad, alpha_rRad); + } + if (model == 'surface') { + var corrModel = _surface_model(theta_iRad, alpha_rRad, alpha_azRad); + } + if (model == 'direct') { + var corrModel = _direct_model(theta_iRad, alpha_rRad, alpha_azRad); + } + + // Apply model for Gamm0_f. + var gamma0_flat = gamma0.divide(corrModel); + + // Transform to dB-scale. + var gamma0_flatDB = ee.Image.constant(10) + .multiply(gamma0_flat.log10()) + .select(['VV', 'VH']); + + // Get layover / shadow mask. + var mask = _masking(alpha_rRad, theta_iRad, proj, buffer); + + // Return gamma_flat plus mask. + return gamma0_flatDB + .addBands(mask) + .copyProperties(image); + } + + // Run and return correction. + return collection.map(_correct); +}; + + +var slope_correction_image = function (image, options) { + // Set defaults if undefined. + options = options || {}; + var model = options.model || 'volume'; + var elevation = options.elevation || ee.Image('USGS/SRTMGL1_003'); + var buffer = options.buffer || 0; + + // We need a 90 degree in radians + // image for a couple of calculations. + var ninetyRad = ee.Image.constant(90) + .multiply(Math.PI/180); + + // Volumetric Model Hoekman 1990 + function _volume_model(theta_iRad, alpha_rRad) { + var nominator = (ninetyRad.subtract(theta_iRad).add(alpha_rRad)) + .tan(); + var denominator = (ninetyRad.subtract(theta_iRad)) + .tan(); + return nominator.divide(denominator); + } + + // Surface model Ulander et al. 1996. + function _surface_model(theta_iRad, alpha_rRad, alpha_azRad) { + var nominator = (ninetyRad.subtract(theta_iRad)) + .cos(); + var denominator = alpha_azRad + .cos() + .multiply((ninetyRad + .subtract(theta_iRad) + .add(alpha_rRad)) + .cos() + ); + return nominator.divide(denominator); + } + + // Buffer function (thanks Noel). + function _erode(img, distance) { + var d = img + .not() + .unmask(1) + .fastDistanceTransform(30) + .sqrt() + .multiply(ee.Image.pixelArea().sqrt()); + return img.updateMask(d.gt(distance)); + } + + // Calculate masks. + function _masking(alpha_rRad, theta_iRad, proj, buffer) { + // Layover where slope > radar viewing angle. + var layover = alpha_rRad + .lt(theta_iRad) + .rename('layover'); + // Shadow. + var shadow = alpha_rRad + .gt(ee.Image.constant(-1).multiply(ninetyRad.subtract(theta_iRad))) + .rename('shadow'); + // Combine layover and shadow. + var mask = layover.and(shadow); + // Add buffer to final mask. + if (buffer > 0) {mask = _erode(mask, buffer)} + return mask.rename('no_data_mask'); + } + + function _correct(image){ + // Get image geometry and projection. + var geom = image.geometry(); + var proj = image.select(1).projection(); + + // Get look direction angle. + var heading = ee.Terrain.aspect(image.select('angle')) + .reduceRegion(ee.Reducer.mean(), geom, 1000) + .get('aspect'); + + // The numbering follows the article chapters. + // 2.1.1 radar geometry. + var theta_iRad = image + .select('angle') + .multiply(Math.PI/180) + .clip(geom); + var phi_iRad = ee.Image.constant(heading) + .multiply(Math.PI/180); + + // 2.1.2 terrain geometry. + var alpha_sRad = ee.Terrain.slope(elevation) + .select('slope') + .multiply(Math.PI/180) + .setDefaultProjection(proj) + .clip(geom); + var phi_sRad = ee.Terrain.aspect(elevation) + .select('aspect') + .multiply(Math.PI/180) + .setDefaultProjection(proj) + .clip(geom); + + // 2.1.3 model geometry. + // Reduce to 3 angle. + var phi_rRad = phi_iRad.subtract(phi_sRad); + + // Slope steepness in range (eq. 2). + var alpha_rRad = (alpha_sRad.tan().multiply(phi_rRad.cos())) + .atan(); + + // Slope steepness in azimuth (eq 3). + var alpha_azRad = (alpha_sRad.tan().multiply(phi_rRad.sin())) + .atan(); + + // 2.2 gamma_nought. + var gamma0 = image.divide(theta_iRad.cos()); + + // Models + if (model == 'volume') { + var corrModel = _volume_model(theta_iRad, alpha_rRad); + } + if (model == 'surface') { + var corrModel = _surface_model(theta_iRad, alpha_rRad, alpha_azRad); + } + if (model == 'direct') { + var corrModel = _direct_model(theta_iRad, alpha_rRad, alpha_azRad); + } + + // Apply model for Gamm0_f + var gamma0_flat = gamma0 + .select(['VV', 'VH']) + .divide(corrModel); + + // Get layover / shadow mask + var mask = _masking(alpha_rRad, theta_iRad, proj, buffer); + + // Return gamma_flat plus mask. + return gamma0_flat + .addBands(image.select('angle')) + .addBands(mask) + .copyProperties(image) + .set('system:time_start', image.get('system:time_start')); + } + + // Run and return correction. + return ee.Image(_correct(image)); +}; + +// Export function. +exports.slope_correction = slope_correction; +exports.slope_correction_image = slope_correction_image; + +// Comments (nclinton). This is too much for me to reformat. +// Please adhere to Google JavaScript stype guidelines as +// described in: +// https://docs.google.com/document/d/19KQBEDA-hYQEg4EizWOXPRNLmeOyc77YqEkqtHH6770/edit?usp=sharing&resourcekey=0-SRpYwdFqCLHgB5rA145AAw + +// LGTM (nclinton) diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.py new file mode 100644 index 0000000..d55cb85 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.5 Deforestation Viewed from Multiple Sensors/modules/slope_correction_lib.py @@ -0,0 +1,305 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# Snapshot of users/andreasvollrath/radar:slope_correction_lib.js +# on 11/4/2020 (reformated) + +def slope_correction (collection, options): + # Set defaults if undefined. + options = options || {} + model = options.model || 'volume' + elevation = options.elevation || ee.Image('USGS/SRTMGL1_003') + buffer = options.buffer || 0 + + # We need a 90 degree in radians + # image for a couple of calculations. + ninetyRad = ee.Image.constant(90) \ + .multiply(math.pi/180) + + # Volumetric model Hoekman 1990. + def _volume_model(theta_iRad, alpha_rRad): + nominator = (ninetyRad.subtract(theta_iRad).add(alpha_rRad)) \ + .tan() + denominator = (ninetyRad.subtract(theta_iRad)) \ + .tan() + return nominator.divide(denominator) + + + # Surface model Ulander et al. 1996. + def _surface_model(theta_iRad, alpha_rRad, alpha_azRad): + nominator = (ninetyRad.subtract(theta_iRad)) \ + .cos() + denominator = alpha_azRad \ + .cos() \ + .multiply((ninetyRad \ + .subtract(theta_iRad) \ + .add(alpha_rRad)) \ + .cos() + ) + return nominator.divide(denominator) + + + # Buffer function (thanks Noel). + def _erode(img, distance): + d = img \ + .Not() \ + .unmask(1) \ + .fastDistanceTransform(30) \ + .sqrt() \ + .multiply(ee.Image.pixelArea().sqrt()) + return img.updateMask(d.gt(distance)) + + + # Calculate masks. + def _masking(alpha_rRad, theta_iRad, proj, buffer): + # Layover, where slope > radar viewing angle. + layover = alpha_rRad.lt(theta_iRad).rename('layover') + # Shadow. + shadow = alpha_rRad \ + .gt(ee.Image.constant(-1) \ + .multiply(ninetyRad.subtract(theta_iRad))) \ + .rename('shadow') + # Combine layover and shadow. + mask = layover.And(shadow) + # Add buffer to final mask. + if (buffer > 0) {mask = _erode(mask, buffer)} + return mask.rename('no_data_mask') + + + def _correct(image): + # Get image geometry and projection . + geom = image.geometry() + proj = image.select(1).projection() + + # Get look direction angle. + heading = ee.Terrain.aspect(image.select('angle')) \ + .reduceRegion(ee.Reducer.mean(), geom, 1000) \ + .get('aspect') + + # The numbering follows the article chapters. + # Sigma0 to Power of input image. + sigma0Pow = ee.Image.constant(10) \ + .pow(image.divide(10.0)) + + # 2.1.1 radar geometry. + theta_iRad = image \ + .select('angle') \ + .multiply(math.pi/180) \ + .clip(geom) + phi_iRad = ee.Image.constant(heading) \ + .multiply(math.pi/180) + + # 2.1.2 terrain geometry. + alpha_sRad = ee.Terrain.slope(elevation) \ + .select('slope') \ + .multiply(math.pi/180) \ + .setDefaultProjection(proj) \ + .clip(geom) + phi_sRad = ee.Terrain.aspect(elevation) \ + .select('aspect') \ + .multiply(math.pi/180) \ + .setDefaultProjection(proj) \ + .clip(geom) + + # 2.1.3 model geometry. + # Reduce to 3 angle. + phi_rRad = phi_iRad.subtract(phi_sRad) + + # Slope steepness in range (eq. 2). + alpha_rRad = (alpha_sRad.tan().multiply(phi_rRad.cos())) \ + .atan() + + # Slope steepness in azimuth (eq 3). + alpha_azRad = (alpha_sRad.tan().multiply(phi_rRad.sin())) \ + .atan() + + # 2.2 gamma_nought. + gamma0 = sigma0Pow.divide(theta_iRad.cos()) + + # Models. + if (model == 'volume') { + corrModel = _volume_model(theta_iRad, alpha_rRad) + } + if (model == 'surface') { + corrModel = _surface_model(theta_iRad, alpha_rRad, alpha_azRad) + } + if (model == 'direct') { + corrModel = _direct_model(theta_iRad, alpha_rRad, alpha_azRad) + } + + # Apply model for Gamm0_f. + gamma0_flat = gamma0.divide(corrModel) + + # Transform to dB-scale. + gamma0_flatDB = ee.Image.constant(10) \ + .multiply(gamma0_flat.log10()) \ + .select(['VV', 'VH']) + + # Get layover / shadow mask. + mask = _masking(alpha_rRad, theta_iRad, proj, buffer) + + # Return gamma_flat plus mask. + return gamma0_flatDB \ + .addBands(mask) \ + .copyProperties(image) + + + # Run and return correction. + return collection.map(_correct) + + + +def slope_correction_image (image, options): + # Set defaults if undefined. + options = options || {} + model = options.model || 'volume' + elevation = options.elevation || ee.Image('USGS/SRTMGL1_003') + buffer = options.buffer || 0 + + # We need a 90 degree in radians + # image for a couple of calculations. + ninetyRad = ee.Image.constant(90) \ + .multiply(math.pi/180) + + # Volumetric Model Hoekman 1990 + def _volume_model(theta_iRad, alpha_rRad): + nominator = (ninetyRad.subtract(theta_iRad).add(alpha_rRad)) \ + .tan() + denominator = (ninetyRad.subtract(theta_iRad)) \ + .tan() + return nominator.divide(denominator) + + + # Surface model Ulander et al. 1996. + def _surface_model(theta_iRad, alpha_rRad, alpha_azRad): + nominator = (ninetyRad.subtract(theta_iRad)) \ + .cos() + denominator = alpha_azRad \ + .cos() \ + .multiply((ninetyRad \ + .subtract(theta_iRad) \ + .add(alpha_rRad)) \ + .cos() + ) + return nominator.divide(denominator) + + + # Buffer function (thanks Noel). + def _erode(img, distance): + d = img \ + .Not() \ + .unmask(1) \ + .fastDistanceTransform(30) \ + .sqrt() \ + .multiply(ee.Image.pixelArea().sqrt()) + return img.updateMask(d.gt(distance)) + + + # Calculate masks. + def _masking(alpha_rRad, theta_iRad, proj, buffer): + # Layover where slope > radar viewing angle. + layover = alpha_rRad \ + .lt(theta_iRad) \ + .rename('layover') + # Shadow. + shadow = alpha_rRad \ + .gt(ee.Image.constant(-1).multiply(ninetyRad.subtract(theta_iRad))) \ + .rename('shadow') + # Combine layover and shadow. + mask = layover.And(shadow) + # Add buffer to final mask. + if (buffer > 0) {mask = _erode(mask, buffer)} + return mask.rename('no_data_mask') + + + def _correct(image): + # Get image geometry and projection. + geom = image.geometry() + proj = image.select(1).projection() + + # Get look direction angle. + heading = ee.Terrain.aspect(image.select('angle')) \ + .reduceRegion(ee.Reducer.mean(), geom, 1000) \ + .get('aspect') + + # The numbering follows the article chapters. + # 2.1.1 radar geometry. + theta_iRad = image \ + .select('angle') \ + .multiply(math.pi/180) \ + .clip(geom) + phi_iRad = ee.Image.constant(heading) \ + .multiply(math.pi/180) + + # 2.1.2 terrain geometry. + alpha_sRad = ee.Terrain.slope(elevation) \ + .select('slope') \ + .multiply(math.pi/180) \ + .setDefaultProjection(proj) \ + .clip(geom) + phi_sRad = ee.Terrain.aspect(elevation) \ + .select('aspect') \ + .multiply(math.pi/180) \ + .setDefaultProjection(proj) \ + .clip(geom) + + # 2.1.3 model geometry. + # Reduce to 3 angle. + phi_rRad = phi_iRad.subtract(phi_sRad) + + # Slope steepness in range (eq. 2). + alpha_rRad = (alpha_sRad.tan().multiply(phi_rRad.cos())) \ + .atan() + + # Slope steepness in azimuth (eq 3). + alpha_azRad = (alpha_sRad.tan().multiply(phi_rRad.sin())) \ + .atan() + + # 2.2 gamma_nought. + gamma0 = image.divide(theta_iRad.cos()) + + # Models + if (model == 'volume') { + corrModel = _volume_model(theta_iRad, alpha_rRad) + } + if (model == 'surface') { + corrModel = _surface_model(theta_iRad, alpha_rRad, alpha_azRad) + } + if (model == 'direct') { + corrModel = _direct_model(theta_iRad, alpha_rRad, alpha_azRad) + } + + # Apply model for Gamm0_f + gamma0_flat = gamma0 \ + .select(['VV', 'VH']) \ + .divide(corrModel) + + # Get layover / shadow mask + mask = _masking(alpha_rRad, theta_iRad, proj, buffer) + + # Return gamma_flat plus mask. + return gamma0_flat \ + .addBands(image.select('angle')) \ + .addBands(mask) \ + .copyProperties(image) \ + .set('system:time_start', image.get('system:time_start')) + + + # Run and return correction. + return ee.Image(_correct(image)) + + +# Export function. +exports.slope_correction = slope_correction +exports.slope_correction_image = slope_correction_image + +# Comments (nclinton). This is too much for me to reformat. +# Please adhere to Google JavaScript stype guidelines as +# described in: +# https:#docs.google.com/document/d/19KQBEDA-hYQEg4EizWOXPRNLmeOyc77YqEkqtHH6770/edit?usp=sharing&resourcekey=0-SRpYwdFqCLHgB5rA145AAw + +# LGTM (nclinton) +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36a Checkpoint.ipynb new file mode 100644 index 0000000..0f47174 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36a Checkpoint.ipynb @@ -0,0 +1,155 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometry =\n", + "\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-112.1088347655006, 38.522463862329126],\n", + " [-112.1088347655006, 38.22315763773188],\n", + " [-111.91520073229748, 38.22315763773188],\n", + " [-111.91520073229748, 38.522463862329126]]], None, False)\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.6 Working With GPS and Weather Data\n", + "# Checkpoint: A36a\n", + "# Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the data and add it to the map and print.\n", + "cougarF53 = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-6/cougarF53')\n", + "\n", + "Map.centerObject(cougarF53, 10)\n", + "\n", + "Map.addLayer(cougarF53, {}, 'cougar presence data')\n", + "\n", + "print(cougarF53, 'cougar data')\n", + "\n", + "# Call in image collection and filter.\n", + "Daymet = ee.ImageCollection('NASA/ORNL/DAYMET_V4') \\\n", + " .filterDate('2014-02-11', '2014-11-02') \\\n", + " .filterBounds(geometry)\n", + "\n", + "def func_zwz(image):\n", + " return image.clip(geometry) \\\n", + " .map(func_zwz)\n", + "\n", + "\n", + "\n", + "\n", + "print(Daymet, 'Daymet')\n", + "\n", + "\n", + "# Convert to a multiband image.\n", + "DaymetImage = Daymet.toBands()\n", + "\n", + "print(DaymetImage, 'DaymetImage')\n", + "\n", + "# Call the sample regions function.\n", + "samples = DaymetImage.sampleRegions({\n", + " 'collection': cougarF53,\n", + " 'properties': ['id'],\n", + " 'scale': 1000\n", + "})\n", + "\n", + "print(samples, 'samples')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36a Checkpoint.js new file mode 100644 index 0000000..f2e5cad --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36a Checkpoint.js @@ -0,0 +1,58 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometry = + /* color: #d63000 */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-112.1088347655006, 38.522463862329126], + [-112.1088347655006, 38.22315763773188], + [-111.91520073229748, 38.22315763773188], + [-111.91520073229748, 38.522463862329126]]], null, false); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.6 Working With GPS and Weather Data +// Checkpoint: A36a +// Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the data and add it to the map and print. +var cougarF53 = ee.FeatureCollection( + 'projects/gee-book/assets/A3-6/cougarF53'); + +Map.centerObject(cougarF53, 10); + +Map.addLayer(cougarF53, {}, 'cougar presence data'); + +print(cougarF53, 'cougar data'); + +// Call in image collection and filter. +var Daymet = ee.ImageCollection('NASA/ORNL/DAYMET_V4') + .filterDate('2014-02-11', '2014-11-02') + .filterBounds(geometry) + .map(function(image) { + return image.clip(geometry); + }); + +print(Daymet, 'Daymet'); + + +// Convert to a multiband image. +var DaymetImage = Daymet.toBands(); + +print(DaymetImage, 'DaymetImage'); + +// Call the sample regions function. +var samples = DaymetImage.sampleRegions({ + collection: cougarF53, + properties: ['id'], + scale: 1000 +}); + +print(samples, 'samples'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36a Checkpoint.py new file mode 100644 index 0000000..46f0002 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36a Checkpoint.py @@ -0,0 +1,68 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometry = + + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-112.1088347655006, 38.522463862329126], + [-112.1088347655006, 38.22315763773188], + [-111.91520073229748, 38.22315763773188], + [-111.91520073229748, 38.522463862329126]]], None, False) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.6 Working With GPS and Weather Data +# Checkpoint: A36a +# Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the data and add it to the map and print. +cougarF53 = ee.FeatureCollection( + 'projects/gee-book/assets/A3-6/cougarF53') + +Map.centerObject(cougarF53, 10) + +Map.addLayer(cougarF53, {}, 'cougar presence data') + +print(cougarF53, 'cougar data') + +# Call in image collection and filter. +Daymet = ee.ImageCollection('NASA/ORNL/DAYMET_V4') \ + .filterDate('2014-02-11', '2014-11-02') \ + .filterBounds(geometry) + +def func_zwz(image): + return image.clip(geometry) \ + .map(func_zwz) + + + + +print(Daymet, 'Daymet') + + +# Convert to a multiband image. +DaymetImage = Daymet.toBands() + +print(DaymetImage, 'DaymetImage') + +# Call the sample regions function. +samples = DaymetImage.sampleRegions({ + 'collection': cougarF53, + 'properties': ['id'], + 'scale': 1000 +}) + +print(samples, 'samples') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36b Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36b Checkpoint.ipynb new file mode 100644 index 0000000..1ca3a6b --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36b Checkpoint.ipynb @@ -0,0 +1,181 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometry =\n", + "\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-112.1088347655006, 38.522463862329126],\n", + " [-112.1088347655006, 38.22315763773188],\n", + " [-111.91520073229748, 38.22315763773188],\n", + " [-111.91520073229748, 38.522463862329126]]], None, False)\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.6 Working With GPS and Weather Data\n", + "# Checkpoint: A36b\n", + "# Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the data and add it to the map and print.\n", + "cougarF53 = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-6/cougarF53')\n", + "\n", + "Map.centerObject(cougarF53, 10)\n", + "\n", + "Map.addLayer(cougarF53, {}, 'cougar presence data')\n", + "\n", + "print(cougarF53, 'cougar data')\n", + "\n", + "# Call in image collection and filter.\n", + "Daymet = ee.ImageCollection('NASA/ORNL/DAYMET_V4') \\\n", + " .filterDate('2014-02-11', '2014-11-02') \\\n", + " .filterBounds(geometry)\n", + "\n", + "def func_gqy(image):\n", + " return image.clip(geometry) \\\n", + " .map(func_gqy)\n", + "\n", + "\n", + "\n", + "\n", + "print(Daymet, 'Daymet')\n", + "\n", + "# Convert to a multiband image.\n", + "DaymetImage = Daymet.toBands()\n", + "\n", + "print(DaymetImage, 'DaymetImage')\n", + "\n", + "# Call the sample regions function.\n", + "samples = DaymetImage.sampleRegions({\n", + " 'collection': cougarF53,\n", + " 'properties': ['id'],\n", + " 'scale': 1000\n", + "})\n", + "\n", + "print(samples, 'samples')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Export value added data to your Google Drive.\n", + "Export.table.toDrive({\n", + " 'collection': samples,\n", + " 'description': 'cougarDaymetToDriveExample',\n", + " 'fileFormat': 'csv'\n", + "})\n", + "\n", + "# Apply a median reducer to the dataset.\n", + "daymet1 = Daymet \\\n", + " .median() \\\n", + " .clip(geometry)\n", + "\n", + "print(daymet1)\n", + "\n", + "# Export the image to drive.\n", + "Export.image.toDrive({\n", + " 'image': daymet1,\n", + " 'description': 'MedianValueForStudyArea',\n", + " 'scale': 1000,\n", + " 'region': geometry,\n", + " 'maxPixels': 1e9\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36b Checkpoint.js new file mode 100644 index 0000000..d2d4572 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36b Checkpoint.js @@ -0,0 +1,84 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometry = + /* color: #d63000 */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-112.1088347655006, 38.522463862329126], + [-112.1088347655006, 38.22315763773188], + [-111.91520073229748, 38.22315763773188], + [-111.91520073229748, 38.522463862329126]]], null, false); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.6 Working With GPS and Weather Data +// Checkpoint: A36b +// Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the data and add it to the map and print. +var cougarF53 = ee.FeatureCollection( + 'projects/gee-book/assets/A3-6/cougarF53'); + +Map.centerObject(cougarF53, 10); + +Map.addLayer(cougarF53, {}, 'cougar presence data'); + +print(cougarF53, 'cougar data'); + +// Call in image collection and filter. +var Daymet = ee.ImageCollection('NASA/ORNL/DAYMET_V4') + .filterDate('2014-02-11', '2014-11-02') + .filterBounds(geometry) + .map(function(image) { + return image.clip(geometry); + }); + +print(Daymet, 'Daymet'); + +// Convert to a multiband image. +var DaymetImage = Daymet.toBands(); + +print(DaymetImage, 'DaymetImage'); + +// Call the sample regions function. +var samples = DaymetImage.sampleRegions({ + collection: cougarF53, + properties: ['id'], + scale: 1000 +}); + +print(samples, 'samples'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Export value added data to your Google Drive. +Export.table.toDrive({ + collection: samples, + description: 'cougarDaymetToDriveExample', + fileFormat: 'csv' +}); + +// Apply a median reducer to the dataset. +var daymet1 = Daymet + .median() + .clip(geometry); + +print(daymet1); + +// Export the image to drive. +Export.image.toDrive({ + image: daymet1, + description: 'MedianValueForStudyArea', + scale: 1000, + region: geometry, + maxPixels: 1e9 +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36b Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36b Checkpoint.py new file mode 100644 index 0000000..cb96cd5 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.6 Working With GPS & Weather Data/A36b Checkpoint.py @@ -0,0 +1,94 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometry = + + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-112.1088347655006, 38.522463862329126], + [-112.1088347655006, 38.22315763773188], + [-111.91520073229748, 38.22315763773188], + [-111.91520073229748, 38.522463862329126]]], None, False) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.6 Working With GPS and Weather Data +# Checkpoint: A36b +# Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the data and add it to the map and print. +cougarF53 = ee.FeatureCollection( + 'projects/gee-book/assets/A3-6/cougarF53') + +Map.centerObject(cougarF53, 10) + +Map.addLayer(cougarF53, {}, 'cougar presence data') + +print(cougarF53, 'cougar data') + +# Call in image collection and filter. +Daymet = ee.ImageCollection('NASA/ORNL/DAYMET_V4') \ + .filterDate('2014-02-11', '2014-11-02') \ + .filterBounds(geometry) + +def func_gqy(image): + return image.clip(geometry) \ + .map(func_gqy) + + + + +print(Daymet, 'Daymet') + +# Convert to a multiband image. +DaymetImage = Daymet.toBands() + +print(DaymetImage, 'DaymetImage') + +# Call the sample regions function. +samples = DaymetImage.sampleRegions({ + 'collection': cougarF53, + 'properties': ['id'], + 'scale': 1000 +}) + +print(samples, 'samples') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Export value added data to your Google Drive. +Export.table.toDrive({ + 'collection': samples, + 'description': 'cougarDaymetToDriveExample', + 'fileFormat': 'csv' +}) + +# Apply a median reducer to the dataset. +daymet1 = Daymet \ + .median() \ + .clip(geometry) + +print(daymet1) + +# Export the image to drive. +Export.image.toDrive({ + 'image': daymet1, + 'description': 'MedianValueForStudyArea', + 'scale': 1000, + 'region': geometry, + 'maxPixels': 1e9 +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37a Checkpoint.ipynb new file mode 100644 index 0000000..aa8996c --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37a Checkpoint.ipynb @@ -0,0 +1,333 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "roi =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-108.01888227338851, 39.04480287274028],\n", + " [-108.01888227338851, 38.98931938880467],\n", + " [-107.85031080122054, 38.98931938880467],\n", + " [-107.85031080122054, 39.04480287274028]]], None, False),\n", + " sampleArea =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Polygon(\n", + " [[[-107.97587902754866, 39.00939572571298],\n", + " [-107.96866924971663, 38.99685612090398],\n", + " [-107.94566662520491, 39.00512717360476],\n", + " [-107.88558514327131, 39.00325960105985],\n", + " [-107.87597210616194, 39.02033271471843],\n", + " [-107.93639691084944, 39.024066908916005]]])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.7 Creating Presence and Absence Points\n", + "# Checkpoint: A37a\n", + "# Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Call in NAIP imagery as an image collection.\n", + "naip = ee.ImageCollection('USDA/NAIP/DOQQ') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2015-01-01', '2017-12-31')\n", + "\n", + "Map.centerObject(naip)\n", + "\n", + "print(naip)\n", + "\n", + "# Filter the data based on date.\n", + "naip2017 = naip \\\n", + " .filterDate('2017-01-01', '2017-12-31')\n", + "\n", + "naip2015 = naip \\\n", + " .filterDate('2015-01-01', '2015-12-31')\n", + "\n", + "# Define viewing parameters for multi band images.\n", + "visParamsFalse = {\n", + " 'bands': ['N', 'R', 'G']\n", + "}\n", + "visParamsTrue = {\n", + " 'bands': ['R', 'G', 'B']\n", + "}\n", + "\n", + "# Add both sets of NAIP imagery to the map to compare coverage.\n", + "Map.addLayer(naip2015, visParamsTrue, '2015_True', False)\n", + "Map.addLayer(naip2017, visParamsTrue, '2017_True', False)\n", + "\n", + "# Add 2015 False color imagery.\n", + "Map.addLayer(naip2015, visParamsFalse, '2015_False', False)\n", + "\n", + "# Creating a geometry feature.\n", + "exclosure = ee.Geometry.MultiPolygon([\n", + " [\n", + " [-107.91079184, 39.012553345],\n", + " [-107.90828129, 39.012553345],\n", + " [-107.90828129, 39.014070552],\n", + " [-107.91079184, 39.014070552],\n", + " [-107.91079184, 39.012553345]\n", + " ],\n", + " [\n", + " [-107.9512176, 39.00870162],\n", + " [-107.9496834, 39.00870162],\n", + " [-107.9496834, 39.00950196],\n", + " [-107.95121765, 39.00950196],\n", + " [-107.95121765, 39.00870162]\n", + " ]\n", + "])\n", + "\n", + "print(exclosure)\n", + "\n", + "Map.addLayer(exclosure, {}, 'exclosures')\n", + "\n", + "# Load in elevation dataset; clip it to general area.\n", + "elev = ee.Image('USGS/NED') \\\n", + " .clip(roi)\n", + "\n", + "Map.addLayer(elev, {\n", + " 'min': 1500,\n", + " 'max': 3300\n", + "}, 'elevation', False)\n", + "\n", + "# Apply mosaic, clip, then calculate NDVI.\n", + "ndvi = naip2015 \\\n", + " .mosaic() \\\n", + " .clip(roi) \\\n", + " .normalizedDifference(['N', 'R']) \\\n", + " .rename('ndvi')\n", + "\n", + "Map.addLayer(ndvi, {\n", + " 'min': -0.8,\n", + " 'max': 0.8\n", + "}, 'NDVI', False)\n", + "\n", + "print(ndvi, 'ndvi')\n", + "\n", + "# Add National Land Cover Database (NLCD).\n", + "dataset = ee.ImageCollection('USGS/NLCD')\n", + "\n", + "print(dataset, 'NLCD')\n", + "\n", + "# Load the selected NLCD image.\n", + "landcover = ee.Image('USGS/NLCD/NLCD2016') \\\n", + " .select('landcover') \\\n", + " .clip(roi)\n", + "\n", + "Map.addLayer(landcover, {}, 'Landcover', False)\n", + "\n", + "# Generate random points within the sample area.\n", + "points = ee.FeatureCollection.randomPoints({\n", + " 'region': sampleArea,\n", + " 'points': 1000,\n", + " 'seed': 1234\n", + "})\n", + "\n", + "print(points, 'points')\n", + "\n", + "Map.addLayer(points, {}, 'Points', False)\n", + "\n", + "# Add bands of elevation and NAIP.\n", + "ndviElev = ndvi \\\n", + " .addBands(elev) \\\n", + " .addBands(landcover)\n", + "\n", + "print(ndviElev, 'Multi band image')\n", + "\n", + "# Extract values to points.\n", + "samples = ndviElev.sampleRegions({\n", + " 'collection': points,\n", + " 'scale': 30,\n", + " 'geometries': True\n", + "})\n", + "\n", + "print(samples, 'samples')\n", + "\n", + "Map.addLayer(samples, {}, 'samples', False)\n", + "\n", + "# Filter metadata for sites in the NLCD deciduous forest layer.\n", + "aspenSites = samples.filter(ee.Filter.equals('landcover', 41))\n", + "\n", + "print(aspenSites, 'Sites')\n", + "\n", + "# Set the NDVI range.\n", + "ndvi1 = ndvi \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': exclosure,\n", + " 'scale': 1,\n", + " 'crs': 'EPSG:4326'\n", + " })\n", + "\n", + "print(ndvi1, 'Mean NDVI')\n", + "\n", + "# Generate a range of acceptable NDVI values.\n", + "ndviNumber = ee.Number(ndvi1.get('ndvi'))\n", + "ndviBuffer = ndviNumber.multiply(0.1)\n", + "ndviRange = [\n", + " ndviNumber.subtract(ndviBuffer),\n", + " ndviNumber.add(ndviBuffer)\n", + "]\n", + "\n", + "print(ndviRange, 'NDVI Range')\n", + "\n", + "#\n", + "This function is used to determine the mean value of an image within a given area.\n", + "'image': an image with a single band of ordinal or interval level data\n", + "'geom': geometry feature that overlaps with the image\n", + "'pixelSize': a number that defines the cell size of the image\n", + "Returns a dictionary with the median values of the band, the key is the band name.\n", + "#\n", + "def reduceRegionFunction(image, geom, pixelSize):\n", + " dict = image.reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': geom,\n", + " 'scale': pixelSize,\n", + " 'crs': 'EPSG:4326'\n", + " })\n", + " return (dict)\n", + "\n", + "\n", + "# Call function on the NDVI dataset to compare.\n", + "ndvi_test = reduceRegionFunction(ndvi, exclosure, 1)\n", + "\n", + "print(ndvi_test, 'ndvi_test')\n", + "\n", + "# Call function on elevation dataset.\n", + "elev1 = reduceRegionFunction(elev, exclosure, 30)\n", + "\n", + "print(elev1, 'elev1')\n", + "\n", + "#\n", + "Generate a range of acceptable values.\n", + "'dictionary': a dictionary object\n", + "'key': key to the value of interest, must be a string\n", + "'proportion': a percentile to define the range of the values around the mean\n", + "Returns a list with a min and max value for the given range.\n", + "#\n", + "def effectiveRange(dictionary, key, proportion):\n", + " number = ee.Number(dictionary.get(key))\n", + " buffer = number.multiply(proportion)\n", + " range = [\n", + " number.subtract(buffer),\n", + " number.add(buffer)\n", + " ]\n", + " return (range)\n", + "\n", + "\n", + "# Call function on elevation data.\n", + "elevRange = effectiveRange(elev1, 'elevation', 0.1)\n", + "\n", + "print(elevRange)\n", + "\n", + "# Apply multiple filters to get at potential locations.\n", + "combinedFilter = ee.Filter.And(\n", + " ee.Filter.greaterThan('ndvi', ndviRange[0]),\n", + " ee.Filter.lessThan('ndvi', ndviRange[1]),\n", + " ee.Filter.greaterThan('elevation', elevRange[0]),\n", + " ee.Filter.lessThan('elevation', elevRange[1])\n", + ")\n", + "\n", + "aspenSites2 = aspenSites.filter(combinedFilter)\n", + "\n", + "print(aspenSites2, 'aspenSites2')\n", + "\n", + "Map.addLayer(aspenSites2, {}, 'aspenSites2', False)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37a Checkpoint.js new file mode 100644 index 0000000..b0d8de6 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37a Checkpoint.js @@ -0,0 +1,240 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var roi = + /* color: #98ff00 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-108.01888227338851, 39.04480287274028], + [-108.01888227338851, 38.98931938880467], + [-107.85031080122054, 38.98931938880467], + [-107.85031080122054, 39.04480287274028]]], null, false), + sampleArea = + /* color: #bf04c2 */ + /* shown: false */ + ee.Geometry.Polygon( + [[[-107.97587902754866, 39.00939572571298], + [-107.96866924971663, 38.99685612090398], + [-107.94566662520491, 39.00512717360476], + [-107.88558514327131, 39.00325960105985], + [-107.87597210616194, 39.02033271471843], + [-107.93639691084944, 39.024066908916005]]]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.7 Creating Presence and Absence Points +// Checkpoint: A37a +// Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Call in NAIP imagery as an image collection. +var naip = ee.ImageCollection('USDA/NAIP/DOQQ') + .filterBounds(roi) + .filterDate('2015-01-01', '2017-12-31'); + +Map.centerObject(naip); + +print(naip); + +// Filter the data based on date. +var naip2017 = naip + .filterDate('2017-01-01', '2017-12-31'); + +var naip2015 = naip + .filterDate('2015-01-01', '2015-12-31'); + +// Define viewing parameters for multi band images. +var visParamsFalse = { + bands: ['N', 'R', 'G'] +}; +var visParamsTrue = { + bands: ['R', 'G', 'B'] +}; + +// Add both sets of NAIP imagery to the map to compare coverage. +Map.addLayer(naip2015, visParamsTrue, '2015_true', false); +Map.addLayer(naip2017, visParamsTrue, '2017_true', false); + +// Add 2015 false color imagery. +Map.addLayer(naip2015, visParamsFalse, '2015_false', false); + +// Creating a geometry feature. +var exclosure = ee.Geometry.MultiPolygon([ + [ + [-107.91079184, 39.012553345], + [-107.90828129, 39.012553345], + [-107.90828129, 39.014070552], + [-107.91079184, 39.014070552], + [-107.91079184, 39.012553345] + ], + [ + [-107.9512176, 39.00870162], + [-107.9496834, 39.00870162], + [-107.9496834, 39.00950196], + [-107.95121765, 39.00950196], + [-107.95121765, 39.00870162] + ] +]); + +print(exclosure); + +Map.addLayer(exclosure, {}, 'exclosures'); + +// Load in elevation dataset; clip it to general area. +var elev = ee.Image('USGS/NED') + .clip(roi); + +Map.addLayer(elev, { + min: 1500, + max: 3300 +}, 'elevation', false); + +// Apply mosaic, clip, then calculate NDVI. +var ndvi = naip2015 + .mosaic() + .clip(roi) + .normalizedDifference(['N', 'R']) + .rename('ndvi'); + +Map.addLayer(ndvi, { + min: -0.8, + max: 0.8 +}, 'NDVI', false); + +print(ndvi, 'ndvi'); + +// Add National Land Cover Database (NLCD). +var dataset = ee.ImageCollection('USGS/NLCD'); + +print(dataset, 'NLCD'); + +// Load the selected NLCD image. +var landcover = ee.Image('USGS/NLCD/NLCD2016') + .select('landcover') + .clip(roi); + +Map.addLayer(landcover, {}, 'Landcover', false); + +// Generate random points within the sample area. +var points = ee.FeatureCollection.randomPoints({ + region: sampleArea, + points: 1000, + seed: 1234 +}); + +print(points, 'points'); + +Map.addLayer(points, {}, 'Points', false); + +// Add bands of elevation and NAIP. +var ndviElev = ndvi + .addBands(elev) + .addBands(landcover); + +print(ndviElev, 'Multi band image'); + +// Extract values to points. +var samples = ndviElev.sampleRegions({ + collection: points, + scale: 30, + geometries: true +}); + +print(samples, 'samples'); + +Map.addLayer(samples, {}, 'samples', false); + +// Filter metadata for sites in the NLCD deciduous forest layer. +var aspenSites = samples.filter(ee.Filter.equals('landcover', 41)); + +print(aspenSites, 'Sites'); + +// Set the NDVI range. +var ndvi1 = ndvi + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: exclosure, + scale: 1, + crs: 'EPSG:4326' + }); + +print(ndvi1, 'Mean NDVI'); + +// Generate a range of acceptable NDVI values. +var ndviNumber = ee.Number(ndvi1.get('ndvi')); +var ndviBuffer = ndviNumber.multiply(0.1); +var ndviRange = [ + ndviNumber.subtract(ndviBuffer), + ndviNumber.add(ndviBuffer) +]; + +print(ndviRange, 'NDVI Range'); + +/* +This function is used to determine the mean value of an image within a given area. +image: an image with a single band of ordinal or interval level data +geom: geometry feature that overlaps with the image +pixelSize: a number that defines the cell size of the image +Returns a dictionary with the median values of the band, the key is the band name. +*/ +var reduceRegionFunction = function(image, geom, pixelSize) { + var dict = image.reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: geom, + scale: pixelSize, + crs: 'EPSG:4326' + }); + return (dict); +}; + +// Call function on the NDVI dataset to compare. +var ndvi_test = reduceRegionFunction(ndvi, exclosure, 1); + +print(ndvi_test, 'ndvi_test'); + +// Call function on elevation dataset. +var elev1 = reduceRegionFunction(elev, exclosure, 30); + +print(elev1, 'elev1'); + +/* +Generate a range of acceptable values. +dictionary: a dictionary object +key: key to the value of interest, must be a string +proportion: a percentile to define the range of the values around the mean +Returns a list with a min and max value for the given range. +*/ +var effectiveRange = function(dictionary, key, proportion) { + var number = ee.Number(dictionary.get(key)); + var buffer = number.multiply(proportion); + var range = [ + number.subtract(buffer), + number.add(buffer) + ]; + return (range); +}; + +// Call function on elevation data. +var elevRange = effectiveRange(elev1, 'elevation', 0.1); + +print(elevRange); + +// Apply multiple filters to get at potential locations. +var combinedFilter = ee.Filter.and( + ee.Filter.greaterThan('ndvi', ndviRange[0]), + ee.Filter.lessThan('ndvi', ndviRange[1]), + ee.Filter.greaterThan('elevation', elevRange[0]), + ee.Filter.lessThan('elevation', elevRange[1]) +); + +var aspenSites2 = aspenSites.filter(combinedFilter); + +print(aspenSites2, 'aspenSites2'); + +Map.addLayer(aspenSites2, {}, 'aspenSites2', false); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37a Checkpoint.py new file mode 100644 index 0000000..08b8183 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37a Checkpoint.py @@ -0,0 +1,246 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +roi = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-108.01888227338851, 39.04480287274028], + [-108.01888227338851, 38.98931938880467], + [-107.85031080122054, 38.98931938880467], + [-107.85031080122054, 39.04480287274028]]], None, False), + sampleArea = + + # shown: False # + ee.Geometry.Polygon( + [[[-107.97587902754866, 39.00939572571298], + [-107.96866924971663, 38.99685612090398], + [-107.94566662520491, 39.00512717360476], + [-107.88558514327131, 39.00325960105985], + [-107.87597210616194, 39.02033271471843], + [-107.93639691084944, 39.024066908916005]]]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.7 Creating Presence and Absence Points +# Checkpoint: A37a +# Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Call in NAIP imagery as an image collection. +naip = ee.ImageCollection('USDA/NAIP/DOQQ') \ + .filterBounds(roi) \ + .filterDate('2015-01-01', '2017-12-31') + +Map.centerObject(naip) + +print(naip) + +# Filter the data based on date. +naip2017 = naip \ + .filterDate('2017-01-01', '2017-12-31') + +naip2015 = naip \ + .filterDate('2015-01-01', '2015-12-31') + +# Define viewing parameters for multi band images. +visParamsFalse = { + 'bands': ['N', 'R', 'G'] +} +visParamsTrue = { + 'bands': ['R', 'G', 'B'] +} + +# Add both sets of NAIP imagery to the map to compare coverage. +Map.addLayer(naip2015, visParamsTrue, '2015_True', False) +Map.addLayer(naip2017, visParamsTrue, '2017_True', False) + +# Add 2015 False color imagery. +Map.addLayer(naip2015, visParamsFalse, '2015_False', False) + +# Creating a geometry feature. +exclosure = ee.Geometry.MultiPolygon([ + [ + [-107.91079184, 39.012553345], + [-107.90828129, 39.012553345], + [-107.90828129, 39.014070552], + [-107.91079184, 39.014070552], + [-107.91079184, 39.012553345] + ], + [ + [-107.9512176, 39.00870162], + [-107.9496834, 39.00870162], + [-107.9496834, 39.00950196], + [-107.95121765, 39.00950196], + [-107.95121765, 39.00870162] + ] +]) + +print(exclosure) + +Map.addLayer(exclosure, {}, 'exclosures') + +# Load in elevation dataset; clip it to general area. +elev = ee.Image('USGS/NED') \ + .clip(roi) + +Map.addLayer(elev, { + 'min': 1500, + 'max': 3300 +}, 'elevation', False) + +# Apply mosaic, clip, then calculate NDVI. +ndvi = naip2015 \ + .mosaic() \ + .clip(roi) \ + .normalizedDifference(['N', 'R']) \ + .rename('ndvi') + +Map.addLayer(ndvi, { + 'min': -0.8, + 'max': 0.8 +}, 'NDVI', False) + +print(ndvi, 'ndvi') + +# Add National Land Cover Database (NLCD). +dataset = ee.ImageCollection('USGS/NLCD') + +print(dataset, 'NLCD') + +# Load the selected NLCD image. +landcover = ee.Image('USGS/NLCD/NLCD2016') \ + .select('landcover') \ + .clip(roi) + +Map.addLayer(landcover, {}, 'Landcover', False) + +# Generate random points within the sample area. +points = ee.FeatureCollection.randomPoints({ + 'region': sampleArea, + 'points': 1000, + 'seed': 1234 +}) + +print(points, 'points') + +Map.addLayer(points, {}, 'Points', False) + +# Add bands of elevation and NAIP. +ndviElev = ndvi \ + .addBands(elev) \ + .addBands(landcover) + +print(ndviElev, 'Multi band image') + +# Extract values to points. +samples = ndviElev.sampleRegions({ + 'collection': points, + 'scale': 30, + 'geometries': True +}) + +print(samples, 'samples') + +Map.addLayer(samples, {}, 'samples', False) + +# Filter metadata for sites in the NLCD deciduous forest layer. +aspenSites = samples.filter(ee.Filter.equals('landcover', 41)) + +print(aspenSites, 'Sites') + +# Set the NDVI range. +ndvi1 = ndvi \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': exclosure, + 'scale': 1, + 'crs': 'EPSG:4326' + }) + +print(ndvi1, 'Mean NDVI') + +# Generate a range of acceptable NDVI values. +ndviNumber = ee.Number(ndvi1.get('ndvi')) +ndviBuffer = ndviNumber.multiply(0.1) +ndviRange = [ + ndviNumber.subtract(ndviBuffer), + ndviNumber.add(ndviBuffer) +] + +print(ndviRange, 'NDVI Range') + +# +This function is used to determine the mean value of an image within a given area. +'image': an image with a single band of ordinal or interval level data +'geom': geometry feature that overlaps with the image +'pixelSize': a number that defines the cell size of the image +Returns a dictionary with the median values of the band, the key is the band name. +# +def reduceRegionFunction(image, geom, pixelSize): + dict = image.reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': geom, + 'scale': pixelSize, + 'crs': 'EPSG:4326' + }) + return (dict) + + +# Call function on the NDVI dataset to compare. +ndvi_test = reduceRegionFunction(ndvi, exclosure, 1) + +print(ndvi_test, 'ndvi_test') + +# Call function on elevation dataset. +elev1 = reduceRegionFunction(elev, exclosure, 30) + +print(elev1, 'elev1') + +# +Generate a range of acceptable values. +'dictionary': a dictionary object +'key': key to the value of interest, must be a string +'proportion': a percentile to define the range of the values around the mean +Returns a list with a min and max value for the given range. +# +def effectiveRange(dictionary, key, proportion): + number = ee.Number(dictionary.get(key)) + buffer = number.multiply(proportion) + range = [ + number.subtract(buffer), + number.add(buffer) + ] + return (range) + + +# Call function on elevation data. +elevRange = effectiveRange(elev1, 'elevation', 0.1) + +print(elevRange) + +# Apply multiple filters to get at potential locations. +combinedFilter = ee.Filter.And( + ee.Filter.greaterThan('ndvi', ndviRange[0]), + ee.Filter.lessThan('ndvi', ndviRange[1]), + ee.Filter.greaterThan('elevation', elevRange[0]), + ee.Filter.lessThan('elevation', elevRange[1]) +) + +aspenSites2 = aspenSites.filter(combinedFilter) + +print(aspenSites2, 'aspenSites2') + +Map.addLayer(aspenSites2, {}, 'aspenSites2', False) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37b Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37b Checkpoint.ipynb new file mode 100644 index 0000000..72bd542 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37b Checkpoint.ipynb @@ -0,0 +1,470 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "roi =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-108.01888227338851, 39.04480287274028],\n", + " [-108.01888227338851, 38.98931938880467],\n", + " [-107.85031080122054, 38.98931938880467],\n", + " [-107.85031080122054, 39.04480287274028]]], None, False),\n", + " sampleArea =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Polygon(\n", + " [[[-107.97587902754866, 39.00939572571298],\n", + " [-107.96866924971663, 38.99685612090398],\n", + " [-107.94566662520491, 39.00512717360476],\n", + " [-107.88558514327131, 39.00325960105985],\n", + " [-107.87597210616194, 39.02033271471843],\n", + " [-107.93639691084944, 39.024066908916005]]]),\n", + "presence = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([-107.95965702742659, 39.00752826586067]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.93244869917952, 39.013330568999095]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.912364318076, 39.013330568999095]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.90558369368635, 39.00992927661494]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.89511234969221, 39.00979588926677]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.89888889998518, 39.00686130396482]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.91262181014143, 39.01146321303844]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.93116123885237, 39.01919908102596]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.96480686873518, 39.012196823046]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.95090229720198, 39.0153312528143]),\n", + " {\n", + " \"Presence\": 1,\n", + " \"system:index\": \"9\"\n", + " })]),\n", + "absence = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([-107.95794041365706, 39.00439349027048]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.95588047713362, 39.01413084931735]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.93905766219221, 39.0132638785638]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.9175141593846, 39.009862582972296]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.91511090010725, 39.01266366181606]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.90352375716292, 39.01599813484129]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.89622814864241, 39.0170651330031]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.921548201743, 39.00559405903748]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.93622524947249, 39.00746156995408]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([-107.92566807478987, 39.00832861183457]),\n", + " {\n", + " \"presence\": 0,\n", + " \"system:index\": \"9\"\n", + " })])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.7 Creating Presence and Absence Points\n", + "# Checkpoint: A37b\n", + "# Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Call in NAIP imagery as an image collection.\n", + "naip = ee.ImageCollection('USDA/NAIP/DOQQ') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2015-01-01', '2017-12-31')\n", + "\n", + "Map.centerObject(naip)\n", + "\n", + "print(naip)\n", + "\n", + "# Filter the data based on date.\n", + "naip2017 = naip \\\n", + " .filterDate('2017-01-01', '2017-12-31')\n", + "\n", + "naip2015 = naip \\\n", + " .filterDate('2015-01-01', '2015-12-31')\n", + "\n", + "# Define viewing parameters for multi band images.\n", + "visParamsFalse = {\n", + " 'bands': ['N', 'R', 'G']\n", + "}\n", + "visParamsTrue = {\n", + " 'bands': ['R', 'G', 'B']\n", + "}\n", + "\n", + "# Add both sets of NAIP imagery to the map to compare coverage.\n", + "Map.addLayer(naip2015, visParamsTrue, '2015_True', False)\n", + "Map.addLayer(naip2017, visParamsTrue, '2017_True', False)\n", + "\n", + "# Add 2015 False color imagery.\n", + "Map.addLayer(naip2015, visParamsFalse, '2015_False', False)\n", + "\n", + "# Creating a geometry feature.\n", + "exclosure = ee.Geometry.MultiPolygon([\n", + " [\n", + " [-107.91079184, 39.012553345],\n", + " [-107.90828129, 39.012553345],\n", + " [-107.90828129, 39.014070552],\n", + " [-107.91079184, 39.014070552],\n", + " [-107.91079184, 39.012553345]\n", + " ],\n", + " [\n", + " [-107.9512176, 39.00870162],\n", + " [-107.9496834, 39.00870162],\n", + " [-107.9496834, 39.00950196],\n", + " [-107.95121765, 39.00950196],\n", + " [-107.95121765, 39.00870162]\n", + " ]\n", + "])\n", + "\n", + "print(exclosure)\n", + "\n", + "Map.addLayer(exclosure, {}, 'exclosures')\n", + "\n", + "# Load in elevation dataset; clip it to general area.\n", + "elev = ee.Image('USGS/NED') \\\n", + " .clip(roi)\n", + "\n", + "Map.addLayer(elev, {\n", + " 'min': 1500,\n", + " 'max': 3300\n", + "}, 'elevation', False)\n", + "\n", + "# Apply mosaic, clip, then calculate NDVI.\n", + "ndvi = naip2015 \\\n", + " .mosaic() \\\n", + " .clip(roi) \\\n", + " .normalizedDifference(['N', 'R']) \\\n", + " .rename('ndvi')\n", + "\n", + "Map.addLayer(ndvi, {\n", + " 'min': -0.8,\n", + " 'max': 0.8\n", + "}, 'NDVI', False)\n", + "\n", + "print(ndvi, 'ndvi')\n", + "\n", + "# Add National Land Cover Database (NLCD).\n", + "dataset = ee.ImageCollection('USGS/NLCD')\n", + "\n", + "print(dataset, 'NLCD')\n", + "\n", + "# Load the selected NLCD image.\n", + "landcover = ee.Image('USGS/NLCD/NLCD2016') \\\n", + " .select('landcover') \\\n", + " .clip(roi)\n", + "\n", + "Map.addLayer(landcover, {}, 'Landcover', False)\n", + "\n", + "# Generate random points within the sample area.\n", + "points = ee.FeatureCollection.randomPoints({\n", + " 'region': sampleArea,\n", + " 'points': 1000,\n", + " 'seed': 1234\n", + "})\n", + "\n", + "print(points, 'points')\n", + "\n", + "Map.addLayer(points, {}, 'Points', False)\n", + "\n", + "# Add bands of elevation and NAIP.\n", + "ndviElev = ndvi \\\n", + " .addBands(elev) \\\n", + " .addBands(landcover)\n", + "\n", + "print(ndviElev, 'Multi band image')\n", + "\n", + "# Extract values to points.\n", + "samples = ndviElev.sampleRegions({\n", + " 'collection': points,\n", + " 'scale': 30,\n", + " 'geometries': True\n", + "})\n", + "\n", + "print(samples, 'samples')\n", + "\n", + "Map.addLayer(samples, {}, 'samples', False)\n", + "\n", + "# Filter metadata for sites in the NLCD deciduous forest layer.\n", + "aspenSites = samples.filter(ee.Filter.equals('landcover', 41))\n", + "\n", + "print(aspenSites, 'Sites')\n", + "\n", + "# Set the NDVI range.\n", + "ndvi1 = ndvi \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': exclosure,\n", + " 'scale': 1,\n", + " 'crs': 'EPSG:4326'\n", + " })\n", + "\n", + "print(ndvi1, 'Mean NDVI')\n", + "\n", + "# Generate a range of acceptable NDVI values.\n", + "ndviNumber = ee.Number(ndvi1.get('ndvi'))\n", + "ndviBuffer = ndviNumber.multiply(0.1)\n", + "ndviRange = [\n", + " ndviNumber.subtract(ndviBuffer),\n", + " ndviNumber.add(ndviBuffer)\n", + "]\n", + "\n", + "print(ndviRange, 'NDVI Range')\n", + "\n", + "#\n", + "This function is used to determine the mean value of an image within a given area.\n", + "'image': an image with a single band of ordinal or interval level data\n", + "'geom': geometry feature that overlaps with the image\n", + "'pixelSize': a number that defines the cell size of the image\n", + "Returns a dictionary with the median values of the band, the key is the band name.\n", + "#\n", + "def reduceRegionFunction(image, geom, pixelSize):\n", + " dict = image.reduceRegion({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'geometry': geom,\n", + " 'scale': pixelSize,\n", + " 'crs': 'EPSG:4326'\n", + " })\n", + " return (dict)\n", + "\n", + "\n", + "# Call function on the NDVI dataset to compare.\n", + "ndvi_test = reduceRegionFunction(ndvi, exclosure, 1)\n", + "\n", + "print(ndvi_test, 'ndvi_test')\n", + "\n", + "# Call function on elevation dataset.\n", + "elev1 = reduceRegionFunction(elev, exclosure, 30)\n", + "\n", + "print(elev1, 'elev1')\n", + "\n", + "#\n", + "Generate a range of acceptable values.\n", + "'dictionary': a dictionary object\n", + "'key': key to the value of interest, must be a string\n", + "'proportion': a percentile to define the range of the values around the mean\n", + "Returns a list with a min and max value for the given range.\n", + "#\n", + "def effectiveRange(dictionary, key, proportion):\n", + " number = ee.Number(dictionary.get(key))\n", + " buffer = number.multiply(proportion)\n", + " range = [\n", + " number.subtract(buffer),\n", + " number.add(buffer)\n", + " ]\n", + " return (range)\n", + "\n", + "\n", + "# Call function on elevation data.\n", + "elevRange = effectiveRange(elev1, 'elevation', 0.1)\n", + "\n", + "print(elevRange)\n", + "\n", + "# Apply multiple filters to get at potential locations.\n", + "combinedFilter = ee.Filter.And(\n", + " ee.Filter.greaterThan('ndvi', ndviRange[0]),\n", + " ee.Filter.lessThan('ndvi', ndviRange[1]),\n", + " ee.Filter.greaterThan('elevation', elevRange[0]),\n", + " ee.Filter.lessThan('elevation', elevRange[1])\n", + ")\n", + "\n", + "aspenSites2 = aspenSites.filter(combinedFilter)\n", + "\n", + "print(aspenSites2, 'aspenSites2')\n", + "\n", + "Map.addLayer(aspenSites2, {}, 'aspenSites2', False)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Merge presence and absence datasets.\n", + "samples = presence.merge(absence)\n", + "\n", + "print(samples, 'Samples')\n", + "\n", + "Export.table.toDrive({\n", + " 'collection': samples,\n", + " 'description': 'presenceAbsencePointsForForest',\n", + " 'fileFormat': 'csv'\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37b Checkpoint.js new file mode 100644 index 0000000..65d4823 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37b Checkpoint.js @@ -0,0 +1,377 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var roi = + /* color: #98ff00 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-108.01888227338851, 39.04480287274028], + [-108.01888227338851, 38.98931938880467], + [-107.85031080122054, 38.98931938880467], + [-107.85031080122054, 39.04480287274028]]], null, false), + sampleArea = + /* color: #bf04c2 */ + /* shown: false */ + ee.Geometry.Polygon( + [[[-107.97587902754866, 39.00939572571298], + [-107.96866924971663, 38.99685612090398], + [-107.94566662520491, 39.00512717360476], + [-107.88558514327131, 39.00325960105985], + [-107.87597210616194, 39.02033271471843], + [-107.93639691084944, 39.024066908916005]]]), + presence = /* color: #00ff00 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([-107.95965702742659, 39.00752826586067]), + { + "Presence": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([-107.93244869917952, 39.013330568999095]), + { + "Presence": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([-107.912364318076, 39.013330568999095]), + { + "Presence": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([-107.90558369368635, 39.00992927661494]), + { + "Presence": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([-107.89511234969221, 39.00979588926677]), + { + "Presence": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([-107.89888889998518, 39.00686130396482]), + { + "Presence": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([-107.91262181014143, 39.01146321303844]), + { + "Presence": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([-107.93116123885237, 39.01919908102596]), + { + "Presence": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([-107.96480686873518, 39.012196823046]), + { + "Presence": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([-107.95090229720198, 39.0153312528143]), + { + "Presence": 1, + "system:index": "9" + })]), + absence = /* color: #0000ff */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([-107.95794041365706, 39.00439349027048]), + { + "presence": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([-107.95588047713362, 39.01413084931735]), + { + "presence": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([-107.93905766219221, 39.0132638785638]), + { + "presence": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([-107.9175141593846, 39.009862582972296]), + { + "presence": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([-107.91511090010725, 39.01266366181606]), + { + "presence": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([-107.90352375716292, 39.01599813484129]), + { + "presence": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([-107.89622814864241, 39.0170651330031]), + { + "presence": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([-107.921548201743, 39.00559405903748]), + { + "presence": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([-107.93622524947249, 39.00746156995408]), + { + "presence": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([-107.92566807478987, 39.00832861183457]), + { + "presence": 0, + "system:index": "9" + })]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.7 Creating Presence and Absence Points +// Checkpoint: A37b +// Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Call in NAIP imagery as an image collection. +var naip = ee.ImageCollection('USDA/NAIP/DOQQ') + .filterBounds(roi) + .filterDate('2015-01-01', '2017-12-31'); + +Map.centerObject(naip); + +print(naip); + +// Filter the data based on date. +var naip2017 = naip + .filterDate('2017-01-01', '2017-12-31'); + +var naip2015 = naip + .filterDate('2015-01-01', '2015-12-31'); + +// Define viewing parameters for multi band images. +var visParamsFalse = { + bands: ['N', 'R', 'G'] +}; +var visParamsTrue = { + bands: ['R', 'G', 'B'] +}; + +// Add both sets of NAIP imagery to the map to compare coverage. +Map.addLayer(naip2015, visParamsTrue, '2015_true', false); +Map.addLayer(naip2017, visParamsTrue, '2017_true', false); + +// Add 2015 false color imagery. +Map.addLayer(naip2015, visParamsFalse, '2015_false', false); + +// Creating a geometry feature. +var exclosure = ee.Geometry.MultiPolygon([ + [ + [-107.91079184, 39.012553345], + [-107.90828129, 39.012553345], + [-107.90828129, 39.014070552], + [-107.91079184, 39.014070552], + [-107.91079184, 39.012553345] + ], + [ + [-107.9512176, 39.00870162], + [-107.9496834, 39.00870162], + [-107.9496834, 39.00950196], + [-107.95121765, 39.00950196], + [-107.95121765, 39.00870162] + ] +]); + +print(exclosure); + +Map.addLayer(exclosure, {}, 'exclosures'); + +// Load in elevation dataset; clip it to general area. +var elev = ee.Image('USGS/NED') + .clip(roi); + +Map.addLayer(elev, { + min: 1500, + max: 3300 +}, 'elevation', false); + +// Apply mosaic, clip, then calculate NDVI. +var ndvi = naip2015 + .mosaic() + .clip(roi) + .normalizedDifference(['N', 'R']) + .rename('ndvi'); + +Map.addLayer(ndvi, { + min: -0.8, + max: 0.8 +}, 'NDVI', false); + +print(ndvi, 'ndvi'); + +// Add National Land Cover Database (NLCD). +var dataset = ee.ImageCollection('USGS/NLCD'); + +print(dataset, 'NLCD'); + +// Load the selected NLCD image. +var landcover = ee.Image('USGS/NLCD/NLCD2016') + .select('landcover') + .clip(roi); + +Map.addLayer(landcover, {}, 'Landcover', false); + +// Generate random points within the sample area. +var points = ee.FeatureCollection.randomPoints({ + region: sampleArea, + points: 1000, + seed: 1234 +}); + +print(points, 'points'); + +Map.addLayer(points, {}, 'Points', false); + +// Add bands of elevation and NAIP. +var ndviElev = ndvi + .addBands(elev) + .addBands(landcover); + +print(ndviElev, 'Multi band image'); + +// Extract values to points. +var samples = ndviElev.sampleRegions({ + collection: points, + scale: 30, + geometries: true +}); + +print(samples, 'samples'); + +Map.addLayer(samples, {}, 'samples', false); + +// Filter metadata for sites in the NLCD deciduous forest layer. +var aspenSites = samples.filter(ee.Filter.equals('landcover', 41)); + +print(aspenSites, 'Sites'); + +// Set the NDVI range. +var ndvi1 = ndvi + .reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: exclosure, + scale: 1, + crs: 'EPSG:4326' + }); + +print(ndvi1, 'Mean NDVI'); + +// Generate a range of acceptable NDVI values. +var ndviNumber = ee.Number(ndvi1.get('ndvi')); +var ndviBuffer = ndviNumber.multiply(0.1); +var ndviRange = [ + ndviNumber.subtract(ndviBuffer), + ndviNumber.add(ndviBuffer) +]; + +print(ndviRange, 'NDVI Range'); + +/* +This function is used to determine the mean value of an image within a given area. +image: an image with a single band of ordinal or interval level data +geom: geometry feature that overlaps with the image +pixelSize: a number that defines the cell size of the image +Returns a dictionary with the median values of the band, the key is the band name. +*/ +var reduceRegionFunction = function(image, geom, pixelSize) { + var dict = image.reduceRegion({ + reducer: ee.Reducer.mean(), + geometry: geom, + scale: pixelSize, + crs: 'EPSG:4326' + }); + return (dict); +}; + +// Call function on the NDVI dataset to compare. +var ndvi_test = reduceRegionFunction(ndvi, exclosure, 1); + +print(ndvi_test, 'ndvi_test'); + +// Call function on elevation dataset. +var elev1 = reduceRegionFunction(elev, exclosure, 30); + +print(elev1, 'elev1'); + +/* +Generate a range of acceptable values. +dictionary: a dictionary object +key: key to the value of interest, must be a string +proportion: a percentile to define the range of the values around the mean +Returns a list with a min and max value for the given range. +*/ +var effectiveRange = function(dictionary, key, proportion) { + var number = ee.Number(dictionary.get(key)); + var buffer = number.multiply(proportion); + var range = [ + number.subtract(buffer), + number.add(buffer) + ]; + return (range); +}; + +// Call function on elevation data. +var elevRange = effectiveRange(elev1, 'elevation', 0.1); + +print(elevRange); + +// Apply multiple filters to get at potential locations. +var combinedFilter = ee.Filter.and( + ee.Filter.greaterThan('ndvi', ndviRange[0]), + ee.Filter.lessThan('ndvi', ndviRange[1]), + ee.Filter.greaterThan('elevation', elevRange[0]), + ee.Filter.lessThan('elevation', elevRange[1]) +); + +var aspenSites2 = aspenSites.filter(combinedFilter); + +print(aspenSites2, 'aspenSites2'); + +Map.addLayer(aspenSites2, {}, 'aspenSites2', false); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Merge presence and absence datasets. +var samples = presence.merge(absence); + +print(samples, 'Samples'); + +Export.table.toDrive({ + collection: samples, + description: 'presenceAbsencePointsForForest', + fileFormat: 'csv' +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37b Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37b Checkpoint.py new file mode 100644 index 0000000..5bed41f --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.7 Creating Presence-Absence Points/A37b Checkpoint.py @@ -0,0 +1,383 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +roi = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-108.01888227338851, 39.04480287274028], + [-108.01888227338851, 38.98931938880467], + [-107.85031080122054, 38.98931938880467], + [-107.85031080122054, 39.04480287274028]]], None, False), + sampleArea = + + # shown: False # + ee.Geometry.Polygon( + [[[-107.97587902754866, 39.00939572571298], + [-107.96866924971663, 38.99685612090398], + [-107.94566662520491, 39.00512717360476], + [-107.88558514327131, 39.00325960105985], + [-107.87597210616194, 39.02033271471843], + [-107.93639691084944, 39.024066908916005]]]), +presence = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([-107.95965702742659, 39.00752826586067]), + { + "Presence": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([-107.93244869917952, 39.013330568999095]), + { + "Presence": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([-107.912364318076, 39.013330568999095]), + { + "Presence": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([-107.90558369368635, 39.00992927661494]), + { + "Presence": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([-107.89511234969221, 39.00979588926677]), + { + "Presence": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([-107.89888889998518, 39.00686130396482]), + { + "Presence": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([-107.91262181014143, 39.01146321303844]), + { + "Presence": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([-107.93116123885237, 39.01919908102596]), + { + "Presence": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([-107.96480686873518, 39.012196823046]), + { + "Presence": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([-107.95090229720198, 39.0153312528143]), + { + "Presence": 1, + "system:index": "9" + })]), +absence = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([-107.95794041365706, 39.00439349027048]), + { + "presence": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([-107.95588047713362, 39.01413084931735]), + { + "presence": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([-107.93905766219221, 39.0132638785638]), + { + "presence": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([-107.9175141593846, 39.009862582972296]), + { + "presence": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([-107.91511090010725, 39.01266366181606]), + { + "presence": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([-107.90352375716292, 39.01599813484129]), + { + "presence": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([-107.89622814864241, 39.0170651330031]), + { + "presence": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([-107.921548201743, 39.00559405903748]), + { + "presence": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([-107.93622524947249, 39.00746156995408]), + { + "presence": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([-107.92566807478987, 39.00832861183457]), + { + "presence": 0, + "system:index": "9" + })]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.7 Creating Presence and Absence Points +# Checkpoint: A37b +# Authors: Peder Engelstad, Daniel Carver, Nicholas E. Young +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Call in NAIP imagery as an image collection. +naip = ee.ImageCollection('USDA/NAIP/DOQQ') \ + .filterBounds(roi) \ + .filterDate('2015-01-01', '2017-12-31') + +Map.centerObject(naip) + +print(naip) + +# Filter the data based on date. +naip2017 = naip \ + .filterDate('2017-01-01', '2017-12-31') + +naip2015 = naip \ + .filterDate('2015-01-01', '2015-12-31') + +# Define viewing parameters for multi band images. +visParamsFalse = { + 'bands': ['N', 'R', 'G'] +} +visParamsTrue = { + 'bands': ['R', 'G', 'B'] +} + +# Add both sets of NAIP imagery to the map to compare coverage. +Map.addLayer(naip2015, visParamsTrue, '2015_True', False) +Map.addLayer(naip2017, visParamsTrue, '2017_True', False) + +# Add 2015 False color imagery. +Map.addLayer(naip2015, visParamsFalse, '2015_False', False) + +# Creating a geometry feature. +exclosure = ee.Geometry.MultiPolygon([ + [ + [-107.91079184, 39.012553345], + [-107.90828129, 39.012553345], + [-107.90828129, 39.014070552], + [-107.91079184, 39.014070552], + [-107.91079184, 39.012553345] + ], + [ + [-107.9512176, 39.00870162], + [-107.9496834, 39.00870162], + [-107.9496834, 39.00950196], + [-107.95121765, 39.00950196], + [-107.95121765, 39.00870162] + ] +]) + +print(exclosure) + +Map.addLayer(exclosure, {}, 'exclosures') + +# Load in elevation dataset; clip it to general area. +elev = ee.Image('USGS/NED') \ + .clip(roi) + +Map.addLayer(elev, { + 'min': 1500, + 'max': 3300 +}, 'elevation', False) + +# Apply mosaic, clip, then calculate NDVI. +ndvi = naip2015 \ + .mosaic() \ + .clip(roi) \ + .normalizedDifference(['N', 'R']) \ + .rename('ndvi') + +Map.addLayer(ndvi, { + 'min': -0.8, + 'max': 0.8 +}, 'NDVI', False) + +print(ndvi, 'ndvi') + +# Add National Land Cover Database (NLCD). +dataset = ee.ImageCollection('USGS/NLCD') + +print(dataset, 'NLCD') + +# Load the selected NLCD image. +landcover = ee.Image('USGS/NLCD/NLCD2016') \ + .select('landcover') \ + .clip(roi) + +Map.addLayer(landcover, {}, 'Landcover', False) + +# Generate random points within the sample area. +points = ee.FeatureCollection.randomPoints({ + 'region': sampleArea, + 'points': 1000, + 'seed': 1234 +}) + +print(points, 'points') + +Map.addLayer(points, {}, 'Points', False) + +# Add bands of elevation and NAIP. +ndviElev = ndvi \ + .addBands(elev) \ + .addBands(landcover) + +print(ndviElev, 'Multi band image') + +# Extract values to points. +samples = ndviElev.sampleRegions({ + 'collection': points, + 'scale': 30, + 'geometries': True +}) + +print(samples, 'samples') + +Map.addLayer(samples, {}, 'samples', False) + +# Filter metadata for sites in the NLCD deciduous forest layer. +aspenSites = samples.filter(ee.Filter.equals('landcover', 41)) + +print(aspenSites, 'Sites') + +# Set the NDVI range. +ndvi1 = ndvi \ + .reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': exclosure, + 'scale': 1, + 'crs': 'EPSG:4326' + }) + +print(ndvi1, 'Mean NDVI') + +# Generate a range of acceptable NDVI values. +ndviNumber = ee.Number(ndvi1.get('ndvi')) +ndviBuffer = ndviNumber.multiply(0.1) +ndviRange = [ + ndviNumber.subtract(ndviBuffer), + ndviNumber.add(ndviBuffer) +] + +print(ndviRange, 'NDVI Range') + +# +This function is used to determine the mean value of an image within a given area. +'image': an image with a single band of ordinal or interval level data +'geom': geometry feature that overlaps with the image +'pixelSize': a number that defines the cell size of the image +Returns a dictionary with the median values of the band, the key is the band name. +# +def reduceRegionFunction(image, geom, pixelSize): + dict = image.reduceRegion({ + 'reducer': ee.Reducer.mean(), + 'geometry': geom, + 'scale': pixelSize, + 'crs': 'EPSG:4326' + }) + return (dict) + + +# Call function on the NDVI dataset to compare. +ndvi_test = reduceRegionFunction(ndvi, exclosure, 1) + +print(ndvi_test, 'ndvi_test') + +# Call function on elevation dataset. +elev1 = reduceRegionFunction(elev, exclosure, 30) + +print(elev1, 'elev1') + +# +Generate a range of acceptable values. +'dictionary': a dictionary object +'key': key to the value of interest, must be a string +'proportion': a percentile to define the range of the values around the mean +Returns a list with a min and max value for the given range. +# +def effectiveRange(dictionary, key, proportion): + number = ee.Number(dictionary.get(key)) + buffer = number.multiply(proportion) + range = [ + number.subtract(buffer), + number.add(buffer) + ] + return (range) + + +# Call function on elevation data. +elevRange = effectiveRange(elev1, 'elevation', 0.1) + +print(elevRange) + +# Apply multiple filters to get at potential locations. +combinedFilter = ee.Filter.And( + ee.Filter.greaterThan('ndvi', ndviRange[0]), + ee.Filter.lessThan('ndvi', ndviRange[1]), + ee.Filter.greaterThan('elevation', elevRange[0]), + ee.Filter.lessThan('elevation', elevRange[1]) +) + +aspenSites2 = aspenSites.filter(combinedFilter) + +print(aspenSites2, 'aspenSites2') + +Map.addLayer(aspenSites2, {}, 'aspenSites2', False) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Merge presence and absence datasets. +samples = presence.merge(absence) + +print(samples, 'Samples') + +Export.table.toDrive({ + 'collection': samples, + 'description': 'presenceAbsencePointsForForest', + 'fileFormat': 'csv' +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38a Checkpoint.ipynb new file mode 100644 index 0000000..cd8532d --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38a Checkpoint.ipynb @@ -0,0 +1,141 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.8 Detecting Land Cover Change in Rangelands\n", + "# Checkpoint: A38a\n", + "# Authors: Ginger Allington, Natalie Kreitzer\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load the shapefile asset for the AOI as a Feature Collection\n", + "aoi = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-8/GEE_Ch_AOI')\n", + "Map.centerObject(aoi, 11)\n", + "Map.addLayer(aoi, {}, 'Subset of Naiman Banner')\n", + "\n", + "# Filter the MODIS Collection\n", + "MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select(\n", + " 'LC_Type1')\n", + "\n", + "# Function to clip an image from the collection and set the year\n", + "def clipCol(img):\n", + " date = ee.String(img.get('system:index'))\n", + " date = date.slice(0, 4)\n", + " return img.select('LC_Type1').clip(aoi) # .clip(aoi) \\\n", + " .set('year', date)\n", + "\n", + "\n", + "# Generate images for diff years you want to compare\n", + "modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map(\n", + " clipCol)\n", + "modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map(\n", + " clipCol)\n", + "modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map(\n", + " clipCol)\n", + "# Create an Image for each of the years\n", + "modis01 = modis01.first()\n", + "modis09 = modis09.first()\n", + "modis16 = modis16.first()\n", + "\n", + "Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False)\n", + "Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False)\n", + "Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False)\n", + "\n", + "# Add and clip the WorldCover data\n", + "wCov = ee.ImageCollection('ESA/WorldCover/v100').first()\n", + "landcover20 = wCov.clip(aoi)\n", + "Map.addLayer(landcover20, {}, 'Landcover 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38a Checkpoint.js new file mode 100644 index 0000000..cf90d4b --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38a Checkpoint.js @@ -0,0 +1,48 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.8 Detecting Land Cover Change in Rangelands +// Checkpoint: A38a +// Authors: Ginger Allington, Natalie Kreitzer +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load the shapefile asset for the AOI as a Feature Collection +var aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI'); +Map.centerObject(aoi, 11); +Map.addLayer(aoi, {}, 'Subset of Naiman Banner'); + +// Filter the MODIS Collection +var MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1'); + +// Function to clip an image from the collection and set the year +var clipCol = function(img) { + var date = ee.String(img.get('system:index')); + date = date.slice(0, 4); + return img.select('LC_Type1').clip(aoi) // .clip(aoi) + .set('year', date); +}; + +// Generate images for diff years you want to compare +var modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol); +var modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol); +var modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol); +// Create an Image for each of the years +var modis01 = modis01.first(); +var modis09 = modis09.first(); +var modis16 = modis16.first(); + +Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', false); +Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', false); +Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', false); + +// Add and clip the WorldCover data +var wCov = ee.ImageCollection('ESA/WorldCover/v100').first(); +var landcover20 = wCov.clip(aoi); +Map.addLayer(landcover20, {}, 'Landcover 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38a Checkpoint.py new file mode 100644 index 0000000..eaed481 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38a Checkpoint.py @@ -0,0 +1,54 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.8 Detecting Land Cover Change in Rangelands +# Checkpoint: A38a +# Authors: Ginger Allington, Natalie Kreitzer +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load the shapefile asset for the AOI as a Feature Collection +aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI') +Map.centerObject(aoi, 11) +Map.addLayer(aoi, {}, 'Subset of Naiman Banner') + +# Filter the MODIS Collection +MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1') + +# Function to clip an image from the collection and set the year +def clipCol(img): + date = ee.String(img.get('system:index')) + date = date.slice(0, 4) + return img.select('LC_Type1').clip(aoi) # .clip(aoi) \ + .set('year', date) + + +# Generate images for diff years you want to compare +modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol) +modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol) +modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol) +# Create an Image for each of the years +modis01 = modis01.first() +modis09 = modis09.first() +modis16 = modis16.first() + +Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False) +Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False) +Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False) + +# Add and clip the WorldCover data +wCov = ee.ImageCollection('ESA/WorldCover/v100').first() +landcover20 = wCov.clip(aoi) +Map.addLayer(landcover20, {}, 'Landcover 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38b Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38b Checkpoint.ipynb new file mode 100644 index 0000000..27b5c7e --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38b Checkpoint.ipynb @@ -0,0 +1,201 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.8 Detecting Land Cover Change in Rangelands\n", + "# Checkpoint: A38b\n", + "# Authors: Ginger Allington, Natalie Kreitzer\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load the shapefile asset for the AOI as a Feature Collection\n", + "aoi = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-8/GEE_Ch_AOI')\n", + "Map.centerObject(aoi, 11)\n", + "Map.addLayer(aoi, {}, 'Subset of Naiman Banner')\n", + "\n", + "# Filter the MODIS Collection\n", + "MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select(\n", + " 'LC_Type1')\n", + "\n", + "# Function to clip an image from the collection and set the year\n", + "def clipCol(img):\n", + " date = ee.String(img.get('system:index'))\n", + " date = date.slice(0, 4)\n", + " return img.select('LC_Type1').clip(aoi) # .clip(aoi) \\\n", + " .set('year', date)\n", + "\n", + "\n", + "# Generate images for diff years you want to compare\n", + "modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map(\n", + " clipCol)\n", + "modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map(\n", + " clipCol)\n", + "modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map(\n", + " clipCol)\n", + "# Create an Image for each of the years\n", + "modis01 = modis01.first()\n", + "modis09 = modis09.first()\n", + "modis16 = modis16.first()\n", + "\n", + "Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False)\n", + "Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False)\n", + "Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False)\n", + "\n", + "# Add and clip the WorldCover data\n", + "wCov = ee.ImageCollection('ESA/WorldCover/v100').first()\n", + "landcover20 = wCov.clip(aoi)\n", + "Map.addLayer(landcover20, {}, 'Landcover 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "greennessColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/GreennessCollection_aoi')\n", + "precipColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/PrecipCollection')\n", + "print(greennessColl, 'Greenness Image Collection')\n", + "print(precipColl, 'Precip Image Collection')\n", + "\n", + "greennessParams = {\n", + " 'bands': ['greenness'],\n", + " 'max': 0.5,\n", + " 'min': 0.06,\n", + " 'opacity': 1,\n", + " 'palette': ['e70808', 'ffffff', '1de22c']\n", + "}\n", + "\n", + "greenness1985 = greennessColl.filterDate('1985-01-01',\n", + " '1986-01-01').select('greenness')\n", + "greenness1999 = greennessColl.filterDate('1999-01-01',\n", + " '2000-01-01').select('greenness')\n", + "\n", + "print(greenness1999)\n", + "greenness2019 = greennessColl.filterDate('2019-01-01',\n", + " '2020-01-01').select('greenness')\n", + "\n", + "Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', False)\n", + "Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', False)\n", + "Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', False)\n", + "\n", + "\n", + "\n", + "# Load a function that will combine the Precipitation and Greenness collections,\n", + "# run a regression, then predict NDVI and calculate the residuals.\n", + "\n", + "# Load the module\n", + "residFunctions = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid'\n", + ")\n", + "\n", + "# Call the function we want that is in that module\n", + "# It requires three input parameters:\n", + "# the greenness collection, the precipitation collection and the aoi\n", + "residualColl = (residFunctions.createResidColl(greennessColl,\n", + " precipColl, aoi))\n", + "\n", + "# Now inspect what you have generated:\n", + "print('Module output of residuals', residualColl)\n", + "\n", + "resids = residualColl.first()\n", + "res1 = resids.select(['residual'])\n", + "print(res1.getInfo(), 'residual image')\n", + "Map.addLayer(res1, {\n", + " 'min': -0.2,\n", + " 'max': 0.2,\n", + " 'palette': ['red', 'white', 'green']\n", + "}, 'residuals 1985', False)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38b Checkpoint.js new file mode 100644 index 0000000..d118efa --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38b Checkpoint.js @@ -0,0 +1,108 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.8 Detecting Land Cover Change in Rangelands +// Checkpoint: A38b +// Authors: Ginger Allington, Natalie Kreitzer +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load the shapefile asset for the AOI as a Feature Collection +var aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI'); +Map.centerObject(aoi, 11); +Map.addLayer(aoi, {}, 'Subset of Naiman Banner'); + +// Filter the MODIS Collection +var MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1'); + +// Function to clip an image from the collection and set the year +var clipCol = function(img) { + var date = ee.String(img.get('system:index')); + date = date.slice(0, 4); + return img.select('LC_Type1').clip(aoi) // .clip(aoi) + .set('year', date); +}; + +// Generate images for diff years you want to compare +var modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol); +var modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol); +var modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol); +// Create an Image for each of the years +var modis01 = modis01.first(); +var modis09 = modis09.first(); +var modis16 = modis16.first(); + +Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', false); +Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', false); +Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', false); + +// Add and clip the WorldCover data +var wCov = ee.ImageCollection('ESA/WorldCover/v100').first(); +var landcover20 = wCov.clip(aoi); +Map.addLayer(landcover20, {}, 'Landcover 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var greennessColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/GreennessCollection_aoi'); +var precipColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/PrecipCollection'); +print(greennessColl, 'Greenness Image Collection'); +print(precipColl, 'Precip Image Collection'); + +var greennessParams = { + bands: ['greenness'], + max: 0.5, + min: 0.06, + opacity: 1, + palette: ['e70808', 'ffffff', '1de22c'] +}; + +var greenness1985 = greennessColl.filterDate('1985-01-01', + '1986-01-01').select('greenness'); +var greenness1999 = greennessColl.filterDate('1999-01-01', + '2000-01-01').select('greenness'); + +print(greenness1999); +var greenness2019 = greennessColl.filterDate('2019-01-01', + '2020-01-01').select('greenness'); + +Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', false); +Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', false); +Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', false); + + + +// Load a function that will combine the Precipitation and Greenness collections, +// run a regression, then predict NDVI and calculate the residuals. + +// Load the module +var residFunctions = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid' +); + +// Call the function we want that is in that module +// It requires three input parameters: +// the greenness collection, the precipitation collection and the aoi +var residualColl = (residFunctions.createResidColl(greennessColl, + precipColl, aoi)); + +// Now inspect what you have generated: +print('Module output of residuals', residualColl); + +var resids = residualColl.first(); +var res1 = resids.select(['residual']); +print(res1.getInfo(), 'residual image'); +Map.addLayer(res1, { + min: -0.2, + max: 0.2, + palette: ['red', 'white', 'green'] +}, 'residuals 1985', false); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38b Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38b Checkpoint.py new file mode 100644 index 0000000..6babc03 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38b Checkpoint.py @@ -0,0 +1,114 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.8 Detecting Land Cover Change in Rangelands +# Checkpoint: A38b +# Authors: Ginger Allington, Natalie Kreitzer +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load the shapefile asset for the AOI as a Feature Collection +aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI') +Map.centerObject(aoi, 11) +Map.addLayer(aoi, {}, 'Subset of Naiman Banner') + +# Filter the MODIS Collection +MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1') + +# Function to clip an image from the collection and set the year +def clipCol(img): + date = ee.String(img.get('system:index')) + date = date.slice(0, 4) + return img.select('LC_Type1').clip(aoi) # .clip(aoi) \ + .set('year', date) + + +# Generate images for diff years you want to compare +modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol) +modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol) +modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol) +# Create an Image for each of the years +modis01 = modis01.first() +modis09 = modis09.first() +modis16 = modis16.first() + +Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False) +Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False) +Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False) + +# Add and clip the WorldCover data +wCov = ee.ImageCollection('ESA/WorldCover/v100').first() +landcover20 = wCov.clip(aoi) +Map.addLayer(landcover20, {}, 'Landcover 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +greennessColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/GreennessCollection_aoi') +precipColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/PrecipCollection') +print(greennessColl, 'Greenness Image Collection') +print(precipColl, 'Precip Image Collection') + +greennessParams = { + 'bands': ['greenness'], + 'max': 0.5, + 'min': 0.06, + 'opacity': 1, + 'palette': ['e70808', 'ffffff', '1de22c'] +} + +greenness1985 = greennessColl.filterDate('1985-01-01', + '1986-01-01').select('greenness') +greenness1999 = greennessColl.filterDate('1999-01-01', + '2000-01-01').select('greenness') + +print(greenness1999) +greenness2019 = greennessColl.filterDate('2019-01-01', + '2020-01-01').select('greenness') + +Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', False) +Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', False) +Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', False) + + + +# Load a function that will combine the Precipitation and Greenness collections, +# run a regression, then predict NDVI and calculate the residuals. + +# Load the module +residFunctions = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid' +) + +# Call the function we want that is in that module +# It requires three input parameters: +# the greenness collection, the precipitation collection and the aoi +residualColl = (residFunctions.createResidColl(greennessColl, + precipColl, aoi)) + +# Now inspect what you have generated: +print('Module output of residuals', residualColl) + +resids = residualColl.first() +res1 = resids.select(['residual']) +print(res1.getInfo(), 'residual image') +Map.addLayer(res1, { + 'min': -0.2, + 'max': 0.2, + 'palette': ['red', 'white', 'green'] +}, 'residuals 1985', False) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38c Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38c Checkpoint.ipynb new file mode 100644 index 0000000..d926919 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38c Checkpoint.ipynb @@ -0,0 +1,313 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.8 Detecting Land Cover Change in Rangelands\n", + "# Checkpoint: A38c\n", + "# Authors: Ginger Allington, Natalie Kreitzer\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load the shapefile asset for the AOI as a Feature Collection\n", + "aoi = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-8/GEE_Ch_AOI')\n", + "Map.centerObject(aoi, 11)\n", + "Map.addLayer(aoi, {}, 'Subset of Naiman Banner')\n", + "\n", + "# Filter the MODIS Collection\n", + "MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select(\n", + " 'LC_Type1')\n", + "\n", + "# Function to clip an image from the collection and set the year\n", + "def clipCol(img):\n", + " date = ee.String(img.get('system:index'))\n", + " date = date.slice(0, 4)\n", + " return img.select('LC_Type1').clip(aoi) # .clip(aoi) \\\n", + " .set('year', date)\n", + "\n", + "\n", + "# Generate images for diff years you want to compare\n", + "modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map(\n", + " clipCol)\n", + "modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map(\n", + " clipCol)\n", + "modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map(\n", + " clipCol)\n", + "# Create an Image for each of the years\n", + "modis01 = modis01.first()\n", + "modis09 = modis09.first()\n", + "modis16 = modis16.first()\n", + "\n", + "#Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False)\n", + "#Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False)\n", + "#Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False)\n", + "\n", + "# Add and clip the WorldCover data\n", + "wCov = ee.ImageCollection('ESA/WorldCover/v100').first()\n", + "landcover20 = wCov.clip(aoi)\n", + "Map.addLayer(landcover20, {}, 'Landcover 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "greennessColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/GreennessCollection_aoi')\n", + "precipColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/PrecipCollection')\n", + "print(greennessColl, 'Greenness Image Collection')\n", + "print(precipColl, 'Precip Image Collection')\n", + "\n", + "greennessParams = {\n", + " 'bands': ['greenness'],\n", + " 'max': 0.5,\n", + " 'min': 0.06,\n", + " 'opacity': 1,\n", + " 'palette': ['e70808', 'ffffff', '1de22c']\n", + "}\n", + "\n", + "greenness1985 = greennessColl.filterDate('1985-01-01',\n", + " '1986-01-01').select('greenness')\n", + "greenness1999 = greennessColl.filterDate('1999-01-01',\n", + " '2000-01-01').select('greenness')\n", + "\n", + "print(greenness1999)\n", + "greenness2019 = greennessColl.filterDate('2019-01-01',\n", + " '2020-01-01').select('greenness')\n", + "\n", + "Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', False)\n", + "Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', False)\n", + "Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', False)\n", + "\n", + "\n", + "\n", + "# Load a function that will combine the Precipitation and Greenness collections, run a regression, then predict NDVI and calculate the residuals.\n", + "\n", + "# Load the module\n", + "residFunctions = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid'\n", + ")\n", + "\n", + "# Call the function we want that is in that module\n", + "# It requires three input parameters:\n", + "# the greenness collection, the precipitation collection and the aoi\n", + "residualColl = (residFunctions.createResidColl(greennessColl,\n", + " precipColl, aoi))\n", + "\n", + "# Now inspect what you have generated:\n", + "print('Module output of residuals', residualColl)\n", + "\n", + "resids = residualColl.first()\n", + "res1 = resids.select(['residual'])\n", + "print(res1.getInfo(), 'residual image')\n", + "Map.addLayer(res1, {\n", + " 'min': -0.2,\n", + " 'max': 0.2,\n", + " 'palette': ['red', 'white', 'green']\n", + "}, 'residuals 1985', False)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "#---- DEFINE RUN PARAMETERS---#\n", + "# LandTrendr run parameters\n", + "runParams = {\n", + " 'maxSegments': 6,\n", + " 'spikeThreshold': 0.9, #\n", + " 'vertexCountOvershoot': 3,\n", + " 'preventOneYearRecovery': True,\n", + " 'recoveryThreshold': 0.25, #\n", + " 'pvalThreshold': 0.05, #\n", + " 'bestModelProportion': 0.75,\n", + " 'minObservationsNeeded': 10 #\n", + "}\n", + "\n", + "# Append the image collection to the LandTrendr run parameter dictionary\n", + "srCollection = residualColl\n", + "runParams.timeSeries = srCollection\n", + "\n", + "# Run LandTrendr\n", + "lt = ee.Algorithms.TemporalSegmentation.LandTrendr(runParams)\n", + "# Explore the output from running LT\n", + "ltlt = lt.select('LandTrendr')\n", + "print(ltlt)\n", + "\n", + "#---- SLICING OUT DATA -----------------#\n", + "\n", + "# Select the LandTrendr band.\n", + "ltlt = lt.select('LandTrendr')\n", + "# Observation Year.\n", + "years = ltlt.arraySlice(0, 0, 1)\n", + "# Slice out observed Residual value.\n", + "observed = ltlt.arraySlice(0, 1, 2)\n", + "# Slice out fitted Residual values (predicted residual from final LT model).\n", + "fitted = ltlt.arraySlice(0, 2, 3)\n", + "# Slice out the 'Is Vertex' row - yes(1)/no(0).\n", + "vertexMask = ltlt.arraySlice(0, 3, 4)\n", + "# Use the 'Is Vertex' row as a mask for all rows.\n", + "vertices = ltlt.arrayMask(vertexMask)\n", + "\n", + "# Define a few params we'll need next:\n", + "startYear_Num = 1985\n", + "endYear_Num = 2019\n", + "numYears = endYear_Num - startYear_Num\n", + "startMonth = '-01-01'\n", + "endMonth = '-12-31'\n", + "\n", + "# Extract fitted residual value per year, per pixel and aggregate into an Image with one band per year\n", + "years = []\n", + "for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \\\n", + " .toString())\n", + "fittedStack = fitted.arrayFlatten([\n", + " ['fittedResidual'], years\n", + "]).toFloat()\n", + "print(fittedStack, 'fitted stack')\n", + "\n", + "Map.addLayer(fittedStack, {\n", + " 'bands': ['fittedResidual_1985'],\n", + " 'min': -0.2,\n", + " 'max': 0.2,\n", + " 'palette': ['red', 'white', 'green']\n", + "}, 'Fitted Residuals 1985')\n", + "\n", + "# Extract boolean 'Is Vertex?' value per year, per pixel and aggregate into image w/ boolean band per year\n", + "years = []\n", + "for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \\\n", + " .toString())\n", + "\n", + "vertexStack = vertexMask.arrayFlatten([\n", + " ['bools'], years\n", + "]).toFloat()\n", + "\n", + "print(vertexStack.getInfo(), 'vertex Stack')\n", + "\n", + "# Load an Asset that has the booleans converted to Collection\n", + "booleanColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/BooleanCollection')\n", + "\n", + "chartBooleanMean = ui.Chart.image \\\n", + " .series({\n", + " 'imageCollection': booleanColl.select('bools'),\n", + " 'region': aoi,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 60,\n", + " 'xProperty': 'system:time_start'\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Naiman Boolean Mean Per Year',\n", + " 'vAxis': {\n", + " 'title': 'Boolean Mean Per Year'\n", + " },\n", + " 'lineWidth': 1\n", + " })\n", + "\n", + "print(chartBooleanMean)\n", + "\n", + "# Plot individual years to see the spatial patterns in the vertices.\n", + "boolParams = {\n", + " # change this for the year you want to view\n", + " 'bands': 'bools_1997',\n", + " 'min': 0,\n", + " # no vertex\n", + " 'max': 1,\n", + " # vertex identified by LT for that year\n", + " 'palette': ['white', 'red']\n", + "}\n", + "\n", + "Map.addLayer(vertexStack, boolParams, 'vertex 1997', False)\n", + "# this visualizes all pixels with a vertex in that year.\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38c Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38c Checkpoint.js new file mode 100644 index 0000000..0a6dc4d --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38c Checkpoint.js @@ -0,0 +1,220 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.8 Detecting Land Cover Change in Rangelands +// Checkpoint: A38c +// Authors: Ginger Allington, Natalie Kreitzer +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load the shapefile asset for the AOI as a Feature Collection +var aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI'); +Map.centerObject(aoi, 11); +Map.addLayer(aoi, {}, 'Subset of Naiman Banner'); + +// Filter the MODIS Collection +var MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1'); + +// Function to clip an image from the collection and set the year +var clipCol = function(img) { + var date = ee.String(img.get('system:index')); + date = date.slice(0, 4); + return img.select('LC_Type1').clip(aoi) // .clip(aoi) + .set('year', date); +}; + +// Generate images for diff years you want to compare +var modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol); +var modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol); +var modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol); +// Create an Image for each of the years +var modis01 = modis01.first(); +var modis09 = modis09.first(); +var modis16 = modis16.first(); + +//Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', false); +//Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', false); +//Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', false); + +// Add and clip the WorldCover data +var wCov = ee.ImageCollection('ESA/WorldCover/v100').first(); +var landcover20 = wCov.clip(aoi); +Map.addLayer(landcover20, {}, 'Landcover 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var greennessColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/GreennessCollection_aoi'); +var precipColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/PrecipCollection'); +print(greennessColl, 'Greenness Image Collection'); +print(precipColl, 'Precip Image Collection'); + +var greennessParams = { + bands: ['greenness'], + max: 0.5, + min: 0.06, + opacity: 1, + palette: ['e70808', 'ffffff', '1de22c'] +}; + +var greenness1985 = greennessColl.filterDate('1985-01-01', + '1986-01-01').select('greenness'); +var greenness1999 = greennessColl.filterDate('1999-01-01', + '2000-01-01').select('greenness'); + +print(greenness1999); +var greenness2019 = greennessColl.filterDate('2019-01-01', + '2020-01-01').select('greenness'); + +Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', false); +Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', false); +Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', false); + + + +// Load a function that will combine the Precipitation and Greenness collections, run a regression, then predict NDVI and calculate the residuals. + +// Load the module +var residFunctions = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid' +); + +// Call the function we want that is in that module +// It requires three input parameters: +// the greenness collection, the precipitation collection and the aoi +var residualColl = (residFunctions.createResidColl(greennessColl, + precipColl, aoi)); + +// Now inspect what you have generated: +print('Module output of residuals', residualColl); + +var resids = residualColl.first(); +var res1 = resids.select(['residual']); +print(res1.getInfo(), 'residual image'); +Map.addLayer(res1, { + min: -0.2, + max: 0.2, + palette: ['red', 'white', 'green'] +}, 'residuals 1985', false); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//---- DEFINE RUN PARAMETERS---// +// LandTrendr run parameters +var runParams = { + maxSegments: 6, + spikeThreshold: 0.9, // + vertexCountOvershoot: 3, + preventOneYearRecovery: true, + recoveryThreshold: 0.25, // + pvalThreshold: 0.05, // + bestModelProportion: 0.75, + minObservationsNeeded: 10 // +}; + +// Append the image collection to the LandTrendr run parameter dictionary +var srCollection = residualColl; +runParams.timeSeries = srCollection; + +// Run LandTrendr +var lt = ee.Algorithms.TemporalSegmentation.LandTrendr(runParams); +// Explore the output from running LT +var ltlt = lt.select('LandTrendr'); +print(ltlt); + +//---- SLICING OUT DATA -----------------// + +// Select the LandTrendr band. +var ltlt = lt.select('LandTrendr'); +// Observation Year. +var years = ltlt.arraySlice(0, 0, 1); +// Slice out observed Residual value. +var observed = ltlt.arraySlice(0, 1, 2); +// Slice out fitted Residual values (predicted residual from final LT model). +var fitted = ltlt.arraySlice(0, 2, 3); +// Slice out the 'Is Vertex' row - yes(1)/no(0). +var vertexMask = ltlt.arraySlice(0, 3, 4); +// Use the 'Is Vertex' row as a mask for all rows. +var vertices = ltlt.arrayMask(vertexMask); + +// Define a few params we'll need next: +var startYear_Num = 1985; +var endYear_Num = 2019; +var numYears = endYear_Num - startYear_Num; +var startMonth = '-01-01'; +var endMonth = '-12-31'; + +// Extract fitted residual value per year, per pixel and aggregate into an Image with one band per year +var years = []; +for (var i = startYear_Num; i <= endYear_Num; ++i) years.push(i + .toString()); +var fittedStack = fitted.arrayFlatten([ + ['fittedResidual'], years +]).toFloat(); +print(fittedStack, 'fitted stack'); + +Map.addLayer(fittedStack, { + bands: ['fittedResidual_1985'], + min: -0.2, + max: 0.2, + palette: ['red', 'white', 'green'] +}, 'Fitted Residuals 1985'); + +// Extract boolean 'Is Vertex?' value per year, per pixel and aggregate into image w/ boolean band per year +var years = []; +for (var i = startYear_Num; i <= endYear_Num; ++i) years.push(i + .toString()); + +var vertexStack = vertexMask.arrayFlatten([ + ['bools'], years +]).toFloat(); + +print(vertexStack.getInfo(), 'vertex Stack'); + +// Load an Asset that has the booleans converted to Collection +var booleanColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/BooleanCollection'); + +var chartBooleanMean = ui.Chart.image + .series({ + imageCollection: booleanColl.select('bools'), + region: aoi, + reducer: ee.Reducer.mean(), + scale: 60, + xProperty: 'system:time_start' + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Naiman Boolean Mean Per Year', + vAxis: { + title: 'Boolean Mean Per Year' + }, + lineWidth: 1 + }); + +print(chartBooleanMean); + +// Plot individual years to see the spatial patterns in the vertices. +var boolParams = { + // change this for the year you want to view + bands: 'bools_1997', + min: 0, + // no vertex + max: 1, + // vertex identified by LT for that year + palette: ['white', 'red'] +}; + +Map.addLayer(vertexStack, boolParams, 'vertex 1997', false); +// this visualizes all pixels with a vertex in that year. + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38c Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38c Checkpoint.py new file mode 100644 index 0000000..ad6ac02 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38c Checkpoint.py @@ -0,0 +1,226 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.8 Detecting Land Cover Change in Rangelands +# Checkpoint: A38c +# Authors: Ginger Allington, Natalie Kreitzer +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load the shapefile asset for the AOI as a Feature Collection +aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI') +Map.centerObject(aoi, 11) +Map.addLayer(aoi, {}, 'Subset of Naiman Banner') + +# Filter the MODIS Collection +MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1') + +# Function to clip an image from the collection and set the year +def clipCol(img): + date = ee.String(img.get('system:index')) + date = date.slice(0, 4) + return img.select('LC_Type1').clip(aoi) # .clip(aoi) \ + .set('year', date) + + +# Generate images for diff years you want to compare +modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol) +modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol) +modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol) +# Create an Image for each of the years +modis01 = modis01.first() +modis09 = modis09.first() +modis16 = modis16.first() + +#Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False) +#Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False) +#Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False) + +# Add and clip the WorldCover data +wCov = ee.ImageCollection('ESA/WorldCover/v100').first() +landcover20 = wCov.clip(aoi) +Map.addLayer(landcover20, {}, 'Landcover 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +greennessColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/GreennessCollection_aoi') +precipColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/PrecipCollection') +print(greennessColl, 'Greenness Image Collection') +print(precipColl, 'Precip Image Collection') + +greennessParams = { + 'bands': ['greenness'], + 'max': 0.5, + 'min': 0.06, + 'opacity': 1, + 'palette': ['e70808', 'ffffff', '1de22c'] +} + +greenness1985 = greennessColl.filterDate('1985-01-01', + '1986-01-01').select('greenness') +greenness1999 = greennessColl.filterDate('1999-01-01', + '2000-01-01').select('greenness') + +print(greenness1999) +greenness2019 = greennessColl.filterDate('2019-01-01', + '2020-01-01').select('greenness') + +Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', False) +Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', False) +Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', False) + + + +# Load a function that will combine the Precipitation and Greenness collections, run a regression, then predict NDVI and calculate the residuals. + +# Load the module +residFunctions = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid' +) + +# Call the function we want that is in that module +# It requires three input parameters: +# the greenness collection, the precipitation collection and the aoi +residualColl = (residFunctions.createResidColl(greennessColl, + precipColl, aoi)) + +# Now inspect what you have generated: +print('Module output of residuals', residualColl) + +resids = residualColl.first() +res1 = resids.select(['residual']) +print(res1.getInfo(), 'residual image') +Map.addLayer(res1, { + 'min': -0.2, + 'max': 0.2, + 'palette': ['red', 'white', 'green'] +}, 'residuals 1985', False) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +#---- DEFINE RUN PARAMETERS---# +# LandTrendr run parameters +runParams = { + 'maxSegments': 6, + 'spikeThreshold': 0.9, # + 'vertexCountOvershoot': 3, + 'preventOneYearRecovery': True, + 'recoveryThreshold': 0.25, # + 'pvalThreshold': 0.05, # + 'bestModelProportion': 0.75, + 'minObservationsNeeded': 10 # +} + +# Append the image collection to the LandTrendr run parameter dictionary +srCollection = residualColl +runParams.timeSeries = srCollection + +# Run LandTrendr +lt = ee.Algorithms.TemporalSegmentation.LandTrendr(runParams) +# Explore the output from running LT +ltlt = lt.select('LandTrendr') +print(ltlt) + +#---- SLICING OUT DATA -----------------# + +# Select the LandTrendr band. +ltlt = lt.select('LandTrendr') +# Observation Year. +years = ltlt.arraySlice(0, 0, 1) +# Slice out observed Residual value. +observed = ltlt.arraySlice(0, 1, 2) +# Slice out fitted Residual values (predicted residual from final LT model). +fitted = ltlt.arraySlice(0, 2, 3) +# Slice out the 'Is Vertex' row - yes(1)/no(0). +vertexMask = ltlt.arraySlice(0, 3, 4) +# Use the 'Is Vertex' row as a mask for all rows. +vertices = ltlt.arrayMask(vertexMask) + +# Define a few params we'll need next: +startYear_Num = 1985 +endYear_Num = 2019 +numYears = endYear_Num - startYear_Num +startMonth = '-01-01' +endMonth = '-12-31' + +# Extract fitted residual value per year, per pixel and aggregate into an Image with one band per year +years = [] +for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \ + .toString()) +fittedStack = fitted.arrayFlatten([ + ['fittedResidual'], years +]).toFloat() +print(fittedStack, 'fitted stack') + +Map.addLayer(fittedStack, { + 'bands': ['fittedResidual_1985'], + 'min': -0.2, + 'max': 0.2, + 'palette': ['red', 'white', 'green'] +}, 'Fitted Residuals 1985') + +# Extract boolean 'Is Vertex?' value per year, per pixel and aggregate into image w/ boolean band per year +years = [] +for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \ + .toString()) + +vertexStack = vertexMask.arrayFlatten([ + ['bools'], years +]).toFloat() + +print(vertexStack.getInfo(), 'vertex Stack') + +# Load an Asset that has the booleans converted to Collection +booleanColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/BooleanCollection') + +chartBooleanMean = ui.Chart.image \ + .series({ + 'imageCollection': booleanColl.select('bools'), + 'region': aoi, + 'reducer': ee.Reducer.mean(), + 'scale': 60, + 'xProperty': 'system:time_start' + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Naiman Boolean Mean Per Year', + 'vAxis': { + 'title': 'Boolean Mean Per Year' + }, + 'lineWidth': 1 + }) + +print(chartBooleanMean) + +# Plot individual years to see the spatial patterns in the vertices. +boolParams = { + # change this for the year you want to view + 'bands': 'bools_1997', + 'min': 0, + # no vertex + 'max': 1, + # vertex identified by LT for that year + 'palette': ['white', 'red'] +} + +Map.addLayer(vertexStack, boolParams, 'vertex 1997', False) +# this visualizes all pixels with a vertex in that year. + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38d Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38d Checkpoint.ipynb new file mode 100644 index 0000000..a66bb17 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38d Checkpoint.ipynb @@ -0,0 +1,342 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.8 Detecting Land Cover Change in Rangelands\n", + "# Checkpoint: A38d\n", + "# Authors: Ginger Allington, Natalie Kreitzer\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load the shapefile asset for the AOI as a Feature Collection\n", + "aoi = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-8/GEE_Ch_AOI')\n", + "Map.centerObject(aoi, 11)\n", + "Map.addLayer(aoi, {}, 'Subset of Naiman Banner')\n", + "\n", + "# Filter the MODIS Collection\n", + "MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select(\n", + " 'LC_Type1')\n", + "\n", + "# Function to clip an image from the collection and set the year\n", + "def clipCol(img):\n", + " date = ee.String(img.get('system:index'))\n", + " date = date.slice(0, 4)\n", + " return img.select('LC_Type1').clip(aoi) # .clip(aoi) \\\n", + " .set('year', date)\n", + "\n", + "\n", + "# Generate images for diff years you want to compare\n", + "modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map(\n", + " clipCol)\n", + "modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map(\n", + " clipCol)\n", + "modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map(\n", + " clipCol)\n", + "# Create an Image for each of the years\n", + "modis01 = modis01.first()\n", + "modis09 = modis09.first()\n", + "modis16 = modis16.first()\n", + "\n", + "Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False)\n", + "Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False)\n", + "Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False)\n", + "\n", + "# Add and clip the WorldCover data\n", + "wCov = ee.ImageCollection('ESA/WorldCover/v100').first()\n", + "landcover20 = wCov.clip(aoi)\n", + "Map.addLayer(landcover20, {}, 'Landcover 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "greennessColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/GreennessCollection_aoi')\n", + "precipColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/PrecipCollection')\n", + "print(greennessColl, 'Greenness Image Collection')\n", + "print(precipColl, 'Precip Image Collection')\n", + "\n", + "greennessParams = {\n", + " 'bands': ['greenness'],\n", + " 'max': 0.5,\n", + " 'min': 0.06,\n", + " 'opacity': 1,\n", + " 'palette': ['e70808', 'ffffff', '1de22c']\n", + "}\n", + "\n", + "greenness1985 = greennessColl.filterDate('1985-01-01',\n", + " '1986-01-01').select('greenness')\n", + "greenness1999 = greennessColl.filterDate('1999-01-01',\n", + " '2000-01-01').select('greenness')\n", + "\n", + "print(greenness1999)\n", + "greenness2019 = greennessColl.filterDate('2019-01-01',\n", + " '2020-01-01').select('greenness')\n", + "\n", + "Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', False)\n", + "Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', False)\n", + "Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', False)\n", + "\n", + "\n", + "\n", + "# Load a function that will combine the Precipitation and Greenness collections, run a regression, then predict NDVI and calculate the residuals.\n", + "\n", + "# Load the module\n", + "residFunctions = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid'\n", + ")\n", + "\n", + "# Call the function we want that is in that module\n", + "# It requires three input parameters:\n", + "# the greenness collection, the precipitation collection and the aoi\n", + "residualColl = (residFunctions.createResidColl(greennessColl,\n", + " precipColl, aoi))\n", + "\n", + "# Now inspect what you have generated:\n", + "print('Module output of residuals', residualColl)\n", + "\n", + "resids = residualColl.first()\n", + "res1 = resids.select(['residual'])\n", + "print(res1.getInfo(), 'residual image')\n", + "Map.addLayer(res1, {\n", + " 'min': -0.2,\n", + " 'max': 0.2,\n", + " 'palette': ['red', 'white', 'green']\n", + "}, 'residuals 1985', False)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "#---- DEFINE RUN PARAMETERS---#\n", + "# LandTrendr run parameters\n", + "runParams = {\n", + " 'maxSegments': 6,\n", + " 'spikeThreshold': 0.9, #\n", + " 'vertexCountOvershoot': 3,\n", + " 'preventOneYearRecovery': True,\n", + " 'recoveryThreshold': 0.25, #\n", + " 'pvalThreshold': 0.05, #\n", + " 'bestModelProportion': 0.75,\n", + " 'minObservationsNeeded': 10 #\n", + "}\n", + "\n", + "# Append the image collection to the LandTrendr run parameter dictionary\n", + "srCollection = residualColl\n", + "runParams.timeSeries = srCollection\n", + "\n", + "# Run LandTrendr\n", + "lt = ee.Algorithms.TemporalSegmentation.LandTrendr(runParams)\n", + "# Explore the output from running LT\n", + "ltlt = lt.select('LandTrendr')\n", + "print(ltlt)\n", + "\n", + "#---- SLICING OUT DATA -----------------#\n", + "\n", + "# Select the LandTrendr band.\n", + "ltlt = lt.select('LandTrendr')\n", + "# Observation Year.\n", + "years = ltlt.arraySlice(0, 0, 1)\n", + "# Slice out observed Residual value.\n", + "observed = ltlt.arraySlice(0, 1, 2)\n", + "# Slice out fitted Residual values (predicted residual from final LT model).\n", + "fitted = ltlt.arraySlice(0, 2, 3)\n", + "# Slice out the 'Is Vertex' row - yes(1)/no(0).\n", + "vertexMask = ltlt.arraySlice(0, 3, 4)\n", + "# Use the 'Is Vertex' row as a mask for all rows.\n", + "vertices = ltlt.arrayMask(vertexMask)\n", + "\n", + "# Define a few params we'll need next:\n", + "startYear_Num = 1985\n", + "endYear_Num = 2019\n", + "numYears = endYear_Num - startYear_Num\n", + "startMonth = '-01-01'\n", + "endMonth = '-12-31'\n", + "\n", + "# Extract fitted residual value per year, per pixel and aggregate into an Image with one band per year\n", + "years = []\n", + "for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \\\n", + " .toString())\n", + "fittedStack = fitted.arrayFlatten([\n", + " ['fittedResidual'], years\n", + "]).toFloat()\n", + "print(fittedStack, 'fitted stack')\n", + "\n", + "Map.addLayer(fittedStack, {\n", + " 'bands': ['fittedResidual_1985'],\n", + " 'min': -0.2,\n", + " 'max': 0.2,\n", + " 'palette': ['red', 'white', 'green']\n", + "}, 'Fitted Residuals 1985')\n", + "\n", + "# Extract boolean 'Is Vertex?' value per year, per pixel and aggregate into image w/ boolean band per year\n", + "years = []\n", + "for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \\\n", + " .toString())\n", + "\n", + "vertexStack = vertexMask.arrayFlatten([\n", + " ['bools'], years\n", + "]).toFloat()\n", + "\n", + "print(vertexStack.getInfo(), 'vertex Stack')\n", + "\n", + "# Load an Asset that has the booleans converted to Collection\n", + "booleanColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/BooleanCollection')\n", + "\n", + "chartBooleanMean = ui.Chart.image \\\n", + " .series({\n", + " 'imageCollection': booleanColl.select('bools'),\n", + " 'region': aoi,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 60,\n", + " 'xProperty': 'system:time_start'\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Naiman Boolean Mean Per Year',\n", + " 'vAxis': {\n", + " 'title': 'Boolean Mean Per Year'\n", + " },\n", + " 'lineWidth': 1\n", + " })\n", + "\n", + "print(chartBooleanMean)\n", + "\n", + "# Plot individual years to see the spatial patterns in the vertices.\n", + "boolParams = {\n", + " # change this for the year you want to view\n", + " 'bands': 'bools_1997',\n", + " 'min': 0,\n", + " # no vertex\n", + " 'max': 1,\n", + " # vertex identified by LT for that year\n", + " 'palette': ['white', 'red']\n", + "}\n", + "\n", + "Map.addLayer(vertexStack, boolParams, 'vertex 1997', False)\n", + "# this visualizes all pixels with a vertex in that year.\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Create training data.\n", + "training = vertexStack.sample({\n", + " 'region': aoi,\n", + " 'scale': 60,\n", + " 'numPixels': 5000\n", + "})\n", + "\n", + "maxclus = 10\n", + "\n", + "# Instantiate the clusterer and train it.\n", + "trained_clusterer = ee.Clusterer.wekaKMeans(maxclus).train(\n", + " training)\n", + "\n", + "# Cluster the input using the trained clusterer\n", + "cluster_result = vertexStack.cluster(trained_clusterer)\n", + "\n", + "# Remap result_totalChange so that class 0 is class 10\n", + "cluster_result = cluster_result.remap(\n", + " [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n", + " [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]) \\\n", + " .toFloat() \\\n", + " .rename('cluster')\n", + "Map.addLayer(cluster_result.randomVisualizer(), {}, maxclus \\\n", + ".toString() + '_clusters')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38d Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38d Checkpoint.js new file mode 100644 index 0000000..5ee06a7 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38d Checkpoint.js @@ -0,0 +1,249 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.8 Detecting Land Cover Change in Rangelands +// Checkpoint: A38d +// Authors: Ginger Allington, Natalie Kreitzer +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load the shapefile asset for the AOI as a Feature Collection +var aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI'); +Map.centerObject(aoi, 11); +Map.addLayer(aoi, {}, 'Subset of Naiman Banner'); + +// Filter the MODIS Collection +var MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1'); + +// Function to clip an image from the collection and set the year +var clipCol = function(img) { + var date = ee.String(img.get('system:index')); + date = date.slice(0, 4); + return img.select('LC_Type1').clip(aoi) // .clip(aoi) + .set('year', date); +}; + +// Generate images for diff years you want to compare +var modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol); +var modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol); +var modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol); +// Create an Image for each of the years +var modis01 = modis01.first(); +var modis09 = modis09.first(); +var modis16 = modis16.first(); + +Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', false); +Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', false); +Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', false); + +// Add and clip the WorldCover data +var wCov = ee.ImageCollection('ESA/WorldCover/v100').first(); +var landcover20 = wCov.clip(aoi); +Map.addLayer(landcover20, {}, 'Landcover 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var greennessColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/GreennessCollection_aoi'); +var precipColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/PrecipCollection'); +print(greennessColl, 'Greenness Image Collection'); +print(precipColl, 'Precip Image Collection'); + +var greennessParams = { + bands: ['greenness'], + max: 0.5, + min: 0.06, + opacity: 1, + palette: ['e70808', 'ffffff', '1de22c'] +}; + +var greenness1985 = greennessColl.filterDate('1985-01-01', + '1986-01-01').select('greenness'); +var greenness1999 = greennessColl.filterDate('1999-01-01', + '2000-01-01').select('greenness'); + +print(greenness1999); +var greenness2019 = greennessColl.filterDate('2019-01-01', + '2020-01-01').select('greenness'); + +Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', false); +Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', false); +Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', false); + + + +// Load a function that will combine the Precipitation and Greenness collections, run a regression, then predict NDVI and calculate the residuals. + +// Load the module +var residFunctions = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid' +); + +// Call the function we want that is in that module +// It requires three input parameters: +// the greenness collection, the precipitation collection and the aoi +var residualColl = (residFunctions.createResidColl(greennessColl, + precipColl, aoi)); + +// Now inspect what you have generated: +print('Module output of residuals', residualColl); + +var resids = residualColl.first(); +var res1 = resids.select(['residual']); +print(res1.getInfo(), 'residual image'); +Map.addLayer(res1, { + min: -0.2, + max: 0.2, + palette: ['red', 'white', 'green'] +}, 'residuals 1985', false); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//---- DEFINE RUN PARAMETERS---// +// LandTrendr run parameters +var runParams = { + maxSegments: 6, + spikeThreshold: 0.9, // + vertexCountOvershoot: 3, + preventOneYearRecovery: true, + recoveryThreshold: 0.25, // + pvalThreshold: 0.05, // + bestModelProportion: 0.75, + minObservationsNeeded: 10 // +}; + +// Append the image collection to the LandTrendr run parameter dictionary +var srCollection = residualColl; +runParams.timeSeries = srCollection; + +// Run LandTrendr +var lt = ee.Algorithms.TemporalSegmentation.LandTrendr(runParams); +// Explore the output from running LT +var ltlt = lt.select('LandTrendr'); +print(ltlt); + +//---- SLICING OUT DATA -----------------// + +// Select the LandTrendr band. +var ltlt = lt.select('LandTrendr'); +// Observation Year. +var years = ltlt.arraySlice(0, 0, 1); +// Slice out observed Residual value. +var observed = ltlt.arraySlice(0, 1, 2); +// Slice out fitted Residual values (predicted residual from final LT model). +var fitted = ltlt.arraySlice(0, 2, 3); +// Slice out the 'Is Vertex' row - yes(1)/no(0). +var vertexMask = ltlt.arraySlice(0, 3, 4); +// Use the 'Is Vertex' row as a mask for all rows. +var vertices = ltlt.arrayMask(vertexMask); + +// Define a few params we'll need next: +var startYear_Num = 1985; +var endYear_Num = 2019; +var numYears = endYear_Num - startYear_Num; +var startMonth = '-01-01'; +var endMonth = '-12-31'; + +// Extract fitted residual value per year, per pixel and aggregate into an Image with one band per year +var years = []; +for (var i = startYear_Num; i <= endYear_Num; ++i) years.push(i + .toString()); +var fittedStack = fitted.arrayFlatten([ + ['fittedResidual'], years +]).toFloat(); +print(fittedStack, 'fitted stack'); + +Map.addLayer(fittedStack, { + bands: ['fittedResidual_1985'], + min: -0.2, + max: 0.2, + palette: ['red', 'white', 'green'] +}, 'Fitted Residuals 1985'); + +// Extract boolean 'Is Vertex?' value per year, per pixel and aggregate into image w/ boolean band per year +var years = []; +for (var i = startYear_Num; i <= endYear_Num; ++i) years.push(i + .toString()); + +var vertexStack = vertexMask.arrayFlatten([ + ['bools'], years +]).toFloat(); + +print(vertexStack.getInfo(), 'vertex Stack'); + +// Load an Asset that has the booleans converted to Collection +var booleanColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/BooleanCollection'); + +var chartBooleanMean = ui.Chart.image + .series({ + imageCollection: booleanColl.select('bools'), + region: aoi, + reducer: ee.Reducer.mean(), + scale: 60, + xProperty: 'system:time_start' + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Naiman Boolean Mean Per Year', + vAxis: { + title: 'Boolean Mean Per Year' + }, + lineWidth: 1 + }); + +print(chartBooleanMean); + +// Plot individual years to see the spatial patterns in the vertices. +var boolParams = { + // change this for the year you want to view + bands: 'bools_1997', + min: 0, + // no vertex + max: 1, + // vertex identified by LT for that year + palette: ['white', 'red'] +}; + +Map.addLayer(vertexStack, boolParams, 'vertex 1997', false); +// this visualizes all pixels with a vertex in that year. + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Create training data. +var training = vertexStack.sample({ + region: aoi, + scale: 60, + numPixels: 5000 +}); + +var maxclus = 10; + +// Instantiate the clusterer and train it. +var trained_clusterer = ee.Clusterer.wekaKMeans(maxclus).train( + training); + +// Cluster the input using the trained clusterer +var cluster_result = vertexStack.cluster(trained_clusterer); + +// Remap result_totalChange so that class 0 is class 10 +cluster_result = cluster_result.remap( + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + .toFloat() + .rename('cluster'); +Map.addLayer(cluster_result.randomVisualizer(), {}, maxclus +.toString() + '_clusters'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38d Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38d Checkpoint.py new file mode 100644 index 0000000..8f8ebe9 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38d Checkpoint.py @@ -0,0 +1,255 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.8 Detecting Land Cover Change in Rangelands +# Checkpoint: A38d +# Authors: Ginger Allington, Natalie Kreitzer +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load the shapefile asset for the AOI as a Feature Collection +aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI') +Map.centerObject(aoi, 11) +Map.addLayer(aoi, {}, 'Subset of Naiman Banner') + +# Filter the MODIS Collection +MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1') + +# Function to clip an image from the collection and set the year +def clipCol(img): + date = ee.String(img.get('system:index')) + date = date.slice(0, 4) + return img.select('LC_Type1').clip(aoi) # .clip(aoi) \ + .set('year', date) + + +# Generate images for diff years you want to compare +modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol) +modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol) +modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol) +# Create an Image for each of the years +modis01 = modis01.first() +modis09 = modis09.first() +modis16 = modis16.first() + +Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False) +Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False) +Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False) + +# Add and clip the WorldCover data +wCov = ee.ImageCollection('ESA/WorldCover/v100').first() +landcover20 = wCov.clip(aoi) +Map.addLayer(landcover20, {}, 'Landcover 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +greennessColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/GreennessCollection_aoi') +precipColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/PrecipCollection') +print(greennessColl, 'Greenness Image Collection') +print(precipColl, 'Precip Image Collection') + +greennessParams = { + 'bands': ['greenness'], + 'max': 0.5, + 'min': 0.06, + 'opacity': 1, + 'palette': ['e70808', 'ffffff', '1de22c'] +} + +greenness1985 = greennessColl.filterDate('1985-01-01', + '1986-01-01').select('greenness') +greenness1999 = greennessColl.filterDate('1999-01-01', + '2000-01-01').select('greenness') + +print(greenness1999) +greenness2019 = greennessColl.filterDate('2019-01-01', + '2020-01-01').select('greenness') + +Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', False) +Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', False) +Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', False) + + + +# Load a function that will combine the Precipitation and Greenness collections, run a regression, then predict NDVI and calculate the residuals. + +# Load the module +residFunctions = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid' +) + +# Call the function we want that is in that module +# It requires three input parameters: +# the greenness collection, the precipitation collection and the aoi +residualColl = (residFunctions.createResidColl(greennessColl, + precipColl, aoi)) + +# Now inspect what you have generated: +print('Module output of residuals', residualColl) + +resids = residualColl.first() +res1 = resids.select(['residual']) +print(res1.getInfo(), 'residual image') +Map.addLayer(res1, { + 'min': -0.2, + 'max': 0.2, + 'palette': ['red', 'white', 'green'] +}, 'residuals 1985', False) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +#---- DEFINE RUN PARAMETERS---# +# LandTrendr run parameters +runParams = { + 'maxSegments': 6, + 'spikeThreshold': 0.9, # + 'vertexCountOvershoot': 3, + 'preventOneYearRecovery': True, + 'recoveryThreshold': 0.25, # + 'pvalThreshold': 0.05, # + 'bestModelProportion': 0.75, + 'minObservationsNeeded': 10 # +} + +# Append the image collection to the LandTrendr run parameter dictionary +srCollection = residualColl +runParams.timeSeries = srCollection + +# Run LandTrendr +lt = ee.Algorithms.TemporalSegmentation.LandTrendr(runParams) +# Explore the output from running LT +ltlt = lt.select('LandTrendr') +print(ltlt) + +#---- SLICING OUT DATA -----------------# + +# Select the LandTrendr band. +ltlt = lt.select('LandTrendr') +# Observation Year. +years = ltlt.arraySlice(0, 0, 1) +# Slice out observed Residual value. +observed = ltlt.arraySlice(0, 1, 2) +# Slice out fitted Residual values (predicted residual from final LT model). +fitted = ltlt.arraySlice(0, 2, 3) +# Slice out the 'Is Vertex' row - yes(1)/no(0). +vertexMask = ltlt.arraySlice(0, 3, 4) +# Use the 'Is Vertex' row as a mask for all rows. +vertices = ltlt.arrayMask(vertexMask) + +# Define a few params we'll need next: +startYear_Num = 1985 +endYear_Num = 2019 +numYears = endYear_Num - startYear_Num +startMonth = '-01-01' +endMonth = '-12-31' + +# Extract fitted residual value per year, per pixel and aggregate into an Image with one band per year +years = [] +for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \ + .toString()) +fittedStack = fitted.arrayFlatten([ + ['fittedResidual'], years +]).toFloat() +print(fittedStack, 'fitted stack') + +Map.addLayer(fittedStack, { + 'bands': ['fittedResidual_1985'], + 'min': -0.2, + 'max': 0.2, + 'palette': ['red', 'white', 'green'] +}, 'Fitted Residuals 1985') + +# Extract boolean 'Is Vertex?' value per year, per pixel and aggregate into image w/ boolean band per year +years = [] +for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \ + .toString()) + +vertexStack = vertexMask.arrayFlatten([ + ['bools'], years +]).toFloat() + +print(vertexStack.getInfo(), 'vertex Stack') + +# Load an Asset that has the booleans converted to Collection +booleanColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/BooleanCollection') + +chartBooleanMean = ui.Chart.image \ + .series({ + 'imageCollection': booleanColl.select('bools'), + 'region': aoi, + 'reducer': ee.Reducer.mean(), + 'scale': 60, + 'xProperty': 'system:time_start' + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Naiman Boolean Mean Per Year', + 'vAxis': { + 'title': 'Boolean Mean Per Year' + }, + 'lineWidth': 1 + }) + +print(chartBooleanMean) + +# Plot individual years to see the spatial patterns in the vertices. +boolParams = { + # change this for the year you want to view + 'bands': 'bools_1997', + 'min': 0, + # no vertex + 'max': 1, + # vertex identified by LT for that year + 'palette': ['white', 'red'] +} + +Map.addLayer(vertexStack, boolParams, 'vertex 1997', False) +# this visualizes all pixels with a vertex in that year. + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Create training data. +training = vertexStack.sample({ + 'region': aoi, + 'scale': 60, + 'numPixels': 5000 +}) + +maxclus = 10 + +# Instantiate the clusterer and train it. +trained_clusterer = ee.Clusterer.wekaKMeans(maxclus).train( + training) + +# Cluster the input using the trained clusterer +cluster_result = vertexStack.cluster(trained_clusterer) + +# Remap result_totalChange so that class 0 is class 10 +cluster_result = cluster_result.remap( + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]) \ + .toFloat() \ + .rename('cluster') +Map.addLayer(cluster_result.randomVisualizer(), {}, maxclus \ +.toString() + '_clusters') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38e Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38e Checkpoint.ipynb new file mode 100644 index 0000000..edff047 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38e Checkpoint.ipynb @@ -0,0 +1,462 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.8 Detecting Land Cover Change in Rangelands\n", + "# Checkpoint: A38e\n", + "# Authors: Ginger Allington, Natalie Kreitzer\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load the shapefile asset for the AOI as a Feature Collection\n", + "aoi = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-8/GEE_Ch_AOI')\n", + "Map.centerObject(aoi, 11)\n", + "Map.addLayer(aoi, {}, 'Subset of Naiman Banner')\n", + "\n", + "# Filter the MODIS Collection\n", + "MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select(\n", + " 'LC_Type1')\n", + "\n", + "# Function to clip an image from the collection and set the year\n", + "def clipCol(img):\n", + " date = ee.String(img.get('system:index'))\n", + " date = date.slice(0, 4)\n", + " return img.select('LC_Type1').clip(aoi) # .clip(aoi) \\\n", + " .set('year', date)\n", + "\n", + "\n", + "# Generate images for diff years you want to compare\n", + "modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map(\n", + " clipCol)\n", + "modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map(\n", + " clipCol)\n", + "modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map(\n", + " clipCol)\n", + "# Create an Image for each of the years\n", + "modis01 = modis01.first()\n", + "modis09 = modis09.first()\n", + "modis16 = modis16.first()\n", + "\n", + "Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False)\n", + "Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False)\n", + "Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False)\n", + "\n", + "# Add and clip the WorldCover data\n", + "wCov = ee.ImageCollection('ESA/WorldCover/v100').first()\n", + "landcover20 = wCov.clip(aoi)\n", + "Map.addLayer(landcover20, {}, 'Landcover 2020')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "greennessColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/GreennessCollection_aoi')\n", + "precipColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/PrecipCollection')\n", + "print(greennessColl, 'Greenness Image Collection')\n", + "print(precipColl, 'Precip Image Collection')\n", + "\n", + "greennessParams = {\n", + " 'bands': ['greenness'],\n", + " 'max': 0.5,\n", + " 'min': 0.06,\n", + " 'opacity': 1,\n", + " 'palette': ['e70808', 'ffffff', '1de22c']\n", + "}\n", + "\n", + "greenness1985 = greennessColl.filterDate('1985-01-01',\n", + " '1986-01-01').select('greenness')\n", + "greenness1999 = greennessColl.filterDate('1999-01-01',\n", + " '2000-01-01').select('greenness')\n", + "\n", + "print(greenness1999)\n", + "greenness2019 = greennessColl.filterDate('2019-01-01',\n", + " '2020-01-01').select('greenness')\n", + "\n", + "Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', False)\n", + "Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', False)\n", + "Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', False)\n", + "\n", + "\n", + "\n", + "# Load a function that will combine the Precipitation and Greenness collections, run a regression, then predict NDVI and calculate the residuals.\n", + "\n", + "# Load the module\n", + "residFunctions = require(\n", + " 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid'\n", + ")\n", + "\n", + "# Call the function we want that is in that module\n", + "# It requires three input parameters:\n", + "# the greenness collection, the precipitation collection and the aoi\n", + "residualColl = (residFunctions.createResidColl(greennessColl,\n", + " precipColl, aoi))\n", + "\n", + "# Now inspect what you have generated:\n", + "print('Module output of residuals', residualColl)\n", + "\n", + "resids = residualColl.first()\n", + "res1 = resids.select(['residual'])\n", + "print(res1.getInfo(), 'residual image')\n", + "Map.addLayer(res1, {\n", + " 'min': -0.2,\n", + " 'max': 0.2,\n", + " 'palette': ['red', 'white', 'green']\n", + "}, 'residuals 1985', False)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "#---- DEFINE RUN PARAMETERS---#\n", + "# LandTrendr run parameters\n", + "runParams = {\n", + " 'maxSegments': 6,\n", + " 'spikeThreshold': 0.9, #\n", + " 'vertexCountOvershoot': 3,\n", + " 'preventOneYearRecovery': True,\n", + " 'recoveryThreshold': 0.25, #\n", + " 'pvalThreshold': 0.05, #\n", + " 'bestModelProportion': 0.75,\n", + " 'minObservationsNeeded': 10 #\n", + "}\n", + "\n", + "# Append the image collection to the LandTrendr run parameter dictionary\n", + "srCollection = residualColl\n", + "runParams.timeSeries = srCollection\n", + "\n", + "# Run LandTrendr\n", + "lt = ee.Algorithms.TemporalSegmentation.LandTrendr(runParams)\n", + "# Explore the output from running LT\n", + "ltlt = lt.select('LandTrendr')\n", + "print(ltlt)\n", + "\n", + "#---- SLICING OUT DATA -----------------#\n", + "\n", + "# Select the LandTrendr band.\n", + "ltlt = lt.select('LandTrendr')\n", + "# Observation Year.\n", + "years = ltlt.arraySlice(0, 0, 1)\n", + "# Slice out observed Residual value.\n", + "observed = ltlt.arraySlice(0, 1, 2)\n", + "# Slice out fitted Residual values (predicted residual from final LT model).\n", + "fitted = ltlt.arraySlice(0, 2, 3)\n", + "# Slice out the 'Is Vertex' row - yes(1)/no(0).\n", + "vertexMask = ltlt.arraySlice(0, 3, 4)\n", + "# Use the 'Is Vertex' row as a mask for all rows.\n", + "vertices = ltlt.arrayMask(vertexMask)\n", + "\n", + "# Define a few params we'll need next:\n", + "startYear_Num = 1985\n", + "endYear_Num = 2019\n", + "numYears = endYear_Num - startYear_Num\n", + "startMonth = '-01-01'\n", + "endMonth = '-12-31'\n", + "\n", + "# Extract fitted residual value per year, per pixel and aggregate into an Image with one band per year\n", + "years = []\n", + "for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \\\n", + " .toString())\n", + "fittedStack = fitted.arrayFlatten([\n", + " ['fittedResidual'], years\n", + "]).toFloat()\n", + "print(fittedStack, 'fitted stack')\n", + "\n", + "Map.addLayer(fittedStack, {\n", + " 'bands': ['fittedResidual_1985'],\n", + " 'min': -0.2,\n", + " 'max': 0.2,\n", + " 'palette': ['red', 'white', 'green']\n", + "}, 'Fitted Residuals 1985')\n", + "\n", + "# Extract boolean 'Is Vertex?' value per year, per pixel and aggregate into image w/ boolean band per year\n", + "years = []\n", + "for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \\\n", + " .toString())\n", + "\n", + "vertexStack = vertexMask.arrayFlatten([\n", + " ['bools'], years\n", + "]).toFloat()\n", + "\n", + "print(vertexStack.getInfo(), 'vertex Stack')\n", + "\n", + "# Load an Asset that has the booleans converted to Collection\n", + "booleanColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/BooleanCollection')\n", + "\n", + "chartBooleanMean = ui.Chart.image \\\n", + " .series({\n", + " 'imageCollection': booleanColl.select('bools'),\n", + " 'region': aoi,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 60,\n", + " 'xProperty': 'system:time_start'\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Naiman Boolean Mean Per Year',\n", + " 'vAxis': {\n", + " 'title': 'Boolean Mean Per Year'\n", + " },\n", + " 'lineWidth': 1\n", + " })\n", + "\n", + "print(chartBooleanMean)\n", + "\n", + "# Plot individual years to see the spatial patterns in the vertices.\n", + "boolParams = {\n", + " # change this for the year you want to view\n", + " 'bands': 'bools_1997',\n", + " 'min': 0,\n", + " # no vertex\n", + " 'max': 1,\n", + " # vertex identified by LT for that year\n", + " 'palette': ['white', 'red']\n", + "}\n", + "\n", + "Map.addLayer(vertexStack, boolParams, 'vertex 1997', False)\n", + "# this visualizes all pixels with a vertex in that year.\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Create training data.\n", + "training = vertexStack.sample({\n", + " 'region': aoi,\n", + " 'scale': 60,\n", + " 'numPixels': 5000\n", + "})\n", + "\n", + "maxclus = 10\n", + "\n", + "# Instantiate the clusterer and train it.\n", + "trained_clusterer = ee.Clusterer.wekaKMeans(maxclus).train(\n", + " training)\n", + "\n", + "# Cluster the input using the trained clusterer\n", + "cluster_result = vertexStack.cluster(trained_clusterer)\n", + "\n", + "# Remap result_totalChange so that class 0 is class 10\n", + "cluster_result = cluster_result.remap(\n", + " [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n", + " [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]) \\\n", + " .toFloat() \\\n", + " .rename('cluster')\n", + "Map.addLayer(cluster_result.randomVisualizer(), {}, maxclus \\\n", + ".toString() + '_clusters')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# GOAL: Find Median Greenness for each cluster per year in the image\n", + "# define a function to add the cluster number band to each Image in the collection\n", + "def addClusters(img):\n", + " return img.addBands(cluster_result)\n", + "\n", + "\n", + "# Add the cluster band\n", + "ObvGreen_wClusters = greennessColl.map(addClusters)\n", + "\n", + "#---Select and mask pixels by cluster number\n", + "cluster_num = 1; # change this to the class of interest\n", + "\n", + "# Mask all pixels but the selected cluster number\n", + "# Define a function so we can map it over the entire collection\n", + "def maskSelCluster(img):\n", + " selCluster = img.select('cluster').eq(cluster_num)\n", + " return img.mask(selCluster)\n", + "\n", + "# map the function over the entire collection\n", + "selClusterColl = ObvGreen_wClusters.map(maskSelCluster)\n", + "\n", + "# Use the following to visualize the location of the focal class:\n", + "Map.addLayer(selClusterColl.select('cluster').first(), {\n", + " 'palette': 'green'\n", + "}, 'Cluster ' + cluster_num.toString())\n", + "\n", + "chartClusterMedian = ui.Chart.image.seriesByRegion({\n", + " 'imageCollection': selClusterColl,\n", + " 'regions': aoi,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'band': 'greenness',\n", + " 'scale': 90,\n", + " 'xProperty': 'system:time_start',\n", + " 'seriesProperty': 'label'\n", + " }) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Median Observed Greenness of Cluster ' + \\\n", + " cluster_num.toString(),\n", + " 'vAxis': {\n", + " 'title': 'Median Observed Greenness'\n", + " },\n", + " 'lineWidth': 1,\n", + " 'pointSize': 4,\n", + " 'series': {\n", + " '0': {\n", + " 'color': 'green'\n", + " },\n", + " }\n", + " })\n", + "\n", + "print(chartClusterMedian)\n", + "\n", + "fittedresidColl = ee.ImageCollection(\n", + " 'projects/gee-book/assets/A3-8/FR_Collection')\n", + "# add the cluster number band to each (function defined above, just use again here)\n", + "fittedresid_wClusters = fittedresidColl.map(addClusters)\n", + "\n", + "#Mask all pixels but the selected cluster number\n", + "# again, function defined above, just call it here\n", + "selFRClusterColl = fittedresid_wClusters.map(maskSelCluster)\n", + "\n", + "Map.addLayer(selFRClusterColl.select('cluster').first(), {\n", + " 'palette': ['white', 'blue']\n", + "}, 'Cluster ' + cluster_num.toString())\n", + "\n", + "#Chart Median Fitted Residual Values by cluster\n", + "\n", + "chartClusterMedian = ui.Chart.image.seriesByRegion({\n", + " 'imageCollection': selFRClusterColl,\n", + " 'regions': aoi,\n", + " 'reducer': ee.Reducer.median(),\n", + " 'band': 'FR',\n", + " 'scale': 90,\n", + " 'xProperty': 'system:time_start',\n", + " 'seriesProperty': 'label'\n", + " }).setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Median Fitted Residual Greenness of Cluster ' + \\\n", + " cluster_num.toString(),\n", + " 'vAxis': {\n", + " 'title': 'Median Residual Greenness'\n", + " },\n", + " 'lineWidth': 1,\n", + " 'pointSize': 4,\n", + " 'series': {\n", + " '0': {\n", + " 'color': 'red'\n", + " },\n", + " }\n", + " })\n", + "\n", + "print(chartClusterMedian)\n", + "\n", + "# Generate a point geometry.\n", + "expt = ee.Geometry.Point(\n", + " [120.52062120781073, 43.10938146169287])\n", + "# Convert to a Feature.\n", + "point = ee.Feature(expt, {})\n", + "\n", + "# Create a time series chart of MODIS Classification:\n", + "chart_LC = ui.Chart.image.seriesByRegion(\n", + " MODIS_LC, point, ee.Reducer.mean(), 'LC_Type1', 30,\n", + " 'system:time_start', 'label') \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'LC of Selected Pixels',\n", + " 'vAxis': {\n", + " 'title': 'MODIS landcover'\n", + " },\n", + " 'lineWidth': 1,\n", + " 'pointSize': 4\n", + " })\n", + "\n", + "print(chart_LC)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38e Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38e Checkpoint.js new file mode 100644 index 0000000..d456ec1 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38e Checkpoint.js @@ -0,0 +1,369 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.8 Detecting Land Cover Change in Rangelands +// Checkpoint: A38e +// Authors: Ginger Allington, Natalie Kreitzer +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load the shapefile asset for the AOI as a Feature Collection +var aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI'); +Map.centerObject(aoi, 11); +Map.addLayer(aoi, {}, 'Subset of Naiman Banner'); + +// Filter the MODIS Collection +var MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1'); + +// Function to clip an image from the collection and set the year +var clipCol = function(img) { + var date = ee.String(img.get('system:index')); + date = date.slice(0, 4); + return img.select('LC_Type1').clip(aoi) // .clip(aoi) + .set('year', date); +}; + +// Generate images for diff years you want to compare +var modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol); +var modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol); +var modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol); +// Create an Image for each of the years +var modis01 = modis01.first(); +var modis09 = modis09.first(); +var modis16 = modis16.first(); + +Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', false); +Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', false); +Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', false); + +// Add and clip the WorldCover data +var wCov = ee.ImageCollection('ESA/WorldCover/v100').first(); +var landcover20 = wCov.clip(aoi); +Map.addLayer(landcover20, {}, 'Landcover 2020'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var greennessColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/GreennessCollection_aoi'); +var precipColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/PrecipCollection'); +print(greennessColl, 'Greenness Image Collection'); +print(precipColl, 'Precip Image Collection'); + +var greennessParams = { + bands: ['greenness'], + max: 0.5, + min: 0.06, + opacity: 1, + palette: ['e70808', 'ffffff', '1de22c'] +}; + +var greenness1985 = greennessColl.filterDate('1985-01-01', + '1986-01-01').select('greenness'); +var greenness1999 = greennessColl.filterDate('1999-01-01', + '2000-01-01').select('greenness'); + +print(greenness1999); +var greenness2019 = greennessColl.filterDate('2019-01-01', + '2020-01-01').select('greenness'); + +Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', false); +Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', false); +Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', false); + + + +// Load a function that will combine the Precipitation and Greenness collections, run a regression, then predict NDVI and calculate the residuals. + +// Load the module +var residFunctions = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid' +); + +// Call the function we want that is in that module +// It requires three input parameters: +// the greenness collection, the precipitation collection and the aoi +var residualColl = (residFunctions.createResidColl(greennessColl, + precipColl, aoi)); + +// Now inspect what you have generated: +print('Module output of residuals', residualColl); + +var resids = residualColl.first(); +var res1 = resids.select(['residual']); +print(res1.getInfo(), 'residual image'); +Map.addLayer(res1, { + min: -0.2, + max: 0.2, + palette: ['red', 'white', 'green'] +}, 'residuals 1985', false); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//---- DEFINE RUN PARAMETERS---// +// LandTrendr run parameters +var runParams = { + maxSegments: 6, + spikeThreshold: 0.9, // + vertexCountOvershoot: 3, + preventOneYearRecovery: true, + recoveryThreshold: 0.25, // + pvalThreshold: 0.05, // + bestModelProportion: 0.75, + minObservationsNeeded: 10 // +}; + +// Append the image collection to the LandTrendr run parameter dictionary +var srCollection = residualColl; +runParams.timeSeries = srCollection; + +// Run LandTrendr +var lt = ee.Algorithms.TemporalSegmentation.LandTrendr(runParams); +// Explore the output from running LT +var ltlt = lt.select('LandTrendr'); +print(ltlt); + +//---- SLICING OUT DATA -----------------// + +// Select the LandTrendr band. +var ltlt = lt.select('LandTrendr'); +// Observation Year. +var years = ltlt.arraySlice(0, 0, 1); +// Slice out observed Residual value. +var observed = ltlt.arraySlice(0, 1, 2); +// Slice out fitted Residual values (predicted residual from final LT model). +var fitted = ltlt.arraySlice(0, 2, 3); +// Slice out the 'Is Vertex' row - yes(1)/no(0). +var vertexMask = ltlt.arraySlice(0, 3, 4); +// Use the 'Is Vertex' row as a mask for all rows. +var vertices = ltlt.arrayMask(vertexMask); + +// Define a few params we'll need next: +var startYear_Num = 1985; +var endYear_Num = 2019; +var numYears = endYear_Num - startYear_Num; +var startMonth = '-01-01'; +var endMonth = '-12-31'; + +// Extract fitted residual value per year, per pixel and aggregate into an Image with one band per year +var years = []; +for (var i = startYear_Num; i <= endYear_Num; ++i) years.push(i + .toString()); +var fittedStack = fitted.arrayFlatten([ + ['fittedResidual'], years +]).toFloat(); +print(fittedStack, 'fitted stack'); + +Map.addLayer(fittedStack, { + bands: ['fittedResidual_1985'], + min: -0.2, + max: 0.2, + palette: ['red', 'white', 'green'] +}, 'Fitted Residuals 1985'); + +// Extract boolean 'Is Vertex?' value per year, per pixel and aggregate into image w/ boolean band per year +var years = []; +for (var i = startYear_Num; i <= endYear_Num; ++i) years.push(i + .toString()); + +var vertexStack = vertexMask.arrayFlatten([ + ['bools'], years +]).toFloat(); + +print(vertexStack.getInfo(), 'vertex Stack'); + +// Load an Asset that has the booleans converted to Collection +var booleanColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/BooleanCollection'); + +var chartBooleanMean = ui.Chart.image + .series({ + imageCollection: booleanColl.select('bools'), + region: aoi, + reducer: ee.Reducer.mean(), + scale: 60, + xProperty: 'system:time_start' + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Naiman Boolean Mean Per Year', + vAxis: { + title: 'Boolean Mean Per Year' + }, + lineWidth: 1 + }); + +print(chartBooleanMean); + +// Plot individual years to see the spatial patterns in the vertices. +var boolParams = { + // change this for the year you want to view + bands: 'bools_1997', + min: 0, + // no vertex + max: 1, + // vertex identified by LT for that year + palette: ['white', 'red'] +}; + +Map.addLayer(vertexStack, boolParams, 'vertex 1997', false); +// this visualizes all pixels with a vertex in that year. + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Create training data. +var training = vertexStack.sample({ + region: aoi, + scale: 60, + numPixels: 5000 +}); + +var maxclus = 10; + +// Instantiate the clusterer and train it. +var trained_clusterer = ee.Clusterer.wekaKMeans(maxclus).train( + training); + +// Cluster the input using the trained clusterer +var cluster_result = vertexStack.cluster(trained_clusterer); + +// Remap result_totalChange so that class 0 is class 10 +cluster_result = cluster_result.remap( + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + .toFloat() + .rename('cluster'); +Map.addLayer(cluster_result.randomVisualizer(), {}, maxclus +.toString() + '_clusters'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// GOAL: Find Median Greenness for each cluster per year in the image +// define a function to add the cluster number band to each Image in the collection +var addClusters = function(img) { + return img.addBands(cluster_result); +}; + +// Add the cluster band +var ObvGreen_wClusters = greennessColl.map(addClusters); + +//---Select and mask pixels by cluster number +var cluster_num = 1; // change this to the class of interest + +// Mask all pixels but the selected cluster number +// Define a function so we can map it over the entire collection +var maskSelCluster = function(img) { + var selCluster = img.select('cluster').eq(cluster_num); + return img.mask(selCluster); +}; +// map the function over the entire collection +var selClusterColl = ObvGreen_wClusters.map(maskSelCluster); + +// Use the following to visualize the location of the focal class: +Map.addLayer(selClusterColl.select('cluster').first(), { + palette: 'green' +}, 'Cluster ' + cluster_num.toString()); + +var chartClusterMedian = ui.Chart.image.seriesByRegion({ + imageCollection: selClusterColl, + regions: aoi, + reducer: ee.Reducer.median(), + band: 'greenness', + scale: 90, + xProperty: 'system:time_start', + seriesProperty: 'label' + }) + .setChartType('ScatterChart') + .setOptions({ + title: 'Median Observed Greenness of Cluster ' + + cluster_num.toString(), + vAxis: { + title: 'Median Observed Greenness' + }, + lineWidth: 1, + pointSize: 4, + series: { + 0: { + color: 'green' + }, + } + }); + +print(chartClusterMedian); + +var fittedresidColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/FR_Collection'); +// add the cluster number band to each (function defined above, just use again here) +var fittedresid_wClusters = fittedresidColl.map(addClusters); + +//Mask all pixels but the selected cluster number +// again, function defined above, just call it here +var selFRClusterColl = fittedresid_wClusters.map(maskSelCluster); + +Map.addLayer(selFRClusterColl.select('cluster').first(), { + palette: ['white', 'blue'] +}, 'Cluster ' + cluster_num.toString()); + +//Chart Median Fitted Residual Values by cluster + +var chartClusterMedian = ui.Chart.image.seriesByRegion({ + imageCollection: selFRClusterColl, + regions: aoi, + reducer: ee.Reducer.median(), + band: 'FR', + scale: 90, + xProperty: 'system:time_start', + seriesProperty: 'label' + }).setChartType('ScatterChart') + .setOptions({ + title: 'Median Fitted Residual Greenness of Cluster ' + + cluster_num.toString(), + vAxis: { + title: 'Median Residual Greenness' + }, + lineWidth: 1, + pointSize: 4, + series: { + 0: { + color: 'red' + }, + } + }); + +print(chartClusterMedian); + +// Generate a point geometry. +var expt = ee.Geometry.Point( + [120.52062120781073, 43.10938146169287]); +// Convert to a Feature. +var point = ee.Feature(expt, {}); + +// Create a time series chart of MODIS Classification: +var chart_LC = ui.Chart.image.seriesByRegion( + MODIS_LC, point, ee.Reducer.mean(), 'LC_Type1', 30, + 'system:time_start', 'label') + .setChartType('ScatterChart') + .setOptions({ + title: 'LC of Selected Pixels', + vAxis: { + title: 'MODIS landcover' + }, + lineWidth: 1, + pointSize: 4 + }); + +print(chart_LC); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38e Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38e Checkpoint.py new file mode 100644 index 0000000..38e7418 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38e Checkpoint.py @@ -0,0 +1,375 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.8 Detecting Land Cover Change in Rangelands +# Checkpoint: A38e +# Authors: Ginger Allington, Natalie Kreitzer +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load the shapefile asset for the AOI as a Feature Collection +aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI') +Map.centerObject(aoi, 11) +Map.addLayer(aoi, {}, 'Subset of Naiman Banner') + +# Filter the MODIS Collection +MODIS_LC = ee.ImageCollection('MODIS/006/MCD12Q1').select( + 'LC_Type1') + +# Function to clip an image from the collection and set the year +def clipCol(img): + date = ee.String(img.get('system:index')) + date = date.slice(0, 4) + return img.select('LC_Type1').clip(aoi) # .clip(aoi) \ + .set('year', date) + + +# Generate images for diff years you want to compare +modis01 = MODIS_LC.filterDate('2001-01-01', '2002-01-01').map( + clipCol) +modis09 = MODIS_LC.filterDate('2009-01-01', '2010-01-01').map( + clipCol) +modis16 = MODIS_LC.filterDate('2016-01-01', '2017-01-01').map( + clipCol) +# Create an Image for each of the years +modis01 = modis01.first() +modis09 = modis09.first() +modis16 = modis16.first() + +Map.addLayer(modis01.randomVisualizer(), {}, 'modis 2001', False) +Map.addLayer(modis09.randomVisualizer(), {}, 'modis 2009', False) +Map.addLayer(modis16.randomVisualizer(), {}, 'modis 2016', False) + +# Add and clip the WorldCover data +wCov = ee.ImageCollection('ESA/WorldCover/v100').first() +landcover20 = wCov.clip(aoi) +Map.addLayer(landcover20, {}, 'Landcover 2020') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +greennessColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/GreennessCollection_aoi') +precipColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/PrecipCollection') +print(greennessColl, 'Greenness Image Collection') +print(precipColl, 'Precip Image Collection') + +greennessParams = { + 'bands': ['greenness'], + 'max': 0.5, + 'min': 0.06, + 'opacity': 1, + 'palette': ['e70808', 'ffffff', '1de22c'] +} + +greenness1985 = greennessColl.filterDate('1985-01-01', + '1986-01-01').select('greenness') +greenness1999 = greennessColl.filterDate('1999-01-01', + '2000-01-01').select('greenness') + +print(greenness1999) +greenness2019 = greennessColl.filterDate('2019-01-01', + '2020-01-01').select('greenness') + +Map.addLayer(greenness1985, greennessParams, 'Greenness 1985', False) +Map.addLayer(greenness1999, greennessParams, 'Greenness 1999', False) +Map.addLayer(greenness2019, greennessParams, 'Greenness 2019', False) + + + +# Load a function that will combine the Precipitation and Greenness collections, run a regression, then predict NDVI and calculate the residuals. + +# Load the module +residFunctions = require( + 'projects/gee-edu/book:Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid' +) + +# Call the function we want that is in that module +# It requires three input parameters: +# the greenness collection, the precipitation collection and the aoi +residualColl = (residFunctions.createResidColl(greennessColl, + precipColl, aoi)) + +# Now inspect what you have generated: +print('Module output of residuals', residualColl) + +resids = residualColl.first() +res1 = resids.select(['residual']) +print(res1.getInfo(), 'residual image') +Map.addLayer(res1, { + 'min': -0.2, + 'max': 0.2, + 'palette': ['red', 'white', 'green'] +}, 'residuals 1985', False) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +#---- DEFINE RUN PARAMETERS---# +# LandTrendr run parameters +runParams = { + 'maxSegments': 6, + 'spikeThreshold': 0.9, # + 'vertexCountOvershoot': 3, + 'preventOneYearRecovery': True, + 'recoveryThreshold': 0.25, # + 'pvalThreshold': 0.05, # + 'bestModelProportion': 0.75, + 'minObservationsNeeded': 10 # +} + +# Append the image collection to the LandTrendr run parameter dictionary +srCollection = residualColl +runParams.timeSeries = srCollection + +# Run LandTrendr +lt = ee.Algorithms.TemporalSegmentation.LandTrendr(runParams) +# Explore the output from running LT +ltlt = lt.select('LandTrendr') +print(ltlt) + +#---- SLICING OUT DATA -----------------# + +# Select the LandTrendr band. +ltlt = lt.select('LandTrendr') +# Observation Year. +years = ltlt.arraySlice(0, 0, 1) +# Slice out observed Residual value. +observed = ltlt.arraySlice(0, 1, 2) +# Slice out fitted Residual values (predicted residual from final LT model). +fitted = ltlt.arraySlice(0, 2, 3) +# Slice out the 'Is Vertex' row - yes(1)/no(0). +vertexMask = ltlt.arraySlice(0, 3, 4) +# Use the 'Is Vertex' row as a mask for all rows. +vertices = ltlt.arrayMask(vertexMask) + +# Define a few params we'll need next: +startYear_Num = 1985 +endYear_Num = 2019 +numYears = endYear_Num - startYear_Num +startMonth = '-01-01' +endMonth = '-12-31' + +# Extract fitted residual value per year, per pixel and aggregate into an Image with one band per year +years = [] +for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \ + .toString()) +fittedStack = fitted.arrayFlatten([ + ['fittedResidual'], years +]).toFloat() +print(fittedStack, 'fitted stack') + +Map.addLayer(fittedStack, { + 'bands': ['fittedResidual_1985'], + 'min': -0.2, + 'max': 0.2, + 'palette': ['red', 'white', 'green'] +}, 'Fitted Residuals 1985') + +# Extract boolean 'Is Vertex?' value per year, per pixel and aggregate into image w/ boolean band per year +years = [] +for (i = startYear_Num; i <= endYear_Num; ++i) years.push(i \ + .toString()) + +vertexStack = vertexMask.arrayFlatten([ + ['bools'], years +]).toFloat() + +print(vertexStack.getInfo(), 'vertex Stack') + +# Load an Asset that has the booleans converted to Collection +booleanColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/BooleanCollection') + +chartBooleanMean = ui.Chart.image \ + .series({ + 'imageCollection': booleanColl.select('bools'), + 'region': aoi, + 'reducer': ee.Reducer.mean(), + 'scale': 60, + 'xProperty': 'system:time_start' + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Naiman Boolean Mean Per Year', + 'vAxis': { + 'title': 'Boolean Mean Per Year' + }, + 'lineWidth': 1 + }) + +print(chartBooleanMean) + +# Plot individual years to see the spatial patterns in the vertices. +boolParams = { + # change this for the year you want to view + 'bands': 'bools_1997', + 'min': 0, + # no vertex + 'max': 1, + # vertex identified by LT for that year + 'palette': ['white', 'red'] +} + +Map.addLayer(vertexStack, boolParams, 'vertex 1997', False) +# this visualizes all pixels with a vertex in that year. + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Create training data. +training = vertexStack.sample({ + 'region': aoi, + 'scale': 60, + 'numPixels': 5000 +}) + +maxclus = 10 + +# Instantiate the clusterer and train it. +trained_clusterer = ee.Clusterer.wekaKMeans(maxclus).train( + training) + +# Cluster the input using the trained clusterer +cluster_result = vertexStack.cluster(trained_clusterer) + +# Remap result_totalChange so that class 0 is class 10 +cluster_result = cluster_result.remap( + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]) \ + .toFloat() \ + .rename('cluster') +Map.addLayer(cluster_result.randomVisualizer(), {}, maxclus \ +.toString() + '_clusters') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# GOAL: Find Median Greenness for each cluster per year in the image +# define a function to add the cluster number band to each Image in the collection +def addClusters(img): + return img.addBands(cluster_result) + + +# Add the cluster band +ObvGreen_wClusters = greennessColl.map(addClusters) + +#---Select and mask pixels by cluster number +cluster_num = 1; # change this to the class of interest + +# Mask all pixels but the selected cluster number +# Define a function so we can map it over the entire collection +def maskSelCluster(img): + selCluster = img.select('cluster').eq(cluster_num) + return img.mask(selCluster) + +# map the function over the entire collection +selClusterColl = ObvGreen_wClusters.map(maskSelCluster) + +# Use the following to visualize the location of the focal class: +Map.addLayer(selClusterColl.select('cluster').first(), { + 'palette': 'green' +}, 'Cluster ' + cluster_num.toString()) + +chartClusterMedian = ui.Chart.image.seriesByRegion({ + 'imageCollection': selClusterColl, + 'regions': aoi, + 'reducer': ee.Reducer.median(), + 'band': 'greenness', + 'scale': 90, + 'xProperty': 'system:time_start', + 'seriesProperty': 'label' + }) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Median Observed Greenness of Cluster ' + \ + cluster_num.toString(), + 'vAxis': { + 'title': 'Median Observed Greenness' + }, + 'lineWidth': 1, + 'pointSize': 4, + 'series': { + '0': { + 'color': 'green' + }, + } + }) + +print(chartClusterMedian) + +fittedresidColl = ee.ImageCollection( + 'projects/gee-book/assets/A3-8/FR_Collection') +# add the cluster number band to each (function defined above, just use again here) +fittedresid_wClusters = fittedresidColl.map(addClusters) + +#Mask all pixels but the selected cluster number +# again, function defined above, just call it here +selFRClusterColl = fittedresid_wClusters.map(maskSelCluster) + +Map.addLayer(selFRClusterColl.select('cluster').first(), { + 'palette': ['white', 'blue'] +}, 'Cluster ' + cluster_num.toString()) + +#Chart Median Fitted Residual Values by cluster + +chartClusterMedian = ui.Chart.image.seriesByRegion({ + 'imageCollection': selFRClusterColl, + 'regions': aoi, + 'reducer': ee.Reducer.median(), + 'band': 'FR', + 'scale': 90, + 'xProperty': 'system:time_start', + 'seriesProperty': 'label' + }).setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Median Fitted Residual Greenness of Cluster ' + \ + cluster_num.toString(), + 'vAxis': { + 'title': 'Median Residual Greenness' + }, + 'lineWidth': 1, + 'pointSize': 4, + 'series': { + '0': { + 'color': 'red' + }, + } + }) + +print(chartClusterMedian) + +# Generate a point geometry. +expt = ee.Geometry.Point( + [120.52062120781073, 43.10938146169287]) +# Convert to a Feature. +point = ee.Feature(expt, {}) + +# Create a time series chart of MODIS Classification: +chart_LC = ui.Chart.image.seriesByRegion( + MODIS_LC, point, ee.Reducer.mean(), 'LC_Type1', 30, + 'system:time_start', 'label') \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'LC of Selected Pixels', + 'vAxis': { + 'title': 'MODIS landcover' + }, + 'lineWidth': 1, + 'pointSize': 4 + }) + +print(chart_LC) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38s1 - Supplemental.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38s1 - Supplemental.ipynb new file mode 100644 index 0000000..679e78c --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38s1 - Supplemental.ipynb @@ -0,0 +1,136 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: A3.8 Detecting Land Cover Change in Rangelands\n", + "# Section: Section 3 (A38s1 - Supplemental)\n", + "# Authors: G.R.H. Allington, N. Kreitzer\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# This code chunk demonstrates how to generate an Image Collection from\n", + "# a multi-band Image. In this case each band in the Image represents a year.\n", + "\n", + "# Load the shapefile asset for the AOI as a Feature Collection.\n", + "aoi = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/A3-8/GEE_Ch_AOI')\n", + "# Load the multi-band Image of fitted residual greenness values.\n", + "fittedStack = ee.Image('projects/gee-book/assets/A3-8/FR_stack')\n", + "\n", + "startYear_Num = 1985\n", + "endYear_Num = 2019\n", + "numYears = endYear_Num - startYear_Num\n", + "startMonth = '-01-01'\n", + "endMonth = '-12-31'\n", + "\n", + "# Convert the multi-band Image to a List\n", + "\n", + "fittedStackList = ee.List([])\n", + " for year in range(startYear_Num, , 1):\n", + " selBand = (fittedStack.select('fittedResidual_' + year.toString()).rename('FR'))\n", + " selImg = ee.Image(selBand)\n", + " nextYear = year + 1\n", + " system_time_start = ee.Date(year.toString() + startMonth).millis()\n", + " system_time_end = ee.Date(nextYear.toString() + startMonth).millis()\n", + " system_index = year - startYear_Num + 1\n", + " selImg = selImg \\\n", + " .set('year', year) \\\n", + " .set('system:time_start', system_time_start) \\\n", + " .set('system:time_end', system_time_end) \\\n", + " .set('system:index', system_index.toString())\n", + " fittedStackList = fittedStackList.add(selImg)\n", + "\n", + "\n", + "\n", + "fittedresidColl = ee.ImageCollection(fittedStackList)\n", + "\n", + "# You will need to export this to an Asset if you want to call it in a separate script." + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38s1 - Supplemental.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38s1 - Supplemental.js new file mode 100644 index 0000000..20ad82a --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38s1 - Supplemental.js @@ -0,0 +1,43 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: A3.8 Detecting Land Cover Change in Rangelands +// Section: Section 3 (A38s1 - Supplemental) +// Authors: G.R.H. Allington, N. Kreitzer +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// This code chunk demonstrates how to generate an Image Collection from +// a multi-band Image. In this case each band in the Image represents a year. + +// Load the shapefile asset for the AOI as a Feature Collection. +var aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI'); +// Load the multi-band Image of fitted residual greenness values. +var fittedStack = ee.Image('projects/gee-book/assets/A3-8/FR_stack'); + +var startYear_Num = 1985; +var endYear_Num = 2019; +var numYears = endYear_Num - startYear_Num; +var startMonth = '-01-01'; +var endMonth = '-12-31'; + +// Convert the multi-band Image to a List + +var fittedStackList = ee.List([]); + for (var year = startYear_Num; year <= endYear_Num ; year++) { + var selBand = (fittedStack.select('fittedResidual_' + year.toString()).rename('FR')); + var selImg = ee.Image(selBand); + var nextYear = year + 1; + var system_time_start = ee.Date(year.toString() + startMonth).millis(); + var system_time_end = ee.Date(nextYear.toString() + startMonth).millis(); + var system_index = year - startYear_Num + 1; + selImg = selImg + .set('year', year) + .set('system:time_start', system_time_start) + .set('system:time_end', system_time_end) + .set('system:index', system_index.toString()); + fittedStackList = fittedStackList.add(selImg); +} + + +var fittedresidColl = ee.ImageCollection(fittedStackList); + +// You will need to export this to an Asset if you want to call it in a separate script. diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38s1 - Supplemental.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38s1 - Supplemental.py new file mode 100644 index 0000000..73c6708 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/A38s1 - Supplemental.py @@ -0,0 +1,49 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: A3.8 Detecting Land Cover Change in Rangelands +# Section: Section 3 (A38s1 - Supplemental) +# Authors: G.R.H. Allington, N. Kreitzer +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# This code chunk demonstrates how to generate an Image Collection from +# a multi-band Image. In this case each band in the Image represents a year. + +# Load the shapefile asset for the AOI as a Feature Collection. +aoi = ee.FeatureCollection( + 'projects/gee-book/assets/A3-8/GEE_Ch_AOI') +# Load the multi-band Image of fitted residual greenness values. +fittedStack = ee.Image('projects/gee-book/assets/A3-8/FR_stack') + +startYear_Num = 1985 +endYear_Num = 2019 +numYears = endYear_Num - startYear_Num +startMonth = '-01-01' +endMonth = '-12-31' + +# Convert the multi-band Image to a List + +fittedStackList = ee.List([]) + for year in range(startYear_Num, , 1): + selBand = (fittedStack.select('fittedResidual_' + year.toString()).rename('FR')) + selImg = ee.Image(selBand) + nextYear = year + 1 + system_time_start = ee.Date(year.toString() + startMonth).millis() + system_time_end = ee.Date(nextYear.toString() + startMonth).millis() + system_index = year - startYear_Num + 1 + selImg = selImg \ + .set('year', year) \ + .set('system:time_start', system_time_start) \ + .set('system:time_end', system_time_end) \ + .set('system:index', system_index.toString()) + fittedStackList = fittedStackList.add(selImg) + + + +fittedresidColl = ee.ImageCollection(fittedStackList) + +# You will need to export this to an Asset if you want to call it in a separate script. +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid.ipynb new file mode 100644 index 0000000..f36a543 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid.ipynb @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "\n", + "\n", + "# Function to calculate predicted ndvi and residuals from precipitation.\n", + "def calcPredNdviAndResiduals(img1):\n", + " predNDVI = img1 \\\n", + " .select('scale') \\\n", + " .multiply(img1.select('precipitation')) \\\n", + " .add(img1.select('offset')) \\\n", + " .rename('predictedNDVI')\n", + " img1 = img1.addBands([predNDVI])\n", + " residual = img1 \\\n", + " .select('predictedNDVI') \\\n", + " .subtract(img1.select('greenness')) \\\n", + " .multiply(-1) \\\n", + " .toFloat() \\\n", + " .rename('residual')\n", + " return img1.addBands([residual])\n", + "\n", + "\n", + "# Prepares Collection to be run in LandTrendr subsetting Residual and Greenness.\n", + "def compileresidualColl(image):\n", + " return image.select(['residual', 'greenness'])\n", + "\n", + "\n", + "# Combine Precipitation and Greenness Lists into Image Collection\n", + "def createResidColl(greenColl, precipColl, aoi):\n", + "\n", + " # set some params\n", + " startYear_Num = 1985\n", + " endYear_Num = 2019\n", + " numYears = endYear_Num - startYear_Num\n", + " startMonth = '-01-01'\n", + " endMonth = '-12-31'\n", + "\n", + " # ---- HERE WE USE LISTS TO COMBINE the two Image Collections :\n", + " # Send GreennessColl to List to prepare integration of precip data.\n", + " greenestList = greenColl.toList(numYears + 1, 0)\n", + " precipList = precipColl.toList(numYears + 1, 0)\n", + "\n", + " # Add precipitation band to greenest pixel composites.\n", + " greenestWprecipList = ee.List([])\n", + " for i in range(0, numYears, 1):\n", + " greenestThisYear = ee.Image(greenestList.get(i))\n", + " greenestThisYear = greenestThisYear.addBands(precipList.get(i))\n", + " greenestWprecipList = greenestWprecipList.add(greenestThisYear)\n", + "\n", + "\n", + " # Create New Image Collection of Precip and Greenest NDVI per Pixel per Year.\n", + " greenestWprecip = ee.ImageCollection(greenestWprecipList)\n", + "\n", + " def aoi_clip(image):\n", + " return image.clip(aoi)\n", + " \n", + "\n", + " # Clips Images in Collection\n", + " greenestWprecipColl = greenestWprecip.map(aoi_clip)\n", + "\n", + " #----------- Regress Precipitation and Greenness per Year per AOI\n", + "\n", + " # Precipitation vs ndvi regression.\n", + " linearFit = greenestWprecipColl \\\n", + " .select(['precipitation', 'greenness']) \\\n", + " .reduce(ee.Reducer.linearFit())\n", + "\n", + " # Function to add a list of scale and offset from 'linearFit' to collection.\n", + " def addRegression2Collection(img):\n", + " scale = linearFit.select('scale')\n", + " offset = linearFit.select('offset')\n", + " return img.addBands([scale, offset])\n", + " \n", + "\n", + " # Add scale and offset as bands in greenestWprecipList collection.\n", + " greenestWprecipColl = greenestWprecipColl.map(addRegression2Collection)\n", + "\n", + " # Calculate predicted ndvi and residuals.\n", + " greenestWprecipColl = greenestWprecipColl.map(calcPredNdviAndResiduals)\n", + " print(greenestWprecipColl, 'see all bands in here now')\n", + " # FYI, this Image Collection now contains the following bands for each year:\n", + " # greeness\n", + " # precipitation\n", + " # scale\n", + " # offset\n", + " # predicted NDVI\n", + " # residual\n", + "\n", + " # Maps compileresidualColl.\n", + " residualColl = greenestWprecipColl.map(compileresidualColl)\n", + "\n", + " return residualColl\n", + "\n", + "\n", + "exports.createResidColl = createResidColl\n", + "\n", + "# LGTM (nclinton)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid.js new file mode 100644 index 0000000..abea626 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid.js @@ -0,0 +1,94 @@ + + +// Function to calculate predicted ndvi and residuals from precipitation. +var calcPredNdviAndResiduals = function(img1) { + var predNDVI = img1 + .select('scale') + .multiply(img1.select('precipitation')) + .add(img1.select('offset')) + .rename('predictedNDVI'); + img1 = img1.addBands([predNDVI]); + var residual = img1 + .select('predictedNDVI') + .subtract(img1.select('greenness')) + .multiply(-1) //Corrects direction of residual + .toFloat() + .rename('residual'); + return img1.addBands([residual]); +}; + +// Prepares Collection to be run in LandTrendr subsetting Residual and Greenness. +var compileresidualColl = function(image) { + return image.select(['residual', 'greenness']); +}; + +// Combine Precipitation and Greenness Lists into Image Collection +var createResidColl = function(greenColl, precipColl, aoi) { + + // set some params + var startYear_Num = 1985; + var endYear_Num = 2019; + var numYears = endYear_Num - startYear_Num; + var startMonth = '-01-01'; + var endMonth = '-12-31'; + + // ---- HERE WE USE LISTS TO COMBINE the two Image Collections : + // Send GreennessColl to List to prepare integration of precip data. + var greenestList = greenColl.toList(numYears + 1, 0); + var precipList = precipColl.toList(numYears + 1, 0); + + // Add precipitation band to greenest pixel composites. + var greenestWprecipList = ee.List([]); + for (var i = 0; i <= numYears; i++) { + var greenestThisYear = ee.Image(greenestList.get(i)); + greenestThisYear = greenestThisYear.addBands(precipList.get(i)); + greenestWprecipList = greenestWprecipList.add(greenestThisYear); + } + + // Create New Image Collection of Precip and Greenest NDVI per Pixel per Year. + var greenestWprecip = ee.ImageCollection(greenestWprecipList); + + var aoi_clip = function(image) { + return image.clip(aoi); + }; + + // Clips Images in Collection + var greenestWprecipColl = greenestWprecip.map(aoi_clip); + + //----------- Regress Precipitation and Greenness per Year per AOI + + // Precipitation vs ndvi regression. + var linearFit = greenestWprecipColl + .select(['precipitation', 'greenness']) + .reduce(ee.Reducer.linearFit()); + + // Function to add a list of scale and offset from 'linearFit' to collection. + var addRegression2Collection = function(img) { + var scale = linearFit.select('scale'); + var offset = linearFit.select('offset'); + return img.addBands([scale, offset]); + }; + + // Add scale and offset as bands in greenestWprecipList collection. + greenestWprecipColl = greenestWprecipColl.map(addRegression2Collection); + + // Calculate predicted ndvi and residuals. + greenestWprecipColl = greenestWprecipColl.map(calcPredNdviAndResiduals); + print(greenestWprecipColl, 'see all bands in here now'); + // FYI, this Image Collection now contains the following bands for each year: + // greeness + // precipitation + // scale + // offset + // predicted NDVI + // residual + + // Maps compileresidualColl. + var residualColl = greenestWprecipColl.map(compileresidualColl); + + return residualColl; +}; + +exports.createResidColl = createResidColl; + +// LGTM (nclinton) diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid.py new file mode 100644 index 0000000..da6fd95 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.8 Detecting Land Cover Change in Rangelands/modules/calcResid.py @@ -0,0 +1,100 @@ +import ee +import geemap + +Map = geemap.Map() + + + +# Function to calculate predicted ndvi and residuals from precipitation. +def calcPredNdviAndResiduals(img1): + predNDVI = img1 \ + .select('scale') \ + .multiply(img1.select('precipitation')) \ + .add(img1.select('offset')) \ + .rename('predictedNDVI') + img1 = img1.addBands([predNDVI]) + residual = img1 \ + .select('predictedNDVI') \ + .subtract(img1.select('greenness')) \ + .multiply(-1) \ + .toFloat() \ + .rename('residual') + return img1.addBands([residual]) + + +# Prepares Collection to be run in LandTrendr subsetting Residual and Greenness. +def compileresidualColl(image): + return image.select(['residual', 'greenness']) + + +# Combine Precipitation and Greenness Lists into Image Collection +def createResidColl(greenColl, precipColl, aoi): + + # set some params + startYear_Num = 1985 + endYear_Num = 2019 + numYears = endYear_Num - startYear_Num + startMonth = '-01-01' + endMonth = '-12-31' + + # ---- HERE WE USE LISTS TO COMBINE the two Image Collections : + # Send GreennessColl to List to prepare integration of precip data. + greenestList = greenColl.toList(numYears + 1, 0) + precipList = precipColl.toList(numYears + 1, 0) + + # Add precipitation band to greenest pixel composites. + greenestWprecipList = ee.List([]) + for i in range(0, numYears, 1): + greenestThisYear = ee.Image(greenestList.get(i)) + greenestThisYear = greenestThisYear.addBands(precipList.get(i)) + greenestWprecipList = greenestWprecipList.add(greenestThisYear) + + + # Create New Image Collection of Precip and Greenest NDVI per Pixel per Year. + greenestWprecip = ee.ImageCollection(greenestWprecipList) + + def aoi_clip(image): + return image.clip(aoi) + + + # Clips Images in Collection + greenestWprecipColl = greenestWprecip.map(aoi_clip) + + #----------- Regress Precipitation and Greenness per Year per AOI + + # Precipitation vs ndvi regression. + linearFit = greenestWprecipColl \ + .select(['precipitation', 'greenness']) \ + .reduce(ee.Reducer.linearFit()) + + # Function to add a list of scale and offset from 'linearFit' to collection. + def addRegression2Collection(img): + scale = linearFit.select('scale') + offset = linearFit.select('offset') + return img.addBands([scale, offset]) + + + # Add scale and offset as bands in greenestWprecipList collection. + greenestWprecipColl = greenestWprecipColl.map(addRegression2Collection) + + # Calculate predicted ndvi and residuals. + greenestWprecipColl = greenestWprecipColl.map(calcPredNdviAndResiduals) + print(greenestWprecipColl, 'see all bands in here now') + # FYI, this Image Collection now contains the following bands for each year: + # greeness + # precipitation + # scale + # offset + # predicted NDVI + # residual + + # Maps compileresidualColl. + residualColl = greenestWprecipColl.map(compileresidualColl) + + return residualColl + + +exports.createResidColl = createResidColl + +# LGTM (nclinton) +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39a Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39a Checkpoint.ipynb new file mode 100644 index 0000000..9e6e251 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39a Checkpoint.ipynb @@ -0,0 +1,190 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: Chapter A3.9 Conservation Applications - Assessing the\n", + "# spatial relationship between burned area and precipitation\n", + "# Checkpoint: A39a\n", + "# Authors: Harriet Branson, Chelsea Smith\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# ** Upload the area of interest ** #\n", + "AOI = ee.Geometry.Polygon([\n", + " [\n", + " [37.72, -11.22],\n", + " [38.49, -11.22],\n", + " [38.49, -12.29],\n", + " [37.72, -12.29]\n", + " ]\n", + "])\n", + "Map.centerObject(AOI, 9)\n", + "Map.addLayer(AOI, {\n", + " 'color': 'white'\n", + "}, 'Area of interest')\n", + "\n", + "# ** MODIS Monthly Burn Area ** #\n", + "\n", + "# Load in the MODIS Monthly Burned Area dataset.\n", + "dataset = ee.ImageCollection('MODIS/006/MCD64A1') \\\n", + " .filter(ee.Filter.date('2010-01-01', '2021-12-31'))\n", + "\n", + "# Select the BurnDate band from the images in the collection.\n", + "MODIS_BurnDate = dataset.select('BurnDate')\n", + "\n", + "# A function that will calculate the area of pixels in each image by date.\n", + "def addArea(img):\n", + " area = ee.Image.pixelArea() \\\n", + " .updateMask(\n", + " img\n", + " ) # Limit area calculation to areas that have burned data. \\\n", + " .divide(1e6) \\\n", + " .clip(AOI) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': AOI,\n", + " 'scale': 500,\n", + " 'bestEffort': True\n", + " }).getNumber(\n", + " 'area'\n", + " ); # Retrieve area from the reduce region calculation.\n", + " # Add a new band to each image in the collection named area.\n", + " return img.addBands(ee.Image(area).rename('area'))\n", + "\n", + "\n", + "# Apply function on image collection.\n", + "burnDateArea = MODIS_BurnDate.map(addArea)\n", + "\n", + "# Select only the area band as we are using system time for date.\n", + "burnedArea = burnDateArea.select('area')\n", + "\n", + "# Create a chart that shows the total burned area over time.\n", + "burnedAreaChart =\n", + " ui.Chart.image \\\n", + " .series({\n", + " 'imageCollection': burnedArea, # Our image collection.\n", + " 'region': AOI,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 500,\n", + " 'xProperty': 'system:time_start' # time\n", + " }) \\\n", + " .setSeriesNames(['Area']) \\\n", + " .setOptions({\n", + " 'title': 'Total monthly area burned in AOI',\n", + " 'hAxis': {\n", + " 'title': 'Date', # The x axis label.\n", + " format: 'YYYY', # Years only for date format.\n", + " 'gridlines': {\n", + " 'count': 12\n", + " },\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Total burned area (km\u00b2)', # The y-axis label\n", + " 'maxValue': 2250, # The bounds for y-axis\n", + " 'minValue': 0,\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'lineWidth': 1.5,\n", + " 'colors': ['d74b46'], # The line color\n", + " })\n", + "print(burnedAreaChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39a Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39a Checkpoint.js new file mode 100644 index 0000000..d1a64ca --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39a Checkpoint.js @@ -0,0 +1,98 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: Chapter A3.9 Conservation Applications - Assessing the +// spatial relationship between burned area and precipitation +// Checkpoint: A39a +// Authors: Harriet Branson, Chelsea Smith +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ** Upload the area of interest ** // +var AOI = ee.Geometry.Polygon([ + [ + [37.72, -11.22], + [38.49, -11.22], + [38.49, -12.29], + [37.72, -12.29] + ] +]); +Map.centerObject(AOI, 9); +Map.addLayer(AOI, { + color: 'white' +}, 'Area of interest'); + +// ** MODIS Monthly Burn Area ** // + +// Load in the MODIS Monthly Burned Area dataset. +var dataset = ee.ImageCollection('MODIS/006/MCD64A1') + // Filter based on the timespan requirements. + .filter(ee.Filter.date('2010-01-01', '2021-12-31')); + +// Select the BurnDate band from the images in the collection. +var MODIS_BurnDate = dataset.select('BurnDate'); + +// A function that will calculate the area of pixels in each image by date. +var addArea = function(img) { + var area = ee.Image.pixelArea() + .updateMask( + img + ) // Limit area calculation to areas that have burned data. + .divide(1e6) // Divide by 1,000,000 for square kilometers. + .clip(AOI) // Clip to the input geometry. + .reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: AOI, + scale: 500, + bestEffort: true + }).getNumber( + 'area' + ); // Retrieve area from the reduce region calculation. + // Add a new band to each image in the collection named area. + return img.addBands(ee.Image(area).rename('area')); +}; + +// Apply function on image collection. +var burnDateArea = MODIS_BurnDate.map(addArea); + +// Select only the area band as we are using system time for date. +var burnedArea = burnDateArea.select('area'); + +// Create a chart that shows the total burned area over time. +var burnedAreaChart = + ui.Chart.image + .series({ + imageCollection: burnedArea, // Our image collection. + region: AOI, + reducer: ee.Reducer.mean(), + scale: 500, + xProperty: 'system:time_start' // time + }) + .setSeriesNames(['Area']) // Label for legend. + .setOptions({ + title: 'Total monthly area burned in AOI', + hAxis: { + title: 'Date', // The x axis label. + format: 'YYYY', // Years only for date format. + gridlines: { + count: 12 + }, + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Total burned area (km²)', // The y-axis label + maxValue: 2250, // The bounds for y-axis + minValue: 0, + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1.5, + colors: ['d74b46'], // The line color + }); +print(burnedAreaChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39a Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39a Checkpoint.py new file mode 100644 index 0000000..568e5c0 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39a Checkpoint.py @@ -0,0 +1,103 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: Chapter A3.9 Conservation Applications - Assessing the +# spatial relationship between burned area and precipitation +# Checkpoint: A39a +# Authors: Harriet Branson, Chelsea Smith +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# ** Upload the area of interest ** # +AOI = ee.Geometry.Polygon([ + [ + [37.72, -11.22], + [38.49, -11.22], + [38.49, -12.29], + [37.72, -12.29] + ] +]) +Map.centerObject(AOI, 9) +Map.addLayer(AOI, { + 'color': 'white' +}, 'Area of interest') + +# ** MODIS Monthly Burn Area ** # + +# Load in the MODIS Monthly Burned Area dataset. +dataset = ee.ImageCollection('MODIS/006/MCD64A1') \ + .filter(ee.Filter.date('2010-01-01', '2021-12-31')) + +# Select the BurnDate band from the images in the collection. +MODIS_BurnDate = dataset.select('BurnDate') + +# A function that will calculate the area of pixels in each image by date. +def addArea(img): + area = ee.Image.pixelArea() \ + .updateMask( + img + ) # Limit area calculation to areas that have burned data. \ + .divide(1e6) \ + .clip(AOI) \ + .reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': AOI, + 'scale': 500, + 'bestEffort': True + }).getNumber( + 'area' + ); # Retrieve area from the reduce region calculation. + # Add a new band to each image in the collection named area. + return img.addBands(ee.Image(area).rename('area')) + + +# Apply function on image collection. +burnDateArea = MODIS_BurnDate.map(addArea) + +# Select only the area band as we are using system time for date. +burnedArea = burnDateArea.select('area') + +# Create a chart that shows the total burned area over time. +burnedAreaChart = + ui.Chart.image \ + .series({ + 'imageCollection': burnedArea, # Our image collection. + 'region': AOI, + 'reducer': ee.Reducer.mean(), + 'scale': 500, + 'xProperty': 'system:time_start' # time + }) \ + .setSeriesNames(['Area']) \ + .setOptions({ + 'title': 'Total monthly area burned in AOI', + 'hAxis': { + 'title': 'Date', # The x axis label. + format: 'YYYY', # Years only for date format. + 'gridlines': { + 'count': 12 + }, + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Total burned area (km²)', # The y-axis label + 'maxValue': 2250, # The bounds for y-axis + 'minValue': 0, + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'lineWidth': 1.5, + 'colors': ['d74b46'], # The line color + }) +print(burnedAreaChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39b Checkpoint.ipynb b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39b Checkpoint.ipynb new file mode 100644 index 0000000..2dc07d4 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39b Checkpoint.ipynb @@ -0,0 +1,313 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: Chapter A3.9 Conservation Applications - Assessing the\n", + "# spatial relationship between burned area and precipitation\n", + "# Checkpoint: A39b\n", + "# Authors: Harriet Branson, Chelsea Smith\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# ** Upload the area of interest ** #\n", + "AOI = ee.Geometry.Polygon([\n", + " [\n", + " [37.72, -11.22],\n", + " [38.49, -11.22],\n", + " [38.49, -12.29],\n", + " [37.72, -12.29]\n", + " ]\n", + "])\n", + "Map.centerObject(AOI, 9)\n", + "Map.addLayer(AOI, {\n", + " 'color': 'white'\n", + "}, 'Area of interest')\n", + "\n", + "# ** MODIS Monthly Burn Area ** #\n", + "\n", + "# Load in the MODIS Monthly Burned Area dataset.\n", + "dataset = ee.ImageCollection('MODIS/006/MCD64A1') \\\n", + " .filter(ee.Filter.date('2010-01-01', '2021-12-31'))\n", + "\n", + "# Select the BurnDate band from the images in the collection.\n", + "MODIS_BurnDate = dataset.select('BurnDate')\n", + "\n", + "# A function that will calculate the area of pixels in each image by date.\n", + "def addArea(img):\n", + " area = ee.Image.pixelArea() \\\n", + " .updateMask(\n", + " img\n", + " ) # Limit area calculation to areas that have burned data. \\\n", + " .divide(1e6) \\\n", + " .clip(AOI) \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': AOI,\n", + " 'scale': 500,\n", + " 'bestEffort': True\n", + " }).getNumber(\n", + " 'area'\n", + " ); # Retrieve area from the reduce region calculation.\n", + " # Add a new band to each image in the collection named area.\n", + " return img.addBands(ee.Image(area).rename('area'))\n", + "\n", + "\n", + "# Apply function on image collection.\n", + "burnDateArea = MODIS_BurnDate.map(addArea)\n", + "\n", + "# Select only the area band as we are using system time for date.\n", + "burnedArea = burnDateArea.select('area')\n", + "\n", + "# Create a chart that shows the total burned area over time.\n", + "burnedAreaChart =\n", + " ui.Chart.image \\\n", + " .series({\n", + " 'imageCollection': burnedArea, # Our image collection.\n", + " 'region': AOI,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 500,\n", + " 'xProperty': 'system:time_start' # time\n", + " }) \\\n", + " .setSeriesNames(['Area']) \\\n", + " .setOptions({\n", + " 'title': 'Total monthly area burned in AOI',\n", + " 'hAxis': {\n", + " 'title': 'Date', # The x axis label.\n", + " format: 'YYYY', # Years only for date format.\n", + " 'gridlines': {\n", + " 'count': 12\n", + " },\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Total burned area (km\u00b2)', # The y-axis label\n", + " 'maxValue': 2250, # The bounds for y-axis\n", + " 'minValue': 0,\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'lineWidth': 1.5,\n", + " 'colors': ['d74b46'], # The line color\n", + " })\n", + "print(burnedAreaChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Load in the CHIRPS rainfall pentad dataset.\n", + "chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "\n", + "# Define the temporal range\n", + "startyear = 2010\n", + "endyear = 2021\n", + "\n", + "# Set the advancing dates from the temporal range.\n", + "startdate = ee.Date.fromYMD(startyear, 1, 1)\n", + "enddate = ee.Date.fromYMD(endyear, 12, 31)\n", + "\n", + "# Create a list of years\n", + "years = ee.List.sequence(startyear, endyear)\n", + "# Create a list of months\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Filter the dataset based on the temporal range.\n", + "Pchirps = chirps.filterDate(startdate, enddate) \\\n", + " .sort('system:time_start',\n", + " False) # Sort chronologically in descending order. \\\n", + " .filterBounds(AOI) \\\n", + " .select('precipitation'); \n", + "\n", + "# Calculate the precipitation per month.\n", + "MonthlyRainfall = ee.ImageCollection.fromImages(\n", + " y\n", + " ) { # Using the list of years based on temporal range.\n", + "\n", + "def func_fdw(m):\n", + " w = Pchirps.filter(ee.Filter \\\n", + " .calendarRange(y, y, 'year')) \\\n", + " .filter(ee.Filter.calendarRange(m, m,\n", + " 'month')) \\\n", + " .sum(); \n", + " return w.set('year', y) \\\n", + " .set('month', m) \\\n", + " .set('system:time_start', ee.Date \\\n", + " .fromYMD(y, m, 1).millis()\n", + " ) # Use millis to keep the system time number. \\\n", + " .set('date', ee.Date.fromYMD(y, m,\n", + " 1))\n", + "\n", + " return months.map(func_fdw)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " }).flatten())\n", + "# Print the image collection.\n", + "print('Monthly Precipitation Image Collection', MonthlyRainfall)\n", + "\n", + "# ** Chart: CHIRPS Precipitation ** #\n", + "\n", + "# Create a chart displaying monthly rainfall over a temporal range.\n", + "monthlyRainfallChart =\n", + " ui.Chart.image \\\n", + " .series({\n", + " 'imageCollection': MonthlyRainfall.select(\n", + " 'precipitation'), # Select precipitation band\n", + " 'region': AOI,\n", + " 'reducer': ee.Reducer \\\n", + " .mean(), \n", + " 'scale': 500,\n", + " 'xProperty': 'system:time_start' # Use system time start for x-axis\n", + " }) \\\n", + " .setSeriesNames(['Precipitation']) \\\n", + " .setOptions({\n", + " 'title': 'Total monthly precipitation in AOI', # Add title\n", + " 'hAxis': {\n", + " 'title': 'Date',\n", + " format: 'YYYY', # Year only date format\n", + " 'gridlines': {\n", + " 'count': 12\n", + " },\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Precipitation (mm)', # The y-axis label\n", + " 'maxValue': 450, # The bounds for y-axis\n", + " 'minValue': 0,\n", + " 'titleTextStyle': {\n", + " 'italic': False,\n", + " 'bold': True\n", + " }\n", + " },\n", + " 'lineWidth': 1.5,\n", + " 'colors': ['4f5ebd'],\n", + " })\n", + "print(monthlyRainfallChart)\n", + "\n", + "# 2010/2011 wet season total\n", + "year = 2010; # Adjust year\n", + "startDate = ee.Date.fromYMD(year, 11, 1); # Adjust months/days\n", + "endDate = ee.Date.fromYMD(year + 1, 5, 31); # Adjust months/days\n", + "filtered = chirps \\\n", + " .filter(ee.Filter.date(startDate, endDate))\n", + "Rains10_11Total = filtered.reduce(ee.Reducer.sum()).clip(AOI)\n", + "\n", + "# 2011/2012 wet season total\n", + "year = 2011; # Adjust year\n", + "startDate = ee.Date.fromYMD(year, 11, 1); # Adjust months/days\n", + "endDate = ee.Date.fromYMD(year + 1, 5, 31); # Adjust months/days\n", + "filtered = chirps \\\n", + " .filter(ee.Filter.date(startDate, endDate))\n", + "Rains11_12Total = filtered.reduce(ee.Reducer.sum()).clip(AOI)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39b Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39b Checkpoint.js new file mode 100644 index 0000000..b96ee37 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39b Checkpoint.js @@ -0,0 +1,206 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: Chapter A3.9 Conservation Applications - Assessing the +// spatial relationship between burned area and precipitation +// Checkpoint: A39b +// Authors: Harriet Branson, Chelsea Smith +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ** Upload the area of interest ** // +var AOI = ee.Geometry.Polygon([ + [ + [37.72, -11.22], + [38.49, -11.22], + [38.49, -12.29], + [37.72, -12.29] + ] +]); +Map.centerObject(AOI, 9); +Map.addLayer(AOI, { + color: 'white' +}, 'Area of interest'); + +// ** MODIS Monthly Burn Area ** // + +// Load in the MODIS Monthly Burned Area dataset. +var dataset = ee.ImageCollection('MODIS/006/MCD64A1') + // Filter based on the timespan requirements. + .filter(ee.Filter.date('2010-01-01', '2021-12-31')); + +// Select the BurnDate band from the images in the collection. +var MODIS_BurnDate = dataset.select('BurnDate'); + +// A function that will calculate the area of pixels in each image by date. +var addArea = function(img) { + var area = ee.Image.pixelArea() + .updateMask( + img + ) // Limit area calculation to areas that have burned data. + .divide(1e6) // Divide by 1,000,000 for square kilometers. + .clip(AOI) // Clip to the input geometry. + .reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: AOI, + scale: 500, + bestEffort: true + }).getNumber( + 'area' + ); // Retrieve area from the reduce region calculation. + // Add a new band to each image in the collection named area. + return img.addBands(ee.Image(area).rename('area')); +}; + +// Apply function on image collection. +var burnDateArea = MODIS_BurnDate.map(addArea); + +// Select only the area band as we are using system time for date. +var burnedArea = burnDateArea.select('area'); + +// Create a chart that shows the total burned area over time. +var burnedAreaChart = + ui.Chart.image + .series({ + imageCollection: burnedArea, // Our image collection. + region: AOI, + reducer: ee.Reducer.mean(), + scale: 500, + xProperty: 'system:time_start' // time + }) + .setSeriesNames(['Area']) // Label for legend. + .setOptions({ + title: 'Total monthly area burned in AOI', + hAxis: { + title: 'Date', // The x axis label. + format: 'YYYY', // Years only for date format. + gridlines: { + count: 12 + }, + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Total burned area (km²)', // The y-axis label + maxValue: 2250, // The bounds for y-axis + minValue: 0, + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1.5, + colors: ['d74b46'], // The line color + }); +print(burnedAreaChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Load in the CHIRPS rainfall pentad dataset. +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Define the temporal range +var startyear = 2010; +var endyear = 2021; + +// Set the advancing dates from the temporal range. +var startdate = ee.Date.fromYMD(startyear, 1, 1); +var enddate = ee.Date.fromYMD(endyear, 12, 31); + +// Create a list of years +var years = ee.List.sequence(startyear, endyear); +// Create a list of months +var months = ee.List.sequence(1, 12); + +// Filter the dataset based on the temporal range. +var Pchirps = chirps.filterDate(startdate, enddate) + .sort('system:time_start', + false) // Sort chronologically in descending order. + .filterBounds(AOI) // Filter to AOI + .select('precipitation'); // Select precipitation band + +// Calculate the precipitation per month. +var MonthlyRainfall = ee.ImageCollection.fromImages( + years.map(function( + y + ) { // Using the list of years based on temporal range. + return months.map(function(m) { + var w = Pchirps.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum(); // Calculating the sum for the month + return w.set('year', y) + .set('month', m) + .set('system:time_start', ee.Date + .fromYMD(y, m, 1).millis() + ) // Use millis to keep the system time number. + .set('date', ee.Date.fromYMD(y, m, + 1)); + }); + }).flatten()); +// Print the image collection. +print('Monthly Precipitation Image Collection', MonthlyRainfall); + +// ** Chart: CHIRPS Precipitation ** // + +// Create a chart displaying monthly rainfall over a temporal range. +var monthlyRainfallChart = + ui.Chart.image + .series({ + imageCollection: MonthlyRainfall.select( + 'precipitation'), // Select precipitation band + region: AOI, + reducer: ee.Reducer + .mean(), // Use mean reducer to calculate AMR + scale: 500, + xProperty: 'system:time_start' // Use system time start for x-axis + }) + .setSeriesNames(['Precipitation']) // /The label legend + .setOptions({ + title: 'Total monthly precipitation in AOI', // Add title + hAxis: { + title: 'Date', + format: 'YYYY', // Year only date format + gridlines: { + count: 12 + }, + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Precipitation (mm)', // The y-axis label + maxValue: 450, // The bounds for y-axis + minValue: 0, + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1.5, + colors: ['4f5ebd'], + }); +print(monthlyRainfallChart); + +// 2010/2011 wet season total +var year = 2010; // Adjust year +var startDate = ee.Date.fromYMD(year, 11, 1); // Adjust months/days +var endDate = ee.Date.fromYMD(year + 1, 5, 31); // Adjust months/days +var filtered = chirps + .filter(ee.Filter.date(startDate, endDate)); +var Rains10_11Total = filtered.reduce(ee.Reducer.sum()).clip(AOI); + +// 2011/2012 wet season total +var year = 2011; // Adjust year +var startDate = ee.Date.fromYMD(year, 11, 1); // Adjust months/days +var endDate = ee.Date.fromYMD(year + 1, 5, 31); // Adjust months/days +var filtered = chirps + .filter(ee.Filter.date(startDate, endDate)); +var Rains11_12Total = filtered.reduce(ee.Reducer.sum()).clip(AOI); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39b Checkpoint.py b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39b Checkpoint.py new file mode 100644 index 0000000..71f410a --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39b Checkpoint.py @@ -0,0 +1,226 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: Chapter A3.9 Conservation Applications - Assessing the +# spatial relationship between burned area and precipitation +# Checkpoint: A39b +# Authors: Harriet Branson, Chelsea Smith +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# ** Upload the area of interest ** # +AOI = ee.Geometry.Polygon([ + [ + [37.72, -11.22], + [38.49, -11.22], + [38.49, -12.29], + [37.72, -12.29] + ] +]) +Map.centerObject(AOI, 9) +Map.addLayer(AOI, { + 'color': 'white' +}, 'Area of interest') + +# ** MODIS Monthly Burn Area ** # + +# Load in the MODIS Monthly Burned Area dataset. +dataset = ee.ImageCollection('MODIS/006/MCD64A1') \ + .filter(ee.Filter.date('2010-01-01', '2021-12-31')) + +# Select the BurnDate band from the images in the collection. +MODIS_BurnDate = dataset.select('BurnDate') + +# A function that will calculate the area of pixels in each image by date. +def addArea(img): + area = ee.Image.pixelArea() \ + .updateMask( + img + ) # Limit area calculation to areas that have burned data. \ + .divide(1e6) \ + .clip(AOI) \ + .reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': AOI, + 'scale': 500, + 'bestEffort': True + }).getNumber( + 'area' + ); # Retrieve area from the reduce region calculation. + # Add a new band to each image in the collection named area. + return img.addBands(ee.Image(area).rename('area')) + + +# Apply function on image collection. +burnDateArea = MODIS_BurnDate.map(addArea) + +# Select only the area band as we are using system time for date. +burnedArea = burnDateArea.select('area') + +# Create a chart that shows the total burned area over time. +burnedAreaChart = + ui.Chart.image \ + .series({ + 'imageCollection': burnedArea, # Our image collection. + 'region': AOI, + 'reducer': ee.Reducer.mean(), + 'scale': 500, + 'xProperty': 'system:time_start' # time + }) \ + .setSeriesNames(['Area']) \ + .setOptions({ + 'title': 'Total monthly area burned in AOI', + 'hAxis': { + 'title': 'Date', # The x axis label. + format: 'YYYY', # Years only for date format. + 'gridlines': { + 'count': 12 + }, + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Total burned area (km²)', # The y-axis label + 'maxValue': 2250, # The bounds for y-axis + 'minValue': 0, + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'lineWidth': 1.5, + 'colors': ['d74b46'], # The line color + }) +print(burnedAreaChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Load in the CHIRPS rainfall pentad dataset. +chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') + +# Define the temporal range +startyear = 2010 +endyear = 2021 + +# Set the advancing dates from the temporal range. +startdate = ee.Date.fromYMD(startyear, 1, 1) +enddate = ee.Date.fromYMD(endyear, 12, 31) + +# Create a list of years +years = ee.List.sequence(startyear, endyear) +# Create a list of months +months = ee.List.sequence(1, 12) + +# Filter the dataset based on the temporal range. +Pchirps = chirps.filterDate(startdate, enddate) \ + .sort('system:time_start', + False) # Sort chronologically in descending order. \ + .filterBounds(AOI) \ + .select('precipitation'); + +# Calculate the precipitation per month. +MonthlyRainfall = ee.ImageCollection.fromImages( + y + ) { # Using the list of years based on temporal range. + +def func_fdw(m): + w = Pchirps.filter(ee.Filter \ + .calendarRange(y, y, 'year')) \ + .filter(ee.Filter.calendarRange(m, m, + 'month')) \ + .sum(); + return w.set('year', y) \ + .set('month', m) \ + .set('system:time_start', ee.Date \ + .fromYMD(y, m, 1).millis() + ) # Use millis to keep the system time number. \ + .set('date', ee.Date.fromYMD(y, m, + 1)) + + return months.map(func_fdw) + + + + + + + + + + + + + + + }).flatten()) +# Print the image collection. +print('Monthly Precipitation Image Collection', MonthlyRainfall) + +# ** Chart: CHIRPS Precipitation ** # + +# Create a chart displaying monthly rainfall over a temporal range. +monthlyRainfallChart = + ui.Chart.image \ + .series({ + 'imageCollection': MonthlyRainfall.select( + 'precipitation'), # Select precipitation band + 'region': AOI, + 'reducer': ee.Reducer \ + .mean(), + 'scale': 500, + 'xProperty': 'system:time_start' # Use system time start for x-axis + }) \ + .setSeriesNames(['Precipitation']) \ + .setOptions({ + 'title': 'Total monthly precipitation in AOI', # Add title + 'hAxis': { + 'title': 'Date', + format: 'YYYY', # Year only date format + 'gridlines': { + 'count': 12 + }, + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'vAxis': { + 'title': 'Precipitation (mm)', # The y-axis label + 'maxValue': 450, # The bounds for y-axis + 'minValue': 0, + 'titleTextStyle': { + 'italic': False, + 'bold': True + } + }, + 'lineWidth': 1.5, + 'colors': ['4f5ebd'], + }) +print(monthlyRainfallChart) + +# 2010/2011 wet season total +year = 2010; # Adjust year +startDate = ee.Date.fromYMD(year, 11, 1); # Adjust months/days +endDate = ee.Date.fromYMD(year + 1, 5, 31); # Adjust months/days +filtered = chirps \ + .filter(ee.Filter.date(startDate, endDate)) +Rains10_11Total = filtered.reduce(ee.Reducer.sum()).clip(AOI) + +# 2011/2012 wet season total +year = 2011; # Adjust year +startDate = ee.Date.fromYMD(year, 11, 1); # Adjust months/days +endDate = ee.Date.fromYMD(year + 1, 5, 31); # Adjust months/days +filtered = chirps \ + .filter(ee.Filter.date(startDate, endDate)) +Rains11_12Total = filtered.reduce(ee.Reducer.sum()).clip(AOI) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39c Checkpoint.js b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39c Checkpoint.js new file mode 100644 index 0000000..eccb240 --- /dev/null +++ b/docs/book/Part A - Applications/A3 - Terrestrial Applications/A3.9 Conservation Applications/A39c Checkpoint.js @@ -0,0 +1,451 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: Chapter A3.9 Conservation Applications - Assessing the +// spatial relationship between burned area and precipitation +// Checkpoint: A39c +// Authors: Harriet Branson, Chelsea Smith +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ** Upload the area of interest ** // +var AOI = ee.Geometry.Polygon([ + [ + [37.72, -11.22], + [38.49, -11.22], + [38.49, -12.29], + [37.72, -12.29] + ] +]); +Map.centerObject(AOI, 9); +Map.addLayer(AOI, { + color: 'white' +}, 'Area of interest'); + +// ** MODIS Monthly Burn Area ** // + +// Load in the MODIS Monthly Burned Area dataset. +var dataset = ee.ImageCollection('MODIS/006/MCD64A1') + // Filter based on the timespan requirements. + .filter(ee.Filter.date('2010-01-01', '2021-12-31')); + +// Select the BurnDate band from the images in the collection. +var MODIS_BurnDate = dataset.select('BurnDate'); + +// A function that will calculate the area of pixels in each image by date. +var addArea = function(img) { + var area = ee.Image.pixelArea() + .updateMask( + img + ) // Limit area calculation to areas that have burned data. + .divide(1e6) // Divide by 1,000,000 for square kilometers. + .clip(AOI) // Clip to the input geometry. + .reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: AOI, + scale: 500, + bestEffort: true + }).getNumber( + 'area' + ); // Retrieve area from the reduce region calculation. + // Add a new band to each image in the collection named area. + return img.addBands(ee.Image(area).rename('area')); +}; + +// Apply function on image collection. +var burnDateArea = MODIS_BurnDate.map(addArea); + +// Select only the area band as we are using system time for date. +var burnedArea = burnDateArea.select('area'); + +// Create a chart that shows the total burned area over time. +var burnedAreaChart = + ui.Chart.image + .series({ + imageCollection: burnedArea, // Our image collection. + region: AOI, + reducer: ee.Reducer.mean(), + scale: 500, + xProperty: 'system:time_start' // time + }) + .setSeriesNames(['Area']) // Label for legend. + .setOptions({ + title: 'Total monthly area burned in AOI', + hAxis: { + title: 'Date', // The x axis label. + format: 'YYYY', // Years only for date format. + gridlines: { + count: 12 + }, + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Total burned area (km²)', // The y-axis label + maxValue: 2250, // The bounds for y-axis + minValue: 0, + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1.5, + colors: ['d74b46'], // The line color + }); +print(burnedAreaChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Load in the CHIRPS rainfall pentad dataset. +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Define the temporal range +var startyear = 2010; +var endyear = 2021; + +// Set the advancing dates from the temporal range. +var startdate = ee.Date.fromYMD(startyear, 1, 1); +var enddate = ee.Date.fromYMD(endyear, 12, 31); + +// Create a list of years +var years = ee.List.sequence(startyear, endyear); +// Create a list of months +var months = ee.List.sequence(1, 12); + +// Filter the dataset based on the temporal range. +var Pchirps = chirps.filterDate(startdate, enddate) + .sort('system:time_start', + false) // Sort chronologically in descending order. + .filterBounds(AOI) // Filter to AOI + .select('precipitation'); // Select precipitation band + +// Calculate the precipitation per month. +var MonthlyRainfall = ee.ImageCollection.fromImages( + years.map(function( + y + ) { // Using the list of years based on temporal range. + return months.map(function(m) { + var w = Pchirps.filter(ee.Filter + .calendarRange(y, y, 'year')) + .filter(ee.Filter.calendarRange(m, m, + 'month')) + .sum(); // Calculating the sum for the month + return w.set('year', y) + .set('month', m) + .set('system:time_start', ee.Date + .fromYMD(y, m, 1).millis() + ) // Use millis to keep the system time number. + .set('date', ee.Date.fromYMD(y, m, + 1)); + }); + }).flatten()); +// Print the image collection. +print('Monthly Precipitation Image Collection', MonthlyRainfall); + +// ** Chart: CHIRPS Precipitation ** // + +// Create a chart displaying monthly rainfall over a temporal range. +var monthlyRainfallChart = + ui.Chart.image + .series({ + imageCollection: MonthlyRainfall.select( + 'precipitation'), // Select precipitation band + region: AOI, + reducer: ee.Reducer + .mean(), // Use mean reducer to calculate AMR + scale: 500, + xProperty: 'system:time_start' // Use system time start for x-axis + }) + .setSeriesNames(['Precipitation']) // /The label legend + .setOptions({ + title: 'Total monthly precipitation in AOI', // Add title + hAxis: { + title: 'Date', + format: 'YYYY', // Year only date format + gridlines: { + count: 12 + }, + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxis: { + title: 'Precipitation (mm)', // The y-axis label + maxValue: 450, // The bounds for y-axis + minValue: 0, + titleTextStyle: { + italic: false, + bold: true + } + }, + lineWidth: 1.5, + colors: ['4f5ebd'], + }); +print(monthlyRainfallChart); + +// 2010/2011 wet season total +var year = 2010; // Adjust year +var startDate = ee.Date.fromYMD(year, 11, 1); // Adjust months/days +var endDate = ee.Date.fromYMD(year + 1, 5, 31); // Adjust months/days +var filtered = chirps + .filter(ee.Filter.date(startDate, endDate)); +var Rains10_11Total = filtered.reduce(ee.Reducer.sum()).clip(AOI); + +// 2011/2012 wet season total +var year = 2011; // Adjust year +var startDate = ee.Date.fromYMD(year, 11, 1); // Adjust months/days +var endDate = ee.Date.fromYMD(year + 1, 5, 31); // Adjust months/days +var filtered = chirps + .filter(ee.Filter.date(startDate, endDate)); +var Rains11_12Total = filtered.reduce(ee.Reducer.sum()).clip(AOI); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// ** Combine: CHIRPS Average Rainfall & MODIS Monthly Burn ** // + +// Combine the two image collections for joint analysis +var bpMerged = burnedArea.merge(MonthlyRainfall); +print('Merged image collection', bpMerged); + +// ** Chart: CHIRPS Average Rainfall & MODIS Monthly Burn ** // +// Plot the two time series on a graph +var bpChart = + ui.Chart.image.series({ + imageCollection: bpMerged, // The merged image collection + region: AOI, + reducer: ee.Reducer.mean(), + scale: 500, + xProperty: 'system:time_start' // Use system time start for synchronous plotting + }) + .setSeriesNames(['Burned Area', 'Precipitation']) // Label series + .setChartType('LineChart') // Define chart type + .setOptions({ + title: 'Relationship between burned area and rainfall in Chuilexi', + interpolateNulls: true, // Interpolate nulls to provide continuous data + series: { // Use two sets of series with a target axis to create the two y-axes needed for plotting + 0: { // 0 and 1 reference the vAxes settings below + targetAxisIndex: 0, + type: 'line', + lineWidth: 1.5, + color: 'd74b46' + }, + 1: { + targetAxisIndex: 1, + type: 'line', + lineWidth: 1.5, + color: '4f5ebd' + }, + }, + hAxis: { + title: 'Date', + format: 'YYYY', + gridlines: { + count: 12 + }, + titleTextStyle: { + italic: false, + bold: true + } + }, + vAxes: { + 0: { + title: 'Burned area (km²)', // Label left-hand y-axis + baseline: 0, + viewWindow: { + min: 0 + }, + titleTextStyle: { + italic: false, + bold: true + } + }, + 1: { + title: 'Precipitation (mm)', // Label right-hand y-axis + baseline: 0, + viewWindow: { + min: 0 + }, + titleTextStyle: { + italic: false, + bold: true + } + }, + }, + curveType: 'function' // For smoothing + }); +bpChart.style().set({ + position: 'bottom-right', + width: '492px', + height: '300px' +}); + +// ** Legend: Rainfall ** // +var rain_palette = ['#ffffcc', '#a1dab4', '#41b6c4', '#2c7fb8', + '#253494' +]; + +function ColorBar(rain_palette) { + return ui.Thumbnail({ + image: ee.Image.pixelLonLat().select(0), + params: { + bbox: [0, 0, 1, 0.1], + dimensions: '300x15', + format: 'png', + min: 0, + max: 1, + palette: rain_palette, + }, + style: { + stretch: 'horizontal', + margin: '0px 22px' + }, + }); +} + +function makeRainLegend(lowLine, midLine, highLine, lowText, midText, + highText, palette) { + var labelheader = ui.Label( + 'Total precipitation in wet season (mm)', { + margin: '5px 17px', + textAlign: 'center', + stretch: 'horizontal', + fontWeight: 'bold' + }); + var labelLines = ui.Panel( + [ + ui.Label(lowLine, { + margin: '-4px 21px' + }), + ui.Label(midLine, { + margin: '-4px 0px', + textAlign: 'center', + stretch: 'horizontal' + }), + ui.Label(highLine, { + margin: '-4px 21px' + }) + ], + ui.Panel.Layout.flow('horizontal')); + var labelPanel = ui.Panel( + [ + ui.Label(lowText, { + margin: '0px 14.5px' + }), + ui.Label(midText, { + margin: '0px 0px', + textAlign: 'center', + stretch: 'horizontal' + }), + ui.Label(highText, { + margin: '0px 1px' + }) + ], + ui.Panel.Layout.flow('horizontal')); + return ui.Panel({ + widgets: [labelheader, ColorBar(rain_palette), + labelLines, labelPanel + ], + style: { + position: 'bottom-left' + } + }); +} +Map.add(makeRainLegend('|', '|', '|', '0', '250', '500', ['#ffffcc', + '#a1dab4', '#41b6c4', '#2c7fb8', '#253494' +])); + +// ** Legend: Burned area ** // +var burnLegend = ui.Panel({ + style: { + position: 'top-left', + padding: '8px 15px' + } +}); + +var makeRow = function(color, name) { + var colorBox = ui.Label({ + style: { + backgroundColor: '#' + color, + padding: '10px', + margin: '0 10px 0 0' + } + }); + var description = ui.Label({ + value: name, + style: { + margin: 'o o 6px 6px' + } + }); + return ui.Panel({ + widgets: [colorBox, description], + layout: ui.Panel.Layout.Flow('horizontal') + }); +}; + +var burnPalette = ['FF0000']; +var names = ['Burned area']; +for (var i = 0; i < 1; i++) { + burnLegend.add(makeRow(burnPalette[i], names[i])); +} +Map.add(burnLegend); + +Map.centerObject(AOI, 9); // Centre the map on the AOI +Map.add( + bpChart +); // Add the merged burned area & precipitation chart to the map + +// ** Chart: Adding an interactive query ** // + +// Add a function where if you click on a point in the map it displays the burned area and rainfall for that date +bpChart.onClick(function(xValue, yValue, seriesName) { + if (!xValue) return; + // Show layer for date selected on the chart + var equalDate = ee.Filter.equals('system:time_start', + xValue); + // Search for the layer in the image collection that links to the selected date + var classificationB = ee.Image(MODIS_BurnDate.filter( + equalDate).first()).clip(AOI).select('BurnDate'); + var classificationR = ee.Image(MonthlyRainfall.filter( + equalDate).first()).clip(AOI).select( + 'precipitation'); + var burnImage = ee.Image(MODIS_BurnDate.filter(equalDate) + .first()); + var date_string = new Date(xValue).toLocaleString( + 'en-EN', { + dateStyle: 'full' + }); + var rainImage = ee.Image(MonthlyRainfall.filter(equalDate) + .first()); + var date_stringR = new Date(xValue).toLocaleString( + 'en-EN', { + dateStyle: 'full' + }); + // Reset the map layers each time a new date is clicked + Map.layers().reset([classificationB]); + Map.layers().reset([classificationR]); + var visParamsBurnLayer = { // Visualisation for burned area + min: 0, + max: 365, + palette: ['red'] + }; + var visParamsRainLayer = { // Visualisation for rain + min: 0, + max: 450, + palette: ['#ffffcc', '#a1dab4', '#41b6c4', + '#2c7fb8', '#253494' + ] + }; + // Add the layers to the map + Map.addLayer(classificationR, visParamsRainLayer, + 'Total monthly rainfall on [' + date_string + ']'); + Map.addLayer(classificationB, visParamsBurnLayer, + 'Burned area on [' + date_string + ']'); +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10a Checkpoint.ipynb new file mode 100644 index 0000000..84314d7 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10a Checkpoint.ipynb @@ -0,0 +1,129 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.0 Exploring images\n", + "# Checkpoint: F10a\n", + "# Author: Ujaval Gandhi\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "print('Hello World')\n", + "\n", + "city = 'San Francisco'\n", + "print(city)\n", + "\n", + "population = 873965\n", + "print(population)\n", + "\n", + "cities = ['San Francisco', 'Los Angeles', 'New York', 'Atlanta']\n", + "print(cities)\n", + "\n", + "cityData = {\n", + " 'city': 'San Francisco',\n", + " 'coordinates': [-122.4194, 37.7749],\n", + " 'population': 873965\n", + "}\n", + "print(cityData)\n", + "\n", + "def greet(name):\n", + " return 'Hello ' + name\n", + "\n", + "print(greet('World'))\n", + "print(greet('Readers'))\n", + "\n", + "# This is a comment!\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10a Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10a Checkpoint.js new file mode 100644 index 0000000..957a94f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10a Checkpoint.js @@ -0,0 +1,37 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.0 Exploring images +// Checkpoint: F10a +// Author: Ujaval Gandhi +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +print('Hello World'); + +var city = 'San Francisco'; +print(city); + +var population = 873965; +print(population); + +var cities = ['San Francisco', 'Los Angeles', 'New York', 'Atlanta']; +print(cities); + +var cityData = { + 'city': 'San Francisco', + 'coordinates': [-122.4194, 37.7749], + 'population': 873965 +}; +print(cityData); + +var greet = function(name) { + return 'Hello ' + name; +}; +print(greet('World')); +print(greet('Readers')); + +// This is a comment! + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10a Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10a Checkpoint.py new file mode 100644 index 0000000..7be474b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10a Checkpoint.py @@ -0,0 +1,43 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.0 Exploring images +# Checkpoint: F10a +# Author: Ujaval Gandhi +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +print('Hello World') + +city = 'San Francisco' +print(city) + +population = 873965 +print(population) + +cities = ['San Francisco', 'Los Angeles', 'New York', 'Atlanta'] +print(cities) + +cityData = { + 'city': 'San Francisco', + 'coordinates': [-122.4194, 37.7749], + 'population': 873965 +} +print(cityData) + +def greet(name): + return 'Hello ' + name + +print(greet('World')) +print(greet('Readers')) + +# This is a comment! + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10b Checkpoint.ipynb new file mode 100644 index 0000000..2b4e69e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10b Checkpoint.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.0 Exploring images\n", + "# Checkpoint: F10b\n", + "# Author: Ujaval Gandhi\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "a = 1\n", + "b = 2\n", + "\n", + "result = ee.Number(a).add(b)\n", + "print(result)\n", + "\n", + "yearList = ee.List.sequence(1980, 2020, 5)\n", + "print(yearList)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10b Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10b Checkpoint.js new file mode 100644 index 0000000..5687f95 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10b Checkpoint.js @@ -0,0 +1,19 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.0 Exploring images +// Checkpoint: F10b +// Author: Ujaval Gandhi +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var a = 1; +var b = 2; + +var result = ee.Number(a).add(b); +print(result); + +var yearList = ee.List.sequence(1980, 2020, 5); +print(yearList); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10b Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10b Checkpoint.py new file mode 100644 index 0000000..57a9636 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.0 Javascript and the Earth Engine API/F10b Checkpoint.py @@ -0,0 +1,25 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.0 Exploring images +# Checkpoint: F10b +# Author: Ujaval Gandhi +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +a = 1 +b = 2 + +result = ee.Number(a).add(b) +print(result) + +yearList = ee.List.sequence(1980, 2020, 5) +print(yearList) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11a Checkpoint.ipynb new file mode 100644 index 0000000..5917507 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11a Checkpoint.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.1 Exploring images\n", + "# Checkpoint: F11a\n", + "# Author: Jeff Howarth\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load an image from its Earth Engine ID.\n", + "first_image = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606')\n", + "\n", + "# Inspect the image object in the Console.\n", + "print(first_image)\n", + "\n", + "# Display band 1 of the image as the first map layer.\n", + "Map.addLayer(\n", + " first_image, # dataset to display\n", + " {\n", + " 'bands': ['SR_B1'], # band to display\n", + " 'min': 8000, # display range\n", + " 'max': 17000\n", + " },\n", + " 'Layer 1' # name to show in Layer Manager\n", + ")\n", + "\n", + "# Display band 2 as the second map layer.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B2'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Layer 2',\n", + " 0, # shown\n", + " 1 # opacity\n", + ")\n", + "\n", + "# Display band 3 as the third map layer.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B3'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Layer 3',\n", + " 1, # shown\n", + " 0 # opacity\n", + ")\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11a Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11a Checkpoint.js new file mode 100644 index 0000000..75f3821 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11a Checkpoint.js @@ -0,0 +1,55 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.1 Exploring images +// Checkpoint: F11a +// Author: Jeff Howarth +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load an image from its Earth Engine ID. +var first_image = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606'); + +// Inspect the image object in the Console. +print(first_image); + +// Display band 1 of the image as the first map layer. +Map.addLayer( + first_image, // dataset to display + { + bands: ['SR_B1'], // band to display + min: 8000, // display range + max: 17000 + }, + 'Layer 1' // name to show in Layer Manager +); + +// Display band 2 as the second map layer. +Map.addLayer( + first_image, + { + bands: ['SR_B2'], + min: 8000, + max: 17000 + }, + 'Layer 2', + 0, // shown + 1 // opacity +); + +// Display band 3 as the third map layer. +Map.addLayer( + first_image, + { + bands: ['SR_B3'], + min: 8000, + max: 17000 + }, + 'Layer 3', + 1, // shown + 0 // opacity +); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11a Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11a Checkpoint.py new file mode 100644 index 0000000..f506c62 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11a Checkpoint.py @@ -0,0 +1,61 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.1 Exploring images +# Checkpoint: F11a +# Author: Jeff Howarth +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load an image from its Earth Engine ID. +first_image = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606') + +# Inspect the image object in the Console. +print(first_image) + +# Display band 1 of the image as the first map layer. +Map.addLayer( + first_image, # dataset to display + { + 'bands': ['SR_B1'], # band to display + 'min': 8000, # display range + 'max': 17000 + }, + 'Layer 1' # name to show in Layer Manager +) + +# Display band 2 as the second map layer. +Map.addLayer( + first_image, + { + 'bands': ['SR_B2'], + 'min': 8000, + 'max': 17000 + }, + 'Layer 2', + 0, # shown + 1 # opacity +) + +# Display band 3 as the third map layer. +Map.addLayer( + first_image, + { + 'bands': ['SR_B3'], + 'min': 8000, + 'max': 17000 + }, + 'Layer 3', + 1, # shown + 0 # opacity +) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11b Checkpoint.ipynb new file mode 100644 index 0000000..5f00905 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11b Checkpoint.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.1 Exploring images\n", + "# Checkpoint: F11b\n", + "# Author: Jeff Howarth\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load an image from its Earth Engine ID.\n", + "first_image = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606')\n", + "\n", + "# Inspect the image object in the Console.\n", + "print(first_image)\n", + "\n", + "# Display band 1 of the image as the first map layer.\n", + "Map.addLayer(\n", + " first_image, # dataset to display\n", + " {\n", + " 'bands': ['SR_B1'], # band to display\n", + " 'min': 8000, # display range\n", + " 'max': 17000\n", + " },\n", + " 'Layer 1' # name to show in Layer Manager\n", + ")\n", + "\n", + "# Display band 2 as the second map layer.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B2'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Layer 2',\n", + " 0, # shown\n", + " 1 # opacity\n", + ")\n", + "\n", + "# Display band 3 as the third map layer.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B3'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Layer 3',\n", + " 1, # shown\n", + " 0 # opacity\n", + ")\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Add a natural color layer by using the first three sensor bands for RGB.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B3', 'SR_B2', 'SR_B1'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Natural Color')\n", + "\n", + "# Add a NIR False-color layer using NIR, red, green sensor bands for RGB.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'False Color')\n", + "\n", + "# Add a SWIR False-color layer using SWIR, NIR, green sensor bands for RGB.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B5', 'SR_B4', 'SR_B2'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Short wave False color')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11b Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11b Checkpoint.js new file mode 100644 index 0000000..02ce4b3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11b Checkpoint.js @@ -0,0 +1,88 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.1 Exploring images +// Checkpoint: F11b +// Author: Jeff Howarth +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load an image from its Earth Engine ID. +var first_image = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606'); + +// Inspect the image object in the Console. +print(first_image); + +// Display band 1 of the image as the first map layer. +Map.addLayer( + first_image, // dataset to display + { + bands: ['SR_B1'], // band to display + min: 8000, // display range + max: 17000 + }, + 'Layer 1' // name to show in Layer Manager +); + +// Display band 2 as the second map layer. +Map.addLayer( + first_image, + { + bands: ['SR_B2'], + min: 8000, + max: 17000 + }, + 'Layer 2', + 0, // shown + 1 // opacity +); + +// Display band 3 as the third map layer. +Map.addLayer( + first_image, + { + bands: ['SR_B3'], + min: 8000, + max: 17000 + }, + 'Layer 3', + 1, // shown + 0 // opacity +); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Add a natural color layer by using the first three sensor bands for RGB. +Map.addLayer( + first_image, + { + bands: ['SR_B3', 'SR_B2', 'SR_B1'], + min: 8000, + max: 17000 + }, + 'Natural Color'); + +// Add a NIR false-color layer using NIR, red, green sensor bands for RGB. +Map.addLayer( + first_image, + { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 8000, + max: 17000 + }, + 'False Color'); + +// Add a SWIR false-color layer using SWIR, NIR, green sensor bands for RGB. +Map.addLayer( + first_image, + { + bands: ['SR_B5', 'SR_B4', 'SR_B2'], + min: 8000, + max: 17000 + }, + 'Short wave false color'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11b Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11b Checkpoint.py new file mode 100644 index 0000000..201e6bb --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11b Checkpoint.py @@ -0,0 +1,94 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.1 Exploring images +# Checkpoint: F11b +# Author: Jeff Howarth +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load an image from its Earth Engine ID. +first_image = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606') + +# Inspect the image object in the Console. +print(first_image) + +# Display band 1 of the image as the first map layer. +Map.addLayer( + first_image, # dataset to display + { + 'bands': ['SR_B1'], # band to display + 'min': 8000, # display range + 'max': 17000 + }, + 'Layer 1' # name to show in Layer Manager +) + +# Display band 2 as the second map layer. +Map.addLayer( + first_image, + { + 'bands': ['SR_B2'], + 'min': 8000, + 'max': 17000 + }, + 'Layer 2', + 0, # shown + 1 # opacity +) + +# Display band 3 as the third map layer. +Map.addLayer( + first_image, + { + 'bands': ['SR_B3'], + 'min': 8000, + 'max': 17000 + }, + 'Layer 3', + 1, # shown + 0 # opacity +) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Add a natural color layer by using the first three sensor bands for RGB. +Map.addLayer( + first_image, + { + 'bands': ['SR_B3', 'SR_B2', 'SR_B1'], + 'min': 8000, + 'max': 17000 + }, + 'Natural Color') + +# Add a NIR False-color layer using NIR, red, green sensor bands for RGB. +Map.addLayer( + first_image, + { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 8000, + 'max': 17000 + }, + 'False Color') + +# Add a SWIR False-color layer using SWIR, NIR, green sensor bands for RGB. +Map.addLayer( + first_image, + { + 'bands': ['SR_B5', 'SR_B4', 'SR_B2'], + 'min': 8000, + 'max': 17000 + }, + 'Short wave False color') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11c Checkpoint.ipynb new file mode 100644 index 0000000..06a83f4 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11c Checkpoint.ipynb @@ -0,0 +1,226 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.1 Exploring images\n", + "# Checkpoint: F11c\n", + "# Author: Jeff Howarth\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load an image from its Earth Engine ID.\n", + "first_image = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606')\n", + "\n", + "# Inspect the image object in the Console.\n", + "print(first_image)\n", + "\n", + "# Display band 1 of the image as the first map layer.\n", + "Map.addLayer(\n", + " first_image, # dataset to display\n", + " {\n", + " 'bands': ['SR_B1'], # band to display\n", + " 'min': 8000, # display range\n", + " 'max': 17000\n", + " },\n", + " 'Layer 1' # name to show in Layer Manager\n", + ")\n", + "\n", + "# Display band 2 as the second map layer.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B2'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Layer 2',\n", + " 0, # shown\n", + " 1 # opacity\n", + ")\n", + "\n", + "# Display band 3 as the third map layer.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B3'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Layer 3',\n", + " 1, # shown\n", + " 0 # opacity\n", + ")\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Add a natural color layer by using the first three sensor bands for RGB.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B3', 'SR_B2', 'SR_B1'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Natural Color')\n", + "\n", + "# Add a NIR False-color layer using NIR, red, green sensor bands for RGB.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'False Color')\n", + "\n", + "# Add a SWIR False-color layer using SWIR, NIR, green sensor bands for RGB.\n", + "Map.addLayer(\n", + " first_image,\n", + " {\n", + " 'bands': ['SR_B5', 'SR_B4', 'SR_B2'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Short wave False color')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Load a 1993 nighttime lights dataset from its Earth Engine ID.\n", + "lights93 = ee.Image('NOAA/DMSP-OLS/NIGHTTIME_LIGHTS/F101993')\n", + "\n", + "# Print image metadata to the Console.\n", + "print('Nighttime lights', lights93)\n", + "\n", + "# Display the 'stable_lights' band as a map layer.\n", + "Map.addLayer(\n", + " lights93,\n", + " {\n", + " 'bands': ['stable_lights'],\n", + " 'min': 0,\n", + " 'max': 63\n", + " },\n", + " 'Lights')\n", + "\n", + "# Construct an image of stable lights for 2003.\n", + "lights03 = ee.Image('NOAA/DMSP-OLS/NIGHTTIME_LIGHTS/F152003') \\\n", + " .select('stable_lights').rename('2003')\n", + "\n", + "# Construct an image of stable lights for 2013.\n", + "lights13 = ee.Image('NOAA/DMSP-OLS/NIGHTTIME_LIGHTS/F182013') \\\n", + " .select('stable_lights').rename('2013')\n", + "\n", + "# Construct an image with three bands,\n", + "# where each band represents stable lights for one year.\n", + "\n", + "changeImage = lights13.addBands(lights03) \\\n", + " .addBands(lights93.select('stable_lights').rename('1993'))\n", + "\n", + "# Print image metadata to the Console.\n", + "print('change image', changeImage)\n", + "\n", + "# Add an RGB composite layer to the Map.\n", + "Map.addLayer(\n", + " changeImage,\n", + " {\n", + " 'min': 0,\n", + " 'max': 63\n", + " },\n", + " 'Change composite')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11c Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11c Checkpoint.js new file mode 100644 index 0000000..49532fe --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11c Checkpoint.js @@ -0,0 +1,133 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.1 Exploring images +// Checkpoint: F11c +// Author: Jeff Howarth +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load an image from its Earth Engine ID. +var first_image = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606'); + +// Inspect the image object in the Console. +print(first_image); + +// Display band 1 of the image as the first map layer. +Map.addLayer( + first_image, // dataset to display + { + bands: ['SR_B1'], // band to display + min: 8000, // display range + max: 17000 + }, + 'Layer 1' // name to show in Layer Manager +); + +// Display band 2 as the second map layer. +Map.addLayer( + first_image, + { + bands: ['SR_B2'], + min: 8000, + max: 17000 + }, + 'Layer 2', + 0, // shown + 1 // opacity +); + +// Display band 3 as the third map layer. +Map.addLayer( + first_image, + { + bands: ['SR_B3'], + min: 8000, + max: 17000 + }, + 'Layer 3', + 1, // shown + 0 // opacity +); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Add a natural color layer by using the first three sensor bands for RGB. +Map.addLayer( + first_image, + { + bands: ['SR_B3', 'SR_B2', 'SR_B1'], + min: 8000, + max: 17000 + }, + 'Natural Color'); + +// Add a NIR false-color layer using NIR, red, green sensor bands for RGB. +Map.addLayer( + first_image, + { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 8000, + max: 17000 + }, + 'False Color'); + +// Add a SWIR false-color layer using SWIR, NIR, green sensor bands for RGB. +Map.addLayer( + first_image, + { + bands: ['SR_B5', 'SR_B4', 'SR_B2'], + min: 8000, + max: 17000 + }, + 'Short wave false color'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Load a 1993 nighttime lights dataset from its Earth Engine ID. +var lights93 = ee.Image('NOAA/DMSP-OLS/NIGHTTIME_LIGHTS/F101993'); + +// Print image metadata to the Console. +print('Nighttime lights', lights93); + +// Display the 'stable_lights' band as a map layer. +Map.addLayer( + lights93, + { + bands: ['stable_lights'], + min: 0, + max: 63 + }, + 'Lights'); + +// Construct an image of stable lights for 2003. +var lights03 = ee.Image('NOAA/DMSP-OLS/NIGHTTIME_LIGHTS/F152003') + .select('stable_lights').rename('2003'); + +// Construct an image of stable lights for 2013. +var lights13 = ee.Image('NOAA/DMSP-OLS/NIGHTTIME_LIGHTS/F182013') + .select('stable_lights').rename('2013'); + +// Construct an image with three bands, +// where each band represents stable lights for one year. + +var changeImage = lights13.addBands(lights03) + .addBands(lights93.select('stable_lights').rename('1993')); + +// Print image metadata to the Console. +print('change image', changeImage); + +// Add an RGB composite layer to the Map. +Map.addLayer( + changeImage, + { + min: 0, + max: 63 + }, + 'Change composite'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11c Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11c Checkpoint.py new file mode 100644 index 0000000..14fcd2f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11c Checkpoint.py @@ -0,0 +1,139 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.1 Exploring images +# Checkpoint: F11c +# Author: Jeff Howarth +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load an image from its Earth Engine ID. +first_image = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606') + +# Inspect the image object in the Console. +print(first_image) + +# Display band 1 of the image as the first map layer. +Map.addLayer( + first_image, # dataset to display + { + 'bands': ['SR_B1'], # band to display + 'min': 8000, # display range + 'max': 17000 + }, + 'Layer 1' # name to show in Layer Manager +) + +# Display band 2 as the second map layer. +Map.addLayer( + first_image, + { + 'bands': ['SR_B2'], + 'min': 8000, + 'max': 17000 + }, + 'Layer 2', + 0, # shown + 1 # opacity +) + +# Display band 3 as the third map layer. +Map.addLayer( + first_image, + { + 'bands': ['SR_B3'], + 'min': 8000, + 'max': 17000 + }, + 'Layer 3', + 1, # shown + 0 # opacity +) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Add a natural color layer by using the first three sensor bands for RGB. +Map.addLayer( + first_image, + { + 'bands': ['SR_B3', 'SR_B2', 'SR_B1'], + 'min': 8000, + 'max': 17000 + }, + 'Natural Color') + +# Add a NIR False-color layer using NIR, red, green sensor bands for RGB. +Map.addLayer( + first_image, + { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 8000, + 'max': 17000 + }, + 'False Color') + +# Add a SWIR False-color layer using SWIR, NIR, green sensor bands for RGB. +Map.addLayer( + first_image, + { + 'bands': ['SR_B5', 'SR_B4', 'SR_B2'], + 'min': 8000, + 'max': 17000 + }, + 'Short wave False color') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Load a 1993 nighttime lights dataset from its Earth Engine ID. +lights93 = ee.Image('NOAA/DMSP-OLS/NIGHTTIME_LIGHTS/F101993') + +# Print image metadata to the Console. +print('Nighttime lights', lights93) + +# Display the 'stable_lights' band as a map layer. +Map.addLayer( + lights93, + { + 'bands': ['stable_lights'], + 'min': 0, + 'max': 63 + }, + 'Lights') + +# Construct an image of stable lights for 2003. +lights03 = ee.Image('NOAA/DMSP-OLS/NIGHTTIME_LIGHTS/F152003') \ + .select('stable_lights').rename('2003') + +# Construct an image of stable lights for 2013. +lights13 = ee.Image('NOAA/DMSP-OLS/NIGHTTIME_LIGHTS/F182013') \ + .select('stable_lights').rename('2013') + +# Construct an image with three bands, +# where each band represents stable lights for one year. + +changeImage = lights13.addBands(lights03) \ + .addBands(lights93.select('stable_lights').rename('1993')) + +# Print image metadata to the Console. +print('change image', changeImage) + +# Add an RGB composite layer to the Map. +Map.addLayer( + changeImage, + { + 'min': 0, + 'max': 63 + }, + 'Change composite') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s1 Assignment 4.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s1 Assignment 4.ipynb new file mode 100644 index 0000000..729f282 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s1 Assignment 4.ipynb @@ -0,0 +1,141 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.1 Exploring images\n", + "# Section: Practice problem (Assignment 4)\n", + "# Author: Jeff Howarth\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load the practice image from the Earth Engine ID.\n", + "practice_image = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_022039_20050907')\n", + "\n", + "# Print image metadata to the Console.\n", + "print(practice_image)\n", + "\n", + "# Center the Map on the image.\n", + "Map.centerObject(practice_image, 9)\n", + "\n", + "# Add a natural color composite to the Map.\n", + "Map.addLayer(\n", + " practice_image,\n", + " {\n", + " 'bands': ['SR_B3', 'SR_B2', 'SR_B1'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Natural color'\n", + ")\n", + "\n", + "# Add an NIR False color composite to the Map.\n", + "Map.addLayer(\n", + " practice_image,\n", + " {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'NIR False color'\n", + ")\n", + "\n", + "# Add a SWIR False color composite to the Map.\n", + "Map.addLayer(\n", + " practice_image,\n", + " {\n", + " 'bands': ['SR_B5', 'SR_B4', 'SR_B2'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'SWIR False color'\n", + ")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s1 Assignment 4.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s1 Assignment 4.js new file mode 100644 index 0000000..7ff1656 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s1 Assignment 4.js @@ -0,0 +1,48 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.1 Exploring images +// Section: Practice problem (Assignment 4) +// Author: Jeff Howarth +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load the practice image from the Earth Engine ID. +var practice_image = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_022039_20050907'); + +// Print image metadata to the Console. +print(practice_image); + +// Center the Map on the image. +Map.centerObject(practice_image, 9); + +// Add a natural color composite to the Map. +Map.addLayer( + practice_image, + { + bands: ['SR_B3', 'SR_B2', 'SR_B1'], + min: 8000, + max: 17000 + }, + 'Natural color' +); + +// Add an NIR false color composite to the Map. +Map.addLayer( + practice_image, + { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 8000, + max: 17000 + }, + 'NIR false color' +); + +// Add a SWIR false color composite to the Map. +Map.addLayer( + practice_image, + { + bands: ['SR_B5', 'SR_B4', 'SR_B2'], + min: 8000, + max: 17000 + }, + 'SWIR false color' +); diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s1 Assignment 4.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s1 Assignment 4.py new file mode 100644 index 0000000..b2fd3a4 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s1 Assignment 4.py @@ -0,0 +1,54 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.1 Exploring images +# Section: Practice problem (Assignment 4) +# Author: Jeff Howarth +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load the practice image from the Earth Engine ID. +practice_image = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_022039_20050907') + +# Print image metadata to the Console. +print(practice_image) + +# Center the Map on the image. +Map.centerObject(practice_image, 9) + +# Add a natural color composite to the Map. +Map.addLayer( + practice_image, + { + 'bands': ['SR_B3', 'SR_B2', 'SR_B1'], + 'min': 8000, + 'max': 17000 + }, + 'Natural color' +) + +# Add an NIR False color composite to the Map. +Map.addLayer( + practice_image, + { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 8000, + 'max': 17000 + }, + 'NIR False color' +) + +# Add a SWIR False color composite to the Map. +Map.addLayer( + practice_image, + { + 'bands': ['SR_B5', 'SR_B4', 'SR_B2'], + 'min': 8000, + 'max': 17000 + }, + 'SWIR False color' +) +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s2 Assignment 5.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s2 Assignment 5.ipynb new file mode 100644 index 0000000..3d5cf2e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s2 Assignment 5.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.1 Exploring images\n", + "# Section: Practice problem (Assignment 5)\n", + "# Author: Jeff Howarth\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "image = ee.Image('LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606')\n", + "\n", + "Map.addLayer(\n", + " image,\n", + " {\n", + " 'bands': ['SR_B1'],\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Layer 1'\n", + ")\n", + "\n", + "Map.addLayer(\n", + " image.select('SR_B1'),\n", + " {\n", + " 'min': 8000,\n", + " 'max': 17000\n", + " },\n", + " 'Layer 2'\n", + ")\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s2 Assignment 5.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s2 Assignment 5.js new file mode 100644 index 0000000..2b02cf3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s2 Assignment 5.js @@ -0,0 +1,29 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.1 Exploring images +// Section: Practice problem (Assignment 5) +// Author: Jeff Howarth +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var image = ee.Image('LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606'); + +Map.addLayer( + image, + { + bands: ['SR_B1'], + min: 8000, + max: 17000 + }, + 'Layer 1' +); + +Map.addLayer( + image.select('SR_B1'), + { + min: 8000, + max: 17000 + }, + 'Layer 2' +); + + + diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s2 Assignment 5.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s2 Assignment 5.py new file mode 100644 index 0000000..6946583 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.1 Exploring Images/F11s2 Assignment 5.py @@ -0,0 +1,35 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.1 Exploring images +# Section: Practice problem (Assignment 5) +# Author: Jeff Howarth +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +image = ee.Image('LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606') + +Map.addLayer( + image, + { + 'bands': ['SR_B1'], + 'min': 8000, + 'max': 17000 + }, + 'Layer 1' +) + +Map.addLayer( + image.select('SR_B1'), + { + 'min': 8000, + 'max': 17000 + }, + 'Layer 2' +) + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12a Checkpoint.ipynb new file mode 100644 index 0000000..423cc7d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12a Checkpoint.ipynb @@ -0,0 +1,129 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.2 Survey of Raster Datasets\n", + "# Checkpoint: F12a\n", + "# Authors: Andr\u00e9a, Karen, Nick Clinton, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##/\n", + "# View an Image Collection\n", + "##/\n", + "\n", + "# Import the Landsat 8 Raw Collection.\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1')\n", + "\n", + "# Print the size of the Landsat 8 dataset.\n", + "print('The size of the Landsat 8 image collection is:', landsat8 \\\n", + ".size())\n", + "\n", + "# Try to print the image collection.\n", + "# WARNING! Running the print code immediately below produces an error because\n", + "# the Console can not print more than 5000 elements.\n", + "print(landsat8)\n", + "\n", + "# Add the Landsat 8 dataset to the Map as a mosaic. The collection is\n", + "# already chronologically sorted, so the most recent pixel is displayed.\n", + "Map.addLayer(landsat8,\n", + " {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 5000,\n", + " 'max': 15000\n", + " },\n", + " 'Landsat 8 Image Collection')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12a Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12a Checkpoint.js new file mode 100644 index 0000000..0e9686d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12a Checkpoint.js @@ -0,0 +1,37 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.2 Survey of Raster Datasets +// Checkpoint: F12a +// Authors: Andréa, Karen, Nick Clinton, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///// +// View an Image Collection +///// + +// Import the Landsat 8 Raw Collection. +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1'); + +// Print the size of the Landsat 8 dataset. +print('The size of the Landsat 8 image collection is:', landsat8 +.size()); + +// Try to print the image collection. +// WARNING! Running the print code immediately below produces an error because +// the Console can not print more than 5000 elements. +print(landsat8); + +// Add the Landsat 8 dataset to the Map as a mosaic. The collection is +// already chronologically sorted, so the most recent pixel is displayed. +Map.addLayer(landsat8, + { + bands: ['B4', 'B3', 'B2'], + min: 5000, + max: 15000 + }, + 'Landsat 8 Image Collection'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12a Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12a Checkpoint.py new file mode 100644 index 0000000..00de506 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12a Checkpoint.py @@ -0,0 +1,43 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.2 Survey of Raster Datasets +# Checkpoint: F12a +# Authors: Andréa, Karen, Nick Clinton, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##/ +# View an Image Collection +##/ + +# Import the Landsat 8 Raw Collection. +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1') + +# Print the size of the Landsat 8 dataset. +print('The size of the Landsat 8 image collection is:', landsat8 \ +.size()) + +# Try to print the image collection. +# WARNING! Running the print code immediately below produces an error because +# the Console can not print more than 5000 elements. +print(landsat8) + +# Add the Landsat 8 dataset to the Map as a mosaic. The collection is +# already chronologically sorted, so the most recent pixel is displayed. +Map.addLayer(landsat8, + { + 'bands': ['B4', 'B3', 'B2'], + 'min': 5000, + 'max': 15000 + }, + 'Landsat 8 Image Collection') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12b Checkpoint.ipynb new file mode 100644 index 0000000..40f4732 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12b Checkpoint.ipynb @@ -0,0 +1,183 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.2 Survey of Raster Datasets\n", + "# Checkpoint: F12b\n", + "# Authors: Andr\u00e9a, Karen, Nick Clinton, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "\n", + "##/\n", + "# View an Image Collection\n", + "##/\n", + "\n", + "# Import the Landsat 8 Raw Collection.\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1')\n", + "\n", + "# Print the size of the Landsat 8 dataset.\n", + "print('The size of the Landsat 8 image collection is:', landsat8 \\\n", + ".size())\n", + "\n", + "# Try to print the image collection.\n", + "# WARNING! Running the print code immediately below produces an error because\n", + "# the Console can not print more than 5000 elements.\n", + "# print(landsat8)\n", + "\n", + "# Add the Landsat 8 dataset to the map as a mosaic. The collection is\n", + "# already chronologically sorted, so the most recent pixel is displayed.\n", + "# Map.addLayer(landsat8,\n", + "# {\n", + "# bands: ['B4', 'B3', 'B2'],\n", + "# min: 5000,\n", + "# max: 15000\n", + "# },\n", + "# 'Landsat 8 Image Collection')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Filter an Image Collection\n", + "##/\n", + "\n", + "# Filter the collection by date.\n", + "landsatWinter = landsat8.filterDate('2020-12-01', '2021-03-01')\n", + "\n", + "Map.addLayer(landsatWinter,\n", + " {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 5000,\n", + " 'max': 15000\n", + " },\n", + " 'Winter Landsat 8')\n", + "\n", + "print('The size of the Winter Landsat 8 image collection is:',\n", + " landsatWinter.size())\n", + "\n", + "# Create an Earth Engine Point object.\n", + "pointMN = ee.Geometry.Point([-93.79, 45.05])\n", + "\n", + "# Filter the collection by location using the point.\n", + "landsatMN = landsatWinter.filterBounds(pointMN)\n", + "Map.addLayer(landsatMN,\n", + " {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 5000,\n", + " 'max': 15000\n", + " },\n", + " 'MN Landsat 8')\n", + "\n", + "# Add the point to the map to see where it is.\n", + "Map.addLayer(pointMN, {}, 'Point MN')\n", + "\n", + "print('The size of the Minneapolis Winter Landsat 8 image collection is: ',\n", + " landsatMN.size())\n", + "\n", + "# Select the first image in the filtered collection.\n", + "landsatFirst = landsatMN.first()\n", + "\n", + "# Display the first image in the filtered collection.\n", + "Map.centerObject(landsatFirst, 7)\n", + "Map.addLayer(landsatFirst,\n", + " {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 5000,\n", + " 'max': 15000\n", + " },\n", + " 'First Landsat 8')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12b Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12b Checkpoint.js new file mode 100644 index 0000000..d280660 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12b Checkpoint.js @@ -0,0 +1,90 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.2 Survey of Raster Datasets +// Checkpoint: F12b +// Authors: Andréa, Karen, Nick Clinton, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +///// +// View an Image Collection +///// + +// Import the Landsat 8 Raw Collection. +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1'); + +// Print the size of the Landsat 8 dataset. +print('The size of the Landsat 8 image collection is:', landsat8 +.size()); + +// Try to print the image collection. +// WARNING! Running the print code immediately below produces an error because +// the Console can not print more than 5000 elements. +// print(landsat8); + +// Add the Landsat 8 dataset to the map as a mosaic. The collection is +// already chronologically sorted, so the most recent pixel is displayed. +// Map.addLayer(landsat8, +// { +// bands: ['B4', 'B3', 'B2'], +// min: 5000, +// max: 15000 +// }, +// 'Landsat 8 Image Collection'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Filter an Image Collection +///// + +// Filter the collection by date. +var landsatWinter = landsat8.filterDate('2020-12-01', '2021-03-01'); + +Map.addLayer(landsatWinter, + { + bands: ['B4', 'B3', 'B2'], + min: 5000, + max: 15000 + }, + 'Winter Landsat 8'); + +print('The size of the Winter Landsat 8 image collection is:', + landsatWinter.size()); + +// Create an Earth Engine Point object. +var pointMN = ee.Geometry.Point([-93.79, 45.05]); + +// Filter the collection by location using the point. +var landsatMN = landsatWinter.filterBounds(pointMN); +Map.addLayer(landsatMN, + { + bands: ['B4', 'B3', 'B2'], + min: 5000, + max: 15000 + }, + 'MN Landsat 8'); + +// Add the point to the map to see where it is. +Map.addLayer(pointMN, {}, 'Point MN'); + +print('The size of the Minneapolis Winter Landsat 8 image collection is: ', + landsatMN.size()); + +// Select the first image in the filtered collection. +var landsatFirst = landsatMN.first(); + +// Display the first image in the filtered collection. +Map.centerObject(landsatFirst, 7); +Map.addLayer(landsatFirst, + { + bands: ['B4', 'B3', 'B2'], + min: 5000, + max: 15000 + }, + 'First Landsat 8'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12b Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12b Checkpoint.py new file mode 100644 index 0000000..346f0df --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12b Checkpoint.py @@ -0,0 +1,96 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.2 Survey of Raster Datasets +# Checkpoint: F12b +# Authors: Andréa, Karen, Nick Clinton, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +##/ +# View an Image Collection +##/ + +# Import the Landsat 8 Raw Collection. +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1') + +# Print the size of the Landsat 8 dataset. +print('The size of the Landsat 8 image collection is:', landsat8 \ +.size()) + +# Try to print the image collection. +# WARNING! Running the print code immediately below produces an error because +# the Console can not print more than 5000 elements. +# print(landsat8) + +# Add the Landsat 8 dataset to the map as a mosaic. The collection is +# already chronologically sorted, so the most recent pixel is displayed. +# Map.addLayer(landsat8, +# { +# bands: ['B4', 'B3', 'B2'], +# min: 5000, +# max: 15000 +# }, +# 'Landsat 8 Image Collection') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Filter an Image Collection +##/ + +# Filter the collection by date. +landsatWinter = landsat8.filterDate('2020-12-01', '2021-03-01') + +Map.addLayer(landsatWinter, + { + 'bands': ['B4', 'B3', 'B2'], + 'min': 5000, + 'max': 15000 + }, + 'Winter Landsat 8') + +print('The size of the Winter Landsat 8 image collection is:', + landsatWinter.size()) + +# Create an Earth Engine Point object. +pointMN = ee.Geometry.Point([-93.79, 45.05]) + +# Filter the collection by location using the point. +landsatMN = landsatWinter.filterBounds(pointMN) +Map.addLayer(landsatMN, + { + 'bands': ['B4', 'B3', 'B2'], + 'min': 5000, + 'max': 15000 + }, + 'MN Landsat 8') + +# Add the point to the map to see where it is. +Map.addLayer(pointMN, {}, 'Point MN') + +print('The size of the Minneapolis Winter Landsat 8 image collection is: ', + landsatMN.size()) + +# Select the first image in the filtered collection. +landsatFirst = landsatMN.first() + +# Display the first image in the filtered collection. +Map.centerObject(landsatFirst, 7) +Map.addLayer(landsatFirst, + { + 'bands': ['B4', 'B3', 'B2'], + 'min': 5000, + 'max': 15000 + }, + 'First Landsat 8') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12c Checkpoint.ipynb new file mode 100644 index 0000000..9ace34f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12c Checkpoint.ipynb @@ -0,0 +1,132 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.2 Survey of Raster Datasets\n", + "# Checkpoint: F12c\n", + "# Authors: Andr\u00e9a, Karen, Nick Clinton, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##/\n", + "# Collections of single images - Landsat 8 Surface Reflectance\n", + "##/\n", + "\n", + "# Create and Earth Engine Point object over San Francisco.\n", + "pointSF = ee.Geometry.Point([-122.44, 37.76])\n", + "\n", + "# Import the Landsat 8 Surface Reflectance collection.\n", + "landsat8SR = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "\n", + "# Filter the collection and select the first image.\n", + "landsat8SRimage = landsat8SR.filterDate('2014-03-18',\n", + " '2014-03-19') \\\n", + " .filterBounds(pointSF) \\\n", + " .first()\n", + "\n", + "print('Landsat 8 Surface Reflectance image', landsat8SRimage)\n", + "\n", + "# Center map to the first image.\n", + "Map.centerObject(landsat8SRimage, 8)\n", + "\n", + "# Add first image to the map.\n", + "Map.addLayer(landsat8SRimage,\n", + " {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 7000,\n", + " 'max': 13000\n", + " },\n", + " 'Landsat 8 SR')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12c Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12c Checkpoint.js new file mode 100644 index 0000000..0514146 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12c Checkpoint.js @@ -0,0 +1,39 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.2 Survey of Raster Datasets +// Checkpoint: F12c +// Authors: Andréa, Karen, Nick Clinton, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///// +// Collections of single images - Landsat 8 Surface Reflectance +///// + +// Create and Earth Engine Point object over San Francisco. +var pointSF = ee.Geometry.Point([-122.44, 37.76]); + +// Import the Landsat 8 Surface Reflectance collection. +var landsat8SR = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); + +// Filter the collection and select the first image. +var landsat8SRimage = landsat8SR.filterDate('2014-03-18', + '2014-03-19') + .filterBounds(pointSF) + .first(); + +print('Landsat 8 Surface Reflectance image', landsat8SRimage); + +// Center map to the first image. +Map.centerObject(landsat8SRimage, 8); + +// Add first image to the map. +Map.addLayer(landsat8SRimage, + { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 7000, + max: 13000 + }, + 'Landsat 8 SR'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12c Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12c Checkpoint.py new file mode 100644 index 0000000..21410ab --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12c Checkpoint.py @@ -0,0 +1,45 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.2 Survey of Raster Datasets +# Checkpoint: F12c +# Authors: Andréa, Karen, Nick Clinton, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##/ +# Collections of single images - Landsat 8 Surface Reflectance +##/ + +# Create and Earth Engine Point object over San Francisco. +pointSF = ee.Geometry.Point([-122.44, 37.76]) + +# Import the Landsat 8 Surface Reflectance collection. +landsat8SR = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + +# Filter the collection and select the first image. +landsat8SRimage = landsat8SR.filterDate('2014-03-18', + '2014-03-19') \ + .filterBounds(pointSF) \ + .first() + +print('Landsat 8 Surface Reflectance image', landsat8SRimage) + +# Center map to the first image. +Map.centerObject(landsat8SRimage, 8) + +# Add first image to the map. +Map.addLayer(landsat8SRimage, + { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 7000, + 'max': 13000 + }, + 'Landsat 8 SR') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12d Checkpoint.ipynb new file mode 100644 index 0000000..b07f51b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12d Checkpoint.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.2 Survey of Raster Datasets\n", + "# Checkpoint: F12d\n", + "# Authors: Andr\u00e9a, Karen, Nick Clinton, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##/\n", + "# Collections of single images - Landsat 8 Surface Reflectance\n", + "##/\n", + "\n", + "# Create and Earth Engine Point object over San Francisco.\n", + "pointSF = ee.Geometry.Point([-122.44, 37.76])\n", + "\n", + "# Import the Landsat 8 Surface Reflectance collection.\n", + "landsat8SR = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')\n", + "\n", + "# Filter the collection and select the first image.\n", + "landsat8SRimage = landsat8SR.filterDate('2014-03-18',\n", + " '2014-03-19') \\\n", + " .filterBounds(pointSF) \\\n", + " .first()\n", + "\n", + "\n", + "print('Landsat 8 Surface Reflectance image', landsat8SRimage)\n", + "\n", + "# Center map to the first image.\n", + "Map.centerObject(landsat8SRimage, 8)\n", + "\n", + "# Add first image to the map.\n", + "Map.addLayer(landsat8SRimage,\n", + " {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 7000,\n", + " 'max': 13000\n", + " },\n", + " 'Landsat 8 SR')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Pre-made composites\n", + "##/\n", + "\n", + "# Import a MODIS dataset of daily BRDF-corrected reflectance.\n", + "modisDaily = ee.ImageCollection('MODIS/006/MCD43A4')\n", + "\n", + "# Filter the dataset to a recent date.\n", + "modisDailyRecent = modisDaily.filterDate('2021-11-01')\n", + "\n", + "# Add the dataset to the map.\n", + "modisVis = {\n", + " 'bands': [\n", + " 'Nadir_Reflectance_Band1',\n", + " 'Nadir_Reflectance_Band4',\n", + " 'Nadir_Reflectance_Band3'\n", + " ],\n", + " 'min': 0,\n", + " 'max': 4000\n", + "}\n", + "Map.addLayer(modisDailyRecent, modisVis, 'MODIS Daily Composite')\n", + "\n", + "\n", + "# Import the MODIS monthly burned areas dataset.\n", + "modisMonthly = ee.ImageCollection('MODIS/006/MCD64A1')\n", + "\n", + "# Filter the dataset to a recent month during fire season.\n", + "modisMonthlyRecent = modisMonthly.filterDate('2021-08-01')\n", + "\n", + "# Add the dataset to the map.\n", + "Map.addLayer(modisMonthlyRecent, {}, 'MODIS Monthly Burn')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12d Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12d Checkpoint.js new file mode 100644 index 0000000..212d78d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12d Checkpoint.js @@ -0,0 +1,76 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.2 Survey of Raster Datasets +// Checkpoint: F12d +// Authors: Andréa, Karen, Nick Clinton, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///// +// Collections of single images - Landsat 8 Surface Reflectance +///// + +// Create and Earth Engine Point object over San Francisco. +var pointSF = ee.Geometry.Point([-122.44, 37.76]); + +// Import the Landsat 8 Surface Reflectance collection. +var landsat8SR = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); + +// Filter the collection and select the first image. +var landsat8SRimage = landsat8SR.filterDate('2014-03-18', + '2014-03-19') + .filterBounds(pointSF) + .first(); + + +print('Landsat 8 Surface Reflectance image', landsat8SRimage); + +// Center map to the first image. +Map.centerObject(landsat8SRimage, 8); + +// Add first image to the map. +Map.addLayer(landsat8SRimage, + { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 7000, + max: 13000 + }, + 'Landsat 8 SR'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Pre-made composites +///// + +// Import a MODIS dataset of daily BRDF-corrected reflectance. +var modisDaily = ee.ImageCollection('MODIS/006/MCD43A4'); + +// Filter the dataset to a recent date. +var modisDailyRecent = modisDaily.filterDate('2021-11-01'); + +// Add the dataset to the map. +var modisVis = { + bands: [ + 'Nadir_Reflectance_Band1', + 'Nadir_Reflectance_Band4', + 'Nadir_Reflectance_Band3' + ], + min: 0, + max: 4000 +}; +Map.addLayer(modisDailyRecent, modisVis, 'MODIS Daily Composite'); + + +// Import the MODIS monthly burned areas dataset. +var modisMonthly = ee.ImageCollection('MODIS/006/MCD64A1'); + +// Filter the dataset to a recent month during fire season. +var modisMonthlyRecent = modisMonthly.filterDate('2021-08-01'); + +// Add the dataset to the map. +Map.addLayer(modisMonthlyRecent, {}, 'MODIS Monthly Burn'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12d Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12d Checkpoint.py new file mode 100644 index 0000000..f406f05 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12d Checkpoint.py @@ -0,0 +1,82 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.2 Survey of Raster Datasets +# Checkpoint: F12d +# Authors: Andréa, Karen, Nick Clinton, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##/ +# Collections of single images - Landsat 8 Surface Reflectance +##/ + +# Create and Earth Engine Point object over San Francisco. +pointSF = ee.Geometry.Point([-122.44, 37.76]) + +# Import the Landsat 8 Surface Reflectance collection. +landsat8SR = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + +# Filter the collection and select the first image. +landsat8SRimage = landsat8SR.filterDate('2014-03-18', + '2014-03-19') \ + .filterBounds(pointSF) \ + .first() + + +print('Landsat 8 Surface Reflectance image', landsat8SRimage) + +# Center map to the first image. +Map.centerObject(landsat8SRimage, 8) + +# Add first image to the map. +Map.addLayer(landsat8SRimage, + { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 7000, + 'max': 13000 + }, + 'Landsat 8 SR') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Pre-made composites +##/ + +# Import a MODIS dataset of daily BRDF-corrected reflectance. +modisDaily = ee.ImageCollection('MODIS/006/MCD43A4') + +# Filter the dataset to a recent date. +modisDailyRecent = modisDaily.filterDate('2021-11-01') + +# Add the dataset to the map. +modisVis = { + 'bands': [ + 'Nadir_Reflectance_Band1', + 'Nadir_Reflectance_Band4', + 'Nadir_Reflectance_Band3' + ], + 'min': 0, + 'max': 4000 +} +Map.addLayer(modisDailyRecent, modisVis, 'MODIS Daily Composite') + + +# Import the MODIS monthly burned areas dataset. +modisMonthly = ee.ImageCollection('MODIS/006/MCD64A1') + +# Filter the dataset to a recent month during fire season. +modisMonthlyRecent = modisMonthly.filterDate('2021-08-01') + +# Add the dataset to the map. +Map.addLayer(modisMonthlyRecent, {}, 'MODIS Monthly Burn') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12e Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12e Checkpoint.ipynb new file mode 100644 index 0000000..ef2e096 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12e Checkpoint.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.2 Survey of Raster Datasets\n", + "# Checkpoint: F12e\n", + "# Authors: Andr\u00e9a, Karen, Nick Clinton, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##/\n", + "# Other satellite products\n", + "##/\n", + "\n", + "# Import a Sentinel-5 methane dataset.\n", + "methane = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_CH4')\n", + "\n", + "# Filter the methane dataset.\n", + "methane2018 = methane.select(\n", + " 'CH4_column_volume_mixing_ratio_dry_air') \\\n", + " .filterDate('2018-11-28', '2018-11-29') \\\n", + " .first()\n", + "\n", + "# Make a visualization for the methane data.\n", + "methaneVis = {\n", + " 'palette': ['black', 'blue', 'purple', 'cyan', 'green',\n", + " 'yellow', 'red'\n", + " ],\n", + " 'min': 1770,\n", + " 'max': 1920\n", + "}\n", + "\n", + "# Center the Map.\n", + "Map.centerObject(methane2018, 3)\n", + "\n", + "# Add the methane dataset to the map.\n", + "Map.addLayer(methane2018, methaneVis, 'Methane')\n", + "\n", + "# Import the ERA5 Monthly dataset\n", + "era5Monthly = ee.ImageCollection('ECMWF/ERA5/MONTHLY')\n", + "\n", + "# Filter the dataset\n", + "era5MonthlyTemp = era5Monthly.select('mean_2m_air_temperature') \\\n", + " .filterDate('2018-01-01', '2018-01-31') \\\n", + " .first()\n", + "\n", + "# Add the ERA dataset to the map.\n", + "Map.addLayer(era5MonthlyTemp,\n", + " {\n", + " 'palette': ['yellow', 'red'],\n", + " 'min': 260,\n", + " 'max': 320\n", + " },\n", + " 'ERA5 Max Monthly Temp')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12e Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12e Checkpoint.js new file mode 100644 index 0000000..6b0954a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12e Checkpoint.js @@ -0,0 +1,54 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.2 Survey of Raster Datasets +// Checkpoint: F12e +// Authors: Andréa, Karen, Nick Clinton, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///// +// Other satellite products +///// + +// Import a Sentinel-5 methane dataset. +var methane = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_CH4'); + +// Filter the methane dataset. +var methane2018 = methane.select( + 'CH4_column_volume_mixing_ratio_dry_air') + .filterDate('2018-11-28', '2018-11-29') + .first(); + +// Make a visualization for the methane data. +var methaneVis = { + palette: ['black', 'blue', 'purple', 'cyan', 'green', + 'yellow', 'red' + ], + min: 1770, + max: 1920 +}; + +// Center the Map. +Map.centerObject(methane2018, 3); + +// Add the methane dataset to the map. +Map.addLayer(methane2018, methaneVis, 'Methane'); + +// Import the ERA5 Monthly dataset +var era5Monthly = ee.ImageCollection('ECMWF/ERA5/MONTHLY'); + +// Filter the dataset +var era5MonthlyTemp = era5Monthly.select('mean_2m_air_temperature') + .filterDate('2018-01-01', '2018-01-31') + .first(); + +// Add the ERA dataset to the map. +Map.addLayer(era5MonthlyTemp, + { + palette: ['yellow', 'red'], + min: 260, + max: 320 + }, + 'ERA5 Max Monthly Temp'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12e Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12e Checkpoint.py new file mode 100644 index 0000000..4a85a9b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12e Checkpoint.py @@ -0,0 +1,60 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.2 Survey of Raster Datasets +# Checkpoint: F12e +# Authors: Andréa, Karen, Nick Clinton, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##/ +# Other satellite products +##/ + +# Import a Sentinel-5 methane dataset. +methane = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_CH4') + +# Filter the methane dataset. +methane2018 = methane.select( + 'CH4_column_volume_mixing_ratio_dry_air') \ + .filterDate('2018-11-28', '2018-11-29') \ + .first() + +# Make a visualization for the methane data. +methaneVis = { + 'palette': ['black', 'blue', 'purple', 'cyan', 'green', + 'yellow', 'red' + ], + 'min': 1770, + 'max': 1920 +} + +# Center the Map. +Map.centerObject(methane2018, 3) + +# Add the methane dataset to the map. +Map.addLayer(methane2018, methaneVis, 'Methane') + +# Import the ERA5 Monthly dataset +era5Monthly = ee.ImageCollection('ECMWF/ERA5/MONTHLY') + +# Filter the dataset +era5MonthlyTemp = era5Monthly.select('mean_2m_air_temperature') \ + .filterDate('2018-01-01', '2018-01-31') \ + .first() + +# Add the ERA dataset to the map. +Map.addLayer(era5MonthlyTemp, + { + 'palette': ['yellow', 'red'], + 'min': 260, + 'max': 320 + }, + 'ERA5 Max Monthly Temp') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12f Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12f Checkpoint.ipynb new file mode 100644 index 0000000..d3b1130 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12f Checkpoint.ipynb @@ -0,0 +1,143 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.2 Survey of Raster Datasets\n", + "# Checkpoint: F12f\n", + "# Authors: Andr\u00e9a, Karen, Nick Clinton, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##/\n", + "# Pre-classified Land Use Land Cover\n", + "##/\n", + "\n", + "# Import the ESA WorldCover dataset.\n", + "worldCover = ee.ImageCollection('ESA/WorldCover/v100').first()\n", + "\n", + "# Center the Map.\n", + "Map.centerObject(worldCover, 3)\n", + "\n", + "# Add the worldCover layer to the map.\n", + "Map.addLayer(worldCover, {\n", + " 'bands': ['Map']\n", + "}, 'WorldCover')\n", + "\n", + "# Import the Hansen Global Forest Change dataset.\n", + "globalForest = ee.Image(\n", + " 'UMD/hansen/global_forest_change_2020_v1_8')\n", + "\n", + "# Create a visualization for tree cover in 2000.\n", + "treeCoverViz = {\n", + " 'bands': ['treecover2000'],\n", + " 'min': 0,\n", + " 'max': 100,\n", + " 'palette': ['black', 'green']\n", + "}\n", + "\n", + "# Add the 2000 tree cover image to the map.\n", + "Map.addLayer(globalForest, treeCoverViz, 'Hansen 2000 Tree Cover')\n", + "\n", + "# Create a visualization for the year of tree loss over the past 20 years.\n", + "treeLossYearViz = {\n", + " 'bands': ['lossyear'],\n", + " 'min': 0,\n", + " 'max': 20,\n", + " 'palette': ['yellow', 'red']\n", + "}\n", + "\n", + "# Add the 2000-2020 tree cover loss image to the map.\n", + "Map.addLayer(globalForest, treeLossYearViz, '2000-2020 Year of Loss')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12f Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12f Checkpoint.js new file mode 100644 index 0000000..a186158 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12f Checkpoint.js @@ -0,0 +1,50 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.2 Survey of Raster Datasets +// Checkpoint: F12f +// Authors: Andréa, Karen, Nick Clinton, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///// +// Pre-classified Land Use Land Cover +///// + +// Import the ESA WorldCover dataset. +var worldCover = ee.ImageCollection('ESA/WorldCover/v100').first(); + +// Center the Map. +Map.centerObject(worldCover, 3); + +// Add the worldCover layer to the map. +Map.addLayer(worldCover, { + bands: ['Map'] +}, 'WorldCover'); + +// Import the Hansen Global Forest Change dataset. +var globalForest = ee.Image( + 'UMD/hansen/global_forest_change_2020_v1_8'); + +// Create a visualization for tree cover in 2000. +var treeCoverViz = { + bands: ['treecover2000'], + min: 0, + max: 100, + palette: ['black', 'green'] +}; + +// Add the 2000 tree cover image to the map. +Map.addLayer(globalForest, treeCoverViz, 'Hansen 2000 Tree Cover'); + +// Create a visualization for the year of tree loss over the past 20 years. +var treeLossYearViz = { + bands: ['lossyear'], + min: 0, + max: 20, + palette: ['yellow', 'red'] +}; + +// Add the 2000-2020 tree cover loss image to the map. +Map.addLayer(globalForest, treeLossYearViz, '2000-2020 Year of Loss'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12f Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12f Checkpoint.py new file mode 100644 index 0000000..a30a8c3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12f Checkpoint.py @@ -0,0 +1,56 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.2 Survey of Raster Datasets +# Checkpoint: F12f +# Authors: Andréa, Karen, Nick Clinton, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##/ +# Pre-classified Land Use Land Cover +##/ + +# Import the ESA WorldCover dataset. +worldCover = ee.ImageCollection('ESA/WorldCover/v100').first() + +# Center the Map. +Map.centerObject(worldCover, 3) + +# Add the worldCover layer to the map. +Map.addLayer(worldCover, { + 'bands': ['Map'] +}, 'WorldCover') + +# Import the Hansen Global Forest Change dataset. +globalForest = ee.Image( + 'UMD/hansen/global_forest_change_2020_v1_8') + +# Create a visualization for tree cover in 2000. +treeCoverViz = { + 'bands': ['treecover2000'], + 'min': 0, + 'max': 100, + 'palette': ['black', 'green'] +} + +# Add the 2000 tree cover image to the map. +Map.addLayer(globalForest, treeCoverViz, 'Hansen 2000 Tree Cover') + +# Create a visualization for the year of tree loss over the past 20 years. +treeLossYearViz = { + 'bands': ['lossyear'], + 'min': 0, + 'max': 20, + 'palette': ['yellow', 'red'] +} + +# Add the 2000-2020 tree cover loss image to the map. +Map.addLayer(globalForest, treeLossYearViz, '2000-2020 Year of Loss') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12g Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12g Checkpoint.ipynb new file mode 100644 index 0000000..195336f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12g Checkpoint.ipynb @@ -0,0 +1,143 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.2 Survey of Raster Datasets\n", + "# Checkpoint: F12g\n", + "# Authors: Andr\u00e9a, Karen, Nick Clinton, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##/\n", + "# Other datasets\n", + "##/\n", + "\n", + "# Import and filter a gridded population dataset.\n", + "griddedPopulation = ee.ImageCollection(\n", + " 'CIESIN/GPWv411/GPW_Population_Count') \\\n", + " .first()\n", + "\n", + "# Predefined palette.\n", + "populationPalette = [\n", + " 'ffffe7',\n", + " '86a192',\n", + " '509791',\n", + " '307296',\n", + " '2c4484',\n", + " '000066'\n", + "]\n", + "\n", + "# Center the Map.\n", + "Map.centerObject(griddedPopulation, 3)\n", + "\n", + "# Add the population data to the map.\n", + "Map.addLayer(griddedPopulation,\n", + " {\n", + " 'min': 0,\n", + " 'max': 1200,\n", + " 'palette': populationPalette\n", + " },\n", + " 'Gridded Population')\n", + "\n", + "# Import the NASA DEM Dataset.\n", + "nasaDEM = ee.Image('NASA/NASADEM_HGT/001')\n", + "\n", + "# Add the elevation layer to the map.\n", + "Map.addLayer(nasaDEM, {\n", + " 'bands': ['elevation'],\n", + " 'min': 0,\n", + " 'max': 3000\n", + "}, 'NASA DEM')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12g Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12g Checkpoint.js new file mode 100644 index 0000000..e07af6e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12g Checkpoint.js @@ -0,0 +1,50 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.2 Survey of Raster Datasets +// Checkpoint: F12g +// Authors: Andréa, Karen, Nick Clinton, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///// +// Other datasets +///// + +// Import and filter a gridded population dataset. +var griddedPopulation = ee.ImageCollection( + 'CIESIN/GPWv411/GPW_Population_Count') + .first(); + +// Predefined palette. +var populationPalette = [ + 'ffffe7', + '86a192', + '509791', + '307296', + '2c4484', + '000066' +]; + +// Center the Map. +Map.centerObject(griddedPopulation, 3); + +// Add the population data to the map. +Map.addLayer(griddedPopulation, + { + min: 0, + max: 1200, + 'palette': populationPalette + }, + 'Gridded Population'); + +// Import the NASA DEM Dataset. +var nasaDEM = ee.Image('NASA/NASADEM_HGT/001'); + +// Add the elevation layer to the map. +Map.addLayer(nasaDEM, { + bands: ['elevation'], + min: 0, + max: 3000 +}, 'NASA DEM'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12g Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12g Checkpoint.py new file mode 100644 index 0000000..4928976 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.2 Survey of Imagery/F12g Checkpoint.py @@ -0,0 +1,56 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.2 Survey of Raster Datasets +# Checkpoint: F12g +# Authors: Andréa, Karen, Nick Clinton, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##/ +# Other datasets +##/ + +# Import and filter a gridded population dataset. +griddedPopulation = ee.ImageCollection( + 'CIESIN/GPWv411/GPW_Population_Count') \ + .first() + +# Predefined palette. +populationPalette = [ + 'ffffe7', + '86a192', + '509791', + '307296', + '2c4484', + '000066' +] + +# Center the Map. +Map.centerObject(griddedPopulation, 3) + +# Add the population data to the map. +Map.addLayer(griddedPopulation, + { + 'min': 0, + 'max': 1200, + 'palette': populationPalette + }, + 'Gridded Population') + +# Import the NASA DEM Dataset. +nasaDEM = ee.Image('NASA/NASADEM_HGT/001') + +# Add the elevation layer to the map. +Map.addLayer(nasaDEM, { + 'bands': ['elevation'], + 'min': 0, + 'max': 3000 +}, 'NASA DEM') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13a Checkpoint.ipynb new file mode 100644 index 0000000..a902be2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13a Checkpoint.ipynb @@ -0,0 +1,198 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "msi = ee.ImageCollection(\"COPERNICUS/S2\"),\n", + " naip = ee.ImageCollection(\"USDA/NAIP/DOQQ\"),\n", + " tm = ee.ImageCollection(\"LANDSAT/LT05/C02/T1\"),\n", + " mod09 = ee.ImageCollection(\"MODIS/061/MOD09A1\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.3 The Remote Sensing Vocabulary\n", + "# Checkpoint: F13a\n", + "# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "###\n", + "# Explore spatial resolution\n", + "###\n", + "\n", + "# Define a region of interest as a point at San Francisco airport.\n", + "sfoPoint = ee.Geometry.Point(-122.3774, 37.6194)\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(sfoPoint, 16)\n", + "\n", + "# MODIS\n", + "# Get an image from your imported MODIS MYD09GA collection.\n", + "modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first()\n", + "\n", + "# Use these MODIS bands for near infrared, red, and green, respectively.\n", + "modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']\n", + "\n", + "# Define visualization parameters for MODIS.\n", + "modisVis = {\n", + " 'bands': modisBands,\n", + " 'min': 0,\n", + " 'max': 3000\n", + "}\n", + "\n", + "# Add the MODIS image to the map.\n", + "Map.addLayer(modisImage, modisVis, 'MODIS')\n", + "\n", + "# Get the scale of the data from the NIR band's projection:\n", + "modisScale = modisImage.select('sur_refl_b02') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('MODIS NIR scale:', modisScale)\n", + "\n", + "# TM\n", + "# Filter TM imagery by location and date.\n", + "\n", + "tmImage = tm \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('1987-03-01', '1987-08-01') \\\n", + " .first()\n", + "\n", + "# Display the TM image as a False color composite.\n", + "Map.addLayer(tmImage, {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 0,\n", + " 'max': 100\n", + "}, 'TM')\n", + "\n", + "# Get the scale of the TM data from its projection:\n", + "tmScale = tmImage.select('B4') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('TM NIR scale:', tmScale)\n", + "\n", + "# MSI\n", + "# Filter MSI imagery by location and date.\n", + "msiImage = msi \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2020-02-01', '2020-04-01') \\\n", + " .first()\n", + "\n", + "# Display the MSI image as a False color composite.\n", + "Map.addLayer(msiImage, {\n", + " 'bands': ['B8', 'B4', 'B3'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + "}, 'MSI')\n", + "\n", + "# Get the scale of the MSI data from its projection:\n", + "msiScale = msiImage.select('B8') \\\n", + " .projection().nominalScale()\n", + "print('MSI scale:', msiScale)\n", + "\n", + "# NAIP\n", + "# Get NAIP images for the study period and region of interest.\n", + "naipImage = naip \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2018-01-01', '2018-12-31') \\\n", + " .first()\n", + "\n", + "# Display the NAIP mosaic as a color-IR composite.\n", + "Map.addLayer(naipImage, {\n", + " 'bands': ['N', 'R', 'G']\n", + "}, 'NAIP')\n", + "\n", + "# Get the NAIP resolution from the first image in the mosaic.\n", + "naipScale = naipImage.select('N') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('NAIP NIR scale:', naipScale)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13a Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13a Checkpoint.js new file mode 100644 index 0000000..e9ba2ed --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13a Checkpoint.js @@ -0,0 +1,105 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.3 The Remote Sensing Vocabulary +// Checkpoint: F13a +// Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +////// +// Explore spatial resolution +////// + +// Define a region of interest as a point at San Francisco airport. +var sfoPoint = ee.Geometry.Point(-122.3774, 37.6194); + +// Center the map at that point. +Map.centerObject(sfoPoint, 16); + +// MODIS +// Get an image from your imported MODIS MYD09GA collection. +var modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first(); + +// Use these MODIS bands for near infrared, red, and green, respectively. +var modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']; + +// Define visualization parameters for MODIS. +var modisVis = { + bands: modisBands, + min: 0, + max: 3000 +}; + +// Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS'); + +// Get the scale of the data from the NIR band's projection: +var modisScale = modisImage.select('sur_refl_b02') + .projection().nominalScale(); + +print('MODIS NIR scale:', modisScale); + +// TM +// Filter TM imagery by location and date. + +var tmImage = tm + .filterBounds(Map.getCenter()) + .filterDate('1987-03-01', '1987-08-01') + .first(); + +// Display the TM image as a false color composite. +Map.addLayer(tmImage, { + bands: ['B4', 'B3', 'B2'], + min: 0, + max: 100 +}, 'TM'); + +// Get the scale of the TM data from its projection: +var tmScale = tmImage.select('B4') + .projection().nominalScale(); + +print('TM NIR scale:', tmScale); + +// MSI +// Filter MSI imagery by location and date. +var msiImage = msi + .filterBounds(Map.getCenter()) + .filterDate('2020-02-01', '2020-04-01') + .first(); + +// Display the MSI image as a false color composite. +Map.addLayer(msiImage, { + bands: ['B8', 'B4', 'B3'], + min: 0, + max: 2000 +}, 'MSI'); + +// Get the scale of the MSI data from its projection: +var msiScale = msiImage.select('B8') + .projection().nominalScale(); +print('MSI scale:', msiScale); + +// NAIP +// Get NAIP images for the study period and region of interest. +var naipImage = naip + .filterBounds(Map.getCenter()) + .filterDate('2018-01-01', '2018-12-31') + .first(); + +// Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + bands: ['N', 'R', 'G'] +}, 'NAIP'); + +// Get the NAIP resolution from the first image in the mosaic. +var naipScale = naipImage.select('N') + .projection().nominalScale(); + +print('NAIP NIR scale:', naipScale); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13a Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13a Checkpoint.py new file mode 100644 index 0000000..da76f15 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13a Checkpoint.py @@ -0,0 +1,111 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.3 The Remote Sensing Vocabulary +# Checkpoint: F13a +# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### +# Explore spatial resolution +### + +# Define a region of interest as a point at San Francisco airport. +sfoPoint = ee.Geometry.Point(-122.3774, 37.6194) + +# Center the map at that point. +Map.centerObject(sfoPoint, 16) + +# MODIS +# Get an image from your imported MODIS MYD09GA collection. +modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first() + +# Use these MODIS bands for near infrared, red, and green, respectively. +modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04'] + +# Define visualization parameters for MODIS. +modisVis = { + 'bands': modisBands, + 'min': 0, + 'max': 3000 +} + +# Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS') + +# Get the scale of the data from the NIR band's projection: +modisScale = modisImage.select('sur_refl_b02') \ + .projection().nominalScale() + +print('MODIS NIR scale:', modisScale) + +# TM +# Filter TM imagery by location and date. + +tmImage = tm \ + .filterBounds(Map.getCenter()) \ + .filterDate('1987-03-01', '1987-08-01') \ + .first() + +# Display the TM image as a False color composite. +Map.addLayer(tmImage, { + 'bands': ['B4', 'B3', 'B2'], + 'min': 0, + 'max': 100 +}, 'TM') + +# Get the scale of the TM data from its projection: +tmScale = tmImage.select('B4') \ + .projection().nominalScale() + +print('TM NIR scale:', tmScale) + +# MSI +# Filter MSI imagery by location and date. +msiImage = msi \ + .filterBounds(Map.getCenter()) \ + .filterDate('2020-02-01', '2020-04-01') \ + .first() + +# Display the MSI image as a False color composite. +Map.addLayer(msiImage, { + 'bands': ['B8', 'B4', 'B3'], + 'min': 0, + 'max': 2000 +}, 'MSI') + +# Get the scale of the MSI data from its projection: +msiScale = msiImage.select('B8') \ + .projection().nominalScale() +print('MSI scale:', msiScale) + +# NAIP +# Get NAIP images for the study period and region of interest. +naipImage = naip \ + .filterBounds(Map.getCenter()) \ + .filterDate('2018-01-01', '2018-12-31') \ + .first() + +# Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + 'bands': ['N', 'R', 'G'] +}, 'NAIP') + +# Get the NAIP resolution from the first image in the mosaic. +naipScale = naipImage.select('N') \ + .projection().nominalScale() + +print('NAIP NIR scale:', naipScale) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13b Checkpoint.ipynb new file mode 100644 index 0000000..7ecb8da --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13b Checkpoint.ipynb @@ -0,0 +1,254 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "msi = ee.ImageCollection(\"COPERNICUS/S2\"),\n", + " naip = ee.ImageCollection(\"USDA/NAIP/DOQQ\"),\n", + " eo1 = ee.ImageCollection(\"EO1/HYPERION\"),\n", + " tm = ee.ImageCollection(\"LANDSAT/LT05/C02/T1\"),\n", + " mod09 = ee.ImageCollection(\"MODIS/061/MOD09A1\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.3 The Remote Sensing Vocabulary\n", + "# Checkpoint: F13b\n", + "# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "###\n", + "# Explore spatial resolution\n", + "###\n", + "\n", + "# Define a region of interest as a point at San Francisco airport.\n", + "sfoPoint = ee.Geometry.Point(-122.3774, 37.6194)\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(sfoPoint, 16)\n", + "\n", + "# MODIS\n", + "# Get an image from your imported MODIS MYD09GA collection.\n", + "modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first()\n", + "\n", + "# Use these MODIS bands for near infrared, red, and green, respectively.\n", + "modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']\n", + "\n", + "# Define visualization parameters for MODIS.\n", + "modisVis = {\n", + " 'bands': modisBands,\n", + " 'min': 0,\n", + " 'max': 3000\n", + "}\n", + "\n", + "# Add the MODIS image to the map.\n", + "Map.addLayer(modisImage, modisVis, 'MODIS')\n", + "\n", + "# Get the scale of the data from the NIR band's projection:\n", + "modisScale = modisImage.select('sur_refl_b02') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('MODIS NIR scale:', modisScale)\n", + "\n", + "# TM\n", + "# Filter TM imagery by location and date.\n", + "\n", + "tmImage = tm \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('1987-03-01', '1987-08-01') \\\n", + " .first()\n", + "\n", + "# Display the TM image as a False color composite.\n", + "Map.addLayer(tmImage, {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 0,\n", + " 'max': 100\n", + "}, 'TM')\n", + "\n", + "# Get the scale of the TM data from its projection:\n", + "tmScale = tmImage.select('B4') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('TM NIR scale:', tmScale)\n", + "\n", + "# MSI\n", + "# Filter MSI imagery by location and date.\n", + "msiImage = msi \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2020-02-01', '2020-04-01') \\\n", + " .first()\n", + "\n", + "# Display the MSI image as a False color composite.\n", + "Map.addLayer(msiImage, {\n", + " 'bands': ['B8', 'B4', 'B3'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + "}, 'MSI')\n", + "\n", + "# Get the scale of the MSI data from its projection:\n", + "msiScale = msiImage.select('B8') \\\n", + " .projection().nominalScale()\n", + "print('MSI scale:', msiScale)\n", + "\n", + "# NAIP\n", + "# Get NAIP images for the study period and region of interest.\n", + "naipImage = naip \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2018-01-01', '2018-12-31') \\\n", + " .first()\n", + "\n", + "# Display the NAIP mosaic as a color-IR composite.\n", + "Map.addLayer(naipImage, {\n", + " 'bands': ['N', 'R', 'G']\n", + "}, 'NAIP')\n", + "\n", + "# Get the NAIP resolution from the first image in the mosaic.\n", + "naipScale = naipImage.select('N') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('NAIP NIR scale:', naipScale)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Explore Temporal Resolution\n", + "##/\n", + "\n", + "# Use Print to see Landsat revisit time\n", + "print('Landsat-5 series:', tm \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('1987-06-01', '1987-09-01'))\n", + "\n", + "# Create a chart to see Landsat 5's 16 day revisit time.\n", + "tmChart = ui.Chart.image.series({\n", + " 'imageCollection': tm.select('B4').filterDate('1987-06-01',\n", + " '1987-09-01'),\n", + " 'region': sfoPoint\n", + "}).setSeriesNames(['NIR'])\n", + "\n", + "# Define a chart style that will let us see the individual dates.\n", + "chartStyle = {\n", + " 'hAxis': {\n", + " 'title': 'Date'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'NIR Mean'\n", + " },\n", + " 'series': {\n", + " '0': {\n", + " 'lineWidth': 3,\n", + " 'pointSize': 6\n", + " }\n", + " },\n", + "}\n", + "\n", + "# Apply custom style properties to the chart.\n", + "tmChart.setOptions(chartStyle)\n", + "\n", + "# Print the chart.\n", + "print('TM Chart', tmChart)\n", + "\n", + "# Sentinel-2 has a 5 day revisit time.\n", + "msiChart = ui.Chart.image.series({\n", + " 'imageCollection': msi.select('B8').filterDate('2020-06-01',\n", + " '2020-09-01'),\n", + " 'region': sfoPoint\n", + "}).setSeriesNames(['NIR'])\n", + "\n", + "# Apply the previously defined custom style properties to the chart.\n", + "msiChart.setOptions(chartStyle)\n", + "\n", + "# Print the chart.\n", + "print('MSI Chart', msiChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13b Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13b Checkpoint.js new file mode 100644 index 0000000..555678a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13b Checkpoint.js @@ -0,0 +1,162 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + eo1 = ee.ImageCollection("EO1/HYPERION"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.3 The Remote Sensing Vocabulary +// Checkpoint: F13b +// Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +////// +// Explore spatial resolution +////// + +// Define a region of interest as a point at San Francisco airport. +var sfoPoint = ee.Geometry.Point(-122.3774, 37.6194); + +// Center the map at that point. +Map.centerObject(sfoPoint, 16); + +// MODIS +// Get an image from your imported MODIS MYD09GA collection. +var modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first(); + +// Use these MODIS bands for near infrared, red, and green, respectively. +var modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']; + +// Define visualization parameters for MODIS. +var modisVis = { + bands: modisBands, + min: 0, + max: 3000 +}; + +// Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS'); + +// Get the scale of the data from the NIR band's projection: +var modisScale = modisImage.select('sur_refl_b02') + .projection().nominalScale(); + +print('MODIS NIR scale:', modisScale); + +// TM +// Filter TM imagery by location and date. + +var tmImage = tm + .filterBounds(Map.getCenter()) + .filterDate('1987-03-01', '1987-08-01') + .first(); + +// Display the TM image as a false color composite. +Map.addLayer(tmImage, { + bands: ['B4', 'B3', 'B2'], + min: 0, + max: 100 +}, 'TM'); + +// Get the scale of the TM data from its projection: +var tmScale = tmImage.select('B4') + .projection().nominalScale(); + +print('TM NIR scale:', tmScale); + +// MSI +// Filter MSI imagery by location and date. +var msiImage = msi + .filterBounds(Map.getCenter()) + .filterDate('2020-02-01', '2020-04-01') + .first(); + +// Display the MSI image as a false color composite. +Map.addLayer(msiImage, { + bands: ['B8', 'B4', 'B3'], + min: 0, + max: 2000 +}, 'MSI'); + +// Get the scale of the MSI data from its projection: +var msiScale = msiImage.select('B8') + .projection().nominalScale(); +print('MSI scale:', msiScale); + +// NAIP +// Get NAIP images for the study period and region of interest. +var naipImage = naip + .filterBounds(Map.getCenter()) + .filterDate('2018-01-01', '2018-12-31') + .first(); + +// Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + bands: ['N', 'R', 'G'] +}, 'NAIP'); + +// Get the NAIP resolution from the first image in the mosaic. +var naipScale = naipImage.select('N') + .projection().nominalScale(); + +print('NAIP NIR scale:', naipScale); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Explore Temporal Resolution +///// + +// Use Print to see Landsat revisit time +print('Landsat-5 series:', tm + .filterBounds(Map.getCenter()) + .filterDate('1987-06-01', '1987-09-01')); + +// Create a chart to see Landsat 5's 16 day revisit time. +var tmChart = ui.Chart.image.series({ + imageCollection: tm.select('B4').filterDate('1987-06-01', + '1987-09-01'), + region: sfoPoint +}).setSeriesNames(['NIR']); + +// Define a chart style that will let us see the individual dates. +var chartStyle = { + hAxis: { + title: 'Date' + }, + vAxis: { + title: 'NIR Mean' + }, + series: { + 0: { + lineWidth: 3, + pointSize: 6 + } + }, +}; + +// Apply custom style properties to the chart. +tmChart.setOptions(chartStyle); + +// Print the chart. +print('TM Chart', tmChart); + +// Sentinel-2 has a 5 day revisit time. +var msiChart = ui.Chart.image.series({ + imageCollection: msi.select('B8').filterDate('2020-06-01', + '2020-09-01'), + region: sfoPoint +}).setSeriesNames(['NIR']); + +// Apply the previously defined custom style properties to the chart. +msiChart.setOptions(chartStyle); + +// Print the chart. +print('MSI Chart', msiChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13b Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13b Checkpoint.py new file mode 100644 index 0000000..388e52d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13b Checkpoint.py @@ -0,0 +1,168 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + eo1 = ee.ImageCollection("EO1/HYPERION"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.3 The Remote Sensing Vocabulary +# Checkpoint: F13b +# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### +# Explore spatial resolution +### + +# Define a region of interest as a point at San Francisco airport. +sfoPoint = ee.Geometry.Point(-122.3774, 37.6194) + +# Center the map at that point. +Map.centerObject(sfoPoint, 16) + +# MODIS +# Get an image from your imported MODIS MYD09GA collection. +modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first() + +# Use these MODIS bands for near infrared, red, and green, respectively. +modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04'] + +# Define visualization parameters for MODIS. +modisVis = { + 'bands': modisBands, + 'min': 0, + 'max': 3000 +} + +# Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS') + +# Get the scale of the data from the NIR band's projection: +modisScale = modisImage.select('sur_refl_b02') \ + .projection().nominalScale() + +print('MODIS NIR scale:', modisScale) + +# TM +# Filter TM imagery by location and date. + +tmImage = tm \ + .filterBounds(Map.getCenter()) \ + .filterDate('1987-03-01', '1987-08-01') \ + .first() + +# Display the TM image as a False color composite. +Map.addLayer(tmImage, { + 'bands': ['B4', 'B3', 'B2'], + 'min': 0, + 'max': 100 +}, 'TM') + +# Get the scale of the TM data from its projection: +tmScale = tmImage.select('B4') \ + .projection().nominalScale() + +print('TM NIR scale:', tmScale) + +# MSI +# Filter MSI imagery by location and date. +msiImage = msi \ + .filterBounds(Map.getCenter()) \ + .filterDate('2020-02-01', '2020-04-01') \ + .first() + +# Display the MSI image as a False color composite. +Map.addLayer(msiImage, { + 'bands': ['B8', 'B4', 'B3'], + 'min': 0, + 'max': 2000 +}, 'MSI') + +# Get the scale of the MSI data from its projection: +msiScale = msiImage.select('B8') \ + .projection().nominalScale() +print('MSI scale:', msiScale) + +# NAIP +# Get NAIP images for the study period and region of interest. +naipImage = naip \ + .filterBounds(Map.getCenter()) \ + .filterDate('2018-01-01', '2018-12-31') \ + .first() + +# Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + 'bands': ['N', 'R', 'G'] +}, 'NAIP') + +# Get the NAIP resolution from the first image in the mosaic. +naipScale = naipImage.select('N') \ + .projection().nominalScale() + +print('NAIP NIR scale:', naipScale) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Explore Temporal Resolution +##/ + +# Use Print to see Landsat revisit time +print('Landsat-5 series:', tm \ + .filterBounds(Map.getCenter()) \ + .filterDate('1987-06-01', '1987-09-01')) + +# Create a chart to see Landsat 5's 16 day revisit time. +tmChart = ui.Chart.image.series({ + 'imageCollection': tm.select('B4').filterDate('1987-06-01', + '1987-09-01'), + 'region': sfoPoint +}).setSeriesNames(['NIR']) + +# Define a chart style that will let us see the individual dates. +chartStyle = { + 'hAxis': { + 'title': 'Date' + }, + 'vAxis': { + 'title': 'NIR Mean' + }, + 'series': { + '0': { + 'lineWidth': 3, + 'pointSize': 6 + } + }, +} + +# Apply custom style properties to the chart. +tmChart.setOptions(chartStyle) + +# Print the chart. +print('TM Chart', tmChart) + +# Sentinel-2 has a 5 day revisit time. +msiChart = ui.Chart.image.series({ + 'imageCollection': msi.select('B8').filterDate('2020-06-01', + '2020-09-01'), + 'region': sfoPoint +}).setSeriesNames(['NIR']) + +# Apply the previously defined custom style properties to the chart. +msiChart.setOptions(chartStyle) + +# Print the chart. +print('MSI Chart', msiChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13c Checkpoint.ipynb new file mode 100644 index 0000000..89426b8 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13c Checkpoint.ipynb @@ -0,0 +1,349 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "msi = ee.ImageCollection(\"COPERNICUS/S2\"),\n", + " naip = ee.ImageCollection(\"USDA/NAIP/DOQQ\"),\n", + " eo1 = ee.ImageCollection(\"EO1/HYPERION\"),\n", + " tm = ee.ImageCollection(\"LANDSAT/LT05/C02/T1\"),\n", + " mod09 = ee.ImageCollection(\"MODIS/061/MOD09A1\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.3 The Remote Sensing Vocabulary\n", + "# Checkpoint: F13c\n", + "# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "###\n", + "# Explore spatial resolution\n", + "###\n", + "\n", + "# Define a region of interest as a point at San Francisco airport.\n", + "sfoPoint = ee.Geometry.Point(-122.3774, 37.6194)\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(sfoPoint, 16)\n", + "\n", + "# MODIS\n", + "# Get an image from your imported MODIS MYD09GA collection.\n", + "modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first()\n", + "\n", + "# Use these MODIS bands for near infrared, red, and green, respectively.\n", + "modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']\n", + "\n", + "# Define visualization parameters for MODIS.\n", + "modisVis = {\n", + " 'bands': modisBands,\n", + " 'min': 0,\n", + " 'max': 3000\n", + "}\n", + "\n", + "# Add the MODIS image to the map.\n", + "Map.addLayer(modisImage, modisVis, 'MODIS')\n", + "\n", + "# Get the scale of the data from the NIR band's projection:\n", + "modisScale = modisImage.select('sur_refl_b02') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('MODIS NIR scale:', modisScale)\n", + "\n", + "# TM\n", + "# Filter TM imagery by location and date.\n", + "\n", + "tmImage = tm \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('1987-03-01', '1987-08-01') \\\n", + " .first()\n", + "\n", + "# Display the TM image as a False color composite.\n", + "Map.addLayer(tmImage, {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 0,\n", + " 'max': 100\n", + "}, 'TM')\n", + "\n", + "# Get the scale of the TM data from its projection:\n", + "tmScale = tmImage.select('B4') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('TM NIR scale:', tmScale)\n", + "\n", + "# MSI\n", + "# Filter MSI imagery by location and date.\n", + "msiImage = msi \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2020-02-01', '2020-04-01') \\\n", + " .first()\n", + "\n", + "# Display the MSI image as a False color composite.\n", + "Map.addLayer(msiImage, {\n", + " 'bands': ['B8', 'B4', 'B3'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + "}, 'MSI')\n", + "\n", + "# Get the scale of the MSI data from its projection:\n", + "msiScale = msiImage.select('B8') \\\n", + " .projection().nominalScale()\n", + "print('MSI scale:', msiScale)\n", + "\n", + "# NAIP\n", + "# Get NAIP images for the study period and region of interest.\n", + "naipImage = naip \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2018-01-01', '2018-12-31') \\\n", + " .first()\n", + "\n", + "# Display the NAIP mosaic as a color-IR composite.\n", + "Map.addLayer(naipImage, {\n", + " 'bands': ['N', 'R', 'G']\n", + "}, 'NAIP')\n", + "\n", + "# Get the NAIP resolution from the first image in the mosaic.\n", + "naipScale = naipImage.select('N') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('NAIP NIR scale:', naipScale)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Explore Temporal Resolution\n", + "##/\n", + "\n", + "# Use Print to see Landsat revisit time\n", + "print('Landsat-5 series:', tm \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('1987-06-01', '1987-09-01'))\n", + "\n", + "# Create a chart to see Landsat 5's 16 day revisit time.\n", + "tmChart = ui.Chart.image.series({\n", + " 'imageCollection': tm.select('B4').filterDate('1987-06-01',\n", + " '1987-09-01'),\n", + " 'region': sfoPoint\n", + "}).setSeriesNames(['NIR'])\n", + "\n", + "# Define a chart style that will let us see the individual dates.\n", + "chartStyle = {\n", + " 'hAxis': {\n", + " 'title': 'Date'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'NIR Mean'\n", + " },\n", + " 'series': {\n", + " '0': {\n", + " 'lineWidth': 3,\n", + " 'pointSize': 6\n", + " }\n", + " },\n", + "}\n", + "\n", + "# Apply custom style properties to the chart.\n", + "tmChart.setOptions(chartStyle)\n", + "\n", + "# Print the chart.\n", + "print('TM Chart', tmChart)\n", + "\n", + "# Sentinel-2 has a 5 day revisit time.\n", + "msiChart = ui.Chart.image.series({\n", + " 'imageCollection': msi.select('B8').filterDate('2020-06-01',\n", + " '2020-09-01'),\n", + " 'region': sfoPoint\n", + "}).setSeriesNames(['NIR'])\n", + "\n", + "# Apply the previously defined custom style properties to the chart.\n", + "msiChart.setOptions(chartStyle)\n", + "\n", + "# Print the chart.\n", + "print('MSI Chart', msiChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Explore spectral resolution\n", + "##/\n", + "\n", + "# Get the MODIS band names as an ee.List\n", + "modisBands = modisImage.bandNames()\n", + "\n", + "# Print the list.\n", + "print('MODIS bands:', modisBands)\n", + "\n", + "# Print the length of the list.\n", + "print('Length of the bands list:', modisBands.length())\n", + "\n", + "# Graph the MODIS spectral bands (bands 11-17).\n", + "\n", + "# Select only the reflectance bands of interest.\n", + "reflectanceImage = modisImage.select(\n", + " 'sur_refl_b01',\n", + " 'sur_refl_b02',\n", + " 'sur_refl_b03',\n", + " 'sur_refl_b04',\n", + " 'sur_refl_b05',\n", + " 'sur_refl_b06',\n", + " 'sur_refl_b07'\n", + ")\n", + "\n", + "# Define an object of customization parameters for the chart.\n", + "options = {\n", + " 'title': 'MODIS spectrum at SFO',\n", + " 'hAxis': {\n", + " 'title': 'Band'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Reflectance'\n", + " },\n", + " 'legend': {\n", + " 'position': 'none'\n", + " },\n", + " 'pointSize': 3\n", + "}\n", + "\n", + "# Make the chart.\n", + "modisReflectanceChart = ui.Chart.image.regions({\n", + " 'image': reflectanceImage,\n", + " 'regions': sfoPoint\n", + "}).setOptions(options)\n", + "\n", + "# Display the chart.\n", + "print(modisReflectanceChart)\n", + "\n", + "# Get the EO-1 band names as a ee.List\n", + "eo1Image = eo1 \\\n", + " .filterDate('2015-01-01', '2016-01-01') \\\n", + " .first()\n", + "\n", + "# Extract the EO-1 band names.\n", + "eo1Bands = eo1Image.bandNames()\n", + "\n", + "# Print the list of band names.\n", + "print('EO-1 bands:', eo1Bands)\n", + "\n", + "# Create an options object for our chart.\n", + "optionsEO1 = {\n", + " 'title': 'EO1 spectrum',\n", + " 'hAxis': {\n", + " 'title': 'Band'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Reflectance'\n", + " },\n", + " 'legend': {\n", + " 'position': 'none'\n", + " },\n", + " 'pointSize': 3\n", + "}\n", + "\n", + "# Make the chart and set the options.\n", + "eo1Chart = ui.Chart.image.regions({\n", + " 'image': eo1Image,\n", + " 'regions': ee.Geometry.Point([6.10, 81.12])\n", + "}).setOptions(optionsEO1)\n", + "\n", + "# Display the chart.\n", + "print(eo1Chart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13c Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13c Checkpoint.js new file mode 100644 index 0000000..30160ed --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13c Checkpoint.js @@ -0,0 +1,257 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + eo1 = ee.ImageCollection("EO1/HYPERION"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.3 The Remote Sensing Vocabulary +// Checkpoint: F13c +// Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +////// +// Explore spatial resolution +////// + +// Define a region of interest as a point at San Francisco airport. +var sfoPoint = ee.Geometry.Point(-122.3774, 37.6194); + +// Center the map at that point. +Map.centerObject(sfoPoint, 16); + +// MODIS +// Get an image from your imported MODIS MYD09GA collection. +var modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first(); + +// Use these MODIS bands for near infrared, red, and green, respectively. +var modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']; + +// Define visualization parameters for MODIS. +var modisVis = { + bands: modisBands, + min: 0, + max: 3000 +}; + +// Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS'); + +// Get the scale of the data from the NIR band's projection: +var modisScale = modisImage.select('sur_refl_b02') + .projection().nominalScale(); + +print('MODIS NIR scale:', modisScale); + +// TM +// Filter TM imagery by location and date. + +var tmImage = tm + .filterBounds(Map.getCenter()) + .filterDate('1987-03-01', '1987-08-01') + .first(); + +// Display the TM image as a false color composite. +Map.addLayer(tmImage, { + bands: ['B4', 'B3', 'B2'], + min: 0, + max: 100 +}, 'TM'); + +// Get the scale of the TM data from its projection: +var tmScale = tmImage.select('B4') + .projection().nominalScale(); + +print('TM NIR scale:', tmScale); + +// MSI +// Filter MSI imagery by location and date. +var msiImage = msi + .filterBounds(Map.getCenter()) + .filterDate('2020-02-01', '2020-04-01') + .first(); + +// Display the MSI image as a false color composite. +Map.addLayer(msiImage, { + bands: ['B8', 'B4', 'B3'], + min: 0, + max: 2000 +}, 'MSI'); + +// Get the scale of the MSI data from its projection: +var msiScale = msiImage.select('B8') + .projection().nominalScale(); +print('MSI scale:', msiScale); + +// NAIP +// Get NAIP images for the study period and region of interest. +var naipImage = naip + .filterBounds(Map.getCenter()) + .filterDate('2018-01-01', '2018-12-31') + .first(); + +// Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + bands: ['N', 'R', 'G'] +}, 'NAIP'); + +// Get the NAIP resolution from the first image in the mosaic. +var naipScale = naipImage.select('N') + .projection().nominalScale(); + +print('NAIP NIR scale:', naipScale); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Explore Temporal Resolution +///// + +// Use Print to see Landsat revisit time +print('Landsat-5 series:', tm + .filterBounds(Map.getCenter()) + .filterDate('1987-06-01', '1987-09-01')); + +// Create a chart to see Landsat 5's 16 day revisit time. +var tmChart = ui.Chart.image.series({ + imageCollection: tm.select('B4').filterDate('1987-06-01', + '1987-09-01'), + region: sfoPoint +}).setSeriesNames(['NIR']); + +// Define a chart style that will let us see the individual dates. +var chartStyle = { + hAxis: { + title: 'Date' + }, + vAxis: { + title: 'NIR Mean' + }, + series: { + 0: { + lineWidth: 3, + pointSize: 6 + } + }, +}; + +// Apply custom style properties to the chart. +tmChart.setOptions(chartStyle); + +// Print the chart. +print('TM Chart', tmChart); + +// Sentinel-2 has a 5 day revisit time. +var msiChart = ui.Chart.image.series({ + imageCollection: msi.select('B8').filterDate('2020-06-01', + '2020-09-01'), + region: sfoPoint +}).setSeriesNames(['NIR']); + +// Apply the previously defined custom style properties to the chart. +msiChart.setOptions(chartStyle); + +// Print the chart. +print('MSI Chart', msiChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Explore spectral resolution +///// + +// Get the MODIS band names as an ee.List +var modisBands = modisImage.bandNames(); + +// Print the list. +print('MODIS bands:', modisBands); + +// Print the length of the list. +print('Length of the bands list:', modisBands.length()); + +// Graph the MODIS spectral bands (bands 11-17). + +// Select only the reflectance bands of interest. +var reflectanceImage = modisImage.select( + 'sur_refl_b01', + 'sur_refl_b02', + 'sur_refl_b03', + 'sur_refl_b04', + 'sur_refl_b05', + 'sur_refl_b06', + 'sur_refl_b07' +); + +// Define an object of customization parameters for the chart. +var options = { + title: 'MODIS spectrum at SFO', + hAxis: { + title: 'Band' + }, + vAxis: { + title: 'Reflectance' + }, + legend: { + position: 'none' + }, + pointSize: 3 +}; + +// Make the chart. +var modisReflectanceChart = ui.Chart.image.regions({ + image: reflectanceImage, + regions: sfoPoint +}).setOptions(options); + +// Display the chart. +print(modisReflectanceChart); + +// Get the EO-1 band names as a ee.List +var eo1Image = eo1 + .filterDate('2015-01-01', '2016-01-01') + .first(); + +// Extract the EO-1 band names. +var eo1Bands = eo1Image.bandNames(); + +// Print the list of band names. +print('EO-1 bands:', eo1Bands); + +// Create an options object for our chart. +var optionsEO1 = { + title: 'EO1 spectrum', + hAxis: { + title: 'Band' + }, + vAxis: { + title: 'Reflectance' + }, + legend: { + position: 'none' + }, + pointSize: 3 +}; + +// Make the chart and set the options. +var eo1Chart = ui.Chart.image.regions({ + image: eo1Image, + regions: ee.Geometry.Point([6.10, 81.12]) +}).setOptions(optionsEO1); + +// Display the chart. +print(eo1Chart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + + + + + diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13c Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13c Checkpoint.py new file mode 100644 index 0000000..f23000f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13c Checkpoint.py @@ -0,0 +1,263 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + eo1 = ee.ImageCollection("EO1/HYPERION"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.3 The Remote Sensing Vocabulary +# Checkpoint: F13c +# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### +# Explore spatial resolution +### + +# Define a region of interest as a point at San Francisco airport. +sfoPoint = ee.Geometry.Point(-122.3774, 37.6194) + +# Center the map at that point. +Map.centerObject(sfoPoint, 16) + +# MODIS +# Get an image from your imported MODIS MYD09GA collection. +modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first() + +# Use these MODIS bands for near infrared, red, and green, respectively. +modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04'] + +# Define visualization parameters for MODIS. +modisVis = { + 'bands': modisBands, + 'min': 0, + 'max': 3000 +} + +# Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS') + +# Get the scale of the data from the NIR band's projection: +modisScale = modisImage.select('sur_refl_b02') \ + .projection().nominalScale() + +print('MODIS NIR scale:', modisScale) + +# TM +# Filter TM imagery by location and date. + +tmImage = tm \ + .filterBounds(Map.getCenter()) \ + .filterDate('1987-03-01', '1987-08-01') \ + .first() + +# Display the TM image as a False color composite. +Map.addLayer(tmImage, { + 'bands': ['B4', 'B3', 'B2'], + 'min': 0, + 'max': 100 +}, 'TM') + +# Get the scale of the TM data from its projection: +tmScale = tmImage.select('B4') \ + .projection().nominalScale() + +print('TM NIR scale:', tmScale) + +# MSI +# Filter MSI imagery by location and date. +msiImage = msi \ + .filterBounds(Map.getCenter()) \ + .filterDate('2020-02-01', '2020-04-01') \ + .first() + +# Display the MSI image as a False color composite. +Map.addLayer(msiImage, { + 'bands': ['B8', 'B4', 'B3'], + 'min': 0, + 'max': 2000 +}, 'MSI') + +# Get the scale of the MSI data from its projection: +msiScale = msiImage.select('B8') \ + .projection().nominalScale() +print('MSI scale:', msiScale) + +# NAIP +# Get NAIP images for the study period and region of interest. +naipImage = naip \ + .filterBounds(Map.getCenter()) \ + .filterDate('2018-01-01', '2018-12-31') \ + .first() + +# Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + 'bands': ['N', 'R', 'G'] +}, 'NAIP') + +# Get the NAIP resolution from the first image in the mosaic. +naipScale = naipImage.select('N') \ + .projection().nominalScale() + +print('NAIP NIR scale:', naipScale) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Explore Temporal Resolution +##/ + +# Use Print to see Landsat revisit time +print('Landsat-5 series:', tm \ + .filterBounds(Map.getCenter()) \ + .filterDate('1987-06-01', '1987-09-01')) + +# Create a chart to see Landsat 5's 16 day revisit time. +tmChart = ui.Chart.image.series({ + 'imageCollection': tm.select('B4').filterDate('1987-06-01', + '1987-09-01'), + 'region': sfoPoint +}).setSeriesNames(['NIR']) + +# Define a chart style that will let us see the individual dates. +chartStyle = { + 'hAxis': { + 'title': 'Date' + }, + 'vAxis': { + 'title': 'NIR Mean' + }, + 'series': { + '0': { + 'lineWidth': 3, + 'pointSize': 6 + } + }, +} + +# Apply custom style properties to the chart. +tmChart.setOptions(chartStyle) + +# Print the chart. +print('TM Chart', tmChart) + +# Sentinel-2 has a 5 day revisit time. +msiChart = ui.Chart.image.series({ + 'imageCollection': msi.select('B8').filterDate('2020-06-01', + '2020-09-01'), + 'region': sfoPoint +}).setSeriesNames(['NIR']) + +# Apply the previously defined custom style properties to the chart. +msiChart.setOptions(chartStyle) + +# Print the chart. +print('MSI Chart', msiChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Explore spectral resolution +##/ + +# Get the MODIS band names as an ee.List +modisBands = modisImage.bandNames() + +# Print the list. +print('MODIS bands:', modisBands) + +# Print the length of the list. +print('Length of the bands list:', modisBands.length()) + +# Graph the MODIS spectral bands (bands 11-17). + +# Select only the reflectance bands of interest. +reflectanceImage = modisImage.select( + 'sur_refl_b01', + 'sur_refl_b02', + 'sur_refl_b03', + 'sur_refl_b04', + 'sur_refl_b05', + 'sur_refl_b06', + 'sur_refl_b07' +) + +# Define an object of customization parameters for the chart. +options = { + 'title': 'MODIS spectrum at SFO', + 'hAxis': { + 'title': 'Band' + }, + 'vAxis': { + 'title': 'Reflectance' + }, + 'legend': { + 'position': 'none' + }, + 'pointSize': 3 +} + +# Make the chart. +modisReflectanceChart = ui.Chart.image.regions({ + 'image': reflectanceImage, + 'regions': sfoPoint +}).setOptions(options) + +# Display the chart. +print(modisReflectanceChart) + +# Get the EO-1 band names as a ee.List +eo1Image = eo1 \ + .filterDate('2015-01-01', '2016-01-01') \ + .first() + +# Extract the EO-1 band names. +eo1Bands = eo1Image.bandNames() + +# Print the list of band names. +print('EO-1 bands:', eo1Bands) + +# Create an options object for our chart. +optionsEO1 = { + 'title': 'EO1 spectrum', + 'hAxis': { + 'title': 'Band' + }, + 'vAxis': { + 'title': 'Reflectance' + }, + 'legend': { + 'position': 'none' + }, + 'pointSize': 3 +} + +# Make the chart and set the options. +eo1Chart = ui.Chart.image.regions({ + 'image': eo1Image, + 'regions': ee.Geometry.Point([6.10, 81.12]) +}).setOptions(optionsEO1) + +# Display the chart. +print(eo1Chart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + + + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13d Checkpoint.ipynb new file mode 100644 index 0000000..e59fe4c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13d Checkpoint.ipynb @@ -0,0 +1,374 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "msi = ee.ImageCollection(\"COPERNICUS/S2\"),\n", + " naip = ee.ImageCollection(\"USDA/NAIP/DOQQ\"),\n", + " eo1 = ee.ImageCollection(\"EO1/HYPERION\"),\n", + " tm = ee.ImageCollection(\"LANDSAT/LT05/C02/T1\"),\n", + " mod09 = ee.ImageCollection(\"MODIS/061/MOD09A1\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.3 The Remote Sensing Vocabulary\n", + "# Checkpoint: F13d\n", + "# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "###\n", + "# Explore spatial resolution\n", + "###\n", + "\n", + "# Define a region of interest as a point at San Francisco airport.\n", + "sfoPoint = ee.Geometry.Point(-122.3774, 37.6194)\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(sfoPoint, 16)\n", + "\n", + "# MODIS\n", + "# Get an image from your imported MODIS MYD09GA collection.\n", + "modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first()\n", + "\n", + "# Use these MODIS bands for near infrared, red, and green, respectively.\n", + "modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']\n", + "\n", + "# Define visualization parameters for MODIS.\n", + "modisVis = {\n", + " 'bands': modisBands,\n", + " 'min': 0,\n", + " 'max': 3000\n", + "}\n", + "\n", + "# Add the MODIS image to the map.\n", + "Map.addLayer(modisImage, modisVis, 'MODIS')\n", + "\n", + "# Get the scale of the data from the NIR band's projection:\n", + "modisScale = modisImage.select('sur_refl_b02') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('MODIS NIR scale:', modisScale)\n", + "\n", + "# TM\n", + "# Filter TM imagery by location and date.\n", + "\n", + "tmImage = tm \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('1987-03-01', '1987-08-01') \\\n", + " .first()\n", + "\n", + "# Display the TM image as a False color composite.\n", + "Map.addLayer(tmImage, {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 0,\n", + " 'max': 100\n", + "}, 'TM')\n", + "\n", + "# Get the scale of the TM data from its projection:\n", + "tmScale = tmImage.select('B4') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('TM NIR scale:', tmScale)\n", + "\n", + "# MSI\n", + "# Filter MSI imagery by location and date.\n", + "msiImage = msi \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2020-02-01', '2020-04-01') \\\n", + " .first()\n", + "\n", + "# Display the MSI image as a False color composite.\n", + "Map.addLayer(msiImage, {\n", + " 'bands': ['B8', 'B4', 'B3'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + "}, 'MSI')\n", + "\n", + "# Get the scale of the MSI data from its projection:\n", + "msiScale = msiImage.select('B8') \\\n", + " .projection().nominalScale()\n", + "print('MSI scale:', msiScale)\n", + "\n", + "# NAIP\n", + "# Get NAIP images for the study period and region of interest.\n", + "naipImage = naip \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2018-01-01', '2018-12-31') \\\n", + " .first()\n", + "\n", + "# Display the NAIP mosaic as a color-IR composite.\n", + "Map.addLayer(naipImage, {\n", + " 'bands': ['N', 'R', 'G']\n", + "}, 'NAIP')\n", + "\n", + "# Get the NAIP resolution from the first image in the mosaic.\n", + "naipScale = naipImage.select('N') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('NAIP NIR scale:', naipScale)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Explore Temporal Resolution\n", + "##/\n", + "\n", + "# Use Print to see Landsat revisit time\n", + "print('Landsat-5 series:', tm \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('1987-06-01', '1987-09-01'))\n", + "\n", + "# Create a chart to see Landsat 5's 16 day revisit time.\n", + "tmChart = ui.Chart.image.series({\n", + " 'imageCollection': tm.select('B4').filterDate('1987-06-01',\n", + " '1987-09-01'),\n", + " 'region': sfoPoint\n", + "}).setSeriesNames(['NIR'])\n", + "\n", + "# Define a chart style that will let us see the individual dates.\n", + "chartStyle = {\n", + " 'hAxis': {\n", + " 'title': 'Date'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'NIR Mean'\n", + " },\n", + " 'series': {\n", + " '0': {\n", + " 'lineWidth': 3,\n", + " 'pointSize': 6\n", + " }\n", + " },\n", + "}\n", + "\n", + "# Apply custom style properties to the chart.\n", + "tmChart.setOptions(chartStyle)\n", + "\n", + "# Print the chart.\n", + "print('TM Chart', tmChart)\n", + "\n", + "# Sentinel-2 has a 5 day revisit time.\n", + "msiChart = ui.Chart.image.series({\n", + " 'imageCollection': msi.select('B8').filterDate('2020-06-01',\n", + " '2020-09-01'),\n", + " 'region': sfoPoint\n", + "}).setSeriesNames(['NIR'])\n", + "\n", + "# Apply the previously defined custom style properties to the chart.\n", + "msiChart.setOptions(chartStyle)\n", + "\n", + "# Print the chart.\n", + "print('MSI Chart', msiChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Explore spectral resolution\n", + "##/\n", + "\n", + "# Get the MODIS band names as an ee.List\n", + "modisBands = modisImage.bandNames()\n", + "\n", + "# Print the list.\n", + "print('MODIS bands:', modisBands)\n", + "\n", + "# Print the length of the list.\n", + "print('Length of the bands list:', modisBands.length())\n", + "\n", + "# Graph the MODIS spectral bands (bands 11-17).\n", + "\n", + "# Select only the reflectance bands of interest.\n", + "reflectanceImage = modisImage.select(\n", + " 'sur_refl_b01',\n", + " 'sur_refl_b02',\n", + " 'sur_refl_b03',\n", + " 'sur_refl_b04',\n", + " 'sur_refl_b05',\n", + " 'sur_refl_b06',\n", + " 'sur_refl_b07'\n", + ")\n", + "\n", + "# Define an object of customization parameters for the chart.\n", + "options = {\n", + " 'title': 'MODIS spectrum at SFO',\n", + " 'hAxis': {\n", + " 'title': 'Band'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Reflectance'\n", + " },\n", + " 'legend': {\n", + " 'position': 'none'\n", + " },\n", + " 'pointSize': 3\n", + "}\n", + "\n", + "# Make the chart.\n", + "modisReflectanceChart = ui.Chart.image.regions({\n", + " 'image': reflectanceImage,\n", + " 'regions': sfoPoint\n", + "}).setOptions(options)\n", + "\n", + "# Display the chart.\n", + "print(modisReflectanceChart)\n", + "\n", + "# Get the EO-1 band names as a ee.List\n", + "eo1Image = eo1 \\\n", + " .filterDate('2015-01-01', '2016-01-01') \\\n", + " .first()\n", + "\n", + "# Extract the EO-1 band names.\n", + "eo1Bands = eo1Image.bandNames()\n", + "\n", + "# Print the list of band names.\n", + "print('EO-1 bands:', eo1Bands)\n", + "\n", + "# Create an options object for our chart.\n", + "optionsEO1 = {\n", + " 'title': 'EO1 spectrum',\n", + " 'hAxis': {\n", + " 'title': 'Band'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Reflectance'\n", + " },\n", + " 'legend': {\n", + " 'position': 'none'\n", + " },\n", + " 'pointSize': 3\n", + "}\n", + "\n", + "# Make the chart and set the options.\n", + "eo1Chart = ui.Chart.image.regions({\n", + " 'image': eo1Image,\n", + " 'regions': ee.Geometry.Point([6.10, 81.12])\n", + "}).setOptions(optionsEO1)\n", + "\n", + "# Display the chart.\n", + "print(eo1Chart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Examine pixel quality\n", + "##/\n", + "\n", + "# Sentinel Quality Visualization.\n", + "msiCloud = msi \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2019-12-31', '2020-02-01') \\\n", + " .first()\n", + "\n", + "# Display the MSI image as a False color composite.\n", + "Map.addLayer(msiCloud,\n", + " {\n", + " 'bands': ['B8', 'B4', 'B3'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + " },\n", + " 'MSI Quality Image')\n", + "\n", + "Map.addLayer(msiCloud,\n", + " {\n", + " 'bands': ['QA60'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + " },\n", + " 'Sentinel Quality Visualization')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13d Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13d Checkpoint.js new file mode 100644 index 0000000..91cecbf --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13d Checkpoint.js @@ -0,0 +1,281 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + eo1 = ee.ImageCollection("EO1/HYPERION"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.3 The Remote Sensing Vocabulary +// Checkpoint: F13d +// Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +////// +// Explore spatial resolution +////// + +// Define a region of interest as a point at San Francisco airport. +var sfoPoint = ee.Geometry.Point(-122.3774, 37.6194); + +// Center the map at that point. +Map.centerObject(sfoPoint, 16); + +// MODIS +// Get an image from your imported MODIS MYD09GA collection. +var modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first(); + +// Use these MODIS bands for near infrared, red, and green, respectively. +var modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']; + +// Define visualization parameters for MODIS. +var modisVis = { + bands: modisBands, + min: 0, + max: 3000 +}; + +// Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS'); + +// Get the scale of the data from the NIR band's projection: +var modisScale = modisImage.select('sur_refl_b02') + .projection().nominalScale(); + +print('MODIS NIR scale:', modisScale); + +// TM +// Filter TM imagery by location and date. + +var tmImage = tm + .filterBounds(Map.getCenter()) + .filterDate('1987-03-01', '1987-08-01') + .first(); + +// Display the TM image as a false color composite. +Map.addLayer(tmImage, { + bands: ['B4', 'B3', 'B2'], + min: 0, + max: 100 +}, 'TM'); + +// Get the scale of the TM data from its projection: +var tmScale = tmImage.select('B4') + .projection().nominalScale(); + +print('TM NIR scale:', tmScale); + +// MSI +// Filter MSI imagery by location and date. +var msiImage = msi + .filterBounds(Map.getCenter()) + .filterDate('2020-02-01', '2020-04-01') + .first(); + +// Display the MSI image as a false color composite. +Map.addLayer(msiImage, { + bands: ['B8', 'B4', 'B3'], + min: 0, + max: 2000 +}, 'MSI'); + +// Get the scale of the MSI data from its projection: +var msiScale = msiImage.select('B8') + .projection().nominalScale(); +print('MSI scale:', msiScale); + +// NAIP +// Get NAIP images for the study period and region of interest. +var naipImage = naip + .filterBounds(Map.getCenter()) + .filterDate('2018-01-01', '2018-12-31') + .first(); + +// Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + bands: ['N', 'R', 'G'] +}, 'NAIP'); + +// Get the NAIP resolution from the first image in the mosaic. +var naipScale = naipImage.select('N') + .projection().nominalScale(); + +print('NAIP NIR scale:', naipScale); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Explore Temporal Resolution +///// + +// Use Print to see Landsat revisit time +print('Landsat-5 series:', tm + .filterBounds(Map.getCenter()) + .filterDate('1987-06-01', '1987-09-01')); + +// Create a chart to see Landsat 5's 16 day revisit time. +var tmChart = ui.Chart.image.series({ + imageCollection: tm.select('B4').filterDate('1987-06-01', + '1987-09-01'), + region: sfoPoint +}).setSeriesNames(['NIR']); + +// Define a chart style that will let us see the individual dates. +var chartStyle = { + hAxis: { + title: 'Date' + }, + vAxis: { + title: 'NIR Mean' + }, + series: { + 0: { + lineWidth: 3, + pointSize: 6 + } + }, +}; + +// Apply custom style properties to the chart. +tmChart.setOptions(chartStyle); + +// Print the chart. +print('TM Chart', tmChart); + +// Sentinel-2 has a 5 day revisit time. +var msiChart = ui.Chart.image.series({ + imageCollection: msi.select('B8').filterDate('2020-06-01', + '2020-09-01'), + region: sfoPoint +}).setSeriesNames(['NIR']); + +// Apply the previously defined custom style properties to the chart. +msiChart.setOptions(chartStyle); + +// Print the chart. +print('MSI Chart', msiChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Explore spectral resolution +///// + +// Get the MODIS band names as an ee.List +var modisBands = modisImage.bandNames(); + +// Print the list. +print('MODIS bands:', modisBands); + +// Print the length of the list. +print('Length of the bands list:', modisBands.length()); + +// Graph the MODIS spectral bands (bands 11-17). + +// Select only the reflectance bands of interest. +var reflectanceImage = modisImage.select( + 'sur_refl_b01', + 'sur_refl_b02', + 'sur_refl_b03', + 'sur_refl_b04', + 'sur_refl_b05', + 'sur_refl_b06', + 'sur_refl_b07' +); + +// Define an object of customization parameters for the chart. +var options = { + title: 'MODIS spectrum at SFO', + hAxis: { + title: 'Band' + }, + vAxis: { + title: 'Reflectance' + }, + legend: { + position: 'none' + }, + pointSize: 3 +}; + +// Make the chart. +var modisReflectanceChart = ui.Chart.image.regions({ + image: reflectanceImage, + regions: sfoPoint +}).setOptions(options); + +// Display the chart. +print(modisReflectanceChart); + +// Get the EO-1 band names as a ee.List +var eo1Image = eo1 + .filterDate('2015-01-01', '2016-01-01') + .first(); + +// Extract the EO-1 band names. +var eo1Bands = eo1Image.bandNames(); + +// Print the list of band names. +print('EO-1 bands:', eo1Bands); + +// Create an options object for our chart. +var optionsEO1 = { + title: 'EO1 spectrum', + hAxis: { + title: 'Band' + }, + vAxis: { + title: 'Reflectance' + }, + legend: { + position: 'none' + }, + pointSize: 3 +}; + +// Make the chart and set the options. +var eo1Chart = ui.Chart.image.regions({ + image: eo1Image, + regions: ee.Geometry.Point([6.10, 81.12]) +}).setOptions(optionsEO1); + +// Display the chart. +print(eo1Chart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Examine pixel quality +///// + +// Sentinel Quality Visualization. +var msiCloud = msi + .filterBounds(Map.getCenter()) + .filterDate('2019-12-31', '2020-02-01') + .first(); + +// Display the MSI image as a false color composite. +Map.addLayer(msiCloud, + { + bands: ['B8', 'B4', 'B3'], + min: 0, + max: 2000 + }, + 'MSI Quality Image'); + +Map.addLayer(msiCloud, + { + bands: ['QA60'], + min: 0, + max: 2000 + }, + 'Sentinel Quality Visualization'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13d Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13d Checkpoint.py new file mode 100644 index 0000000..f013a30 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13d Checkpoint.py @@ -0,0 +1,287 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + eo1 = ee.ImageCollection("EO1/HYPERION"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.3 The Remote Sensing Vocabulary +# Checkpoint: F13d +# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### +# Explore spatial resolution +### + +# Define a region of interest as a point at San Francisco airport. +sfoPoint = ee.Geometry.Point(-122.3774, 37.6194) + +# Center the map at that point. +Map.centerObject(sfoPoint, 16) + +# MODIS +# Get an image from your imported MODIS MYD09GA collection. +modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first() + +# Use these MODIS bands for near infrared, red, and green, respectively. +modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04'] + +# Define visualization parameters for MODIS. +modisVis = { + 'bands': modisBands, + 'min': 0, + 'max': 3000 +} + +# Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS') + +# Get the scale of the data from the NIR band's projection: +modisScale = modisImage.select('sur_refl_b02') \ + .projection().nominalScale() + +print('MODIS NIR scale:', modisScale) + +# TM +# Filter TM imagery by location and date. + +tmImage = tm \ + .filterBounds(Map.getCenter()) \ + .filterDate('1987-03-01', '1987-08-01') \ + .first() + +# Display the TM image as a False color composite. +Map.addLayer(tmImage, { + 'bands': ['B4', 'B3', 'B2'], + 'min': 0, + 'max': 100 +}, 'TM') + +# Get the scale of the TM data from its projection: +tmScale = tmImage.select('B4') \ + .projection().nominalScale() + +print('TM NIR scale:', tmScale) + +# MSI +# Filter MSI imagery by location and date. +msiImage = msi \ + .filterBounds(Map.getCenter()) \ + .filterDate('2020-02-01', '2020-04-01') \ + .first() + +# Display the MSI image as a False color composite. +Map.addLayer(msiImage, { + 'bands': ['B8', 'B4', 'B3'], + 'min': 0, + 'max': 2000 +}, 'MSI') + +# Get the scale of the MSI data from its projection: +msiScale = msiImage.select('B8') \ + .projection().nominalScale() +print('MSI scale:', msiScale) + +# NAIP +# Get NAIP images for the study period and region of interest. +naipImage = naip \ + .filterBounds(Map.getCenter()) \ + .filterDate('2018-01-01', '2018-12-31') \ + .first() + +# Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + 'bands': ['N', 'R', 'G'] +}, 'NAIP') + +# Get the NAIP resolution from the first image in the mosaic. +naipScale = naipImage.select('N') \ + .projection().nominalScale() + +print('NAIP NIR scale:', naipScale) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Explore Temporal Resolution +##/ + +# Use Print to see Landsat revisit time +print('Landsat-5 series:', tm \ + .filterBounds(Map.getCenter()) \ + .filterDate('1987-06-01', '1987-09-01')) + +# Create a chart to see Landsat 5's 16 day revisit time. +tmChart = ui.Chart.image.series({ + 'imageCollection': tm.select('B4').filterDate('1987-06-01', + '1987-09-01'), + 'region': sfoPoint +}).setSeriesNames(['NIR']) + +# Define a chart style that will let us see the individual dates. +chartStyle = { + 'hAxis': { + 'title': 'Date' + }, + 'vAxis': { + 'title': 'NIR Mean' + }, + 'series': { + '0': { + 'lineWidth': 3, + 'pointSize': 6 + } + }, +} + +# Apply custom style properties to the chart. +tmChart.setOptions(chartStyle) + +# Print the chart. +print('TM Chart', tmChart) + +# Sentinel-2 has a 5 day revisit time. +msiChart = ui.Chart.image.series({ + 'imageCollection': msi.select('B8').filterDate('2020-06-01', + '2020-09-01'), + 'region': sfoPoint +}).setSeriesNames(['NIR']) + +# Apply the previously defined custom style properties to the chart. +msiChart.setOptions(chartStyle) + +# Print the chart. +print('MSI Chart', msiChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Explore spectral resolution +##/ + +# Get the MODIS band names as an ee.List +modisBands = modisImage.bandNames() + +# Print the list. +print('MODIS bands:', modisBands) + +# Print the length of the list. +print('Length of the bands list:', modisBands.length()) + +# Graph the MODIS spectral bands (bands 11-17). + +# Select only the reflectance bands of interest. +reflectanceImage = modisImage.select( + 'sur_refl_b01', + 'sur_refl_b02', + 'sur_refl_b03', + 'sur_refl_b04', + 'sur_refl_b05', + 'sur_refl_b06', + 'sur_refl_b07' +) + +# Define an object of customization parameters for the chart. +options = { + 'title': 'MODIS spectrum at SFO', + 'hAxis': { + 'title': 'Band' + }, + 'vAxis': { + 'title': 'Reflectance' + }, + 'legend': { + 'position': 'none' + }, + 'pointSize': 3 +} + +# Make the chart. +modisReflectanceChart = ui.Chart.image.regions({ + 'image': reflectanceImage, + 'regions': sfoPoint +}).setOptions(options) + +# Display the chart. +print(modisReflectanceChart) + +# Get the EO-1 band names as a ee.List +eo1Image = eo1 \ + .filterDate('2015-01-01', '2016-01-01') \ + .first() + +# Extract the EO-1 band names. +eo1Bands = eo1Image.bandNames() + +# Print the list of band names. +print('EO-1 bands:', eo1Bands) + +# Create an options object for our chart. +optionsEO1 = { + 'title': 'EO1 spectrum', + 'hAxis': { + 'title': 'Band' + }, + 'vAxis': { + 'title': 'Reflectance' + }, + 'legend': { + 'position': 'none' + }, + 'pointSize': 3 +} + +# Make the chart and set the options. +eo1Chart = ui.Chart.image.regions({ + 'image': eo1Image, + 'regions': ee.Geometry.Point([6.10, 81.12]) +}).setOptions(optionsEO1) + +# Display the chart. +print(eo1Chart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Examine pixel quality +##/ + +# Sentinel Quality Visualization. +msiCloud = msi \ + .filterBounds(Map.getCenter()) \ + .filterDate('2019-12-31', '2020-02-01') \ + .first() + +# Display the MSI image as a False color composite. +Map.addLayer(msiCloud, + { + 'bands': ['B8', 'B4', 'B3'], + 'min': 0, + 'max': 2000 + }, + 'MSI Quality Image') + +Map.addLayer(msiCloud, + { + 'bands': ['QA60'], + 'min': 0, + 'max': 2000 + }, + 'Sentinel Quality Visualization') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13e Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13e Checkpoint.ipynb new file mode 100644 index 0000000..bbdc37a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13e Checkpoint.ipynb @@ -0,0 +1,388 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "msi = ee.ImageCollection(\"COPERNICUS/S2\"),\n", + " naip = ee.ImageCollection(\"USDA/NAIP/DOQQ\"),\n", + " eo1 = ee.ImageCollection(\"EO1/HYPERION\"),\n", + " tm = ee.ImageCollection(\"LANDSAT/LT05/C02/T1\"),\n", + " mod09 = ee.ImageCollection(\"MODIS/061/MOD09A1\")\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F1.3 The Remote Sensing Vocabulary\n", + "# Checkpoint: F13e\n", + "# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "###\n", + "# Explore spatial resolution\n", + "###\n", + "\n", + "# Define a region of interest as a point at San Francisco airport.\n", + "sfoPoint = ee.Geometry.Point(-122.3774, 37.6194)\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(sfoPoint, 16)\n", + "\n", + "# MODIS\n", + "# Get an image from your imported MODIS MYD09GA collection.\n", + "modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first()\n", + "\n", + "# Use these MODIS bands for near infrared, red, and green, respectively.\n", + "modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']\n", + "\n", + "# Define visualization parameters for MODIS.\n", + "modisVis = {\n", + " 'bands': modisBands,\n", + " 'min': 0,\n", + " 'max': 3000\n", + "}\n", + "\n", + "# Add the MODIS image to the map.\n", + "Map.addLayer(modisImage, modisVis, 'MODIS')\n", + "\n", + "# Get the scale of the data from the NIR band's projection:\n", + "modisScale = modisImage.select('sur_refl_b02') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('MODIS NIR scale:', modisScale)\n", + "\n", + "# TM\n", + "# Filter TM imagery by location and date.\n", + "\n", + "tmImage = tm \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('1987-03-01', '1987-08-01') \\\n", + " .first()\n", + "\n", + "# Display the TM image as a False color composite.\n", + "Map.addLayer(tmImage, {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 0,\n", + " 'max': 100\n", + "}, 'TM')\n", + "\n", + "# Get the scale of the TM data from its projection:\n", + "tmScale = tmImage.select('B4') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('TM NIR scale:', tmScale)\n", + "\n", + "# MSI\n", + "# Filter MSI imagery by location and date.\n", + "msiImage = msi \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2020-02-01', '2020-04-01') \\\n", + " .first()\n", + "\n", + "# Display the MSI image as a False color composite.\n", + "Map.addLayer(msiImage, {\n", + " 'bands': ['B8', 'B4', 'B3'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + "}, 'MSI')\n", + "\n", + "# Get the scale of the MSI data from its projection:\n", + "msiScale = msiImage.select('B8') \\\n", + " .projection().nominalScale()\n", + "print('MSI scale:', msiScale)\n", + "\n", + "# NAIP\n", + "# Get NAIP images for the study period and region of interest.\n", + "naipImage = naip \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2018-01-01', '2018-12-31') \\\n", + " .first()\n", + "\n", + "# Display the NAIP mosaic as a color-IR composite.\n", + "Map.addLayer(naipImage, {\n", + " 'bands': ['N', 'R', 'G']\n", + "}, 'NAIP')\n", + "\n", + "# Get the NAIP resolution from the first image in the mosaic.\n", + "naipScale = naipImage.select('N') \\\n", + " .projection().nominalScale()\n", + "\n", + "print('NAIP NIR scale:', naipScale)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Explore Temporal Resolution\n", + "##/\n", + "\n", + "# Use Print to see Landsat revisit time\n", + "print('Landsat-5 series:', tm \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('1987-06-01', '1987-09-01'))\n", + "\n", + "# Create a chart to see Landsat 5's 16 day revisit time.\n", + "tmChart = ui.Chart.image.series({\n", + " 'imageCollection': tm.select('B4').filterDate('1987-06-01',\n", + " '1987-09-01'),\n", + " 'region': sfoPoint\n", + "}).setSeriesNames(['NIR'])\n", + "\n", + "# Define a chart style that will let us see the individual dates.\n", + "chartStyle = {\n", + " 'hAxis': {\n", + " 'title': 'Date'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'NIR Mean'\n", + " },\n", + " 'series': {\n", + " '0': {\n", + " 'lineWidth': 3,\n", + " 'pointSize': 6\n", + " }\n", + " },\n", + "}\n", + "\n", + "# Apply custom style properties to the chart.\n", + "tmChart.setOptions(chartStyle)\n", + "\n", + "# Print the chart.\n", + "print('TM Chart', tmChart)\n", + "\n", + "# Sentinel-2 has a 5 day revisit time.\n", + "msiChart = ui.Chart.image.series({\n", + " 'imageCollection': msi.select('B8').filterDate('2020-06-01',\n", + " '2020-09-01'),\n", + " 'region': sfoPoint\n", + "}).setSeriesNames(['NIR'])\n", + "\n", + "# Apply the previously defined custom style properties to the chart.\n", + "msiChart.setOptions(chartStyle)\n", + "\n", + "# Print the chart.\n", + "print('MSI Chart', msiChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Explore spectral resolution\n", + "##/\n", + "\n", + "# Get the MODIS band names as an ee.List\n", + "modisBands = modisImage.bandNames()\n", + "\n", + "# Print the list.\n", + "print('MODIS bands:', modisBands)\n", + "\n", + "# Print the length of the list.\n", + "print('Length of the bands list:', modisBands.length())\n", + "\n", + "# Graph the MODIS spectral bands (bands 11-17).\n", + "\n", + "# Select only the reflectance bands of interest.\n", + "reflectanceImage = modisImage.select(\n", + " 'sur_refl_b01',\n", + " 'sur_refl_b02',\n", + " 'sur_refl_b03',\n", + " 'sur_refl_b04',\n", + " 'sur_refl_b05',\n", + " 'sur_refl_b06',\n", + " 'sur_refl_b07'\n", + ")\n", + "\n", + "# Define an object of customization parameters for the chart.\n", + "options = {\n", + " 'title': 'MODIS spectrum at SFO',\n", + " 'hAxis': {\n", + " 'title': 'Band'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Reflectance'\n", + " },\n", + " 'legend': {\n", + " 'position': 'none'\n", + " },\n", + " 'pointSize': 3\n", + "}\n", + "\n", + "# Make the chart.\n", + "modisReflectanceChart = ui.Chart.image.regions({\n", + " 'image': reflectanceImage,\n", + " 'regions': sfoPoint\n", + "}).setOptions(options)\n", + "\n", + "# Display the chart.\n", + "print(modisReflectanceChart)\n", + "\n", + "# Get the EO-1 band names as a ee.List\n", + "eo1Image = eo1 \\\n", + " .filterDate('2015-01-01', '2016-01-01') \\\n", + " .first()\n", + "\n", + "# Extract the EO-1 band names.\n", + "eo1Bands = eo1Image.bandNames()\n", + "\n", + "# Print the list of band names.\n", + "print('EO-1 bands:', eo1Bands)\n", + "\n", + "# Create an options object for our chart.\n", + "optionsEO1 = {\n", + " 'title': 'EO1 spectrum',\n", + " 'hAxis': {\n", + " 'title': 'Band'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Reflectance'\n", + " },\n", + " 'legend': {\n", + " 'position': 'none'\n", + " },\n", + " 'pointSize': 3\n", + "}\n", + "\n", + "# Make the chart and set the options.\n", + "eo1Chart = ui.Chart.image.regions({\n", + " 'image': eo1Image,\n", + " 'regions': ee.Geometry.Point([6.10, 81.12])\n", + "}).setOptions(optionsEO1)\n", + "\n", + "# Display the chart.\n", + "print(eo1Chart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Examine pixel quality\n", + "##/\n", + "\n", + "# Sentinel Quality Visualization.\n", + "msiCloud = msi \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterDate('2019-12-31', '2020-02-01') \\\n", + " .first()\n", + "\n", + "# Display the MSI image as a False color composite.\n", + "Map.addLayer(msiCloud,\n", + " {\n", + " 'bands': ['B8', 'B4', 'B3'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + " },\n", + " 'MSI Quality Image')\n", + "\n", + "Map.addLayer(msiCloud,\n", + " {\n", + " 'bands': ['QA60'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + " },\n", + " 'Sentinel Quality Visualization')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Metadata\n", + "##/\n", + "print('MSI Image Metadata', msiImage)\n", + "\n", + "# Image-level Cloud info\n", + "msiCloudiness = msiImage.get('CLOUDY_PIXEL_PERCENTAGE')\n", + "\n", + "print('MSI CLOUDY_PIXEL_PERCENTAGE:', msiCloudiness)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13e Checkpoint.js b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13e Checkpoint.js new file mode 100644 index 0000000..feab35c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13e Checkpoint.js @@ -0,0 +1,295 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + eo1 = ee.ImageCollection("EO1/HYPERION"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1"); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F1.3 The Remote Sensing Vocabulary +// Checkpoint: F13e +// Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +////// +// Explore spatial resolution +////// + +// Define a region of interest as a point at San Francisco airport. +var sfoPoint = ee.Geometry.Point(-122.3774, 37.6194); + +// Center the map at that point. +Map.centerObject(sfoPoint, 16); + +// MODIS +// Get an image from your imported MODIS MYD09GA collection. +var modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first(); + +// Use these MODIS bands for near infrared, red, and green, respectively. +var modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04']; + +// Define visualization parameters for MODIS. +var modisVis = { + bands: modisBands, + min: 0, + max: 3000 +}; + +// Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS'); + +// Get the scale of the data from the NIR band's projection: +var modisScale = modisImage.select('sur_refl_b02') + .projection().nominalScale(); + +print('MODIS NIR scale:', modisScale); + +// TM +// Filter TM imagery by location and date. + +var tmImage = tm + .filterBounds(Map.getCenter()) + .filterDate('1987-03-01', '1987-08-01') + .first(); + +// Display the TM image as a false color composite. +Map.addLayer(tmImage, { + bands: ['B4', 'B3', 'B2'], + min: 0, + max: 100 +}, 'TM'); + +// Get the scale of the TM data from its projection: +var tmScale = tmImage.select('B4') + .projection().nominalScale(); + +print('TM NIR scale:', tmScale); + +// MSI +// Filter MSI imagery by location and date. +var msiImage = msi + .filterBounds(Map.getCenter()) + .filterDate('2020-02-01', '2020-04-01') + .first(); + +// Display the MSI image as a false color composite. +Map.addLayer(msiImage, { + bands: ['B8', 'B4', 'B3'], + min: 0, + max: 2000 +}, 'MSI'); + +// Get the scale of the MSI data from its projection: +var msiScale = msiImage.select('B8') + .projection().nominalScale(); +print('MSI scale:', msiScale); + +// NAIP +// Get NAIP images for the study period and region of interest. +var naipImage = naip + .filterBounds(Map.getCenter()) + .filterDate('2018-01-01', '2018-12-31') + .first(); + +// Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + bands: ['N', 'R', 'G'] +}, 'NAIP'); + +// Get the NAIP resolution from the first image in the mosaic. +var naipScale = naipImage.select('N') + .projection().nominalScale(); + +print('NAIP NIR scale:', naipScale); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Explore Temporal Resolution +///// + +// Use Print to see Landsat revisit time +print('Landsat-5 series:', tm + .filterBounds(Map.getCenter()) + .filterDate('1987-06-01', '1987-09-01')); + +// Create a chart to see Landsat 5's 16 day revisit time. +var tmChart = ui.Chart.image.series({ + imageCollection: tm.select('B4').filterDate('1987-06-01', + '1987-09-01'), + region: sfoPoint +}).setSeriesNames(['NIR']); + +// Define a chart style that will let us see the individual dates. +var chartStyle = { + hAxis: { + title: 'Date' + }, + vAxis: { + title: 'NIR Mean' + }, + series: { + 0: { + lineWidth: 3, + pointSize: 6 + } + }, +}; + +// Apply custom style properties to the chart. +tmChart.setOptions(chartStyle); + +// Print the chart. +print('TM Chart', tmChart); + +// Sentinel-2 has a 5 day revisit time. +var msiChart = ui.Chart.image.series({ + imageCollection: msi.select('B8').filterDate('2020-06-01', + '2020-09-01'), + region: sfoPoint +}).setSeriesNames(['NIR']); + +// Apply the previously defined custom style properties to the chart. +msiChart.setOptions(chartStyle); + +// Print the chart. +print('MSI Chart', msiChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Explore spectral resolution +///// + +// Get the MODIS band names as an ee.List +var modisBands = modisImage.bandNames(); + +// Print the list. +print('MODIS bands:', modisBands); + +// Print the length of the list. +print('Length of the bands list:', modisBands.length()); + +// Graph the MODIS spectral bands (bands 11-17). + +// Select only the reflectance bands of interest. +var reflectanceImage = modisImage.select( + 'sur_refl_b01', + 'sur_refl_b02', + 'sur_refl_b03', + 'sur_refl_b04', + 'sur_refl_b05', + 'sur_refl_b06', + 'sur_refl_b07' +); + +// Define an object of customization parameters for the chart. +var options = { + title: 'MODIS spectrum at SFO', + hAxis: { + title: 'Band' + }, + vAxis: { + title: 'Reflectance' + }, + legend: { + position: 'none' + }, + pointSize: 3 +}; + +// Make the chart. +var modisReflectanceChart = ui.Chart.image.regions({ + image: reflectanceImage, + regions: sfoPoint +}).setOptions(options); + +// Display the chart. +print(modisReflectanceChart); + +// Get the EO-1 band names as a ee.List +var eo1Image = eo1 + .filterDate('2015-01-01', '2016-01-01') + .first(); + +// Extract the EO-1 band names. +var eo1Bands = eo1Image.bandNames(); + +// Print the list of band names. +print('EO-1 bands:', eo1Bands); + +// Create an options object for our chart. +var optionsEO1 = { + title: 'EO1 spectrum', + hAxis: { + title: 'Band' + }, + vAxis: { + title: 'Reflectance' + }, + legend: { + position: 'none' + }, + pointSize: 3 +}; + +// Make the chart and set the options. +var eo1Chart = ui.Chart.image.regions({ + image: eo1Image, + regions: ee.Geometry.Point([6.10, 81.12]) +}).setOptions(optionsEO1); + +// Display the chart. +print(eo1Chart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Examine pixel quality +///// + +// Sentinel Quality Visualization. +var msiCloud = msi + .filterBounds(Map.getCenter()) + .filterDate('2019-12-31', '2020-02-01') + .first(); + +// Display the MSI image as a false color composite. +Map.addLayer(msiCloud, + { + bands: ['B8', 'B4', 'B3'], + min: 0, + max: 2000 + }, + 'MSI Quality Image'); + +Map.addLayer(msiCloud, + { + bands: ['QA60'], + min: 0, + max: 2000 + }, + 'Sentinel Quality Visualization'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Metadata +///// +print('MSI Image Metadata', msiImage); + +// Image-level Cloud info +var msiCloudiness = msiImage.get('CLOUDY_PIXEL_PERCENTAGE'); + +print('MSI CLOUDY_PIXEL_PERCENTAGE:', msiCloudiness); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13e Checkpoint.py b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13e Checkpoint.py new file mode 100644 index 0000000..e3cb356 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F1 - Programming and Remote Sensing Basics/F1.3 The Remote Sensing Vocabulary/F13e Checkpoint.py @@ -0,0 +1,301 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +msi = ee.ImageCollection("COPERNICUS/S2"), + naip = ee.ImageCollection("USDA/NAIP/DOQQ"), + eo1 = ee.ImageCollection("EO1/HYPERION"), + tm = ee.ImageCollection("LANDSAT/LT05/C02/T1"), + mod09 = ee.ImageCollection("MODIS/061/MOD09A1") +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F1.3 The Remote Sensing Vocabulary +# Checkpoint: F13e +# Authors: K. Dyson, A. P. Nicolau, D. Saah, and N. Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### +# Explore spatial resolution +### + +# Define a region of interest as a point at San Francisco airport. +sfoPoint = ee.Geometry.Point(-122.3774, 37.6194) + +# Center the map at that point. +Map.centerObject(sfoPoint, 16) + +# MODIS +# Get an image from your imported MODIS MYD09GA collection. +modisImage = mod09.filterDate('2020-02-01', '2020-03-01').first() + +# Use these MODIS bands for near infrared, red, and green, respectively. +modisBands = ['sur_refl_b02', 'sur_refl_b01', 'sur_refl_b04'] + +# Define visualization parameters for MODIS. +modisVis = { + 'bands': modisBands, + 'min': 0, + 'max': 3000 +} + +# Add the MODIS image to the map. +Map.addLayer(modisImage, modisVis, 'MODIS') + +# Get the scale of the data from the NIR band's projection: +modisScale = modisImage.select('sur_refl_b02') \ + .projection().nominalScale() + +print('MODIS NIR scale:', modisScale) + +# TM +# Filter TM imagery by location and date. + +tmImage = tm \ + .filterBounds(Map.getCenter()) \ + .filterDate('1987-03-01', '1987-08-01') \ + .first() + +# Display the TM image as a False color composite. +Map.addLayer(tmImage, { + 'bands': ['B4', 'B3', 'B2'], + 'min': 0, + 'max': 100 +}, 'TM') + +# Get the scale of the TM data from its projection: +tmScale = tmImage.select('B4') \ + .projection().nominalScale() + +print('TM NIR scale:', tmScale) + +# MSI +# Filter MSI imagery by location and date. +msiImage = msi \ + .filterBounds(Map.getCenter()) \ + .filterDate('2020-02-01', '2020-04-01') \ + .first() + +# Display the MSI image as a False color composite. +Map.addLayer(msiImage, { + 'bands': ['B8', 'B4', 'B3'], + 'min': 0, + 'max': 2000 +}, 'MSI') + +# Get the scale of the MSI data from its projection: +msiScale = msiImage.select('B8') \ + .projection().nominalScale() +print('MSI scale:', msiScale) + +# NAIP +# Get NAIP images for the study period and region of interest. +naipImage = naip \ + .filterBounds(Map.getCenter()) \ + .filterDate('2018-01-01', '2018-12-31') \ + .first() + +# Display the NAIP mosaic as a color-IR composite. +Map.addLayer(naipImage, { + 'bands': ['N', 'R', 'G'] +}, 'NAIP') + +# Get the NAIP resolution from the first image in the mosaic. +naipScale = naipImage.select('N') \ + .projection().nominalScale() + +print('NAIP NIR scale:', naipScale) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Explore Temporal Resolution +##/ + +# Use Print to see Landsat revisit time +print('Landsat-5 series:', tm \ + .filterBounds(Map.getCenter()) \ + .filterDate('1987-06-01', '1987-09-01')) + +# Create a chart to see Landsat 5's 16 day revisit time. +tmChart = ui.Chart.image.series({ + 'imageCollection': tm.select('B4').filterDate('1987-06-01', + '1987-09-01'), + 'region': sfoPoint +}).setSeriesNames(['NIR']) + +# Define a chart style that will let us see the individual dates. +chartStyle = { + 'hAxis': { + 'title': 'Date' + }, + 'vAxis': { + 'title': 'NIR Mean' + }, + 'series': { + '0': { + 'lineWidth': 3, + 'pointSize': 6 + } + }, +} + +# Apply custom style properties to the chart. +tmChart.setOptions(chartStyle) + +# Print the chart. +print('TM Chart', tmChart) + +# Sentinel-2 has a 5 day revisit time. +msiChart = ui.Chart.image.series({ + 'imageCollection': msi.select('B8').filterDate('2020-06-01', + '2020-09-01'), + 'region': sfoPoint +}).setSeriesNames(['NIR']) + +# Apply the previously defined custom style properties to the chart. +msiChart.setOptions(chartStyle) + +# Print the chart. +print('MSI Chart', msiChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Explore spectral resolution +##/ + +# Get the MODIS band names as an ee.List +modisBands = modisImage.bandNames() + +# Print the list. +print('MODIS bands:', modisBands) + +# Print the length of the list. +print('Length of the bands list:', modisBands.length()) + +# Graph the MODIS spectral bands (bands 11-17). + +# Select only the reflectance bands of interest. +reflectanceImage = modisImage.select( + 'sur_refl_b01', + 'sur_refl_b02', + 'sur_refl_b03', + 'sur_refl_b04', + 'sur_refl_b05', + 'sur_refl_b06', + 'sur_refl_b07' +) + +# Define an object of customization parameters for the chart. +options = { + 'title': 'MODIS spectrum at SFO', + 'hAxis': { + 'title': 'Band' + }, + 'vAxis': { + 'title': 'Reflectance' + }, + 'legend': { + 'position': 'none' + }, + 'pointSize': 3 +} + +# Make the chart. +modisReflectanceChart = ui.Chart.image.regions({ + 'image': reflectanceImage, + 'regions': sfoPoint +}).setOptions(options) + +# Display the chart. +print(modisReflectanceChart) + +# Get the EO-1 band names as a ee.List +eo1Image = eo1 \ + .filterDate('2015-01-01', '2016-01-01') \ + .first() + +# Extract the EO-1 band names. +eo1Bands = eo1Image.bandNames() + +# Print the list of band names. +print('EO-1 bands:', eo1Bands) + +# Create an options object for our chart. +optionsEO1 = { + 'title': 'EO1 spectrum', + 'hAxis': { + 'title': 'Band' + }, + 'vAxis': { + 'title': 'Reflectance' + }, + 'legend': { + 'position': 'none' + }, + 'pointSize': 3 +} + +# Make the chart and set the options. +eo1Chart = ui.Chart.image.regions({ + 'image': eo1Image, + 'regions': ee.Geometry.Point([6.10, 81.12]) +}).setOptions(optionsEO1) + +# Display the chart. +print(eo1Chart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Examine pixel quality +##/ + +# Sentinel Quality Visualization. +msiCloud = msi \ + .filterBounds(Map.getCenter()) \ + .filterDate('2019-12-31', '2020-02-01') \ + .first() + +# Display the MSI image as a False color composite. +Map.addLayer(msiCloud, + { + 'bands': ['B8', 'B4', 'B3'], + 'min': 0, + 'max': 2000 + }, + 'MSI Quality Image') + +Map.addLayer(msiCloud, + { + 'bands': ['QA60'], + 'min': 0, + 'max': 2000 + }, + 'Sentinel Quality Visualization') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Metadata +##/ +print('MSI Image Metadata', msiImage) + +# Image-level Cloud info +msiCloudiness = msiImage.get('CLOUDY_PIXEL_PERCENTAGE') + +print('MSI CLOUDY_PIXEL_PERCENTAGE:', msiCloudiness) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20a Checkpoint.ipynb new file mode 100644 index 0000000..663d273 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20a Checkpoint.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F2.0 Image Manipulation: Bands, Arithmetic, Thresholds, and Masks\n", + "# Checkpoint: F20a\n", + "# Authors: Karen Dyson, Andrea Puzzi Nicolau, David Saah, and Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##/\n", + "# Band Arithmetic\n", + "##/\n", + "\n", + "# Calculate NDVI using Sentinel 2\n", + "\n", + "# Import and filter imagery by location and date.\n", + "sfoPoint = ee.Geometry.Point(-122.3774, 37.6194)\n", + "sfoImage = ee.ImageCollection('COPERNICUS/S2') \\\n", + " .filterBounds(sfoPoint) \\\n", + " .filterDate('2020-02-01', '2020-04-01') \\\n", + " .first()\n", + "\n", + "# Display the image as a False color composite.\n", + "Map.centerObject(sfoImage, 11)\n", + "Map.addLayer(sfoImage, {\n", + " 'bands': ['B8', 'B4', 'B3'],\n", + " 'min': 0,\n", + " 'max': 2000\n", + "}, 'False color')\n", + "\n", + "# Extract the near infrared and red bands.\n", + "nir = sfoImage.select('B8')\n", + "red = sfoImage.select('B4')\n", + "\n", + "# Calculate the numerator and the denominator using subtraction and addition respectively.\n", + "numerator = nir.subtract(red)\n", + "denominator = nir.add(red)\n", + "\n", + "# Now calculate NDVI.\n", + "ndvi = numerator.divide(denominator)\n", + "\n", + "# Add the layer to our map with a palette.\n", + "vegPalette = ['red', 'white', 'green']\n", + "Map.addLayer(ndvi, {\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': vegPalette\n", + "}, 'NDVI Manual')\n", + "\n", + "# Now use the built-in normalizedDifference function to achieve the same outcome.\n", + "ndviND = sfoImage.normalizedDifference(['B8', 'B4'])\n", + "Map.addLayer(ndviND, {\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': vegPalette\n", + "}, 'NDVI normalizedDiff')\n", + "\n", + "# Use normalizedDifference to calculate NDWI\n", + "ndwi = sfoImage.normalizedDifference(['B8', 'B11'])\n", + "waterPalette = ['white', 'blue']\n", + "Map.addLayer(ndwi, {\n", + " 'min': -0.5,\n", + " 'max': 1,\n", + " 'palette': waterPalette\n", + "}, 'NDWI')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20a Checkpoint.js b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20a Checkpoint.js new file mode 100644 index 0000000..3fb2ec2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20a Checkpoint.js @@ -0,0 +1,67 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F2.0 Image Manipulation: Bands, Arithmetic, Thresholds, and Masks +// Checkpoint: F20a +// Authors: Karen Dyson, Andrea Puzzi Nicolau, David Saah, and Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///// +// Band Arithmetic +///// + +// Calculate NDVI using Sentinel 2 + +// Import and filter imagery by location and date. +var sfoPoint = ee.Geometry.Point(-122.3774, 37.6194); +var sfoImage = ee.ImageCollection('COPERNICUS/S2') + .filterBounds(sfoPoint) + .filterDate('2020-02-01', '2020-04-01') + .first(); + +// Display the image as a false color composite. +Map.centerObject(sfoImage, 11); +Map.addLayer(sfoImage, { + bands: ['B8', 'B4', 'B3'], + min: 0, + max: 2000 +}, 'False color'); + +// Extract the near infrared and red bands. +var nir = sfoImage.select('B8'); +var red = sfoImage.select('B4'); + +// Calculate the numerator and the denominator using subtraction and addition respectively. +var numerator = nir.subtract(red); +var denominator = nir.add(red); + +// Now calculate NDVI. +var ndvi = numerator.divide(denominator); + +// Add the layer to our map with a palette. +var vegPalette = ['red', 'white', 'green']; +Map.addLayer(ndvi, { + min: -1, + max: 1, + palette: vegPalette +}, 'NDVI Manual'); + +// Now use the built-in normalizedDifference function to achieve the same outcome. +var ndviND = sfoImage.normalizedDifference(['B8', 'B4']); +Map.addLayer(ndviND, { + min: -1, + max: 1, + palette: vegPalette +}, 'NDVI normalizedDiff'); + +// Use normalizedDifference to calculate NDWI +var ndwi = sfoImage.normalizedDifference(['B8', 'B11']); +var waterPalette = ['white', 'blue']; +Map.addLayer(ndwi, { + min: -0.5, + max: 1, + palette: waterPalette +}, 'NDWI'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20a Checkpoint.py b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20a Checkpoint.py new file mode 100644 index 0000000..e593d67 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20a Checkpoint.py @@ -0,0 +1,73 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F2.0 Image Manipulation: Bands, Arithmetic, Thresholds, and Masks +# Checkpoint: F20a +# Authors: Karen Dyson, Andrea Puzzi Nicolau, David Saah, and Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##/ +# Band Arithmetic +##/ + +# Calculate NDVI using Sentinel 2 + +# Import and filter imagery by location and date. +sfoPoint = ee.Geometry.Point(-122.3774, 37.6194) +sfoImage = ee.ImageCollection('COPERNICUS/S2') \ + .filterBounds(sfoPoint) \ + .filterDate('2020-02-01', '2020-04-01') \ + .first() + +# Display the image as a False color composite. +Map.centerObject(sfoImage, 11) +Map.addLayer(sfoImage, { + 'bands': ['B8', 'B4', 'B3'], + 'min': 0, + 'max': 2000 +}, 'False color') + +# Extract the near infrared and red bands. +nir = sfoImage.select('B8') +red = sfoImage.select('B4') + +# Calculate the numerator and the denominator using subtraction and addition respectively. +numerator = nir.subtract(red) +denominator = nir.add(red) + +# Now calculate NDVI. +ndvi = numerator.divide(denominator) + +# Add the layer to our map with a palette. +vegPalette = ['red', 'white', 'green'] +Map.addLayer(ndvi, { + 'min': -1, + 'max': 1, + 'palette': vegPalette +}, 'NDVI Manual') + +# Now use the built-in normalizedDifference function to achieve the same outcome. +ndviND = sfoImage.normalizedDifference(['B8', 'B4']) +Map.addLayer(ndviND, { + 'min': -1, + 'max': 1, + 'palette': vegPalette +}, 'NDVI normalizedDiff') + +# Use normalizedDifference to calculate NDWI +ndwi = sfoImage.normalizedDifference(['B8', 'B11']) +waterPalette = ['white', 'blue'] +Map.addLayer(ndwi, { + 'min': -0.5, + 'max': 1, + 'palette': waterPalette +}, 'NDWI') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20b Checkpoint.ipynb new file mode 100644 index 0000000..a242add --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20b Checkpoint.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F2.0 Image Manipulation: Bands, Arithmetic, Thresholds, and Masks\n", + "# Checkpoint: F20b\n", + "# Authors: Karen Dyson, Andrea Puzzi Nicolau, David Saah, and Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Create an NDVI image using Sentinel 2.\n", + "seaPoint = ee.Geometry.Point(-122.2040, 47.6221)\n", + "seaImage = ee.ImageCollection('COPERNICUS/S2') \\\n", + " .filterBounds(seaPoint) \\\n", + " .filterDate('2020-08-15', '2020-10-01') \\\n", + " .first()\n", + "\n", + "seaNDVI = seaImage.normalizedDifference(['B8', 'B4'])\n", + "\n", + "# And map it.\n", + "Map.centerObject(seaPoint, 10)\n", + "vegPalette = ['red', 'white', 'green']\n", + "Map.addLayer(seaNDVI,\n", + " {\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': vegPalette\n", + " },\n", + " 'NDVI Seattle')\n", + "\n", + "# Implement a threshold.\n", + "seaVeg = seaNDVI.gt(0.5)\n", + "\n", + "# Map the threshold.\n", + "Map.addLayer(seaVeg,\n", + " {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['white', 'green']\n", + " },\n", + " 'Non-forest vs. Forest')\n", + "\n", + "# Implement .where.\n", + "# Create a starting image with all values = 1.\n", + "seaWhere = ee.Image(1) \\\n", + " .clip(seaNDVI.geometry())\n", + "\n", + "# Make all NDVI values less than -0.1 equal 0.\n", + "seaWhere = seaWhere.where(seaNDVI.lte(-0.1), 0)\n", + "\n", + "# Make all NDVI values greater than 0.5 equal 2.\n", + "seaWhere = seaWhere.where(seaNDVI.gte(0.5), 2)\n", + "\n", + "# Map our layer that has been divided into three classes.\n", + "Map.addLayer(seaWhere,\n", + " {\n", + " 'min': 0,\n", + " 'max': 2,\n", + " 'palette': ['blue', 'white', 'green']\n", + " },\n", + " 'Water, Non-forest, Forest')\n", + "\n", + "# Implement masking.\n", + "# View the seaVeg layer's current mask.\n", + "Map.centerObject(seaPoint, 9)\n", + "Map.addLayer(seaVeg.mask(), {}, 'seaVeg Mask')\n", + "\n", + "# Create a binary mask of non-forest.\n", + "vegMask = seaVeg.eq(1)\n", + "\n", + "# Update the seaVeg mask with the non-forest mask.\n", + "maskedVeg = seaVeg.updateMask(vegMask)\n", + "\n", + "# Map the updated Veg layer\n", + "Map.addLayer(maskedVeg,\n", + " {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['green']\n", + " },\n", + " 'Masked Forest Layer')\n", + "\n", + "# Map the updated mask\n", + "Map.addLayer(maskedVeg.mask(), {}, 'maskedVeg Mask')\n", + "\n", + "# Implement remapping.\n", + "# Remap the values from the seaWhere layer.\n", + "seaRemap = seaWhere.remap([0, 1, 2], # Existing values.\n", + " [9, 11, 10]); # Remapped values.\n", + "\n", + "Map.addLayer(seaRemap,\n", + " {\n", + " 'min': 9,\n", + " 'max': 11,\n", + " 'palette': ['blue', 'green', 'white']\n", + " },\n", + " 'Remapped Values')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20b Checkpoint.js b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20b Checkpoint.js new file mode 100644 index 0000000..0f550f3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20b Checkpoint.js @@ -0,0 +1,105 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F2.0 Image Manipulation: Bands, Arithmetic, Thresholds, and Masks +// Checkpoint: F20b +// Authors: Karen Dyson, Andrea Puzzi Nicolau, David Saah, and Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create an NDVI image using Sentinel 2. +var seaPoint = ee.Geometry.Point(-122.2040, 47.6221); +var seaImage = ee.ImageCollection('COPERNICUS/S2') + .filterBounds(seaPoint) + .filterDate('2020-08-15', '2020-10-01') + .first(); + +var seaNDVI = seaImage.normalizedDifference(['B8', 'B4']); + +// And map it. +Map.centerObject(seaPoint, 10); +var vegPalette = ['red', 'white', 'green']; +Map.addLayer(seaNDVI, + { + min: -1, + max: 1, + palette: vegPalette + }, + 'NDVI Seattle'); + +// Implement a threshold. +var seaVeg = seaNDVI.gt(0.5); + +// Map the threshold. +Map.addLayer(seaVeg, + { + min: 0, + max: 1, + palette: ['white', 'green'] + }, + 'Non-forest vs. Forest'); + +// Implement .where. +// Create a starting image with all values = 1. +var seaWhere = ee.Image(1) + // Use clip to constrain the size of the new image. + .clip(seaNDVI.geometry()); + +// Make all NDVI values less than -0.1 equal 0. +seaWhere = seaWhere.where(seaNDVI.lte(-0.1), 0); + +// Make all NDVI values greater than 0.5 equal 2. +seaWhere = seaWhere.where(seaNDVI.gte(0.5), 2); + +// Map our layer that has been divided into three classes. +Map.addLayer(seaWhere, + { + min: 0, + max: 2, + palette: ['blue', 'white', 'green'] + }, + 'Water, Non-forest, Forest'); + +// Implement masking. +// View the seaVeg layer's current mask. +Map.centerObject(seaPoint, 9); +Map.addLayer(seaVeg.mask(), {}, 'seaVeg Mask'); + +// Create a binary mask of non-forest. +var vegMask = seaVeg.eq(1); + +// Update the seaVeg mask with the non-forest mask. +var maskedVeg = seaVeg.updateMask(vegMask); + +// Map the updated Veg layer +Map.addLayer(maskedVeg, + { + min: 0, + max: 1, + palette: ['green'] + }, + 'Masked Forest Layer'); + +// Map the updated mask +Map.addLayer(maskedVeg.mask(), {}, 'maskedVeg Mask'); + +// Implement remapping. +// Remap the values from the seaWhere layer. +var seaRemap = seaWhere.remap([0, 1, 2], // Existing values. + [9, 11, 10]); // Remapped values. + +Map.addLayer(seaRemap, + { + min: 9, + max: 11, + palette: ['blue', 'green', 'white'] + }, + 'Remapped Values'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + + + + + diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20b Checkpoint.py b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20b Checkpoint.py new file mode 100644 index 0000000..58da707 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.0 Image Manipulation Bands Arithmetic Thresholds and Masks/F20b Checkpoint.py @@ -0,0 +1,110 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F2.0 Image Manipulation: Bands, Arithmetic, Thresholds, and Masks +# Checkpoint: F20b +# Authors: Karen Dyson, Andrea Puzzi Nicolau, David Saah, and Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Create an NDVI image using Sentinel 2. +seaPoint = ee.Geometry.Point(-122.2040, 47.6221) +seaImage = ee.ImageCollection('COPERNICUS/S2') \ + .filterBounds(seaPoint) \ + .filterDate('2020-08-15', '2020-10-01') \ + .first() + +seaNDVI = seaImage.normalizedDifference(['B8', 'B4']) + +# And map it. +Map.centerObject(seaPoint, 10) +vegPalette = ['red', 'white', 'green'] +Map.addLayer(seaNDVI, + { + 'min': -1, + 'max': 1, + 'palette': vegPalette + }, + 'NDVI Seattle') + +# Implement a threshold. +seaVeg = seaNDVI.gt(0.5) + +# Map the threshold. +Map.addLayer(seaVeg, + { + 'min': 0, + 'max': 1, + 'palette': ['white', 'green'] + }, + 'Non-forest vs. Forest') + +# Implement .where. +# Create a starting image with all values = 1. +seaWhere = ee.Image(1) \ + .clip(seaNDVI.geometry()) + +# Make all NDVI values less than -0.1 equal 0. +seaWhere = seaWhere.where(seaNDVI.lte(-0.1), 0) + +# Make all NDVI values greater than 0.5 equal 2. +seaWhere = seaWhere.where(seaNDVI.gte(0.5), 2) + +# Map our layer that has been divided into three classes. +Map.addLayer(seaWhere, + { + 'min': 0, + 'max': 2, + 'palette': ['blue', 'white', 'green'] + }, + 'Water, Non-forest, Forest') + +# Implement masking. +# View the seaVeg layer's current mask. +Map.centerObject(seaPoint, 9) +Map.addLayer(seaVeg.mask(), {}, 'seaVeg Mask') + +# Create a binary mask of non-forest. +vegMask = seaVeg.eq(1) + +# Update the seaVeg mask with the non-forest mask. +maskedVeg = seaVeg.updateMask(vegMask) + +# Map the updated Veg layer +Map.addLayer(maskedVeg, + { + 'min': 0, + 'max': 1, + 'palette': ['green'] + }, + 'Masked Forest Layer') + +# Map the updated mask +Map.addLayer(maskedVeg.mask(), {}, 'maskedVeg Mask') + +# Implement remapping. +# Remap the values from the seaWhere layer. +seaRemap = seaWhere.remap([0, 1, 2], # Existing values. + [9, 11, 10]); # Remapped values. + +Map.addLayer(seaRemap, + { + 'min': 9, + 'max': 11, + 'palette': ['blue', 'green', 'white'] + }, + 'Remapped Values') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + + + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21a Checkpoint.ipynb new file mode 100644 index 0000000..04174d6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21a Checkpoint.ipynb @@ -0,0 +1,729 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "forest = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.414318330642528, 44.573441859314016]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427705541156865, 44.58422671008443]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.400411382221318, 44.59498464279749]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427190557026005, 44.600607315157376]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427018895649052, 44.571877083168374]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.352346196674443, 44.56062563530188]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.584676704909665, 44.528474349106816]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.568368874099118, 44.53899788426392]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.557210884597165, 44.534470549891495]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.563219032790524, 44.508523361153955]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.652654610183102, 44.530799479832886]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.691499968871002, 44.50146601530913]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.67055728088272, 44.502567915176314]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.668154021605377, 44.4990172743743]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.668154021605377, 44.48285300484169]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.65733935485733, 44.482118158872886]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.605325957640533, 44.49448683251806]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.592108031615142, 44.47342177876237]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.69252993713272, 44.47084936162859]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.738535186156158, 44.48922128217961]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.80740370242143, 44.44605496001787]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.759338516874555, 44.4477706457772]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.753158707304243, 44.45120186611758]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.622735604942841, 44.17490267165223]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.514245614708466, 44.1906597047536]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"24\"\n", + " })]),\n", + "developed = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.19467878610836, 45.46435783697627]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.203090193579063, 45.464899612733554]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.204463484594688, 45.462852876998106]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.180087569067345, 45.458879589622896]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.18068838388668, 45.45641119434588]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167642119238243, 45.455267267211944]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.165668013403282, 45.45340080996563]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167556288549767, 45.45135365679475]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167813780615196, 45.46297327527481]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.176911833593712, 45.46706666369604]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.223853948611414, 45.47248322583851]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.242822530764734, 45.47537221988128]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.211236837405359, 45.47729813363197]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.203597906130945, 45.47669629265562]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.154784524052499, 45.18401973624338]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.158217751591561, 45.185713605296485]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.156057754172835, 45.18958733293765]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.160520949973616, 45.19122054778279]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.158289352073226, 45.19599894427136]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.144728103293929, 45.194063439607106]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.145843902244124, 45.192914202565674]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.138548293723616, 45.19019223278913]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.144470611228499, 45.17924255060339]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.180176177634749, 45.18347748407685]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.177257934226546, 45.18626026884151]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"24\"\n", + " })]),\n", + "water = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.980378415331183, 43.953687197631126]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.735932614549933, 44.00704943549187]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.461274411424933, 44.12546046543348]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.282746579393683, 44.235763707116455]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.068269040331183, 43.94775509959863]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.202851559862433, 43.765549960385265]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.178132321581183, 43.72785127863614]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.213837887987433, 43.6821842672651]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.065522458299933, 43.72586647981521]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.941926266893683, 43.894339574154564]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.88486387395865, 45.077069068166345]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.848471662044588, 45.09864207259974]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.81448270940787, 45.0773115067334]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.828902265071932, 45.06179336476103]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.95455839300162, 45.11657297387295]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.002623578548494, 45.115603879971225]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.02322294378287, 45.10276183206325]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.043822309017244, 45.07149269722714]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.248517220628196, 45.02613418018433]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.263280099046165, 45.01836869065415]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.280102913987571, 45.006475743526394]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.265340035569603, 45.03802304474337]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.220021432053978, 45.023222245044195]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.182599251878196, 45.04069163407949]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.156163399827415, 45.03292811948761]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"24\"\n", + " })]),\n", + "herbaceous = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.647866129015439, 45.00732805319811]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.63911139879083, 45.00150212185294]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.63859641465997, 44.995432813342106]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.679108499620908, 44.99688950601573]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.680653452013486, 44.99106251314061]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.616967081163876, 44.98474926892666]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.625550150011533, 44.984627853569535]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.577313303087704, 44.99968139680247]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.682183386109417, 45.11939912570097]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.662270666382854, 45.142166966714186]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.655747534058635, 45.14483069451677]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.602875829957073, 45.13926093989158]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.57849991442973, 45.14265129011751]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.56476700427348, 45.14047180240153]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.55652725817973, 45.11794555067206]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.511208654664104, 45.12666644539884]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.601502538941448, 45.15887374651922]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.770417333863323, 45.15378959281897]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.706286368107783, 45.13319818507588]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.704827246403681, 45.13574123701328]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.699248251652705, 45.13955560228794]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.688776907658564, 45.13598342652142]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.688519415593134, 45.130655019734995]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.653500494694697, 45.13997940490131]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.67341321442126, 45.12260091467352]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"24\"\n", + " })])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F2.1 Interpreting an Image: Classification\n", + "# Checkpoint: F21a\n", + "# Author: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Create an Earth Engine Point object over Milan.\n", + "pt = ee.Geometry.Point([9.453, 45.424])\n", + "\n", + "# Filter the Landsat 8 collection and select the least cloudy image.\n", + "landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(pt) \\\n", + " .filterDate('2019-01-01', '2020-01-01') \\\n", + " .sort('CLOUD_COVER') \\\n", + " .first()\n", + "\n", + "# Center the map on that image.\n", + "Map.centerObject(landsat, 8)\n", + "\n", + "# Add Landsat image to the map.\n", + "visParams = {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 7000,\n", + " 'max': 12000\n", + "}\n", + "Map.addLayer(landsat, visParams, 'Landsat 8 image')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21a Checkpoint.js b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21a Checkpoint.js new file mode 100644 index 0000000..84ff06d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21a Checkpoint.js @@ -0,0 +1,637 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var forest = /* color: #589400 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.414318330642528, 44.573441859314016]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.427705541156865, 44.58422671008443]), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.400411382221318, 44.59498464279749]), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.427190557026005, 44.600607315157376]), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.427018895649052, 44.571877083168374]), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.352346196674443, 44.56062563530188]), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.584676704909665, 44.528474349106816]), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.568368874099118, 44.53899788426392]), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.557210884597165, 44.534470549891495]), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.563219032790524, 44.508523361153955]), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.652654610183102, 44.530799479832886]), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.691499968871002, 44.50146601530913]), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.67055728088272, 44.502567915176314]), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.4990172743743]), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.48285300484169]), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.65733935485733, 44.482118158872886]), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.605325957640533, 44.49448683251806]), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.592108031615142, 44.47342177876237]), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.69252993713272, 44.47084936162859]), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.738535186156158, 44.48922128217961]), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.80740370242143, 44.44605496001787]), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.759338516874555, 44.4477706457772]), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.753158707304243, 44.45120186611758]), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.622735604942841, 44.17490267165223]), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.514245614708466, 44.1906597047536]), + { + "class": 0, + "system:index": "24" + })]), + developed = /* color: #ff0000 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.19467878610836, 45.46435783697627]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.203090193579063, 45.464899612733554]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.204463484594688, 45.462852876998106]), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.180087569067345, 45.458879589622896]), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.18068838388668, 45.45641119434588]), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.167642119238243, 45.455267267211944]), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.165668013403282, 45.45340080996563]), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.167556288549767, 45.45135365679475]), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.167813780615196, 45.46297327527481]), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.176911833593712, 45.46706666369604]), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.223853948611414, 45.47248322583851]), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.242822530764734, 45.47537221988128]), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.211236837405359, 45.47729813363197]), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.203597906130945, 45.47669629265562]), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.154784524052499, 45.18401973624338]), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.158217751591561, 45.185713605296485]), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.156057754172835, 45.18958733293765]), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.160520949973616, 45.19122054778279]), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.158289352073226, 45.19599894427136]), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.144728103293929, 45.194063439607106]), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.145843902244124, 45.192914202565674]), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.138548293723616, 45.19019223278913]), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.144470611228499, 45.17924255060339]), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.180176177634749, 45.18347748407685]), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.177257934226546, 45.18626026884151]), + { + "class": 1, + "system:index": "24" + })]), + water = /* color: #1a11ff */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.980378415331183, 43.953687197631126]), + { + "class": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.735932614549933, 44.00704943549187]), + { + "class": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.461274411424933, 44.12546046543348]), + { + "class": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.282746579393683, 44.235763707116455]), + { + "class": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([10.068269040331183, 43.94775509959863]), + { + "class": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([10.202851559862433, 43.765549960385265]), + { + "class": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([10.178132321581183, 43.72785127863614]), + { + "class": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([10.213837887987433, 43.6821842672651]), + { + "class": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([10.065522458299933, 43.72586647981521]), + { + "class": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.941926266893683, 43.894339574154564]), + { + "class": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.88486387395865, 45.077069068166345]), + { + "class": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.848471662044588, 45.09864207259974]), + { + "class": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.81448270940787, 45.0773115067334]), + { + "class": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.828902265071932, 45.06179336476103]), + { + "class": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.95455839300162, 45.11657297387295]), + { + "class": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([10.002623578548494, 45.115603879971225]), + { + "class": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([10.02322294378287, 45.10276183206325]), + { + "class": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([10.043822309017244, 45.07149269722714]), + { + "class": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([10.248517220628196, 45.02613418018433]), + { + "class": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([10.263280099046165, 45.01836869065415]), + { + "class": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([10.280102913987571, 45.006475743526394]), + { + "class": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([10.265340035569603, 45.03802304474337]), + { + "class": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([10.220021432053978, 45.023222245044195]), + { + "class": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.182599251878196, 45.04069163407949]), + { + "class": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.156163399827415, 45.03292811948761]), + { + "class": 2, + "system:index": "24" + })]), + herbaceous = /* color: #d0741e */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.647866129015439, 45.00732805319811]), + { + "class": 3, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.63911139879083, 45.00150212185294]), + { + "class": 3, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.63859641465997, 44.995432813342106]), + { + "class": 3, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.679108499620908, 44.99688950601573]), + { + "class": 3, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.680653452013486, 44.99106251314061]), + { + "class": 3, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.616967081163876, 44.98474926892666]), + { + "class": 3, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.625550150011533, 44.984627853569535]), + { + "class": 3, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.577313303087704, 44.99968139680247]), + { + "class": 3, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.682183386109417, 45.11939912570097]), + { + "class": 3, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.662270666382854, 45.142166966714186]), + { + "class": 3, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.655747534058635, 45.14483069451677]), + { + "class": 3, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.602875829957073, 45.13926093989158]), + { + "class": 3, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.57849991442973, 45.14265129011751]), + { + "class": 3, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.56476700427348, 45.14047180240153]), + { + "class": 3, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.55652725817973, 45.11794555067206]), + { + "class": 3, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.511208654664104, 45.12666644539884]), + { + "class": 3, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.601502538941448, 45.15887374651922]), + { + "class": 3, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.770417333863323, 45.15378959281897]), + { + "class": 3, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.706286368107783, 45.13319818507588]), + { + "class": 3, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.704827246403681, 45.13574123701328]), + { + "class": 3, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.699248251652705, 45.13955560228794]), + { + "class": 3, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.688776907658564, 45.13598342652142]), + { + "class": 3, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.688519415593134, 45.130655019734995]), + { + "class": 3, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.653500494694697, 45.13997940490131]), + { + "class": 3, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.67341321442126, 45.12260091467352]), + { + "class": 3, + "system:index": "24" + })]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F2.1 Interpreting an Image: Classification +// Checkpoint: F21a +// Author: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create an Earth Engine Point object over Milan. +var pt = ee.Geometry.Point([9.453, 45.424]); + +// Filter the Landsat 8 collection and select the least cloudy image. +var landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(pt) + .filterDate('2019-01-01', '2020-01-01') + .sort('CLOUD_COVER') + .first(); + +// Center the map on that image. +Map.centerObject(landsat, 8); + +// Add Landsat image to the map. +var visParams = { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 7000, + max: 12000 +}; +Map.addLayer(landsat, visParams, 'Landsat 8 image'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21a Checkpoint.py b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21a Checkpoint.py new file mode 100644 index 0000000..f8d400c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21a Checkpoint.py @@ -0,0 +1,643 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +forest = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.414318330642528, 44.573441859314016]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.427705541156865, 44.58422671008443]), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.400411382221318, 44.59498464279749]), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.427190557026005, 44.600607315157376]), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.427018895649052, 44.571877083168374]), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.352346196674443, 44.56062563530188]), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.584676704909665, 44.528474349106816]), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.568368874099118, 44.53899788426392]), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.557210884597165, 44.534470549891495]), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.563219032790524, 44.508523361153955]), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.652654610183102, 44.530799479832886]), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.691499968871002, 44.50146601530913]), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.67055728088272, 44.502567915176314]), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.4990172743743]), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.48285300484169]), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.65733935485733, 44.482118158872886]), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.605325957640533, 44.49448683251806]), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.592108031615142, 44.47342177876237]), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.69252993713272, 44.47084936162859]), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.738535186156158, 44.48922128217961]), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.80740370242143, 44.44605496001787]), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.759338516874555, 44.4477706457772]), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.753158707304243, 44.45120186611758]), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.622735604942841, 44.17490267165223]), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.514245614708466, 44.1906597047536]), + { + "class": 0, + "system:index": "24" + })]), +developed = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.19467878610836, 45.46435783697627]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.203090193579063, 45.464899612733554]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.204463484594688, 45.462852876998106]), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.180087569067345, 45.458879589622896]), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.18068838388668, 45.45641119434588]), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.167642119238243, 45.455267267211944]), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.165668013403282, 45.45340080996563]), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.167556288549767, 45.45135365679475]), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.167813780615196, 45.46297327527481]), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.176911833593712, 45.46706666369604]), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.223853948611414, 45.47248322583851]), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.242822530764734, 45.47537221988128]), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.211236837405359, 45.47729813363197]), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.203597906130945, 45.47669629265562]), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.154784524052499, 45.18401973624338]), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.158217751591561, 45.185713605296485]), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.156057754172835, 45.18958733293765]), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.160520949973616, 45.19122054778279]), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.158289352073226, 45.19599894427136]), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.144728103293929, 45.194063439607106]), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.145843902244124, 45.192914202565674]), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.138548293723616, 45.19019223278913]), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.144470611228499, 45.17924255060339]), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.180176177634749, 45.18347748407685]), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.177257934226546, 45.18626026884151]), + { + "class": 1, + "system:index": "24" + })]), +water = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.980378415331183, 43.953687197631126]), + { + "class": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.735932614549933, 44.00704943549187]), + { + "class": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.461274411424933, 44.12546046543348]), + { + "class": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.282746579393683, 44.235763707116455]), + { + "class": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([10.068269040331183, 43.94775509959863]), + { + "class": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([10.202851559862433, 43.765549960385265]), + { + "class": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([10.178132321581183, 43.72785127863614]), + { + "class": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([10.213837887987433, 43.6821842672651]), + { + "class": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([10.065522458299933, 43.72586647981521]), + { + "class": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.941926266893683, 43.894339574154564]), + { + "class": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.88486387395865, 45.077069068166345]), + { + "class": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.848471662044588, 45.09864207259974]), + { + "class": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.81448270940787, 45.0773115067334]), + { + "class": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.828902265071932, 45.06179336476103]), + { + "class": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.95455839300162, 45.11657297387295]), + { + "class": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([10.002623578548494, 45.115603879971225]), + { + "class": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([10.02322294378287, 45.10276183206325]), + { + "class": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([10.043822309017244, 45.07149269722714]), + { + "class": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([10.248517220628196, 45.02613418018433]), + { + "class": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([10.263280099046165, 45.01836869065415]), + { + "class": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([10.280102913987571, 45.006475743526394]), + { + "class": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([10.265340035569603, 45.03802304474337]), + { + "class": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([10.220021432053978, 45.023222245044195]), + { + "class": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.182599251878196, 45.04069163407949]), + { + "class": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.156163399827415, 45.03292811948761]), + { + "class": 2, + "system:index": "24" + })]), +herbaceous = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.647866129015439, 45.00732805319811]), + { + "class": 3, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.63911139879083, 45.00150212185294]), + { + "class": 3, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.63859641465997, 44.995432813342106]), + { + "class": 3, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.679108499620908, 44.99688950601573]), + { + "class": 3, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.680653452013486, 44.99106251314061]), + { + "class": 3, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.616967081163876, 44.98474926892666]), + { + "class": 3, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.625550150011533, 44.984627853569535]), + { + "class": 3, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.577313303087704, 44.99968139680247]), + { + "class": 3, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.682183386109417, 45.11939912570097]), + { + "class": 3, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.662270666382854, 45.142166966714186]), + { + "class": 3, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.655747534058635, 45.14483069451677]), + { + "class": 3, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.602875829957073, 45.13926093989158]), + { + "class": 3, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.57849991442973, 45.14265129011751]), + { + "class": 3, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.56476700427348, 45.14047180240153]), + { + "class": 3, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.55652725817973, 45.11794555067206]), + { + "class": 3, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.511208654664104, 45.12666644539884]), + { + "class": 3, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.601502538941448, 45.15887374651922]), + { + "class": 3, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.770417333863323, 45.15378959281897]), + { + "class": 3, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.706286368107783, 45.13319818507588]), + { + "class": 3, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.704827246403681, 45.13574123701328]), + { + "class": 3, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.699248251652705, 45.13955560228794]), + { + "class": 3, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.688776907658564, 45.13598342652142]), + { + "class": 3, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.688519415593134, 45.130655019734995]), + { + "class": 3, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.653500494694697, 45.13997940490131]), + { + "class": 3, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.67341321442126, 45.12260091467352]), + { + "class": 3, + "system:index": "24" + })]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F2.1 Interpreting an Image: Classification +# Checkpoint: F21a +# Author: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Create an Earth Engine Point object over Milan. +pt = ee.Geometry.Point([9.453, 45.424]) + +# Filter the Landsat 8 collection and select the least cloudy image. +landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(pt) \ + .filterDate('2019-01-01', '2020-01-01') \ + .sort('CLOUD_COVER') \ + .first() + +# Center the map on that image. +Map.centerObject(landsat, 8) + +# Add Landsat image to the map. +visParams = { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 7000, + 'max': 12000 +} +Map.addLayer(landsat, visParams, 'Landsat 8 image') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21b Checkpoint.ipynb new file mode 100644 index 0000000..85f8360 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21b Checkpoint.ipynb @@ -0,0 +1,792 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "forest = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.414318330642528, 44.573441859314016]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427705541156865, 44.58422671008443]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.400411382221318, 44.59498464279749]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427190557026005, 44.600607315157376]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427018895649052, 44.571877083168374]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.352346196674443, 44.56062563530188]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.584676704909665, 44.528474349106816]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.568368874099118, 44.53899788426392]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.557210884597165, 44.534470549891495]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.563219032790524, 44.508523361153955]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.652654610183102, 44.530799479832886]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.691499968871002, 44.50146601530913]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.67055728088272, 44.502567915176314]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.668154021605377, 44.4990172743743]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.668154021605377, 44.48285300484169]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.65733935485733, 44.482118158872886]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.605325957640533, 44.49448683251806]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.592108031615142, 44.47342177876237]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.69252993713272, 44.47084936162859]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.738535186156158, 44.48922128217961]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.80740370242143, 44.44605496001787]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.759338516874555, 44.4477706457772]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.753158707304243, 44.45120186611758]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.622735604942841, 44.17490267165223]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.514245614708466, 44.1906597047536]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"24\"\n", + " })]),\n", + "developed = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.19467878610836, 45.46435783697627]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.203090193579063, 45.464899612733554]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.204463484594688, 45.462852876998106]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.180087569067345, 45.458879589622896]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.18068838388668, 45.45641119434588]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167642119238243, 45.455267267211944]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.165668013403282, 45.45340080996563]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167556288549767, 45.45135365679475]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167813780615196, 45.46297327527481]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.176911833593712, 45.46706666369604]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.223853948611414, 45.47248322583851]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.242822530764734, 45.47537221988128]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.211236837405359, 45.47729813363197]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.203597906130945, 45.47669629265562]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.154784524052499, 45.18401973624338]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.158217751591561, 45.185713605296485]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.156057754172835, 45.18958733293765]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.160520949973616, 45.19122054778279]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.158289352073226, 45.19599894427136]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.144728103293929, 45.194063439607106]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.145843902244124, 45.192914202565674]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.138548293723616, 45.19019223278913]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.144470611228499, 45.17924255060339]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.180176177634749, 45.18347748407685]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.177257934226546, 45.18626026884151]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"24\"\n", + " })]),\n", + "water = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.980378415331183, 43.953687197631126]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.735932614549933, 44.00704943549187]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.461274411424933, 44.12546046543348]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.282746579393683, 44.235763707116455]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.068269040331183, 43.94775509959863]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.202851559862433, 43.765549960385265]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.178132321581183, 43.72785127863614]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.213837887987433, 43.6821842672651]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.065522458299933, 43.72586647981521]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.941926266893683, 43.894339574154564]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.88486387395865, 45.077069068166345]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.848471662044588, 45.09864207259974]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.81448270940787, 45.0773115067334]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.828902265071932, 45.06179336476103]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.95455839300162, 45.11657297387295]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.002623578548494, 45.115603879971225]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.02322294378287, 45.10276183206325]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.043822309017244, 45.07149269722714]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.248517220628196, 45.02613418018433]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.263280099046165, 45.01836869065415]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.280102913987571, 45.006475743526394]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.265340035569603, 45.03802304474337]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.220021432053978, 45.023222245044195]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.182599251878196, 45.04069163407949]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.156163399827415, 45.03292811948761]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"24\"\n", + " })]),\n", + "herbaceous = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.647866129015439, 45.00732805319811]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.63911139879083, 45.00150212185294]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.63859641465997, 44.995432813342106]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.679108499620908, 44.99688950601573]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.680653452013486, 44.99106251314061]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.616967081163876, 44.98474926892666]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.625550150011533, 44.984627853569535]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.577313303087704, 44.99968139680247]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.682183386109417, 45.11939912570097]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.662270666382854, 45.142166966714186]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.655747534058635, 45.14483069451677]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.602875829957073, 45.13926093989158]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.57849991442973, 45.14265129011751]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.56476700427348, 45.14047180240153]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.55652725817973, 45.11794555067206]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.511208654664104, 45.12666644539884]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.601502538941448, 45.15887374651922]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.770417333863323, 45.15378959281897]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.706286368107783, 45.13319818507588]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.704827246403681, 45.13574123701328]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.699248251652705, 45.13955560228794]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.688776907658564, 45.13598342652142]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.688519415593134, 45.130655019734995]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.653500494694697, 45.13997940490131]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.67341321442126, 45.12260091467352]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"24\"\n", + " })])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F2.1 Interpreting an Image: Classification\n", + "# Checkpoint: F21b\n", + "# Author: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Create an Earth Engine Point object over Milan.\n", + "pt = ee.Geometry.Point([9.453, 45.424])\n", + "\n", + "# Filter the Landsat 8 collection and select the least cloudy image.\n", + "landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(pt) \\\n", + " .filterDate('2019-01-01', '2020-01-01') \\\n", + " .sort('CLOUD_COVER') \\\n", + " .first()\n", + "\n", + "# Center the map on that image.\n", + "Map.centerObject(landsat, 8)\n", + "\n", + "# Add Landsat image to the map.\n", + "visParams = {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 7000,\n", + " 'max': 12000\n", + "}\n", + "Map.addLayer(landsat, visParams, 'Landsat 8 image')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Combine training feature collections.\n", + "trainingFeatures = ee.FeatureCollection([\n", + " forest, developed, water, herbaceous\n", + "]).flatten()\n", + "\n", + "# Define prediction bands.\n", + "predictionBands = [\n", + " 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7',\n", + " 'ST_B10'\n", + "]\n", + "\n", + "# Sample training points.\n", + "classifierTraining = landsat.select(predictionBands) \\\n", + " .sampleRegions({\n", + " 'collection': trainingFeatures,\n", + " 'properties': ['class'],\n", + " 'scale': 30\n", + " })\n", + "\n", + "######## CART Classifier #########/\n", + "\n", + "# Train a CART Classifier.\n", + "classifier = ee.Classifier.smileCart().train({\n", + " 'features': classifierTraining,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + "})\n", + "\n", + "# Classify the Landsat image.\n", + "classified = landsat.select(predictionBands).classify(classifier)\n", + "\n", + "# Define classification image visualization parameters.\n", + "classificationVis = {\n", + " 'min': 0,\n", + " 'max': 3,\n", + " 'palette': ['589400', 'ff0000', '1a11ff', 'd0741e']\n", + "}\n", + "\n", + "# Add the classified image to the map.\n", + "Map.addLayer(classified, classificationVis, 'CART classified')\n", + "\n", + "#######/ Random Forest Classifier ##########/\n", + "\n", + "# Train RF classifier.\n", + "RFclassifier = ee.Classifier.smileRandomForest(50).train({\n", + " 'features': classifierTraining,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + "})\n", + "\n", + "# Classify Landsat image.\n", + "RFclassified = landsat.select(predictionBands).classify(\n", + " RFclassifier)\n", + "\n", + "# Add classified image to the map.\n", + "Map.addLayer(RFclassified, classificationVis, 'RF classified')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21b Checkpoint.js b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21b Checkpoint.js new file mode 100644 index 0000000..8d44069 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21b Checkpoint.js @@ -0,0 +1,700 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var forest = /* color: #589400 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.414318330642528, 44.573441859314016]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.427705541156865, 44.58422671008443]), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.400411382221318, 44.59498464279749]), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.427190557026005, 44.600607315157376]), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.427018895649052, 44.571877083168374]), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.352346196674443, 44.56062563530188]), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.584676704909665, 44.528474349106816]), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.568368874099118, 44.53899788426392]), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.557210884597165, 44.534470549891495]), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.563219032790524, 44.508523361153955]), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.652654610183102, 44.530799479832886]), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.691499968871002, 44.50146601530913]), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.67055728088272, 44.502567915176314]), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.4990172743743]), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.48285300484169]), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.65733935485733, 44.482118158872886]), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.605325957640533, 44.49448683251806]), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.592108031615142, 44.47342177876237]), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.69252993713272, 44.47084936162859]), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.738535186156158, 44.48922128217961]), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.80740370242143, 44.44605496001787]), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.759338516874555, 44.4477706457772]), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.753158707304243, 44.45120186611758]), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.622735604942841, 44.17490267165223]), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.514245614708466, 44.1906597047536]), + { + "class": 0, + "system:index": "24" + })]), + developed = /* color: #ff0000 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.19467878610836, 45.46435783697627]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.203090193579063, 45.464899612733554]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.204463484594688, 45.462852876998106]), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.180087569067345, 45.458879589622896]), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.18068838388668, 45.45641119434588]), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.167642119238243, 45.455267267211944]), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.165668013403282, 45.45340080996563]), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.167556288549767, 45.45135365679475]), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.167813780615196, 45.46297327527481]), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.176911833593712, 45.46706666369604]), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.223853948611414, 45.47248322583851]), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.242822530764734, 45.47537221988128]), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.211236837405359, 45.47729813363197]), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.203597906130945, 45.47669629265562]), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.154784524052499, 45.18401973624338]), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.158217751591561, 45.185713605296485]), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.156057754172835, 45.18958733293765]), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.160520949973616, 45.19122054778279]), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.158289352073226, 45.19599894427136]), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.144728103293929, 45.194063439607106]), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.145843902244124, 45.192914202565674]), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.138548293723616, 45.19019223278913]), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.144470611228499, 45.17924255060339]), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.180176177634749, 45.18347748407685]), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.177257934226546, 45.18626026884151]), + { + "class": 1, + "system:index": "24" + })]), + water = /* color: #1a11ff */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.980378415331183, 43.953687197631126]), + { + "class": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.735932614549933, 44.00704943549187]), + { + "class": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.461274411424933, 44.12546046543348]), + { + "class": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.282746579393683, 44.235763707116455]), + { + "class": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([10.068269040331183, 43.94775509959863]), + { + "class": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([10.202851559862433, 43.765549960385265]), + { + "class": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([10.178132321581183, 43.72785127863614]), + { + "class": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([10.213837887987433, 43.6821842672651]), + { + "class": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([10.065522458299933, 43.72586647981521]), + { + "class": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.941926266893683, 43.894339574154564]), + { + "class": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.88486387395865, 45.077069068166345]), + { + "class": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.848471662044588, 45.09864207259974]), + { + "class": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.81448270940787, 45.0773115067334]), + { + "class": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.828902265071932, 45.06179336476103]), + { + "class": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.95455839300162, 45.11657297387295]), + { + "class": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([10.002623578548494, 45.115603879971225]), + { + "class": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([10.02322294378287, 45.10276183206325]), + { + "class": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([10.043822309017244, 45.07149269722714]), + { + "class": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([10.248517220628196, 45.02613418018433]), + { + "class": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([10.263280099046165, 45.01836869065415]), + { + "class": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([10.280102913987571, 45.006475743526394]), + { + "class": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([10.265340035569603, 45.03802304474337]), + { + "class": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([10.220021432053978, 45.023222245044195]), + { + "class": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.182599251878196, 45.04069163407949]), + { + "class": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.156163399827415, 45.03292811948761]), + { + "class": 2, + "system:index": "24" + })]), + herbaceous = /* color: #d0741e */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.647866129015439, 45.00732805319811]), + { + "class": 3, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.63911139879083, 45.00150212185294]), + { + "class": 3, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.63859641465997, 44.995432813342106]), + { + "class": 3, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.679108499620908, 44.99688950601573]), + { + "class": 3, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.680653452013486, 44.99106251314061]), + { + "class": 3, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.616967081163876, 44.98474926892666]), + { + "class": 3, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.625550150011533, 44.984627853569535]), + { + "class": 3, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.577313303087704, 44.99968139680247]), + { + "class": 3, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.682183386109417, 45.11939912570097]), + { + "class": 3, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.662270666382854, 45.142166966714186]), + { + "class": 3, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.655747534058635, 45.14483069451677]), + { + "class": 3, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.602875829957073, 45.13926093989158]), + { + "class": 3, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.57849991442973, 45.14265129011751]), + { + "class": 3, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.56476700427348, 45.14047180240153]), + { + "class": 3, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.55652725817973, 45.11794555067206]), + { + "class": 3, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.511208654664104, 45.12666644539884]), + { + "class": 3, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.601502538941448, 45.15887374651922]), + { + "class": 3, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.770417333863323, 45.15378959281897]), + { + "class": 3, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.706286368107783, 45.13319818507588]), + { + "class": 3, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.704827246403681, 45.13574123701328]), + { + "class": 3, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.699248251652705, 45.13955560228794]), + { + "class": 3, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.688776907658564, 45.13598342652142]), + { + "class": 3, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.688519415593134, 45.130655019734995]), + { + "class": 3, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.653500494694697, 45.13997940490131]), + { + "class": 3, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.67341321442126, 45.12260091467352]), + { + "class": 3, + "system:index": "24" + })]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F2.1 Interpreting an Image: Classification +// Checkpoint: F21b +// Author: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create an Earth Engine Point object over Milan. +var pt = ee.Geometry.Point([9.453, 45.424]); + +// Filter the Landsat 8 collection and select the least cloudy image. +var landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(pt) + .filterDate('2019-01-01', '2020-01-01') + .sort('CLOUD_COVER') + .first(); + +// Center the map on that image. +Map.centerObject(landsat, 8); + +// Add Landsat image to the map. +var visParams = { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 7000, + max: 12000 +}; +Map.addLayer(landsat, visParams, 'Landsat 8 image'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Combine training feature collections. +var trainingFeatures = ee.FeatureCollection([ + forest, developed, water, herbaceous +]).flatten(); + +// Define prediction bands. +var predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10' +]; + +// Sample training points. +var classifierTraining = landsat.select(predictionBands) + .sampleRegions({ + collection: trainingFeatures, + properties: ['class'], + scale: 30 + }); + +//////////////// CART Classifier /////////////////// + +// Train a CART Classifier. +var classifier = ee.Classifier.smileCart().train({ + features: classifierTraining, + classProperty: 'class', + inputProperties: predictionBands +}); + +// Classify the Landsat image. +var classified = landsat.select(predictionBands).classify(classifier); + +// Define classification image visualization parameters. +var classificationVis = { + min: 0, + max: 3, + palette: ['589400', 'ff0000', '1a11ff', 'd0741e'] +}; + +// Add the classified image to the map. +Map.addLayer(classified, classificationVis, 'CART classified'); + +/////////////// Random Forest Classifier ///////////////////// + +// Train RF classifier. +var RFclassifier = ee.Classifier.smileRandomForest(50).train({ + features: classifierTraining, + classProperty: 'class', + inputProperties: predictionBands +}); + +// Classify Landsat image. +var RFclassified = landsat.select(predictionBands).classify( + RFclassifier); + +// Add classified image to the map. +Map.addLayer(RFclassified, classificationVis, 'RF classified'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21b Checkpoint.py b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21b Checkpoint.py new file mode 100644 index 0000000..1fa73e9 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21b Checkpoint.py @@ -0,0 +1,706 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +forest = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.414318330642528, 44.573441859314016]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.427705541156865, 44.58422671008443]), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.400411382221318, 44.59498464279749]), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.427190557026005, 44.600607315157376]), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.427018895649052, 44.571877083168374]), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.352346196674443, 44.56062563530188]), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.584676704909665, 44.528474349106816]), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.568368874099118, 44.53899788426392]), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.557210884597165, 44.534470549891495]), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.563219032790524, 44.508523361153955]), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.652654610183102, 44.530799479832886]), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.691499968871002, 44.50146601530913]), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.67055728088272, 44.502567915176314]), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.4990172743743]), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.48285300484169]), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.65733935485733, 44.482118158872886]), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.605325957640533, 44.49448683251806]), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.592108031615142, 44.47342177876237]), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.69252993713272, 44.47084936162859]), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.738535186156158, 44.48922128217961]), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.80740370242143, 44.44605496001787]), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.759338516874555, 44.4477706457772]), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.753158707304243, 44.45120186611758]), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.622735604942841, 44.17490267165223]), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.514245614708466, 44.1906597047536]), + { + "class": 0, + "system:index": "24" + })]), +developed = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.19467878610836, 45.46435783697627]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.203090193579063, 45.464899612733554]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.204463484594688, 45.462852876998106]), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.180087569067345, 45.458879589622896]), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.18068838388668, 45.45641119434588]), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.167642119238243, 45.455267267211944]), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.165668013403282, 45.45340080996563]), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.167556288549767, 45.45135365679475]), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.167813780615196, 45.46297327527481]), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.176911833593712, 45.46706666369604]), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.223853948611414, 45.47248322583851]), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.242822530764734, 45.47537221988128]), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.211236837405359, 45.47729813363197]), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.203597906130945, 45.47669629265562]), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.154784524052499, 45.18401973624338]), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.158217751591561, 45.185713605296485]), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.156057754172835, 45.18958733293765]), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.160520949973616, 45.19122054778279]), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.158289352073226, 45.19599894427136]), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.144728103293929, 45.194063439607106]), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.145843902244124, 45.192914202565674]), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.138548293723616, 45.19019223278913]), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.144470611228499, 45.17924255060339]), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.180176177634749, 45.18347748407685]), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.177257934226546, 45.18626026884151]), + { + "class": 1, + "system:index": "24" + })]), +water = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.980378415331183, 43.953687197631126]), + { + "class": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.735932614549933, 44.00704943549187]), + { + "class": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.461274411424933, 44.12546046543348]), + { + "class": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.282746579393683, 44.235763707116455]), + { + "class": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([10.068269040331183, 43.94775509959863]), + { + "class": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([10.202851559862433, 43.765549960385265]), + { + "class": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([10.178132321581183, 43.72785127863614]), + { + "class": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([10.213837887987433, 43.6821842672651]), + { + "class": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([10.065522458299933, 43.72586647981521]), + { + "class": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.941926266893683, 43.894339574154564]), + { + "class": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.88486387395865, 45.077069068166345]), + { + "class": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.848471662044588, 45.09864207259974]), + { + "class": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.81448270940787, 45.0773115067334]), + { + "class": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.828902265071932, 45.06179336476103]), + { + "class": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.95455839300162, 45.11657297387295]), + { + "class": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([10.002623578548494, 45.115603879971225]), + { + "class": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([10.02322294378287, 45.10276183206325]), + { + "class": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([10.043822309017244, 45.07149269722714]), + { + "class": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([10.248517220628196, 45.02613418018433]), + { + "class": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([10.263280099046165, 45.01836869065415]), + { + "class": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([10.280102913987571, 45.006475743526394]), + { + "class": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([10.265340035569603, 45.03802304474337]), + { + "class": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([10.220021432053978, 45.023222245044195]), + { + "class": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.182599251878196, 45.04069163407949]), + { + "class": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.156163399827415, 45.03292811948761]), + { + "class": 2, + "system:index": "24" + })]), +herbaceous = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.647866129015439, 45.00732805319811]), + { + "class": 3, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.63911139879083, 45.00150212185294]), + { + "class": 3, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.63859641465997, 44.995432813342106]), + { + "class": 3, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.679108499620908, 44.99688950601573]), + { + "class": 3, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.680653452013486, 44.99106251314061]), + { + "class": 3, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.616967081163876, 44.98474926892666]), + { + "class": 3, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.625550150011533, 44.984627853569535]), + { + "class": 3, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.577313303087704, 44.99968139680247]), + { + "class": 3, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.682183386109417, 45.11939912570097]), + { + "class": 3, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.662270666382854, 45.142166966714186]), + { + "class": 3, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.655747534058635, 45.14483069451677]), + { + "class": 3, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.602875829957073, 45.13926093989158]), + { + "class": 3, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.57849991442973, 45.14265129011751]), + { + "class": 3, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.56476700427348, 45.14047180240153]), + { + "class": 3, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.55652725817973, 45.11794555067206]), + { + "class": 3, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.511208654664104, 45.12666644539884]), + { + "class": 3, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.601502538941448, 45.15887374651922]), + { + "class": 3, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.770417333863323, 45.15378959281897]), + { + "class": 3, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.706286368107783, 45.13319818507588]), + { + "class": 3, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.704827246403681, 45.13574123701328]), + { + "class": 3, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.699248251652705, 45.13955560228794]), + { + "class": 3, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.688776907658564, 45.13598342652142]), + { + "class": 3, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.688519415593134, 45.130655019734995]), + { + "class": 3, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.653500494694697, 45.13997940490131]), + { + "class": 3, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.67341321442126, 45.12260091467352]), + { + "class": 3, + "system:index": "24" + })]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F2.1 Interpreting an Image: Classification +# Checkpoint: F21b +# Author: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Create an Earth Engine Point object over Milan. +pt = ee.Geometry.Point([9.453, 45.424]) + +# Filter the Landsat 8 collection and select the least cloudy image. +landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(pt) \ + .filterDate('2019-01-01', '2020-01-01') \ + .sort('CLOUD_COVER') \ + .first() + +# Center the map on that image. +Map.centerObject(landsat, 8) + +# Add Landsat image to the map. +visParams = { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 7000, + 'max': 12000 +} +Map.addLayer(landsat, visParams, 'Landsat 8 image') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Combine training feature collections. +trainingFeatures = ee.FeatureCollection([ + forest, developed, water, herbaceous +]).flatten() + +# Define prediction bands. +predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10' +] + +# Sample training points. +classifierTraining = landsat.select(predictionBands) \ + .sampleRegions({ + 'collection': trainingFeatures, + 'properties': ['class'], + 'scale': 30 + }) + +######## CART Classifier #########/ + +# Train a CART Classifier. +classifier = ee.Classifier.smileCart().train({ + 'features': classifierTraining, + 'classProperty': 'class', + 'inputProperties': predictionBands +}) + +# Classify the Landsat image. +classified = landsat.select(predictionBands).classify(classifier) + +# Define classification image visualization parameters. +classificationVis = { + 'min': 0, + 'max': 3, + 'palette': ['589400', 'ff0000', '1a11ff', 'd0741e'] +} + +# Add the classified image to the map. +Map.addLayer(classified, classificationVis, 'CART classified') + +#######/ Random Forest Classifier ##########/ + +# Train RF classifier. +RFclassifier = ee.Classifier.smileRandomForest(50).train({ + 'features': classifierTraining, + 'classProperty': 'class', + 'inputProperties': predictionBands +}) + +# Classify Landsat image. +RFclassified = landsat.select(predictionBands).classify( + RFclassifier) + +# Add classified image to the map. +Map.addLayer(RFclassified, classificationVis, 'RF classified') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21c Checkpoint.ipynb new file mode 100644 index 0000000..83628a5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21c Checkpoint.ipynb @@ -0,0 +1,815 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "forest = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.414318330642528, 44.573441859314016]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427705541156865, 44.58422671008443]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.400411382221318, 44.59498464279749]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427190557026005, 44.600607315157376]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427018895649052, 44.571877083168374]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.352346196674443, 44.56062563530188]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.584676704909665, 44.528474349106816]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.568368874099118, 44.53899788426392]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.557210884597165, 44.534470549891495]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.563219032790524, 44.508523361153955]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.652654610183102, 44.530799479832886]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.691499968871002, 44.50146601530913]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.67055728088272, 44.502567915176314]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.668154021605377, 44.4990172743743]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.668154021605377, 44.48285300484169]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.65733935485733, 44.482118158872886]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.605325957640533, 44.49448683251806]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.592108031615142, 44.47342177876237]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.69252993713272, 44.47084936162859]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.738535186156158, 44.48922128217961]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.80740370242143, 44.44605496001787]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.759338516874555, 44.4477706457772]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.753158707304243, 44.45120186611758]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.622735604942841, 44.17490267165223]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.514245614708466, 44.1906597047536]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"24\"\n", + " })]),\n", + "developed = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.19467878610836, 45.46435783697627]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.203090193579063, 45.464899612733554]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.204463484594688, 45.462852876998106]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.180087569067345, 45.458879589622896]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.18068838388668, 45.45641119434588]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167642119238243, 45.455267267211944]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.165668013403282, 45.45340080996563]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167556288549767, 45.45135365679475]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167813780615196, 45.46297327527481]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.176911833593712, 45.46706666369604]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.223853948611414, 45.47248322583851]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.242822530764734, 45.47537221988128]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.211236837405359, 45.47729813363197]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.203597906130945, 45.47669629265562]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.154784524052499, 45.18401973624338]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.158217751591561, 45.185713605296485]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.156057754172835, 45.18958733293765]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.160520949973616, 45.19122054778279]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.158289352073226, 45.19599894427136]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.144728103293929, 45.194063439607106]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.145843902244124, 45.192914202565674]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.138548293723616, 45.19019223278913]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.144470611228499, 45.17924255060339]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.180176177634749, 45.18347748407685]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.177257934226546, 45.18626026884151]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"24\"\n", + " })]),\n", + "water = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.980378415331183, 43.953687197631126]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.735932614549933, 44.00704943549187]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.461274411424933, 44.12546046543348]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.282746579393683, 44.235763707116455]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.068269040331183, 43.94775509959863]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.202851559862433, 43.765549960385265]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.178132321581183, 43.72785127863614]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.213837887987433, 43.6821842672651]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.065522458299933, 43.72586647981521]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.941926266893683, 43.894339574154564]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.88486387395865, 45.077069068166345]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.848471662044588, 45.09864207259974]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.81448270940787, 45.0773115067334]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.828902265071932, 45.06179336476103]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.95455839300162, 45.11657297387295]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.002623578548494, 45.115603879971225]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.02322294378287, 45.10276183206325]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.043822309017244, 45.07149269722714]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.248517220628196, 45.02613418018433]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.263280099046165, 45.01836869065415]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.280102913987571, 45.006475743526394]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.265340035569603, 45.03802304474337]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.220021432053978, 45.023222245044195]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.182599251878196, 45.04069163407949]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.156163399827415, 45.03292811948761]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"24\"\n", + " })]),\n", + "herbaceous = ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.647866129015439, 45.00732805319811]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.63911139879083, 45.00150212185294]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.63859641465997, 44.995432813342106]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.679108499620908, 44.99688950601573]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.680653452013486, 44.99106251314061]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.616967081163876, 44.98474926892666]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.625550150011533, 44.984627853569535]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.577313303087704, 44.99968139680247]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.682183386109417, 45.11939912570097]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.662270666382854, 45.142166966714186]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.655747534058635, 45.14483069451677]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.602875829957073, 45.13926093989158]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.57849991442973, 45.14265129011751]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.56476700427348, 45.14047180240153]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.55652725817973, 45.11794555067206]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.511208654664104, 45.12666644539884]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.601502538941448, 45.15887374651922]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.770417333863323, 45.15378959281897]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.706286368107783, 45.13319818507588]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.704827246403681, 45.13574123701328]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.699248251652705, 45.13955560228794]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.688776907658564, 45.13598342652142]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.688519415593134, 45.130655019734995]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.653500494694697, 45.13997940490131]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.67341321442126, 45.12260091467352]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"24\"\n", + " })])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F2.1 Interpreting an Image: Classification\n", + "# Checkpoint: F21c\n", + "# Author: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Create an Earth Engine Point object over Milan.\n", + "pt = ee.Geometry.Point([9.453, 45.424])\n", + "\n", + "# Filter the Landsat 8 collection and select the least cloudy image.\n", + "landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(pt) \\\n", + " .filterDate('2019-01-01', '2020-01-01') \\\n", + " .sort('CLOUD_COVER') \\\n", + " .first()\n", + "\n", + "# Center the map on that image.\n", + "Map.centerObject(landsat, 8)\n", + "\n", + "# Add Landsat image to the map.\n", + "visParams = {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 7000,\n", + " 'max': 12000\n", + "}\n", + "Map.addLayer(landsat, visParams, 'Landsat 8 image')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Combine training feature collections.\n", + "trainingFeatures = ee.FeatureCollection([\n", + " forest, developed, water, herbaceous\n", + "]).flatten()\n", + "\n", + "# Define prediction bands.\n", + "predictionBands = [\n", + " 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7',\n", + " 'ST_B10'\n", + "]\n", + "\n", + "# Sample training points.\n", + "classifierTraining = landsat.select(predictionBands) \\\n", + " .sampleRegions({\n", + " 'collection': trainingFeatures,\n", + " 'properties': ['class'],\n", + " 'scale': 30\n", + " })\n", + "\n", + "######## CART Classifier #########/\n", + "\n", + "# Train a CART Classifier.\n", + "classifier = ee.Classifier.smileCart().train({\n", + " 'features': classifierTraining,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + "})\n", + "\n", + "# Classify the Landsat image.\n", + "classified = landsat.select(predictionBands).classify(classifier)\n", + "\n", + "# Define classification image visualization parameters.\n", + "classificationVis = {\n", + " 'min': 0,\n", + " 'max': 3,\n", + " 'palette': ['589400', 'ff0000', '1a11ff', 'd0741e']\n", + "}\n", + "\n", + "# Add the classified image to the map.\n", + "Map.addLayer(classified, classificationVis, 'CART classified')\n", + "\n", + "#######/ Random Forest Classifier ##########/\n", + "\n", + "# Train RF classifier.\n", + "RFclassifier = ee.Classifier.smileRandomForest(50).train({\n", + " 'features': classifierTraining,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + "})\n", + "\n", + "# Classify Landsat image.\n", + "RFclassified = landsat.select(predictionBands).classify(\n", + " RFclassifier)\n", + "\n", + "# Add classified image to the map.\n", + "Map.addLayer(RFclassified, classificationVis, 'RF classified')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "######## Unsupervised classification ########\n", + "\n", + "# Make the training dataset.\n", + "training = landsat.sample({\n", + " 'region': landsat.geometry(),\n", + " 'scale': 30,\n", + " 'numPixels': 1000,\n", + " 'tileScale': 8\n", + "})\n", + "\n", + "# Instantiate the clusterer and train it.\n", + "clusterer = ee.Clusterer.wekaKMeans(4).train(training)\n", + "\n", + "# Cluster the input using the trained clusterer.\n", + "Kclassified = landsat.cluster(clusterer)\n", + "\n", + "# Display the clusters with random colors.\n", + "Map.addLayer(Kclassified.randomVisualizer(), {},\n", + " 'K-means classified - random colors')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21c Checkpoint.js b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21c Checkpoint.js new file mode 100644 index 0000000..2a2e333 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21c Checkpoint.js @@ -0,0 +1,723 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var forest = /* color: #589400 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.414318330642528, 44.573441859314016]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.427705541156865, 44.58422671008443]), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.400411382221318, 44.59498464279749]), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.427190557026005, 44.600607315157376]), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.427018895649052, 44.571877083168374]), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.352346196674443, 44.56062563530188]), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.584676704909665, 44.528474349106816]), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.568368874099118, 44.53899788426392]), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.557210884597165, 44.534470549891495]), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.563219032790524, 44.508523361153955]), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.652654610183102, 44.530799479832886]), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.691499968871002, 44.50146601530913]), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.67055728088272, 44.502567915176314]), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.4990172743743]), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.48285300484169]), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.65733935485733, 44.482118158872886]), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.605325957640533, 44.49448683251806]), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.592108031615142, 44.47342177876237]), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.69252993713272, 44.47084936162859]), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.738535186156158, 44.48922128217961]), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.80740370242143, 44.44605496001787]), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.759338516874555, 44.4477706457772]), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.753158707304243, 44.45120186611758]), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.622735604942841, 44.17490267165223]), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.514245614708466, 44.1906597047536]), + { + "class": 0, + "system:index": "24" + })]), + developed = /* color: #ff0000 */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.19467878610836, 45.46435783697627]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.203090193579063, 45.464899612733554]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.204463484594688, 45.462852876998106]), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.180087569067345, 45.458879589622896]), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.18068838388668, 45.45641119434588]), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.167642119238243, 45.455267267211944]), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.165668013403282, 45.45340080996563]), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.167556288549767, 45.45135365679475]), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.167813780615196, 45.46297327527481]), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.176911833593712, 45.46706666369604]), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.223853948611414, 45.47248322583851]), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.242822530764734, 45.47537221988128]), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.211236837405359, 45.47729813363197]), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.203597906130945, 45.47669629265562]), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.154784524052499, 45.18401973624338]), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.158217751591561, 45.185713605296485]), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.156057754172835, 45.18958733293765]), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.160520949973616, 45.19122054778279]), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.158289352073226, 45.19599894427136]), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.144728103293929, 45.194063439607106]), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.145843902244124, 45.192914202565674]), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.138548293723616, 45.19019223278913]), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.144470611228499, 45.17924255060339]), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.180176177634749, 45.18347748407685]), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.177257934226546, 45.18626026884151]), + { + "class": 1, + "system:index": "24" + })]), + water = /* color: #1a11ff */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.980378415331183, 43.953687197631126]), + { + "class": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.735932614549933, 44.00704943549187]), + { + "class": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.461274411424933, 44.12546046543348]), + { + "class": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.282746579393683, 44.235763707116455]), + { + "class": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([10.068269040331183, 43.94775509959863]), + { + "class": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([10.202851559862433, 43.765549960385265]), + { + "class": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([10.178132321581183, 43.72785127863614]), + { + "class": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([10.213837887987433, 43.6821842672651]), + { + "class": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([10.065522458299933, 43.72586647981521]), + { + "class": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.941926266893683, 43.894339574154564]), + { + "class": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.88486387395865, 45.077069068166345]), + { + "class": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.848471662044588, 45.09864207259974]), + { + "class": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.81448270940787, 45.0773115067334]), + { + "class": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.828902265071932, 45.06179336476103]), + { + "class": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.95455839300162, 45.11657297387295]), + { + "class": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([10.002623578548494, 45.115603879971225]), + { + "class": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([10.02322294378287, 45.10276183206325]), + { + "class": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([10.043822309017244, 45.07149269722714]), + { + "class": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([10.248517220628196, 45.02613418018433]), + { + "class": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([10.263280099046165, 45.01836869065415]), + { + "class": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([10.280102913987571, 45.006475743526394]), + { + "class": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([10.265340035569603, 45.03802304474337]), + { + "class": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([10.220021432053978, 45.023222245044195]), + { + "class": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.182599251878196, 45.04069163407949]), + { + "class": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.156163399827415, 45.03292811948761]), + { + "class": 2, + "system:index": "24" + })]), + herbaceous = /* color: #d0741e */ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.647866129015439, 45.00732805319811]), + { + "class": 3, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.63911139879083, 45.00150212185294]), + { + "class": 3, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.63859641465997, 44.995432813342106]), + { + "class": 3, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.679108499620908, 44.99688950601573]), + { + "class": 3, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.680653452013486, 44.99106251314061]), + { + "class": 3, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.616967081163876, 44.98474926892666]), + { + "class": 3, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.625550150011533, 44.984627853569535]), + { + "class": 3, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.577313303087704, 44.99968139680247]), + { + "class": 3, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.682183386109417, 45.11939912570097]), + { + "class": 3, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.662270666382854, 45.142166966714186]), + { + "class": 3, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.655747534058635, 45.14483069451677]), + { + "class": 3, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.602875829957073, 45.13926093989158]), + { + "class": 3, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.57849991442973, 45.14265129011751]), + { + "class": 3, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.56476700427348, 45.14047180240153]), + { + "class": 3, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.55652725817973, 45.11794555067206]), + { + "class": 3, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.511208654664104, 45.12666644539884]), + { + "class": 3, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.601502538941448, 45.15887374651922]), + { + "class": 3, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.770417333863323, 45.15378959281897]), + { + "class": 3, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.706286368107783, 45.13319818507588]), + { + "class": 3, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.704827246403681, 45.13574123701328]), + { + "class": 3, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.699248251652705, 45.13955560228794]), + { + "class": 3, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.688776907658564, 45.13598342652142]), + { + "class": 3, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.688519415593134, 45.130655019734995]), + { + "class": 3, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.653500494694697, 45.13997940490131]), + { + "class": 3, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.67341321442126, 45.12260091467352]), + { + "class": 3, + "system:index": "24" + })]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F2.1 Interpreting an Image: Classification +// Checkpoint: F21c +// Author: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create an Earth Engine Point object over Milan. +var pt = ee.Geometry.Point([9.453, 45.424]); + +// Filter the Landsat 8 collection and select the least cloudy image. +var landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(pt) + .filterDate('2019-01-01', '2020-01-01') + .sort('CLOUD_COVER') + .first(); + +// Center the map on that image. +Map.centerObject(landsat, 8); + +// Add Landsat image to the map. +var visParams = { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 7000, + max: 12000 +}; +Map.addLayer(landsat, visParams, 'Landsat 8 image'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Combine training feature collections. +var trainingFeatures = ee.FeatureCollection([ + forest, developed, water, herbaceous +]).flatten(); + +// Define prediction bands. +var predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10' +]; + +// Sample training points. +var classifierTraining = landsat.select(predictionBands) + .sampleRegions({ + collection: trainingFeatures, + properties: ['class'], + scale: 30 + }); + +//////////////// CART Classifier /////////////////// + +// Train a CART Classifier. +var classifier = ee.Classifier.smileCart().train({ + features: classifierTraining, + classProperty: 'class', + inputProperties: predictionBands +}); + +// Classify the Landsat image. +var classified = landsat.select(predictionBands).classify(classifier); + +// Define classification image visualization parameters. +var classificationVis = { + min: 0, + max: 3, + palette: ['589400', 'ff0000', '1a11ff', 'd0741e'] +}; + +// Add the classified image to the map. +Map.addLayer(classified, classificationVis, 'CART classified'); + +/////////////// Random Forest Classifier ///////////////////// + +// Train RF classifier. +var RFclassifier = ee.Classifier.smileRandomForest(50).train({ + features: classifierTraining, + classProperty: 'class', + inputProperties: predictionBands +}); + +// Classify Landsat image. +var RFclassified = landsat.select(predictionBands).classify( + RFclassifier); + +// Add classified image to the map. +Map.addLayer(RFclassified, classificationVis, 'RF classified'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +//////////////// Unsupervised classification //////////////// + +// Make the training dataset. +var training = landsat.sample({ + region: landsat.geometry(), + scale: 30, + numPixels: 1000, + tileScale: 8 +}); + +// Instantiate the clusterer and train it. +var clusterer = ee.Clusterer.wekaKMeans(4).train(training); + +// Cluster the input using the trained clusterer. +var Kclassified = landsat.cluster(clusterer); + +// Display the clusters with random colors. +Map.addLayer(Kclassified.randomVisualizer(), {}, + 'K-means classified - random colors'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21c Checkpoint.py b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21c Checkpoint.py new file mode 100644 index 0000000..8ebf1da --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21c Checkpoint.py @@ -0,0 +1,729 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +forest = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.414318330642528, 44.573441859314016]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.427705541156865, 44.58422671008443]), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.400411382221318, 44.59498464279749]), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.427190557026005, 44.600607315157376]), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.427018895649052, 44.571877083168374]), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.352346196674443, 44.56062563530188]), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.584676704909665, 44.528474349106816]), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.568368874099118, 44.53899788426392]), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.557210884597165, 44.534470549891495]), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.563219032790524, 44.508523361153955]), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.652654610183102, 44.530799479832886]), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.691499968871002, 44.50146601530913]), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.67055728088272, 44.502567915176314]), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.4990172743743]), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.48285300484169]), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.65733935485733, 44.482118158872886]), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.605325957640533, 44.49448683251806]), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.592108031615142, 44.47342177876237]), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.69252993713272, 44.47084936162859]), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.738535186156158, 44.48922128217961]), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.80740370242143, 44.44605496001787]), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.759338516874555, 44.4477706457772]), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.753158707304243, 44.45120186611758]), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.622735604942841, 44.17490267165223]), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.514245614708466, 44.1906597047536]), + { + "class": 0, + "system:index": "24" + })]), +developed = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.19467878610836, 45.46435783697627]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.203090193579063, 45.464899612733554]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.204463484594688, 45.462852876998106]), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.180087569067345, 45.458879589622896]), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.18068838388668, 45.45641119434588]), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.167642119238243, 45.455267267211944]), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.165668013403282, 45.45340080996563]), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.167556288549767, 45.45135365679475]), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.167813780615196, 45.46297327527481]), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.176911833593712, 45.46706666369604]), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.223853948611414, 45.47248322583851]), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.242822530764734, 45.47537221988128]), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.211236837405359, 45.47729813363197]), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.203597906130945, 45.47669629265562]), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.154784524052499, 45.18401973624338]), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.158217751591561, 45.185713605296485]), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.156057754172835, 45.18958733293765]), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.160520949973616, 45.19122054778279]), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.158289352073226, 45.19599894427136]), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.144728103293929, 45.194063439607106]), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.145843902244124, 45.192914202565674]), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.138548293723616, 45.19019223278913]), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.144470611228499, 45.17924255060339]), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.180176177634749, 45.18347748407685]), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.177257934226546, 45.18626026884151]), + { + "class": 1, + "system:index": "24" + })]), +water = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.980378415331183, 43.953687197631126]), + { + "class": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.735932614549933, 44.00704943549187]), + { + "class": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.461274411424933, 44.12546046543348]), + { + "class": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.282746579393683, 44.235763707116455]), + { + "class": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([10.068269040331183, 43.94775509959863]), + { + "class": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([10.202851559862433, 43.765549960385265]), + { + "class": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([10.178132321581183, 43.72785127863614]), + { + "class": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([10.213837887987433, 43.6821842672651]), + { + "class": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([10.065522458299933, 43.72586647981521]), + { + "class": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.941926266893683, 43.894339574154564]), + { + "class": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.88486387395865, 45.077069068166345]), + { + "class": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.848471662044588, 45.09864207259974]), + { + "class": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.81448270940787, 45.0773115067334]), + { + "class": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.828902265071932, 45.06179336476103]), + { + "class": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.95455839300162, 45.11657297387295]), + { + "class": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([10.002623578548494, 45.115603879971225]), + { + "class": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([10.02322294378287, 45.10276183206325]), + { + "class": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([10.043822309017244, 45.07149269722714]), + { + "class": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([10.248517220628196, 45.02613418018433]), + { + "class": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([10.263280099046165, 45.01836869065415]), + { + "class": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([10.280102913987571, 45.006475743526394]), + { + "class": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([10.265340035569603, 45.03802304474337]), + { + "class": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([10.220021432053978, 45.023222245044195]), + { + "class": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.182599251878196, 45.04069163407949]), + { + "class": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.156163399827415, 45.03292811948761]), + { + "class": 2, + "system:index": "24" + })]), +herbaceous = ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.647866129015439, 45.00732805319811]), + { + "class": 3, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.63911139879083, 45.00150212185294]), + { + "class": 3, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.63859641465997, 44.995432813342106]), + { + "class": 3, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.679108499620908, 44.99688950601573]), + { + "class": 3, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.680653452013486, 44.99106251314061]), + { + "class": 3, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.616967081163876, 44.98474926892666]), + { + "class": 3, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.625550150011533, 44.984627853569535]), + { + "class": 3, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.577313303087704, 44.99968139680247]), + { + "class": 3, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.682183386109417, 45.11939912570097]), + { + "class": 3, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.662270666382854, 45.142166966714186]), + { + "class": 3, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.655747534058635, 45.14483069451677]), + { + "class": 3, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.602875829957073, 45.13926093989158]), + { + "class": 3, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.57849991442973, 45.14265129011751]), + { + "class": 3, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.56476700427348, 45.14047180240153]), + { + "class": 3, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.55652725817973, 45.11794555067206]), + { + "class": 3, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.511208654664104, 45.12666644539884]), + { + "class": 3, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.601502538941448, 45.15887374651922]), + { + "class": 3, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.770417333863323, 45.15378959281897]), + { + "class": 3, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.706286368107783, 45.13319818507588]), + { + "class": 3, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.704827246403681, 45.13574123701328]), + { + "class": 3, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.699248251652705, 45.13955560228794]), + { + "class": 3, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.688776907658564, 45.13598342652142]), + { + "class": 3, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.688519415593134, 45.130655019734995]), + { + "class": 3, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.653500494694697, 45.13997940490131]), + { + "class": 3, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.67341321442126, 45.12260091467352]), + { + "class": 3, + "system:index": "24" + })]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F2.1 Interpreting an Image: Classification +# Checkpoint: F21c +# Author: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Create an Earth Engine Point object over Milan. +pt = ee.Geometry.Point([9.453, 45.424]) + +# Filter the Landsat 8 collection and select the least cloudy image. +landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(pt) \ + .filterDate('2019-01-01', '2020-01-01') \ + .sort('CLOUD_COVER') \ + .first() + +# Center the map on that image. +Map.centerObject(landsat, 8) + +# Add Landsat image to the map. +visParams = { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 7000, + 'max': 12000 +} +Map.addLayer(landsat, visParams, 'Landsat 8 image') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Combine training feature collections. +trainingFeatures = ee.FeatureCollection([ + forest, developed, water, herbaceous +]).flatten() + +# Define prediction bands. +predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10' +] + +# Sample training points. +classifierTraining = landsat.select(predictionBands) \ + .sampleRegions({ + 'collection': trainingFeatures, + 'properties': ['class'], + 'scale': 30 + }) + +######## CART Classifier #########/ + +# Train a CART Classifier. +classifier = ee.Classifier.smileCart().train({ + 'features': classifierTraining, + 'classProperty': 'class', + 'inputProperties': predictionBands +}) + +# Classify the Landsat image. +classified = landsat.select(predictionBands).classify(classifier) + +# Define classification image visualization parameters. +classificationVis = { + 'min': 0, + 'max': 3, + 'palette': ['589400', 'ff0000', '1a11ff', 'd0741e'] +} + +# Add the classified image to the map. +Map.addLayer(classified, classificationVis, 'CART classified') + +#######/ Random Forest Classifier ##########/ + +# Train RF classifier. +RFclassifier = ee.Classifier.smileRandomForest(50).train({ + 'features': classifierTraining, + 'classProperty': 'class', + 'inputProperties': predictionBands +}) + +# Classify Landsat image. +RFclassified = landsat.select(predictionBands).classify( + RFclassifier) + +# Add classified image to the map. +Map.addLayer(RFclassified, classificationVis, 'RF classified') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +######## Unsupervised classification ######## + +# Make the training dataset. +training = landsat.sample({ + 'region': landsat.geometry(), + 'scale': 30, + 'numPixels': 1000, + 'tileScale': 8 +}) + +# Instantiate the clusterer and train it. +clusterer = ee.Clusterer.wekaKMeans(4).train(training) + +# Cluster the input using the trained clusterer. +Kclassified = landsat.cluster(clusterer) + +# Display the clusters with random colors. +Map.addLayer(Kclassified.randomVisualizer(), {}, + 'K-means classified - random colors') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21s1 Assignment 6.ipynb b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21s1 Assignment 6.ipynb new file mode 100644 index 0000000..f5135f6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21s1 Assignment 6.ipynb @@ -0,0 +1,2612 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "forest =\n", + "\n", + " # shown: False #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.414318330642528, 44.573441859314016]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427705541156865, 44.58422671008443]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.400411382221318, 44.59498464279749]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427190557026005, 44.600607315157376]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.427018895649052, 44.571877083168374]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.352346196674443, 44.56062563530188]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.584676704909665, 44.528474349106816]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.568368874099118, 44.53899788426392]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.557210884597165, 44.534470549891495]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.563219032790524, 44.508523361153955]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.652654610183102, 44.530799479832886]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.691499968871002, 44.50146601530913]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.67055728088272, 44.502567915176314]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.668154021605377, 44.4990172743743]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.668154021605377, 44.48285300484169]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.65733935485733, 44.482118158872886]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.605325957640533, 44.49448683251806]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.592108031615142, 44.47342177876237]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.69252993713272, 44.47084936162859]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.738535186156158, 44.48922128217961]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.80740370242143, 44.44605496001787]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.759338516874555, 44.4477706457772]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.753158707304243, 44.45120186611758]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.622735604942841, 44.17490267165223]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.514245614708466, 44.1906597047536]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.042922670006837, 44.30621875527554]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.043609315514649, 44.2880350593344]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.068328553795899, 44.27181241762688]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.114333802819337, 44.28017009547173]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.109527284264649, 44.29393309121647]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.090301210045899, 44.32439682017676]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.887397462487305, 44.283119580315365]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.849975282311524, 44.30277902847262]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.868171388268555, 44.26812482891884]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.920699769616212, 44.233696177590424]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.974944764733399, 44.26738728341367]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.980437928795899, 44.27549977497149]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.955375367760743, 44.32439682017676]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.418427521884842, 44.38209136110383]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.411904389560624, 44.37767453815662]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.40126138418953, 44.37522060365833]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.386841828525467, 44.3720303350693]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.374825532138749, 44.375711398784944]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.407441193759842, 44.36577199572992]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.419800812900467, 44.378410698452875]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.402634675205155, 44.39190533029205]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.430787141025467, 44.39607576894639]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.456364686191483, 44.40110443203785]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.491555268466874, 44.40147236602735]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.52760415762703, 44.39656638924877]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"49\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.518334443271561, 44.375711398784944]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"50\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.54408364981453, 44.376447583762115]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"51\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.362465912998124, 44.38515840322767]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"52\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.150727904135598, 44.58657203242108]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"53\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.069360411459817, 44.593906906576656]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"54\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.087556517416848, 44.55966957437203]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"55\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([8.995546019369973, 44.57874714637613]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"56\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([8.969453490073098, 44.600751953971006]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"57\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.07004705696763, 44.54988377686661]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"58\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.08549658089341, 44.524188229078355]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"59\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.123262083823098, 44.53250993354593]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"60\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.12669531136216, 44.52125087305466]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"61\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.101289427573098, 44.5117034431649]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"62\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.001725828940286, 44.52002693100144]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"63\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.048761046225442, 44.579480774182784]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"64\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.097856200034036, 44.58119253640071]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"65\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.232438719565286, 44.577279862993244]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"66\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.25303808479966, 44.592195518735345]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"67\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.930848996624745, 44.05820855928862]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"68\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.961061398968495, 44.034518385008376]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"69\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.950075070843495, 44.10753265821489]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"70\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.88278381107787, 44.1233076844616]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"71\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.72348205326537, 44.02069474136502]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"72\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.669923703655995, 43.99995323119841]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"73\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.64383117435912, 43.97821625026472]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"74\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.737204832742563, 45.20169532981405]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"75\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.736861509988657, 45.19903426034426]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"76\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.74029473752772, 45.1974012697325]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"77\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.742955488870493, 45.196614998278925]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"78\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.746560377786508, 45.196191616842306]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"79\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.749221129129282, 45.199094740578026]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"80\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.751109404275766, 45.20242105443272]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"81\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.752053541849008, 45.20441674940112]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"82\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.740638060281626, 45.207017095376]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"83\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.738063139627329, 45.20508196549987]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"84\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.74029473752772, 45.20302581787672]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"85\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.73454408139979, 45.20133246403324]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"86\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.728624023302768, 43.74014883100581]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"87\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.738923705919955, 43.73717221940949]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"88\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.716951049669955, 43.731714713822]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"89\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.732743896349643, 43.75478168565866]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"90\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.768106140001986, 43.776352419327765]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"91\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.77600256334183, 43.670656005581066]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"92\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.573442138537143, 43.74436544412549]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"93\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.560395873888705, 43.74758971259468]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"94\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.555246032580111, 43.76767547313776]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"95\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.53430334459183, 43.77065056793546]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"96\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.642793334826205, 43.68555410716658]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"97\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.717637695177768, 43.72501618629434]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"98\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.735147155626986, 43.7535417519611]),\n", + " {\n", + " \"class\": 0,\n", + " \"system:index\": \"99\"\n", + " })]),\n", + " developed =\n", + "\n", + " # shown: False #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.19467878610836, 45.46435783697627]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.203090193579063, 45.464899612733554]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.204463484594688, 45.462852876998106]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.180087569067345, 45.458879589622896]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.18068838388668, 45.45641119434588]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167642119238243, 45.455267267211944]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.165668013403282, 45.45340080996563]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167556288549767, 45.45135365679475]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.167813780615196, 45.46297327527481]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.176911833593712, 45.46706666369604]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.223853948611414, 45.47248322583851]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.242822530764734, 45.47537221988128]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.211236837405359, 45.47729813363197]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.203597906130945, 45.47669629265562]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.154784524052499, 45.18401973624338]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.158217751591561, 45.185713605296485]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.156057754172835, 45.18958733293765]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.160520949973616, 45.19122054778279]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.158289352073226, 45.19599894427136]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.144728103293929, 45.194063439607106]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.145843902244124, 45.192914202565674]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.138548293723616, 45.19019223278913]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.144470611228499, 45.17924255060339]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.180176177634749, 45.18347748407685]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.177257934226546, 45.18626026884151]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.78698889146683, 43.71211320778847]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.789392150744174, 43.71285768592188]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.809304870470736, 43.72625671087301]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.839517272814486, 43.69486354220674]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.848100341662143, 43.692877650647986]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.801408447130893, 43.68816089463136]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.792825378283236, 43.68580237752021]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.793855346544955, 43.681705785290106]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.744760192736361, 43.69945566455851]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.757978118761752, 43.708142501552466]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.752313293322299, 43.711368720406874]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.747335113390658, 43.71633179492939]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.756433166369174, 43.72414780380379]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.75729147325394, 43.722659118819244]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.782697357043002, 43.73121855228781]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.101396448196057, 44.02806798391265]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.142938501418714, 44.03831132632035]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.131265527785901, 44.04386420551437]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.073930627883557, 44.03954534445121]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.059682733596448, 44.049169803814]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.034448511184339, 44.04028574299332]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.028955347121839, 44.04818275173984]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.109121210158948, 44.01374902094095]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.103628046096448, 44.01103296542014]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.090238458694104, 44.022143315216184]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"49\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.080797082961682, 44.04386420551437]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"50\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.064832574905042, 44.03497934899128]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"51\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.329484511360473, 44.80057754997864]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"52\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.337380934700317, 44.79485244645107]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"53\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.330514479622192, 44.79911587541933]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"54\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.317296553596801, 44.802160988964836]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"55\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.318498183235473, 44.79984671732763]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"56\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.300988722786254, 44.80313539135592]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"57\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.357636977180785, 44.808616098157394]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"58\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.35351710413391, 44.79034505045052]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"59\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.34408578523026, 44.79250875336787]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"60\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.335202308972935, 44.79025500784725]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"61\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.337519737561802, 44.78663055684301]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"62\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.326662155469517, 44.791625539258725]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"63\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.68779982182756, 45.05295255153792]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"64\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.693636308643967, 45.05076963745494]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"65\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.700502763722092, 45.04907175778813]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"66\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.764360795948654, 45.02845062567073]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"67\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.738954912159592, 45.04446297319648]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"68\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.731401811573654, 45.05125473667368]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"69\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.734835039112717, 45.03378857269489]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"70\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.695696245167404, 45.041066789045686]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"71\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.670977006886154, 45.04397781637543]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"72\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.71002997014299, 45.03529497150581]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"73\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.699472795460373, 45.0422091170089]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"74\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.730543504688889, 45.04396784528239]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"75\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.727453599903733, 45.044028490120596]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"76\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.728741060230881, 45.04912242702095]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"77\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.673637758228928, 45.042936873196716]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"78\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.68007505986467, 45.03772108261854]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"79\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.681019197437912, 45.036811303005315]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"80\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.693378816578537, 45.03420318794656]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"81\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.695953737232834, 45.03311138355789]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"82\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.928861454431917, 44.645179237899704]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"83\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.926114872400667, 44.645179237899704]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"84\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.922509983484652, 44.64652267753729]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"85\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.931264713709261, 44.63724009583039]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"86\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.950061634485628, 44.6343084456789]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"87\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.953924015467074, 44.63797298522629]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"88\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.922424152796175, 44.631376647419025]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"89\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.923110798303988, 44.63308688106989]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"90\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.91255362362137, 44.64383576714894]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"91\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.908347919886019, 44.64481283987146]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"92\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.900108173792269, 44.647621832280535]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"93\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.909463718836214, 44.63724009583039]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"94\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.93504126400223, 44.626978672326416]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"95\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.982591465418245, 44.63711794669777]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"96\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.988256290857699, 44.63479706432279]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"97\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.992290333216097, 44.63290364416077]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"98\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.992548194323003, 44.632782655700204]),\n", + " {\n", + " \"class\": 1,\n", + " \"system:index\": \"99\"\n", + " })]),\n", + " water =\n", + "\n", + " # shown: False #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.980378415331183, 43.953687197631126]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.735932614549933, 44.00704943549187]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.461274411424933, 44.12546046543348]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.282746579393683, 44.235763707116455]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.068269040331183, 43.94775509959863]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.202851559862433, 43.765549960385265]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.178132321581183, 43.72785127863614]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.213837887987433, 43.6821842672651]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.065522458299933, 43.72586647981521]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.941926266893683, 43.894339574154564]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.88486387395865, 45.077069068166345]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.848471662044588, 45.09864207259974]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.81448270940787, 45.0773115067334]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.828902265071932, 45.06179336476103]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.95455839300162, 45.11657297387295]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.002623578548494, 45.115603879971225]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.02322294378287, 45.10276183206325]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.043822309017244, 45.07149269722714]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.248517220628196, 45.02613418018433]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.263280099046165, 45.01836869065415]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.280102913987571, 45.006475743526394]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.265340035569603, 45.03802304474337]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.220021432053978, 45.023222245044195]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.182599251878196, 45.04069163407949]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.156163399827415, 45.03292811948761]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.98911496678394, 44.644081206444866]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.988943305406988, 44.64285984756699]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.987484183702886, 44.641821672303635]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.987741675768316, 44.63919561665319]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.990659919176519, 44.63748556302968]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.984823432360113, 44.62844587093865]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.990316596422613, 44.626857671514365]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.026050685338417, 45.051974176463936]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.063816188268104, 45.04372703391621]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.12286770193998, 45.068464894331655]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.19427883475248, 45.05779497293618]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.260883449010292, 45.05585477327662]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.262256740025917, 45.03014091290893]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.321308253697792, 44.99907480907841]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.358387111119667, 44.98402110649786]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.869495509557167, 45.06119016393412]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.805637477330604, 45.04372703391621]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.756885646275917, 45.04566764502083]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.184665797643104, 45.21328137697889]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([11.014377711705604, 45.22392224246559]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.656680360814072, 44.9558559658398]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.636424318333603, 44.94249200515986]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.62749792673204, 44.926208067303]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.537547365208603, 44.912350932821255]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.50218512155626, 44.921103196045436]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"49\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.428370729466415, 44.96071481644557]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"50\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.405711427708603, 44.98718832057907]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"51\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.380992189427353, 44.9789318417816]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"52\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.475062623997665, 44.93568733902074]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"53\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.464568669294943, 45.424644452593405]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"54\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.458217198347677, 45.41536673223165]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"55\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.463710362410177, 45.407172153109734]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"56\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.459933812117209, 45.39584239478833]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"57\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.46439700791799, 45.3902972170168]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"58\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.454783970808615, 45.4118721306585]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"59\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.481048161482443, 45.43584797837749]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"60\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.469203526472677, 45.43102953016216]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"61\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.283229596846958, 45.48773969818685]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"62\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.27842307829227, 45.48846176503586]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"63\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.27842307829227, 45.50602920541026]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"64\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.274646527999302, 45.41596826492388]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"65\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.041187055343052, 45.219455970317355]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"66\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.058009870284458, 45.21897229982002]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"67\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.077579267257114, 45.20228314814136]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"68\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.085475690596958, 45.196235145464364]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"69\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.175769574874302, 45.16792194842297]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"70\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.20426536344852, 45.16332274987339]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"71\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.213878400557896, 45.141774192169606]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"72\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.21628165983524, 45.15121782146389]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"73\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.222804792159458, 45.14371147444317]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"74\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.255763776534458, 45.136446326478705]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"75\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.313441999190708, 45.12167100406328]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"76\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.151736982100864, 45.12142875377629]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"77\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.105045087569614, 45.10374170456197]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"78\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.07071281217899, 45.09622910773991]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"79\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.38107658171024, 45.10010670050038]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"80\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.406482465499302, 45.093078369729355]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"81\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.424335248702427, 45.09089698773592]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"82\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.399529842312088, 44.059942165310375]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"83\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([8.877679256374588, 44.17036779637155]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"84\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.355584529812088, 43.96512739709022]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"85\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.064446834499588, 44.22550322825024]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"86\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.053460506374588, 44.15460533997702]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"87\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.597283748562088, 43.88995820658324]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"88\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.204020885402908, 44.67242037723368]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"89\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.200415996486893, 44.66991778726374]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"90\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.198699382717361, 44.668513848016225]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"91\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.195094493801346, 44.666072133544375]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"92\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.192862895900955, 44.66472914674318]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"93\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.18874302285408, 44.66283670344126]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"94\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.185309795315018, 44.66045579992672]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"95\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.090552715236893, 44.69024057554722]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"96\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.884559062893143, 44.6882879445253]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"97\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.091239360744705, 44.687555690920945]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"98\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.085917858059158, 44.682429656495245]),\n", + " {\n", + " \"class\": 2,\n", + " \"system:index\": \"99\"\n", + " })]),\n", + " herbaceous =\n", + "\n", + " # shown: False #\n", + " ee.FeatureCollection(\n", + " [ee.Feature(\n", + " ee.Geometry.Point([9.647866129015439, 45.00732805319811]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"0\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.63911139879083, 45.00150212185294]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"1\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.63859641465997, 44.995432813342106]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"2\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.679108499620908, 44.99688950601573]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"3\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.680653452013486, 44.99106251314061]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"4\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.616967081163876, 44.98474926892666]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"5\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.625550150011533, 44.984627853569535]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"6\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.577313303087704, 44.99968139680247]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"7\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.682183386109417, 45.11939912570097]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"8\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.662270666382854, 45.142166966714186]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"9\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.655747534058635, 45.14483069451677]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"10\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.602875829957073, 45.13926093989158]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"11\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.57849991442973, 45.14265129011751]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"12\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.56476700427348, 45.14047180240153]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"13\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.55652725817973, 45.11794555067206]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"14\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.511208654664104, 45.12666644539884]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"15\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.601502538941448, 45.15887374651922]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"16\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.770417333863323, 45.15378959281897]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"17\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.706286368107783, 45.13319818507588]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"18\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.704827246403681, 45.13574123701328]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"19\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.699248251652705, 45.13955560228794]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"20\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.688776907658564, 45.13598342652142]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"21\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.688519415593134, 45.130655019734995]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"22\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.653500494694697, 45.13997940490131]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"23\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.67341321442126, 45.12260091467352]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"24\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.7573680083494, 44.76085711753607]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"25\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.787065426562291, 44.77743157501226]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"26\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.805604855273229, 44.78193997941965]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"27\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.800111691210729, 44.782914723275496]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"28\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.801484982226354, 44.78206182330164]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"29\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.701234738085729, 44.76743872144162]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"30\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.706727902148229, 44.77036363804527]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"31\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.716512600634557, 44.77060737440978]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"32\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.714281002734166, 44.773775853547704]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"33\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.724237362597448, 44.78133075615248]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"34\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.686300198290807, 44.778650097404636]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"35\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.69797317192362, 44.78474232364748]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"36\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.726983944628698, 44.74257095015713]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"37\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.732305447314245, 44.750617576606686]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"38\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.73367873832987, 44.749886111397124]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"39\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.747926632616979, 44.74842315320647]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"40\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.800111691210729, 44.74915463693038]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"41\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.840967098925573, 44.745740967018534]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"42\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.823457638476354, 44.747691660225364]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"43\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.828607479784948, 44.75659086265001]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"44\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.832384030077916, 44.76280730056898]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"45\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.838563839648229, 44.780234138071414]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"46\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.360658566210729, 45.27366166900315]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"47\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.357225338671666, 45.305061440557125]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"48\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.356538693163854, 45.302163728326626]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"49\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.357911984179479, 45.292986662466724]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"50\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.352418820116979, 45.292986662466724]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"51\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.322549740527135, 45.28090931297517]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"52\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.297487179491979, 45.27994301393099]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"53\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.301607052538854, 45.2668963660993]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"54\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.33490935966776, 45.260371917443365]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"55\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.327699581835729, 45.25819693459614]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"56\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.265901486132604, 45.25215487843267]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"57\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.249078671191198, 45.27559446457621]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"58\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.238092343066198, 45.28260029670276]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"59\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.248048702929479, 45.271728807601804]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"60\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.228135983202916, 45.26303011666926]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"61\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.307786862109166, 45.234508395220274]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"62\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.288904110644323, 45.23934359330129]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"63\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.277574459765416, 45.23475016489584]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"64\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.344179074023229, 45.23063994052452]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"65\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.394647518847448, 45.25771359376027]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"66\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.459878842089635, 45.25674689974561]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"67\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.467775265429479, 45.26544655342014]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"68\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.542276303027135, 45.293228183228244]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"69\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.533693234179479, 45.30602731172016]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"70\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.553262631152135, 45.30433702638502]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"71\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.585191647265416, 45.292020569135126]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"72\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.575235287402135, 45.24417837995096]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"73\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.557725826952916, 45.2311235117616]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"74\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.521333615038854, 45.24321145553549]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"75\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.50794402763651, 45.22386951120088]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"76\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.484941403124791, 45.229189202127266]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"77\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.43653289482401, 45.21226118479587]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"78\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.404603878710729, 45.21226118479587]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"79\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.394304196093541, 45.22870561443287]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"80\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.098933611495559, 45.29673011868558]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"81\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.108460817916457, 45.295643334272455]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"82\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.06717625675923, 45.29775650706211]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"83\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.045289431197707, 45.30131853435977]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"84\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.05146924076802, 45.30373334083693]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"85\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.083569918258254, 45.304397394586246]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"86\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.08717480717427, 45.284895122576465]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"87\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([10.095929537398879, 45.281150885164806]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"88\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.719647799117629, 45.4015670962912]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"89\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.755353365523879, 45.40928043956986]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"90\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.740247164352004, 45.43988238640316]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"91\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.67467251835591, 45.423017223473764]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"92\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.667462740523879, 45.43072763756811]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"93\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.640683565719192, 45.38637837388185]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"94\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.699735079391067, 45.39023621391478]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"95\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.670552645309035, 45.384449355127416]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"96\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.665402804000442, 45.39361160795464]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"97\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.604977999312942, 45.38155570357316]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"98\"\n", + " }),\n", + " ee.Feature(\n", + " ee.Geometry.Point([9.596051607711379, 45.39602248027528]),\n", + " {\n", + " \"class\": 3,\n", + " \"system:index\": \"99\"\n", + " })])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# Create an Earth Engine Point object over Milan.\n", + "pt = ee.Geometry.Point([9.453, 45.424])\n", + "\n", + "# Filter the Landsat 8 collection and select the least cloudy image.\n", + "landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(pt) \\\n", + " .filterDate('2019-01-01', '2020-01-01') \\\n", + " .sort('CLOUD_COVER') \\\n", + " .first()\n", + "\n", + "# Add NDVI and NDWI as bands.\n", + "ndvi = landsat.normalizedDifference(['SR_B5', 'SR_B4']).rename('ndvi')\n", + "ndwi = landsat.normalizedDifference(['SR_B5', 'SR_B6']).rename('ndwi')\n", + "landsat = landsat.addBands(ndvi).addBands(ndwi)\n", + "\n", + "# Center the map on that image.\n", + "Map.centerObject(landsat, 8)\n", + "\n", + "# Add Landsat image to the map.\n", + "visParams = {'bands': ['SR_B4', 'SR_B3', 'SR_B2'], 'min': 7000, 'max': 12000}\n", + "Map.addLayer(landsat, visParams, 'Landsat 8 image')\n", + "\n", + "# Combine training feature collections. Here we are using 100 points per class.\n", + "# See imports at the top.\n", + "trainingFeatures = ee.FeatureCollection([\n", + " forest, developed, water, herbaceous\n", + "]).flatten()\n", + "\n", + "# Define the prediction bands.\n", + "predictionBands = [\n", + " 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', 'ST_B10',\n", + " 'ndvi', 'ndwi'\n", + "]\n", + "\n", + "# Sample training points.\n", + "classifierTraining = landsat.select(predictionBands) \\\n", + " .sampleRegions({\n", + " 'collection': trainingFeatures,\n", + " 'properties': ['class'],\n", + " 'scale': 30\n", + " })\n", + "\n", + "######## CART Classifier #########/\n", + "\n", + "# Train a CART Classifier.\n", + "classifier = ee.Classifier.smileCart().train({\n", + " 'features': classifierTraining,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + "})\n", + "\n", + "# Classify the Landsat image.\n", + "classified = landsat.select(predictionBands).classify(classifier)\n", + "\n", + "# Define classification image visualization parameters.\n", + "classificationVis = {\n", + " 'min': 0, 'max': 3, 'palette': ['589400', 'ff0000', '1a11ff', 'd0741e']\n", + "}\n", + "\n", + "# Add the classified image to the map.\n", + "Map.addLayer(classified, classificationVis, 'CART classified')\n", + "\n", + "#######/ Random Forest Classifier ##########/\n", + "\n", + "# Train RF classifier.\n", + "RFclassifier = ee.Classifier.smileRandomForest(50).train({\n", + " 'features': classifierTraining,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + "})\n", + "\n", + "# Classify Landsat image.\n", + "RFclassified = landsat.select(predictionBands).classify(RFclassifier)\n", + "\n", + "# Add classified image to the map.\n", + "Map.addLayer(RFclassified, classificationVis, 'RF classified')\n", + "\n", + "######## Unsupervised classification ########\n", + "\n", + "# Make the training dataset.\n", + "training = landsat.sample({\n", + " 'region': landsat.geometry(),\n", + " 'scale': 30,\n", + " 'numPixels': 1000,\n", + " 'tileScale': 8\n", + "})\n", + "\n", + "# Instantiate the clusterer and train it.\n", + "clusterer = ee.Clusterer.wekaKMeans(4).train(training)\n", + "\n", + "# Cluster the input using the trained clusterer.\n", + "Kclassified = landsat.cluster(clusterer)\n", + "\n", + "# Display the clusters with random colors.\n", + "Map.addLayer(Kclassified.randomVisualizer(), {}, 'K-means classified - random colors')\n", + "\n", + "# Display the clusters with same palette as supervised classification\n", + "# herbaceous is 0, water is 1, forest is 2, developed is 3.\n", + "Map.addLayer(Kclassified,\n", + " {'min': 0, 'max': 3, 'palette': ['d0741e','1a11ff','589400', 'ff0000']},\n", + " 'K-means classified')" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21s1 Assignment 6.js b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21s1 Assignment 6.js new file mode 100644 index 0000000..9cb61b4 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21s1 Assignment 6.js @@ -0,0 +1,2519 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var forest = + /* color: #589400 */ + /* shown: false */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.414318330642528, 44.573441859314016]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.427705541156865, 44.58422671008443]), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.400411382221318, 44.59498464279749]), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.427190557026005, 44.600607315157376]), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.427018895649052, 44.571877083168374]), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.352346196674443, 44.56062563530188]), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.584676704909665, 44.528474349106816]), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.568368874099118, 44.53899788426392]), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.557210884597165, 44.534470549891495]), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.563219032790524, 44.508523361153955]), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.652654610183102, 44.530799479832886]), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.691499968871002, 44.50146601530913]), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.67055728088272, 44.502567915176314]), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.4990172743743]), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.48285300484169]), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.65733935485733, 44.482118158872886]), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.605325957640533, 44.49448683251806]), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.592108031615142, 44.47342177876237]), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.69252993713272, 44.47084936162859]), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.738535186156158, 44.48922128217961]), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.80740370242143, 44.44605496001787]), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.759338516874555, 44.4477706457772]), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.753158707304243, 44.45120186611758]), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.622735604942841, 44.17490267165223]), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.514245614708466, 44.1906597047536]), + { + "class": 0, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([10.042922670006837, 44.30621875527554]), + { + "class": 0, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([10.043609315514649, 44.2880350593344]), + { + "class": 0, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([10.068328553795899, 44.27181241762688]), + { + "class": 0, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([10.114333802819337, 44.28017009547173]), + { + "class": 0, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([10.109527284264649, 44.29393309121647]), + { + "class": 0, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([10.090301210045899, 44.32439682017676]), + { + "class": 0, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([9.887397462487305, 44.283119580315365]), + { + "class": 0, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([9.849975282311524, 44.30277902847262]), + { + "class": 0, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([9.868171388268555, 44.26812482891884]), + { + "class": 0, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([9.920699769616212, 44.233696177590424]), + { + "class": 0, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([9.974944764733399, 44.26738728341367]), + { + "class": 0, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([9.980437928795899, 44.27549977497149]), + { + "class": 0, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([9.955375367760743, 44.32439682017676]), + { + "class": 0, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([9.418427521884842, 44.38209136110383]), + { + "class": 0, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([9.411904389560624, 44.37767453815662]), + { + "class": 0, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([9.40126138418953, 44.37522060365833]), + { + "class": 0, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([9.386841828525467, 44.3720303350693]), + { + "class": 0, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([9.374825532138749, 44.375711398784944]), + { + "class": 0, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([9.407441193759842, 44.36577199572992]), + { + "class": 0, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([9.419800812900467, 44.378410698452875]), + { + "class": 0, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([9.402634675205155, 44.39190533029205]), + { + "class": 0, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([9.430787141025467, 44.39607576894639]), + { + "class": 0, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([9.456364686191483, 44.40110443203785]), + { + "class": 0, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([9.491555268466874, 44.40147236602735]), + { + "class": 0, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([9.52760415762703, 44.39656638924877]), + { + "class": 0, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([9.518334443271561, 44.375711398784944]), + { + "class": 0, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([9.54408364981453, 44.376447583762115]), + { + "class": 0, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([9.362465912998124, 44.38515840322767]), + { + "class": 0, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([9.150727904135598, 44.58657203242108]), + { + "class": 0, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([9.069360411459817, 44.593906906576656]), + { + "class": 0, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([9.087556517416848, 44.55966957437203]), + { + "class": 0, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([8.995546019369973, 44.57874714637613]), + { + "class": 0, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([8.969453490073098, 44.600751953971006]), + { + "class": 0, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([9.07004705696763, 44.54988377686661]), + { + "class": 0, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([9.08549658089341, 44.524188229078355]), + { + "class": 0, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([9.123262083823098, 44.53250993354593]), + { + "class": 0, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([9.12669531136216, 44.52125087305466]), + { + "class": 0, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([9.101289427573098, 44.5117034431649]), + { + "class": 0, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([9.001725828940286, 44.52002693100144]), + { + "class": 0, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([9.048761046225442, 44.579480774182784]), + { + "class": 0, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([9.097856200034036, 44.58119253640071]), + { + "class": 0, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([9.232438719565286, 44.577279862993244]), + { + "class": 0, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([9.25303808479966, 44.592195518735345]), + { + "class": 0, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([10.930848996624745, 44.05820855928862]), + { + "class": 0, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([10.961061398968495, 44.034518385008376]), + { + "class": 0, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([10.950075070843495, 44.10753265821489]), + { + "class": 0, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([10.88278381107787, 44.1233076844616]), + { + "class": 0, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([10.72348205326537, 44.02069474136502]), + { + "class": 0, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([10.669923703655995, 43.99995323119841]), + { + "class": 0, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([10.64383117435912, 43.97821625026472]), + { + "class": 0, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([10.737204832742563, 45.20169532981405]), + { + "class": 0, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([10.736861509988657, 45.19903426034426]), + { + "class": 0, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([10.74029473752772, 45.1974012697325]), + { + "class": 0, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([10.742955488870493, 45.196614998278925]), + { + "class": 0, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([10.746560377786508, 45.196191616842306]), + { + "class": 0, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([10.749221129129282, 45.199094740578026]), + { + "class": 0, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([10.751109404275766, 45.20242105443272]), + { + "class": 0, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([10.752053541849008, 45.20441674940112]), + { + "class": 0, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([10.740638060281626, 45.207017095376]), + { + "class": 0, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([10.738063139627329, 45.20508196549987]), + { + "class": 0, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([10.74029473752772, 45.20302581787672]), + { + "class": 0, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([10.73454408139979, 45.20133246403324]), + { + "class": 0, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([10.728624023302768, 43.74014883100581]), + { + "class": 0, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([10.738923705919955, 43.73717221940949]), + { + "class": 0, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([10.716951049669955, 43.731714713822]), + { + "class": 0, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([10.732743896349643, 43.75478168565866]), + { + "class": 0, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([10.768106140001986, 43.776352419327765]), + { + "class": 0, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([10.77600256334183, 43.670656005581066]), + { + "class": 0, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([10.573442138537143, 43.74436544412549]), + { + "class": 0, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([10.560395873888705, 43.74758971259468]), + { + "class": 0, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([10.555246032580111, 43.76767547313776]), + { + "class": 0, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([10.53430334459183, 43.77065056793546]), + { + "class": 0, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([10.642793334826205, 43.68555410716658]), + { + "class": 0, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([10.717637695177768, 43.72501618629434]), + { + "class": 0, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([10.735147155626986, 43.7535417519611]), + { + "class": 0, + "system:index": "99" + })]), + developed = + /* color: #ff0000 */ + /* shown: false */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.19467878610836, 45.46435783697627]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.203090193579063, 45.464899612733554]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.204463484594688, 45.462852876998106]), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.180087569067345, 45.458879589622896]), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.18068838388668, 45.45641119434588]), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.167642119238243, 45.455267267211944]), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.165668013403282, 45.45340080996563]), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.167556288549767, 45.45135365679475]), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.167813780615196, 45.46297327527481]), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.176911833593712, 45.46706666369604]), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.223853948611414, 45.47248322583851]), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.242822530764734, 45.47537221988128]), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.211236837405359, 45.47729813363197]), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.203597906130945, 45.47669629265562]), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.154784524052499, 45.18401973624338]), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.158217751591561, 45.185713605296485]), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.156057754172835, 45.18958733293765]), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.160520949973616, 45.19122054778279]), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.158289352073226, 45.19599894427136]), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.144728103293929, 45.194063439607106]), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.145843902244124, 45.192914202565674]), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.138548293723616, 45.19019223278913]), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.144470611228499, 45.17924255060339]), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.180176177634749, 45.18347748407685]), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.177257934226546, 45.18626026884151]), + { + "class": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([10.78698889146683, 43.71211320778847]), + { + "class": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([10.789392150744174, 43.71285768592188]), + { + "class": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([10.809304870470736, 43.72625671087301]), + { + "class": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([10.839517272814486, 43.69486354220674]), + { + "class": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([10.848100341662143, 43.692877650647986]), + { + "class": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([10.801408447130893, 43.68816089463136]), + { + "class": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([10.792825378283236, 43.68580237752021]), + { + "class": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([10.793855346544955, 43.681705785290106]), + { + "class": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([10.744760192736361, 43.69945566455851]), + { + "class": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([10.757978118761752, 43.708142501552466]), + { + "class": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([10.752313293322299, 43.711368720406874]), + { + "class": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([10.747335113390658, 43.71633179492939]), + { + "class": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([10.756433166369174, 43.72414780380379]), + { + "class": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([10.75729147325394, 43.722659118819244]), + { + "class": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([10.782697357043002, 43.73121855228781]), + { + "class": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([10.101396448196057, 44.02806798391265]), + { + "class": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([10.142938501418714, 44.03831132632035]), + { + "class": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([10.131265527785901, 44.04386420551437]), + { + "class": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([10.073930627883557, 44.03954534445121]), + { + "class": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([10.059682733596448, 44.049169803814]), + { + "class": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([10.034448511184339, 44.04028574299332]), + { + "class": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([10.028955347121839, 44.04818275173984]), + { + "class": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([10.109121210158948, 44.01374902094095]), + { + "class": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([10.103628046096448, 44.01103296542014]), + { + "class": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([10.090238458694104, 44.022143315216184]), + { + "class": 1, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([10.080797082961682, 44.04386420551437]), + { + "class": 1, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([10.064832574905042, 44.03497934899128]), + { + "class": 1, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([10.329484511360473, 44.80057754997864]), + { + "class": 1, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([10.337380934700317, 44.79485244645107]), + { + "class": 1, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([10.330514479622192, 44.79911587541933]), + { + "class": 1, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([10.317296553596801, 44.802160988964836]), + { + "class": 1, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([10.318498183235473, 44.79984671732763]), + { + "class": 1, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([10.300988722786254, 44.80313539135592]), + { + "class": 1, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([10.357636977180785, 44.808616098157394]), + { + "class": 1, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([10.35351710413391, 44.79034505045052]), + { + "class": 1, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([10.34408578523026, 44.79250875336787]), + { + "class": 1, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([10.335202308972935, 44.79025500784725]), + { + "class": 1, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([10.337519737561802, 44.78663055684301]), + { + "class": 1, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([10.326662155469517, 44.791625539258725]), + { + "class": 1, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([9.68779982182756, 45.05295255153792]), + { + "class": 1, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([9.693636308643967, 45.05076963745494]), + { + "class": 1, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([9.700502763722092, 45.04907175778813]), + { + "class": 1, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([9.764360795948654, 45.02845062567073]), + { + "class": 1, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([9.738954912159592, 45.04446297319648]), + { + "class": 1, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([9.731401811573654, 45.05125473667368]), + { + "class": 1, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([9.734835039112717, 45.03378857269489]), + { + "class": 1, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([9.695696245167404, 45.041066789045686]), + { + "class": 1, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([9.670977006886154, 45.04397781637543]), + { + "class": 1, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([9.71002997014299, 45.03529497150581]), + { + "class": 1, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([9.699472795460373, 45.0422091170089]), + { + "class": 1, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([9.730543504688889, 45.04396784528239]), + { + "class": 1, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([9.727453599903733, 45.044028490120596]), + { + "class": 1, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([9.728741060230881, 45.04912242702095]), + { + "class": 1, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([9.673637758228928, 45.042936873196716]), + { + "class": 1, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([9.68007505986467, 45.03772108261854]), + { + "class": 1, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([9.681019197437912, 45.036811303005315]), + { + "class": 1, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([9.693378816578537, 45.03420318794656]), + { + "class": 1, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([9.695953737232834, 45.03311138355789]), + { + "class": 1, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([10.928861454431917, 44.645179237899704]), + { + "class": 1, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([10.926114872400667, 44.645179237899704]), + { + "class": 1, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([10.922509983484652, 44.64652267753729]), + { + "class": 1, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([10.931264713709261, 44.63724009583039]), + { + "class": 1, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([10.950061634485628, 44.6343084456789]), + { + "class": 1, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([10.953924015467074, 44.63797298522629]), + { + "class": 1, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([10.922424152796175, 44.631376647419025]), + { + "class": 1, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([10.923110798303988, 44.63308688106989]), + { + "class": 1, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([10.91255362362137, 44.64383576714894]), + { + "class": 1, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([10.908347919886019, 44.64481283987146]), + { + "class": 1, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([10.900108173792269, 44.647621832280535]), + { + "class": 1, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([10.909463718836214, 44.63724009583039]), + { + "class": 1, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([10.93504126400223, 44.626978672326416]), + { + "class": 1, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([10.982591465418245, 44.63711794669777]), + { + "class": 1, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([10.988256290857699, 44.63479706432279]), + { + "class": 1, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([10.992290333216097, 44.63290364416077]), + { + "class": 1, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([10.992548194323003, 44.632782655700204]), + { + "class": 1, + "system:index": "99" + })]), + water = + /* color: #1a11ff */ + /* shown: false */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.980378415331183, 43.953687197631126]), + { + "class": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.735932614549933, 44.00704943549187]), + { + "class": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.461274411424933, 44.12546046543348]), + { + "class": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.282746579393683, 44.235763707116455]), + { + "class": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([10.068269040331183, 43.94775509959863]), + { + "class": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([10.202851559862433, 43.765549960385265]), + { + "class": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([10.178132321581183, 43.72785127863614]), + { + "class": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([10.213837887987433, 43.6821842672651]), + { + "class": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([10.065522458299933, 43.72586647981521]), + { + "class": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.941926266893683, 43.894339574154564]), + { + "class": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.88486387395865, 45.077069068166345]), + { + "class": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.848471662044588, 45.09864207259974]), + { + "class": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.81448270940787, 45.0773115067334]), + { + "class": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.828902265071932, 45.06179336476103]), + { + "class": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.95455839300162, 45.11657297387295]), + { + "class": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([10.002623578548494, 45.115603879971225]), + { + "class": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([10.02322294378287, 45.10276183206325]), + { + "class": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([10.043822309017244, 45.07149269722714]), + { + "class": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([10.248517220628196, 45.02613418018433]), + { + "class": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([10.263280099046165, 45.01836869065415]), + { + "class": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([10.280102913987571, 45.006475743526394]), + { + "class": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([10.265340035569603, 45.03802304474337]), + { + "class": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([10.220021432053978, 45.023222245044195]), + { + "class": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.182599251878196, 45.04069163407949]), + { + "class": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.156163399827415, 45.03292811948761]), + { + "class": 2, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([10.98911496678394, 44.644081206444866]), + { + "class": 2, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([10.988943305406988, 44.64285984756699]), + { + "class": 2, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([10.987484183702886, 44.641821672303635]), + { + "class": 2, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([10.987741675768316, 44.63919561665319]), + { + "class": 2, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([10.990659919176519, 44.63748556302968]), + { + "class": 2, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([10.984823432360113, 44.62844587093865]), + { + "class": 2, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([10.990316596422613, 44.626857671514365]), + { + "class": 2, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([11.026050685338417, 45.051974176463936]), + { + "class": 2, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([11.063816188268104, 45.04372703391621]), + { + "class": 2, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([11.12286770193998, 45.068464894331655]), + { + "class": 2, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([11.19427883475248, 45.05779497293618]), + { + "class": 2, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([11.260883449010292, 45.05585477327662]), + { + "class": 2, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([11.262256740025917, 45.03014091290893]), + { + "class": 2, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([11.321308253697792, 44.99907480907841]), + { + "class": 2, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([11.358387111119667, 44.98402110649786]), + { + "class": 2, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([10.869495509557167, 45.06119016393412]), + { + "class": 2, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([10.805637477330604, 45.04372703391621]), + { + "class": 2, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([10.756885646275917, 45.04566764502083]), + { + "class": 2, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([11.184665797643104, 45.21328137697889]), + { + "class": 2, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([11.014377711705604, 45.22392224246559]), + { + "class": 2, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([10.656680360814072, 44.9558559658398]), + { + "class": 2, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([10.636424318333603, 44.94249200515986]), + { + "class": 2, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([10.62749792673204, 44.926208067303]), + { + "class": 2, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([10.537547365208603, 44.912350932821255]), + { + "class": 2, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([10.50218512155626, 44.921103196045436]), + { + "class": 2, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([10.428370729466415, 44.96071481644557]), + { + "class": 2, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([10.405711427708603, 44.98718832057907]), + { + "class": 2, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([10.380992189427353, 44.9789318417816]), + { + "class": 2, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([10.475062623997665, 44.93568733902074]), + { + "class": 2, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([9.464568669294943, 45.424644452593405]), + { + "class": 2, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([9.458217198347677, 45.41536673223165]), + { + "class": 2, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([9.463710362410177, 45.407172153109734]), + { + "class": 2, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([9.459933812117209, 45.39584239478833]), + { + "class": 2, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([9.46439700791799, 45.3902972170168]), + { + "class": 2, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([9.454783970808615, 45.4118721306585]), + { + "class": 2, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([9.481048161482443, 45.43584797837749]), + { + "class": 2, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([9.469203526472677, 45.43102953016216]), + { + "class": 2, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([9.283229596846958, 45.48773969818685]), + { + "class": 2, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([9.27842307829227, 45.48846176503586]), + { + "class": 2, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([9.27842307829227, 45.50602920541026]), + { + "class": 2, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([9.274646527999302, 45.41596826492388]), + { + "class": 2, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([9.041187055343052, 45.219455970317355]), + { + "class": 2, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([9.058009870284458, 45.21897229982002]), + { + "class": 2, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([9.077579267257114, 45.20228314814136]), + { + "class": 2, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([9.085475690596958, 45.196235145464364]), + { + "class": 2, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([9.175769574874302, 45.16792194842297]), + { + "class": 2, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([9.20426536344852, 45.16332274987339]), + { + "class": 2, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([9.213878400557896, 45.141774192169606]), + { + "class": 2, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([9.21628165983524, 45.15121782146389]), + { + "class": 2, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([9.222804792159458, 45.14371147444317]), + { + "class": 2, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([9.255763776534458, 45.136446326478705]), + { + "class": 2, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([9.313441999190708, 45.12167100406328]), + { + "class": 2, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([9.151736982100864, 45.12142875377629]), + { + "class": 2, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([9.105045087569614, 45.10374170456197]), + { + "class": 2, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([9.07071281217899, 45.09622910773991]), + { + "class": 2, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([9.38107658171024, 45.10010670050038]), + { + "class": 2, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([9.406482465499302, 45.093078369729355]), + { + "class": 2, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([9.424335248702427, 45.09089698773592]), + { + "class": 2, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([9.399529842312088, 44.059942165310375]), + { + "class": 2, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([8.877679256374588, 44.17036779637155]), + { + "class": 2, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([9.355584529812088, 43.96512739709022]), + { + "class": 2, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([9.064446834499588, 44.22550322825024]), + { + "class": 2, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([9.053460506374588, 44.15460533997702]), + { + "class": 2, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([9.597283748562088, 43.88995820658324]), + { + "class": 2, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([10.204020885402908, 44.67242037723368]), + { + "class": 2, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([10.200415996486893, 44.66991778726374]), + { + "class": 2, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([10.198699382717361, 44.668513848016225]), + { + "class": 2, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([10.195094493801346, 44.666072133544375]), + { + "class": 2, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([10.192862895900955, 44.66472914674318]), + { + "class": 2, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([10.18874302285408, 44.66283670344126]), + { + "class": 2, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([10.185309795315018, 44.66045579992672]), + { + "class": 2, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([10.090552715236893, 44.69024057554722]), + { + "class": 2, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([9.884559062893143, 44.6882879445253]), + { + "class": 2, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([10.091239360744705, 44.687555690920945]), + { + "class": 2, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([10.085917858059158, 44.682429656495245]), + { + "class": 2, + "system:index": "99" + })]), + herbaceous = + /* color: #d0741e */ + /* shown: false */ + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.647866129015439, 45.00732805319811]), + { + "class": 3, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.63911139879083, 45.00150212185294]), + { + "class": 3, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.63859641465997, 44.995432813342106]), + { + "class": 3, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.679108499620908, 44.99688950601573]), + { + "class": 3, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.680653452013486, 44.99106251314061]), + { + "class": 3, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.616967081163876, 44.98474926892666]), + { + "class": 3, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.625550150011533, 44.984627853569535]), + { + "class": 3, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.577313303087704, 44.99968139680247]), + { + "class": 3, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.682183386109417, 45.11939912570097]), + { + "class": 3, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.662270666382854, 45.142166966714186]), + { + "class": 3, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.655747534058635, 45.14483069451677]), + { + "class": 3, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.602875829957073, 45.13926093989158]), + { + "class": 3, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.57849991442973, 45.14265129011751]), + { + "class": 3, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.56476700427348, 45.14047180240153]), + { + "class": 3, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.55652725817973, 45.11794555067206]), + { + "class": 3, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.511208654664104, 45.12666644539884]), + { + "class": 3, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.601502538941448, 45.15887374651922]), + { + "class": 3, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.770417333863323, 45.15378959281897]), + { + "class": 3, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.706286368107783, 45.13319818507588]), + { + "class": 3, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.704827246403681, 45.13574123701328]), + { + "class": 3, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.699248251652705, 45.13955560228794]), + { + "class": 3, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.688776907658564, 45.13598342652142]), + { + "class": 3, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.688519415593134, 45.130655019734995]), + { + "class": 3, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.653500494694697, 45.13997940490131]), + { + "class": 3, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.67341321442126, 45.12260091467352]), + { + "class": 3, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([10.7573680083494, 44.76085711753607]), + { + "class": 3, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([10.787065426562291, 44.77743157501226]), + { + "class": 3, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([10.805604855273229, 44.78193997941965]), + { + "class": 3, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([10.800111691210729, 44.782914723275496]), + { + "class": 3, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([10.801484982226354, 44.78206182330164]), + { + "class": 3, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([10.701234738085729, 44.76743872144162]), + { + "class": 3, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([10.706727902148229, 44.77036363804527]), + { + "class": 3, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([10.716512600634557, 44.77060737440978]), + { + "class": 3, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([10.714281002734166, 44.773775853547704]), + { + "class": 3, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([10.724237362597448, 44.78133075615248]), + { + "class": 3, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([10.686300198290807, 44.778650097404636]), + { + "class": 3, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([10.69797317192362, 44.78474232364748]), + { + "class": 3, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([10.726983944628698, 44.74257095015713]), + { + "class": 3, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([10.732305447314245, 44.750617576606686]), + { + "class": 3, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([10.73367873832987, 44.749886111397124]), + { + "class": 3, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([10.747926632616979, 44.74842315320647]), + { + "class": 3, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([10.800111691210729, 44.74915463693038]), + { + "class": 3, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([10.840967098925573, 44.745740967018534]), + { + "class": 3, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([10.823457638476354, 44.747691660225364]), + { + "class": 3, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([10.828607479784948, 44.75659086265001]), + { + "class": 3, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([10.832384030077916, 44.76280730056898]), + { + "class": 3, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([10.838563839648229, 44.780234138071414]), + { + "class": 3, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([10.360658566210729, 45.27366166900315]), + { + "class": 3, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([10.357225338671666, 45.305061440557125]), + { + "class": 3, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([10.356538693163854, 45.302163728326626]), + { + "class": 3, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([10.357911984179479, 45.292986662466724]), + { + "class": 3, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([10.352418820116979, 45.292986662466724]), + { + "class": 3, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([10.322549740527135, 45.28090931297517]), + { + "class": 3, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([10.297487179491979, 45.27994301393099]), + { + "class": 3, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([10.301607052538854, 45.2668963660993]), + { + "class": 3, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([10.33490935966776, 45.260371917443365]), + { + "class": 3, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([10.327699581835729, 45.25819693459614]), + { + "class": 3, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([10.265901486132604, 45.25215487843267]), + { + "class": 3, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([10.249078671191198, 45.27559446457621]), + { + "class": 3, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([10.238092343066198, 45.28260029670276]), + { + "class": 3, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([10.248048702929479, 45.271728807601804]), + { + "class": 3, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([10.228135983202916, 45.26303011666926]), + { + "class": 3, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([10.307786862109166, 45.234508395220274]), + { + "class": 3, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([10.288904110644323, 45.23934359330129]), + { + "class": 3, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([10.277574459765416, 45.23475016489584]), + { + "class": 3, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([10.344179074023229, 45.23063994052452]), + { + "class": 3, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([10.394647518847448, 45.25771359376027]), + { + "class": 3, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([10.459878842089635, 45.25674689974561]), + { + "class": 3, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([10.467775265429479, 45.26544655342014]), + { + "class": 3, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([10.542276303027135, 45.293228183228244]), + { + "class": 3, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([10.533693234179479, 45.30602731172016]), + { + "class": 3, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([10.553262631152135, 45.30433702638502]), + { + "class": 3, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([10.585191647265416, 45.292020569135126]), + { + "class": 3, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([10.575235287402135, 45.24417837995096]), + { + "class": 3, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([10.557725826952916, 45.2311235117616]), + { + "class": 3, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([10.521333615038854, 45.24321145553549]), + { + "class": 3, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([10.50794402763651, 45.22386951120088]), + { + "class": 3, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([10.484941403124791, 45.229189202127266]), + { + "class": 3, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([10.43653289482401, 45.21226118479587]), + { + "class": 3, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([10.404603878710729, 45.21226118479587]), + { + "class": 3, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([10.394304196093541, 45.22870561443287]), + { + "class": 3, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([10.098933611495559, 45.29673011868558]), + { + "class": 3, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([10.108460817916457, 45.295643334272455]), + { + "class": 3, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([10.06717625675923, 45.29775650706211]), + { + "class": 3, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([10.045289431197707, 45.30131853435977]), + { + "class": 3, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([10.05146924076802, 45.30373334083693]), + { + "class": 3, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([10.083569918258254, 45.304397394586246]), + { + "class": 3, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([10.08717480717427, 45.284895122576465]), + { + "class": 3, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([10.095929537398879, 45.281150885164806]), + { + "class": 3, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([9.719647799117629, 45.4015670962912]), + { + "class": 3, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([9.755353365523879, 45.40928043956986]), + { + "class": 3, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([9.740247164352004, 45.43988238640316]), + { + "class": 3, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([9.67467251835591, 45.423017223473764]), + { + "class": 3, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([9.667462740523879, 45.43072763756811]), + { + "class": 3, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([9.640683565719192, 45.38637837388185]), + { + "class": 3, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([9.699735079391067, 45.39023621391478]), + { + "class": 3, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([9.670552645309035, 45.384449355127416]), + { + "class": 3, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([9.665402804000442, 45.39361160795464]), + { + "class": 3, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([9.604977999312942, 45.38155570357316]), + { + "class": 3, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([9.596051607711379, 45.39602248027528]), + { + "class": 3, + "system:index": "99" + })]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// Create an Earth Engine Point object over Milan. +var pt = ee.Geometry.Point([9.453, 45.424]); + +// Filter the Landsat 8 collection and select the least cloudy image. +var landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(pt) + .filterDate('2019-01-01', '2020-01-01') + .sort('CLOUD_COVER') + .first(); + +// Add NDVI and NDWI as bands. +var ndvi = landsat.normalizedDifference(['SR_B5', 'SR_B4']).rename('ndvi'); +var ndwi = landsat.normalizedDifference(['SR_B5', 'SR_B6']).rename('ndwi'); +var landsat = landsat.addBands(ndvi).addBands(ndwi); + +// Center the map on that image. +Map.centerObject(landsat, 8); + +// Add Landsat image to the map. +var visParams = {bands: ['SR_B4', 'SR_B3', 'SR_B2'], min: 7000, max: 12000}; +Map.addLayer(landsat, visParams, 'Landsat 8 image'); + +// Combine training feature collections. Here we are using 100 points per class. +// See imports at the top. +var trainingFeatures = ee.FeatureCollection([ + forest, developed, water, herbaceous +]).flatten(); + +// Define the prediction bands. +var predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', 'ST_B10', + 'ndvi', 'ndwi' +]; + +// Sample training points. +var classifierTraining = landsat.select(predictionBands) + .sampleRegions({ + collection: trainingFeatures, + properties: ['class'], + scale: 30 + }); + +//////////////// CART Classifier /////////////////// + +// Train a CART Classifier. +var classifier = ee.Classifier.smileCart().train({ + features: classifierTraining, + classProperty: 'class', + inputProperties: predictionBands +}); + +// Classify the Landsat image. +var classified = landsat.select(predictionBands).classify(classifier); + +// Define classification image visualization parameters. +var classificationVis = { + min: 0, max: 3, palette: ['589400', 'ff0000', '1a11ff', 'd0741e'] +}; + +// Add the classified image to the map. +Map.addLayer(classified, classificationVis, 'CART classified'); + +/////////////// Random Forest Classifier ///////////////////// + +// Train RF classifier. +var RFclassifier = ee.Classifier.smileRandomForest(50).train({ + features: classifierTraining, + classProperty: 'class', + inputProperties: predictionBands +}); + +// Classify Landsat image. +var RFclassified = landsat.select(predictionBands).classify(RFclassifier); + +// Add classified image to the map. +Map.addLayer(RFclassified, classificationVis, 'RF classified'); + +//////////////// Unsupervised classification //////////////// + +// Make the training dataset. +var training = landsat.sample({ + region: landsat.geometry(), + scale: 30, + numPixels: 1000, + tileScale: 8 +}); + +// Instantiate the clusterer and train it. +var clusterer = ee.Clusterer.wekaKMeans(4).train(training); + +// Cluster the input using the trained clusterer. +var Kclassified = landsat.cluster(clusterer); + +// Display the clusters with random colors. +Map.addLayer(Kclassified.randomVisualizer(), {}, 'K-means classified - random colors'); + +// Display the clusters with same palette as supervised classification +// herbaceous is 0, water is 1, forest is 2, developed is 3. +Map.addLayer(Kclassified, + {min: 0, max: 3, palette: ['d0741e','1a11ff','589400', 'ff0000']}, + 'K-means classified'); diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21s1 Assignment 6.py b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21s1 Assignment 6.py new file mode 100644 index 0000000..c0d8562 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.1 Interpreting an Image - Classification/F21s1 Assignment 6.py @@ -0,0 +1,2525 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +forest = + + # shown: False # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.414318330642528, 44.573441859314016]), + { + "class": 0, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.427705541156865, 44.58422671008443]), + { + "class": 0, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.400411382221318, 44.59498464279749]), + { + "class": 0, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.427190557026005, 44.600607315157376]), + { + "class": 0, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.427018895649052, 44.571877083168374]), + { + "class": 0, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.352346196674443, 44.56062563530188]), + { + "class": 0, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.584676704909665, 44.528474349106816]), + { + "class": 0, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.568368874099118, 44.53899788426392]), + { + "class": 0, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.557210884597165, 44.534470549891495]), + { + "class": 0, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.563219032790524, 44.508523361153955]), + { + "class": 0, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.652654610183102, 44.530799479832886]), + { + "class": 0, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.691499968871002, 44.50146601530913]), + { + "class": 0, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.67055728088272, 44.502567915176314]), + { + "class": 0, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.4990172743743]), + { + "class": 0, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.668154021605377, 44.48285300484169]), + { + "class": 0, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.65733935485733, 44.482118158872886]), + { + "class": 0, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.605325957640533, 44.49448683251806]), + { + "class": 0, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.592108031615142, 44.47342177876237]), + { + "class": 0, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.69252993713272, 44.47084936162859]), + { + "class": 0, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.738535186156158, 44.48922128217961]), + { + "class": 0, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.80740370242143, 44.44605496001787]), + { + "class": 0, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.759338516874555, 44.4477706457772]), + { + "class": 0, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.753158707304243, 44.45120186611758]), + { + "class": 0, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.622735604942841, 44.17490267165223]), + { + "class": 0, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.514245614708466, 44.1906597047536]), + { + "class": 0, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([10.042922670006837, 44.30621875527554]), + { + "class": 0, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([10.043609315514649, 44.2880350593344]), + { + "class": 0, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([10.068328553795899, 44.27181241762688]), + { + "class": 0, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([10.114333802819337, 44.28017009547173]), + { + "class": 0, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([10.109527284264649, 44.29393309121647]), + { + "class": 0, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([10.090301210045899, 44.32439682017676]), + { + "class": 0, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([9.887397462487305, 44.283119580315365]), + { + "class": 0, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([9.849975282311524, 44.30277902847262]), + { + "class": 0, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([9.868171388268555, 44.26812482891884]), + { + "class": 0, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([9.920699769616212, 44.233696177590424]), + { + "class": 0, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([9.974944764733399, 44.26738728341367]), + { + "class": 0, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([9.980437928795899, 44.27549977497149]), + { + "class": 0, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([9.955375367760743, 44.32439682017676]), + { + "class": 0, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([9.418427521884842, 44.38209136110383]), + { + "class": 0, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([9.411904389560624, 44.37767453815662]), + { + "class": 0, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([9.40126138418953, 44.37522060365833]), + { + "class": 0, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([9.386841828525467, 44.3720303350693]), + { + "class": 0, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([9.374825532138749, 44.375711398784944]), + { + "class": 0, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([9.407441193759842, 44.36577199572992]), + { + "class": 0, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([9.419800812900467, 44.378410698452875]), + { + "class": 0, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([9.402634675205155, 44.39190533029205]), + { + "class": 0, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([9.430787141025467, 44.39607576894639]), + { + "class": 0, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([9.456364686191483, 44.40110443203785]), + { + "class": 0, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([9.491555268466874, 44.40147236602735]), + { + "class": 0, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([9.52760415762703, 44.39656638924877]), + { + "class": 0, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([9.518334443271561, 44.375711398784944]), + { + "class": 0, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([9.54408364981453, 44.376447583762115]), + { + "class": 0, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([9.362465912998124, 44.38515840322767]), + { + "class": 0, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([9.150727904135598, 44.58657203242108]), + { + "class": 0, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([9.069360411459817, 44.593906906576656]), + { + "class": 0, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([9.087556517416848, 44.55966957437203]), + { + "class": 0, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([8.995546019369973, 44.57874714637613]), + { + "class": 0, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([8.969453490073098, 44.600751953971006]), + { + "class": 0, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([9.07004705696763, 44.54988377686661]), + { + "class": 0, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([9.08549658089341, 44.524188229078355]), + { + "class": 0, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([9.123262083823098, 44.53250993354593]), + { + "class": 0, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([9.12669531136216, 44.52125087305466]), + { + "class": 0, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([9.101289427573098, 44.5117034431649]), + { + "class": 0, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([9.001725828940286, 44.52002693100144]), + { + "class": 0, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([9.048761046225442, 44.579480774182784]), + { + "class": 0, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([9.097856200034036, 44.58119253640071]), + { + "class": 0, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([9.232438719565286, 44.577279862993244]), + { + "class": 0, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([9.25303808479966, 44.592195518735345]), + { + "class": 0, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([10.930848996624745, 44.05820855928862]), + { + "class": 0, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([10.961061398968495, 44.034518385008376]), + { + "class": 0, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([10.950075070843495, 44.10753265821489]), + { + "class": 0, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([10.88278381107787, 44.1233076844616]), + { + "class": 0, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([10.72348205326537, 44.02069474136502]), + { + "class": 0, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([10.669923703655995, 43.99995323119841]), + { + "class": 0, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([10.64383117435912, 43.97821625026472]), + { + "class": 0, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([10.737204832742563, 45.20169532981405]), + { + "class": 0, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([10.736861509988657, 45.19903426034426]), + { + "class": 0, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([10.74029473752772, 45.1974012697325]), + { + "class": 0, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([10.742955488870493, 45.196614998278925]), + { + "class": 0, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([10.746560377786508, 45.196191616842306]), + { + "class": 0, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([10.749221129129282, 45.199094740578026]), + { + "class": 0, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([10.751109404275766, 45.20242105443272]), + { + "class": 0, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([10.752053541849008, 45.20441674940112]), + { + "class": 0, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([10.740638060281626, 45.207017095376]), + { + "class": 0, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([10.738063139627329, 45.20508196549987]), + { + "class": 0, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([10.74029473752772, 45.20302581787672]), + { + "class": 0, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([10.73454408139979, 45.20133246403324]), + { + "class": 0, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([10.728624023302768, 43.74014883100581]), + { + "class": 0, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([10.738923705919955, 43.73717221940949]), + { + "class": 0, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([10.716951049669955, 43.731714713822]), + { + "class": 0, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([10.732743896349643, 43.75478168565866]), + { + "class": 0, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([10.768106140001986, 43.776352419327765]), + { + "class": 0, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([10.77600256334183, 43.670656005581066]), + { + "class": 0, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([10.573442138537143, 43.74436544412549]), + { + "class": 0, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([10.560395873888705, 43.74758971259468]), + { + "class": 0, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([10.555246032580111, 43.76767547313776]), + { + "class": 0, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([10.53430334459183, 43.77065056793546]), + { + "class": 0, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([10.642793334826205, 43.68555410716658]), + { + "class": 0, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([10.717637695177768, 43.72501618629434]), + { + "class": 0, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([10.735147155626986, 43.7535417519611]), + { + "class": 0, + "system:index": "99" + })]), + developed = + + # shown: False # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.19467878610836, 45.46435783697627]), + { + "class": 1, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.203090193579063, 45.464899612733554]), + { + "class": 1, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.204463484594688, 45.462852876998106]), + { + "class": 1, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.180087569067345, 45.458879589622896]), + { + "class": 1, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.18068838388668, 45.45641119434588]), + { + "class": 1, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.167642119238243, 45.455267267211944]), + { + "class": 1, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.165668013403282, 45.45340080996563]), + { + "class": 1, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.167556288549767, 45.45135365679475]), + { + "class": 1, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.167813780615196, 45.46297327527481]), + { + "class": 1, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.176911833593712, 45.46706666369604]), + { + "class": 1, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.223853948611414, 45.47248322583851]), + { + "class": 1, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.242822530764734, 45.47537221988128]), + { + "class": 1, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.211236837405359, 45.47729813363197]), + { + "class": 1, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.203597906130945, 45.47669629265562]), + { + "class": 1, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.154784524052499, 45.18401973624338]), + { + "class": 1, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.158217751591561, 45.185713605296485]), + { + "class": 1, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.156057754172835, 45.18958733293765]), + { + "class": 1, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.160520949973616, 45.19122054778279]), + { + "class": 1, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.158289352073226, 45.19599894427136]), + { + "class": 1, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.144728103293929, 45.194063439607106]), + { + "class": 1, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.145843902244124, 45.192914202565674]), + { + "class": 1, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.138548293723616, 45.19019223278913]), + { + "class": 1, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.144470611228499, 45.17924255060339]), + { + "class": 1, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.180176177634749, 45.18347748407685]), + { + "class": 1, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.177257934226546, 45.18626026884151]), + { + "class": 1, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([10.78698889146683, 43.71211320778847]), + { + "class": 1, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([10.789392150744174, 43.71285768592188]), + { + "class": 1, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([10.809304870470736, 43.72625671087301]), + { + "class": 1, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([10.839517272814486, 43.69486354220674]), + { + "class": 1, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([10.848100341662143, 43.692877650647986]), + { + "class": 1, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([10.801408447130893, 43.68816089463136]), + { + "class": 1, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([10.792825378283236, 43.68580237752021]), + { + "class": 1, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([10.793855346544955, 43.681705785290106]), + { + "class": 1, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([10.744760192736361, 43.69945566455851]), + { + "class": 1, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([10.757978118761752, 43.708142501552466]), + { + "class": 1, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([10.752313293322299, 43.711368720406874]), + { + "class": 1, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([10.747335113390658, 43.71633179492939]), + { + "class": 1, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([10.756433166369174, 43.72414780380379]), + { + "class": 1, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([10.75729147325394, 43.722659118819244]), + { + "class": 1, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([10.782697357043002, 43.73121855228781]), + { + "class": 1, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([10.101396448196057, 44.02806798391265]), + { + "class": 1, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([10.142938501418714, 44.03831132632035]), + { + "class": 1, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([10.131265527785901, 44.04386420551437]), + { + "class": 1, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([10.073930627883557, 44.03954534445121]), + { + "class": 1, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([10.059682733596448, 44.049169803814]), + { + "class": 1, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([10.034448511184339, 44.04028574299332]), + { + "class": 1, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([10.028955347121839, 44.04818275173984]), + { + "class": 1, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([10.109121210158948, 44.01374902094095]), + { + "class": 1, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([10.103628046096448, 44.01103296542014]), + { + "class": 1, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([10.090238458694104, 44.022143315216184]), + { + "class": 1, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([10.080797082961682, 44.04386420551437]), + { + "class": 1, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([10.064832574905042, 44.03497934899128]), + { + "class": 1, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([10.329484511360473, 44.80057754997864]), + { + "class": 1, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([10.337380934700317, 44.79485244645107]), + { + "class": 1, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([10.330514479622192, 44.79911587541933]), + { + "class": 1, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([10.317296553596801, 44.802160988964836]), + { + "class": 1, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([10.318498183235473, 44.79984671732763]), + { + "class": 1, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([10.300988722786254, 44.80313539135592]), + { + "class": 1, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([10.357636977180785, 44.808616098157394]), + { + "class": 1, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([10.35351710413391, 44.79034505045052]), + { + "class": 1, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([10.34408578523026, 44.79250875336787]), + { + "class": 1, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([10.335202308972935, 44.79025500784725]), + { + "class": 1, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([10.337519737561802, 44.78663055684301]), + { + "class": 1, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([10.326662155469517, 44.791625539258725]), + { + "class": 1, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([9.68779982182756, 45.05295255153792]), + { + "class": 1, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([9.693636308643967, 45.05076963745494]), + { + "class": 1, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([9.700502763722092, 45.04907175778813]), + { + "class": 1, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([9.764360795948654, 45.02845062567073]), + { + "class": 1, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([9.738954912159592, 45.04446297319648]), + { + "class": 1, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([9.731401811573654, 45.05125473667368]), + { + "class": 1, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([9.734835039112717, 45.03378857269489]), + { + "class": 1, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([9.695696245167404, 45.041066789045686]), + { + "class": 1, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([9.670977006886154, 45.04397781637543]), + { + "class": 1, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([9.71002997014299, 45.03529497150581]), + { + "class": 1, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([9.699472795460373, 45.0422091170089]), + { + "class": 1, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([9.730543504688889, 45.04396784528239]), + { + "class": 1, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([9.727453599903733, 45.044028490120596]), + { + "class": 1, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([9.728741060230881, 45.04912242702095]), + { + "class": 1, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([9.673637758228928, 45.042936873196716]), + { + "class": 1, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([9.68007505986467, 45.03772108261854]), + { + "class": 1, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([9.681019197437912, 45.036811303005315]), + { + "class": 1, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([9.693378816578537, 45.03420318794656]), + { + "class": 1, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([9.695953737232834, 45.03311138355789]), + { + "class": 1, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([10.928861454431917, 44.645179237899704]), + { + "class": 1, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([10.926114872400667, 44.645179237899704]), + { + "class": 1, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([10.922509983484652, 44.64652267753729]), + { + "class": 1, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([10.931264713709261, 44.63724009583039]), + { + "class": 1, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([10.950061634485628, 44.6343084456789]), + { + "class": 1, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([10.953924015467074, 44.63797298522629]), + { + "class": 1, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([10.922424152796175, 44.631376647419025]), + { + "class": 1, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([10.923110798303988, 44.63308688106989]), + { + "class": 1, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([10.91255362362137, 44.64383576714894]), + { + "class": 1, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([10.908347919886019, 44.64481283987146]), + { + "class": 1, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([10.900108173792269, 44.647621832280535]), + { + "class": 1, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([10.909463718836214, 44.63724009583039]), + { + "class": 1, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([10.93504126400223, 44.626978672326416]), + { + "class": 1, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([10.982591465418245, 44.63711794669777]), + { + "class": 1, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([10.988256290857699, 44.63479706432279]), + { + "class": 1, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([10.992290333216097, 44.63290364416077]), + { + "class": 1, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([10.992548194323003, 44.632782655700204]), + { + "class": 1, + "system:index": "99" + })]), + water = + + # shown: False # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.980378415331183, 43.953687197631126]), + { + "class": 2, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.735932614549933, 44.00704943549187]), + { + "class": 2, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.461274411424933, 44.12546046543348]), + { + "class": 2, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.282746579393683, 44.235763707116455]), + { + "class": 2, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([10.068269040331183, 43.94775509959863]), + { + "class": 2, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([10.202851559862433, 43.765549960385265]), + { + "class": 2, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([10.178132321581183, 43.72785127863614]), + { + "class": 2, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([10.213837887987433, 43.6821842672651]), + { + "class": 2, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([10.065522458299933, 43.72586647981521]), + { + "class": 2, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.941926266893683, 43.894339574154564]), + { + "class": 2, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.88486387395865, 45.077069068166345]), + { + "class": 2, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.848471662044588, 45.09864207259974]), + { + "class": 2, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.81448270940787, 45.0773115067334]), + { + "class": 2, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.828902265071932, 45.06179336476103]), + { + "class": 2, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.95455839300162, 45.11657297387295]), + { + "class": 2, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([10.002623578548494, 45.115603879971225]), + { + "class": 2, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([10.02322294378287, 45.10276183206325]), + { + "class": 2, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([10.043822309017244, 45.07149269722714]), + { + "class": 2, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([10.248517220628196, 45.02613418018433]), + { + "class": 2, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([10.263280099046165, 45.01836869065415]), + { + "class": 2, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([10.280102913987571, 45.006475743526394]), + { + "class": 2, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([10.265340035569603, 45.03802304474337]), + { + "class": 2, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([10.220021432053978, 45.023222245044195]), + { + "class": 2, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([10.182599251878196, 45.04069163407949]), + { + "class": 2, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([10.156163399827415, 45.03292811948761]), + { + "class": 2, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([10.98911496678394, 44.644081206444866]), + { + "class": 2, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([10.988943305406988, 44.64285984756699]), + { + "class": 2, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([10.987484183702886, 44.641821672303635]), + { + "class": 2, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([10.987741675768316, 44.63919561665319]), + { + "class": 2, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([10.990659919176519, 44.63748556302968]), + { + "class": 2, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([10.984823432360113, 44.62844587093865]), + { + "class": 2, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([10.990316596422613, 44.626857671514365]), + { + "class": 2, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([11.026050685338417, 45.051974176463936]), + { + "class": 2, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([11.063816188268104, 45.04372703391621]), + { + "class": 2, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([11.12286770193998, 45.068464894331655]), + { + "class": 2, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([11.19427883475248, 45.05779497293618]), + { + "class": 2, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([11.260883449010292, 45.05585477327662]), + { + "class": 2, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([11.262256740025917, 45.03014091290893]), + { + "class": 2, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([11.321308253697792, 44.99907480907841]), + { + "class": 2, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([11.358387111119667, 44.98402110649786]), + { + "class": 2, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([10.869495509557167, 45.06119016393412]), + { + "class": 2, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([10.805637477330604, 45.04372703391621]), + { + "class": 2, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([10.756885646275917, 45.04566764502083]), + { + "class": 2, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([11.184665797643104, 45.21328137697889]), + { + "class": 2, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([11.014377711705604, 45.22392224246559]), + { + "class": 2, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([10.656680360814072, 44.9558559658398]), + { + "class": 2, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([10.636424318333603, 44.94249200515986]), + { + "class": 2, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([10.62749792673204, 44.926208067303]), + { + "class": 2, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([10.537547365208603, 44.912350932821255]), + { + "class": 2, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([10.50218512155626, 44.921103196045436]), + { + "class": 2, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([10.428370729466415, 44.96071481644557]), + { + "class": 2, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([10.405711427708603, 44.98718832057907]), + { + "class": 2, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([10.380992189427353, 44.9789318417816]), + { + "class": 2, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([10.475062623997665, 44.93568733902074]), + { + "class": 2, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([9.464568669294943, 45.424644452593405]), + { + "class": 2, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([9.458217198347677, 45.41536673223165]), + { + "class": 2, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([9.463710362410177, 45.407172153109734]), + { + "class": 2, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([9.459933812117209, 45.39584239478833]), + { + "class": 2, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([9.46439700791799, 45.3902972170168]), + { + "class": 2, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([9.454783970808615, 45.4118721306585]), + { + "class": 2, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([9.481048161482443, 45.43584797837749]), + { + "class": 2, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([9.469203526472677, 45.43102953016216]), + { + "class": 2, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([9.283229596846958, 45.48773969818685]), + { + "class": 2, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([9.27842307829227, 45.48846176503586]), + { + "class": 2, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([9.27842307829227, 45.50602920541026]), + { + "class": 2, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([9.274646527999302, 45.41596826492388]), + { + "class": 2, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([9.041187055343052, 45.219455970317355]), + { + "class": 2, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([9.058009870284458, 45.21897229982002]), + { + "class": 2, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([9.077579267257114, 45.20228314814136]), + { + "class": 2, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([9.085475690596958, 45.196235145464364]), + { + "class": 2, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([9.175769574874302, 45.16792194842297]), + { + "class": 2, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([9.20426536344852, 45.16332274987339]), + { + "class": 2, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([9.213878400557896, 45.141774192169606]), + { + "class": 2, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([9.21628165983524, 45.15121782146389]), + { + "class": 2, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([9.222804792159458, 45.14371147444317]), + { + "class": 2, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([9.255763776534458, 45.136446326478705]), + { + "class": 2, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([9.313441999190708, 45.12167100406328]), + { + "class": 2, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([9.151736982100864, 45.12142875377629]), + { + "class": 2, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([9.105045087569614, 45.10374170456197]), + { + "class": 2, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([9.07071281217899, 45.09622910773991]), + { + "class": 2, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([9.38107658171024, 45.10010670050038]), + { + "class": 2, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([9.406482465499302, 45.093078369729355]), + { + "class": 2, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([9.424335248702427, 45.09089698773592]), + { + "class": 2, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([9.399529842312088, 44.059942165310375]), + { + "class": 2, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([8.877679256374588, 44.17036779637155]), + { + "class": 2, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([9.355584529812088, 43.96512739709022]), + { + "class": 2, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([9.064446834499588, 44.22550322825024]), + { + "class": 2, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([9.053460506374588, 44.15460533997702]), + { + "class": 2, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([9.597283748562088, 43.88995820658324]), + { + "class": 2, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([10.204020885402908, 44.67242037723368]), + { + "class": 2, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([10.200415996486893, 44.66991778726374]), + { + "class": 2, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([10.198699382717361, 44.668513848016225]), + { + "class": 2, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([10.195094493801346, 44.666072133544375]), + { + "class": 2, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([10.192862895900955, 44.66472914674318]), + { + "class": 2, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([10.18874302285408, 44.66283670344126]), + { + "class": 2, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([10.185309795315018, 44.66045579992672]), + { + "class": 2, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([10.090552715236893, 44.69024057554722]), + { + "class": 2, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([9.884559062893143, 44.6882879445253]), + { + "class": 2, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([10.091239360744705, 44.687555690920945]), + { + "class": 2, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([10.085917858059158, 44.682429656495245]), + { + "class": 2, + "system:index": "99" + })]), + herbaceous = + + # shown: False # + ee.FeatureCollection( + [ee.Feature( + ee.Geometry.Point([9.647866129015439, 45.00732805319811]), + { + "class": 3, + "system:index": "0" + }), + ee.Feature( + ee.Geometry.Point([9.63911139879083, 45.00150212185294]), + { + "class": 3, + "system:index": "1" + }), + ee.Feature( + ee.Geometry.Point([9.63859641465997, 44.995432813342106]), + { + "class": 3, + "system:index": "2" + }), + ee.Feature( + ee.Geometry.Point([9.679108499620908, 44.99688950601573]), + { + "class": 3, + "system:index": "3" + }), + ee.Feature( + ee.Geometry.Point([9.680653452013486, 44.99106251314061]), + { + "class": 3, + "system:index": "4" + }), + ee.Feature( + ee.Geometry.Point([9.616967081163876, 44.98474926892666]), + { + "class": 3, + "system:index": "5" + }), + ee.Feature( + ee.Geometry.Point([9.625550150011533, 44.984627853569535]), + { + "class": 3, + "system:index": "6" + }), + ee.Feature( + ee.Geometry.Point([9.577313303087704, 44.99968139680247]), + { + "class": 3, + "system:index": "7" + }), + ee.Feature( + ee.Geometry.Point([9.682183386109417, 45.11939912570097]), + { + "class": 3, + "system:index": "8" + }), + ee.Feature( + ee.Geometry.Point([9.662270666382854, 45.142166966714186]), + { + "class": 3, + "system:index": "9" + }), + ee.Feature( + ee.Geometry.Point([9.655747534058635, 45.14483069451677]), + { + "class": 3, + "system:index": "10" + }), + ee.Feature( + ee.Geometry.Point([9.602875829957073, 45.13926093989158]), + { + "class": 3, + "system:index": "11" + }), + ee.Feature( + ee.Geometry.Point([9.57849991442973, 45.14265129011751]), + { + "class": 3, + "system:index": "12" + }), + ee.Feature( + ee.Geometry.Point([9.56476700427348, 45.14047180240153]), + { + "class": 3, + "system:index": "13" + }), + ee.Feature( + ee.Geometry.Point([9.55652725817973, 45.11794555067206]), + { + "class": 3, + "system:index": "14" + }), + ee.Feature( + ee.Geometry.Point([9.511208654664104, 45.12666644539884]), + { + "class": 3, + "system:index": "15" + }), + ee.Feature( + ee.Geometry.Point([9.601502538941448, 45.15887374651922]), + { + "class": 3, + "system:index": "16" + }), + ee.Feature( + ee.Geometry.Point([9.770417333863323, 45.15378959281897]), + { + "class": 3, + "system:index": "17" + }), + ee.Feature( + ee.Geometry.Point([9.706286368107783, 45.13319818507588]), + { + "class": 3, + "system:index": "18" + }), + ee.Feature( + ee.Geometry.Point([9.704827246403681, 45.13574123701328]), + { + "class": 3, + "system:index": "19" + }), + ee.Feature( + ee.Geometry.Point([9.699248251652705, 45.13955560228794]), + { + "class": 3, + "system:index": "20" + }), + ee.Feature( + ee.Geometry.Point([9.688776907658564, 45.13598342652142]), + { + "class": 3, + "system:index": "21" + }), + ee.Feature( + ee.Geometry.Point([9.688519415593134, 45.130655019734995]), + { + "class": 3, + "system:index": "22" + }), + ee.Feature( + ee.Geometry.Point([9.653500494694697, 45.13997940490131]), + { + "class": 3, + "system:index": "23" + }), + ee.Feature( + ee.Geometry.Point([9.67341321442126, 45.12260091467352]), + { + "class": 3, + "system:index": "24" + }), + ee.Feature( + ee.Geometry.Point([10.7573680083494, 44.76085711753607]), + { + "class": 3, + "system:index": "25" + }), + ee.Feature( + ee.Geometry.Point([10.787065426562291, 44.77743157501226]), + { + "class": 3, + "system:index": "26" + }), + ee.Feature( + ee.Geometry.Point([10.805604855273229, 44.78193997941965]), + { + "class": 3, + "system:index": "27" + }), + ee.Feature( + ee.Geometry.Point([10.800111691210729, 44.782914723275496]), + { + "class": 3, + "system:index": "28" + }), + ee.Feature( + ee.Geometry.Point([10.801484982226354, 44.78206182330164]), + { + "class": 3, + "system:index": "29" + }), + ee.Feature( + ee.Geometry.Point([10.701234738085729, 44.76743872144162]), + { + "class": 3, + "system:index": "30" + }), + ee.Feature( + ee.Geometry.Point([10.706727902148229, 44.77036363804527]), + { + "class": 3, + "system:index": "31" + }), + ee.Feature( + ee.Geometry.Point([10.716512600634557, 44.77060737440978]), + { + "class": 3, + "system:index": "32" + }), + ee.Feature( + ee.Geometry.Point([10.714281002734166, 44.773775853547704]), + { + "class": 3, + "system:index": "33" + }), + ee.Feature( + ee.Geometry.Point([10.724237362597448, 44.78133075615248]), + { + "class": 3, + "system:index": "34" + }), + ee.Feature( + ee.Geometry.Point([10.686300198290807, 44.778650097404636]), + { + "class": 3, + "system:index": "35" + }), + ee.Feature( + ee.Geometry.Point([10.69797317192362, 44.78474232364748]), + { + "class": 3, + "system:index": "36" + }), + ee.Feature( + ee.Geometry.Point([10.726983944628698, 44.74257095015713]), + { + "class": 3, + "system:index": "37" + }), + ee.Feature( + ee.Geometry.Point([10.732305447314245, 44.750617576606686]), + { + "class": 3, + "system:index": "38" + }), + ee.Feature( + ee.Geometry.Point([10.73367873832987, 44.749886111397124]), + { + "class": 3, + "system:index": "39" + }), + ee.Feature( + ee.Geometry.Point([10.747926632616979, 44.74842315320647]), + { + "class": 3, + "system:index": "40" + }), + ee.Feature( + ee.Geometry.Point([10.800111691210729, 44.74915463693038]), + { + "class": 3, + "system:index": "41" + }), + ee.Feature( + ee.Geometry.Point([10.840967098925573, 44.745740967018534]), + { + "class": 3, + "system:index": "42" + }), + ee.Feature( + ee.Geometry.Point([10.823457638476354, 44.747691660225364]), + { + "class": 3, + "system:index": "43" + }), + ee.Feature( + ee.Geometry.Point([10.828607479784948, 44.75659086265001]), + { + "class": 3, + "system:index": "44" + }), + ee.Feature( + ee.Geometry.Point([10.832384030077916, 44.76280730056898]), + { + "class": 3, + "system:index": "45" + }), + ee.Feature( + ee.Geometry.Point([10.838563839648229, 44.780234138071414]), + { + "class": 3, + "system:index": "46" + }), + ee.Feature( + ee.Geometry.Point([10.360658566210729, 45.27366166900315]), + { + "class": 3, + "system:index": "47" + }), + ee.Feature( + ee.Geometry.Point([10.357225338671666, 45.305061440557125]), + { + "class": 3, + "system:index": "48" + }), + ee.Feature( + ee.Geometry.Point([10.356538693163854, 45.302163728326626]), + { + "class": 3, + "system:index": "49" + }), + ee.Feature( + ee.Geometry.Point([10.357911984179479, 45.292986662466724]), + { + "class": 3, + "system:index": "50" + }), + ee.Feature( + ee.Geometry.Point([10.352418820116979, 45.292986662466724]), + { + "class": 3, + "system:index": "51" + }), + ee.Feature( + ee.Geometry.Point([10.322549740527135, 45.28090931297517]), + { + "class": 3, + "system:index": "52" + }), + ee.Feature( + ee.Geometry.Point([10.297487179491979, 45.27994301393099]), + { + "class": 3, + "system:index": "53" + }), + ee.Feature( + ee.Geometry.Point([10.301607052538854, 45.2668963660993]), + { + "class": 3, + "system:index": "54" + }), + ee.Feature( + ee.Geometry.Point([10.33490935966776, 45.260371917443365]), + { + "class": 3, + "system:index": "55" + }), + ee.Feature( + ee.Geometry.Point([10.327699581835729, 45.25819693459614]), + { + "class": 3, + "system:index": "56" + }), + ee.Feature( + ee.Geometry.Point([10.265901486132604, 45.25215487843267]), + { + "class": 3, + "system:index": "57" + }), + ee.Feature( + ee.Geometry.Point([10.249078671191198, 45.27559446457621]), + { + "class": 3, + "system:index": "58" + }), + ee.Feature( + ee.Geometry.Point([10.238092343066198, 45.28260029670276]), + { + "class": 3, + "system:index": "59" + }), + ee.Feature( + ee.Geometry.Point([10.248048702929479, 45.271728807601804]), + { + "class": 3, + "system:index": "60" + }), + ee.Feature( + ee.Geometry.Point([10.228135983202916, 45.26303011666926]), + { + "class": 3, + "system:index": "61" + }), + ee.Feature( + ee.Geometry.Point([10.307786862109166, 45.234508395220274]), + { + "class": 3, + "system:index": "62" + }), + ee.Feature( + ee.Geometry.Point([10.288904110644323, 45.23934359330129]), + { + "class": 3, + "system:index": "63" + }), + ee.Feature( + ee.Geometry.Point([10.277574459765416, 45.23475016489584]), + { + "class": 3, + "system:index": "64" + }), + ee.Feature( + ee.Geometry.Point([10.344179074023229, 45.23063994052452]), + { + "class": 3, + "system:index": "65" + }), + ee.Feature( + ee.Geometry.Point([10.394647518847448, 45.25771359376027]), + { + "class": 3, + "system:index": "66" + }), + ee.Feature( + ee.Geometry.Point([10.459878842089635, 45.25674689974561]), + { + "class": 3, + "system:index": "67" + }), + ee.Feature( + ee.Geometry.Point([10.467775265429479, 45.26544655342014]), + { + "class": 3, + "system:index": "68" + }), + ee.Feature( + ee.Geometry.Point([10.542276303027135, 45.293228183228244]), + { + "class": 3, + "system:index": "69" + }), + ee.Feature( + ee.Geometry.Point([10.533693234179479, 45.30602731172016]), + { + "class": 3, + "system:index": "70" + }), + ee.Feature( + ee.Geometry.Point([10.553262631152135, 45.30433702638502]), + { + "class": 3, + "system:index": "71" + }), + ee.Feature( + ee.Geometry.Point([10.585191647265416, 45.292020569135126]), + { + "class": 3, + "system:index": "72" + }), + ee.Feature( + ee.Geometry.Point([10.575235287402135, 45.24417837995096]), + { + "class": 3, + "system:index": "73" + }), + ee.Feature( + ee.Geometry.Point([10.557725826952916, 45.2311235117616]), + { + "class": 3, + "system:index": "74" + }), + ee.Feature( + ee.Geometry.Point([10.521333615038854, 45.24321145553549]), + { + "class": 3, + "system:index": "75" + }), + ee.Feature( + ee.Geometry.Point([10.50794402763651, 45.22386951120088]), + { + "class": 3, + "system:index": "76" + }), + ee.Feature( + ee.Geometry.Point([10.484941403124791, 45.229189202127266]), + { + "class": 3, + "system:index": "77" + }), + ee.Feature( + ee.Geometry.Point([10.43653289482401, 45.21226118479587]), + { + "class": 3, + "system:index": "78" + }), + ee.Feature( + ee.Geometry.Point([10.404603878710729, 45.21226118479587]), + { + "class": 3, + "system:index": "79" + }), + ee.Feature( + ee.Geometry.Point([10.394304196093541, 45.22870561443287]), + { + "class": 3, + "system:index": "80" + }), + ee.Feature( + ee.Geometry.Point([10.098933611495559, 45.29673011868558]), + { + "class": 3, + "system:index": "81" + }), + ee.Feature( + ee.Geometry.Point([10.108460817916457, 45.295643334272455]), + { + "class": 3, + "system:index": "82" + }), + ee.Feature( + ee.Geometry.Point([10.06717625675923, 45.29775650706211]), + { + "class": 3, + "system:index": "83" + }), + ee.Feature( + ee.Geometry.Point([10.045289431197707, 45.30131853435977]), + { + "class": 3, + "system:index": "84" + }), + ee.Feature( + ee.Geometry.Point([10.05146924076802, 45.30373334083693]), + { + "class": 3, + "system:index": "85" + }), + ee.Feature( + ee.Geometry.Point([10.083569918258254, 45.304397394586246]), + { + "class": 3, + "system:index": "86" + }), + ee.Feature( + ee.Geometry.Point([10.08717480717427, 45.284895122576465]), + { + "class": 3, + "system:index": "87" + }), + ee.Feature( + ee.Geometry.Point([10.095929537398879, 45.281150885164806]), + { + "class": 3, + "system:index": "88" + }), + ee.Feature( + ee.Geometry.Point([9.719647799117629, 45.4015670962912]), + { + "class": 3, + "system:index": "89" + }), + ee.Feature( + ee.Geometry.Point([9.755353365523879, 45.40928043956986]), + { + "class": 3, + "system:index": "90" + }), + ee.Feature( + ee.Geometry.Point([9.740247164352004, 45.43988238640316]), + { + "class": 3, + "system:index": "91" + }), + ee.Feature( + ee.Geometry.Point([9.67467251835591, 45.423017223473764]), + { + "class": 3, + "system:index": "92" + }), + ee.Feature( + ee.Geometry.Point([9.667462740523879, 45.43072763756811]), + { + "class": 3, + "system:index": "93" + }), + ee.Feature( + ee.Geometry.Point([9.640683565719192, 45.38637837388185]), + { + "class": 3, + "system:index": "94" + }), + ee.Feature( + ee.Geometry.Point([9.699735079391067, 45.39023621391478]), + { + "class": 3, + "system:index": "95" + }), + ee.Feature( + ee.Geometry.Point([9.670552645309035, 45.384449355127416]), + { + "class": 3, + "system:index": "96" + }), + ee.Feature( + ee.Geometry.Point([9.665402804000442, 45.39361160795464]), + { + "class": 3, + "system:index": "97" + }), + ee.Feature( + ee.Geometry.Point([9.604977999312942, 45.38155570357316]), + { + "class": 3, + "system:index": "98" + }), + ee.Feature( + ee.Geometry.Point([9.596051607711379, 45.39602248027528]), + { + "class": 3, + "system:index": "99" + })]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# Create an Earth Engine Point object over Milan. +pt = ee.Geometry.Point([9.453, 45.424]) + +# Filter the Landsat 8 collection and select the least cloudy image. +landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(pt) \ + .filterDate('2019-01-01', '2020-01-01') \ + .sort('CLOUD_COVER') \ + .first() + +# Add NDVI and NDWI as bands. +ndvi = landsat.normalizedDifference(['SR_B5', 'SR_B4']).rename('ndvi') +ndwi = landsat.normalizedDifference(['SR_B5', 'SR_B6']).rename('ndwi') +landsat = landsat.addBands(ndvi).addBands(ndwi) + +# Center the map on that image. +Map.centerObject(landsat, 8) + +# Add Landsat image to the map. +visParams = {'bands': ['SR_B4', 'SR_B3', 'SR_B2'], 'min': 7000, 'max': 12000} +Map.addLayer(landsat, visParams, 'Landsat 8 image') + +# Combine training feature collections. Here we are using 100 points per class. +# See imports at the top. +trainingFeatures = ee.FeatureCollection([ + forest, developed, water, herbaceous +]).flatten() + +# Define the prediction bands. +predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', 'ST_B10', + 'ndvi', 'ndwi' +] + +# Sample training points. +classifierTraining = landsat.select(predictionBands) \ + .sampleRegions({ + 'collection': trainingFeatures, + 'properties': ['class'], + 'scale': 30 + }) + +######## CART Classifier #########/ + +# Train a CART Classifier. +classifier = ee.Classifier.smileCart().train({ + 'features': classifierTraining, + 'classProperty': 'class', + 'inputProperties': predictionBands +}) + +# Classify the Landsat image. +classified = landsat.select(predictionBands).classify(classifier) + +# Define classification image visualization parameters. +classificationVis = { + 'min': 0, 'max': 3, 'palette': ['589400', 'ff0000', '1a11ff', 'd0741e'] +} + +# Add the classified image to the map. +Map.addLayer(classified, classificationVis, 'CART classified') + +#######/ Random Forest Classifier ##########/ + +# Train RF classifier. +RFclassifier = ee.Classifier.smileRandomForest(50).train({ + 'features': classifierTraining, + 'classProperty': 'class', + 'inputProperties': predictionBands +}) + +# Classify Landsat image. +RFclassified = landsat.select(predictionBands).classify(RFclassifier) + +# Add classified image to the map. +Map.addLayer(RFclassified, classificationVis, 'RF classified') + +######## Unsupervised classification ######## + +# Make the training dataset. +training = landsat.sample({ + 'region': landsat.geometry(), + 'scale': 30, + 'numPixels': 1000, + 'tileScale': 8 +}) + +# Instantiate the clusterer and train it. +clusterer = ee.Clusterer.wekaKMeans(4).train(training) + +# Cluster the input using the trained clusterer. +Kclassified = landsat.cluster(clusterer) + +# Display the clusters with random colors. +Map.addLayer(Kclassified.randomVisualizer(), {}, 'K-means classified - random colors') + +# Display the clusters with same palette as supervised classification +# herbaceous is 0, water is 1, forest is 2, developed is 3. +Map.addLayer(Kclassified, + {'min': 0, 'max': 3, 'palette': ['d0741e','1a11ff','589400', 'ff0000']}, + 'K-means classified') +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22a Checkpoint.ipynb new file mode 100644 index 0000000..a2efbd8 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22a Checkpoint.ipynb @@ -0,0 +1,142 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F2.2 Accuracy Assessment: Quantifying Classification Quality\n", + "# Checkpoint: F22a\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the reference dataset.\n", + "data = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/F2-2/milan_data')\n", + "\n", + "# Define the prediction bands.\n", + "predictionBands = [\n", + " 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7',\n", + " 'ST_B10',\n", + " 'ndvi', 'ndwi'\n", + "]\n", + "\n", + "# Split the dataset into training and testing sets.\n", + "trainingTesting = data.randomColumn()\n", + "trainingSet = trainingTesting \\\n", + " .filter(ee.Filter.lessThan('random', 0.8))\n", + "testingSet = trainingTesting \\\n", + " .filter(ee.Filter.greaterThanOrEquals('random', 0.8))\n", + "\n", + "# Train the Random Forest Classifier with the trainingSet.\n", + "RFclassifier = ee.Classifier.smileRandomForest(50).train({\n", + " 'features': trainingSet,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + "})\n", + "\n", + "# Now, to test the classification (verify model's accuracy),\n", + "# we classify the testingSet and get a confusion matrix.\n", + "confusionMatrix = testingSet.classify(RFclassifier) \\\n", + " .errorMatrix({\n", + " 'actual': 'class',\n", + " 'predicted': 'classification'\n", + " })\n", + "\n", + "# Print the results.\n", + "print('Confusion matrix:', confusionMatrix)\n", + "print('Overall Accuracy:', confusionMatrix.accuracy())\n", + "print('Producers Accuracy:', confusionMatrix.producersAccuracy())\n", + "print('Consumers Accuracy:', confusionMatrix.consumersAccuracy())\n", + "print('Kappa:', confusionMatrix.kappa())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22a Checkpoint.js b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22a Checkpoint.js new file mode 100644 index 0000000..770f4f8 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22a Checkpoint.js @@ -0,0 +1,50 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F2.2 Accuracy Assessment: Quantifying Classification Quality +// Checkpoint: F22a +// Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the reference dataset. +var data = ee.FeatureCollection( + 'projects/gee-book/assets/F2-2/milan_data'); + +// Define the prediction bands. +var predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10', + 'ndvi', 'ndwi' +]; + +// Split the dataset into training and testing sets. +var trainingTesting = data.randomColumn(); +var trainingSet = trainingTesting + .filter(ee.Filter.lessThan('random', 0.8)); +var testingSet = trainingTesting + .filter(ee.Filter.greaterThanOrEquals('random', 0.8)); + +// Train the Random Forest Classifier with the trainingSet. +var RFclassifier = ee.Classifier.smileRandomForest(50).train({ + features: trainingSet, + classProperty: 'class', + inputProperties: predictionBands +}); + +// Now, to test the classification (verify model's accuracy), +// we classify the testingSet and get a confusion matrix. +var confusionMatrix = testingSet.classify(RFclassifier) + .errorMatrix({ + actual: 'class', + predicted: 'classification' + }); + +// Print the results. +print('Confusion matrix:', confusionMatrix); +print('Overall Accuracy:', confusionMatrix.accuracy()); +print('Producers Accuracy:', confusionMatrix.producersAccuracy()); +print('Consumers Accuracy:', confusionMatrix.consumersAccuracy()); +print('Kappa:', confusionMatrix.kappa()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22a Checkpoint.py b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22a Checkpoint.py new file mode 100644 index 0000000..41fd8e6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22a Checkpoint.py @@ -0,0 +1,56 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F2.2 Accuracy Assessment: Quantifying Classification Quality +# Checkpoint: F22a +# Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the reference dataset. +data = ee.FeatureCollection( + 'projects/gee-book/assets/F2-2/milan_data') + +# Define the prediction bands. +predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10', + 'ndvi', 'ndwi' +] + +# Split the dataset into training and testing sets. +trainingTesting = data.randomColumn() +trainingSet = trainingTesting \ + .filter(ee.Filter.lessThan('random', 0.8)) +testingSet = trainingTesting \ + .filter(ee.Filter.greaterThanOrEquals('random', 0.8)) + +# Train the Random Forest Classifier with the trainingSet. +RFclassifier = ee.Classifier.smileRandomForest(50).train({ + 'features': trainingSet, + 'classProperty': 'class', + 'inputProperties': predictionBands +}) + +# Now, to test the classification (verify model's accuracy), +# we classify the testingSet and get a confusion matrix. +confusionMatrix = testingSet.classify(RFclassifier) \ + .errorMatrix({ + 'actual': 'class', + 'predicted': 'classification' + }) + +# Print the results. +print('Confusion matrix:', confusionMatrix) +print('Overall Accuracy:', confusionMatrix.accuracy()) +print('Producers Accuracy:', confusionMatrix.producersAccuracy()) +print('Consumers Accuracy:', confusionMatrix.consumersAccuracy()) +print('Kappa:', confusionMatrix.kappa()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22b Checkpoint.ipynb new file mode 100644 index 0000000..649418a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22b Checkpoint.ipynb @@ -0,0 +1,190 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F2.2 Accuracy Assessment: Quantifying Classification Quality\n", + "# Checkpoint: F22b\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the reference dataset.\n", + "data = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/F2-2/milan_data')\n", + "\n", + "# Define the prediction bands.\n", + "predictionBands = [\n", + " 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7',\n", + " 'ST_B10',\n", + " 'ndvi', 'ndwi'\n", + "]\n", + "\n", + "# Split the dataset into training and testing sets.\n", + "trainingTesting = data.randomColumn()\n", + "trainingSet = trainingTesting \\\n", + " .filter(ee.Filter.lessThan('random', 0.8))\n", + "testingSet = trainingTesting \\\n", + " .filter(ee.Filter.greaterThanOrEquals('random', 0.8))\n", + "\n", + "# Train the Random Forest Classifier with the trainingSet.\n", + "RFclassifier = ee.Classifier.smileRandomForest(50).train({\n", + " 'features': trainingSet,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + "})\n", + "\n", + "# Now, to test the classification (verify model's accuracy),\n", + "# we classify the testingSet and get a confusion matrix.\n", + "confusionMatrix = testingSet.classify(RFclassifier) \\\n", + " .errorMatrix({\n", + " 'actual': 'class',\n", + " 'predicted': 'classification'\n", + " })\n", + "\n", + "# Print the results.\n", + "print('Confusion matrix:', confusionMatrix)\n", + "print('Overall Accuracy:', confusionMatrix.accuracy())\n", + "print('Producers Accuracy:', confusionMatrix.producersAccuracy())\n", + "print('Consumers Accuracy:', confusionMatrix.consumersAccuracy())\n", + "print('Kappa:', confusionMatrix.kappa())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Hyperparameter tuning.\n", + "numTrees = ee.List.sequence(5, 100, 5)\n", + "\n", + "\n", + "def func_ehk(t):\n", + " classifier = ee.Classifier.smileRandomForest(t) \\\n", + " .train({\n", + " 'features': trainingSet,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + " })\n", + " return testingSet \\\n", + " .classify(classifier) \\\n", + " .errorMatrix('class', 'classification') \\\n", + " .accuracy()\n", + "\n", + "accuracies = numTrees.map(func_ehk)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "print(ui.Chart.array.values({\n", + " 'array': ee.Array(accuracies),\n", + " 'axis': 0,\n", + " 'xLabels': numTrees\n", + "}).setOptions({\n", + " 'hAxis': {\n", + " 'title': 'Number of trees'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Accuracy'\n", + " },\n", + " 'title': 'Accuracy per number of trees'\n", + "}))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22b Checkpoint.js b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22b Checkpoint.js new file mode 100644 index 0000000..110bb82 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22b Checkpoint.js @@ -0,0 +1,83 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F2.2 Accuracy Assessment: Quantifying Classification Quality +// Checkpoint: F22b +// Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the reference dataset. +var data = ee.FeatureCollection( + 'projects/gee-book/assets/F2-2/milan_data'); + +// Define the prediction bands. +var predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10', + 'ndvi', 'ndwi' +]; + +// Split the dataset into training and testing sets. +var trainingTesting = data.randomColumn(); +var trainingSet = trainingTesting + .filter(ee.Filter.lessThan('random', 0.8)); +var testingSet = trainingTesting + .filter(ee.Filter.greaterThanOrEquals('random', 0.8)); + +// Train the Random Forest Classifier with the trainingSet. +var RFclassifier = ee.Classifier.smileRandomForest(50).train({ + features: trainingSet, + classProperty: 'class', + inputProperties: predictionBands +}); + +// Now, to test the classification (verify model's accuracy), +// we classify the testingSet and get a confusion matrix. +var confusionMatrix = testingSet.classify(RFclassifier) + .errorMatrix({ + actual: 'class', + predicted: 'classification' + }); + +// Print the results. +print('Confusion matrix:', confusionMatrix); +print('Overall Accuracy:', confusionMatrix.accuracy()); +print('Producers Accuracy:', confusionMatrix.producersAccuracy()); +print('Consumers Accuracy:', confusionMatrix.consumersAccuracy()); +print('Kappa:', confusionMatrix.kappa()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Hyperparameter tuning. +var numTrees = ee.List.sequence(5, 100, 5); + +var accuracies = numTrees.map(function(t) { + var classifier = ee.Classifier.smileRandomForest(t) + .train({ + features: trainingSet, + classProperty: 'class', + inputProperties: predictionBands + }); + return testingSet + .classify(classifier) + .errorMatrix('class', 'classification') + .accuracy(); +}); + +print(ui.Chart.array.values({ + array: ee.Array(accuracies), + axis: 0, + xLabels: numTrees +}).setOptions({ + hAxis: { + title: 'Number of trees' + }, + vAxis: { + title: 'Accuracy' + }, + title: 'Accuracy per number of trees' +})); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22b Checkpoint.py b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22b Checkpoint.py new file mode 100644 index 0000000..671afd0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22b Checkpoint.py @@ -0,0 +1,103 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F2.2 Accuracy Assessment: Quantifying Classification Quality +# Checkpoint: F22b +# Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the reference dataset. +data = ee.FeatureCollection( + 'projects/gee-book/assets/F2-2/milan_data') + +# Define the prediction bands. +predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10', + 'ndvi', 'ndwi' +] + +# Split the dataset into training and testing sets. +trainingTesting = data.randomColumn() +trainingSet = trainingTesting \ + .filter(ee.Filter.lessThan('random', 0.8)) +testingSet = trainingTesting \ + .filter(ee.Filter.greaterThanOrEquals('random', 0.8)) + +# Train the Random Forest Classifier with the trainingSet. +RFclassifier = ee.Classifier.smileRandomForest(50).train({ + 'features': trainingSet, + 'classProperty': 'class', + 'inputProperties': predictionBands +}) + +# Now, to test the classification (verify model's accuracy), +# we classify the testingSet and get a confusion matrix. +confusionMatrix = testingSet.classify(RFclassifier) \ + .errorMatrix({ + 'actual': 'class', + 'predicted': 'classification' + }) + +# Print the results. +print('Confusion matrix:', confusionMatrix) +print('Overall Accuracy:', confusionMatrix.accuracy()) +print('Producers Accuracy:', confusionMatrix.producersAccuracy()) +print('Consumers Accuracy:', confusionMatrix.consumersAccuracy()) +print('Kappa:', confusionMatrix.kappa()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Hyperparameter tuning. +numTrees = ee.List.sequence(5, 100, 5) + + +def func_ehk(t): + classifier = ee.Classifier.smileRandomForest(t) \ + .train({ + 'features': trainingSet, + 'classProperty': 'class', + 'inputProperties': predictionBands + }) + return testingSet \ + .classify(classifier) \ + .errorMatrix('class', 'classification') \ + .accuracy() + +accuracies = numTrees.map(func_ehk) + + + + + + + + + + + + + +print(ui.Chart.array.values({ + 'array': ee.Array(accuracies), + 'axis': 0, + 'xLabels': numTrees +}).setOptions({ + 'hAxis': { + 'title': 'Number of trees' + }, + 'vAxis': { + 'title': 'Accuracy' + }, + 'title': 'Accuracy per number of trees' +})) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22c Checkpoint.ipynb new file mode 100644 index 0000000..d9a630c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22c Checkpoint.ipynb @@ -0,0 +1,154 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F2.2 Accuracy Assessment: Quantifying Classification Quality\n", + "# Checkpoint: F22c\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the reference dataset.\n", + "data = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/F2-2/milan_data')\n", + "\n", + "# Define the prediction bands.\n", + "predictionBands = [\n", + " 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7',\n", + " 'ST_B10',\n", + " 'ndvi', 'ndwi'\n", + "]\n", + "\n", + "# Split the dataset into training and testing sets.\n", + "trainingTesting = data.randomColumn()\n", + "trainingSet = trainingTesting \\\n", + " .filter(ee.Filter.lessThan('random', 0.8))\n", + "testingSet = trainingTesting \\\n", + " .filter(ee.Filter.greaterThanOrEquals('random', 0.8))\n", + "\n", + "# Spatial join.\n", + "distFilter = ee.Filter.withinDistance({\n", + " 'distance': 1000,\n", + " 'leftField': '.geo',\n", + " 'rightField': '.geo',\n", + " 'maxError': 10\n", + "})\n", + "\n", + "join = ee.Join.inverted()\n", + "\n", + "trainingSet = join.apply(trainingSet, testingSet, distFilter)\n", + "\n", + "# Train the Random Forest Classifier with the trainingSet.\n", + "RFclassifier = ee.Classifier.smileRandomForest(50).train({\n", + " 'features': trainingSet,\n", + " 'classProperty': 'class',\n", + " 'inputProperties': predictionBands\n", + "})\n", + "\n", + "# Now, to test the classification (verify model's accuracy),\n", + "# we classify the testingSet and get a confusion matrix.\n", + "confusionMatrix = testingSet.classify(RFclassifier) \\\n", + " .errorMatrix({\n", + " 'actual': 'class',\n", + " 'predicted': 'classification'\n", + " })\n", + "\n", + "# Print the results.\n", + "print('Confusion matrix:', confusionMatrix)\n", + "print('Overall Accuracy:', confusionMatrix.accuracy())\n", + "print('Producers Accuracy:', confusionMatrix.producersAccuracy())\n", + "print('Consumers Accuracy:', confusionMatrix.consumersAccuracy())\n", + "print('Kappa:', confusionMatrix.kappa())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22c Checkpoint.js b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22c Checkpoint.js new file mode 100644 index 0000000..a06481d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22c Checkpoint.js @@ -0,0 +1,61 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F2.2 Accuracy Assessment: Quantifying Classification Quality +// Checkpoint: F22c +// Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the reference dataset. +var data = ee.FeatureCollection( + 'projects/gee-book/assets/F2-2/milan_data'); + +// Define the prediction bands. +var predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10', + 'ndvi', 'ndwi' +]; + +// Split the dataset into training and testing sets. +var trainingTesting = data.randomColumn(); +var trainingSet = trainingTesting + .filter(ee.Filter.lessThan('random', 0.8)); +var testingSet = trainingTesting + .filter(ee.Filter.greaterThanOrEquals('random', 0.8)); + +// Spatial join. +var distFilter = ee.Filter.withinDistance({ + distance: 1000, + leftField: '.geo', + rightField: '.geo', + maxError: 10 +}); + +var join = ee.Join.inverted(); + +var trainingSet = join.apply(trainingSet, testingSet, distFilter); + +// Train the Random Forest Classifier with the trainingSet. +var RFclassifier = ee.Classifier.smileRandomForest(50).train({ + features: trainingSet, + classProperty: 'class', + inputProperties: predictionBands +}); + +// Now, to test the classification (verify model's accuracy), +// we classify the testingSet and get a confusion matrix. +var confusionMatrix = testingSet.classify(RFclassifier) + .errorMatrix({ + actual: 'class', + predicted: 'classification' + }); + +// Print the results. +print('Confusion matrix:', confusionMatrix); +print('Overall Accuracy:', confusionMatrix.accuracy()); +print('Producers Accuracy:', confusionMatrix.producersAccuracy()); +print('Consumers Accuracy:', confusionMatrix.consumersAccuracy()); +print('Kappa:', confusionMatrix.kappa()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22c Checkpoint.py b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22c Checkpoint.py new file mode 100644 index 0000000..146fdca --- /dev/null +++ b/docs/book/Part F - Fundamentals/F2 - Interpreting Images/F2.2 Accuracy Assessment/F22c Checkpoint.py @@ -0,0 +1,67 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F2.2 Accuracy Assessment: Quantifying Classification Quality +# Checkpoint: F22c +# Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the reference dataset. +data = ee.FeatureCollection( + 'projects/gee-book/assets/F2-2/milan_data') + +# Define the prediction bands. +predictionBands = [ + 'SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7', + 'ST_B10', + 'ndvi', 'ndwi' +] + +# Split the dataset into training and testing sets. +trainingTesting = data.randomColumn() +trainingSet = trainingTesting \ + .filter(ee.Filter.lessThan('random', 0.8)) +testingSet = trainingTesting \ + .filter(ee.Filter.greaterThanOrEquals('random', 0.8)) + +# Spatial join. +distFilter = ee.Filter.withinDistance({ + 'distance': 1000, + 'leftField': '.geo', + 'rightField': '.geo', + 'maxError': 10 +}) + +join = ee.Join.inverted() + +trainingSet = join.apply(trainingSet, testingSet, distFilter) + +# Train the Random Forest Classifier with the trainingSet. +RFclassifier = ee.Classifier.smileRandomForest(50).train({ + 'features': trainingSet, + 'classProperty': 'class', + 'inputProperties': predictionBands +}) + +# Now, to test the classification (verify model's accuracy), +# we classify the testingSet and get a confusion matrix. +confusionMatrix = testingSet.classify(RFclassifier) \ + .errorMatrix({ + 'actual': 'class', + 'predicted': 'classification' + }) + +# Print the results. +print('Confusion matrix:', confusionMatrix) +print('Overall Accuracy:', confusionMatrix.accuracy()) +print('Producers Accuracy:', confusionMatrix.producersAccuracy()) +print('Consumers Accuracy:', confusionMatrix.consumersAccuracy()) +print('Kappa:', confusionMatrix.kappa()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30a Checkpoint.ipynb new file mode 100644 index 0000000..777e855 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30a Checkpoint.ipynb @@ -0,0 +1,195 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.0 Interpreting an Image: Regression\n", + "# Checkpoint: F30a\n", + "# Authors: K. Dyson, A. Nicolau, D. Saah, N. Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define a Turin polygon.\n", + "Turin = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [7.455553918110218, 45.258245019259036],\n", + " [7.455553918110218, 44.71237367431335],\n", + " [8.573412804828967, 44.71237367431335],\n", + " [8.573412804828967, 45.258245019259036]\n", + " ]\n", + " ], None, False)\n", + "\n", + "# Center on Turin\n", + "Map.centerObject(Turin, 9)\n", + "\n", + "mod44b = ee.ImageCollection('MODIS/006/MOD44B')\n", + "\n", + "##/\n", + "# Start Linear Fit\n", + "##/\n", + "\n", + "# Put together the dependent variable by filtering the\n", + "# ImageCollection to just the 2020 image near Turin and\n", + "# selecting the percent tree cover band.\n", + "percentTree2020 = mod44b \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .first() \\\n", + " .clip(Turin) \\\n", + " .select('Percent_Tree_Cover')\n", + "\n", + "# You can print information to the console for inspection.\n", + "print('2020 Image', percentTree2020)\n", + "\n", + "Map.addLayer(percentTree2020, {\n", + " 'max': 100\n", + "}, 'Percent Tree Cover')\n", + "\n", + "landsat8_raw = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT')\n", + "\n", + "# Put together the independent variable.\n", + "landsat8filtered = landsat8_raw \\\n", + " .filterBounds(Turin.centroid({\n", + " 'maxError': 1\n", + " })) \\\n", + " .filterDate('2020-04-01', '2020-4-30') \\\n", + " .first()\n", + "\n", + "print('Landsat8 filtered', landsat8filtered)\n", + "\n", + "# Display the L8 image.\n", + "visParams = {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'max': 16000\n", + "}\n", + "Map.addLayer(landsat8filtered, visParams, 'Landsat 8 Image')\n", + "\n", + "# Calculate NDVI which will be the independent variable.\n", + "ndvi = landsat8filtered.normalizedDifference(['B5', 'B4'])\n", + "\n", + "# Create the training image.\n", + "trainingImage = ndvi.addBands(percentTree2020)\n", + "print('training image for linear fit', trainingImage)\n", + "\n", + "\n", + "# Independent variable first, dependent variable second.\n", + "# You need to include the scale variable.\n", + "linearFit = trainingImage.reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': Turin,\n", + " 'scale': 30,\n", + " 'bestEffort': True\n", + "})\n", + "\n", + "# Inspect the results.\n", + "print('OLS estimates:', linearFit)\n", + "print('y-intercept:', linearFit.get('offset'))\n", + "print('Slope:', linearFit.get('scale'))\n", + "\n", + "# Create a prediction based on the linearFit model.\n", + "predictedTree = ndvi.expression(\n", + " 'intercept + slope * ndvi', {\n", + " 'ndvi': ndvi.select('nd'),\n", + " 'intercept': ee.Number(linearFit.get('offset')),\n", + " 'slope': ee.Number(linearFit.get('scale'))\n", + " })\n", + "\n", + "print('predictedTree', predictedTree)\n", + "\n", + "# Display the results.\n", + "Map.addLayer(predictedTree, {\n", + " 'max': 100\n", + "}, 'Predicted Percent Tree Cover')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30a Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30a Checkpoint.js new file mode 100644 index 0000000..e5ffdf5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30a Checkpoint.js @@ -0,0 +1,103 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.0 Interpreting an Image: Regression +// Checkpoint: F30a +// Authors: K. Dyson, A. Nicolau, D. Saah, N. Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define a Turin polygon. +var Turin = ee.Geometry.Polygon( + [ + [ + [7.455553918110218, 45.258245019259036], + [7.455553918110218, 44.71237367431335], + [8.573412804828967, 44.71237367431335], + [8.573412804828967, 45.258245019259036] + ] + ], null, false); + +// Center on Turin +Map.centerObject(Turin, 9); + +var mod44b = ee.ImageCollection('MODIS/006/MOD44B'); + +///// +// Start Linear Fit +///// + +// Put together the dependent variable by filtering the +// ImageCollection to just the 2020 image near Turin and +// selecting the percent tree cover band. +var percentTree2020 = mod44b + .filterDate('2020-01-01', '2021-01-01') + .first() + .clip(Turin) + .select('Percent_Tree_Cover'); + +// You can print information to the console for inspection. +print('2020 Image', percentTree2020); + +Map.addLayer(percentTree2020, { + max: 100 +}, 'Percent Tree Cover'); + +var landsat8_raw = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT'); + +// Put together the independent variable. +var landsat8filtered = landsat8_raw + .filterBounds(Turin.centroid({ + 'maxError': 1 + })) + .filterDate('2020-04-01', '2020-4-30') + .first(); + +print('Landsat8 filtered', landsat8filtered); + +// Display the L8 image. +var visParams = { + bands: ['B4', 'B3', 'B2'], + max: 16000 +}; +Map.addLayer(landsat8filtered, visParams, 'Landsat 8 Image'); + +// Calculate NDVI which will be the independent variable. +var ndvi = landsat8filtered.normalizedDifference(['B5', 'B4']); + +// Create the training image. +var trainingImage = ndvi.addBands(percentTree2020); +print('training image for linear fit', trainingImage); + + +// Independent variable first, dependent variable second. +// You need to include the scale variable. +var linearFit = trainingImage.reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: Turin, + scale: 30, + bestEffort: true +}); + +// Inspect the results. +print('OLS estimates:', linearFit); +print('y-intercept:', linearFit.get('offset')); +print('Slope:', linearFit.get('scale')); + +// Create a prediction based on the linearFit model. +var predictedTree = ndvi.expression( + 'intercept + slope * ndvi', { + 'ndvi': ndvi.select('nd'), + 'intercept': ee.Number(linearFit.get('offset')), + 'slope': ee.Number(linearFit.get('scale')) + }); + +print('predictedTree', predictedTree); + +// Display the results. +Map.addLayer(predictedTree, { + max: 100 +}, 'Predicted Percent Tree Cover'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30a Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30a Checkpoint.py new file mode 100644 index 0000000..8b5e011 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30a Checkpoint.py @@ -0,0 +1,109 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.0 Interpreting an Image: Regression +# Checkpoint: F30a +# Authors: K. Dyson, A. Nicolau, D. Saah, N. Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define a Turin polygon. +Turin = ee.Geometry.Polygon( + [ + [ + [7.455553918110218, 45.258245019259036], + [7.455553918110218, 44.71237367431335], + [8.573412804828967, 44.71237367431335], + [8.573412804828967, 45.258245019259036] + ] + ], None, False) + +# Center on Turin +Map.centerObject(Turin, 9) + +mod44b = ee.ImageCollection('MODIS/006/MOD44B') + +##/ +# Start Linear Fit +##/ + +# Put together the dependent variable by filtering the +# ImageCollection to just the 2020 image near Turin and +# selecting the percent tree cover band. +percentTree2020 = mod44b \ + .filterDate('2020-01-01', '2021-01-01') \ + .first() \ + .clip(Turin) \ + .select('Percent_Tree_Cover') + +# You can print information to the console for inspection. +print('2020 Image', percentTree2020) + +Map.addLayer(percentTree2020, { + 'max': 100 +}, 'Percent Tree Cover') + +landsat8_raw = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT') + +# Put together the independent variable. +landsat8filtered = landsat8_raw \ + .filterBounds(Turin.centroid({ + 'maxError': 1 + })) \ + .filterDate('2020-04-01', '2020-4-30') \ + .first() + +print('Landsat8 filtered', landsat8filtered) + +# Display the L8 image. +visParams = { + 'bands': ['B4', 'B3', 'B2'], + 'max': 16000 +} +Map.addLayer(landsat8filtered, visParams, 'Landsat 8 Image') + +# Calculate NDVI which will be the independent variable. +ndvi = landsat8filtered.normalizedDifference(['B5', 'B4']) + +# Create the training image. +trainingImage = ndvi.addBands(percentTree2020) +print('training image for linear fit', trainingImage) + + +# Independent variable first, dependent variable second. +# You need to include the scale variable. +linearFit = trainingImage.reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': Turin, + 'scale': 30, + 'bestEffort': True +}) + +# Inspect the results. +print('OLS estimates:', linearFit) +print('y-intercept:', linearFit.get('offset')) +print('Slope:', linearFit.get('scale')) + +# Create a prediction based on the linearFit model. +predictedTree = ndvi.expression( + 'intercept + slope * ndvi', { + 'ndvi': ndvi.select('nd'), + 'intercept': ee.Number(linearFit.get('offset')), + 'slope': ee.Number(linearFit.get('scale')) + }) + +print('predictedTree', predictedTree) + +# Display the results. +Map.addLayer(predictedTree, { + 'max': 100 +}, 'Predicted Percent Tree Cover') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30b Checkpoint.ipynb new file mode 100644 index 0000000..3669604 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30b Checkpoint.ipynb @@ -0,0 +1,249 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.0 Interpreting an Image: Regression\n", + "# Checkpoint: F30b\n", + "# Authors: K. Dyson, A. Nicolau, D. Saah, N. Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define a Turin polygon.\n", + "Turin = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [7.455553918110218, 45.258245019259036],\n", + " [7.455553918110218, 44.71237367431335],\n", + " [8.573412804828967, 44.71237367431335],\n", + " [8.573412804828967, 45.258245019259036]\n", + " ]\n", + " ], None, False)\n", + "\n", + "# Center on Turin\n", + "Map.centerObject(Turin, 9)\n", + "\n", + "mod44b = ee.ImageCollection('MODIS/006/MOD44B')\n", + "\n", + "##/\n", + "# Start Linear Fit\n", + "##/\n", + "\n", + "# Put together the dependent variable by filtering the\n", + "# ImageCollection to just the 2020 image near Turin and\n", + "# selecting the percent tree cover band.\n", + "percentTree2020 = mod44b \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .first() \\\n", + " .clip(Turin) \\\n", + " .select('Percent_Tree_Cover')\n", + "\n", + "# You can print information to the console for inspection.\n", + "print('2020 Image', percentTree2020)\n", + "\n", + "Map.addLayer(percentTree2020, {\n", + " 'max': 100\n", + "}, 'Percent Tree Cover')\n", + "\n", + "landsat8_raw = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT')\n", + "\n", + "# Put together the independent variable.\n", + "landsat8filtered = landsat8_raw \\\n", + " .filterBounds(Turin.centroid({\n", + " 'maxError': 1\n", + " })) \\\n", + " .filterDate('2020-04-01', '2020-4-30') \\\n", + " .first()\n", + "\n", + "print('Landsat8 filtered', landsat8filtered)\n", + "\n", + "# Display the L8 image.\n", + "visParams = {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'max': 16000\n", + "}\n", + "Map.addLayer(landsat8filtered, visParams, 'Landsat 8 Image')\n", + "\n", + "# Calculate NDVI which will be the independent variable.\n", + "ndvi = landsat8filtered.normalizedDifference(['B5', 'B4'])\n", + "\n", + "# Create the training image.\n", + "trainingImage = ndvi.addBands(percentTree2020)\n", + "print('training image for linear fit', trainingImage)\n", + "\n", + "\n", + "# Independent variable first, dependent variable second.\n", + "# You need to include the scale variable.\n", + "linearFit = trainingImage.reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': Turin,\n", + " 'scale': 30,\n", + " 'bestEffort': True\n", + "})\n", + "\n", + "# Inspect the results.\n", + "print('OLS estimates:', linearFit)\n", + "print('y-intercept:', linearFit.get('offset'))\n", + "print('Slope:', linearFit.get('scale'))\n", + "\n", + "# Create a prediction based on the linearFit model.\n", + "predictedTree = ndvi.expression(\n", + " 'intercept + slope * ndvi', {\n", + " 'ndvi': ndvi.select('nd'),\n", + " 'intercept': ee.Number(linearFit.get('offset')),\n", + " 'slope': ee.Number(linearFit.get('scale'))\n", + " })\n", + "\n", + "print('predictedTree', predictedTree)\n", + "\n", + "# Display the results.\n", + "Map.addLayer(predictedTree, {\n", + " 'max': 100\n", + "}, 'Predicted Percent Tree Cover')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "###\n", + "# Start Linear Regression\n", + "###\n", + "\n", + "# Assemble the independent variables.\n", + "predictionBands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7',\n", + " 'B10', 'B11'\n", + "]\n", + "\n", + "# Create the training image stack for linear regression.\n", + "trainingImageLR = ee.Image(1) \\\n", + " .addBands(landsat8filtered.select(predictionBands)) \\\n", + " .addBands(percentTree2020)\n", + "\n", + "print('Linear Regression training image:', trainingImageLR)\n", + "\n", + "# Compute ordinary least squares regression coefficients using\n", + "# the linearRegression reducer.\n", + "linearRegression = trainingImageLR.reduceRegion({\n", + " 'reducer': ee.Reducer.linearRegression({\n", + " 'numX': 10,\n", + " 'numY': 1\n", + " }),\n", + " 'geometry': Turin,\n", + " 'scale': 30,\n", + " 'bestEffort': True\n", + "})\n", + "\n", + "# Inspect the results.\n", + "print('Linear regression results:', linearRegression)\n", + "\n", + "# Extract the coefficients as a list.\n", + "coefficients = ee.Array(linearRegression.get('coefficients')) \\\n", + " .project([0]) \\\n", + " .toList()\n", + "\n", + "print('Coefficients', coefficients)\n", + "\n", + "# Create the predicted tree cover based on linear regression.\n", + "predictedTreeLR = ee.Image(1) \\\n", + " .addBands(landsat8filtered.select(predictionBands)) \\\n", + " .multiply(ee.Image.constant(coefficients)) \\\n", + " .reduce(ee.Reducer.sum()) \\\n", + " .rename('predictedTreeLR') \\\n", + " .clip(landsat8filtered.geometry())\n", + "\n", + "Map.addLayer(predictedTreeLR, {\n", + " 'min': 0,\n", + " 'max': 100\n", + "}, 'LR prediction')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30b Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30b Checkpoint.js new file mode 100644 index 0000000..fe69f3a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30b Checkpoint.js @@ -0,0 +1,156 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.0 Interpreting an Image: Regression +// Checkpoint: F30b +// Authors: K. Dyson, A. Nicolau, D. Saah, N. Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define a Turin polygon. +var Turin = ee.Geometry.Polygon( + [ + [ + [7.455553918110218, 45.258245019259036], + [7.455553918110218, 44.71237367431335], + [8.573412804828967, 44.71237367431335], + [8.573412804828967, 45.258245019259036] + ] + ], null, false); + +// Center on Turin +Map.centerObject(Turin, 9); + +var mod44b = ee.ImageCollection('MODIS/006/MOD44B'); + +///// +// Start Linear Fit +///// + +// Put together the dependent variable by filtering the +// ImageCollection to just the 2020 image near Turin and +// selecting the percent tree cover band. +var percentTree2020 = mod44b + .filterDate('2020-01-01', '2021-01-01') + .first() + .clip(Turin) + .select('Percent_Tree_Cover'); + +// You can print information to the console for inspection. +print('2020 Image', percentTree2020); + +Map.addLayer(percentTree2020, { + max: 100 +}, 'Percent Tree Cover'); + +var landsat8_raw = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT'); + +// Put together the independent variable. +var landsat8filtered = landsat8_raw + .filterBounds(Turin.centroid({ + 'maxError': 1 + })) + .filterDate('2020-04-01', '2020-4-30') + .first(); + +print('Landsat8 filtered', landsat8filtered); + +// Display the L8 image. +var visParams = { + bands: ['B4', 'B3', 'B2'], + max: 16000 +}; +Map.addLayer(landsat8filtered, visParams, 'Landsat 8 Image'); + +// Calculate NDVI which will be the independent variable. +var ndvi = landsat8filtered.normalizedDifference(['B5', 'B4']); + +// Create the training image. +var trainingImage = ndvi.addBands(percentTree2020); +print('training image for linear fit', trainingImage); + + +// Independent variable first, dependent variable second. +// You need to include the scale variable. +var linearFit = trainingImage.reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: Turin, + scale: 30, + bestEffort: true +}); + +// Inspect the results. +print('OLS estimates:', linearFit); +print('y-intercept:', linearFit.get('offset')); +print('Slope:', linearFit.get('scale')); + +// Create a prediction based on the linearFit model. +var predictedTree = ndvi.expression( + 'intercept + slope * ndvi', { + 'ndvi': ndvi.select('nd'), + 'intercept': ee.Number(linearFit.get('offset')), + 'slope': ee.Number(linearFit.get('scale')) + }); + +print('predictedTree', predictedTree); + +// Display the results. +Map.addLayer(predictedTree, { + max: 100 +}, 'Predicted Percent Tree Cover'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +////// +// Start Linear Regression +////// + +// Assemble the independent variables. +var predictionBands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', + 'B10', 'B11' +]; + +// Create the training image stack for linear regression. +var trainingImageLR = ee.Image(1) + .addBands(landsat8filtered.select(predictionBands)) + .addBands(percentTree2020); + +print('Linear Regression training image:', trainingImageLR); + +// Compute ordinary least squares regression coefficients using +// the linearRegression reducer. +var linearRegression = trainingImageLR.reduceRegion({ + reducer: ee.Reducer.linearRegression({ + numX: 10, + numY: 1 + }), + geometry: Turin, + scale: 30, + bestEffort: true +}); + +// Inspect the results. +print('Linear regression results:', linearRegression); + +// Extract the coefficients as a list. +var coefficients = ee.Array(linearRegression.get('coefficients')) + .project([0]) + .toList(); + +print('Coefficients', coefficients); + +// Create the predicted tree cover based on linear regression. +var predictedTreeLR = ee.Image(1) + .addBands(landsat8filtered.select(predictionBands)) + .multiply(ee.Image.constant(coefficients)) + .reduce(ee.Reducer.sum()) + .rename('predictedTreeLR') + .clip(landsat8filtered.geometry()); + +Map.addLayer(predictedTreeLR, { + min: 0, + max: 100 +}, 'LR prediction'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30b Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30b Checkpoint.py new file mode 100644 index 0000000..bdd35a6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30b Checkpoint.py @@ -0,0 +1,162 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.0 Interpreting an Image: Regression +# Checkpoint: F30b +# Authors: K. Dyson, A. Nicolau, D. Saah, N. Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define a Turin polygon. +Turin = ee.Geometry.Polygon( + [ + [ + [7.455553918110218, 45.258245019259036], + [7.455553918110218, 44.71237367431335], + [8.573412804828967, 44.71237367431335], + [8.573412804828967, 45.258245019259036] + ] + ], None, False) + +# Center on Turin +Map.centerObject(Turin, 9) + +mod44b = ee.ImageCollection('MODIS/006/MOD44B') + +##/ +# Start Linear Fit +##/ + +# Put together the dependent variable by filtering the +# ImageCollection to just the 2020 image near Turin and +# selecting the percent tree cover band. +percentTree2020 = mod44b \ + .filterDate('2020-01-01', '2021-01-01') \ + .first() \ + .clip(Turin) \ + .select('Percent_Tree_Cover') + +# You can print information to the console for inspection. +print('2020 Image', percentTree2020) + +Map.addLayer(percentTree2020, { + 'max': 100 +}, 'Percent Tree Cover') + +landsat8_raw = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT') + +# Put together the independent variable. +landsat8filtered = landsat8_raw \ + .filterBounds(Turin.centroid({ + 'maxError': 1 + })) \ + .filterDate('2020-04-01', '2020-4-30') \ + .first() + +print('Landsat8 filtered', landsat8filtered) + +# Display the L8 image. +visParams = { + 'bands': ['B4', 'B3', 'B2'], + 'max': 16000 +} +Map.addLayer(landsat8filtered, visParams, 'Landsat 8 Image') + +# Calculate NDVI which will be the independent variable. +ndvi = landsat8filtered.normalizedDifference(['B5', 'B4']) + +# Create the training image. +trainingImage = ndvi.addBands(percentTree2020) +print('training image for linear fit', trainingImage) + + +# Independent variable first, dependent variable second. +# You need to include the scale variable. +linearFit = trainingImage.reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': Turin, + 'scale': 30, + 'bestEffort': True +}) + +# Inspect the results. +print('OLS estimates:', linearFit) +print('y-intercept:', linearFit.get('offset')) +print('Slope:', linearFit.get('scale')) + +# Create a prediction based on the linearFit model. +predictedTree = ndvi.expression( + 'intercept + slope * ndvi', { + 'ndvi': ndvi.select('nd'), + 'intercept': ee.Number(linearFit.get('offset')), + 'slope': ee.Number(linearFit.get('scale')) + }) + +print('predictedTree', predictedTree) + +# Display the results. +Map.addLayer(predictedTree, { + 'max': 100 +}, 'Predicted Percent Tree Cover') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +### +# Start Linear Regression +### + +# Assemble the independent variables. +predictionBands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', + 'B10', 'B11' +] + +# Create the training image stack for linear regression. +trainingImageLR = ee.Image(1) \ + .addBands(landsat8filtered.select(predictionBands)) \ + .addBands(percentTree2020) + +print('Linear Regression training image:', trainingImageLR) + +# Compute ordinary least squares regression coefficients using +# the linearRegression reducer. +linearRegression = trainingImageLR.reduceRegion({ + 'reducer': ee.Reducer.linearRegression({ + 'numX': 10, + 'numY': 1 + }), + 'geometry': Turin, + 'scale': 30, + 'bestEffort': True +}) + +# Inspect the results. +print('Linear regression results:', linearRegression) + +# Extract the coefficients as a list. +coefficients = ee.Array(linearRegression.get('coefficients')) \ + .project([0]) \ + .toList() + +print('Coefficients', coefficients) + +# Create the predicted tree cover based on linear regression. +predictedTreeLR = ee.Image(1) \ + .addBands(landsat8filtered.select(predictionBands)) \ + .multiply(ee.Image.constant(coefficients)) \ + .reduce(ee.Reducer.sum()) \ + .rename('predictedTreeLR') \ + .clip(landsat8filtered.geometry()) + +Map.addLayer(predictedTreeLR, { + 'min': 0, + 'max': 100 +}, 'LR prediction') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30c Checkpoint.ipynb new file mode 100644 index 0000000..d9a8a0c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30c Checkpoint.ipynb @@ -0,0 +1,359 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.0 Interpreting an Image: Regression\n", + "# Checkpoint: F30c\n", + "# Authors: K. Dyson, A. Nicolau, D. Saah, N. Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define a Turin polygon.\n", + "Turin = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [7.455553918110218, 45.258245019259036],\n", + " [7.455553918110218, 44.71237367431335],\n", + " [8.573412804828967, 44.71237367431335],\n", + " [8.573412804828967, 45.258245019259036]\n", + " ]\n", + " ], None, False)\n", + "\n", + "# Center on Turin\n", + "Map.centerObject(Turin, 9)\n", + "\n", + "mod44b = ee.ImageCollection('MODIS/006/MOD44B')\n", + "\n", + "##/\n", + "# Start Linear Fit\n", + "##/\n", + "\n", + "# Put together the dependent variable by filtering the\n", + "# ImageCollection to just the 2020 image near Turin and\n", + "# selecting the percent tree cover band.\n", + "percentTree2020 = mod44b \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .first() \\\n", + " .clip(Turin) \\\n", + " .select('Percent_Tree_Cover')\n", + "\n", + "# You can print information to the console for inspection.\n", + "print('2020 Image', percentTree2020)\n", + "\n", + "Map.addLayer(percentTree2020, {\n", + " 'max': 100\n", + "}, 'Percent Tree Cover')\n", + "\n", + "landsat8_raw = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT')\n", + "\n", + "# Put together the independent variable.\n", + "landsat8filtered = landsat8_raw \\\n", + " .filterBounds(Turin.centroid({\n", + " 'maxError': 1\n", + " })) \\\n", + " .filterDate('2020-04-01', '2020-4-30') \\\n", + " .first()\n", + "\n", + "print('Landsat8 filtered', landsat8filtered)\n", + "\n", + "# Display the L8 image.\n", + "visParams = {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'max': 16000\n", + "}\n", + "Map.addLayer(landsat8filtered, visParams, 'Landsat 8 Image')\n", + "\n", + "# Calculate NDVI which will be the independent variable.\n", + "ndvi = landsat8filtered.normalizedDifference(['B5', 'B4'])\n", + "\n", + "# Create the training image.\n", + "trainingImage = ndvi.addBands(percentTree2020)\n", + "print('training image for linear fit', trainingImage)\n", + "\n", + "\n", + "# Independent variable first, dependent variable second.\n", + "# You need to include the scale variable.\n", + "linearFit = trainingImage.reduceRegion({\n", + " 'reducer': ee.Reducer.linearFit(),\n", + " 'geometry': Turin,\n", + " 'scale': 30,\n", + " 'bestEffort': True\n", + "})\n", + "\n", + "# Inspect the results.\n", + "print('OLS estimates:', linearFit)\n", + "print('y-intercept:', linearFit.get('offset'))\n", + "print('Slope:', linearFit.get('scale'))\n", + "\n", + "# Create a prediction based on the linearFit model.\n", + "predictedTree = ndvi.expression(\n", + " 'intercept + slope * ndvi', {\n", + " 'ndvi': ndvi.select('nd'),\n", + " 'intercept': ee.Number(linearFit.get('offset')),\n", + " 'slope': ee.Number(linearFit.get('scale'))\n", + " })\n", + "\n", + "print('predictedTree', predictedTree)\n", + "\n", + "# Display the results.\n", + "Map.addLayer(predictedTree, {\n", + " 'max': 100\n", + "}, 'Predicted Percent Tree Cover')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "###\n", + "# Start Linear Regression\n", + "###\n", + "\n", + "# Assemble the independent variables.\n", + "predictionBands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7',\n", + " 'B10', 'B11'\n", + "]\n", + "\n", + "# Create the training image stack for linear regression.\n", + "trainingImageLR = ee.Image(1) \\\n", + " .addBands(landsat8filtered.select(predictionBands)) \\\n", + " .addBands(percentTree2020)\n", + "\n", + "print('Linear Regression training image:', trainingImageLR)\n", + "\n", + "# Compute ordinary least squares regression coefficients using\n", + "# the linearRegression reducer.\n", + "linearRegression = trainingImageLR.reduceRegion({\n", + " 'reducer': ee.Reducer.linearRegression({\n", + " 'numX': 10,\n", + " 'numY': 1\n", + " }),\n", + " 'geometry': Turin,\n", + " 'scale': 30,\n", + " 'bestEffort': True\n", + "})\n", + "\n", + "# Inspect the results.\n", + "print('Linear regression results:', linearRegression)\n", + "\n", + "# Extract the coefficients as a list.\n", + "coefficients = ee.Array(linearRegression.get('coefficients')) \\\n", + " .project([0]) \\\n", + " .toList()\n", + "\n", + "print('Coefficients', coefficients)\n", + "\n", + "# Create the predicted tree cover based on linear regression.\n", + "predictedTreeLR = ee.Image(1) \\\n", + " .addBands(landsat8filtered.select(predictionBands)) \\\n", + " .multiply(ee.Image.constant(coefficients)) \\\n", + " .reduce(ee.Reducer.sum()) \\\n", + " .rename('predictedTreeLR') \\\n", + " .clip(landsat8filtered.geometry())\n", + "\n", + "Map.addLayer(predictedTreeLR, {\n", + " 'min': 0,\n", + " 'max': 100\n", + "}, 'LR prediction')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##/\n", + "# Start Non-linear Regression\n", + "##/\n", + "# Create the training data stack.\n", + "trainingImageCART = ee.Image(landsat8filtered.select(predictionBands)) \\\n", + " .addBands(percentTree2020)\n", + "\n", + "# Sample the training data stack.\n", + "trainingData = trainingImageCART.sample({\n", + " 'region': Turin,\n", + " 'scale': 30,\n", + " 'numPixels': 1500,\n", + " 'seed': 5\n", + "})\n", + "\n", + "# Examine the CART training data.\n", + "print('CART training data', trainingData)\n", + "\n", + "# Run the CART regression.\n", + "cartRegression = ee.Classifier.smileCart() \\\n", + " .setOutputMode('REGRESSION') \\\n", + " .train({\n", + " 'features': trainingData,\n", + " 'classProperty': 'Percent_Tree_Cover',\n", + " 'inputProperties': predictionBands\n", + " })\n", + "\n", + "# Create a prediction of tree cover based on the CART regression.\n", + "cartRegressionImage = landsat8filtered.select(predictionBands) \\\n", + " .classify(cartRegression, 'cartRegression')\n", + "\n", + "Map.addLayer(cartRegressionImage, {\n", + " 'min': 0,\n", + " 'max': 100\n", + "}, 'CART regression')\n", + "\n", + "##/\n", + "# Calculating RMSE to assess model performance\n", + "##/\n", + "\n", + "# Concatenate percent tree cover image and all predictions.\n", + "concat = ee.Image.cat(percentTree2020,\n", + " predictedTree,\n", + " predictedTreeLR,\n", + " cartRegressionImage) \\\n", + " .rename([\n", + " 'TCpercent',\n", + " 'LFprediction',\n", + " 'LRprediction',\n", + " 'CARTprediction'\n", + " ])\n", + "\n", + "# Sample pixels\n", + "sample = concat.sample({\n", + " 'region': Turin,\n", + " 'scale': 30,\n", + " 'numPixels': 500,\n", + " 'seed': 5\n", + "})\n", + "\n", + "print('First feature in sample', sample.first())\n", + "\n", + "# First step: This function computes the squared difference between\n", + "# the predicted percent tree cover and the known percent tree cover\n", + "def calculateDiff(feature):\n", + " TCpercent = ee.Number(feature.get('TCpercent'))\n", + " diffLFsq = ee.Number(feature.get('LFprediction')) \\\n", + " .subtract(TCpercent).pow(2)\n", + " diffLRsq = ee.Number(feature.get('LRprediction')) \\\n", + " .subtract(TCpercent).pow(2)\n", + " diffCARTsq = ee.Number(feature.get('CARTprediction')) \\\n", + " .subtract(TCpercent).pow(2)\n", + "\n", + " # Return the feature with the squared difference set to a 'diff' property.\n", + " return feature.set({\n", + " 'diffLFsq': diffLFsq,\n", + " 'diffLRsq': diffLRsq,\n", + " 'diffCARTsq': diffCARTsq\n", + " })\n", + "\n", + "\n", + "# Second step: Calculate RMSE for population of difference pairs.\n", + "rmse = ee.List([ee.Number(\n", + " # Map the difference function over the collection.\n", + " sample.map(calculateDiff) \\\n", + " .reduceColumns({\n", + " 'reducer': ee.Reducer.mean().repeat(3),\n", + " 'selectors': ['diffLFsq', 'diffLRsq',\n", + " 'diffCARTsq'\n", + " ]\n", + " }).get('mean')\n", + " # Flatten the list of lists.\n", + "\n", + "def func_jce(i):\n", + " # Take the square root of the mean square differences.\n", + " return ee.Number(i).sqrt()\n", + "\n", + ")]).flatten().map(func_jce)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Print the result.\n", + "print('RMSE', rmse)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30c Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30c Checkpoint.js new file mode 100644 index 0000000..0b7ce53 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30c Checkpoint.js @@ -0,0 +1,262 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.0 Interpreting an Image: Regression +// Checkpoint: F30c +// Authors: K. Dyson, A. Nicolau, D. Saah, N. Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define a Turin polygon. +var Turin = ee.Geometry.Polygon( + [ + [ + [7.455553918110218, 45.258245019259036], + [7.455553918110218, 44.71237367431335], + [8.573412804828967, 44.71237367431335], + [8.573412804828967, 45.258245019259036] + ] + ], null, false); + +// Center on Turin +Map.centerObject(Turin, 9); + +var mod44b = ee.ImageCollection('MODIS/006/MOD44B'); + +///// +// Start Linear Fit +///// + +// Put together the dependent variable by filtering the +// ImageCollection to just the 2020 image near Turin and +// selecting the percent tree cover band. +var percentTree2020 = mod44b + .filterDate('2020-01-01', '2021-01-01') + .first() + .clip(Turin) + .select('Percent_Tree_Cover'); + +// You can print information to the console for inspection. +print('2020 Image', percentTree2020); + +Map.addLayer(percentTree2020, { + max: 100 +}, 'Percent Tree Cover'); + +var landsat8_raw = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT'); + +// Put together the independent variable. +var landsat8filtered = landsat8_raw + .filterBounds(Turin.centroid({ + 'maxError': 1 + })) + .filterDate('2020-04-01', '2020-4-30') + .first(); + +print('Landsat8 filtered', landsat8filtered); + +// Display the L8 image. +var visParams = { + bands: ['B4', 'B3', 'B2'], + max: 16000 +}; +Map.addLayer(landsat8filtered, visParams, 'Landsat 8 Image'); + +// Calculate NDVI which will be the independent variable. +var ndvi = landsat8filtered.normalizedDifference(['B5', 'B4']); + +// Create the training image. +var trainingImage = ndvi.addBands(percentTree2020); +print('training image for linear fit', trainingImage); + + +// Independent variable first, dependent variable second. +// You need to include the scale variable. +var linearFit = trainingImage.reduceRegion({ + reducer: ee.Reducer.linearFit(), + geometry: Turin, + scale: 30, + bestEffort: true +}); + +// Inspect the results. +print('OLS estimates:', linearFit); +print('y-intercept:', linearFit.get('offset')); +print('Slope:', linearFit.get('scale')); + +// Create a prediction based on the linearFit model. +var predictedTree = ndvi.expression( + 'intercept + slope * ndvi', { + 'ndvi': ndvi.select('nd'), + 'intercept': ee.Number(linearFit.get('offset')), + 'slope': ee.Number(linearFit.get('scale')) + }); + +print('predictedTree', predictedTree); + +// Display the results. +Map.addLayer(predictedTree, { + max: 100 +}, 'Predicted Percent Tree Cover'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +////// +// Start Linear Regression +////// + +// Assemble the independent variables. +var predictionBands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', + 'B10', 'B11' +]; + +// Create the training image stack for linear regression. +var trainingImageLR = ee.Image(1) + .addBands(landsat8filtered.select(predictionBands)) + .addBands(percentTree2020); + +print('Linear Regression training image:', trainingImageLR); + +// Compute ordinary least squares regression coefficients using +// the linearRegression reducer. +var linearRegression = trainingImageLR.reduceRegion({ + reducer: ee.Reducer.linearRegression({ + numX: 10, + numY: 1 + }), + geometry: Turin, + scale: 30, + bestEffort: true +}); + +// Inspect the results. +print('Linear regression results:', linearRegression); + +// Extract the coefficients as a list. +var coefficients = ee.Array(linearRegression.get('coefficients')) + .project([0]) + .toList(); + +print('Coefficients', coefficients); + +// Create the predicted tree cover based on linear regression. +var predictedTreeLR = ee.Image(1) + .addBands(landsat8filtered.select(predictionBands)) + .multiply(ee.Image.constant(coefficients)) + .reduce(ee.Reducer.sum()) + .rename('predictedTreeLR') + .clip(landsat8filtered.geometry()); + +Map.addLayer(predictedTreeLR, { + min: 0, + max: 100 +}, 'LR prediction'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///// +// Start Non-linear Regression +///// +// Create the training data stack. +var trainingImageCART = ee.Image(landsat8filtered.select(predictionBands)) + .addBands(percentTree2020); + +// Sample the training data stack. +var trainingData = trainingImageCART.sample({ + region: Turin, + scale: 30, + numPixels: 1500, + seed: 5 +}); + +// Examine the CART training data. +print('CART training data', trainingData); + +// Run the CART regression. +var cartRegression = ee.Classifier.smileCart() + .setOutputMode('REGRESSION') + .train({ + features: trainingData, + classProperty: 'Percent_Tree_Cover', + inputProperties: predictionBands + }); + +// Create a prediction of tree cover based on the CART regression. +var cartRegressionImage = landsat8filtered.select(predictionBands) + .classify(cartRegression, 'cartRegression'); + +Map.addLayer(cartRegressionImage, { + min: 0, + max: 100 +}, 'CART regression'); + +///// +// Calculating RMSE to assess model performance +///// + +// Concatenate percent tree cover image and all predictions. +var concat = ee.Image.cat(percentTree2020, + predictedTree, + predictedTreeLR, + cartRegressionImage) + .rename([ + 'TCpercent', + 'LFprediction', + 'LRprediction', + 'CARTprediction' + ]); + +// Sample pixels +var sample = concat.sample({ + region: Turin, + scale: 30, + numPixels: 500, + seed: 5 +}); + +print('First feature in sample', sample.first()); + +// First step: This function computes the squared difference between +// the predicted percent tree cover and the known percent tree cover +var calculateDiff = function(feature) { + var TCpercent = ee.Number(feature.get('TCpercent')); + var diffLFsq = ee.Number(feature.get('LFprediction')) + .subtract(TCpercent).pow(2); + var diffLRsq = ee.Number(feature.get('LRprediction')) + .subtract(TCpercent).pow(2); + var diffCARTsq = ee.Number(feature.get('CARTprediction')) + .subtract(TCpercent).pow(2); + + // Return the feature with the squared difference set to a 'diff' property. + return feature.set({ + 'diffLFsq': diffLFsq, + 'diffLRsq': diffLRsq, + 'diffCARTsq': diffCARTsq + }); +}; + +// Second step: Calculate RMSE for population of difference pairs. +var rmse = ee.List([ee.Number( + // Map the difference function over the collection. + sample.map(calculateDiff) + // Reduce to get the mean squared difference. + .reduceColumns({ + reducer: ee.Reducer.mean().repeat(3), + selectors: ['diffLFsq', 'diffLRsq', + 'diffCARTsq' + ] + }).get('mean') + // Flatten the list of lists. +)]).flatten().map(function(i) { + // Take the square root of the mean square differences. + return ee.Number(i).sqrt(); +}); + +// Print the result. +print('RMSE', rmse); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30c Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30c Checkpoint.py new file mode 100644 index 0000000..c3e657c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.0 Interpreting an Image Regression/F30c Checkpoint.py @@ -0,0 +1,273 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.0 Interpreting an Image: Regression +# Checkpoint: F30c +# Authors: K. Dyson, A. Nicolau, D. Saah, N. Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define a Turin polygon. +Turin = ee.Geometry.Polygon( + [ + [ + [7.455553918110218, 45.258245019259036], + [7.455553918110218, 44.71237367431335], + [8.573412804828967, 44.71237367431335], + [8.573412804828967, 45.258245019259036] + ] + ], None, False) + +# Center on Turin +Map.centerObject(Turin, 9) + +mod44b = ee.ImageCollection('MODIS/006/MOD44B') + +##/ +# Start Linear Fit +##/ + +# Put together the dependent variable by filtering the +# ImageCollection to just the 2020 image near Turin and +# selecting the percent tree cover band. +percentTree2020 = mod44b \ + .filterDate('2020-01-01', '2021-01-01') \ + .first() \ + .clip(Turin) \ + .select('Percent_Tree_Cover') + +# You can print information to the console for inspection. +print('2020 Image', percentTree2020) + +Map.addLayer(percentTree2020, { + 'max': 100 +}, 'Percent Tree Cover') + +landsat8_raw = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT') + +# Put together the independent variable. +landsat8filtered = landsat8_raw \ + .filterBounds(Turin.centroid({ + 'maxError': 1 + })) \ + .filterDate('2020-04-01', '2020-4-30') \ + .first() + +print('Landsat8 filtered', landsat8filtered) + +# Display the L8 image. +visParams = { + 'bands': ['B4', 'B3', 'B2'], + 'max': 16000 +} +Map.addLayer(landsat8filtered, visParams, 'Landsat 8 Image') + +# Calculate NDVI which will be the independent variable. +ndvi = landsat8filtered.normalizedDifference(['B5', 'B4']) + +# Create the training image. +trainingImage = ndvi.addBands(percentTree2020) +print('training image for linear fit', trainingImage) + + +# Independent variable first, dependent variable second. +# You need to include the scale variable. +linearFit = trainingImage.reduceRegion({ + 'reducer': ee.Reducer.linearFit(), + 'geometry': Turin, + 'scale': 30, + 'bestEffort': True +}) + +# Inspect the results. +print('OLS estimates:', linearFit) +print('y-intercept:', linearFit.get('offset')) +print('Slope:', linearFit.get('scale')) + +# Create a prediction based on the linearFit model. +predictedTree = ndvi.expression( + 'intercept + slope * ndvi', { + 'ndvi': ndvi.select('nd'), + 'intercept': ee.Number(linearFit.get('offset')), + 'slope': ee.Number(linearFit.get('scale')) + }) + +print('predictedTree', predictedTree) + +# Display the results. +Map.addLayer(predictedTree, { + 'max': 100 +}, 'Predicted Percent Tree Cover') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +### +# Start Linear Regression +### + +# Assemble the independent variables. +predictionBands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', + 'B10', 'B11' +] + +# Create the training image stack for linear regression. +trainingImageLR = ee.Image(1) \ + .addBands(landsat8filtered.select(predictionBands)) \ + .addBands(percentTree2020) + +print('Linear Regression training image:', trainingImageLR) + +# Compute ordinary least squares regression coefficients using +# the linearRegression reducer. +linearRegression = trainingImageLR.reduceRegion({ + 'reducer': ee.Reducer.linearRegression({ + 'numX': 10, + 'numY': 1 + }), + 'geometry': Turin, + 'scale': 30, + 'bestEffort': True +}) + +# Inspect the results. +print('Linear regression results:', linearRegression) + +# Extract the coefficients as a list. +coefficients = ee.Array(linearRegression.get('coefficients')) \ + .project([0]) \ + .toList() + +print('Coefficients', coefficients) + +# Create the predicted tree cover based on linear regression. +predictedTreeLR = ee.Image(1) \ + .addBands(landsat8filtered.select(predictionBands)) \ + .multiply(ee.Image.constant(coefficients)) \ + .reduce(ee.Reducer.sum()) \ + .rename('predictedTreeLR') \ + .clip(landsat8filtered.geometry()) + +Map.addLayer(predictedTreeLR, { + 'min': 0, + 'max': 100 +}, 'LR prediction') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##/ +# Start Non-linear Regression +##/ +# Create the training data stack. +trainingImageCART = ee.Image(landsat8filtered.select(predictionBands)) \ + .addBands(percentTree2020) + +# Sample the training data stack. +trainingData = trainingImageCART.sample({ + 'region': Turin, + 'scale': 30, + 'numPixels': 1500, + 'seed': 5 +}) + +# Examine the CART training data. +print('CART training data', trainingData) + +# Run the CART regression. +cartRegression = ee.Classifier.smileCart() \ + .setOutputMode('REGRESSION') \ + .train({ + 'features': trainingData, + 'classProperty': 'Percent_Tree_Cover', + 'inputProperties': predictionBands + }) + +# Create a prediction of tree cover based on the CART regression. +cartRegressionImage = landsat8filtered.select(predictionBands) \ + .classify(cartRegression, 'cartRegression') + +Map.addLayer(cartRegressionImage, { + 'min': 0, + 'max': 100 +}, 'CART regression') + +##/ +# Calculating RMSE to assess model performance +##/ + +# Concatenate percent tree cover image and all predictions. +concat = ee.Image.cat(percentTree2020, + predictedTree, + predictedTreeLR, + cartRegressionImage) \ + .rename([ + 'TCpercent', + 'LFprediction', + 'LRprediction', + 'CARTprediction' + ]) + +# Sample pixels +sample = concat.sample({ + 'region': Turin, + 'scale': 30, + 'numPixels': 500, + 'seed': 5 +}) + +print('First feature in sample', sample.first()) + +# First step: This function computes the squared difference between +# the predicted percent tree cover and the known percent tree cover +def calculateDiff(feature): + TCpercent = ee.Number(feature.get('TCpercent')) + diffLFsq = ee.Number(feature.get('LFprediction')) \ + .subtract(TCpercent).pow(2) + diffLRsq = ee.Number(feature.get('LRprediction')) \ + .subtract(TCpercent).pow(2) + diffCARTsq = ee.Number(feature.get('CARTprediction')) \ + .subtract(TCpercent).pow(2) + + # Return the feature with the squared difference set to a 'diff' property. + return feature.set({ + 'diffLFsq': diffLFsq, + 'diffLRsq': diffLRsq, + 'diffCARTsq': diffCARTsq + }) + + +# Second step: Calculate RMSE for population of difference pairs. +rmse = ee.List([ee.Number( + # Map the difference function over the collection. + sample.map(calculateDiff) \ + .reduceColumns({ + 'reducer': ee.Reducer.mean().repeat(3), + 'selectors': ['diffLFsq', 'diffLRsq', + 'diffCARTsq' + ] + }).get('mean') + # Flatten the list of lists. + +def func_jce(i): + # Take the square root of the mean square differences. + return ee.Number(i).sqrt() + +)]).flatten().map(func_jce) + + + + + +# Print the result. +print('RMSE', rmse) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31a Checkpoint.ipynb new file mode 100644 index 0000000..3448dc2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31a Checkpoint.ipynb @@ -0,0 +1,148 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.1 Advanced Pixel-Based Image Transformations\n", + "# Checkpoint: F31a\n", + "# Authors: Karen, Andrea, Nick, and David\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import and filter imagery by location and date.\n", + "sfoPoint = ee.Geometry.Point(-122.3774, 37.6194)\n", + "\n", + "sfoImage = ee.ImageCollection('COPERNICUS/S2') \\\n", + " .filterBounds(sfoPoint) \\\n", + " .filterDate('2020-02-01', '2020-04-01') \\\n", + " .first()\n", + "Map.centerObject(sfoImage, 11)\n", + "\n", + "# Calculate EVI using Sentinel 2\n", + "\n", + "# Extract the bands and divide by 10,000 to account for scaling done.\n", + "nirScaled = sfoImage.select('B8').divide(10000)\n", + "redScaled = sfoImage.select('B4').divide(10000)\n", + "blueScaled = sfoImage.select('B2').divide(10000)\n", + "\n", + "# Calculate the numerator, note that order goes from left to right.\n", + "numeratorEVI = (nirScaled.subtract(redScaled)).multiply(2.5)\n", + "\n", + "# Calculate the denominator.\n", + "denomClause1 = redScaled.multiply(6)\n", + "denomClause2 = blueScaled.multiply(7.5)\n", + "denominatorEVI = nirScaled.add(denomClause1) \\\n", + " .subtract(denomClause2).add(1)\n", + "\n", + "# Calculate EVI and name it.\n", + "EVI = numeratorEVI.divide(denominatorEVI).rename('EVI')\n", + "\n", + "# And now map EVI using our vegetation palette.\n", + "vegPalette = ['red', 'white', 'green']\n", + "visParams = {'min': -1, 'max': 1, 'palette': vegPalette}\n", + "\tMap.addLayer(EVI, visParams, 'EVI')\n", + "\n", + "# Calculate EVI.\n", + "eviExpression = sfoImage.expression({\n", + " 'expression': '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))',\n", + " 'map': { # Map between variables in the expression and images.\n", + " 'NIR': sfoImage.select('B8').divide(10000),\n", + " 'RED': sfoImage.select('B4').divide(10000),\n", + " 'BLUE': sfoImage.select('B2').divide(10000)\n", + " }\n", + "})\n", + "\n", + "# And now map EVI using our vegetation palette.\n", + "Map.addLayer(eviExpression, visParams, 'EVI Expression')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31a Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31a Checkpoint.js new file mode 100644 index 0000000..b5afc4f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31a Checkpoint.js @@ -0,0 +1,55 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.1 Advanced Pixel-Based Image Transformations +// Checkpoint: F31a +// Authors: Karen, Andrea, Nick, and David +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import and filter imagery by location and date. +var sfoPoint = ee.Geometry.Point(-122.3774, 37.6194); + +var sfoImage = ee.ImageCollection('COPERNICUS/S2') + .filterBounds(sfoPoint) + .filterDate('2020-02-01', '2020-04-01') + .first(); +Map.centerObject(sfoImage, 11); + +// Calculate EVI using Sentinel 2 + +// Extract the bands and divide by 10,000 to account for scaling done. +var nirScaled = sfoImage.select('B8').divide(10000); +var redScaled = sfoImage.select('B4').divide(10000); +var blueScaled = sfoImage.select('B2').divide(10000); + +// Calculate the numerator, note that order goes from left to right. +var numeratorEVI = (nirScaled.subtract(redScaled)).multiply(2.5); + +// Calculate the denominator. +var denomClause1 = redScaled.multiply(6); +var denomClause2 = blueScaled.multiply(7.5); +var denominatorEVI = nirScaled.add(denomClause1) + .subtract(denomClause2).add(1); + +// Calculate EVI and name it. +var EVI = numeratorEVI.divide(denominatorEVI).rename('EVI'); + +// And now map EVI using our vegetation palette. +var vegPalette = ['red', 'white', 'green']; +var visParams = {min: -1, max: 1, palette: vegPalette}; + Map.addLayer(EVI, visParams, 'EVI'); + +// Calculate EVI. +var eviExpression = sfoImage.expression({ + expression: '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', + map: { // Map between variables in the expression and images. + 'NIR': sfoImage.select('B8').divide(10000), + 'RED': sfoImage.select('B4').divide(10000), + 'BLUE': sfoImage.select('B2').divide(10000) + } +}); + +// And now map EVI using our vegetation palette. +Map.addLayer(eviExpression, visParams, 'EVI Expression'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31a Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31a Checkpoint.py new file mode 100644 index 0000000..2bf2b4c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31a Checkpoint.py @@ -0,0 +1,61 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.1 Advanced Pixel-Based Image Transformations +# Checkpoint: F31a +# Authors: Karen, Andrea, Nick, and David +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import and filter imagery by location and date. +sfoPoint = ee.Geometry.Point(-122.3774, 37.6194) + +sfoImage = ee.ImageCollection('COPERNICUS/S2') \ + .filterBounds(sfoPoint) \ + .filterDate('2020-02-01', '2020-04-01') \ + .first() +Map.centerObject(sfoImage, 11) + +# Calculate EVI using Sentinel 2 + +# Extract the bands and divide by 10,000 to account for scaling done. +nirScaled = sfoImage.select('B8').divide(10000) +redScaled = sfoImage.select('B4').divide(10000) +blueScaled = sfoImage.select('B2').divide(10000) + +# Calculate the numerator, note that order goes from left to right. +numeratorEVI = (nirScaled.subtract(redScaled)).multiply(2.5) + +# Calculate the denominator. +denomClause1 = redScaled.multiply(6) +denomClause2 = blueScaled.multiply(7.5) +denominatorEVI = nirScaled.add(denomClause1) \ + .subtract(denomClause2).add(1) + +# Calculate EVI and name it. +EVI = numeratorEVI.divide(denominatorEVI).rename('EVI') + +# And now map EVI using our vegetation palette. +vegPalette = ['red', 'white', 'green'] +visParams = {'min': -1, 'max': 1, 'palette': vegPalette} + Map.addLayer(EVI, visParams, 'EVI') + +# Calculate EVI. +eviExpression = sfoImage.expression({ + 'expression': '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', + 'map': { # Map between variables in the expression and images. + 'NIR': sfoImage.select('B8').divide(10000), + 'RED': sfoImage.select('B4').divide(10000), + 'BLUE': sfoImage.select('B2').divide(10000) + } +}) + +# And now map EVI using our vegetation palette. +Map.addLayer(eviExpression, visParams, 'EVI Expression') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31b Checkpoint.ipynb new file mode 100644 index 0000000..25ecc61 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31b Checkpoint.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.1 Advanced Pixel-Based Image Transformations\n", + "# Checkpoint: F31b\n", + "# Authors: Karen, Andrea, Nick, and David\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Examine the True-color Landsat 8 images for the 2013 Rim Fire.\n", + "burnImage = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterBounds(ee.Geometry.Point(-120.083, 37.850)) \\\n", + " .filterDate('2013-09-15', '2013-09-27') \\\n", + " .sort('CLOUD_COVER') \\\n", + " .first()\n", + "\n", + "Map.centerObject(ee.Geometry.Point(-120.083, 37.850), 11)\n", + "\n", + "rgbParams = {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 0,\n", + " 'max': 0.3\n", + "}\n", + "Map.addLayer(burnImage, rgbParams, 'True-Color Burn Image')\n", + "\n", + "# Calculate BAI.\n", + "bai = burnImage.expression(\n", + " '1.0 / ((0.1 - RED)**2 + (0.06 - NIR)**2)', {\n", + " 'NIR': burnImage.select('B5'),\n", + " 'RED': burnImage.select('B4'),\n", + " })\n", + "\n", + "# Display the BAI image.\n", + "burnPalette = ['green', 'blue', 'yellow', 'red']\n", + "Map.addLayer(bai, {\n", + " 'min': 0,\n", + " 'max': 400,\n", + " 'palette': burnPalette\n", + "}, 'BAI')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31b Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31b Checkpoint.js new file mode 100644 index 0000000..edb17b0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31b Checkpoint.js @@ -0,0 +1,40 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.1 Advanced Pixel-Based Image Transformations +// Checkpoint: F31b +// Authors: Karen, Andrea, Nick, and David +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Examine the true-color Landsat 8 images for the 2013 Rim Fire. +var burnImage = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterBounds(ee.Geometry.Point(-120.083, 37.850)) + .filterDate('2013-09-15', '2013-09-27') + .sort('CLOUD_COVER') + .first(); + +Map.centerObject(ee.Geometry.Point(-120.083, 37.850), 11); + +var rgbParams = { + bands: ['B4', 'B3', 'B2'], + min: 0, + max: 0.3 +}; +Map.addLayer(burnImage, rgbParams, 'True-Color Burn Image'); + +// Calculate BAI. +var bai = burnImage.expression( + '1.0 / ((0.1 - RED)**2 + (0.06 - NIR)**2)', { + 'NIR': burnImage.select('B5'), + 'RED': burnImage.select('B4'), + }); + +// Display the BAI image. +var burnPalette = ['green', 'blue', 'yellow', 'red']; +Map.addLayer(bai, { + min: 0, + max: 400, + palette: burnPalette +}, 'BAI'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31b Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31b Checkpoint.py new file mode 100644 index 0000000..215d7d5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31b Checkpoint.py @@ -0,0 +1,46 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.1 Advanced Pixel-Based Image Transformations +# Checkpoint: F31b +# Authors: Karen, Andrea, Nick, and David +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Examine the True-color Landsat 8 images for the 2013 Rim Fire. +burnImage = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterBounds(ee.Geometry.Point(-120.083, 37.850)) \ + .filterDate('2013-09-15', '2013-09-27') \ + .sort('CLOUD_COVER') \ + .first() + +Map.centerObject(ee.Geometry.Point(-120.083, 37.850), 11) + +rgbParams = { + 'bands': ['B4', 'B3', 'B2'], + 'min': 0, + 'max': 0.3 +} +Map.addLayer(burnImage, rgbParams, 'True-Color Burn Image') + +# Calculate BAI. +bai = burnImage.expression( + '1.0 / ((0.1 - RED)**2 + (0.06 - NIR)**2)', { + 'NIR': burnImage.select('B5'), + 'RED': burnImage.select('B4'), + }) + +# Display the BAI image. +burnPalette = ['green', 'blue', 'yellow', 'red'] +Map.addLayer(bai, { + 'min': 0, + 'max': 400, + 'palette': burnPalette +}, 'BAI') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31c Checkpoint.ipynb new file mode 100644 index 0000000..e6f736a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31c Checkpoint.ipynb @@ -0,0 +1,351 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.1 Advanced Pixel-Based Image Transformations\n", + "# Checkpoint: F31c\n", + "# Authors: Karen, Andrea, Nick, and David\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##/\n", + "# Manipulating images with matrices\n", + "##/\n", + "\n", + "# Begin Tasseled Cap example.\n", + "landsat5RT = ee.Array([\n", + " [0.3037, 0.2793, 0.4743, 0.5585, 0.5082, 0.1863],\n", + " [-0.2848, -0.2435, -0.5436, 0.7243, 0.0840, -0.1800],\n", + " [0.1509, 0.1973, 0.3279, 0.3406, -0.7112, -0.4572],\n", + " [-0.8242, 0.0849, 0.4392, -0.0580, 0.2012, -0.2768],\n", + " [-0.3280, 0.0549, 0.1075, 0.1855, -0.4357, 0.8085],\n", + " [0.1084, -0.9022, 0.4120, 0.0573, -0.0251, 0.0238]\n", + "])\n", + "\n", + "print('RT for Landsat 5', landsat5RT)\n", + "\n", + "# Define a point of interest in Odessa, Washington, USA.\n", + "point = ee.Geometry.Point([-118.7436019417829,\n", + "47.18135755009023])\n", + "Map.centerObject(point, 10)\n", + "\n", + "# Filter to get a cloud free image to use for the TC.\n", + "imageL5 = ee.ImageCollection('LANDSAT/LT05/C02/T1_TOA') \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2008-06-01', '2008-09-01') \\\n", + " .sort('CLOUD_COVER') \\\n", + " .first()\n", + "\n", + "#Display the True-color image.\n", + "TrueColor = {\n", + " 'bands': ['B3', 'B2', 'B1'],\n", + " 'min': 0,\n", + " 'max': 0.3\n", + "}\n", + "Map.addLayer(imageL5, TrueColor, 'L5 True color')\n", + "\n", + "bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B7']\n", + "\n", + "# Make an Array Image, with a one dimensional array per pixel.\n", + "# This is essentially a list of values of length 6,\n", + "# one from each band in variable 'bands.'\n", + "arrayImage1D = imageL5.select(bands).toArray()\n", + "\n", + "# Make an Array Image with a two dimensional array per pixel,\n", + "# of dimensions 6x1. This is essentially a one column matrix with\n", + "# six rows, with one value from each band in 'bands.'\n", + "# This step is needed for matrix multiplication (p0).\n", + "arrayImage2D = arrayImage1D.toArray(1)\n", + "\n", + "#Multiply RT by p0.\n", + "tasselCapImage = ee.Image(landsat5RT)\n", + " # Multiply the tasseled cap coefficients by the array \\\n", + " .matrixMultiply(arrayImage2D) \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten(\n", + " [\n", + " ['brightness', 'greenness', 'wetness', 'fourth', 'fifth',\n", + " 'sixth'\n", + " ]\n", + " ])\n", + "\n", + "vizParams = {\n", + " 'bands': ['brightness', 'greenness', 'wetness'],\n", + " 'min': -0.1,\n", + " 'max': [0.5, 0.1, 0.1]\n", + "}\n", + "Map.addLayer(tasselCapImage, vizParams, 'TC components')\n", + "\n", + "# Begin PCA example.\n", + "\n", + "# Select and map a True-color L8 image.\n", + "imageL8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2018-06-01', '2018-09-01') \\\n", + " .sort('CLOUD_COVER') \\\n", + " .first()\n", + "\n", + "TrueColorL8 = {\n", + " 'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 0,\n", + " 'max': 0.3\n", + "}\n", + "Map.addLayer(imageL8, TrueColorL8, 'L8 True color')\n", + "\n", + "# Select which bands to use for the PCA.\n", + "PCAbands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B10', 'B11']\n", + "\n", + "# Convert the Landsat 8 image to a 2D array for the later matrix\n", + "# computations.\n", + "arrayImage = imageL8.select(PCAbands).toArray()\n", + "\n", + "# Calculate the covariance using the reduceRegion method.\n", + "covar = arrayImage.reduceRegion({\n", + " 'reducer': ee.Reducer.covariance(),\n", + " 'maxPixels': 1e9\n", + "})\n", + "\n", + "# Extract the covariance matrix and store it as an array.\n", + "covarArray = ee.Array(covar.get('array'))\n", + "\n", + "#Compute and extract the eigenvectors\n", + "eigens = covarArray.eigen()\n", + "eigenVectors = eigens.slice(1, 1)\n", + "\n", + "# Perform matrix multiplication\n", + "principalComponents = ee.Image(eigenVectors) \\\n", + " .matrixMultiply(arrayImage.toArray(1))\n", + "\n", + "pcImage = principalComponents \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([\n", + " ['pc1', 'pc2', 'pc3', 'pc4', 'pc5', 'pc6', 'pc7', 'pc8']\n", + " ])\n", + "\n", + "# Stretch this to the appropriate scale.\n", + "Map.addLayer(pcImage.select('pc1'), {}, 'pc1')\n", + "\n", + "#The min and max values will need to change if you map different bands or locations.\n", + "visParamsPCA = {\n", + " 'bands': ['pc1', 'pc3', 'pc4'],\n", + " 'min': [-455.09, -2.206, -4.53],\n", + " 'max': [-417.59, -1.3, -4.18]\n", + "}\n", + "\n", + "Map.addLayer(pcImage, visParamsPCA, 'PC_multi')\n", + "\n", + "# Begin spectral unmixing example.\n", + "\n", + "# Specify which bands to use for the unmixing.\n", + "unmixImage = imageL8.select(['B2', 'B3', 'B4', 'B5', 'B6', 'B7'])\n", + "\n", + "# Use a False color composite to help define polygons of 'pure' land cover.\n", + "Map.addLayer(imageL8, {\n", + " 'bands': ['B5', 'B4', 'B3'],\n", + " 'min': 0.0,\n", + " 'max': 0.4\n", + "}, 'False color')\n", + "\n", + "# Define polygons of bare, water, and vegetation.\n", + "bare = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-119.29158963591193, 47.204453926034134],\n", + " [-119.29192222982978, 47.20372502078616],\n", + " [-119.29054893881415, 47.20345532330602],\n", + " [-119.29017342955207, 47.20414049800489]\n", + " ]\n", + " ]),\n", + "water = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-119.42904610218152, 47.22253398528318],\n", + " [-119.42973274768933, 47.22020224831784],\n", + " [-119.43299431385144, 47.21390604625894],\n", + " [-119.42904610218152, 47.21326472446865],\n", + " [-119.4271149116908, 47.21868656429651],\n", + " [-119.42608494342907, 47.2217470355224]\n", + " ]\n", + " ]),\n", + "veg = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-119.13546041722502, 47.04929418944858],\n", + " [-119.13752035374846, 47.04929418944858],\n", + " [-119.13966612096037, 47.04765665820436],\n", + " [-119.13777784581389, 47.04408900535686]\n", + " ]\n", + " ])\n", + "\n", + "#Print a chart.\n", + "lcfeatures = ee.FeatureCollection([\n", + " ee.Feature(bare, {\n", + " 'label': 'bare'\n", + " }),\n", + " ee.Feature(water, {\n", + " 'label': 'water'\n", + " }),\n", + " ee.Feature(veg, {\n", + " 'label': 'vegetation'\n", + " })\n", + "])\n", + "\n", + "print(\n", + " ui.Chart.image.regions({\n", + " 'image': unmixImage,\n", + " 'regions': lcfeatures,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 30,\n", + " 'seriesProperty': 'label',\n", + " 'xLabels': [0.48, 0.56, 0.65, 0.86, 1.61, 2.2]\n", + " }) \\\n", + " .setChartType('LineChart') \\\n", + " .setOptions({\n", + " 'title': 'Image band values in 3 regions',\n", + " 'hAxis': {\n", + " 'title': 'Wavelength'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Mean Reflectance'\n", + " }\n", + " }))\n", + "\n", + "# Get the means for each region.\n", + "bareMean = unmixImage \\\n", + " .reduceRegion(ee.Reducer.mean(), bare, 30).values()\n", + "waterMean = unmixImage \\\n", + " .reduceRegion(ee.Reducer.mean(), water, 30).values()\n", + "vegMean = unmixImage \\\n", + " .reduceRegion(ee.Reducer.mean(), veg, 30).values()\n", + "\n", + "# Stack these mean vectors to create an Array.\n", + "endmembers = ee.Array.cat([bareMean, vegMean, waterMean], 1)\n", + "print(endmembers)\n", + "\n", + "# Convert the 6-band input image to an image array.\n", + "arrayImage = unmixImage.toArray().toArray(1)\n", + "\n", + "# Solve for f.\n", + "unmixed = ee.Image(endmembers).matrixSolve(arrayImage)\n", + "\n", + "# Convert the result back to a multi-band image.\n", + "unmixedImage = unmixed \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([\n", + " ['bare', 'veg', 'water']\n", + " ])\n", + "\n", + "Map.addLayer(unmixedImage, {}, 'Unmixed')\n", + "\n", + "# Begin HSV transformation example\n", + "\n", + "# Convert Landsat 8 RGB bands to HSV color space\n", + "hsv = imageL8.select(['B4', 'B3', 'B2']).rgbToHsv()\n", + "\n", + "Map.addLayer(hsv, {\n", + " 'max': 0.4\n", + "}, 'HSV Transform')\n", + "\n", + "# Convert back to RGB, swapping the image panchromatic band for the value.\n", + "rgb = ee.Image.cat([\n", + " hsv.select('hue'),\n", + " hsv.select('saturation'),\n", + " imageL8.select(['B8'])\n", + "]).hsvToRgb()\n", + "\n", + "Map.addLayer(rgb, {\n", + " 'max': 0.4\n", + "}, 'Pan-sharpened')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31c Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31c Checkpoint.js new file mode 100644 index 0000000..ef4a6b1 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31c Checkpoint.js @@ -0,0 +1,263 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.1 Advanced Pixel-Based Image Transformations +// Checkpoint: F31c +// Authors: Karen, Andrea, Nick, and David +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///// +// Manipulating images with matrices +///// + +// Begin Tasseled Cap example. +var landsat5RT = 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] +]); + +print('RT for Landsat 5', landsat5RT); + +// Define a point of interest in Odessa, Washington, USA. +var point = ee.Geometry.Point([-118.7436019417829, +47.18135755009023]); +Map.centerObject(point, 10); + +// Filter to get a cloud free image to use for the TC. +var imageL5 = ee.ImageCollection('LANDSAT/LT05/C02/T1_TOA') + .filterBounds(point) + .filterDate('2008-06-01', '2008-09-01') + .sort('CLOUD_COVER') + .first(); + +//Display the true-color image. +var trueColor = { + bands: ['B3', 'B2', 'B1'], + min: 0, + max: 0.3 +}; +Map.addLayer(imageL5, trueColor, 'L5 true color'); + +var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B7']; + +// Make an Array Image, with a one dimensional array per pixel. +// This is essentially a list of values of length 6, +// one from each band in variable 'bands.' +var arrayImage1D = imageL5.select(bands).toArray(); + +// Make an Array Image with a two dimensional array per pixel, +// of dimensions 6x1. This is essentially a one column matrix with +// six rows, with one value from each band in 'bands.' +// This step is needed for matrix multiplication (p0). +var arrayImage2D = arrayImage1D.toArray(1); + +//Multiply RT by p0. +var tasselCapImage = ee.Image(landsat5RT) + // Multiply the tasseled cap coefficients by the array + // made from the 6 bands for each pixel. + .matrixMultiply(arrayImage2D) + // Get rid of the extra dimensions. + .arrayProject([0]) + // Get a multi-band image with TC-named bands. + .arrayFlatten( + [ + ['brightness', 'greenness', 'wetness', 'fourth', 'fifth', + 'sixth' + ] + ]); + +var vizParams = { + bands: ['brightness', 'greenness', 'wetness'], + min: -0.1, + max: [0.5, 0.1, 0.1] +}; +Map.addLayer(tasselCapImage, vizParams, 'TC components'); + +// Begin PCA example. + +// Select and map a true-color L8 image. +var imageL8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterBounds(point) + .filterDate('2018-06-01', '2018-09-01') + .sort('CLOUD_COVER') + .first(); + +var trueColorL8 = { + bands: ['B4', 'B3', 'B2'], + min: 0, + max: 0.3 +}; +Map.addLayer(imageL8, trueColorL8, 'L8 true color'); + +// Select which bands to use for the PCA. +var PCAbands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B10', 'B11']; + +// Convert the Landsat 8 image to a 2D array for the later matrix +// computations. +var arrayImage = imageL8.select(PCAbands).toArray(); + +// Calculate the covariance using the reduceRegion method. +var covar = arrayImage.reduceRegion({ + reducer: ee.Reducer.covariance(), + maxPixels: 1e9 +}); + +// Extract the covariance matrix and store it as an array. +var covarArray = ee.Array(covar.get('array')); + +//Compute and extract the eigenvectors +var eigens = covarArray.eigen(); +var eigenVectors = eigens.slice(1, 1); + +// Perform matrix multiplication +var principalComponents = ee.Image(eigenVectors) + .matrixMultiply(arrayImage.toArray(1)); + +var pcImage = principalComponents + // Throw out an unneeded dimension, [[]] -> []. + .arrayProject([0]) + // Make the one band array image a multi-band image, [] -> image. + .arrayFlatten([ + ['pc1', 'pc2', 'pc3', 'pc4', 'pc5', 'pc6', 'pc7', 'pc8'] + ]); + +// Stretch this to the appropriate scale. +Map.addLayer(pcImage.select('pc1'), {}, 'pc1'); + +//The min and max values will need to change if you map different bands or locations. +var visParamsPCA = { + bands: ['pc1', 'pc3', 'pc4'], + min: [-455.09, -2.206, -4.53], + max: [-417.59, -1.3, -4.18] +}; + +Map.addLayer(pcImage, visParamsPCA, 'PC_multi'); + +// Begin spectral unmixing example. + +// Specify which bands to use for the unmixing. +var unmixImage = imageL8.select(['B2', 'B3', 'B4', 'B5', 'B6', 'B7']); + +// Use a false color composite to help define polygons of 'pure' land cover. +Map.addLayer(imageL8, { + bands: ['B5', 'B4', 'B3'], + min: 0.0, + max: 0.4 +}, 'false color'); + +// Define polygons of bare, water, and vegetation. +var bare = /* color: #d63000 */ ee.Geometry.Polygon( + [ + [ + [-119.29158963591193, 47.204453926034134], + [-119.29192222982978, 47.20372502078616], + [-119.29054893881415, 47.20345532330602], + [-119.29017342955207, 47.20414049800489] + ] + ]), + water = /* color: #98ff00 */ ee.Geometry.Polygon( + [ + [ + [-119.42904610218152, 47.22253398528318], + [-119.42973274768933, 47.22020224831784], + [-119.43299431385144, 47.21390604625894], + [-119.42904610218152, 47.21326472446865], + [-119.4271149116908, 47.21868656429651], + [-119.42608494342907, 47.2217470355224] + ] + ]), + veg = /* color: #0b4a8b */ ee.Geometry.Polygon( + [ + [ + [-119.13546041722502, 47.04929418944858], + [-119.13752035374846, 47.04929418944858], + [-119.13966612096037, 47.04765665820436], + [-119.13777784581389, 47.04408900535686] + ] + ]); + +//Print a chart. +var lcfeatures = ee.FeatureCollection([ + ee.Feature(bare, { + label: 'bare' + }), + ee.Feature(water, { + label: 'water' + }), + ee.Feature(veg, { + label: 'vegetation' + }) +]); + +print( + ui.Chart.image.regions({ + image: unmixImage, + regions: lcfeatures, + reducer: ee.Reducer.mean(), + scale: 30, + seriesProperty: 'label', + xLabels: [0.48, 0.56, 0.65, 0.86, 1.61, 2.2] + }) + .setChartType('LineChart') + .setOptions({ + title: 'Image band values in 3 regions', + hAxis: { + title: 'Wavelength' + }, + vAxis: { + title: 'Mean Reflectance' + } + })); + +// Get the means for each region. +var bareMean = unmixImage + .reduceRegion(ee.Reducer.mean(), bare, 30).values(); +var waterMean = unmixImage + .reduceRegion(ee.Reducer.mean(), water, 30).values(); +var vegMean = unmixImage + .reduceRegion(ee.Reducer.mean(), veg, 30).values(); + +// Stack these mean vectors to create an Array. +var endmembers = ee.Array.cat([bareMean, vegMean, waterMean], 1); +print(endmembers); + +// Convert the 6-band input image to an image array. +var arrayImage = unmixImage.toArray().toArray(1); + +// Solve for f. +var unmixed = ee.Image(endmembers).matrixSolve(arrayImage); + +// Convert the result back to a multi-band image. +var unmixedImage = unmixed + .arrayProject([0]) + .arrayFlatten([ + ['bare', 'veg', 'water'] + ]); + +Map.addLayer(unmixedImage, {}, 'Unmixed'); + +// Begin HSV transformation example + +// Convert Landsat 8 RGB bands to HSV color space +var hsv = imageL8.select(['B4', 'B3', 'B2']).rgbToHsv(); + +Map.addLayer(hsv, { + max: 0.4 +}, 'HSV Transform'); + +// Convert back to RGB, swapping the image panchromatic band for the value. +var rgb = ee.Image.cat([ + hsv.select('hue'), + hsv.select('saturation'), + imageL8.select(['B8']) +]).hsvToRgb(); + +Map.addLayer(rgb, { + max: 0.4 +}, 'Pan-sharpened'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31c Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31c Checkpoint.py new file mode 100644 index 0000000..1a9f2d5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.1 Advanced Pixel-Based Image Transformations/F31c Checkpoint.py @@ -0,0 +1,264 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.1 Advanced Pixel-Based Image Transformations +# Checkpoint: F31c +# Authors: Karen, Andrea, Nick, and David +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##/ +# Manipulating images with matrices +##/ + +# Begin Tasseled Cap example. +landsat5RT = 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] +]) + +print('RT for Landsat 5', landsat5RT) + +# Define a point of interest in Odessa, Washington, USA. +point = ee.Geometry.Point([-118.7436019417829, +47.18135755009023]) +Map.centerObject(point, 10) + +# Filter to get a cloud free image to use for the TC. +imageL5 = ee.ImageCollection('LANDSAT/LT05/C02/T1_TOA') \ + .filterBounds(point) \ + .filterDate('2008-06-01', '2008-09-01') \ + .sort('CLOUD_COVER') \ + .first() + +#Display the True-color image. +TrueColor = { + 'bands': ['B3', 'B2', 'B1'], + 'min': 0, + 'max': 0.3 +} +Map.addLayer(imageL5, TrueColor, 'L5 True color') + +bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B7'] + +# Make an Array Image, with a one dimensional array per pixel. +# This is essentially a list of values of length 6, +# one from each band in variable 'bands.' +arrayImage1D = imageL5.select(bands).toArray() + +# Make an Array Image with a two dimensional array per pixel, +# of dimensions 6x1. This is essentially a one column matrix with +# six rows, with one value from each band in 'bands.' +# This step is needed for matrix multiplication (p0). +arrayImage2D = arrayImage1D.toArray(1) + +#Multiply RT by p0. +tasselCapImage = ee.Image(landsat5RT) + # Multiply the tasseled cap coefficients by the array \ + .matrixMultiply(arrayImage2D) \ + .arrayProject([0]) \ + .arrayFlatten( + [ + ['brightness', 'greenness', 'wetness', 'fourth', 'fifth', + 'sixth' + ] + ]) + +vizParams = { + 'bands': ['brightness', 'greenness', 'wetness'], + 'min': -0.1, + 'max': [0.5, 0.1, 0.1] +} +Map.addLayer(tasselCapImage, vizParams, 'TC components') + +# Begin PCA example. + +# Select and map a True-color L8 image. +imageL8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterBounds(point) \ + .filterDate('2018-06-01', '2018-09-01') \ + .sort('CLOUD_COVER') \ + .first() + +TrueColorL8 = { + 'bands': ['B4', 'B3', 'B2'], + 'min': 0, + 'max': 0.3 +} +Map.addLayer(imageL8, TrueColorL8, 'L8 True color') + +# Select which bands to use for the PCA. +PCAbands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B10', 'B11'] + +# Convert the Landsat 8 image to a 2D array for the later matrix +# computations. +arrayImage = imageL8.select(PCAbands).toArray() + +# Calculate the covariance using the reduceRegion method. +covar = arrayImage.reduceRegion({ + 'reducer': ee.Reducer.covariance(), + 'maxPixels': 1e9 +}) + +# Extract the covariance matrix and store it as an array. +covarArray = ee.Array(covar.get('array')) + +#Compute and extract the eigenvectors +eigens = covarArray.eigen() +eigenVectors = eigens.slice(1, 1) + +# Perform matrix multiplication +principalComponents = ee.Image(eigenVectors) \ + .matrixMultiply(arrayImage.toArray(1)) + +pcImage = principalComponents \ + .arrayProject([0]) \ + .arrayFlatten([ + ['pc1', 'pc2', 'pc3', 'pc4', 'pc5', 'pc6', 'pc7', 'pc8'] + ]) + +# Stretch this to the appropriate scale. +Map.addLayer(pcImage.select('pc1'), {}, 'pc1') + +#The min and max values will need to change if you map different bands or locations. +visParamsPCA = { + 'bands': ['pc1', 'pc3', 'pc4'], + 'min': [-455.09, -2.206, -4.53], + 'max': [-417.59, -1.3, -4.18] +} + +Map.addLayer(pcImage, visParamsPCA, 'PC_multi') + +# Begin spectral unmixing example. + +# Specify which bands to use for the unmixing. +unmixImage = imageL8.select(['B2', 'B3', 'B4', 'B5', 'B6', 'B7']) + +# Use a False color composite to help define polygons of 'pure' land cover. +Map.addLayer(imageL8, { + 'bands': ['B5', 'B4', 'B3'], + 'min': 0.0, + 'max': 0.4 +}, 'False color') + +# Define polygons of bare, water, and vegetation. +bare = ee.Geometry.Polygon( + [ + [ + [-119.29158963591193, 47.204453926034134], + [-119.29192222982978, 47.20372502078616], + [-119.29054893881415, 47.20345532330602], + [-119.29017342955207, 47.20414049800489] + ] + ]), +water = ee.Geometry.Polygon( + [ + [ + [-119.42904610218152, 47.22253398528318], + [-119.42973274768933, 47.22020224831784], + [-119.43299431385144, 47.21390604625894], + [-119.42904610218152, 47.21326472446865], + [-119.4271149116908, 47.21868656429651], + [-119.42608494342907, 47.2217470355224] + ] + ]), +veg = ee.Geometry.Polygon( + [ + [ + [-119.13546041722502, 47.04929418944858], + [-119.13752035374846, 47.04929418944858], + [-119.13966612096037, 47.04765665820436], + [-119.13777784581389, 47.04408900535686] + ] + ]) + +#Print a chart. +lcfeatures = ee.FeatureCollection([ + ee.Feature(bare, { + 'label': 'bare' + }), + ee.Feature(water, { + 'label': 'water' + }), + ee.Feature(veg, { + 'label': 'vegetation' + }) +]) + +print( + ui.Chart.image.regions({ + 'image': unmixImage, + 'regions': lcfeatures, + 'reducer': ee.Reducer.mean(), + 'scale': 30, + 'seriesProperty': 'label', + 'xLabels': [0.48, 0.56, 0.65, 0.86, 1.61, 2.2] + }) \ + .setChartType('LineChart') \ + .setOptions({ + 'title': 'Image band values in 3 regions', + 'hAxis': { + 'title': 'Wavelength' + }, + 'vAxis': { + 'title': 'Mean Reflectance' + } + })) + +# Get the means for each region. +bareMean = unmixImage \ + .reduceRegion(ee.Reducer.mean(), bare, 30).values() +waterMean = unmixImage \ + .reduceRegion(ee.Reducer.mean(), water, 30).values() +vegMean = unmixImage \ + .reduceRegion(ee.Reducer.mean(), veg, 30).values() + +# Stack these mean vectors to create an Array. +endmembers = ee.Array.cat([bareMean, vegMean, waterMean], 1) +print(endmembers) + +# Convert the 6-band input image to an image array. +arrayImage = unmixImage.toArray().toArray(1) + +# Solve for f. +unmixed = ee.Image(endmembers).matrixSolve(arrayImage) + +# Convert the result back to a multi-band image. +unmixedImage = unmixed \ + .arrayProject([0]) \ + .arrayFlatten([ + ['bare', 'veg', 'water'] + ]) + +Map.addLayer(unmixedImage, {}, 'Unmixed') + +# Begin HSV transformation example + +# Convert Landsat 8 RGB bands to HSV color space +hsv = imageL8.select(['B4', 'B3', 'B2']).rgbToHsv() + +Map.addLayer(hsv, { + 'max': 0.4 +}, 'HSV Transform') + +# Convert back to RGB, swapping the image panchromatic band for the value. +rgb = ee.Image.cat([ + hsv.select('hue'), + hsv.select('saturation'), + imageL8.select(['B8']) +]).hsvToRgb() + +Map.addLayer(rgb, { + 'max': 0.4 +}, 'Pan-sharpened') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32a Checkpoint.ipynb new file mode 100644 index 0000000..978d0e7 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32a Checkpoint.ipynb @@ -0,0 +1,199 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.2 Neighborhood-Based Image Transformation\n", + "# Checkpoint: F32a\n", + "# Authors: Karen, Andrea, David, Nick\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Create and print a uniform kernel to see its weights.\n", + "print('A uniform kernel:', ee.Kernel.square(2))\n", + "\n", + "# Define a point of interest in Odessa, Washington, USA.\n", + "point = ee.Geometry.Point([-118.71845096212049,\n", + " 47.15743083101999])\n", + "Map.centerObject(point)\n", + "\n", + "# Load NAIP data.\n", + "imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') \\\n", + " .filterBounds(point) \\\n", + " .filter(ee.Filter.date('2017-01-01', '2018-12-31')) \\\n", + " .first()\n", + "\n", + "Map.centerObject(point, 17)\n", + "\n", + "TrueColor = {\n", + " 'bands': ['R', 'G', 'B'],\n", + " 'min': 0,\n", + " 'max': 255\n", + "}\n", + "Map.addLayer(imageNAIP, TrueColor, 'True color')\n", + "\n", + "# Begin smoothing example.\n", + "# Define a square, uniform kernel.\n", + "uniformKernel = ee.Kernel.square({\n", + " 'radius': 2,\n", + " 'units': 'meters',\n", + "})\n", + "\n", + "# Convolve the image by convolving with the smoothing kernel.\n", + "smoothed = imageNAIP.convolve(uniformKernel)\n", + "Map.addLayer(smoothed, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'smoothed image')\n", + "\n", + "# Begin Gaussian smoothing example.\n", + "# Print a Gaussian kernel to see its weights.\n", + "print('A Gaussian kernel:', ee.Kernel.gaussian(2))\n", + "\n", + "# Define a square Gaussian kernel:\n", + "gaussianKernel = ee.Kernel.gaussian({\n", + " 'radius': 2,\n", + " 'units': 'meters',\n", + "})\n", + "\n", + "# Convolve the image with the Gaussian kernel.\n", + "gaussian = imageNAIP.convolve(gaussianKernel)\n", + "Map.addLayer(gaussian, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Gaussian smoothed image')\n", + "\n", + "# Begin edge detection example.\n", + "# For edge detection, define a Laplacian kernel.\n", + "laplacianKernel = ee.Kernel.laplacian8()\n", + "\n", + "# Print the kernel to see its weights.\n", + "print('Edge detection Laplacian kernel:', laplacianKernel)\n", + "\n", + "# Convolve the image with the Laplacian kernel.\n", + "edges = imageNAIP.convolve(laplacianKernel)\n", + "Map.addLayer(edges, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Laplacian convolution image')\n", + "\n", + "# Begin image sharpening example.\n", + "# Define a \"fat\" Gaussian kernel.\n", + "fat = ee.Kernel.gaussian({\n", + " 'radius': 3,\n", + " 'sigma': 3,\n", + " 'magnitude': -1,\n", + " 'units': 'meters'\n", + "})\n", + "\n", + "# Define a \"skinny\" Gaussian kernel.\n", + "skinny = ee.Kernel.gaussian({\n", + " 'radius': 3,\n", + " 'sigma': 0.5,\n", + " 'units': 'meters'\n", + "})\n", + "\n", + "# Compute a difference-of-Gaussians (DOG) kernel.\n", + "dog = fat.add(skinny)\n", + "\n", + "# Print the kernel to see its weights.\n", + "print('DoG kernel for image sharpening', dog)\n", + "\n", + "# Add the DoG convolved image to the original image.\n", + "sharpened = imageNAIP.add(imageNAIP.convolve(dog))\n", + "Map.addLayer(sharpened, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'DoG edge enhancement')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32a Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32a Checkpoint.js new file mode 100644 index 0000000..bd0b62c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32a Checkpoint.js @@ -0,0 +1,106 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.2 Neighborhood-Based Image Transformation +// Checkpoint: F32a +// Authors: Karen, Andrea, David, Nick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create and print a uniform kernel to see its weights. +print('A uniform kernel:', ee.Kernel.square(2)); + +// Define a point of interest in Odessa, Washington, USA. +var point = ee.Geometry.Point([-118.71845096212049, + 47.15743083101999]); +Map.centerObject(point); + +// Load NAIP data. +var imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') + .filterBounds(point) + .filter(ee.Filter.date('2017-01-01', '2018-12-31')) + .first(); + +Map.centerObject(point, 17); + +var trueColor = { + bands: ['R', 'G', 'B'], + min: 0, + max: 255 +}; +Map.addLayer(imageNAIP, trueColor, 'true color'); + +// Begin smoothing example. +// Define a square, uniform kernel. +var uniformKernel = ee.Kernel.square({ + radius: 2, + units: 'meters', +}); + +// Convolve the image by convolving with the smoothing kernel. +var smoothed = imageNAIP.convolve(uniformKernel); +Map.addLayer(smoothed, { + min: 0, + max: 255 +}, 'smoothed image'); + +// Begin Gaussian smoothing example. +// Print a Gaussian kernel to see its weights. +print('A Gaussian kernel:', ee.Kernel.gaussian(2)); + +// Define a square Gaussian kernel: +var gaussianKernel = ee.Kernel.gaussian({ + radius: 2, + units: 'meters', +}); + +// Convolve the image with the Gaussian kernel. +var gaussian = imageNAIP.convolve(gaussianKernel); +Map.addLayer(gaussian, { + min: 0, + max: 255 +}, 'Gaussian smoothed image'); + +// Begin edge detection example. +// For edge detection, define a Laplacian kernel. +var laplacianKernel = ee.Kernel.laplacian8(); + +// Print the kernel to see its weights. +print('Edge detection Laplacian kernel:', laplacianKernel); + +// Convolve the image with the Laplacian kernel. +var edges = imageNAIP.convolve(laplacianKernel); +Map.addLayer(edges, { + min: 0, + max: 255 +}, 'Laplacian convolution image'); + +// Begin image sharpening example. +// Define a "fat" Gaussian kernel. +var fat = ee.Kernel.gaussian({ + radius: 3, + sigma: 3, + magnitude: -1, + units: 'meters' +}); + +// Define a "skinny" Gaussian kernel. +var skinny = ee.Kernel.gaussian({ + radius: 3, + sigma: 0.5, + units: 'meters' +}); + +// Compute a difference-of-Gaussians (DOG) kernel. +var dog = fat.add(skinny); + +// Print the kernel to see its weights. +print('DoG kernel for image sharpening', dog); + +// Add the DoG convolved image to the original image. +var sharpened = imageNAIP.add(imageNAIP.convolve(dog)); +Map.addLayer(sharpened, { + min: 0, + max: 255 +}, 'DoG edge enhancement'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32a Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32a Checkpoint.py new file mode 100644 index 0000000..dab7a35 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32a Checkpoint.py @@ -0,0 +1,112 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.2 Neighborhood-Based Image Transformation +# Checkpoint: F32a +# Authors: Karen, Andrea, David, Nick +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Create and print a uniform kernel to see its weights. +print('A uniform kernel:', ee.Kernel.square(2)) + +# Define a point of interest in Odessa, Washington, USA. +point = ee.Geometry.Point([-118.71845096212049, + 47.15743083101999]) +Map.centerObject(point) + +# Load NAIP data. +imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') \ + .filterBounds(point) \ + .filter(ee.Filter.date('2017-01-01', '2018-12-31')) \ + .first() + +Map.centerObject(point, 17) + +TrueColor = { + 'bands': ['R', 'G', 'B'], + 'min': 0, + 'max': 255 +} +Map.addLayer(imageNAIP, TrueColor, 'True color') + +# Begin smoothing example. +# Define a square, uniform kernel. +uniformKernel = ee.Kernel.square({ + 'radius': 2, + 'units': 'meters', +}) + +# Convolve the image by convolving with the smoothing kernel. +smoothed = imageNAIP.convolve(uniformKernel) +Map.addLayer(smoothed, { + 'min': 0, + 'max': 255 +}, 'smoothed image') + +# Begin Gaussian smoothing example. +# Print a Gaussian kernel to see its weights. +print('A Gaussian kernel:', ee.Kernel.gaussian(2)) + +# Define a square Gaussian kernel: +gaussianKernel = ee.Kernel.gaussian({ + 'radius': 2, + 'units': 'meters', +}) + +# Convolve the image with the Gaussian kernel. +gaussian = imageNAIP.convolve(gaussianKernel) +Map.addLayer(gaussian, { + 'min': 0, + 'max': 255 +}, 'Gaussian smoothed image') + +# Begin edge detection example. +# For edge detection, define a Laplacian kernel. +laplacianKernel = ee.Kernel.laplacian8() + +# Print the kernel to see its weights. +print('Edge detection Laplacian kernel:', laplacianKernel) + +# Convolve the image with the Laplacian kernel. +edges = imageNAIP.convolve(laplacianKernel) +Map.addLayer(edges, { + 'min': 0, + 'max': 255 +}, 'Laplacian convolution image') + +# Begin image sharpening example. +# Define a "fat" Gaussian kernel. +fat = ee.Kernel.gaussian({ + 'radius': 3, + 'sigma': 3, + 'magnitude': -1, + 'units': 'meters' +}) + +# Define a "skinny" Gaussian kernel. +skinny = ee.Kernel.gaussian({ + 'radius': 3, + 'sigma': 0.5, + 'units': 'meters' +}) + +# Compute a difference-of-Gaussians (DOG) kernel. +dog = fat.add(skinny) + +# Print the kernel to see its weights. +print('DoG kernel for image sharpening', dog) + +# Add the DoG convolved image to the original image. +sharpened = imageNAIP.add(imageNAIP.convolve(dog)) +Map.addLayer(sharpened, { + 'min': 0, + 'max': 255 +}, 'DoG edge enhancement') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32b Checkpoint.ipynb new file mode 100644 index 0000000..0a0f2b3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32b Checkpoint.ipynb @@ -0,0 +1,235 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.2 Neighborhood-Based Image Transformation\n", + "# Checkpoint: F32b\n", + "# Authors: Karen, Andrea, David, Nick\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Create and print a uniform kernel to see its weights.\n", + "print('A uniform kernel:', ee.Kernel.square(2))\n", + "\n", + "# Define a point of interest in Odessa, Washington, USA.\n", + "point = ee.Geometry.Point([-118.71845096212049,\n", + " 47.15743083101999])\n", + "Map.centerObject(point)\n", + "\n", + "# Load NAIP data.\n", + "imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') \\\n", + " .filterBounds(point) \\\n", + " .filter(ee.Filter.date('2017-01-01', '2018-12-31')) \\\n", + " .first()\n", + "\n", + "Map.centerObject(point, 17)\n", + "\n", + "TrueColor = {\n", + " 'bands': ['R', 'G', 'B'],\n", + " 'min': 0,\n", + " 'max': 255\n", + "}\n", + "Map.addLayer(imageNAIP, TrueColor, 'True color')\n", + "\n", + "# Begin smoothing example.\n", + "# Define a square, uniform kernel.\n", + "uniformKernel = ee.Kernel.square({\n", + " 'radius': 2,\n", + " 'units': 'meters',\n", + "})\n", + "\n", + "# Convolve the image by convolving with the smoothing kernel.\n", + "smoothed = imageNAIP.convolve(uniformKernel)\n", + "Map.addLayer(smoothed, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'smoothed image')\n", + "\n", + "# Begin Gaussian smoothing example.\n", + "# Print a Gaussian kernel to see its weights.\n", + "print('A Gaussian kernel:', ee.Kernel.gaussian(2))\n", + "\n", + "# Define a square Gaussian kernel:\n", + "gaussianKernel = ee.Kernel.gaussian({\n", + " 'radius': 2,\n", + " 'units': 'meters',\n", + "})\n", + "\n", + "# Convolve the image with the Gaussian kernel.\n", + "gaussian = imageNAIP.convolve(gaussianKernel)\n", + "Map.addLayer(gaussian, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Gaussian smoothed image')\n", + "\n", + "# Begin edge detection example.\n", + "# For edge detection, define a Laplacian kernel.\n", + "laplacianKernel = ee.Kernel.laplacian8()\n", + "\n", + "# Print the kernel to see its weights.\n", + "print('Edge detection Laplacian kernel:', laplacianKernel)\n", + "\n", + "# Convolve the image with the Laplacian kernel.\n", + "edges = imageNAIP.convolve(laplacianKernel)\n", + "Map.addLayer(edges, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Laplacian convolution image')\n", + "\n", + "# Begin image sharpening example.\n", + "# Define a \"fat\" Gaussian kernel.\n", + "fat = ee.Kernel.gaussian({\n", + " 'radius': 3,\n", + " 'sigma': 3,\n", + " 'magnitude': -1,\n", + " 'units': 'meters'\n", + "})\n", + "\n", + "# Define a \"skinny\" Gaussian kernel.\n", + "skinny = ee.Kernel.gaussian({\n", + " 'radius': 3,\n", + " 'sigma': 0.5,\n", + " 'units': 'meters'\n", + "})\n", + "\n", + "# Compute a difference-of-Gaussians (DOG) kernel.\n", + "dog = fat.add(skinny)\n", + "\n", + "# Print the kernel to see its weights.\n", + "print('DoG kernel for image sharpening', dog)\n", + "\n", + "# Add the DoG convolved image to the original image.\n", + "sharpened = imageNAIP.add(imageNAIP.convolve(dog))\n", + "Map.addLayer(sharpened, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'DoG edge enhancement')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Begin median example.\n", + "# Pass a median neighborhood filter using our uniformKernel.\n", + "median = imageNAIP.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.median(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(median, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Median Neighborhood Filter')\n", + "\n", + "# Mode example\n", + "# Create and display a simple two-class image.\n", + "veg = imageNAIP.select('N').gt(200)\n", + "\n", + "# Display the two-class (binary) result.\n", + "binaryVis = {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['black', 'green']\n", + "}\n", + "Map.addLayer(veg, binaryVis, 'Vegetation categorical image')\n", + "\n", + "# Compute the mode in each 5x5 neighborhood and display the result.\n", + "mode = veg.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.mode(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(mode, binaryVis, 'Mode Neighborhood Filter on Vegetation categorical image')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32b Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32b Checkpoint.js new file mode 100644 index 0000000..de61097 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32b Checkpoint.js @@ -0,0 +1,142 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.2 Neighborhood-Based Image Transformation +// Checkpoint: F32b +// Authors: Karen, Andrea, David, Nick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create and print a uniform kernel to see its weights. +print('A uniform kernel:', ee.Kernel.square(2)); + +// Define a point of interest in Odessa, Washington, USA. +var point = ee.Geometry.Point([-118.71845096212049, + 47.15743083101999]); +Map.centerObject(point); + +// Load NAIP data. +var imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') + .filterBounds(point) + .filter(ee.Filter.date('2017-01-01', '2018-12-31')) + .first(); + +Map.centerObject(point, 17); + +var trueColor = { + bands: ['R', 'G', 'B'], + min: 0, + max: 255 +}; +Map.addLayer(imageNAIP, trueColor, 'true color'); + +// Begin smoothing example. +// Define a square, uniform kernel. +var uniformKernel = ee.Kernel.square({ + radius: 2, + units: 'meters', +}); + +// Convolve the image by convolving with the smoothing kernel. +var smoothed = imageNAIP.convolve(uniformKernel); +Map.addLayer(smoothed, { + min: 0, + max: 255 +}, 'smoothed image'); + +// Begin Gaussian smoothing example. +// Print a Gaussian kernel to see its weights. +print('A Gaussian kernel:', ee.Kernel.gaussian(2)); + +// Define a square Gaussian kernel: +var gaussianKernel = ee.Kernel.gaussian({ + radius: 2, + units: 'meters', +}); + +// Convolve the image with the Gaussian kernel. +var gaussian = imageNAIP.convolve(gaussianKernel); +Map.addLayer(gaussian, { + min: 0, + max: 255 +}, 'Gaussian smoothed image'); + +// Begin edge detection example. +// For edge detection, define a Laplacian kernel. +var laplacianKernel = ee.Kernel.laplacian8(); + +// Print the kernel to see its weights. +print('Edge detection Laplacian kernel:', laplacianKernel); + +// Convolve the image with the Laplacian kernel. +var edges = imageNAIP.convolve(laplacianKernel); +Map.addLayer(edges, { + min: 0, + max: 255 +}, 'Laplacian convolution image'); + +// Begin image sharpening example. +// Define a "fat" Gaussian kernel. +var fat = ee.Kernel.gaussian({ + radius: 3, + sigma: 3, + magnitude: -1, + units: 'meters' +}); + +// Define a "skinny" Gaussian kernel. +var skinny = ee.Kernel.gaussian({ + radius: 3, + sigma: 0.5, + units: 'meters' +}); + +// Compute a difference-of-Gaussians (DOG) kernel. +var dog = fat.add(skinny); + +// Print the kernel to see its weights. +print('DoG kernel for image sharpening', dog); + +// Add the DoG convolved image to the original image. +var sharpened = imageNAIP.add(imageNAIP.convolve(dog)); +Map.addLayer(sharpened, { + min: 0, + max: 255 +}, 'DoG edge enhancement'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Begin median example. +// Pass a median neighborhood filter using our uniformKernel. +var median = imageNAIP.reduceNeighborhood({ + reducer: ee.Reducer.median(), + kernel: uniformKernel +}); + +Map.addLayer(median, { + min: 0, + max: 255 +}, 'Median Neighborhood Filter'); + +// Mode example +// Create and display a simple two-class image. +var veg = imageNAIP.select('N').gt(200); + +// Display the two-class (binary) result. +var binaryVis = { + min: 0, + max: 1, + palette: ['black', 'green'] +}; +Map.addLayer(veg, binaryVis, 'Vegetation categorical image'); + +// Compute the mode in each 5x5 neighborhood and display the result. +var mode = veg.reduceNeighborhood({ + reducer: ee.Reducer.mode(), + kernel: uniformKernel +}); + +Map.addLayer(mode, binaryVis, 'Mode Neighborhood Filter on Vegetation categorical image'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32b Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32b Checkpoint.py new file mode 100644 index 0000000..4f1be52 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32b Checkpoint.py @@ -0,0 +1,148 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.2 Neighborhood-Based Image Transformation +# Checkpoint: F32b +# Authors: Karen, Andrea, David, Nick +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Create and print a uniform kernel to see its weights. +print('A uniform kernel:', ee.Kernel.square(2)) + +# Define a point of interest in Odessa, Washington, USA. +point = ee.Geometry.Point([-118.71845096212049, + 47.15743083101999]) +Map.centerObject(point) + +# Load NAIP data. +imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') \ + .filterBounds(point) \ + .filter(ee.Filter.date('2017-01-01', '2018-12-31')) \ + .first() + +Map.centerObject(point, 17) + +TrueColor = { + 'bands': ['R', 'G', 'B'], + 'min': 0, + 'max': 255 +} +Map.addLayer(imageNAIP, TrueColor, 'True color') + +# Begin smoothing example. +# Define a square, uniform kernel. +uniformKernel = ee.Kernel.square({ + 'radius': 2, + 'units': 'meters', +}) + +# Convolve the image by convolving with the smoothing kernel. +smoothed = imageNAIP.convolve(uniformKernel) +Map.addLayer(smoothed, { + 'min': 0, + 'max': 255 +}, 'smoothed image') + +# Begin Gaussian smoothing example. +# Print a Gaussian kernel to see its weights. +print('A Gaussian kernel:', ee.Kernel.gaussian(2)) + +# Define a square Gaussian kernel: +gaussianKernel = ee.Kernel.gaussian({ + 'radius': 2, + 'units': 'meters', +}) + +# Convolve the image with the Gaussian kernel. +gaussian = imageNAIP.convolve(gaussianKernel) +Map.addLayer(gaussian, { + 'min': 0, + 'max': 255 +}, 'Gaussian smoothed image') + +# Begin edge detection example. +# For edge detection, define a Laplacian kernel. +laplacianKernel = ee.Kernel.laplacian8() + +# Print the kernel to see its weights. +print('Edge detection Laplacian kernel:', laplacianKernel) + +# Convolve the image with the Laplacian kernel. +edges = imageNAIP.convolve(laplacianKernel) +Map.addLayer(edges, { + 'min': 0, + 'max': 255 +}, 'Laplacian convolution image') + +# Begin image sharpening example. +# Define a "fat" Gaussian kernel. +fat = ee.Kernel.gaussian({ + 'radius': 3, + 'sigma': 3, + 'magnitude': -1, + 'units': 'meters' +}) + +# Define a "skinny" Gaussian kernel. +skinny = ee.Kernel.gaussian({ + 'radius': 3, + 'sigma': 0.5, + 'units': 'meters' +}) + +# Compute a difference-of-Gaussians (DOG) kernel. +dog = fat.add(skinny) + +# Print the kernel to see its weights. +print('DoG kernel for image sharpening', dog) + +# Add the DoG convolved image to the original image. +sharpened = imageNAIP.add(imageNAIP.convolve(dog)) +Map.addLayer(sharpened, { + 'min': 0, + 'max': 255 +}, 'DoG edge enhancement') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Begin median example. +# Pass a median neighborhood filter using our uniformKernel. +median = imageNAIP.reduceNeighborhood({ + 'reducer': ee.Reducer.median(), + 'kernel': uniformKernel +}) + +Map.addLayer(median, { + 'min': 0, + 'max': 255 +}, 'Median Neighborhood Filter') + +# Mode example +# Create and display a simple two-class image. +veg = imageNAIP.select('N').gt(200) + +# Display the two-class (binary) result. +binaryVis = { + 'min': 0, + 'max': 1, + 'palette': ['black', 'green'] +} +Map.addLayer(veg, binaryVis, 'Vegetation categorical image') + +# Compute the mode in each 5x5 neighborhood and display the result. +mode = veg.reduceNeighborhood({ + 'reducer': ee.Reducer.mode(), + 'kernel': uniformKernel +}) + +Map.addLayer(mode, binaryVis, 'Mode Neighborhood Filter on Vegetation categorical image') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32c Checkpoint.ipynb new file mode 100644 index 0000000..eea3c9f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32c Checkpoint.ipynb @@ -0,0 +1,275 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.2 Neighborhood-Based Image Transformation\n", + "# Checkpoint: F32c\n", + "# Authors: Karen, Andrea, David, Nick\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Create and print a uniform kernel to see its weights.\n", + "print('A uniform kernel:', ee.Kernel.square(2))\n", + "\n", + "# Define a point of interest in Odessa, Washington, USA.\n", + "point = ee.Geometry.Point([-118.71845096212049,\n", + " 47.15743083101999])\n", + "Map.centerObject(point)\n", + "\n", + "# Load NAIP data.\n", + "imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') \\\n", + " .filterBounds(point) \\\n", + " .filter(ee.Filter.date('2017-01-01', '2018-12-31')) \\\n", + " .first()\n", + "\n", + "Map.centerObject(point, 17)\n", + "\n", + "TrueColor = {\n", + " 'bands': ['R', 'G', 'B'],\n", + " 'min': 0,\n", + " 'max': 255\n", + "}\n", + "Map.addLayer(imageNAIP, TrueColor, 'True color')\n", + "\n", + "# Begin smoothing example.\n", + "# Define a square, uniform kernel.\n", + "uniformKernel = ee.Kernel.square({\n", + " 'radius': 2,\n", + " 'units': 'meters',\n", + "})\n", + "\n", + "# Convolve the image by convolving with the smoothing kernel.\n", + "smoothed = imageNAIP.convolve(uniformKernel)\n", + "Map.addLayer(smoothed, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'smoothed image')\n", + "\n", + "# Begin Gaussian smoothing example.\n", + "# Print a Gaussian kernel to see its weights.\n", + "print('A Gaussian kernel:', ee.Kernel.gaussian(2))\n", + "\n", + "# Define a square Gaussian kernel:\n", + "gaussianKernel = ee.Kernel.gaussian({\n", + " 'radius': 2,\n", + " 'units': 'meters',\n", + "})\n", + "\n", + "# Convolve the image with the Gaussian kernel.\n", + "gaussian = imageNAIP.convolve(gaussianKernel)\n", + "Map.addLayer(gaussian, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Gaussian smoothed image')\n", + "\n", + "# Begin edge detection example.\n", + "# For edge detection, define a Laplacian kernel.\n", + "laplacianKernel = ee.Kernel.laplacian8()\n", + "\n", + "# Print the kernel to see its weights.\n", + "print('Edge detection Laplacian kernel:', laplacianKernel)\n", + "\n", + "# Convolve the image with the Laplacian kernel.\n", + "edges = imageNAIP.convolve(laplacianKernel)\n", + "Map.addLayer(edges, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Laplacian convolution image')\n", + "\n", + "# Begin image sharpening example.\n", + "# Define a \"fat\" Gaussian kernel.\n", + "fat = ee.Kernel.gaussian({\n", + " 'radius': 3,\n", + " 'sigma': 3,\n", + " 'magnitude': -1,\n", + " 'units': 'meters'\n", + "})\n", + "\n", + "# Define a \"skinny\" Gaussian kernel.\n", + "skinny = ee.Kernel.gaussian({\n", + " 'radius': 3,\n", + " 'sigma': 0.5,\n", + " 'units': 'meters'\n", + "})\n", + "\n", + "# Compute a difference-of-Gaussians (DOG) kernel.\n", + "dog = fat.add(skinny)\n", + "\n", + "# Print the kernel to see its weights.\n", + "print('DoG kernel for image sharpening', dog)\n", + "\n", + "# Add the DoG convolved image to the original image.\n", + "sharpened = imageNAIP.add(imageNAIP.convolve(dog))\n", + "Map.addLayer(sharpened, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'DoG edge enhancement')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Begin median example.\n", + "# Pass a median neighborhood filter using our uniformKernel.\n", + "median = imageNAIP.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.median(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(median, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Median Neighborhood Filter')\n", + "\n", + "# Mode example\n", + "# Create and display a simple two-class image.\n", + "veg = imageNAIP.select('N').gt(200)\n", + "\n", + "# Display the two-class (binary) result.\n", + "binaryVis = {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['black', 'green']\n", + "}\n", + "Map.addLayer(veg, binaryVis, 'Vegetation categorical image')\n", + "\n", + "# Compute the mode in each 5x5 neighborhood and display the result.\n", + "mode = veg.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.mode(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(mode, binaryVis, 'Mode Neighborhood Filter on Vegetation categorical image')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Begin Dilation example.\n", + "# Dilate by taking the max in each 5x5 neighborhood.\n", + "max = veg.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(max, binaryVis, 'Dilation using max')\n", + "\n", + "# Begin Erosion example.\n", + "# Erode by taking the min in each 5x5 neighborhood.\n", + "min = veg.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.min(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(min, binaryVis, 'Erosion using min')\n", + "\n", + "# Begin Opening example.\n", + "# Perform an opening by dilating the eroded image.\n", + "openedVeg = min.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(openedVeg, binaryVis, 'Opened image')\n", + "\n", + "# Begin Closing example.\n", + "# Perform a closing by eroding the dilated image.\n", + "closedVeg = max.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.min(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(closedVeg, binaryVis, 'Closed image')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32c Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32c Checkpoint.js new file mode 100644 index 0000000..7811a12 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32c Checkpoint.js @@ -0,0 +1,182 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.2 Neighborhood-Based Image Transformation +// Checkpoint: F32c +// Authors: Karen, Andrea, David, Nick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create and print a uniform kernel to see its weights. +print('A uniform kernel:', ee.Kernel.square(2)); + +// Define a point of interest in Odessa, Washington, USA. +var point = ee.Geometry.Point([-118.71845096212049, + 47.15743083101999]); +Map.centerObject(point); + +// Load NAIP data. +var imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') + .filterBounds(point) + .filter(ee.Filter.date('2017-01-01', '2018-12-31')) + .first(); + +Map.centerObject(point, 17); + +var trueColor = { + bands: ['R', 'G', 'B'], + min: 0, + max: 255 +}; +Map.addLayer(imageNAIP, trueColor, 'true color'); + +// Begin smoothing example. +// Define a square, uniform kernel. +var uniformKernel = ee.Kernel.square({ + radius: 2, + units: 'meters', +}); + +// Convolve the image by convolving with the smoothing kernel. +var smoothed = imageNAIP.convolve(uniformKernel); +Map.addLayer(smoothed, { + min: 0, + max: 255 +}, 'smoothed image'); + +// Begin Gaussian smoothing example. +// Print a Gaussian kernel to see its weights. +print('A Gaussian kernel:', ee.Kernel.gaussian(2)); + +// Define a square Gaussian kernel: +var gaussianKernel = ee.Kernel.gaussian({ + radius: 2, + units: 'meters', +}); + +// Convolve the image with the Gaussian kernel. +var gaussian = imageNAIP.convolve(gaussianKernel); +Map.addLayer(gaussian, { + min: 0, + max: 255 +}, 'Gaussian smoothed image'); + +// Begin edge detection example. +// For edge detection, define a Laplacian kernel. +var laplacianKernel = ee.Kernel.laplacian8(); + +// Print the kernel to see its weights. +print('Edge detection Laplacian kernel:', laplacianKernel); + +// Convolve the image with the Laplacian kernel. +var edges = imageNAIP.convolve(laplacianKernel); +Map.addLayer(edges, { + min: 0, + max: 255 +}, 'Laplacian convolution image'); + +// Begin image sharpening example. +// Define a "fat" Gaussian kernel. +var fat = ee.Kernel.gaussian({ + radius: 3, + sigma: 3, + magnitude: -1, + units: 'meters' +}); + +// Define a "skinny" Gaussian kernel. +var skinny = ee.Kernel.gaussian({ + radius: 3, + sigma: 0.5, + units: 'meters' +}); + +// Compute a difference-of-Gaussians (DOG) kernel. +var dog = fat.add(skinny); + +// Print the kernel to see its weights. +print('DoG kernel for image sharpening', dog); + +// Add the DoG convolved image to the original image. +var sharpened = imageNAIP.add(imageNAIP.convolve(dog)); +Map.addLayer(sharpened, { + min: 0, + max: 255 +}, 'DoG edge enhancement'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Begin median example. +// Pass a median neighborhood filter using our uniformKernel. +var median = imageNAIP.reduceNeighborhood({ + reducer: ee.Reducer.median(), + kernel: uniformKernel +}); + +Map.addLayer(median, { + min: 0, + max: 255 +}, 'Median Neighborhood Filter'); + +// Mode example +// Create and display a simple two-class image. +var veg = imageNAIP.select('N').gt(200); + +// Display the two-class (binary) result. +var binaryVis = { + min: 0, + max: 1, + palette: ['black', 'green'] +}; +Map.addLayer(veg, binaryVis, 'Vegetation categorical image'); + +// Compute the mode in each 5x5 neighborhood and display the result. +var mode = veg.reduceNeighborhood({ + reducer: ee.Reducer.mode(), + kernel: uniformKernel +}); + +Map.addLayer(mode, binaryVis, 'Mode Neighborhood Filter on Vegetation categorical image'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Begin Dilation example. +// Dilate by taking the max in each 5x5 neighborhood. +var max = veg.reduceNeighborhood({ + reducer: ee.Reducer.max(), + kernel: uniformKernel +}); + +Map.addLayer(max, binaryVis, 'Dilation using max'); + +// Begin Erosion example. +// Erode by taking the min in each 5x5 neighborhood. +var min = veg.reduceNeighborhood({ + reducer: ee.Reducer.min(), + kernel: uniformKernel +}); + +Map.addLayer(min, binaryVis, 'Erosion using min'); + +// Begin Opening example. +// Perform an opening by dilating the eroded image. +var openedVeg = min.reduceNeighborhood({ + reducer: ee.Reducer.max(), + kernel: uniformKernel +}); + +Map.addLayer(openedVeg, binaryVis, 'Opened image'); + +// Begin Closing example. +// Perform a closing by eroding the dilated image. +var closedVeg = max.reduceNeighborhood({ + reducer: ee.Reducer.min(), + kernel: uniformKernel +}); + +Map.addLayer(closedVeg, binaryVis, 'Closed image'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32c Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32c Checkpoint.py new file mode 100644 index 0000000..1ba2e91 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32c Checkpoint.py @@ -0,0 +1,188 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.2 Neighborhood-Based Image Transformation +# Checkpoint: F32c +# Authors: Karen, Andrea, David, Nick +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Create and print a uniform kernel to see its weights. +print('A uniform kernel:', ee.Kernel.square(2)) + +# Define a point of interest in Odessa, Washington, USA. +point = ee.Geometry.Point([-118.71845096212049, + 47.15743083101999]) +Map.centerObject(point) + +# Load NAIP data. +imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') \ + .filterBounds(point) \ + .filter(ee.Filter.date('2017-01-01', '2018-12-31')) \ + .first() + +Map.centerObject(point, 17) + +TrueColor = { + 'bands': ['R', 'G', 'B'], + 'min': 0, + 'max': 255 +} +Map.addLayer(imageNAIP, TrueColor, 'True color') + +# Begin smoothing example. +# Define a square, uniform kernel. +uniformKernel = ee.Kernel.square({ + 'radius': 2, + 'units': 'meters', +}) + +# Convolve the image by convolving with the smoothing kernel. +smoothed = imageNAIP.convolve(uniformKernel) +Map.addLayer(smoothed, { + 'min': 0, + 'max': 255 +}, 'smoothed image') + +# Begin Gaussian smoothing example. +# Print a Gaussian kernel to see its weights. +print('A Gaussian kernel:', ee.Kernel.gaussian(2)) + +# Define a square Gaussian kernel: +gaussianKernel = ee.Kernel.gaussian({ + 'radius': 2, + 'units': 'meters', +}) + +# Convolve the image with the Gaussian kernel. +gaussian = imageNAIP.convolve(gaussianKernel) +Map.addLayer(gaussian, { + 'min': 0, + 'max': 255 +}, 'Gaussian smoothed image') + +# Begin edge detection example. +# For edge detection, define a Laplacian kernel. +laplacianKernel = ee.Kernel.laplacian8() + +# Print the kernel to see its weights. +print('Edge detection Laplacian kernel:', laplacianKernel) + +# Convolve the image with the Laplacian kernel. +edges = imageNAIP.convolve(laplacianKernel) +Map.addLayer(edges, { + 'min': 0, + 'max': 255 +}, 'Laplacian convolution image') + +# Begin image sharpening example. +# Define a "fat" Gaussian kernel. +fat = ee.Kernel.gaussian({ + 'radius': 3, + 'sigma': 3, + 'magnitude': -1, + 'units': 'meters' +}) + +# Define a "skinny" Gaussian kernel. +skinny = ee.Kernel.gaussian({ + 'radius': 3, + 'sigma': 0.5, + 'units': 'meters' +}) + +# Compute a difference-of-Gaussians (DOG) kernel. +dog = fat.add(skinny) + +# Print the kernel to see its weights. +print('DoG kernel for image sharpening', dog) + +# Add the DoG convolved image to the original image. +sharpened = imageNAIP.add(imageNAIP.convolve(dog)) +Map.addLayer(sharpened, { + 'min': 0, + 'max': 255 +}, 'DoG edge enhancement') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Begin median example. +# Pass a median neighborhood filter using our uniformKernel. +median = imageNAIP.reduceNeighborhood({ + 'reducer': ee.Reducer.median(), + 'kernel': uniformKernel +}) + +Map.addLayer(median, { + 'min': 0, + 'max': 255 +}, 'Median Neighborhood Filter') + +# Mode example +# Create and display a simple two-class image. +veg = imageNAIP.select('N').gt(200) + +# Display the two-class (binary) result. +binaryVis = { + 'min': 0, + 'max': 1, + 'palette': ['black', 'green'] +} +Map.addLayer(veg, binaryVis, 'Vegetation categorical image') + +# Compute the mode in each 5x5 neighborhood and display the result. +mode = veg.reduceNeighborhood({ + 'reducer': ee.Reducer.mode(), + 'kernel': uniformKernel +}) + +Map.addLayer(mode, binaryVis, 'Mode Neighborhood Filter on Vegetation categorical image') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Begin Dilation example. +# Dilate by taking the max in each 5x5 neighborhood. +max = veg.reduceNeighborhood({ + 'reducer': ee.Reducer.max(), + 'kernel': uniformKernel +}) + +Map.addLayer(max, binaryVis, 'Dilation using max') + +# Begin Erosion example. +# Erode by taking the min in each 5x5 neighborhood. +min = veg.reduceNeighborhood({ + 'reducer': ee.Reducer.min(), + 'kernel': uniformKernel +}) + +Map.addLayer(min, binaryVis, 'Erosion using min') + +# Begin Opening example. +# Perform an opening by dilating the eroded image. +openedVeg = min.reduceNeighborhood({ + 'reducer': ee.Reducer.max(), + 'kernel': uniformKernel +}) + +Map.addLayer(openedVeg, binaryVis, 'Opened image') + +# Begin Closing example. +# Perform a closing by eroding the dilated image. +closedVeg = max.reduceNeighborhood({ + 'reducer': ee.Reducer.min(), + 'kernel': uniformKernel +}) + +Map.addLayer(closedVeg, binaryVis, 'Closed image') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32d Checkpoint.ipynb new file mode 100644 index 0000000..3d5c20a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32d Checkpoint.ipynb @@ -0,0 +1,355 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F3.2 Neighborhood-Based Image Transformation\n", + "# Checkpoint: F32d\n", + "# Authors: Karen, Andrea, David, Nick\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Create and print a uniform kernel to see its weights.\n", + "print('A uniform kernel:', ee.Kernel.square(2))\n", + "\n", + "# Define a point of interest in Odessa, Washington, USA.\n", + "point = ee.Geometry.Point([-118.71845096212049,\n", + " 47.15743083101999])\n", + "Map.centerObject(point)\n", + "\n", + "# Load NAIP data.\n", + "imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') \\\n", + " .filterBounds(point) \\\n", + " .filter(ee.Filter.date('2017-01-01', '2018-12-31')) \\\n", + " .first()\n", + "\n", + "Map.centerObject(point, 17)\n", + "\n", + "TrueColor = {\n", + " 'bands': ['R', 'G', 'B'],\n", + " 'min': 0,\n", + " 'max': 255\n", + "}\n", + "Map.addLayer(imageNAIP, TrueColor, 'True color')\n", + "\n", + "# Begin smoothing example.\n", + "# Define a square, uniform kernel.\n", + "uniformKernel = ee.Kernel.square({\n", + " 'radius': 2,\n", + " 'units': 'meters',\n", + "})\n", + "\n", + "# Convolve the image by convolving with the smoothing kernel.\n", + "smoothed = imageNAIP.convolve(uniformKernel)\n", + "Map.addLayer(smoothed, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'smoothed image')\n", + "\n", + "# Begin Gaussian smoothing example.\n", + "# Print a Gaussian kernel to see its weights.\n", + "print('A Gaussian kernel:', ee.Kernel.gaussian(2))\n", + "\n", + "# Define a square Gaussian kernel:\n", + "gaussianKernel = ee.Kernel.gaussian({\n", + " 'radius': 2,\n", + " 'units': 'meters',\n", + "})\n", + "\n", + "# Convolve the image with the Gaussian kernel.\n", + "gaussian = imageNAIP.convolve(gaussianKernel)\n", + "Map.addLayer(gaussian, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Gaussian smoothed image')\n", + "\n", + "# Begin edge detection example.\n", + "# For edge detection, define a Laplacian kernel.\n", + "laplacianKernel = ee.Kernel.laplacian8()\n", + "\n", + "# Print the kernel to see its weights.\n", + "print('Edge detection Laplacian kernel:', laplacianKernel)\n", + "\n", + "# Convolve the image with the Laplacian kernel.\n", + "edges = imageNAIP.convolve(laplacianKernel)\n", + "Map.addLayer(edges, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Laplacian convolution image')\n", + "\n", + "# Begin image sharpening example.\n", + "# Define a \"fat\" Gaussian kernel.\n", + "fat = ee.Kernel.gaussian({\n", + " 'radius': 3,\n", + " 'sigma': 3,\n", + " 'magnitude': -1,\n", + " 'units': 'meters'\n", + "})\n", + "\n", + "# Define a \"skinny\" Gaussian kernel.\n", + "skinny = ee.Kernel.gaussian({\n", + " 'radius': 3,\n", + " 'sigma': 0.5,\n", + " 'units': 'meters'\n", + "})\n", + "\n", + "# Compute a difference-of-Gaussians (DOG) kernel.\n", + "dog = fat.add(skinny)\n", + "\n", + "# Print the kernel to see its weights.\n", + "print('DoG kernel for image sharpening', dog)\n", + "\n", + "# Add the DoG convolved image to the original image.\n", + "sharpened = imageNAIP.add(imageNAIP.convolve(dog))\n", + "Map.addLayer(sharpened, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'DoG edge enhancement')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Begin median example.\n", + "# Pass a median neighborhood filter using our uniformKernel.\n", + "median = imageNAIP.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.median(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(median, {\n", + " 'min': 0,\n", + " 'max': 255\n", + "}, 'Median Neighborhood Filter')\n", + "\n", + "# Mode example\n", + "# Create and display a simple two-class image.\n", + "veg = imageNAIP.select('N').gt(200)\n", + "\n", + "# Display the two-class (binary) result.\n", + "binaryVis = {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'palette': ['black', 'green']\n", + "}\n", + "Map.addLayer(veg, binaryVis, 'Vegetation categorical image')\n", + "\n", + "# Compute the mode in each 5x5 neighborhood and display the result.\n", + "mode = veg.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.mode(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(mode, binaryVis, 'Mode Neighborhood Filter on Vegetation categorical image')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Begin Dilation example.\n", + "# Dilate by taking the max in each 5x5 neighborhood.\n", + "max = veg.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(max, binaryVis, 'Dilation using max')\n", + "\n", + "# Begin Erosion example.\n", + "# Erode by taking the min in each 5x5 neighborhood.\n", + "min = veg.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.min(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(min, binaryVis, 'Erosion using min')\n", + "\n", + "# Begin Opening example.\n", + "# Perform an opening by dilating the eroded image.\n", + "openedVeg = min.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.max(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(openedVeg, binaryVis, 'Opened image')\n", + "\n", + "# Begin Closing example.\n", + "# Perform a closing by eroding the dilated image.\n", + "closedVeg = max.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.min(),\n", + " 'kernel': uniformKernel\n", + "})\n", + "\n", + "Map.addLayer(closedVeg, binaryVis, 'Closed image')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Begin Standard Deviation example.\n", + "# Define a big neighborhood with a 7-meter radius kernel.\n", + "bigKernel = ee.Kernel.square({\n", + " 'radius': 7,\n", + " 'units': 'meters'\n", + "})\n", + "\n", + "# Compute SD in a neighborhood.\n", + "sd = imageNAIP.reduceNeighborhood({\n", + " 'reducer': ee.Reducer.stdDev(),\n", + " 'kernel': bigKernel\n", + "})\n", + "\n", + "Map.addLayer(sd, {\n", + " 'min': 0,\n", + " 'max': 70\n", + "}, 'SD')\n", + "\n", + "# Begin entropy example.\n", + "# Create an integer version of the NAIP image.\n", + "intNAIP = imageNAIP.int()\n", + "\n", + "# Compute entropy in a neighborhood.\n", + "entropy = intNAIP.select('N').entropy(bigKernel)\n", + "\n", + "Map.addLayer(entropy, {\n", + " 'min': 1,\n", + " 'max': 3\n", + "}, 'entropy')\n", + "\n", + "# Begin GLCM example.\n", + "# Use the GLCM to compute a large number of texture measures.\n", + "glcmTexture = intNAIP.glcmTexture(7)\n", + "print('view the glcmTexture output', glcmTexture)\n", + "\n", + "# Display the 'contrast' results for the red, green and blue bands.\n", + "contrastVis = {\n", + " 'bands': ['R_contrast', 'G_contrast', 'B_contrast'],\n", + " 'min': 40,\n", + " 'max': 1000\n", + "}\n", + "\n", + "Map.addLayer(glcmTexture, contrastVis, 'contrast')\n", + "\n", + "# Begin spatial statistics example using Geary's C.\n", + "\n", + "# Create a list of weights for a 9x9 kernel.\n", + "list = [1, 1, 1, 1, 1, 1, 1, 1, 1]\n", + "# The center of the kernel is zero.\n", + "centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1]\n", + "# Assemble a list of lists: the 9x9 kernel weights as a 2-D matrix.\n", + "lists = [list, list, list, list, centerList, list, list, list,\n", + " list\n", + "]\n", + "# Create the kernel from the weights.\n", + "# Non-zero weights represent the spatial neighborhood.\n", + "kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, False)\n", + "\n", + "# Use the max among bands as the input.\n", + "maxBands = imageNAIP.reduce(ee.Reducer.max())\n", + "\n", + "# Convert the neighborhood into multiple bands.\n", + "neighBands = maxBands.neighborhoodToBands(kernel)\n", + "\n", + "# Compute local Geary's C, a measure of spatial association.\n", + "gearys = maxBands.subtract(neighBands).pow(2).reduce(ee.Reducer \\\n", + " .sum()) \\\n", + " .divide(math.pow(9, 2))\n", + "\n", + "Map.addLayer(gearys, {\n", + " 'min': 20,\n", + " 'max': 2500\n", + "}, \"Geary's C\")\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32d Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32d Checkpoint.js new file mode 100644 index 0000000..bd3ff6a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32d Checkpoint.js @@ -0,0 +1,263 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.2 Neighborhood-Based Image Transformation +// Checkpoint: F32d +// Authors: Karen, Andrea, David, Nick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Create and print a uniform kernel to see its weights. +print('A uniform kernel:', ee.Kernel.square(2)); + +// Define a point of interest in Odessa, Washington, USA. +var point = ee.Geometry.Point([-118.71845096212049, + 47.15743083101999]); +Map.centerObject(point); + +// Load NAIP data. +var imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') + .filterBounds(point) + .filter(ee.Filter.date('2017-01-01', '2018-12-31')) + .first(); + +Map.centerObject(point, 17); + +var trueColor = { + bands: ['R', 'G', 'B'], + min: 0, + max: 255 +}; +Map.addLayer(imageNAIP, trueColor, 'true color'); + +// Begin smoothing example. +// Define a square, uniform kernel. +var uniformKernel = ee.Kernel.square({ + radius: 2, + units: 'meters', +}); + +// Convolve the image by convolving with the smoothing kernel. +var smoothed = imageNAIP.convolve(uniformKernel); +Map.addLayer(smoothed, { + min: 0, + max: 255 +}, 'smoothed image'); + +// Begin Gaussian smoothing example. +// Print a Gaussian kernel to see its weights. +print('A Gaussian kernel:', ee.Kernel.gaussian(2)); + +// Define a square Gaussian kernel: +var gaussianKernel = ee.Kernel.gaussian({ + radius: 2, + units: 'meters', +}); + +// Convolve the image with the Gaussian kernel. +var gaussian = imageNAIP.convolve(gaussianKernel); +Map.addLayer(gaussian, { + min: 0, + max: 255 +}, 'Gaussian smoothed image'); + +// Begin edge detection example. +// For edge detection, define a Laplacian kernel. +var laplacianKernel = ee.Kernel.laplacian8(); + +// Print the kernel to see its weights. +print('Edge detection Laplacian kernel:', laplacianKernel); + +// Convolve the image with the Laplacian kernel. +var edges = imageNAIP.convolve(laplacianKernel); +Map.addLayer(edges, { + min: 0, + max: 255 +}, 'Laplacian convolution image'); + +// Begin image sharpening example. +// Define a "fat" Gaussian kernel. +var fat = ee.Kernel.gaussian({ + radius: 3, + sigma: 3, + magnitude: -1, + units: 'meters' +}); + +// Define a "skinny" Gaussian kernel. +var skinny = ee.Kernel.gaussian({ + radius: 3, + sigma: 0.5, + units: 'meters' +}); + +// Compute a difference-of-Gaussians (DOG) kernel. +var dog = fat.add(skinny); + +// Print the kernel to see its weights. +print('DoG kernel for image sharpening', dog); + +// Add the DoG convolved image to the original image. +var sharpened = imageNAIP.add(imageNAIP.convolve(dog)); +Map.addLayer(sharpened, { + min: 0, + max: 255 +}, 'DoG edge enhancement'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Begin median example. +// Pass a median neighborhood filter using our uniformKernel. +var median = imageNAIP.reduceNeighborhood({ + reducer: ee.Reducer.median(), + kernel: uniformKernel +}); + +Map.addLayer(median, { + min: 0, + max: 255 +}, 'Median Neighborhood Filter'); + +// Mode example +// Create and display a simple two-class image. +var veg = imageNAIP.select('N').gt(200); + +// Display the two-class (binary) result. +var binaryVis = { + min: 0, + max: 1, + palette: ['black', 'green'] +}; +Map.addLayer(veg, binaryVis, 'Vegetation categorical image'); + +// Compute the mode in each 5x5 neighborhood and display the result. +var mode = veg.reduceNeighborhood({ + reducer: ee.Reducer.mode(), + kernel: uniformKernel +}); + +Map.addLayer(mode, binaryVis, 'Mode Neighborhood Filter on Vegetation categorical image'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Begin Dilation example. +// Dilate by taking the max in each 5x5 neighborhood. +var max = veg.reduceNeighborhood({ + reducer: ee.Reducer.max(), + kernel: uniformKernel +}); + +Map.addLayer(max, binaryVis, 'Dilation using max'); + +// Begin Erosion example. +// Erode by taking the min in each 5x5 neighborhood. +var min = veg.reduceNeighborhood({ + reducer: ee.Reducer.min(), + kernel: uniformKernel +}); + +Map.addLayer(min, binaryVis, 'Erosion using min'); + +// Begin Opening example. +// Perform an opening by dilating the eroded image. +var openedVeg = min.reduceNeighborhood({ + reducer: ee.Reducer.max(), + kernel: uniformKernel +}); + +Map.addLayer(openedVeg, binaryVis, 'Opened image'); + +// Begin Closing example. +// Perform a closing by eroding the dilated image. +var closedVeg = max.reduceNeighborhood({ + reducer: ee.Reducer.min(), + kernel: uniformKernel +}); + +Map.addLayer(closedVeg, binaryVis, 'Closed image'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Begin Standard Deviation example. +// Define a big neighborhood with a 7-meter radius kernel. +var bigKernel = ee.Kernel.square({ + radius: 7, + units: 'meters' +}); + +// Compute SD in a neighborhood. +var sd = imageNAIP.reduceNeighborhood({ + reducer: ee.Reducer.stdDev(), + kernel: bigKernel +}); + +Map.addLayer(sd, { + min: 0, + max: 70 +}, 'SD'); + +// Begin entropy example. +// Create an integer version of the NAIP image. +var intNAIP = imageNAIP.int(); + +// Compute entropy in a neighborhood. +var entropy = intNAIP.select('N').entropy(bigKernel); + +Map.addLayer(entropy, { + min: 1, + max: 3 +}, 'entropy'); + +// Begin GLCM example. +// Use the GLCM to compute a large number of texture measures. +var glcmTexture = intNAIP.glcmTexture(7); +print('view the glcmTexture output', glcmTexture); + +// Display the 'contrast' results for the red, green and blue bands. +var contrastVis = { + bands: ['R_contrast', 'G_contrast', 'B_contrast'], + min: 40, + max: 1000 +}; + +Map.addLayer(glcmTexture, contrastVis, 'contrast'); + +// Begin spatial statistics example using Geary's C. + +// Create a list of weights for a 9x9 kernel. +var list = [1, 1, 1, 1, 1, 1, 1, 1, 1]; +// The center of the kernel is zero. +var centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1]; +// Assemble a list of lists: the 9x9 kernel weights as a 2-D matrix. +var lists = [list, list, list, list, centerList, list, list, list, + list +]; +// Create the kernel from the weights. +// Non-zero weights represent the spatial neighborhood. +var kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, false); + +// Use the max among bands as the input. +var maxBands = imageNAIP.reduce(ee.Reducer.max()); + +// Convert the neighborhood into multiple bands. +var neighBands = maxBands.neighborhoodToBands(kernel); + +// Compute local Geary's C, a measure of spatial association. +var gearys = maxBands.subtract(neighBands).pow(2).reduce(ee.Reducer + .sum()) + .divide(Math.pow(9, 2)); + +Map.addLayer(gearys, { + min: 20, + max: 2500 +}, "Geary's C"); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32d Checkpoint.py b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32d Checkpoint.py new file mode 100644 index 0000000..f78eecd --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.2 Neighborhood based Image Transformation/F32d Checkpoint.py @@ -0,0 +1,270 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F3.2 Neighborhood-Based Image Transformation +# Checkpoint: F32d +# Authors: Karen, Andrea, David, Nick +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Create and print a uniform kernel to see its weights. +print('A uniform kernel:', ee.Kernel.square(2)) + +# Define a point of interest in Odessa, Washington, USA. +point = ee.Geometry.Point([-118.71845096212049, + 47.15743083101999]) +Map.centerObject(point) + +# Load NAIP data. +imageNAIP = ee.ImageCollection('USDA/NAIP/DOQQ') \ + .filterBounds(point) \ + .filter(ee.Filter.date('2017-01-01', '2018-12-31')) \ + .first() + +Map.centerObject(point, 17) + +TrueColor = { + 'bands': ['R', 'G', 'B'], + 'min': 0, + 'max': 255 +} +Map.addLayer(imageNAIP, TrueColor, 'True color') + +# Begin smoothing example. +# Define a square, uniform kernel. +uniformKernel = ee.Kernel.square({ + 'radius': 2, + 'units': 'meters', +}) + +# Convolve the image by convolving with the smoothing kernel. +smoothed = imageNAIP.convolve(uniformKernel) +Map.addLayer(smoothed, { + 'min': 0, + 'max': 255 +}, 'smoothed image') + +# Begin Gaussian smoothing example. +# Print a Gaussian kernel to see its weights. +print('A Gaussian kernel:', ee.Kernel.gaussian(2)) + +# Define a square Gaussian kernel: +gaussianKernel = ee.Kernel.gaussian({ + 'radius': 2, + 'units': 'meters', +}) + +# Convolve the image with the Gaussian kernel. +gaussian = imageNAIP.convolve(gaussianKernel) +Map.addLayer(gaussian, { + 'min': 0, + 'max': 255 +}, 'Gaussian smoothed image') + +# Begin edge detection example. +# For edge detection, define a Laplacian kernel. +laplacianKernel = ee.Kernel.laplacian8() + +# Print the kernel to see its weights. +print('Edge detection Laplacian kernel:', laplacianKernel) + +# Convolve the image with the Laplacian kernel. +edges = imageNAIP.convolve(laplacianKernel) +Map.addLayer(edges, { + 'min': 0, + 'max': 255 +}, 'Laplacian convolution image') + +# Begin image sharpening example. +# Define a "fat" Gaussian kernel. +fat = ee.Kernel.gaussian({ + 'radius': 3, + 'sigma': 3, + 'magnitude': -1, + 'units': 'meters' +}) + +# Define a "skinny" Gaussian kernel. +skinny = ee.Kernel.gaussian({ + 'radius': 3, + 'sigma': 0.5, + 'units': 'meters' +}) + +# Compute a difference-of-Gaussians (DOG) kernel. +dog = fat.add(skinny) + +# Print the kernel to see its weights. +print('DoG kernel for image sharpening', dog) + +# Add the DoG convolved image to the original image. +sharpened = imageNAIP.add(imageNAIP.convolve(dog)) +Map.addLayer(sharpened, { + 'min': 0, + 'max': 255 +}, 'DoG edge enhancement') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Begin median example. +# Pass a median neighborhood filter using our uniformKernel. +median = imageNAIP.reduceNeighborhood({ + 'reducer': ee.Reducer.median(), + 'kernel': uniformKernel +}) + +Map.addLayer(median, { + 'min': 0, + 'max': 255 +}, 'Median Neighborhood Filter') + +# Mode example +# Create and display a simple two-class image. +veg = imageNAIP.select('N').gt(200) + +# Display the two-class (binary) result. +binaryVis = { + 'min': 0, + 'max': 1, + 'palette': ['black', 'green'] +} +Map.addLayer(veg, binaryVis, 'Vegetation categorical image') + +# Compute the mode in each 5x5 neighborhood and display the result. +mode = veg.reduceNeighborhood({ + 'reducer': ee.Reducer.mode(), + 'kernel': uniformKernel +}) + +Map.addLayer(mode, binaryVis, 'Mode Neighborhood Filter on Vegetation categorical image') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Begin Dilation example. +# Dilate by taking the max in each 5x5 neighborhood. +max = veg.reduceNeighborhood({ + 'reducer': ee.Reducer.max(), + 'kernel': uniformKernel +}) + +Map.addLayer(max, binaryVis, 'Dilation using max') + +# Begin Erosion example. +# Erode by taking the min in each 5x5 neighborhood. +min = veg.reduceNeighborhood({ + 'reducer': ee.Reducer.min(), + 'kernel': uniformKernel +}) + +Map.addLayer(min, binaryVis, 'Erosion using min') + +# Begin Opening example. +# Perform an opening by dilating the eroded image. +openedVeg = min.reduceNeighborhood({ + 'reducer': ee.Reducer.max(), + 'kernel': uniformKernel +}) + +Map.addLayer(openedVeg, binaryVis, 'Opened image') + +# Begin Closing example. +# Perform a closing by eroding the dilated image. +closedVeg = max.reduceNeighborhood({ + 'reducer': ee.Reducer.min(), + 'kernel': uniformKernel +}) + +Map.addLayer(closedVeg, binaryVis, 'Closed image') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Begin Standard Deviation example. +# Define a big neighborhood with a 7-meter radius kernel. +bigKernel = ee.Kernel.square({ + 'radius': 7, + 'units': 'meters' +}) + +# Compute SD in a neighborhood. +sd = imageNAIP.reduceNeighborhood({ + 'reducer': ee.Reducer.stdDev(), + 'kernel': bigKernel +}) + +Map.addLayer(sd, { + 'min': 0, + 'max': 70 +}, 'SD') + +# Begin entropy example. +# Create an integer version of the NAIP image. +intNAIP = imageNAIP.int() + +# Compute entropy in a neighborhood. +entropy = intNAIP.select('N').entropy(bigKernel) + +Map.addLayer(entropy, { + 'min': 1, + 'max': 3 +}, 'entropy') + +# Begin GLCM example. +# Use the GLCM to compute a large number of texture measures. +glcmTexture = intNAIP.glcmTexture(7) +print('view the glcmTexture output', glcmTexture) + +# Display the 'contrast' results for the red, green and blue bands. +contrastVis = { + 'bands': ['R_contrast', 'G_contrast', 'B_contrast'], + 'min': 40, + 'max': 1000 +} + +Map.addLayer(glcmTexture, contrastVis, 'contrast') + +# Begin spatial statistics example using Geary's C. + +# Create a list of weights for a 9x9 kernel. +list = [1, 1, 1, 1, 1, 1, 1, 1, 1] +# The center of the kernel is zero. +centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1] +# Assemble a list of lists: the 9x9 kernel weights as a 2-D matrix. +lists = [list, list, list, list, centerList, list, list, list, + list +] +# Create the kernel from the weights. +# Non-zero weights represent the spatial neighborhood. +kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, False) + +# Use the max among bands as the input. +maxBands = imageNAIP.reduce(ee.Reducer.max()) + +# Convert the neighborhood into multiple bands. +neighBands = maxBands.neighborhoodToBands(kernel) + +# Compute local Geary's C, a measure of spatial association. +gearys = maxBands.subtract(neighBands).pow(2).reduce(ee.Reducer \ + .sum()) \ + .divide(math.pow(9, 2)) + +Map.addLayer(gearys, { + 'min': 20, + 'max': 2500 +}, "Geary's C") + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33a Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33a Checkpoint.js new file mode 100644 index 0000000..80900e3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33a Checkpoint.js @@ -0,0 +1,145 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.3 Object-Based Image Analysis +// Checkpoint: F33a +// Authors: Morgan A. Crowley, Jeffrey Cardille, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// 1.1 Unsupervised k-Means classification + +// This function does unsupervised clustering classification +// input = any image. All bands will be used for clustering. +// numberOfUnsupervisedClusters = tunable parameter for how +// many clusters to create. +var afn_Kmeans = function(input, numberOfUnsupervisedClusters, + defaultStudyArea, nativeScaleOfImage) { + + // Make a new sample set on the input. Here the sample set is + // randomly selected spatially. + var training = input.sample({ + region: defaultStudyArea, + scale: nativeScaleOfImage, + numPixels: 1000 + }); + + var cluster = ee.Clusterer.wekaKMeans( + numberOfUnsupervisedClusters) + .train(training); + + // Now apply that clusterer to the raw image that was also passed in. + var toexport = input.cluster(cluster); + + // The first item is the unsupervised classification. Name the band. + var clusterUnsup = toexport.select(0).rename( + 'unsupervisedClass'); + return (clusterUnsup); +}; + +// 1.2 Simple normalization by maxes function. +var afn_normalize_by_maxes = function(img, bandMaxes) { + return img.divide(bandMaxes); +}; + +// 1.4 Simple add mean to Band Name function +var afn_addMeanToBandName = (function(i) { + return i + '_mean'; +}); + +//////////////////////////////////////////////////////////// +// 2. Parameters to function calls +//////////////////////////////////////////////////////////// + +// 2.1. Unsupervised KMeans Classification Parameters +var numberOfUnsupervisedClusters = 4; + +//////////////////////////////////////////////////////////// +// 2.2. Visualization and Saving parameters +// For different images, you might want to change the min and max +// values to stretch. Useful for images 2 and 3, the normalized images. +var centerObjectYN = true; + +////////////////////////////////////////////////////////// +// 3. Statements +////////////////////////////////////////////////////////// + +// 3.1 Selecting Image to Classify +var whichImage = 1; // will be used to select among images +if (whichImage == 1) { + // Image 1. + // Puget Sound, WA: Forest Harvest + // (April 21, 2016) + // Harvested Parcels + // Clear Parcel Boundaries + // Sentinel 2, 10m + var whichCollection = 'COPERNICUS/S2'; + var ImageToUseID = '20160421T191704_20160421T212107_T10TDT'; + var originalImage = ee.Image(whichCollection + '/' + + ImageToUseID); + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 10; + var threeBandsToDraw = ['B4', 'B3', 'B2']; + var bandsToUse = ['B4', 'B3', 'B2']; + var bandMaxes = [1e4, 1e4, 1e4]; + var drawMin = 0; + var drawMax = 0.3; + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-123.13105468749993, 47.612974066532004], + [-123.13105468749993, 47.56214700543596], + [-123.00179367065422, 47.56214700543596], + [-123.00179367065422, 47.612974066532004] + ] + ]); + var zoomArea = ee.Geometry.Polygon( + [ + [ + [-123.13105468749993, 47.612974066532004], + [-123.13105468749993, 47.56214700543596], + [-123.00179367065422, 47.56214700543596], + [-123.00179367065422, 47.612974066532004] + ] + ], null, false); +} +Map.addLayer(originalImage.select(threeBandsToDraw), { + min: 0, + max: 2000 +}, '3.1 ' + ImageToUseID, true, 1); + + +//////////////////////////////////////////////////////////// +// 4. Image Preprocessing +//////////////////////////////////////////////////////////// +var clippedImageSelectedBands = originalImage.clip(defaultStudyArea) + .select(bandsToUse); +var ImageToUse = afn_normalize_by_maxes(clippedImageSelectedBands, + bandMaxes); + +Map.addLayer(ImageToUse.select(threeBandsToDraw), { + min: 0.028, + max: 0.12 + }, + '4.3 Post-normalization image', true, 0); + +//////////////////////////////////////////////////////////// +// 6. Execute Classifications +//////////////////////////////////////////////////////////// + +// 6.1 Per Pixel Unsupervised Classification for Comparison +var PerPixelUnsupervised = afn_Kmeans(ImageToUse, + numberOfUnsupervisedClusters, defaultStudyArea, + nativeScaleOfImage); +Map.addLayer(PerPixelUnsupervised.select('unsupervisedClass') + .randomVisualizer(), {}, '6.1 Per-Pixel Unsupervised', true, 0 +); +print('6.1b Per-Pixel Unsupervised Results:', PerPixelUnsupervised); + +//////////////////////////////////////////////////////////// +// 7. Zoom if requested +//////////////////////////////////////////////////////////// +if (centerObjectYN === true) { + Map.centerObject(zoomArea, 14); +} + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33b Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33b Checkpoint.js new file mode 100644 index 0000000..2cf8763 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33b Checkpoint.js @@ -0,0 +1,147 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.3 Object-Based Image Analysis +// Checkpoint: F33b +// Authors: Morgan A. Crowley, Jeffrey Cardille, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// 1.1 Unsupervised k-Means classification + +// This function does unsupervised clustering classification +// input = any image. All bands will be used for clustering. +// numberOfUnsupervisedClusters = tunable parameter for how +// many clusters to create. +var afn_Kmeans = function(input, numberOfUnsupervisedClusters, + defaultStudyArea, nativeScaleOfImage) { + + // Make a new sample set on the input. Here the sample set is + // randomly selected spatially. + var training = input.sample({ + region: defaultStudyArea, + scale: nativeScaleOfImage, + numPixels: 1000 + }); + + var cluster = ee.Clusterer.wekaKMeans( + numberOfUnsupervisedClusters) + .train(training); + + // Now apply that clusterer to the raw image that was also passed in. + var toexport = input.cluster(cluster); + + // The first item is the unsupervised classification. Name the band. + var clusterUnsup = toexport.select(0).rename( + 'unsupervisedClass'); + return (clusterUnsup); +}; + +// 1.2 Simple normalization by maxes function. +var afn_normalize_by_maxes = function(img, bandMaxes) { + return img.divide(bandMaxes); +}; + +// 1.4 Simple add mean to Band Name function +var afn_addMeanToBandName = (function(i) { + return i + '_mean'; +}); + +//////////////////////////////////////////////////////////// +// 2. Parameters to function calls +//////////////////////////////////////////////////////////// + +// 2.1. Unsupervised KMeans Classification Parameters +var numberOfUnsupervisedClusters = 4; + +//////////////////////////////////////////////////////////// +// 2.2. Visualization and Saving parameters +// For different images, you might want to change the min and max +// values to stretch. Useful for images 2 and 3, the normalized images. +var centerObjectYN = true; + +////////////////////////////////////////////////////////// +// 3. Statements +////////////////////////////////////////////////////////// + +// 3.1 Selecting Image to Classify +var whichImage = 1; // will be used to select among images +if (whichImage == 1) { + // Image 1. + // Puget Sound, WA: Forest Harvest + // (April 21, 2016) + // Harvested Parcels + // Clear Parcel Boundaries + // Sentinel 2, 10m + var whichCollection = 'COPERNICUS/S2'; + var ImageToUseID = '20160421T191704_20160421T212107_T10TDT'; + var originalImage = ee.Image(whichCollection + '/' + + ImageToUseID); + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 10; + // var threeBandsToDraw = ['B4', 'B3', 'B2']; + var threeBandsToDraw = ['B8', 'B11', 'B12']; + // var bandsToUse = ['B4', 'B3', 'B2']; + var bandsToUse = ['B8', 'B11', 'B12']; + var bandMaxes = [1e4, 1e4, 1e4]; + var drawMin = 0; + var drawMax = 0.3; + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-123.13105468749993, 47.612974066532004], + [-123.13105468749993, 47.56214700543596], + [-123.00179367065422, 47.56214700543596], + [-123.00179367065422, 47.612974066532004] + ] + ]); + var zoomArea = ee.Geometry.Polygon( + [ + [ + [-123.13105468749993, 47.612974066532004], + [-123.13105468749993, 47.56214700543596], + [-123.00179367065422, 47.56214700543596], + [-123.00179367065422, 47.612974066532004] + ] + ], null, false); +} +Map.addLayer(originalImage.select(threeBandsToDraw), { + min: 0, + max: 2000 +}, '3.1 ' + ImageToUseID, true, 1); + + +//////////////////////////////////////////////////////////// +// 4. Image Preprocessing +//////////////////////////////////////////////////////////// +var clippedImageSelectedBands = originalImage.clip(defaultStudyArea) + .select(bandsToUse); +var ImageToUse = afn_normalize_by_maxes(clippedImageSelectedBands, + bandMaxes); + +Map.addLayer(ImageToUse.select(threeBandsToDraw), { + min: 0.028, + max: 0.12 + }, + '4.3 Post-normalization image', true, 0); + +//////////////////////////////////////////////////////////// +// 6. Execute Classifications +//////////////////////////////////////////////////////////// + +// 6.1 Per Pixel Unsupervised Classification for Comparison +var PerPixelUnsupervised = afn_Kmeans(ImageToUse, + numberOfUnsupervisedClusters, defaultStudyArea, + nativeScaleOfImage); +Map.addLayer(PerPixelUnsupervised.select('unsupervisedClass') + .randomVisualizer(), {}, '6.1 Per-Pixel Unsupervised', true, 0 +); +print('6.1b Per-Pixel Unsupervised Results:', PerPixelUnsupervised); + +//////////////////////////////////////////////////////////// +// 7. Zoom if requested +//////////////////////////////////////////////////////////// +if (centerObjectYN === true) { + Map.centerObject(zoomArea, 14); +} + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33c Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33c Checkpoint.js new file mode 100644 index 0000000..7951671 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33c Checkpoint.js @@ -0,0 +1,218 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.3 Object-Based Image Analysis +// Checkpoint: F33c +// Authors: Morgan A. Crowley, Jeffrey Cardille, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// 1.1 Unsupervised k-Means classification + +// This function does unsupervised clustering classification +// input = any image. All bands will be used for clustering. +// numberOfUnsupervisedClusters = tunable parameter for how +// many clusters to create. +var afn_Kmeans = function(input, numberOfUnsupervisedClusters, + defaultStudyArea, nativeScaleOfImage) { + + // Make a new sample set on the input. Here the sample set is + // randomly selected spatially. + var training = input.sample({ + region: defaultStudyArea, + scale: nativeScaleOfImage, + numPixels: 1000 + }); + + var cluster = ee.Clusterer.wekaKMeans( + numberOfUnsupervisedClusters) + .train(training); + + // Now apply that clusterer to the raw image that was also passed in. + var toexport = input.cluster(cluster); + + // The first item is the unsupervised classification. Name the band. + var clusterUnsup = toexport.select(0).rename( + 'unsupervisedClass'); + return (clusterUnsup); +}; + +// 1.2 Simple normalization by maxes function. +var afn_normalize_by_maxes = function(img, bandMaxes) { + return img.divide(bandMaxes); +}; + +// 1.3 Seed Creation and SNIC segmentation Function +var afn_SNIC = function(imageOriginal, SuperPixelSize, Compactness, + Connectivity, NeighborhoodSize, SeedShape) { + var theSeeds = ee.Algorithms.Image.Segmentation.seedGrid( + SuperPixelSize, SeedShape); + var snic2 = ee.Algorithms.Image.Segmentation.SNIC({ + image: imageOriginal, + size: SuperPixelSize, + compactness: Compactness, + connectivity: Connectivity, + neighborhoodSize: NeighborhoodSize, + seeds: theSeeds + }); + var theStack = snic2.addBands(theSeeds); + return (theStack); +}; + +// 1.4 Simple add mean to Band Name function +var afn_addMeanToBandName = (function(i) { + return i + '_mean'; +}); + +//////////////////////////////////////////////////////////// +// 2. Parameters to function calls +//////////////////////////////////////////////////////////// + +// 2.1. Unsupervised KMeans Classification Parameters +var numberOfUnsupervisedClusters = 4; + +//////////////////////////////////////////////////////////// +// 2.2. Visualization and Saving parameters +// For different images, you might want to change the min and max +// values to stretch. Useful for images 2 and 3, the normalized images. +var centerObjectYN = true; + +// 2.3 Object-growing parameters to change +// Adjustable Superpixel Seed and SNIC segmentation Parameters: +// The superpixel seed location spacing, in pixels. +var SNIC_SuperPixelSize = 16; +// Larger values cause clusters to be more compact (square/hexagonal). +// Setting this to 0 disables spatial distance weighting. +var SNIC_Compactness = 0; +// Connectivity. Either 4 or 8. +var SNIC_Connectivity = 4; +// Either 'square' or 'hex'. +var SNIC_SeedShape = 'square'; + +// 2.4 Parameters that can stay unchanged +// Tile neighborhood size (to avoid tile boundary artifacts). Defaults to 2 * size. +var SNIC_NeighborhoodSize = 2 * SNIC_SuperPixelSize; + +////////////////////////////////////////////////////////// +// 3. Statements +////////////////////////////////////////////////////////// + +// 3.1 Selecting Image to Classify +var whichImage = 1; // will be used to select among images +if (whichImage == 1) { + // Image 1. + // Puget Sound, WA: Forest Harvest + // (April 21, 2016) + // Harvested Parcels + // Clear Parcel Boundaries + // Sentinel 2, 10m + var whichCollection = 'COPERNICUS/S2'; + var ImageToUseID = '20160421T191704_20160421T212107_T10TDT'; + var originalImage = ee.Image(whichCollection + '/' + + ImageToUseID); + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 10; + // var threeBandsToDraw = ['B4', 'B3', 'B2']; + var threeBandsToDraw = ['B8', 'B11', 'B12']; + // var bandsToUse = ['B4', 'B3', 'B2']; + var bandsToUse = ['B8', 'B11', 'B12']; + var bandMaxes = [1e4, 1e4, 1e4]; + var drawMin = 0; + var drawMax = 0.3; + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-123.13105468749993, 47.612974066532004], + [-123.13105468749993, 47.56214700543596], + [-123.00179367065422, 47.56214700543596], + [-123.00179367065422, 47.612974066532004] + ] + ]); + var zoomArea = ee.Geometry.Polygon( + [ + [ + [-123.13105468749993, 47.612974066532004], + [-123.13105468749993, 47.56214700543596], + [-123.00179367065422, 47.56214700543596], + [-123.00179367065422, 47.612974066532004] + ] + ], null, false); +} +Map.addLayer(originalImage.select(threeBandsToDraw), { + min: 0, + max: 2000 +}, '3.1 ' + ImageToUseID, true, 1); + + +//////////////////////////////////////////////////////////// +// 4. Image Preprocessing +//////////////////////////////////////////////////////////// +var clippedImageSelectedBands = originalImage.clip(defaultStudyArea) + .select(bandsToUse); +var ImageToUse = afn_normalize_by_maxes(clippedImageSelectedBands, + bandMaxes); + +Map.addLayer(ImageToUse.select(threeBandsToDraw), { + min: 0.028, + max: 0.12 + }, + '4.3 Pre-normalization image', true, 0); + +//////////////////////////////////////////////////////////// +// 5. SNIC Clustering +//////////////////////////////////////////////////////////// + +// This function returns a multi-banded image that has had SNIC +// applied to it. It automatically determine the new names +// of the bands that will be returned from the segmentation. +print('5.1 Execute SNIC'); +var SNIC_MultiBandedResults = afn_SNIC( + ImageToUse, + SNIC_SuperPixelSize, + SNIC_Compactness, + SNIC_Connectivity, + SNIC_NeighborhoodSize, + SNIC_SeedShape +); + +var SNIC_MultiBandedResults = SNIC_MultiBandedResults + .reproject('EPSG:3857', null, nativeScaleOfImage); +print('5.2 SNIC Multi-Banded Results', SNIC_MultiBandedResults); + +Map.addLayer(SNIC_MultiBandedResults.select('clusters') + .randomVisualizer(), {}, '5.3 SNIC Segment Clusters', true, 1); + +var theSeeds = SNIC_MultiBandedResults.select('seeds'); +Map.addLayer(theSeeds, { + palette: 'red' +}, '5.4 Seed points of clusters', true, 1); + +var bandMeansToDraw = threeBandsToDraw.map(afn_addMeanToBandName); +print('5.5 band means to draw', bandMeansToDraw); +var clusterMeans = SNIC_MultiBandedResults.select(bandMeansToDraw); +print('5.6 Cluster Means by Band', clusterMeans); +Map.addLayer(clusterMeans, { + min: drawMin, + max: drawMax +}, '5.7 Image repainted by segments', true, 0); + +//////////////////////////////////////////////////////////// +// 6. Execute Classifications +//////////////////////////////////////////////////////////// + +// 6.1 Per Pixel Unsupervised Classification for Comparison +var PerPixelUnsupervised = afn_Kmeans(ImageToUse, + numberOfUnsupervisedClusters, defaultStudyArea, + nativeScaleOfImage); +Map.addLayer(PerPixelUnsupervised.select('unsupervisedClass') + .randomVisualizer(), {}, '6.1 Per-Pixel Unsupervised', true, 0 +); +print('6.1b Per-Pixel Unsupervised Results:', PerPixelUnsupervised); + +//////////////////////////////////////////////////////////// +// 7. Zoom if requested +//////////////////////////////////////////////////////////// +if (centerObjectYN === true) { + Map.centerObject(zoomArea, 14); +} + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33d Checkpoint.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33d Checkpoint.js new file mode 100644 index 0000000..20de981 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33d Checkpoint.js @@ -0,0 +1,232 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.3 Object-Based Image Analysis +// Checkpoint: F33d +// Authors: Morgan A. Crowley, Jeffrey Cardille, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// 1.1 Unsupervised k-Means classification + +// This function does unsupervised clustering classification +// input = any image. All bands will be used for clustering. +// numberOfUnsupervisedClusters = tunable parameter for how +// many clusters to create. +var afn_Kmeans = function(input, numberOfUnsupervisedClusters, + defaultStudyArea, nativeScaleOfImage) { + + // Make a new sample set on the input. Here the sample set is + // randomly selected spatially. + var training = input.sample({ + region: defaultStudyArea, + scale: nativeScaleOfImage, + numPixels: 1000 + }); + + var cluster = ee.Clusterer.wekaKMeans( + numberOfUnsupervisedClusters) + .train(training); + + // Now apply that clusterer to the raw image that was also passed in. + var toexport = input.cluster(cluster); + + // The first item is the unsupervised classification. Name the band. + var clusterUnsup = toexport.select(0).rename( + 'unsupervisedClass'); + return (clusterUnsup); +}; + +// 1.2 Simple normalization by maxes function. +var afn_normalize_by_maxes = function(img, bandMaxes) { + return img.divide(bandMaxes); +}; + +// 1.3 Seed Creation and SNIC segmentation Function +var afn_SNIC = function(imageOriginal, SuperPixelSize, Compactness, + Connectivity, NeighborhoodSize, SeedShape) { + var theSeeds = ee.Algorithms.Image.Segmentation.seedGrid( + SuperPixelSize, SeedShape); + var snic2 = ee.Algorithms.Image.Segmentation.SNIC({ + image: imageOriginal, + size: SuperPixelSize, + compactness: Compactness, + connectivity: Connectivity, + neighborhoodSize: NeighborhoodSize, + seeds: theSeeds + }); + var theStack = snic2.addBands(theSeeds); + return (theStack); +}; + +// 1.4 Simple add mean to Band Name function +var afn_addMeanToBandName = (function(i) { + return i + '_mean'; +}); + +//////////////////////////////////////////////////////////// +// 2. Parameters to function calls +//////////////////////////////////////////////////////////// + +// 2.1. Unsupervised KMeans Classification Parameters +var numberOfUnsupervisedClusters = 4; + +//////////////////////////////////////////////////////////// +// 2.2. Visualization and Saving parameters +// For different images, you might want to change the min and max +// values to stretch. Useful for images 2 and 3, the normalized images. +var centerObjectYN = true; + +// 2.3 Object-growing parameters to change +// Adjustable Superpixel Seed and SNIC segmentation Parameters: +// The superpixel seed location spacing, in pixels. +var SNIC_SuperPixelSize = 16; +// Larger values cause clusters to be more compact (square/hexagonal). +// Setting this to 0 disables spatial distance weighting. +var SNIC_Compactness = 0; +// Connectivity. Either 4 or 8. +var SNIC_Connectivity = 4; +// Either 'square' or 'hex'. +var SNIC_SeedShape = 'square'; + +// 2.4 Parameters that can stay unchanged +// Tile neighborhood size (to avoid tile boundary artifacts). Defaults to 2 * size. +var SNIC_NeighborhoodSize = 2 * SNIC_SuperPixelSize; + +////////////////////////////////////////////////////////// +// 3. Statements +////////////////////////////////////////////////////////// + +// 3.1 Selecting Image to Classify +var whichImage = 1; // will be used to select among images +if (whichImage == 1) { + // Image 1. + // Puget Sound, WA: Forest Harvest + // (April 21, 2016) + // Harvested Parcels + // Clear Parcel Boundaries + // Sentinel 2, 10m + var whichCollection = 'COPERNICUS/S2'; + var ImageToUseID = '20160421T191704_20160421T212107_T10TDT'; + var originalImage = ee.Image(whichCollection + '/' + + ImageToUseID); + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 10; + // var threeBandsToDraw = ['B4', 'B3', 'B2']; + var threeBandsToDraw = ['B8', 'B11', 'B12']; + // var bandsToUse = ['B4', 'B3', 'B2']; + var bandsToUse = ['B8', 'B11', 'B12']; + var bandMaxes = [1e4, 1e4, 1e4]; + var drawMin = 0; + var drawMax = 0.3; + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-123.13105468749993, 47.612974066532004], + [-123.13105468749993, 47.56214700543596], + [-123.00179367065422, 47.56214700543596], + [-123.00179367065422, 47.612974066532004] + ] + ]); + var zoomArea = ee.Geometry.Polygon( + [ + [ + [-123.13105468749993, 47.612974066532004], + [-123.13105468749993, 47.56214700543596], + [-123.00179367065422, 47.56214700543596], + [-123.00179367065422, 47.612974066532004] + ] + ], null, false); +} +Map.addLayer(originalImage.select(threeBandsToDraw), { + min: 0, + max: 2000 +}, '3.1 ' + ImageToUseID, true, 1); + + +//////////////////////////////////////////////////////////// +// 4. Image Preprocessing +//////////////////////////////////////////////////////////// +var clippedImageSelectedBands = originalImage.clip(defaultStudyArea) + .select(bandsToUse); +var ImageToUse = afn_normalize_by_maxes(clippedImageSelectedBands, + bandMaxes); + +Map.addLayer(ImageToUse.select(threeBandsToDraw), { + min: 0.028, + max: 0.12 + }, + '4.3 Pre-normalization image', true, 0); + +//////////////////////////////////////////////////////////// +// 5. SNIC Clustering +//////////////////////////////////////////////////////////// + +// This function returns a multi-banded image that has had SNIC +// applied to it. It automatically determine the new names +// of the bands that will be returned from the segmentation. +print('5.1 Execute SNIC'); +var SNIC_MultiBandedResults = afn_SNIC( + ImageToUse, + SNIC_SuperPixelSize, + SNIC_Compactness, + SNIC_Connectivity, + SNIC_NeighborhoodSize, + SNIC_SeedShape +); + +var SNIC_MultiBandedResults = SNIC_MultiBandedResults + .reproject('EPSG:3857', null, nativeScaleOfImage); +print('5.2 SNIC Multi-Banded Results', SNIC_MultiBandedResults); + +Map.addLayer(SNIC_MultiBandedResults.select('clusters') + .randomVisualizer(), {}, '5.3 SNIC Segment Clusters', true, 1); + +var theSeeds = SNIC_MultiBandedResults.select('seeds'); +Map.addLayer(theSeeds, { + palette: 'red' +}, '5.4 Seed points of clusters', true, 1); + +var bandMeansToDraw = threeBandsToDraw.map(afn_addMeanToBandName); +print('5.5 band means to draw', bandMeansToDraw); +var clusterMeans = SNIC_MultiBandedResults.select(bandMeansToDraw); +print('5.6 Cluster Means by Band', clusterMeans); +Map.addLayer(clusterMeans, { + min: drawMin, + max: drawMax +}, '5.7 Image repainted by segments', true, 0); + + + +//////////////////////////////////////////////////////////// +// 6. Execute Classifications +//////////////////////////////////////////////////////////// + +// 6.1 Per Pixel Unsupervised Classification for Comparison +var PerPixelUnsupervised = afn_Kmeans(ImageToUse, + numberOfUnsupervisedClusters, defaultStudyArea, + nativeScaleOfImage); +Map.addLayer(PerPixelUnsupervised.select('unsupervisedClass') + .randomVisualizer(), {}, '6.1 Per-Pixel Unsupervised', true, 0 +); +print('6.1b Per-Pixel Unsupervised Results:', PerPixelUnsupervised); + +// 6.2 SNIC Unsupervised Classification for Comparison +var bandMeansNames = bandsToUse.map(afn_addMeanToBandName); +print('6.2 band mean names returned by segmentation', bandMeansNames); +var meanSegments = SNIC_MultiBandedResults.select(bandMeansNames); +var SegmentUnsupervised = afn_Kmeans(meanSegments, + numberOfUnsupervisedClusters, defaultStudyArea, + nativeScaleOfImage); +Map.addLayer(SegmentUnsupervised.randomVisualizer(), {}, + '6.3 SNIC Clusters Unsupervised', true, 0); +print('6.3b Per-Segment Unsupervised Results:', SegmentUnsupervised); +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// 7. Zoom if requested +//////////////////////////////////////////////////////////// +if (centerObjectYN === true) { + Map.centerObject(zoomArea, 14); +} + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33s1 Additional Images.js b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33s1 Additional Images.js new file mode 100644 index 0000000..93e01f9 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F3 - Advanced Image Processing/F3.3 Object-based Image Analysis/F33s1 Additional Images.js @@ -0,0 +1,427 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F3.3 Object-Based Image Analysis +// Checkpoint: F33s1 - Supplemental +// Authors: Morgan A. Crowley, Jeffrey Cardille, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//////////////////////////////////////////////////////////// +// The purpose of this script is to compare segmented and +// per-pixel unsupervised classifications for the same image. +// In particular, this script uses SNIC segmentation to grow +// superpixels, basing the segmentation on multiple bands. +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// 0. More information about SNIC segmentation +//////////////////////////////////////////////////////////// + +// SNIC stands for 'Simple Non-Iterative Clustering.' +// Segmentation algorithms like SNIC create pixel clusters +// using imagery information such as texture, color or pixel +// values, shape, and size. SNIC is a bottom-up, seed-based +// segmentation approach that groups neighboring pixels together +// into clusters based on input data and parameters such as +// compactness, connectivity, and neighborhood size. + +//////////////////////////////////////////////////////////// +// 1. Functions to be used in this script. +//////////////////////////////////////////////////////////// + +// 1.1 Unsupervised k-Means classification + +// This function does unsupervised clustering classification . +// input = any image. All bands will be used for clustering. +// numberOfUnsupervisedClusters = tuneable parameter for how +// many clusters to create. +var afn_Kmeans = function(input, + numberOfUnsupervisedClusters, + defaultStudyArea, + nativeScaleOfImage) { + + // Make a new sample set on the input. Here the sample set is + // randomly selected spatially. + var training = input.sample({ + region: defaultStudyArea, + scale: nativeScaleOfImage, + numPixels: 1000 + }); + + var cluster = ee.Clusterer.wekaKMeans( + numberOfUnsupervisedClusters) + .train(training); + + // Now apply that clusterer to the raw image that was also passed in. + var toexport = input.cluster(cluster); + + // The first item is the unsupervised classification. Name the band. + return toexport.select(0).rename('unsupervisedClass'); +}; + +// 1.2 Simple normalization by maxes function. +var afn_normalize_by_maxes = function(img, bandMaxes) { + return img.divide(bandMaxes); +}; + +// 1.3 Seed Creation and SNIC segmentation Function +var afn_SNIC = function(imageOriginal, SuperPixelSize, Compactness, + Connectivity, NeighborhoodSize, SeedShape) { + print('** 1.3a Begin Seed Creation **'); + var theSeeds = ee.Algorithms.Image.Segmentation.seedGrid( + SuperPixelSize, SeedShape); + + print('** 1.3b Begin SNIC segmentation **'); + var snic2 = ee.Algorithms.Image.Segmentation.SNIC({ + image: imageOriginal, + size: SuperPixelSize, + compactness: Compactness, + connectivity: Connectivity, + neighborhoodSize: NeighborhoodSize, + seeds: theSeeds + }); + + var theStack = snic2.addBands(theSeeds); + + print( + '** 1.3c Finished Seed Creation and SNIC segmentation **' + ); + return (theStack); +}; + +// 1.4 Simple add mean to Band Name function +var afn_addMeanToBandName = (function(i) { + return i + '_mean'; +}); + +//////////////////////////////////////////////////////////// +// 2. Parameters to function calls +//////////////////////////////////////////////////////////// + +// 2.1. Unsupervised KMeans Classification Parameters +var numberOfUnsupervisedClusters = 4; + +// 2.2. Visualization and Saving parameters +// For different images, you might want to change the min and max +// values to stretch. Useful for images 2 and 3, the normalized images. +var centerObjectYN = true; + +// 2.3 Object-growing parameters to change +// Adjustable Superpixel Seed and SNIC segmentation Parameters: +// The superpixel seed location spacing, in pixels. +var SNIC_SuperPixelSize = 16; +// Larger values cause clusters to be more compact (square/hexagonal). +// Setting this to 0 disables spatial distance weighting. +var SNIC_Compactness = 0; +// Connectivity. Either 4 or 8. +var SNIC_Connectivity = 4; +// Either 'square' or 'hex'. +var SNIC_SeedShape = 'square'; + +// 2.4 Parameters that can stay the same. +// Tile neighborhood size (to avoid tile boundary artifacts). +// Defaults to 2 * size. +var SNIC_NeighborhoodSize = 2 * SNIC_SuperPixelSize; + +////////////////////////////////////////////////////////// +// 3. Statements +////////////////////////////////////////////////////////// + +// 3.1 Selecting an Image to Classify + +// NOTE: If you're unsure which bands to use for your image, check out: +// Sentinel-2: https://forum.step.esa.int/t/list-of-band-combinations-for-sentinel-2/1156 +// Landsat 8: https://www.esri.com/arcgis-blog/products/product/imagery/band-combinations-for-landsat-8/ +// Landsat 5 and 7: http://web.pdx.edu/~emch/ip1/bandcombinations.html + +var whichImage = 6; + +if (whichImage == 1) { + // Image 1 + // Puget Sound, WA: Forest Harvest + // (April 21, 2016) + // Harvested Parcels + // Clear Parcel Boundaries + // Sentinel 2, 10m + var whichCollection = 'COPERNICUS/S2'; + var ImageToUseID = '20160421T191704_20160421T212107_T10TDT'; + var originalImage = ee.Image(whichCollection + '/' + + ImageToUseID); + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 10; + var threeBandsToDraw = ['B4', 'B3', 'B2']; + var bandsToUse = ['B4', 'B3', 'B2']; + var bandMaxes = [1e4, 1e4, 1e4]; + var drawMin = 0; + var drawMax = 0.3; + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-123.35, 47.7], + [-123.35, 47.5], + [-123, 47.5], + [-123, 47.7] + ] + ]); + var zoomBox1 = + ee.Geometry.Polygon( + [ + [ + [-123.13105468749993, 47.612974066532004], + [-123.13105468749993, 47.56214700543596], + [-123.00179367065422, 47.56214700543596], + [-123.00179367065422, 47.612974066532004] + ] + ], null, false); + var zoomArea = zoomBox1; + Map.addLayer(originalImage.select(threeBandsToDraw), { + min: 0, + max: 2000 + }, '3.1 ' + ImageToUseID, + true, + 1); +} + +if (whichImage == 2) { + ////Image 4.2 + //Puget Sound, WA: Forest Harvest + //(August 12, 1973) + //Harvested Parcels + //Clear Parcel Boundaries + //Landsat 1, 80m + var originalImage = ee.Image('LANDSAT/LM1/LM10510271973224AAA05'); + var ImageToUseID = 'LM10510271973224AAA05'; + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 80; + var bandsToUse = ['B4', 'B5', 'B6', 'B7']; + var bandMaxes = [150, 150, 150, 150]; + var threeBandsToDraw = ['B6', 'B5', 'B4'] + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-123.39225769042969, 47.74178608664663], + [-123.3929443359375, 47.515964043627555], + [-122.90542602539062, 47.51318147039422], + [-122.904052734375, 47.741786086646655] + ] + ]); + var zoomArea = defaultStudyArea; + Map.addLayer(originalImage, { + min: 0, + max: 150 + }, '3.2 ' + ImageToUseID); + var drawMax = 1; +} + +if (whichImage == 3) { + ////Image 4.3 + //'Cape Cod, MA: + //Shoreline Changes + //(June 12, 1984) + //Earthshots' + //L5, 30m + var originalImage = ee.Image( + 'LANDSAT/LT05/C01/T1/LT05_011031_19840612'); + var ImageToUseID = 'LT05_011031_19840612'; + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 30; + var bandsToUse = ['B4', 'B3', 'B2']; + var bandMaxes = [255, 255, 255]; + var threeBandsToDraw = ['B4', 'B3', 'B2']; + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-70.521240234375, 41.5538109921796], + [-69.840087890625, 41.545589036668105], + [-69.85107421875, 42.18375873465217], + [-70.5047607421875, 42.18375873465217] + ] + ]); + var zoomArea = defaultStudyArea; + Map.addLayer(originalImage.select(threeBandsToDraw), { + min: 0, + max: 150 + }, '3.3 ' + + ImageToUseID); + var drawMax = 1; +} + +if (whichImage == 4) { + ////Image 4.4 + //'Cape Cod, MA: + //Shoreline Changes + //(Sep 15, 2015) + //Earthshots' + //L8, 30m + var originalImage = ee.Image( + 'LANDSAT/LC08/C01/T1_SR/LC08_011031_20150906'); + var ImageToUseID = 'LC08_011031_20150906'; + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 30; + var bandsToUse = ['B5', 'B4', 'B3']; + var bandMaxes = [1e4, 1e4, 1e4]; + var threeBandsToDraw = ['B5', 'B4', 'B3']; + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-70.521240234375, 41.5538109921796], + [-69.840087890625, 41.545589036668105], + [-69.85107421875, 42.18375873465217], + [-70.5047607421875, 42.18375873465217] + ] + ]); + var zoomArea = defaultStudyArea; + Map.addLayer(originalImage.select(threeBandsToDraw).clip( + defaultStudyArea),{ + min: 0, + max: 1000 + } , '3.4 ' + ImageToUseID); + var drawMax = 1; +} + +if (whichImage == 5) { + ////Image 4.5 + //'Hanceville, BC: + //Fire Disturbance + //(Sept. 28, 2017)' + //Sentinel-2, 20m + var originalImage = ee.Image( + 'COPERNICUS/S2/20170928T191139_20170928T191139_T10UEC'); + var ImageToUseID = '20170928T191139_20170928T191139_T10UEC'; + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 20; + var bandsToUse = ['B8', 'B11', 'B12']; + var bandMaxes = [1e4, 1e4, 1e4]; + var threeBandsToDraw = ['B8', 'B11', 'B12']; + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-122.9754638671875, 51.77803705914518], + [-121.46484375, 51.529251355189906], + [-121.4483642578125, 51.70660846336452], + [-121.431884765625, 52.32526831457076], + [-122.9864501953125, 52.34540753654635] + ] + ]); + var zoomArea = defaultStudyArea; + Map.addLayer(originalImage.select(threeBandsToDraw), {min:0, max:2000}, '3.5 ' + + ImageToUseID); + var drawMax = 1; +} + +if (whichImage == 6) { + ////Image 4.6 + //'Hanceville, BC: + //Fire Disturbance + //(Oct 3, 2017)' + //Modis, 250m + var originalImage = ee.Image('MODIS/006/MOD09GQ/2017_10_03'); + var ImageToUseID = 'MOD09GQ2017_10_03'; + print(ImageToUseID, originalImage); + var nativeScaleOfImage = 250; + var bandsToUse = ['sur_refl_b01', 'sur_refl_b02']; + var bandMaxes = [1e4, 1e4]; + var threeBandsToDraw = ['sur_refl_b02','sur_refl_b01']; + var defaultStudyArea = ee.Geometry.Polygon( + [ + [ + [-122.9754638671875, 51.77803705914518], + [-121.46484375, 51.529251355189906], + [-121.4483642578125, 51.70660846336452], + [-121.431884765625, 52.32526831457076], + [-122.9864501953125, 52.34540753654635] + ] + ]); + var zoomArea = defaultStudyArea; + Map.addLayer(originalImage.select(threeBandsToDraw), {min:-100,max:5000}, '3.6 ' + + ImageToUseID); + var drawMax = 1; +} + +//////////////////////////////////////////////////////////// +// 4. Image Preprocessing +//////////////////////////////////////////////////////////// + +//4.1 You can use the geometry of image to clip by using the following line: +//var defaultStudyArea = originalImage.geometry(); + +var clippedImageSelectedBands = originalImage.clip(defaultStudyArea) + .select(bandsToUse); + +var ImageToUse = afn_normalize_by_maxes(clippedImageSelectedBands, + bandMaxes); + +//////////////////////////////////////////////////////////// +// 5. SNIC Clustering +//////////////////////////////////////////////////////////// + +// This function returns a multi-banded image that has had +// SNIC applied to it. It automatically determines the new names +// of the bands that will be returned from the segmentation. + +print('5.1 Execute SNIC'); +var SNIC_MultiBandedResults = afn_SNIC( + ImageToUse, + SNIC_SuperPixelSize, + SNIC_Compactness, + SNIC_Connectivity, + SNIC_NeighborhoodSize, + SNIC_SeedShape +); + +var SNIC_MultiBandedResults = SNIC_MultiBandedResults + .reproject('EPSG:3857', null, nativeScaleOfImage); +print('5.2 SNIC Multi-Banded Results', SNIC_MultiBandedResults); + +Map.addLayer(SNIC_MultiBandedResults.select('clusters') + .randomVisualizer(), {}, '5.3 SNIC Segment Clusters', true, 1); + +var theSeeds = SNIC_MultiBandedResults.select('seeds'); +Map.addLayer(theSeeds, { + palette: 'red' +}, '5.4 Seed points of clusters', true, 1); + +var bandMeansToDraw = threeBandsToDraw.map(afn_addMeanToBandName); +print('5.5 band means to draw', bandMeansToDraw); +var clusterMeans = SNIC_MultiBandedResults.select(bandMeansToDraw); +print('5.6 Cluster Means by Band', clusterMeans); +Map.addLayer(clusterMeans, { + min: drawMin, + max: drawMax +}, '5.7 Image repainted by segments', true, 0); + +//////////////////////////////////////////////////////////// +// 6. Execute Classifications +//////////////////////////////////////////////////////////// + +// 6.1 Per Pixel Unsupervised Classification for Comparison + +var PerPixelUnsupervised = afn_Kmeans(ImageToUse, + numberOfUnsupervisedClusters, defaultStudyArea, + nativeScaleOfImage); +Map.addLayer(PerPixelUnsupervised.select('unsupervisedClass') + .randomVisualizer(), {}, '6.1 Per-Pixel Unsupervised', true, 0 +); +print('6.1b Per-Pixel Unsupervised Results:', PerPixelUnsupervised); + +// 6.2 SNIC Unsupervised Classification for Comparison + +var bandMeansNames = bandsToUse.map(afn_addMeanToBandName); +print('6.2 band mean names returned by segmentation', bandMeansNames); +var meanSegments = SNIC_MultiBandedResults.select(bandMeansNames); +var SegmentUnsupervised = afn_Kmeans(meanSegments, + numberOfUnsupervisedClusters, defaultStudyArea, + nativeScaleOfImage); +Map.addLayer(SegmentUnsupervised.randomVisualizer(), {}, + '6.3 SNIC Clusters Unsupervised', true, 0); +print('6.3b Per-Segment Unsupervised Results:', SegmentUnsupervised); + +//////////////////////////////////////////////////////////// +// 7. Zoom if requested +//////////////////////////////////////////////////////////// + +if (centerObjectYN === true) { + Map.centerObject(zoomArea, 14); +} + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40a Checkpoint.ipynb new file mode 100644 index 0000000..8035f4a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40a Checkpoint.ipynb @@ -0,0 +1,140 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.0 Filter, Map, Reduce\n", + "# Checkpoint: F40a\n", + "# Author: Jeff Cardille\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2')\n", + "# How many Tier 1 Landsat 5 images have ever been collected?\n", + "print(\"All images ever: \", imgCol.size()); # A very large number\n", + "\n", + "# How many images were collected in the 2000s?\n", + "startDate = '2000-01-01'\n", + "endDate = '2010-01-01'\n", + "\n", + "imgColfilteredByDate = imgCol.filterDate(startDate, endDate)\n", + "print(\"All images 2000-2010: \", imgColfilteredByDate.size())\n", + "# A smaller (but still large) number\n", + "\n", + "ShanghaiImage = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606')\n", + "Map.centerObject(ShanghaiImage, 9)\n", + "\n", + "imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map \\\n", + " .getCenter())\n", + "print(\"All images here, 2000-2010: \", imgColfilteredByDateHere \\\n", + ".size()); \n", + "\n", + "L5FilteredLowCloudImages = imgColfilteredByDateHere \\\n", + " .filterMetadata('CLOUD_COVER', 'less_than', 50)\n", + "print(\"Less than 50% clouds in this area, 2000-2010\",\n", + " L5FilteredLowCloudImages.size()); # A smaller number\n", + "\n", + "chainedFilteredSet = imgCol.filterDate(startDate, endDate) \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterMetadata('CLOUD_COVER', 'less_than', 50)\n", + "print('Chained: Less than 50% clouds in this area, 2000-2010',\n", + " chainedFilteredSet.size())\n", + "\n", + "efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) \\\n", + " .filterDate(startDate, endDate) \\\n", + " .filterMetadata('CLOUD_COVER', 'less_than', 50)\n", + "print('Efficient filtering: Less than 50% clouds in this area, 2000-2010',\n", + " efficientFilteredSet.size())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40a Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40a Checkpoint.js new file mode 100644 index 0000000..ce5d9c8 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40a Checkpoint.js @@ -0,0 +1,47 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.0 Filter, Map, Reduce +// Checkpoint: F40a +// Author: Jeff Cardille +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2'); +// How many Tier 1 Landsat 5 images have ever been collected? +print("All images ever: ", imgCol.size()); // A very large number + +// How many images were collected in the 2000s? +var startDate = '2000-01-01'; +var endDate = '2010-01-01'; + +var imgColfilteredByDate = imgCol.filterDate(startDate, endDate); +print("All images 2000-2010: ", imgColfilteredByDate.size()); +// A smaller (but still large) number + +var ShanghaiImage = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606'); +Map.centerObject(ShanghaiImage, 9); + +var imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map + .getCenter()); +print("All images here, 2000-2010: ", imgColfilteredByDateHere +.size()); // A smaller number + +var L5FilteredLowCloudImages = imgColfilteredByDateHere + .filterMetadata('CLOUD_COVER', 'less_than', 50); +print("Less than 50% clouds in this area, 2000-2010", + L5FilteredLowCloudImages.size()); // A smaller number + +var chainedFilteredSet = imgCol.filterDate(startDate, endDate) + .filterBounds(Map.getCenter()) + .filterMetadata('CLOUD_COVER', 'less_than', 50); +print('Chained: Less than 50% clouds in this area, 2000-2010', + chainedFilteredSet.size()); + +var efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) + .filterDate(startDate, endDate) + .filterMetadata('CLOUD_COVER', 'less_than', 50); +print('Efficient filtering: Less than 50% clouds in this area, 2000-2010', + efficientFilteredSet.size()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40a Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40a Checkpoint.py new file mode 100644 index 0000000..50fe9ef --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40a Checkpoint.py @@ -0,0 +1,53 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.0 Filter, Map, Reduce +# Checkpoint: F40a +# Author: Jeff Cardille +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2') +# How many Tier 1 Landsat 5 images have ever been collected? +print("All images ever: ", imgCol.size()); # A very large number + +# How many images were collected in the 2000s? +startDate = '2000-01-01' +endDate = '2010-01-01' + +imgColfilteredByDate = imgCol.filterDate(startDate, endDate) +print("All images 2000-2010: ", imgColfilteredByDate.size()) +# A smaller (but still large) number + +ShanghaiImage = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606') +Map.centerObject(ShanghaiImage, 9) + +imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map \ + .getCenter()) +print("All images here, 2000-2010: ", imgColfilteredByDateHere \ +.size()); + +L5FilteredLowCloudImages = imgColfilteredByDateHere \ + .filterMetadata('CLOUD_COVER', 'less_than', 50) +print("Less than 50% clouds in this area, 2000-2010", + L5FilteredLowCloudImages.size()); # A smaller number + +chainedFilteredSet = imgCol.filterDate(startDate, endDate) \ + .filterBounds(Map.getCenter()) \ + .filterMetadata('CLOUD_COVER', 'less_than', 50) +print('Chained: Less than 50% clouds in this area, 2000-2010', + chainedFilteredSet.size()) + +efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) \ + .filterDate(startDate, endDate) \ + .filterMetadata('CLOUD_COVER', 'less_than', 50) +print('Efficient filtering: Less than 50% clouds in this area, 2000-2010', + efficientFilteredSet.size()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40b Checkpoint.ipynb new file mode 100644 index 0000000..7ac9b9f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40b Checkpoint.ipynb @@ -0,0 +1,177 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.0 Filter, Map, Reduce\n", + "# Checkpoint: F40b\n", + "# Author: Jeff Cardille\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2')\n", + "# How many Tier 1 Landsat 5 images have ever been collected?\n", + "print(\"All images ever: \", imgCol.size()); # A very large number\n", + "\n", + "# How many images were collected in the 2000s?\n", + "startDate = '2000-01-01'\n", + "endDate = '2010-01-01'\n", + "\n", + "imgColfilteredByDate = imgCol.filterDate(startDate, endDate)\n", + "print(\"All images 2000-2010: \", imgColfilteredByDate.size())\n", + "# A smaller (but still large) number\n", + "\n", + "ShanghaiImage = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606')\n", + "Map.centerObject(ShanghaiImage, 9)\n", + "\n", + "imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map \\\n", + " .getCenter())\n", + "print(\"All images here, 2000-2010: \", imgColfilteredByDateHere \\\n", + ".size()); \n", + "\n", + "L5FilteredLowCloudImages = imgColfilteredByDateHere \\\n", + " .filterMetadata('CLOUD_COVER', 'less_than', 50)\n", + "print(\"Less than 50% clouds in this area, 2000-2010\",\n", + " L5FilteredLowCloudImages.size()); # A smaller number\n", + "\n", + "chainedFilteredSet = imgCol.filterDate(startDate, endDate) \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterMetadata('CLOUD_COVER', 'less_than', 50)\n", + "print('Chained: Less than 50% clouds in this area, 2000-2010',\n", + " chainedFilteredSet.size())\n", + "\n", + "efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) \\\n", + " .filterDate(startDate, endDate) \\\n", + " .filterMetadata('CLOUD_COVER', 'less_than', 50)\n", + "print('Efficient filtering: Less than 50% clouds in this area, 2000-2010',\n", + " efficientFilteredSet.size())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "def makeLandsat5EVI(oneL5Image):\n", + " # compute the EVI for any Landsat 5 image. Note it's specific to\n", + " # Landsat 5 images due to the band numbers. Don't run this exact\n", + " # function for images from sensors other than Landsat 5.\n", + "\n", + " # Extract the bands and divide by 1e4 to account for scaling done.\n", + " nirScaled = oneL5Image.select('SR_B4').divide(10000)\n", + " redScaled = oneL5Image.select('SR_B3').divide(10000)\n", + " blueScaled = oneL5Image.select('SR_B1').divide(10000)\n", + "\n", + " # Calculate the numerator, note that order goes from left to right.\n", + " numeratorEVI = (nirScaled.subtract(redScaled)).multiply(\n", + " 2.5)\n", + "\n", + " # Calculate the denominator\n", + " denomClause1 = redScaled.multiply(6)\n", + " denomClause2 = blueScaled.multiply(7.5)\n", + " denominatorEVI = nirScaled.add(denomClause1).subtract(\n", + " denomClause2).add(1)\n", + "\n", + " # Calculate EVI and name it.\n", + " landsat5EVI = numeratorEVI.divide(denominatorEVI).rename(\n", + " 'EVI')\n", + " return (landsat5EVI)\n", + "\n", + "\n", + "L5EVIimages = efficientFilteredSet.map(makeLandsat5EVI)\n", + "print('Verifying that the .map gives back the same number of images: ',\n", + " L5EVIimages.size())\n", + "print(L5EVIimages)\n", + "\n", + "Map.addLayer(L5EVIimages, {}, 'L5EVIimages', 1, 1)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40b Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40b Checkpoint.js new file mode 100644 index 0000000..d9dc7f2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40b Checkpoint.js @@ -0,0 +1,84 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.0 Filter, Map, Reduce +// Checkpoint: F40b +// Author: Jeff Cardille +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2'); +// How many Tier 1 Landsat 5 images have ever been collected? +print("All images ever: ", imgCol.size()); // A very large number + +// How many images were collected in the 2000s? +var startDate = '2000-01-01'; +var endDate = '2010-01-01'; + +var imgColfilteredByDate = imgCol.filterDate(startDate, endDate); +print("All images 2000-2010: ", imgColfilteredByDate.size()); +// A smaller (but still large) number + +var ShanghaiImage = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606'); +Map.centerObject(ShanghaiImage, 9); + +var imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map + .getCenter()); +print("All images here, 2000-2010: ", imgColfilteredByDateHere +.size()); // A smaller number + +var L5FilteredLowCloudImages = imgColfilteredByDateHere + .filterMetadata('CLOUD_COVER', 'less_than', 50); +print("Less than 50% clouds in this area, 2000-2010", + L5FilteredLowCloudImages.size()); // A smaller number + +var chainedFilteredSet = imgCol.filterDate(startDate, endDate) + .filterBounds(Map.getCenter()) + .filterMetadata('CLOUD_COVER', 'less_than', 50); +print('Chained: Less than 50% clouds in this area, 2000-2010', + chainedFilteredSet.size()); + +var efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) + .filterDate(startDate, endDate) + .filterMetadata('CLOUD_COVER', 'less_than', 50); +print('Efficient filtering: Less than 50% clouds in this area, 2000-2010', + efficientFilteredSet.size()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var makeLandsat5EVI = function(oneL5Image) { + // compute the EVI for any Landsat 5 image. Note it's specific to + // Landsat 5 images due to the band numbers. Don't run this exact + // function for images from sensors other than Landsat 5. + + // Extract the bands and divide by 1e4 to account for scaling done. + var nirScaled = oneL5Image.select('SR_B4').divide(10000); + var redScaled = oneL5Image.select('SR_B3').divide(10000); + var blueScaled = oneL5Image.select('SR_B1').divide(10000); + + // Calculate the numerator, note that order goes from left to right. + var numeratorEVI = (nirScaled.subtract(redScaled)).multiply( + 2.5); + + // Calculate the denominator + var denomClause1 = redScaled.multiply(6); + var denomClause2 = blueScaled.multiply(7.5); + var denominatorEVI = nirScaled.add(denomClause1).subtract( + denomClause2).add(1); + + // Calculate EVI and name it. + var landsat5EVI = numeratorEVI.divide(denominatorEVI).rename( + 'EVI'); + return (landsat5EVI); +}; + +var L5EVIimages = efficientFilteredSet.map(makeLandsat5EVI); +print('Verifying that the .map gives back the same number of images: ', + L5EVIimages.size()); +print(L5EVIimages); + +Map.addLayer(L5EVIimages, {}, 'L5EVIimages', 1, 1); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40b Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40b Checkpoint.py new file mode 100644 index 0000000..fab1e74 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40b Checkpoint.py @@ -0,0 +1,90 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.0 Filter, Map, Reduce +# Checkpoint: F40b +# Author: Jeff Cardille +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2') +# How many Tier 1 Landsat 5 images have ever been collected? +print("All images ever: ", imgCol.size()); # A very large number + +# How many images were collected in the 2000s? +startDate = '2000-01-01' +endDate = '2010-01-01' + +imgColfilteredByDate = imgCol.filterDate(startDate, endDate) +print("All images 2000-2010: ", imgColfilteredByDate.size()) +# A smaller (but still large) number + +ShanghaiImage = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606') +Map.centerObject(ShanghaiImage, 9) + +imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map \ + .getCenter()) +print("All images here, 2000-2010: ", imgColfilteredByDateHere \ +.size()); + +L5FilteredLowCloudImages = imgColfilteredByDateHere \ + .filterMetadata('CLOUD_COVER', 'less_than', 50) +print("Less than 50% clouds in this area, 2000-2010", + L5FilteredLowCloudImages.size()); # A smaller number + +chainedFilteredSet = imgCol.filterDate(startDate, endDate) \ + .filterBounds(Map.getCenter()) \ + .filterMetadata('CLOUD_COVER', 'less_than', 50) +print('Chained: Less than 50% clouds in this area, 2000-2010', + chainedFilteredSet.size()) + +efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) \ + .filterDate(startDate, endDate) \ + .filterMetadata('CLOUD_COVER', 'less_than', 50) +print('Efficient filtering: Less than 50% clouds in this area, 2000-2010', + efficientFilteredSet.size()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +def makeLandsat5EVI(oneL5Image): + # compute the EVI for any Landsat 5 image. Note it's specific to + # Landsat 5 images due to the band numbers. Don't run this exact + # function for images from sensors other than Landsat 5. + + # Extract the bands and divide by 1e4 to account for scaling done. + nirScaled = oneL5Image.select('SR_B4').divide(10000) + redScaled = oneL5Image.select('SR_B3').divide(10000) + blueScaled = oneL5Image.select('SR_B1').divide(10000) + + # Calculate the numerator, note that order goes from left to right. + numeratorEVI = (nirScaled.subtract(redScaled)).multiply( + 2.5) + + # Calculate the denominator + denomClause1 = redScaled.multiply(6) + denomClause2 = blueScaled.multiply(7.5) + denominatorEVI = nirScaled.add(denomClause1).subtract( + denomClause2).add(1) + + # Calculate EVI and name it. + landsat5EVI = numeratorEVI.divide(denominatorEVI).rename( + 'EVI') + return (landsat5EVI) + + +L5EVIimages = efficientFilteredSet.map(makeLandsat5EVI) +print('Verifying that the .map gives back the same number of images: ', + L5EVIimages.size()) +print(L5EVIimages) + +Map.addLayer(L5EVIimages, {}, 'L5EVIimages', 1, 1) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40c Checkpoint.ipynb new file mode 100644 index 0000000..ab3edc2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40c Checkpoint.ipynb @@ -0,0 +1,197 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.0 Filter, Map, Reduce\n", + "# Checkpoint: F40c\n", + "# Author: Jeff Cardille\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2')\n", + "# How many Tier 1 Landsat 5 images have ever been collected?\n", + "print(\"All images ever: \", imgCol.size()); # A very large number\n", + "\n", + "# How many images were collected in the 2000s?\n", + "startDate = '2000-01-01'\n", + "endDate = '2010-01-01'\n", + "\n", + "imgColfilteredByDate = imgCol.filterDate(startDate, endDate)\n", + "print(\"All images 2000-2010: \", imgColfilteredByDate.size())\n", + "# A smaller (but still large) number\n", + "\n", + "ShanghaiImage = ee.Image(\n", + " 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606')\n", + "Map.centerObject(ShanghaiImage, 9)\n", + "\n", + "imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map \\\n", + " .getCenter())\n", + "print(\"All images here, 2000-2010: \", imgColfilteredByDateHere \\\n", + ".size()); \n", + "\n", + "L5FilteredLowCloudImages = imgColfilteredByDateHere \\\n", + " .filterMetadata('CLOUD_COVER', 'less_than', 50)\n", + "print(\"Less than 50% clouds in this area, 2000-2010\",\n", + " L5FilteredLowCloudImages.size()); # A smaller number\n", + "\n", + "chainedFilteredSet = imgCol.filterDate(startDate, endDate) \\\n", + " .filterBounds(Map.getCenter()) \\\n", + " .filterMetadata('CLOUD_COVER', 'less_than', 50)\n", + "print('Chained: Less than 50% clouds in this area, 2000-2010',\n", + " chainedFilteredSet.size())\n", + "\n", + "efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) \\\n", + " .filterDate(startDate, endDate) \\\n", + " .filterMetadata('CLOUD_COVER', 'less_than', 50)\n", + "print('Efficient filtering: Less than 50% clouds in this area, 2000-2010',\n", + " efficientFilteredSet.size())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "def makeLandsat5EVI(oneL5Image):\n", + " # compute the EVI for any Landsat 5 image. Note it's specific to\n", + " # Landsat 5 images due to the band numbers. Don't run this exact\n", + " # function for images from sensors other than Landsat 5.\n", + "\n", + " # Extract the bands and divide by 1e4 to account for scaling done.\n", + " nirScaled = oneL5Image.select('SR_B4').divide(10000)\n", + " redScaled = oneL5Image.select('SR_B3').divide(10000)\n", + " blueScaled = oneL5Image.select('SR_B1').divide(10000)\n", + "\n", + " # Calculate the numerator, note that order goes from left to right.\n", + " numeratorEVI = (nirScaled.subtract(redScaled)).multiply(\n", + " 2.5)\n", + "\n", + " # Calculate the denominator\n", + " denomClause1 = redScaled.multiply(6)\n", + " denomClause2 = blueScaled.multiply(7.5)\n", + " denominatorEVI = nirScaled.add(denomClause1).subtract(\n", + " denomClause2).add(1)\n", + "\n", + " # Calculate EVI and name it.\n", + " landsat5EVI = numeratorEVI.divide(denominatorEVI).rename(\n", + " 'EVI')\n", + " return (landsat5EVI)\n", + "\n", + "\n", + "L5EVIimages = efficientFilteredSet.map(makeLandsat5EVI)\n", + "print('Verifying that the .map gives back the same number of images: ',\n", + " L5EVIimages.size())\n", + "print(L5EVIimages)\n", + "\n", + "Map.addLayer(L5EVIimages, {}, 'L5EVIimages', 1, 1)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "L5EVImean = L5EVIimages.reduce(ee.Reducer.mean())\n", + "print(L5EVImean)\n", + "Map.addLayer(L5EVImean, {\n", + " 'min': -1,\n", + " 'max': 2,\n", + " 'palette': ['red', 'white', 'green']\n", + "}, 'Mean EVI')\n", + "\n", + "L5EVImedian = L5EVIimages.reduce(ee.Reducer.median())\n", + "print(L5EVImedian)\n", + "Map.addLayer(L5EVImedian, {\n", + " 'min': -1,\n", + " 'max': 2,\n", + " 'palette': ['red', 'white', 'green']\n", + "}, 'Median EVI')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40c Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40c Checkpoint.js new file mode 100644 index 0000000..01f92d6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40c Checkpoint.js @@ -0,0 +1,104 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.0 Filter, Map, Reduce +// Checkpoint: F40c +// Author: Jeff Cardille +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2'); +// How many Tier 1 Landsat 5 images have ever been collected? +print("All images ever: ", imgCol.size()); // A very large number + +// How many images were collected in the 2000s? +var startDate = '2000-01-01'; +var endDate = '2010-01-01'; + +var imgColfilteredByDate = imgCol.filterDate(startDate, endDate); +print("All images 2000-2010: ", imgColfilteredByDate.size()); +// A smaller (but still large) number + +var ShanghaiImage = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606'); +Map.centerObject(ShanghaiImage, 9); + +var imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map + .getCenter()); +print("All images here, 2000-2010: ", imgColfilteredByDateHere +.size()); // A smaller number + +var L5FilteredLowCloudImages = imgColfilteredByDateHere + .filterMetadata('CLOUD_COVER', 'less_than', 50); +print("Less than 50% clouds in this area, 2000-2010", + L5FilteredLowCloudImages.size()); // A smaller number + +var chainedFilteredSet = imgCol.filterDate(startDate, endDate) + .filterBounds(Map.getCenter()) + .filterMetadata('CLOUD_COVER', 'less_than', 50); +print('Chained: Less than 50% clouds in this area, 2000-2010', + chainedFilteredSet.size()); + +var efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) + .filterDate(startDate, endDate) + .filterMetadata('CLOUD_COVER', 'less_than', 50); +print('Efficient filtering: Less than 50% clouds in this area, 2000-2010', + efficientFilteredSet.size()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var makeLandsat5EVI = function(oneL5Image) { + // compute the EVI for any Landsat 5 image. Note it's specific to + // Landsat 5 images due to the band numbers. Don't run this exact + // function for images from sensors other than Landsat 5. + + // Extract the bands and divide by 1e4 to account for scaling done. + var nirScaled = oneL5Image.select('SR_B4').divide(10000); + var redScaled = oneL5Image.select('SR_B3').divide(10000); + var blueScaled = oneL5Image.select('SR_B1').divide(10000); + + // Calculate the numerator, note that order goes from left to right. + var numeratorEVI = (nirScaled.subtract(redScaled)).multiply( + 2.5); + + // Calculate the denominator + var denomClause1 = redScaled.multiply(6); + var denomClause2 = blueScaled.multiply(7.5); + var denominatorEVI = nirScaled.add(denomClause1).subtract( + denomClause2).add(1); + + // Calculate EVI and name it. + var landsat5EVI = numeratorEVI.divide(denominatorEVI).rename( + 'EVI'); + return (landsat5EVI); +}; + +var L5EVIimages = efficientFilteredSet.map(makeLandsat5EVI); +print('Verifying that the .map gives back the same number of images: ', + L5EVIimages.size()); +print(L5EVIimages); + +Map.addLayer(L5EVIimages, {}, 'L5EVIimages', 1, 1); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var L5EVImean = L5EVIimages.reduce(ee.Reducer.mean()); +print(L5EVImean); +Map.addLayer(L5EVImean, { + min: -1, + max: 2, + palette: ['red', 'white', 'green'] +}, 'Mean EVI'); + +var L5EVImedian = L5EVIimages.reduce(ee.Reducer.median()); +print(L5EVImedian); +Map.addLayer(L5EVImedian, { + min: -1, + max: 2, + palette: ['red', 'white', 'green'] +}, 'Median EVI'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40c Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40c Checkpoint.py new file mode 100644 index 0000000..e4889a2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.0 Functional Programming Concepts/F40c Checkpoint.py @@ -0,0 +1,110 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.0 Filter, Map, Reduce +# Checkpoint: F40c +# Author: Jeff Cardille +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2') +# How many Tier 1 Landsat 5 images have ever been collected? +print("All images ever: ", imgCol.size()); # A very large number + +# How many images were collected in the 2000s? +startDate = '2000-01-01' +endDate = '2010-01-01' + +imgColfilteredByDate = imgCol.filterDate(startDate, endDate) +print("All images 2000-2010: ", imgColfilteredByDate.size()) +# A smaller (but still large) number + +ShanghaiImage = ee.Image( + 'LANDSAT/LT05/C02/T1_L2/LT05_118038_20000606') +Map.centerObject(ShanghaiImage, 9) + +imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map \ + .getCenter()) +print("All images here, 2000-2010: ", imgColfilteredByDateHere \ +.size()); + +L5FilteredLowCloudImages = imgColfilteredByDateHere \ + .filterMetadata('CLOUD_COVER', 'less_than', 50) +print("Less than 50% clouds in this area, 2000-2010", + L5FilteredLowCloudImages.size()); # A smaller number + +chainedFilteredSet = imgCol.filterDate(startDate, endDate) \ + .filterBounds(Map.getCenter()) \ + .filterMetadata('CLOUD_COVER', 'less_than', 50) +print('Chained: Less than 50% clouds in this area, 2000-2010', + chainedFilteredSet.size()) + +efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) \ + .filterDate(startDate, endDate) \ + .filterMetadata('CLOUD_COVER', 'less_than', 50) +print('Efficient filtering: Less than 50% clouds in this area, 2000-2010', + efficientFilteredSet.size()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +def makeLandsat5EVI(oneL5Image): + # compute the EVI for any Landsat 5 image. Note it's specific to + # Landsat 5 images due to the band numbers. Don't run this exact + # function for images from sensors other than Landsat 5. + + # Extract the bands and divide by 1e4 to account for scaling done. + nirScaled = oneL5Image.select('SR_B4').divide(10000) + redScaled = oneL5Image.select('SR_B3').divide(10000) + blueScaled = oneL5Image.select('SR_B1').divide(10000) + + # Calculate the numerator, note that order goes from left to right. + numeratorEVI = (nirScaled.subtract(redScaled)).multiply( + 2.5) + + # Calculate the denominator + denomClause1 = redScaled.multiply(6) + denomClause2 = blueScaled.multiply(7.5) + denominatorEVI = nirScaled.add(denomClause1).subtract( + denomClause2).add(1) + + # Calculate EVI and name it. + landsat5EVI = numeratorEVI.divide(denominatorEVI).rename( + 'EVI') + return (landsat5EVI) + + +L5EVIimages = efficientFilteredSet.map(makeLandsat5EVI) +print('Verifying that the .map gives back the same number of images: ', + L5EVIimages.size()) +print(L5EVIimages) + +Map.addLayer(L5EVIimages, {}, 'L5EVIimages', 1, 1) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +L5EVImean = L5EVIimages.reduce(ee.Reducer.mean()) +print(L5EVImean) +Map.addLayer(L5EVImean, { + 'min': -1, + 'max': 2, + 'palette': ['red', 'white', 'green'] +}, 'Mean EVI') + +L5EVImedian = L5EVIimages.reduce(ee.Reducer.median()) +print(L5EVImedian) +Map.addLayer(L5EVImedian, { + 'min': -1, + 'max': 2, + 'palette': ['red', 'white', 'green'] +}, 'Median EVI') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41a Checkpoint.ipynb new file mode 100644 index 0000000..f2ce6fe --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41a Checkpoint.ipynb @@ -0,0 +1,130 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.1 Exploring Image Collections\n", + "# Checkpoint: F41a\n", + "# Author: Gennadii Donchyts\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define a region of interest as a point in Lisbon, Portugal.\n", + "lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948)\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(lisbonPoint, 16)\n", + "\n", + "# filter the large ImageCollection to be just images from 2020\n", + "# around Lisbon. From each image, select True-color bands to draw\n", + "filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .filterBounds(lisbonPoint) \\\n", + " .select(['B6', 'B5', 'B4'])\n", + "\n", + "# Add the filtered ImageCollection so that we can inspect values\n", + "# via the Inspector tool\n", + "Map.addLayer(filteredIC, {}, 'TOA image collection')\n", + "\n", + "# Construct a chart using values queried from image collection.\n", + "chart = ui.Chart.image.series({\n", + " 'imageCollection': filteredIC,\n", + " 'region': lisbonPoint,\n", + " 'reducer': ee.Reducer.first(),\n", + " 'scale': 10\n", + "})\n", + "\n", + "# Show the chart in the Console.\n", + "print(chart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41a Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41a Checkpoint.js new file mode 100644 index 0000000..19af63d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41a Checkpoint.js @@ -0,0 +1,37 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.1 Exploring Image Collections +// Checkpoint: F41a +// Author: Gennadii Donchyts +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define a region of interest as a point in Lisbon, Portugal. +var lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948); + +// Center the map at that point. +Map.centerObject(lisbonPoint, 16); + +// filter the large ImageCollection to be just images from 2020 +// around Lisbon. From each image, select true-color bands to draw +var filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterDate('2020-01-01', '2021-01-01') + .filterBounds(lisbonPoint) + .select(['B6', 'B5', 'B4']); + +// Add the filtered ImageCollection so that we can inspect values +// via the Inspector tool +Map.addLayer(filteredIC, {}, 'TOA image collection'); + +// Construct a chart using values queried from image collection. +var chart = ui.Chart.image.series({ + imageCollection: filteredIC, + region: lisbonPoint, + reducer: ee.Reducer.first(), + scale: 10 +}); + +// Show the chart in the Console. +print(chart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41a Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41a Checkpoint.py new file mode 100644 index 0000000..84b0bdc --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41a Checkpoint.py @@ -0,0 +1,43 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.1 Exploring Image Collections +# Checkpoint: F41a +# Author: Gennadii Donchyts +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define a region of interest as a point in Lisbon, Portugal. +lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948) + +# Center the map at that point. +Map.centerObject(lisbonPoint, 16) + +# filter the large ImageCollection to be just images from 2020 +# around Lisbon. From each image, select True-color bands to draw +filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterDate('2020-01-01', '2021-01-01') \ + .filterBounds(lisbonPoint) \ + .select(['B6', 'B5', 'B4']) + +# Add the filtered ImageCollection so that we can inspect values +# via the Inspector tool +Map.addLayer(filteredIC, {}, 'TOA image collection') + +# Construct a chart using values queried from image collection. +chart = ui.Chart.image.series({ + 'imageCollection': filteredIC, + 'region': lisbonPoint, + 'reducer': ee.Reducer.first(), + 'scale': 10 +}) + +# Show the chart in the Console. +print(chart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41b Checkpoint.ipynb new file mode 100644 index 0000000..318b3fd --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41b Checkpoint.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.1 Exploring Image Collections\n", + "# Checkpoint: F41b\n", + "# Author: Gennadii Donchyts\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define a region of interest as a point in Lisbon, Portugal.\n", + "lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948)\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(lisbonPoint, 16)\n", + "\n", + "# filter the large ImageCollection to be just images from 2020\n", + "# around Lisbon. From each image, select True-color bands to draw\n", + "filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .filterBounds(lisbonPoint) \\\n", + " .select(['B6', 'B5', 'B4'])\n", + "\n", + "# Add the filtered ImageCollection so that we can inspect values\n", + "# via the Inspector tool\n", + "Map.addLayer(filteredIC, {}, 'TOA image collection')\n", + "\n", + "# Construct a chart using values queried from image collection.\n", + "chart = ui.Chart.image.series({\n", + " 'imageCollection': filteredIC,\n", + " 'region': lisbonPoint,\n", + " 'reducer': ee.Reducer.first(),\n", + " 'scale': 10\n", + "})\n", + "\n", + "# Show the chart in the Console.\n", + "print(chart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# compute and show the number of observations in an image collection\n", + "count = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .select(['B6']) \\\n", + " .count()\n", + "\n", + "# add white background and switch to HYBRID basemap\n", + "Map.addLayer(ee.Image(1), {\n", + " 'palette': ['white']\n", + "}, 'white', True, 0.5)\n", + "Map.setOptions('HYBRID')\n", + "\n", + "# show image count\n", + "Map.addLayer(count, {\n", + " 'min': 0,\n", + " 'max': 50,\n", + " 'palette': ['d7191c', 'fdae61', 'ffffbf', 'a6d96a',\n", + " '1a9641']\n", + "}, 'landsat 8 image count (2020)')\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(lisbonPoint, 5)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41b Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41b Checkpoint.js new file mode 100644 index 0000000..743631a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41b Checkpoint.js @@ -0,0 +1,67 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.1 Exploring Image Collections +// Checkpoint: F41b +// Author: Gennadii Donchyts +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define a region of interest as a point in Lisbon, Portugal. +var lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948); + +// Center the map at that point. +Map.centerObject(lisbonPoint, 16); + +// filter the large ImageCollection to be just images from 2020 +// around Lisbon. From each image, select true-color bands to draw +var filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterDate('2020-01-01', '2021-01-01') + .filterBounds(lisbonPoint) + .select(['B6', 'B5', 'B4']); + +// Add the filtered ImageCollection so that we can inspect values +// via the Inspector tool +Map.addLayer(filteredIC, {}, 'TOA image collection'); + +// Construct a chart using values queried from image collection. +var chart = ui.Chart.image.series({ + imageCollection: filteredIC, + region: lisbonPoint, + reducer: ee.Reducer.first(), + scale: 10 +}); + +// Show the chart in the Console. +print(chart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// compute and show the number of observations in an image collection +var count = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterDate('2020-01-01', '2021-01-01') + .select(['B6']) + .count(); + +// add white background and switch to HYBRID basemap +Map.addLayer(ee.Image(1), { + palette: ['white'] +}, 'white', true, 0.5); +Map.setOptions('HYBRID'); + +// show image count +Map.addLayer(count, { + min: 0, + max: 50, + palette: ['d7191c', 'fdae61', 'ffffbf', 'a6d96a', + '1a9641'] +}, 'landsat 8 image count (2020)'); + +// Center the map at that point. +Map.centerObject(lisbonPoint, 5); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41b Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41b Checkpoint.py new file mode 100644 index 0000000..162947e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41b Checkpoint.py @@ -0,0 +1,73 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.1 Exploring Image Collections +# Checkpoint: F41b +# Author: Gennadii Donchyts +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define a region of interest as a point in Lisbon, Portugal. +lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948) + +# Center the map at that point. +Map.centerObject(lisbonPoint, 16) + +# filter the large ImageCollection to be just images from 2020 +# around Lisbon. From each image, select True-color bands to draw +filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterDate('2020-01-01', '2021-01-01') \ + .filterBounds(lisbonPoint) \ + .select(['B6', 'B5', 'B4']) + +# Add the filtered ImageCollection so that we can inspect values +# via the Inspector tool +Map.addLayer(filteredIC, {}, 'TOA image collection') + +# Construct a chart using values queried from image collection. +chart = ui.Chart.image.series({ + 'imageCollection': filteredIC, + 'region': lisbonPoint, + 'reducer': ee.Reducer.first(), + 'scale': 10 +}) + +# Show the chart in the Console. +print(chart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# compute and show the number of observations in an image collection +count = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterDate('2020-01-01', '2021-01-01') \ + .select(['B6']) \ + .count() + +# add white background and switch to HYBRID basemap +Map.addLayer(ee.Image(1), { + 'palette': ['white'] +}, 'white', True, 0.5) +Map.setOptions('HYBRID') + +# show image count +Map.addLayer(count, { + 'min': 0, + 'max': 50, + 'palette': ['d7191c', 'fdae61', 'ffffbf', 'a6d96a', + '1a9641'] +}, 'landsat 8 image count (2020)') + +# Center the map at that point. +Map.centerObject(lisbonPoint, 5) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41c Checkpoint.ipynb new file mode 100644 index 0000000..d57aa03 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41c Checkpoint.ipynb @@ -0,0 +1,176 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.1 Exploring Image Collections\n", + "# Checkpoint: F41c\n", + "# Author: Gennadii Donchyts\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define a region of interest as a point in Lisbon, Portugal.\n", + "lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948)\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(lisbonPoint, 16)\n", + "\n", + "# filter the large ImageCollection to be just images from 2020\n", + "# around Lisbon. From each image, select True-color bands to draw\n", + "filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .filterBounds(lisbonPoint) \\\n", + " .select(['B6', 'B5', 'B4'])\n", + "\n", + "# Add the filtered ImageCollection so that we can inspect values\n", + "# via the Inspector tool\n", + "Map.addLayer(filteredIC, {}, 'TOA image collection')\n", + "\n", + "# Construct a chart using values queried from image collection.\n", + "chart = ui.Chart.image.series({\n", + " 'imageCollection': filteredIC,\n", + " 'region': lisbonPoint,\n", + " 'reducer': ee.Reducer.first(),\n", + " 'scale': 10\n", + "})\n", + "\n", + "# Show the chart in the Console.\n", + "print(chart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# compute and show the number of observations in an image collection\n", + "count = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .select(['B6']) \\\n", + " .count()\n", + "\n", + "# add white background and switch to HYBRID basemap\n", + "Map.addLayer(ee.Image(1), {\n", + " 'palette': ['white']\n", + "}, 'white', True, 0.5)\n", + "Map.setOptions('HYBRID')\n", + "\n", + "# show image count\n", + "Map.addLayer(count, {\n", + " 'min': 0,\n", + " 'max': 50,\n", + " 'palette': ['d7191c', 'fdae61', 'ffffbf', 'a6d96a',\n", + " '1a9641']\n", + "}, 'landsat 8 image count (2020)')\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(lisbonPoint, 5)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Zoom to an informative scale for the code that follows.\n", + "Map.centerObject(lisbonPoint, 10)\n", + "\n", + "# Add a mean composite image.\n", + "meanFilteredIC = filteredIC.reduce(ee.Reducer.mean())\n", + "Map.addLayer(meanFilteredIC, {},\n", + " 'Mean values within image collection')\n", + "\n", + "# Add a median composite image.\n", + "medianFilteredIC = filteredIC.reduce(ee.Reducer.median())\n", + "Map.addLayer(medianFilteredIC, {},\n", + " 'Median values within image collection')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41c Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41c Checkpoint.js new file mode 100644 index 0000000..1a03128 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41c Checkpoint.js @@ -0,0 +1,84 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.1 Exploring Image Collections +// Checkpoint: F41c +// Author: Gennadii Donchyts +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define a region of interest as a point in Lisbon, Portugal. +var lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948); + +// Center the map at that point. +Map.centerObject(lisbonPoint, 16); + +// filter the large ImageCollection to be just images from 2020 +// around Lisbon. From each image, select true-color bands to draw +var filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterDate('2020-01-01', '2021-01-01') + .filterBounds(lisbonPoint) + .select(['B6', 'B5', 'B4']); + +// Add the filtered ImageCollection so that we can inspect values +// via the Inspector tool +Map.addLayer(filteredIC, {}, 'TOA image collection'); + +// Construct a chart using values queried from image collection. +var chart = ui.Chart.image.series({ + imageCollection: filteredIC, + region: lisbonPoint, + reducer: ee.Reducer.first(), + scale: 10 +}); + +// Show the chart in the Console. +print(chart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// compute and show the number of observations in an image collection +var count = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterDate('2020-01-01', '2021-01-01') + .select(['B6']) + .count(); + +// add white background and switch to HYBRID basemap +Map.addLayer(ee.Image(1), { + palette: ['white'] +}, 'white', true, 0.5); +Map.setOptions('HYBRID'); + +// show image count +Map.addLayer(count, { + min: 0, + max: 50, + palette: ['d7191c', 'fdae61', 'ffffbf', 'a6d96a', + '1a9641'] +}, 'landsat 8 image count (2020)'); + +// Center the map at that point. +Map.centerObject(lisbonPoint, 5); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Zoom to an informative scale for the code that follows. +Map.centerObject(lisbonPoint, 10); + +// Add a mean composite image. +var meanFilteredIC = filteredIC.reduce(ee.Reducer.mean()); +Map.addLayer(meanFilteredIC, {}, + 'Mean values within image collection'); + +// Add a median composite image. +var medianFilteredIC = filteredIC.reduce(ee.Reducer.median()); +Map.addLayer(medianFilteredIC, {}, + 'Median values within image collection'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41c Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41c Checkpoint.py new file mode 100644 index 0000000..e59a709 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41c Checkpoint.py @@ -0,0 +1,90 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.1 Exploring Image Collections +# Checkpoint: F41c +# Author: Gennadii Donchyts +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define a region of interest as a point in Lisbon, Portugal. +lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948) + +# Center the map at that point. +Map.centerObject(lisbonPoint, 16) + +# filter the large ImageCollection to be just images from 2020 +# around Lisbon. From each image, select True-color bands to draw +filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterDate('2020-01-01', '2021-01-01') \ + .filterBounds(lisbonPoint) \ + .select(['B6', 'B5', 'B4']) + +# Add the filtered ImageCollection so that we can inspect values +# via the Inspector tool +Map.addLayer(filteredIC, {}, 'TOA image collection') + +# Construct a chart using values queried from image collection. +chart = ui.Chart.image.series({ + 'imageCollection': filteredIC, + 'region': lisbonPoint, + 'reducer': ee.Reducer.first(), + 'scale': 10 +}) + +# Show the chart in the Console. +print(chart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# compute and show the number of observations in an image collection +count = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterDate('2020-01-01', '2021-01-01') \ + .select(['B6']) \ + .count() + +# add white background and switch to HYBRID basemap +Map.addLayer(ee.Image(1), { + 'palette': ['white'] +}, 'white', True, 0.5) +Map.setOptions('HYBRID') + +# show image count +Map.addLayer(count, { + 'min': 0, + 'max': 50, + 'palette': ['d7191c', 'fdae61', 'ffffbf', 'a6d96a', + '1a9641'] +}, 'landsat 8 image count (2020)') + +# Center the map at that point. +Map.centerObject(lisbonPoint, 5) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Zoom to an informative scale for the code that follows. +Map.centerObject(lisbonPoint, 10) + +# Add a mean composite image. +meanFilteredIC = filteredIC.reduce(ee.Reducer.mean()) +Map.addLayer(meanFilteredIC, {}, + 'Mean values within image collection') + +# Add a median composite image. +medianFilteredIC = filteredIC.reduce(ee.Reducer.median()) +Map.addLayer(medianFilteredIC, {}, + 'Median values within image collection') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41d Checkpoint.ipynb new file mode 100644 index 0000000..ad632ed --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41d Checkpoint.ipynb @@ -0,0 +1,208 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.1 Exploring Image Collections\n", + "# Checkpoint: F41d\n", + "# Author: Gennadii Donchyts\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define a region of interest as a point in Lisbon, Portugal.\n", + "lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948)\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(lisbonPoint, 16)\n", + "\n", + "# filter the large ImageCollection to be just images from 2020\n", + "# around Lisbon. From each image, select True-color bands to draw\n", + "filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .filterBounds(lisbonPoint) \\\n", + " .select(['B6', 'B5', 'B4'])\n", + "\n", + "# Add the filtered ImageCollection so that we can inspect values\n", + "# via the Inspector tool\n", + "Map.addLayer(filteredIC, {}, 'TOA image collection')\n", + "\n", + "# Construct a chart using values queried from image collection.\n", + "chart = ui.Chart.image.series({\n", + " 'imageCollection': filteredIC,\n", + " 'region': lisbonPoint,\n", + " 'reducer': ee.Reducer.first(),\n", + " 'scale': 10\n", + "})\n", + "\n", + "# Show the chart in the Console.\n", + "print(chart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# compute and show the number of observations in an image collection\n", + "count = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \\\n", + " .filterDate('2020-01-01', '2021-01-01') \\\n", + " .select(['B6']) \\\n", + " .count()\n", + "\n", + "# add white background and switch to HYBRID basemap\n", + "Map.addLayer(ee.Image(1), {\n", + " 'palette': ['white']\n", + "}, 'white', True, 0.5)\n", + "Map.setOptions('HYBRID')\n", + "\n", + "# show image count\n", + "Map.addLayer(count, {\n", + " 'min': 0,\n", + " 'max': 50,\n", + " 'palette': ['d7191c', 'fdae61', 'ffffbf', 'a6d96a',\n", + " '1a9641']\n", + "}, 'landsat 8 image count (2020)')\n", + "\n", + "# Center the map at that point.\n", + "Map.centerObject(lisbonPoint, 5)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Zoom to an informative scale for the code that follows.\n", + "Map.centerObject(lisbonPoint, 10)\n", + "\n", + "# Add a mean composite image.\n", + "meanFilteredIC = filteredIC.reduce(ee.Reducer.mean())\n", + "Map.addLayer(meanFilteredIC, {},\n", + " 'Mean values within image collection')\n", + "\n", + "# Add a median composite image.\n", + "medianFilteredIC = filteredIC.reduce(ee.Reducer.median())\n", + "Map.addLayer(medianFilteredIC, {},\n", + " 'Median values within image collection')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# compute a single 30% percentile\n", + "p30 = filteredIC.reduce(ee.Reducer.percentile([30]))\n", + "\n", + "Map.addLayer(p30, {\n", + " 'min': 0.05,\n", + " 'max': 0.35\n", + "}, '30%')\n", + "\n", + "percentiles = [0, 10, 20, 30, 40, 50, 60, 70, 80]\n", + "\n", + "# let's compute percentile images and add them as separate layers\n", + "\n", + "def func_sax(p):\n", + " image = filteredIC.reduce(ee.Reducer.percentile([p]))\n", + " Map.addLayer(image, {\n", + " 'min': 0.05,\n", + " 'max': 0.35\n", + " }, p + '%')\n", + "\n", + "percentiles.map(func_sax)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41d Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41d Checkpoint.js new file mode 100644 index 0000000..c799371 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41d Checkpoint.js @@ -0,0 +1,107 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.1 Exploring Image Collections +// Checkpoint: F41d +// Author: Gennadii Donchyts +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define a region of interest as a point in Lisbon, Portugal. +var lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948); + +// Center the map at that point. +Map.centerObject(lisbonPoint, 16); + +// filter the large ImageCollection to be just images from 2020 +// around Lisbon. From each image, select true-color bands to draw +var filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterDate('2020-01-01', '2021-01-01') + .filterBounds(lisbonPoint) + .select(['B6', 'B5', 'B4']); + +// Add the filtered ImageCollection so that we can inspect values +// via the Inspector tool +Map.addLayer(filteredIC, {}, 'TOA image collection'); + +// Construct a chart using values queried from image collection. +var chart = ui.Chart.image.series({ + imageCollection: filteredIC, + region: lisbonPoint, + reducer: ee.Reducer.first(), + scale: 10 +}); + +// Show the chart in the Console. +print(chart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// compute and show the number of observations in an image collection +var count = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + .filterDate('2020-01-01', '2021-01-01') + .select(['B6']) + .count(); + +// add white background and switch to HYBRID basemap +Map.addLayer(ee.Image(1), { + palette: ['white'] +}, 'white', true, 0.5); +Map.setOptions('HYBRID'); + +// show image count +Map.addLayer(count, { + min: 0, + max: 50, + palette: ['d7191c', 'fdae61', 'ffffbf', 'a6d96a', + '1a9641'] +}, 'landsat 8 image count (2020)'); + +// Center the map at that point. +Map.centerObject(lisbonPoint, 5); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Zoom to an informative scale for the code that follows. +Map.centerObject(lisbonPoint, 10); + +// Add a mean composite image. +var meanFilteredIC = filteredIC.reduce(ee.Reducer.mean()); +Map.addLayer(meanFilteredIC, {}, + 'Mean values within image collection'); + +// Add a median composite image. +var medianFilteredIC = filteredIC.reduce(ee.Reducer.median()); +Map.addLayer(medianFilteredIC, {}, + 'Median values within image collection'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// compute a single 30% percentile +var p30 = filteredIC.reduce(ee.Reducer.percentile([30])); + +Map.addLayer(p30, { + min: 0.05, + max: 0.35 +}, '30%'); + +var percentiles = [0, 10, 20, 30, 40, 50, 60, 70, 80]; + +// let's compute percentile images and add them as separate layers +percentiles.map(function(p) { + var image = filteredIC.reduce(ee.Reducer.percentile([p])); + Map.addLayer(image, { + min: 0.05, + max: 0.35 + }, p + '%'); +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41d Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41d Checkpoint.py new file mode 100644 index 0000000..1dc85ae --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.1 Exploring Image Collections/F41d Checkpoint.py @@ -0,0 +1,122 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.1 Exploring Image Collections +# Checkpoint: F41d +# Author: Gennadii Donchyts +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define a region of interest as a point in Lisbon, Portugal. +lisbonPoint = ee.Geometry.Point(-9.179473, 38.763948) + +# Center the map at that point. +Map.centerObject(lisbonPoint, 16) + +# filter the large ImageCollection to be just images from 2020 +# around Lisbon. From each image, select True-color bands to draw +filteredIC = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterDate('2020-01-01', '2021-01-01') \ + .filterBounds(lisbonPoint) \ + .select(['B6', 'B5', 'B4']) + +# Add the filtered ImageCollection so that we can inspect values +# via the Inspector tool +Map.addLayer(filteredIC, {}, 'TOA image collection') + +# Construct a chart using values queried from image collection. +chart = ui.Chart.image.series({ + 'imageCollection': filteredIC, + 'region': lisbonPoint, + 'reducer': ee.Reducer.first(), + 'scale': 10 +}) + +# Show the chart in the Console. +print(chart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# compute and show the number of observations in an image collection +count = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') \ + .filterDate('2020-01-01', '2021-01-01') \ + .select(['B6']) \ + .count() + +# add white background and switch to HYBRID basemap +Map.addLayer(ee.Image(1), { + 'palette': ['white'] +}, 'white', True, 0.5) +Map.setOptions('HYBRID') + +# show image count +Map.addLayer(count, { + 'min': 0, + 'max': 50, + 'palette': ['d7191c', 'fdae61', 'ffffbf', 'a6d96a', + '1a9641'] +}, 'landsat 8 image count (2020)') + +# Center the map at that point. +Map.centerObject(lisbonPoint, 5) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Zoom to an informative scale for the code that follows. +Map.centerObject(lisbonPoint, 10) + +# Add a mean composite image. +meanFilteredIC = filteredIC.reduce(ee.Reducer.mean()) +Map.addLayer(meanFilteredIC, {}, + 'Mean values within image collection') + +# Add a median composite image. +medianFilteredIC = filteredIC.reduce(ee.Reducer.median()) +Map.addLayer(medianFilteredIC, {}, + 'Median values within image collection') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# compute a single 30% percentile +p30 = filteredIC.reduce(ee.Reducer.percentile([30])) + +Map.addLayer(p30, { + 'min': 0.05, + 'max': 0.35 +}, '30%') + +percentiles = [0, 10, 20, 30, 40, 50, 60, 70, 80] + +# let's compute percentile images and add them as separate layers + +def func_sax(p): + image = filteredIC.reduce(ee.Reducer.percentile([p])) + Map.addLayer(image, { + 'min': 0.05, + 'max': 0.35 + }, p + '%') + +percentiles.map(func_sax) + + + + + + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42a Checkpoint.ipynb new file mode 100644 index 0000000..df13b68 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42a Checkpoint.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.2 Aggregating Images for Time Series\n", + "# Checkpoint: F42a\n", + "# Author: Ujaval Gandhi\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "startDate = '2019-01-01'\n", + "endDate = '2020-01-01'\n", + "yearFiltered = chirps.filter(ee.Filter.date(startDate, endDate))\n", + "\n", + "print(yearFiltered, 'Date-filtered CHIRPS images')\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42a Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42a Checkpoint.js new file mode 100644 index 0000000..a75050a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42a Checkpoint.js @@ -0,0 +1,19 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.2 Aggregating Images for Time Series +// Checkpoint: F42a +// Author: Ujaval Gandhi +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); +var startDate = '2019-01-01'; +var endDate = '2020-01-01'; +var yearFiltered = chirps.filter(ee.Filter.date(startDate, endDate)); + +print(yearFiltered, 'Date-filtered CHIRPS images'); + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42a Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42a Checkpoint.py new file mode 100644 index 0000000..da8c767 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42a Checkpoint.py @@ -0,0 +1,25 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.2 Aggregating Images for Time Series +# Checkpoint: F42a +# Author: Ujaval Gandhi +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') +startDate = '2019-01-01' +endDate = '2020-01-01' +yearFiltered = chirps.filter(ee.Filter.date(startDate, endDate)) + +print(yearFiltered, 'Date-filtered CHIRPS images') + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42b Checkpoint.ipynb new file mode 100644 index 0000000..b16d4dc --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42b Checkpoint.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.2 Aggregating Images for Time Series\n", + "# Checkpoint: F42b\n", + "# Author: Ujaval Gandhi\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "year = 2019\n", + "startDate = ee.Date.fromYMD(year, 1, 1)\n", + "\n", + "endDate = startDate.advance(1, 'year')\n", + "\n", + "yearFiltered = chirps \\\n", + " .filter(ee.Filter.date(startDate, endDate))\n", + "print(yearFiltered, 'Date-filtered CHIRPS images')\n", + "\n", + "print(startDate, 'Start date')\n", + "print(endDate, 'End date')\n", + "\n", + "print('Start date as timestamp', startDate.millis())\n", + "print('End date as timestamp', endDate.millis())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42b Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42b Checkpoint.js new file mode 100644 index 0000000..8db7c18 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42b Checkpoint.js @@ -0,0 +1,27 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.2 Aggregating Images for Time Series +// Checkpoint: F42b +// Author: Ujaval Gandhi +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); +var year = 2019; +var startDate = ee.Date.fromYMD(year, 1, 1); + +var endDate = startDate.advance(1, 'year'); + +var yearFiltered = chirps + .filter(ee.Filter.date(startDate, endDate)); +print(yearFiltered, 'Date-filtered CHIRPS images'); + +print(startDate, 'Start date'); +print(endDate, 'End date'); + +print('Start date as timestamp', startDate.millis()); +print('End date as timestamp', endDate.millis()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42b Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42b Checkpoint.py new file mode 100644 index 0000000..84abe3c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42b Checkpoint.py @@ -0,0 +1,33 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.2 Aggregating Images for Time Series +# Checkpoint: F42b +# Author: Ujaval Gandhi +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') +year = 2019 +startDate = ee.Date.fromYMD(year, 1, 1) + +endDate = startDate.advance(1, 'year') + +yearFiltered = chirps \ + .filter(ee.Filter.date(startDate, endDate)) +print(yearFiltered, 'Date-filtered CHIRPS images') + +print(startDate, 'Start date') +print(endDate, 'End date') + +print('Start date as timestamp', startDate.millis()) +print('End date as timestamp', endDate.millis()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42c Checkpoint.ipynb new file mode 100644 index 0000000..30b8b34 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42c Checkpoint.ipynb @@ -0,0 +1,152 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.2 Aggregating Images for Time Series\n", + "# Checkpoint: F42c\n", + "# Author: Ujaval Gandhi\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "year = 2019\n", + "startDate = ee.Date.fromYMD(year, 1, 1)\n", + "\n", + "endDate = startDate.advance(1, 'year')\n", + "\n", + "yearFiltered = chirps \\\n", + " .filter(ee.Filter.date(startDate, endDate))\n", + "print(yearFiltered, 'Date-filtered CHIRPS images')\n", + "\n", + "print(startDate, 'Start date')\n", + "print(endDate, 'End date')\n", + "\n", + "print('Start date as timestamp', startDate.millis())\n", + "print('End date as timestamp', endDate.millis())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Aggregate this time series to compute monthly images.\n", + "# Create a list of months\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Write a function that takes a month number\n", + "# and returns a monthly image.\n", + "def createMonthlyImage(beginningMonth):\n", + " startDate = ee.Date.fromYMD(year, beginningMonth, 1)\n", + " endDate = startDate.advance(1, 'month')\n", + " monthFiltered = yearFiltered \\\n", + " .filter(ee.Filter.date(startDate, endDate))\n", + "\n", + " # Calculate total precipitation.\n", + " total = monthFiltered.reduce(ee.Reducer.sum())\n", + " return total.set({\n", + " 'system:time_start': startDate.millis(),\n", + " 'system:time_end': endDate.millis(),\n", + " 'year': year,\n", + " 'month': beginningMonth\n", + " })\n", + "\n", + "\n", + "# map() the function on the list of months\n", + "# This creates a list with images for each month in the list\n", + "monthlyImages = months.map(createMonthlyImage)\n", + "\n", + "# Create an ee.ImageCollection.\n", + "monthlyCollection = ee.ImageCollection.fromImages(monthlyImages)\n", + "print(monthlyCollection)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42c Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42c Checkpoint.js new file mode 100644 index 0000000..35278e2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42c Checkpoint.js @@ -0,0 +1,60 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.2 Aggregating Images for Time Series +// Checkpoint: F42c +// Author: Ujaval Gandhi +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); +var year = 2019; +var startDate = ee.Date.fromYMD(year, 1, 1); + +var endDate = startDate.advance(1, 'year'); + +var yearFiltered = chirps + .filter(ee.Filter.date(startDate, endDate)); +print(yearFiltered, 'Date-filtered CHIRPS images'); + +print(startDate, 'Start date'); +print(endDate, 'End date'); + +print('Start date as timestamp', startDate.millis()); +print('End date as timestamp', endDate.millis()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Aggregate this time series to compute monthly images. +// Create a list of months +var months = ee.List.sequence(1, 12); + +// Write a function that takes a month number +// and returns a monthly image. +var createMonthlyImage = function(beginningMonth) { + var startDate = ee.Date.fromYMD(year, beginningMonth, 1); + var endDate = startDate.advance(1, 'month'); + var monthFiltered = yearFiltered + .filter(ee.Filter.date(startDate, endDate)); + + // Calculate total precipitation. + var total = monthFiltered.reduce(ee.Reducer.sum()); + return total.set({ + 'system:time_start': startDate.millis(), + 'system:time_end': endDate.millis(), + 'year': year, + 'month': beginningMonth + }); +}; + +// map() the function on the list of months +// This creates a list with images for each month in the list +var monthlyImages = months.map(createMonthlyImage); + +// Create an ee.ImageCollection. +var monthlyCollection = ee.ImageCollection.fromImages(monthlyImages); +print(monthlyCollection); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42c Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42c Checkpoint.py new file mode 100644 index 0000000..fddb275 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42c Checkpoint.py @@ -0,0 +1,66 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.2 Aggregating Images for Time Series +# Checkpoint: F42c +# Author: Ujaval Gandhi +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') +year = 2019 +startDate = ee.Date.fromYMD(year, 1, 1) + +endDate = startDate.advance(1, 'year') + +yearFiltered = chirps \ + .filter(ee.Filter.date(startDate, endDate)) +print(yearFiltered, 'Date-filtered CHIRPS images') + +print(startDate, 'Start date') +print(endDate, 'End date') + +print('Start date as timestamp', startDate.millis()) +print('End date as timestamp', endDate.millis()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Aggregate this time series to compute monthly images. +# Create a list of months +months = ee.List.sequence(1, 12) + +# Write a function that takes a month number +# and returns a monthly image. +def createMonthlyImage(beginningMonth): + startDate = ee.Date.fromYMD(year, beginningMonth, 1) + endDate = startDate.advance(1, 'month') + monthFiltered = yearFiltered \ + .filter(ee.Filter.date(startDate, endDate)) + + # Calculate total precipitation. + total = monthFiltered.reduce(ee.Reducer.sum()) + return total.set({ + 'system:time_start': startDate.millis(), + 'system:time_end': endDate.millis(), + 'year': year, + 'month': beginningMonth + }) + + +# map() the function on the list of months +# This creates a list with images for each month in the list +monthlyImages = months.map(createMonthlyImage) + +# Create an ee.ImageCollection. +monthlyCollection = ee.ImageCollection.fromImages(monthlyImages) +print(monthlyCollection) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42d Checkpoint.ipynb new file mode 100644 index 0000000..89ae947 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42d Checkpoint.ipynb @@ -0,0 +1,189 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.2 Aggregating Images for Time Series\n", + "# Checkpoint: F42d\n", + "# Author: Ujaval Gandhi\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "year = 2019\n", + "startDate = ee.Date.fromYMD(year, 1, 1)\n", + "\n", + "endDate = startDate.advance(1, 'year')\n", + "\n", + "yearFiltered = chirps \\\n", + " .filter(ee.Filter.date(startDate, endDate))\n", + "print(yearFiltered, 'Date-filtered CHIRPS images')\n", + "\n", + "print(startDate, 'Start date')\n", + "print(endDate, 'End date')\n", + "\n", + "print('Start date as timestamp', startDate.millis())\n", + "print('End date as timestamp', endDate.millis())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Aggregate this time series to compute monthly images.\n", + "# Create a list of months\n", + "months = ee.List.sequence(1, 12)\n", + "\n", + "# Write a function that takes a month number\n", + "# and returns a monthly image.\n", + "def createMonthlyImage(beginningMonth):\n", + " startDate = ee.Date.fromYMD(year, beginningMonth, 1)\n", + " endDate = startDate.advance(1, 'month')\n", + " monthFiltered = yearFiltered \\\n", + " .filter(ee.Filter.date(startDate, endDate))\n", + "\n", + " # Calculate total precipitation.\n", + " total = monthFiltered.reduce(ee.Reducer.sum())\n", + " return total.set({\n", + " 'system:time_start': startDate.millis(),\n", + " 'system:time_end': endDate.millis(),\n", + " 'year': year,\n", + " 'month': beginningMonth\n", + " })\n", + "\n", + "\n", + "# map() the function on the list of months\n", + "# This creates a list with images for each month in the list\n", + "monthlyImages = months.map(createMonthlyImage)\n", + "\n", + "# Create an ee.ImageCollection.\n", + "monthlyCollection = ee.ImageCollection.fromImages(monthlyImages)\n", + "print(monthlyCollection)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Create a point with coordinates for the city of Bengaluru, India.\n", + "point = ee.Geometry.Point(77.5946, 12.9716)\n", + "\n", + "chart = ui.Chart.image.series({\n", + " 'imageCollection': monthlyCollection,\n", + " 'region': point,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 5566,\n", + "})\n", + "print(chart)\n", + "\n", + "\n", + "chart = ui.Chart.image.series({\n", + " 'imageCollection': monthlyCollection,\n", + " 'region': point,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 5566\n", + "}).setOptions({\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " 'title': 'Monthly Rainfall at Bengaluru',\n", + " 'vAxis': {\n", + " 'title': 'Rainfall (mm)'\n", + " },\n", + " 'hAxis': {\n", + " 'title': 'Month',\n", + " 'gridlines': {\n", + " 'count': 12\n", + " }\n", + " }\n", + "})\n", + "print(chart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42d Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42d Checkpoint.js new file mode 100644 index 0000000..b0f219e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42d Checkpoint.js @@ -0,0 +1,97 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.2 Aggregating Images for Time Series +// Checkpoint: F42d +// Author: Ujaval Gandhi +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); +var year = 2019; +var startDate = ee.Date.fromYMD(year, 1, 1); + +var endDate = startDate.advance(1, 'year'); + +var yearFiltered = chirps + .filter(ee.Filter.date(startDate, endDate)); +print(yearFiltered, 'Date-filtered CHIRPS images'); + +print(startDate, 'Start date'); +print(endDate, 'End date'); + +print('Start date as timestamp', startDate.millis()); +print('End date as timestamp', endDate.millis()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Aggregate this time series to compute monthly images. +// Create a list of months +var months = ee.List.sequence(1, 12); + +// Write a function that takes a month number +// and returns a monthly image. +var createMonthlyImage = function(beginningMonth) { + var startDate = ee.Date.fromYMD(year, beginningMonth, 1); + var endDate = startDate.advance(1, 'month'); + var monthFiltered = yearFiltered + .filter(ee.Filter.date(startDate, endDate)); + + // Calculate total precipitation. + var total = monthFiltered.reduce(ee.Reducer.sum()); + return total.set({ + 'system:time_start': startDate.millis(), + 'system:time_end': endDate.millis(), + 'year': year, + 'month': beginningMonth + }); +}; + +// map() the function on the list of months +// This creates a list with images for each month in the list +var monthlyImages = months.map(createMonthlyImage); + +// Create an ee.ImageCollection. +var monthlyCollection = ee.ImageCollection.fromImages(monthlyImages); +print(monthlyCollection); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Create a point with coordinates for the city of Bengaluru, India. +var point = ee.Geometry.Point(77.5946, 12.9716); + +var chart = ui.Chart.image.series({ + imageCollection: monthlyCollection, + region: point, + reducer: ee.Reducer.mean(), + scale: 5566, +}); +print(chart); + + +var chart = ui.Chart.image.series({ + imageCollection: monthlyCollection, + region: point, + reducer: ee.Reducer.mean(), + scale: 5566 +}).setOptions({ + lineWidth: 1, + pointSize: 3, + title: 'Monthly Rainfall at Bengaluru', + vAxis: { + title: 'Rainfall (mm)' + }, + hAxis: { + title: 'Month', + gridlines: { + count: 12 + } + } +}); +print(chart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42d Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42d Checkpoint.py new file mode 100644 index 0000000..c6f220c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.2 Aggregating Time Series/F42d Checkpoint.py @@ -0,0 +1,103 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.2 Aggregating Images for Time Series +# Checkpoint: F42d +# Author: Ujaval Gandhi +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') +year = 2019 +startDate = ee.Date.fromYMD(year, 1, 1) + +endDate = startDate.advance(1, 'year') + +yearFiltered = chirps \ + .filter(ee.Filter.date(startDate, endDate)) +print(yearFiltered, 'Date-filtered CHIRPS images') + +print(startDate, 'Start date') +print(endDate, 'End date') + +print('Start date as timestamp', startDate.millis()) +print('End date as timestamp', endDate.millis()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Aggregate this time series to compute monthly images. +# Create a list of months +months = ee.List.sequence(1, 12) + +# Write a function that takes a month number +# and returns a monthly image. +def createMonthlyImage(beginningMonth): + startDate = ee.Date.fromYMD(year, beginningMonth, 1) + endDate = startDate.advance(1, 'month') + monthFiltered = yearFiltered \ + .filter(ee.Filter.date(startDate, endDate)) + + # Calculate total precipitation. + total = monthFiltered.reduce(ee.Reducer.sum()) + return total.set({ + 'system:time_start': startDate.millis(), + 'system:time_end': endDate.millis(), + 'year': year, + 'month': beginningMonth + }) + + +# map() the function on the list of months +# This creates a list with images for each month in the list +monthlyImages = months.map(createMonthlyImage) + +# Create an ee.ImageCollection. +monthlyCollection = ee.ImageCollection.fromImages(monthlyImages) +print(monthlyCollection) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Create a point with coordinates for the city of Bengaluru, India. +point = ee.Geometry.Point(77.5946, 12.9716) + +chart = ui.Chart.image.series({ + 'imageCollection': monthlyCollection, + 'region': point, + 'reducer': ee.Reducer.mean(), + 'scale': 5566, +}) +print(chart) + + +chart = ui.Chart.image.series({ + 'imageCollection': monthlyCollection, + 'region': point, + 'reducer': ee.Reducer.mean(), + 'scale': 5566 +}).setOptions({ + 'lineWidth': 1, + 'pointSize': 3, + 'title': 'Monthly Rainfall at Bengaluru', + 'vAxis': { + 'title': 'Rainfall (mm)' + }, + 'hAxis': { + 'title': 'Month', + 'gridlines': { + 'count': 12 + } + } +}) +print(chart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43a Checkpoint.ipynb new file mode 100644 index 0000000..d3d23e1 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43a Checkpoint.ipynb @@ -0,0 +1,183 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.3 Clouds and Image Compositing\n", + "# Checkpoint: F43a\n", + "# Authors: Txomin Hermosilla, Saverio Francini, Andr\u00e9a P. Nicolau,\n", + "# Michael A. Wulder, Joanne C. White, Nicholas C. Coops,\n", + "# Gherardo Chirici\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# ---------- Section 1 -----------------\n", + "\n", + "# Define the AOI.\n", + "country = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') \\\n", + " .filter(ee.Filter.equals('country_na', 'Colombia'))\n", + "\n", + "# Center the Map. The second parameter is zoom level.\n", + "Map.centerObject(country, 5)\n", + "\n", + "# Define time variables.\n", + "startDate = '2019-01-01'\n", + "endDate = '2019-12-31'\n", + "\n", + "# Load and filter the Landsat 8 collection.\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(country) \\\n", + " .filterDate(startDate, endDate)\n", + "\n", + "# Apply scaling factors.\n", + "def applyScaleFactors(image):\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + " return image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True)\n", + "\n", + "\n", + "landsat8 = landsat8.map(applyScaleFactors)\n", + "\n", + "# Create composite.\n", + "composite = landsat8.median().clip(country)\n", + "\n", + "visParams = {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 0,\n", + " 'max': 0.2\n", + "}\n", + "Map.addLayer(composite, visParams, 'L8 Composite')\n", + "\n", + "# Filter by the CLOUD_COVER property.\n", + "landsat8FiltClouds = landsat8 \\\n", + " .filterBounds(country) \\\n", + " .filterDate(startDate, endDate) \\\n", + " .filter(ee.Filter.lessThan('CLOUD_COVER', 50))\n", + "\n", + "# Create a composite from the filtered imagery.\n", + "compositeFiltClouds = landsat8FiltClouds.median().clip(country)\n", + "\n", + "Map.addLayer(compositeFiltClouds, visParams,\n", + " 'L8 Composite cloud filter')\n", + "\n", + "# Print size of collections, for comparison.\n", + "print('Size landsat8 collection', landsat8.size())\n", + "print('Size landsat8FiltClouds collection', landsat8FiltClouds.size())\n", + "\n", + "# Define the cloud mask function.\n", + "def maskSrClouds(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " return image.updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + "\n", + "\n", + "# Apply the cloud mask to the collection.\n", + "landsat8FiltMasked = landsat8FiltClouds.map(maskSrClouds)\n", + "\n", + "# Create a composite.\n", + "landsat8compositeMasked = landsat8FiltMasked.median().clip(country)\n", + "\n", + "Map.addLayer(landsat8compositeMasked, visParams, 'L8 composite masked')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43a Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43a Checkpoint.js new file mode 100644 index 0000000..14c1377 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43a Checkpoint.js @@ -0,0 +1,90 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.3 Clouds and Image Compositing +// Checkpoint: F43a +// Authors: Txomin Hermosilla, Saverio Francini, Andréa P. Nicolau, +// Michael A. Wulder, Joanne C. White, Nicholas C. Coops, +// Gherardo Chirici +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ---------- Section 1 ----------------- + +// Define the AOI. +var country = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + .filter(ee.Filter.equals('country_na', 'Colombia')); + +// Center the Map. The second parameter is zoom level. +Map.centerObject(country, 5); + +// Define time variables. +var startDate = '2019-01-01'; +var endDate = '2019-12-31'; + +// Load and filter the Landsat 8 collection. +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(country) + .filterDate(startDate, endDate); + +// Apply scaling factors. +function applyScaleFactors(image) { + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + return image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true); +} + +landsat8 = landsat8.map(applyScaleFactors); + +// Create composite. +var composite = landsat8.median().clip(country); + +var visParams = { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 0, + max: 0.2 +}; +Map.addLayer(composite, visParams, 'L8 Composite'); + +// Filter by the CLOUD_COVER property. +var landsat8FiltClouds = landsat8 + .filterBounds(country) + .filterDate(startDate, endDate) + .filter(ee.Filter.lessThan('CLOUD_COVER', 50)); + +// Create a composite from the filtered imagery. +var compositeFiltClouds = landsat8FiltClouds.median().clip(country); + +Map.addLayer(compositeFiltClouds, visParams, + 'L8 Composite cloud filter'); + +// Print size of collections, for comparison. +print('Size landsat8 collection', landsat8.size()); +print('Size landsat8FiltClouds collection', landsat8FiltClouds.size()); + +// Define the cloud mask function. +function maskSrClouds(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + return image.updateMask(qaMask) + .updateMask(saturationMask); +} + +// Apply the cloud mask to the collection. +var landsat8FiltMasked = landsat8FiltClouds.map(maskSrClouds); + +// Create a composite. +var landsat8compositeMasked = landsat8FiltMasked.median().clip(country); + +Map.addLayer(landsat8compositeMasked, visParams, 'L8 composite masked'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43a Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43a Checkpoint.py new file mode 100644 index 0000000..fd5819b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43a Checkpoint.py @@ -0,0 +1,96 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.3 Clouds and Image Compositing +# Checkpoint: F43a +# Authors: Txomin Hermosilla, Saverio Francini, Andréa P. Nicolau, +# Michael A. Wulder, Joanne C. White, Nicholas C. Coops, +# Gherardo Chirici +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# ---------- Section 1 ----------------- + +# Define the AOI. +country = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') \ + .filter(ee.Filter.equals('country_na', 'Colombia')) + +# Center the Map. The second parameter is zoom level. +Map.centerObject(country, 5) + +# Define time variables. +startDate = '2019-01-01' +endDate = '2019-12-31' + +# Load and filter the Landsat 8 collection. +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(country) \ + .filterDate(startDate, endDate) + +# Apply scaling factors. +def applyScaleFactors(image): + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + return image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) + + +landsat8 = landsat8.map(applyScaleFactors) + +# Create composite. +composite = landsat8.median().clip(country) + +visParams = { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 0, + 'max': 0.2 +} +Map.addLayer(composite, visParams, 'L8 Composite') + +# Filter by the CLOUD_COVER property. +landsat8FiltClouds = landsat8 \ + .filterBounds(country) \ + .filterDate(startDate, endDate) \ + .filter(ee.Filter.lessThan('CLOUD_COVER', 50)) + +# Create a composite from the filtered imagery. +compositeFiltClouds = landsat8FiltClouds.median().clip(country) + +Map.addLayer(compositeFiltClouds, visParams, + 'L8 Composite cloud filter') + +# Print size of collections, for comparison. +print('Size landsat8 collection', landsat8.size()) +print('Size landsat8FiltClouds collection', landsat8FiltClouds.size()) + +# Define the cloud mask function. +def maskSrClouds(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + return image.updateMask(qaMask) \ + .updateMask(saturationMask) + + +# Apply the cloud mask to the collection. +landsat8FiltMasked = landsat8FiltClouds.map(maskSrClouds) + +# Create a composite. +landsat8compositeMasked = landsat8FiltMasked.median().clip(country) + +Map.addLayer(landsat8compositeMasked, visParams, 'L8 composite masked') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43b Checkpoint.ipynb new file mode 100644 index 0000000..5404ab1 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43b Checkpoint.ipynb @@ -0,0 +1,251 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.3 Clouds and Image Compositing\n", + "# Checkpoint: F43b\n", + "# Authors: Txomin Hermosilla, Saverio Francini, Andr\u00e9a P. Nicolau,\n", + "# Michael A. Wulder, Joanne C. White, Nicholas C. Coops,\n", + "# Gherardo Chirici\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# ---------- Section 1 -----------------\n", + "\n", + "# Define the AOI.\n", + "country = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') \\\n", + " .filter(ee.Filter.equals('country_na', 'Colombia'))\n", + "\n", + "# Center the Map. The second parameter is zoom level.\n", + "Map.centerObject(country, 5)\n", + "\n", + "# Define time variables.\n", + "startDate = '2019-01-01'\n", + "endDate = '2019-12-31'\n", + "\n", + "# Load and filter the Landsat 8 collection.\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(country) \\\n", + " .filterDate(startDate, endDate)\n", + "\n", + "# Apply scaling factors.\n", + "def applyScaleFactors(image):\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + " return image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True)\n", + "\n", + "\n", + "landsat8 = landsat8.map(applyScaleFactors)\n", + "\n", + "# Create composite.\n", + "composite = landsat8.median().clip(country)\n", + "\n", + "visParams = {\n", + " 'bands': ['SR_B4', 'SR_B3', 'SR_B2'],\n", + " 'min': 0,\n", + " 'max': 0.2\n", + "}\n", + "Map.addLayer(composite, visParams, 'L8 Composite')\n", + "\n", + "# Filter by the CLOUD_COVER property.\n", + "landsat8FiltClouds = landsat8 \\\n", + " .filterBounds(country) \\\n", + " .filterDate(startDate, endDate) \\\n", + " .filter(ee.Filter.lessThan('CLOUD_COVER', 50))\n", + "\n", + "# Create a composite from the filtered imagery.\n", + "compositeFiltClouds = landsat8FiltClouds.median().clip(country)\n", + "\n", + "Map.addLayer(compositeFiltClouds, visParams,\n", + " 'L8 Composite cloud filter')\n", + "\n", + "# Print size of collections, for comparison.\n", + "print('Size landsat8 collection', landsat8.size())\n", + "print('Size landsat8FiltClouds collection', landsat8FiltClouds.size())\n", + "\n", + "# Define the cloud mask function.\n", + "def maskSrClouds(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " return image.updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + "\n", + "\n", + "# Apply the cloud mask to the collection.\n", + "landsat8FiltMasked = landsat8FiltClouds.map(maskSrClouds)\n", + "\n", + "# Create a composite.\n", + "landsat8compositeMasked = landsat8FiltMasked.median().clip(country)\n", + "\n", + "Map.addLayer(landsat8compositeMasked, visParams, 'L8 composite masked')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# ---------- Section 2 -----------------\n", + "\n", + "# Define Landsat 7 Level 2, Collection 2, Tier 1 collection.\n", + "landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2')\n", + "\n", + "# Scaling factors for L7.\n", + "def applyScaleFactorsL7(image):\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBand = image.select('ST_B6').multiply(0.00341802).add(\n", + " 149.0)\n", + " return image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBand, None, True)\n", + "\n", + "\n", + "# Filter collection, apply cloud mask, and scaling factors.\n", + "landsat7FiltMasked = landsat7 \\\n", + " .filterBounds(country) \\\n", + " .filterDate(startDate, endDate) \\\n", + " .filter(ee.Filter.lessThan('CLOUD_COVER', 50)) \\\n", + " .map(maskSrClouds) \\\n", + " .map(applyScaleFactorsL7)\n", + "\n", + "# Create composite.\n", + "landsat7compositeMasked = landsat7FiltMasked \\\n", + " .median() \\\n", + " .clip(country)\n", + "\n", + "Map.addLayer(landsat7compositeMasked,\n", + " {\n", + " 'bands': ['SR_B3', 'SR_B2', 'SR_B1'],\n", + " 'min': 0,\n", + " 'max': 0.2\n", + " },\n", + " 'L7 composite masked')\n", + "\n", + "# Since Landsat 7 and 8 have different band designations,\n", + "# let's create a function to rename L7 bands to match to L8.\n", + "def rename(image):\n", + " return image.select(\n", + " ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'],\n", + " ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'])\n", + "\n", + "\n", + "# Apply the rename function.\n", + "landsat7FiltMaskedRenamed = landsat7FiltMasked.map(rename)\n", + "\n", + "# Merge Landsat collections.\n", + "landsat78 = landsat7FiltMaskedRenamed \\\n", + " .merge(landsat8FiltMasked.select(\n", + " ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7']))\n", + "\n", + "def func_fpu(img):\n", + " return img.toFloat() \\\n", + " .map(func_fpu)\n", + "\n", + "\n", + "\n", + "print('Merged collections', landsat78)\n", + "\n", + "# Create Landsat 7 and 8 image composite and add to the Map.\n", + "landsat78composite = landsat78.median().clip(country)\n", + "Map.addLayer(landsat78composite, visParams, 'L7 and L8 composite')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43b Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43b Checkpoint.js new file mode 100644 index 0000000..cd7628c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43b Checkpoint.js @@ -0,0 +1,154 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.3 Clouds and Image Compositing +// Checkpoint: F43b +// Authors: Txomin Hermosilla, Saverio Francini, Andréa P. Nicolau, +// Michael A. Wulder, Joanne C. White, Nicholas C. Coops, +// Gherardo Chirici +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ---------- Section 1 ----------------- + +// Define the AOI. +var country = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') + .filter(ee.Filter.equals('country_na', 'Colombia')); + +// Center the Map. The second parameter is zoom level. +Map.centerObject(country, 5); + +// Define time variables. +var startDate = '2019-01-01'; +var endDate = '2019-12-31'; + +// Load and filter the Landsat 8 collection. +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(country) + .filterDate(startDate, endDate); + +// Apply scaling factors. +function applyScaleFactors(image) { + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + return image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true); +} + +landsat8 = landsat8.map(applyScaleFactors); + +// Create composite. +var composite = landsat8.median().clip(country); + +var visParams = { + bands: ['SR_B4', 'SR_B3', 'SR_B2'], + min: 0, + max: 0.2 +}; +Map.addLayer(composite, visParams, 'L8 Composite'); + +// Filter by the CLOUD_COVER property. +var landsat8FiltClouds = landsat8 + .filterBounds(country) + .filterDate(startDate, endDate) + .filter(ee.Filter.lessThan('CLOUD_COVER', 50)); + +// Create a composite from the filtered imagery. +var compositeFiltClouds = landsat8FiltClouds.median().clip(country); + +Map.addLayer(compositeFiltClouds, visParams, + 'L8 Composite cloud filter'); + +// Print size of collections, for comparison. +print('Size landsat8 collection', landsat8.size()); +print('Size landsat8FiltClouds collection', landsat8FiltClouds.size()); + +// Define the cloud mask function. +function maskSrClouds(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + return image.updateMask(qaMask) + .updateMask(saturationMask); +} + +// Apply the cloud mask to the collection. +var landsat8FiltMasked = landsat8FiltClouds.map(maskSrClouds); + +// Create a composite. +var landsat8compositeMasked = landsat8FiltMasked.median().clip(country); + +Map.addLayer(landsat8compositeMasked, visParams, 'L8 composite masked'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// ---------- Section 2 ----------------- + +// Define Landsat 7 Level 2, Collection 2, Tier 1 collection. +var landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2'); + +// Scaling factors for L7. +function applyScaleFactorsL7(image) { + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0); + return image.addBands(opticalBands, null, true) + .addBands(thermalBand, null, true); +} + +// Filter collection, apply cloud mask, and scaling factors. +var landsat7FiltMasked = landsat7 + .filterBounds(country) + .filterDate(startDate, endDate) + .filter(ee.Filter.lessThan('CLOUD_COVER', 50)) + .map(maskSrClouds) + .map(applyScaleFactorsL7); + +// Create composite. +var landsat7compositeMasked = landsat7FiltMasked + .median() + .clip(country); + +Map.addLayer(landsat7compositeMasked, + { + bands: ['SR_B3', 'SR_B2', 'SR_B1'], + min: 0, + max: 0.2 + }, + 'L7 composite masked'); + +// Since Landsat 7 and 8 have different band designations, +// let's create a function to rename L7 bands to match to L8. +function rename(image) { + return image.select( + ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'], + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7']); +} + +// Apply the rename function. +var landsat7FiltMaskedRenamed = landsat7FiltMasked.map(rename); + +// Merge Landsat collections. +var landsat78 = landsat7FiltMaskedRenamed + .merge(landsat8FiltMasked.select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'])) + .map(function(img) { + return img.toFloat(); + }); +print('Merged collections', landsat78); + +// Create Landsat 7 and 8 image composite and add to the Map. +var landsat78composite = landsat78.median().clip(country); +Map.addLayer(landsat78composite, visParams, 'L7 and L8 composite'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43b Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43b Checkpoint.py new file mode 100644 index 0000000..5180c33 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43b Checkpoint.py @@ -0,0 +1,164 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.3 Clouds and Image Compositing +# Checkpoint: F43b +# Authors: Txomin Hermosilla, Saverio Francini, Andréa P. Nicolau, +# Michael A. Wulder, Joanne C. White, Nicholas C. Coops, +# Gherardo Chirici +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# ---------- Section 1 ----------------- + +# Define the AOI. +country = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') \ + .filter(ee.Filter.equals('country_na', 'Colombia')) + +# Center the Map. The second parameter is zoom level. +Map.centerObject(country, 5) + +# Define time variables. +startDate = '2019-01-01' +endDate = '2019-12-31' + +# Load and filter the Landsat 8 collection. +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(country) \ + .filterDate(startDate, endDate) + +# Apply scaling factors. +def applyScaleFactors(image): + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + return image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) + + +landsat8 = landsat8.map(applyScaleFactors) + +# Create composite. +composite = landsat8.median().clip(country) + +visParams = { + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], + 'min': 0, + 'max': 0.2 +} +Map.addLayer(composite, visParams, 'L8 Composite') + +# Filter by the CLOUD_COVER property. +landsat8FiltClouds = landsat8 \ + .filterBounds(country) \ + .filterDate(startDate, endDate) \ + .filter(ee.Filter.lessThan('CLOUD_COVER', 50)) + +# Create a composite from the filtered imagery. +compositeFiltClouds = landsat8FiltClouds.median().clip(country) + +Map.addLayer(compositeFiltClouds, visParams, + 'L8 Composite cloud filter') + +# Print size of collections, for comparison. +print('Size landsat8 collection', landsat8.size()) +print('Size landsat8FiltClouds collection', landsat8FiltClouds.size()) + +# Define the cloud mask function. +def maskSrClouds(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + return image.updateMask(qaMask) \ + .updateMask(saturationMask) + + +# Apply the cloud mask to the collection. +landsat8FiltMasked = landsat8FiltClouds.map(maskSrClouds) + +# Create a composite. +landsat8compositeMasked = landsat8FiltMasked.median().clip(country) + +Map.addLayer(landsat8compositeMasked, visParams, 'L8 composite masked') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# ---------- Section 2 ----------------- + +# Define Landsat 7 Level 2, Collection 2, Tier 1 collection. +landsat7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') + +# Scaling factors for L7. +def applyScaleFactorsL7(image): + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBand = image.select('ST_B6').multiply(0.00341802).add( + 149.0) + return image.addBands(opticalBands, None, True) \ + .addBands(thermalBand, None, True) + + +# Filter collection, apply cloud mask, and scaling factors. +landsat7FiltMasked = landsat7 \ + .filterBounds(country) \ + .filterDate(startDate, endDate) \ + .filter(ee.Filter.lessThan('CLOUD_COVER', 50)) \ + .map(maskSrClouds) \ + .map(applyScaleFactorsL7) + +# Create composite. +landsat7compositeMasked = landsat7FiltMasked \ + .median() \ + .clip(country) + +Map.addLayer(landsat7compositeMasked, + { + 'bands': ['SR_B3', 'SR_B2', 'SR_B1'], + 'min': 0, + 'max': 0.2 + }, + 'L7 composite masked') + +# Since Landsat 7 and 8 have different band designations, +# let's create a function to rename L7 bands to match to L8. +def rename(image): + return image.select( + ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'], + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7']) + + +# Apply the rename function. +landsat7FiltMaskedRenamed = landsat7FiltMasked.map(rename) + +# Merge Landsat collections. +landsat78 = landsat7FiltMaskedRenamed \ + .merge(landsat8FiltMasked.select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'])) + +def func_fpu(img): + return img.toFloat() \ + .map(func_fpu) + + + +print('Merged collections', landsat78) + +# Create Landsat 7 and 8 image composite and add to the Map. +landsat78composite = landsat78.median().clip(country) +Map.addLayer(landsat78composite, visParams, 'L7 and L8 composite') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43c Checkpoint.ipynb new file mode 100644 index 0000000..7653e4f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43c Checkpoint.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.3 Clouds and Image Compositing\n", + "# Checkpoint: F43c\n", + "# Authors: Txomin Hermosilla, Saverio Francini, Andr\u00e9a P. Nicolau,\n", + "# Michael A. Wulder, Joanne C. White, Nicholas C. Coops,\n", + "# Gherardo Chirici\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Access the GEE-BAP interface at the following link,\n", + "# by copy-pasting the line below into your browser.\n", + "\n", + "#\n", + "'https':#code.earthengine.google.com/?accept_repo=users/sfrancini/bap\n", + "\n", + "This will create a repository on your Earth Engine account.\n", + "The repository will appear in the Reader section of the Scripts panel.\n", + "\n", + "To access the user interface, open the \u201cui\u201d script and click Run.\n", + "#\n", + "\n", + "# You can find more information about GEE-BAP at:\n", + "# https:#github.com/saveriofrancini/bap\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43c Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43c Checkpoint.js new file mode 100644 index 0000000..0653c93 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43c Checkpoint.js @@ -0,0 +1,27 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.3 Clouds and Image Compositing +// Checkpoint: F43c +// Authors: Txomin Hermosilla, Saverio Francini, Andréa P. Nicolau, +// Michael A. Wulder, Joanne C. White, Nicholas C. Coops, +// Gherardo Chirici +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Access the GEE-BAP interface at the following link, +// by copy-pasting the line below into your browser. + +/* +https://code.earthengine.google.com/?accept_repo=users/sfrancini/bap + +This will create a repository on your Earth Engine account. +The repository will appear in the Reader section of the Scripts panel. + +To access the user interface, open the “ui” script and click Run. +*/ + +// You can find more information about GEE-BAP at: +// https://github.com/saveriofrancini/bap + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43c Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43c Checkpoint.py new file mode 100644 index 0000000..c948352 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43c Checkpoint.py @@ -0,0 +1,33 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.3 Clouds and Image Compositing +# Checkpoint: F43c +# Authors: Txomin Hermosilla, Saverio Francini, Andréa P. Nicolau, +# Michael A. Wulder, Joanne C. White, Nicholas C. Coops, +# Gherardo Chirici +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Access the GEE-BAP interface at the following link, +# by copy-pasting the line below into your browser. + +# +'https':#code.earthengine.google.com/?accept_repo=users/sfrancini/bap + +This will create a repository on your Earth Engine account. +The repository will appear in the Reader section of the Scripts panel. + +To access the user interface, open the “ui” script and click Run. +# + +# You can find more information about GEE-BAP at: +# https:#github.com/saveriofrancini/bap + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43d Checkpoint.ipynb new file mode 100644 index 0000000..369a375 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43d Checkpoint.ipynb @@ -0,0 +1,142 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.3 Clouds and Image Compositing\n", + "# Checkpoint: F43d\n", + "# Authors: Txomin Hermosilla, Saverio Francini, Andr\u00e9a P. Nicolau,\n", + "# Michael A. Wulder, Joanne C. White, Nicholas C. Coops,\n", + "# Gherardo Chirici\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define required parameters.\n", + "targetDay = '06-01'\n", + "daysRange = 75\n", + "cloudsTh = 70\n", + "SLCoffPenalty = 0.7\n", + "opacityScoreMin = 0.2\n", + "opacityScoreMax = 0.3\n", + "cloudDistMax = 1500\n", + "despikeTh = 0.65\n", + "despikeNbands = 3\n", + "startYear = 2015\n", + "endYear = 2017\n", + "\n", + "# Define study area.\n", + "worldCountries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')\n", + "colombia = worldCountries.filter(ee.Filter.eq('country_na',\n", + " 'Colombia'))\n", + "\n", + "# Load the bap library.\n", + "library = require('users/sfrancini/bap:library')\n", + "\n", + "# Calculate BAP.\n", + "BAPCS = library.BAP(None, targetDay, daysRange, cloudsTh,\n", + " SLCoffPenalty, opacityScoreMin, opacityScoreMax, cloudDistMax)\n", + "\n", + "# Despike the collection.\n", + "BAPCS = library.despikeCollection(despikeTh, despikeNbands, BAPCS,\n", + " 1984, 2021, True)\n", + "\n", + "# Infill datagaps.\n", + "BAPCS = library.infill(BAPCS, 1984, 2021, False, True)\n", + "\n", + "# Visualize the image.\n", + "Map.centerObject(colombia, 5)\n", + "library.ShowCollection(BAPCS, startYear, endYear, colombia, False,\n", + " None)\n", + "library.AddSLider(startYear, endYear)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43d Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43d Checkpoint.js new file mode 100644 index 0000000..f8f95b7 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43d Checkpoint.js @@ -0,0 +1,49 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.3 Clouds and Image Compositing +// Checkpoint: F43d +// Authors: Txomin Hermosilla, Saverio Francini, Andréa P. Nicolau, +// Michael A. Wulder, Joanne C. White, Nicholas C. Coops, +// Gherardo Chirici +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define required parameters. +var targetDay = '06-01'; +var daysRange = 75; +var cloudsTh = 70; +var SLCoffPenalty = 0.7; +var opacityScoreMin = 0.2; +var opacityScoreMax = 0.3; +var cloudDistMax = 1500; +var despikeTh = 0.65; +var despikeNbands = 3; +var startYear = 2015; +var endYear = 2017; + +// Define study area. +var worldCountries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017'); +var colombia = worldCountries.filter(ee.Filter.eq('country_na', + 'Colombia')); + +// Load the bap library. +var library = require('users/sfrancini/bap:library'); + +// Calculate BAP. +var BAPCS = library.BAP(null, targetDay, daysRange, cloudsTh, + SLCoffPenalty, opacityScoreMin, opacityScoreMax, cloudDistMax); + +// Despike the collection. +BAPCS = library.despikeCollection(despikeTh, despikeNbands, BAPCS, + 1984, 2021, true); + +// Infill datagaps. +BAPCS = library.infill(BAPCS, 1984, 2021, false, true); + +// Visualize the image. +Map.centerObject(colombia, 5); +library.ShowCollection(BAPCS, startYear, endYear, colombia, false, + null); +library.AddSLider(startYear, endYear); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43d Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43d Checkpoint.py new file mode 100644 index 0000000..3dd26c4 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.3 Clouds and Image Compositing/F43d Checkpoint.py @@ -0,0 +1,55 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.3 Clouds and Image Compositing +# Checkpoint: F43d +# Authors: Txomin Hermosilla, Saverio Francini, Andréa P. Nicolau, +# Michael A. Wulder, Joanne C. White, Nicholas C. Coops, +# Gherardo Chirici +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define required parameters. +targetDay = '06-01' +daysRange = 75 +cloudsTh = 70 +SLCoffPenalty = 0.7 +opacityScoreMin = 0.2 +opacityScoreMax = 0.3 +cloudDistMax = 1500 +despikeTh = 0.65 +despikeNbands = 3 +startYear = 2015 +endYear = 2017 + +# Define study area. +worldCountries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') +colombia = worldCountries.filter(ee.Filter.eq('country_na', + 'Colombia')) + +# Load the bap library. +library = require('users/sfrancini/bap:library') + +# Calculate BAP. +BAPCS = library.BAP(None, targetDay, daysRange, cloudsTh, + SLCoffPenalty, opacityScoreMin, opacityScoreMax, cloudDistMax) + +# Despike the collection. +BAPCS = library.despikeCollection(despikeTh, despikeNbands, BAPCS, + 1984, 2021, True) + +# Infill datagaps. +BAPCS = library.infill(BAPCS, 1984, 2021, False, True) + +# Visualize the image. +Map.centerObject(colombia, 5) +library.ShowCollection(BAPCS, startYear, endYear, colombia, False, + None) +library.AddSLider(startYear, endYear) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44a Checkpoint.ipynb new file mode 100644 index 0000000..678a416 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44a Checkpoint.ipynb @@ -0,0 +1,138 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.4 Change Detection\n", + "# Checkpoint: F44a\n", + "# Author: Karis Tenneson, John Dilger, Crystal Wespestad, Brian Zutta,\n", + "# Andr\u00e9a P Nicolau, Karen Dyson\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .select(\n", + " ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'],\n", + " ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']\n", + " )\n", + "\n", + "point = ee.Geometry.Point([-123.64, 42.96])\n", + "Map.centerObject(point, 11)\n", + "\n", + "preImage = landsat8 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2013-06-01', '2013-06-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "\n", + "postImage = landsat8 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2020-06-01', '2020-06-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "\n", + "visParam = {\n", + " 'bands': ['swir2', 'nir', 'red'],\n", + " 'min': 7750,\n", + " 'max': 22200\n", + "}\n", + "Map.addLayer(preImage, visParam, 'pre')\n", + "Map.addLayer(postImage, visParam, 'post')\n", + "\n", + "# Calculate NBR.\n", + "nbrPre = preImage.normalizedDifference(['nir', 'swir2']) \\\n", + " .rename('nbr_pre')\n", + "nbrPost = postImage.normalizedDifference(['nir', 'swir2']) \\\n", + " .rename('nbr_post')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44a Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44a Checkpoint.js new file mode 100644 index 0000000..2be879c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44a Checkpoint.js @@ -0,0 +1,45 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.4 Change Detection +// Checkpoint: F44a +// Author: Karis Tenneson, John Dilger, Crystal Wespestad, Brian Zutta, +// Andréa P Nicolau, Karen Dyson +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'] + ); + +var point = ee.Geometry.Point([-123.64, 42.96]); +Map.centerObject(point, 11); + +var preImage = landsat8 + .filterBounds(point) + .filterDate('2013-06-01', '2013-06-30') + .sort('CLOUD_COVER', true) + .first(); + +var postImage = landsat8 + .filterBounds(point) + .filterDate('2020-06-01', '2020-06-30') + .sort('CLOUD_COVER', true) + .first(); + +var visParam = { + 'bands': ['swir2', 'nir', 'red'], + 'min': 7750, + 'max': 22200 +}; +Map.addLayer(preImage, visParam, 'pre'); +Map.addLayer(postImage, visParam, 'post'); + +// Calculate NBR. +var nbrPre = preImage.normalizedDifference(['nir', 'swir2']) + .rename('nbr_pre'); +var nbrPost = postImage.normalizedDifference(['nir', 'swir2']) + .rename('nbr_post'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44a Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44a Checkpoint.py new file mode 100644 index 0000000..dfc2c25 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44a Checkpoint.py @@ -0,0 +1,51 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.4 Change Detection +# Checkpoint: F44a +# Author: Karis Tenneson, John Dilger, Crystal Wespestad, Brian Zutta, +# Andréa P Nicolau, Karen Dyson +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'] + ) + +point = ee.Geometry.Point([-123.64, 42.96]) +Map.centerObject(point, 11) + +preImage = landsat8 \ + .filterBounds(point) \ + .filterDate('2013-06-01', '2013-06-30') \ + .sort('CLOUD_COVER', True) \ + .first() + +postImage = landsat8 \ + .filterBounds(point) \ + .filterDate('2020-06-01', '2020-06-30') \ + .sort('CLOUD_COVER', True) \ + .first() + +visParam = { + 'bands': ['swir2', 'nir', 'red'], + 'min': 7750, + 'max': 22200 +} +Map.addLayer(preImage, visParam, 'pre') +Map.addLayer(postImage, visParam, 'post') + +# Calculate NBR. +nbrPre = preImage.normalizedDifference(['nir', 'swir2']) \ + .rename('nbr_pre') +nbrPost = postImage.normalizedDifference(['nir', 'swir2']) \ + .rename('nbr_post') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44b Checkpoint.ipynb new file mode 100644 index 0000000..f3e6bbe --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44b Checkpoint.ipynb @@ -0,0 +1,175 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.4 Change Detection\n", + "# Checkpoint: F44b\n", + "# Author: Karis Tenneson, John Dilger, Crystal Wespestad, Brian Zutta,\n", + "# Andr\u00e9a P Nicolau, Karen Dyson\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .select(\n", + " ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'],\n", + " ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']\n", + " )\n", + "\n", + "point = ee.Geometry.Point([-123.64, 42.96])\n", + "Map.centerObject(point, 11)\n", + "\n", + "preImage = landsat8 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2013-06-01', '2013-06-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "\n", + "postImage = landsat8 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2020-06-01', '2020-06-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "\n", + "visParam = {\n", + " 'bands': ['swir2', 'nir', 'red'],\n", + " 'min': 7750,\n", + " 'max': 22200\n", + "}\n", + "Map.addLayer(preImage, visParam, 'pre')\n", + "Map.addLayer(postImage, visParam, 'post')\n", + "\n", + "# Calculate NBR.\n", + "nbrPre = preImage.normalizedDifference(['nir', 'swir2']) \\\n", + " .rename('nbr_pre')\n", + "nbrPost = postImage.normalizedDifference(['nir', 'swir2']) \\\n", + " .rename('nbr_post')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# 2-date change.\n", + "diff = nbrPost.subtract(nbrPre).rename('change')\n", + "\n", + "palette = [\n", + " '011959', '0E365E', '1D5561', '3E6C55', '687B3E',\n", + " '9B882E', 'D59448', 'F9A380', 'FDB7BD', 'FACCFA'\n", + "]\n", + "visParams = {\n", + " 'palette': palette,\n", + " 'min': -0.2,\n", + " 'max': 0.2\n", + "}\n", + "Map.addLayer(diff, visParams, 'change')\n", + "\n", + "# Classify change\n", + "thresholdGain = 0.10\n", + "thresholdLoss = -0.10\n", + "\n", + "diffClassified = ee.Image(0)\n", + "\n", + "diffClassified = diffClassified.where(diff.lte(thresholdLoss), 2)\n", + "diffClassified = diffClassified.where(diff.gte(thresholdGain), 1)\n", + "\n", + "changeVis = {\n", + " 'palette': 'fcffc8,2659eb,fa1373',\n", + " 'min': 0,\n", + " 'max': 2\n", + "}\n", + "\n", + "Map.addLayer(diffClassified.selfMask(),\n", + " changeVis,\n", + " 'change classified by threshold')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44b Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44b Checkpoint.js new file mode 100644 index 0000000..0b4ccf6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44b Checkpoint.js @@ -0,0 +1,83 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.4 Change Detection +// Checkpoint: F44b +// Author: Karis Tenneson, John Dilger, Crystal Wespestad, Brian Zutta, +// Andréa P Nicolau, Karen Dyson +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'] + ); + +var point = ee.Geometry.Point([-123.64, 42.96]); +Map.centerObject(point, 11); + +var preImage = landsat8 + .filterBounds(point) + .filterDate('2013-06-01', '2013-06-30') + .sort('CLOUD_COVER', true) + .first(); + +var postImage = landsat8 + .filterBounds(point) + .filterDate('2020-06-01', '2020-06-30') + .sort('CLOUD_COVER', true) + .first(); + +var visParam = { + 'bands': ['swir2', 'nir', 'red'], + 'min': 7750, + 'max': 22200 +}; +Map.addLayer(preImage, visParam, 'pre'); +Map.addLayer(postImage, visParam, 'post'); + +// Calculate NBR. +var nbrPre = preImage.normalizedDifference(['nir', 'swir2']) + .rename('nbr_pre'); +var nbrPost = postImage.normalizedDifference(['nir', 'swir2']) + .rename('nbr_post'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// 2-date change. +var diff = nbrPost.subtract(nbrPre).rename('change'); + +var palette = [ + '011959', '0E365E', '1D5561', '3E6C55', '687B3E', + '9B882E', 'D59448', 'F9A380', 'FDB7BD', 'FACCFA' +]; +var visParams = { + palette: palette, + min: -0.2, + max: 0.2 +}; +Map.addLayer(diff, visParams, 'change'); + +// Classify change +var thresholdGain = 0.10; +var thresholdLoss = -0.10; + +var diffClassified = ee.Image(0); + +diffClassified = diffClassified.where(diff.lte(thresholdLoss), 2); +diffClassified = diffClassified.where(diff.gte(thresholdGain), 1); + +var changeVis = { + palette: 'fcffc8,2659eb,fa1373', + min: 0, + max: 2 +}; + +Map.addLayer(diffClassified.selfMask(), + changeVis, + 'change classified by threshold'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44b Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44b Checkpoint.py new file mode 100644 index 0000000..571b4fa --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/F44b Checkpoint.py @@ -0,0 +1,89 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.4 Change Detection +# Checkpoint: F44b +# Author: Karis Tenneson, John Dilger, Crystal Wespestad, Brian Zutta, +# Andréa P Nicolau, Karen Dyson +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'] + ) + +point = ee.Geometry.Point([-123.64, 42.96]) +Map.centerObject(point, 11) + +preImage = landsat8 \ + .filterBounds(point) \ + .filterDate('2013-06-01', '2013-06-30') \ + .sort('CLOUD_COVER', True) \ + .first() + +postImage = landsat8 \ + .filterBounds(point) \ + .filterDate('2020-06-01', '2020-06-30') \ + .sort('CLOUD_COVER', True) \ + .first() + +visParam = { + 'bands': ['swir2', 'nir', 'red'], + 'min': 7750, + 'max': 22200 +} +Map.addLayer(preImage, visParam, 'pre') +Map.addLayer(postImage, visParam, 'post') + +# Calculate NBR. +nbrPre = preImage.normalizedDifference(['nir', 'swir2']) \ + .rename('nbr_pre') +nbrPost = postImage.normalizedDifference(['nir', 'swir2']) \ + .rename('nbr_post') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# 2-date change. +diff = nbrPost.subtract(nbrPre).rename('change') + +palette = [ + '011959', '0E365E', '1D5561', '3E6C55', '687B3E', + '9B882E', 'D59448', 'F9A380', 'FDB7BD', 'FACCFA' +] +visParams = { + 'palette': palette, + 'min': -0.2, + 'max': 0.2 +} +Map.addLayer(diff, visParams, 'change') + +# Classify change +thresholdGain = 0.10 +thresholdLoss = -0.10 + +diffClassified = ee.Image(0) + +diffClassified = diffClassified.where(diff.lte(thresholdLoss), 2) +diffClassified = diffClassified.where(diff.gte(thresholdGain), 1) + +changeVis = { + 'palette': 'fcffc8,2659eb,fa1373', + 'min': 0, + 'max': 2 +} + +Map.addLayer(diffClassified.selfMask(), + changeVis, + 'change classified by threshold') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/incheon.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/incheon.ipynb new file mode 100644 index 0000000..2a389bb --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/incheon.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "point = ee.Geometry.Point([126.46560976562499, 37.520194763339695]),\n", + " preIncheon = {\"opacity\":1,\"bands\":[\"red\",\"nir1\",\"green\"],\"min\":3.9,\"max\":143.1,\"gamma\":0.711},\n", + " postIncheon = {\"opacity\":1,\"bands\":[\"red\",\"nir\",\"green\"],\"min\":7196.82,\"max\":16980.18,\"gamma\":0.814}\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .select(\n", + " ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'],\n", + " ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'])\n", + "landsat3 = ee.ImageCollection('LANDSAT/LM03/C01/T2') \\\n", + " .select(['B4', 'B5', 'B6', 'B7'], ['green', 'red', 'nir1', 'nir2'])\n", + "\n", + "preImage = landsat3 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('1981-01-01', '1981-12-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "postImage = landsat8 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2020-01-01', '2020-12-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "\n", + "Map.centerObject(point, 10)\n", + "Map.addLayer(preImage, preIncheon, 'pre')\n", + "Map.addLayer(postImage, postIncheon, 'post')" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/incheon.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/incheon.js new file mode 100644 index 0000000..0cf14e3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/incheon.js @@ -0,0 +1,26 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var point = /* color: #ffc82d */ee.Geometry.Point([126.46560976562499, 37.520194763339695]), + preIncheon = {"opacity":1,"bands":["red","nir1","green"],"min":3.9,"max":143.1,"gamma":0.711}, + postIncheon = {"opacity":1,"bands":["red","nir","green"],"min":7196.82,"max":16980.18,"gamma":0.814}; +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']); +var landsat3 = ee.ImageCollection('LANDSAT/LM03/C01/T2') + .select(['B4', 'B5', 'B6', 'B7'], ['green', 'red', 'nir1', 'nir2']); + +var preImage = landsat3 + .filterBounds(point) + .filterDate('1981-01-01', '1981-12-30') + .sort('CLOUD_COVER', true) + .first(); +var postImage = landsat8 + .filterBounds(point) + .filterDate('2020-01-01', '2020-12-30') + .sort('CLOUD_COVER', true) + .first(); + +Map.centerObject(point, 10); +Map.addLayer(preImage, preIncheon, 'pre'); +Map.addLayer(postImage, postIncheon, 'post'); diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/incheon.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/incheon.py new file mode 100644 index 0000000..930c766 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/incheon.py @@ -0,0 +1,32 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +point = ee.Geometry.Point([126.46560976562499, 37.520194763339695]), + preIncheon = {"opacity":1,"bands":["red","nir1","green"],"min":3.9,"max":143.1,"gamma":0.711}, + postIncheon = {"opacity":1,"bands":["red","nir","green"],"min":7196.82,"max":16980.18,"gamma":0.814} +#**** End of imports. If edited, may not auto-convert in the playground. ****# +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']) +landsat3 = ee.ImageCollection('LANDSAT/LM03/C01/T2') \ + .select(['B4', 'B5', 'B6', 'B7'], ['green', 'red', 'nir1', 'nir2']) + +preImage = landsat3 \ + .filterBounds(point) \ + .filterDate('1981-01-01', '1981-12-30') \ + .sort('CLOUD_COVER', True) \ + .first() +postImage = landsat8 \ + .filterBounds(point) \ + .filterDate('2020-01-01', '2020-12-30') \ + .sort('CLOUD_COVER', True) \ + .first() + +Map.centerObject(point, 10) +Map.addLayer(preImage, preIncheon, 'pre') +Map.addLayer(postImage, postIncheon, 'post') +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mining.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mining.ipynb new file mode 100644 index 0000000..dbcf8a3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mining.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "point = ee.Geometry.Point([-70.54473946976444, -13.046675490210111]),\n", + " mininPostVis = {\"opacity\":1,\"bands\":[\"swir2\",\"nir\",\"red\"],\"min\":7749,\"max\":22215,\"gamma\":1},\n", + " miningPreVis = {\"opacity\":1,\"bands\":[\"swir2\",\"nir\",\"red\"],\"min\":569.5106854708367,\"max\":3002.543077970024,\"gamma\":0.649}\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .select(\n", + " ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'],\n", + " ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'])\n", + "landsat5 = ee.ImageCollection('LANDSAT/LT05/C01/T2_SR') \\\n", + " .select(\n", + " ['B1', 'B2', 'B3', 'B4', 'B5', 'B7'],\n", + " ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'])\n", + "\n", + "preImage = landsat5 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('1985-01-01', '2002-12-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "postImage = landsat8 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2020-01-01', '2020-12-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "\n", + "Map.centerObject(point, 10)\n", + "Map.addLayer(preImage, miningPreVis, 'pre')\n", + "Map.addLayer(postImage, mininPostVis, 'post')" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mining.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mining.js new file mode 100644 index 0000000..d0578ef --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mining.js @@ -0,0 +1,28 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var point = /* color: #d63000 */ee.Geometry.Point([-70.54473946976444, -13.046675490210111]), + mininPostVis = {"opacity":1,"bands":["swir2","nir","red"],"min":7749,"max":22215,"gamma":1}, + miningPreVis = {"opacity":1,"bands":["swir2","nir","red"],"min":569.5106854708367,"max":3002.543077970024,"gamma":0.649}; +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']); +var landsat5 = ee.ImageCollection('LANDSAT/LT05/C01/T2_SR') + .select( + ['B1', 'B2', 'B3', 'B4', 'B5', 'B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']); + +var preImage = landsat5 + .filterBounds(point) + .filterDate('1985-01-01', '2002-12-30') + .sort('CLOUD_COVER', true) + .first(); +var postImage = landsat8 + .filterBounds(point) + .filterDate('2020-01-01', '2020-12-30') + .sort('CLOUD_COVER', true) + .first(); + +Map.centerObject(point, 10); +Map.addLayer(preImage, miningPreVis, 'pre'); +Map.addLayer(postImage, mininPostVis, 'post'); \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mining.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mining.py new file mode 100644 index 0000000..5fe7d5f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mining.py @@ -0,0 +1,34 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +point = ee.Geometry.Point([-70.54473946976444, -13.046675490210111]), + mininPostVis = {"opacity":1,"bands":["swir2","nir","red"],"min":7749,"max":22215,"gamma":1}, + miningPreVis = {"opacity":1,"bands":["swir2","nir","red"],"min":569.5106854708367,"max":3002.543077970024,"gamma":0.649} +#**** End of imports. If edited, may not auto-convert in the playground. ****# +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']) +landsat5 = ee.ImageCollection('LANDSAT/LT05/C01/T2_SR') \ + .select( + ['B1', 'B2', 'B3', 'B4', 'B5', 'B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']) + +preImage = landsat5 \ + .filterBounds(point) \ + .filterDate('1985-01-01', '2002-12-30') \ + .sort('CLOUD_COVER', True) \ + .first() +postImage = landsat8 \ + .filterBounds(point) \ + .filterDate('2020-01-01', '2020-12-30') \ + .sort('CLOUD_COVER', True) \ + .first() + +Map.centerObject(point, 10) +Map.addLayer(preImage, miningPreVis, 'pre') +Map.addLayer(postImage, mininPostVis, 'post') +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mtStHelen.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mtStHelen.ipynb new file mode 100644 index 0000000..2d54e37 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mtStHelen.ipynb @@ -0,0 +1,125 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "point =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([-122.19174741047361, 46.20040199038881])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "landsat2 = ee.ImageCollection('LANDSAT/LM02/C02/T2') \\\n", + " .select(['B4', 'B5', 'B6', 'B7'],\n", + " ['green', 'red', 'nir1', 'nir2'])\n", + "\n", + "preImage = landsat2 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('1979-08-01', '1979-10-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "postImage = landsat2 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('1980-04-01', '1981-10-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "\n", + "visParam = {\n", + " 'opacity': 1,\n", + " 'bands': ['nir1', 'red', 'green'],\n", + " 'min': 0,\n", + " 'max': 128,\n", + " 'gamma':1\n", + "}\n", + "\n", + "Map.centerObject(point, 10)\n", + "Map.addLayer(preImage, visParam, 'pre')\n", + "Map.addLayer(postImage, visParam, 'post')\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mtStHelen.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mtStHelen.js new file mode 100644 index 0000000..771249a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mtStHelen.js @@ -0,0 +1,33 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var point = + /* color: #d63000 */ + /* shown: false */ + ee.Geometry.Point([-122.19174741047361, 46.20040199038881]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +var landsat2 = ee.ImageCollection('LANDSAT/LM02/C02/T2') + .select(['B4', 'B5', 'B6', 'B7'], + ['green', 'red', 'nir1', 'nir2']); + +var preImage = landsat2 + .filterBounds(point) + .filterDate('1979-08-01', '1979-10-30') + .sort('CLOUD_COVER', true) + .first(); +var postImage = landsat2 + .filterBounds(point) + .filterDate('1980-04-01', '1981-10-30') + .sort('CLOUD_COVER', true) + .first(); + +var visParam = { + 'opacity': 1, + 'bands': ['nir1', 'red', 'green'], + 'min': 0, + 'max': 128, + 'gamma':1 +}; + +Map.centerObject(point, 10); +Map.addLayer(preImage, visParam, 'pre'); +Map.addLayer(postImage, visParam, 'post'); + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mtStHelen.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mtStHelen.py new file mode 100644 index 0000000..471efa5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/mtStHelen.py @@ -0,0 +1,39 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +point = + + # shown: False # + ee.Geometry.Point([-122.19174741047361, 46.20040199038881]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +landsat2 = ee.ImageCollection('LANDSAT/LM02/C02/T2') \ + .select(['B4', 'B5', 'B6', 'B7'], + ['green', 'red', 'nir1', 'nir2']) + +preImage = landsat2 \ + .filterBounds(point) \ + .filterDate('1979-08-01', '1979-10-30') \ + .sort('CLOUD_COVER', True) \ + .first() +postImage = landsat2 \ + .filterBounds(point) \ + .filterDate('1980-04-01', '1981-10-30') \ + .sort('CLOUD_COVER', True) \ + .first() + +visParam = { + 'opacity': 1, + 'bands': ['nir1', 'red', 'green'], + 'min': 0, + 'max': 128, + 'gamma':1 +} + +Map.centerObject(point, 10) +Map.addLayer(preImage, visParam, 'pre') +Map.addLayer(postImage, visParam, 'post') + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/paradise.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/paradise.ipynb new file mode 100644 index 0000000..306fd33 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/paradise.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "imageVisParam = {\"opacity\":1,\"bands\":[\"swir2\",\"nir\",\"red\"],\"min\":7749,\"max\":22215,\"gamma\":1},\n", + " point =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([-121.55188822809693, 39.794570152006976])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .select(\n", + " ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'],\n", + " ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'])\n", + "\n", + "preImage = landsat8 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2018-10-01', '2018-10-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "postImage = landsat8 \\\n", + " .filterBounds(point) \\\n", + " .filterDate('2018-12-01', '2019-04-30') \\\n", + " .sort('CLOUD_COVER', True) \\\n", + " .first()\n", + "\n", + "Map.centerObject(point, 10)\n", + "Map.addLayer(preImage, imageVisParam, 'pre')\n", + "Map.addLayer(postImage, imageVisParam, 'post')" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/paradise.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/paradise.js new file mode 100644 index 0000000..e091b35 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/paradise.js @@ -0,0 +1,26 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var imageVisParam = {"opacity":1,"bands":["swir2","nir","red"],"min":7749,"max":22215,"gamma":1}, + point = + /* color: #0b4a8b */ + /* shown: false */ + ee.Geometry.Point([-121.55188822809693, 39.794570152006976]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']); + +var preImage = landsat8 + .filterBounds(point) + .filterDate('2018-10-01', '2018-10-30') + .sort('CLOUD_COVER', true) + .first(); +var postImage = landsat8 + .filterBounds(point) + .filterDate('2018-12-01', '2019-04-30') + .sort('CLOUD_COVER', true) + .first(); + +Map.centerObject(point, 10); +Map.addLayer(preImage, imageVisParam, 'pre'); +Map.addLayer(postImage, imageVisParam, 'post'); diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/paradise.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/paradise.py new file mode 100644 index 0000000..9000608 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.4 Change Detection/vis/paradise.py @@ -0,0 +1,32 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +imageVisParam = {"opacity":1,"bands":["swir2","nir","red"],"min":7749,"max":22215,"gamma":1}, + point = + + # shown: False # + ee.Geometry.Point([-121.55188822809693, 39.794570152006976]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']) + +preImage = landsat8 \ + .filterBounds(point) \ + .filterDate('2018-10-01', '2018-10-30') \ + .sort('CLOUD_COVER', True) \ + .first() +postImage = landsat8 \ + .filterBounds(point) \ + .filterDate('2018-12-01', '2019-04-30') \ + .sort('CLOUD_COVER', True) \ + .first() + +Map.centerObject(point, 10) +Map.addLayer(preImage, imageVisParam, 'pre') +Map.addLayer(postImage, imageVisParam, 'post') +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.5 LandTrendr/F45a LandTrendr Links and info.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.5 LandTrendr/F45a LandTrendr Links and info.ipynb new file mode 100644 index 0000000..c59caf5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.5 LandTrendr/F45a LandTrendr Links and info.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.5 Interpreting Annual Time Series with LandTrendr\n", + "# Checkpoint: F45a\n", + "# Authors: Robert Kennedy, Justin Braaten, Peter Clary\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "\n", + "# the interface used in this chapter can be seen at the following link:\n", + "\n", + "# https:#code.earthengine.google.com/?accept_repo=users%2Femaprlab%2Fpublic&scriptPath=users%2Femaprlab%2Fpublic%3ALT-data-download%2FLT-Data-Visualization-Download-App\n", + "\n", + "# Enter that link above into your browser, and you should see the interface described in the book.\n", + "\n", + "\n", + "# for more advanced work, you could dig into the script-based\n", + "# application of these same concepts by exploring the more\n", + "# expansive set of manuals on the https:#emapr.github.io/LT-GEE/site.\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.5 LandTrendr/F45a LandTrendr Links and info.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.5 LandTrendr/F45a LandTrendr Links and info.js new file mode 100644 index 0000000..98f822c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.5 LandTrendr/F45a LandTrendr Links and info.js @@ -0,0 +1,22 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.5 Interpreting Annual Time Series with LandTrendr +// Checkpoint: F45a +// Authors: Robert Kennedy, Justin Braaten, Peter Clary +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +// the interface used in this chapter can be seen at the following link: + +// https://code.earthengine.google.com/?accept_repo=users%2Femaprlab%2Fpublic&scriptPath=users%2Femaprlab%2Fpublic%3ALT-data-download%2FLT-Data-Visualization-Download-App + +// Enter that link above into your browser, and you should see the interface described in the book. + + +// for more advanced work, you could dig into the script-based +// application of these same concepts by exploring the more +// expansive set of manuals on the https://emapr.github.io/LT-GEE/site. + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.5 LandTrendr/F45a LandTrendr Links and info.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.5 LandTrendr/F45a LandTrendr Links and info.py new file mode 100644 index 0000000..e011179 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.5 LandTrendr/F45a LandTrendr Links and info.py @@ -0,0 +1,28 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.5 Interpreting Annual Time Series with LandTrendr +# Checkpoint: F45a +# Authors: Robert Kennedy, Justin Braaten, Peter Clary +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +# the interface used in this chapter can be seen at the following link: + +# https:#code.earthengine.google.com/?accept_repo=users%2Femaprlab%2Fpublic&scriptPath=users%2Femaprlab%2Fpublic%3ALT-data-download%2FLT-Data-Visualization-Download-App + +# Enter that link above into your browser, and you should see the interface described in the book. + + +# for more advanced work, you could dig into the script-based +# application of these same concepts by exploring the more +# expansive set of manuals on the https:#emapr.github.io/LT-GEE/site. + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46a Checkpoint.ipynb new file mode 100644 index 0000000..18bc4e3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46a Checkpoint.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.6 Fitting Functions to Time Series\n", + "# Checkpoint: F46a\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah,\n", + "# Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##########/ Sections 1 & 2 ##############/\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(ee.Image(years).rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Import point of interest over California, USA.\n", + "roi = ee.Geometry.Point([-121.059, 37.9242])\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection),\n", + "# filter, mask clouds, scale, and add variables.\n", + "landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2013-01-01', '2018-01-01') \\\n", + " .map(maskScaleAndAddVariable)\n", + "\n", + "# Set map center over the ROI.\n", + "Map.centerObject(roi, 6)\n", + "\n", + "# Plot a time series of NDVI at a single location.\n", + "landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat 8 NDVI time series at ROI',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsat8Chart)\n", + "\n", + "# Plot a time series of NDVI with a linear trend line\n", + "# at a single location.\n", + "landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat 8 NDVI time series at ROI',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsat8ChartTL)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46a Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46a Checkpoint.js new file mode 100644 index 0000000..fb02d93 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46a Checkpoint.js @@ -0,0 +1,92 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.6 Fitting Functions to Time Series +// Checkpoint: F46a +// Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +// Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///////////////////// Sections 1 & 2 ///////////////////////////// + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(ee.Image(years).rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import point of interest over California, USA. +var roi = ee.Geometry.Point([-121.059, 37.9242]); + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center over the ROI. +Map.centerObject(roi, 6); + +// Plot a time series of NDVI at a single location. +var landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat 8 NDVI time series at ROI', + lineWidth: 1, + pointSize: 3, + }); +print(landsat8Chart); + +// Plot a time series of NDVI with a linear trend line +// at a single location. +var landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat 8 NDVI time series at ROI', + trendlines: { + 0: { + color: 'CC0000' + } + }, + lineWidth: 1, + pointSize: 3, + }); +print(landsat8ChartTL); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46a Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46a Checkpoint.py new file mode 100644 index 0000000..2a3babf --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46a Checkpoint.py @@ -0,0 +1,95 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.6 Fitting Functions to Time Series +# Checkpoint: F46a +# Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +# Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##########/ Sections 1 & 2 ##############/ + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(ee.Image(years).rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Import point of interest over California, USA. +roi = ee.Geometry.Point([-121.059, 37.9242]) + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +# filter, mask clouds, scale, and add variables. +landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .filterDate('2013-01-01', '2018-01-01') \ + .map(maskScaleAndAddVariable) + +# Set map center over the ROI. +Map.centerObject(roi, 6) + +# Plot a time series of NDVI at a single location. +landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat 8 NDVI time series at ROI', + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsat8Chart) + +# Plot a time series of NDVI with a linear trend line +# at a single location. +landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat 8 NDVI time series at ROI', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsat8ChartTL) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46b Checkpoint.ipynb new file mode 100644 index 0000000..53ccdc6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46b Checkpoint.ipynb @@ -0,0 +1,239 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.6 Fitting Functions to Time Series\n", + "# Checkpoint: F46b\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah,\n", + "# Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##########/ Sections 1 & 2 ##############/\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(ee.Image(years).rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Import point of interest over California, USA.\n", + "roi = ee.Geometry.Point([-121.059, 37.9242])\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection),\n", + "# filter, mask clouds, scale, and add variables.\n", + "landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2013-01-01', '2018-01-01') \\\n", + " .map(maskScaleAndAddVariable)\n", + "\n", + "# Set map center over the ROI.\n", + "Map.centerObject(roi, 6)\n", + "\n", + "# Plot a time series of NDVI at a single location.\n", + "landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat 8 NDVI time series at ROI',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsat8Chart)\n", + "\n", + "# Plot a time series of NDVI with a linear trend line\n", + "# at a single location.\n", + "landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat 8 NDVI time series at ROI',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsat8ChartTL)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##########/ Section 3 ##############/\n", + "\n", + "# List of the independent variable names\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('NDVI')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 (Array Image) band called 'coefficients'.\n", + "# (Columns are for dependent variables)\n", + "trend = landsat8sr.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "Map.addLayer(trend, {}, 'trend array image')\n", + "\n", + "# Flatten the coefficients into a 2-band image.\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "Map.addLayer(coefficients, {}, 'coefficients image')\n", + "\n", + "# Compute a detrended series.\n", + "\n", + "def func_hvg(image):\n", + " return image.select(dependent).subtract(\n", + " image.select(independents).multiply(coefficients) \\\n", + " .reduce('sum')) \\\n", + " .rename(dependent) \\\n", + " .copyProperties(image, ['system:time_start'])\n", + "\n", + "detrended = landsat8sr.map(func_hvg)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Plot the detrended results.\n", + "detrendedChart = ui.Chart.image.series(detrended, roi, None, 30) \\\n", + " .setOptions({\n", + " 'title': 'Detrended Landsat time series at ROI',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " })\n", + "print(detrendedChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46b Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46b Checkpoint.js new file mode 100644 index 0000000..113f34d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46b Checkpoint.js @@ -0,0 +1,142 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.6 Fitting Functions to Time Series +// Checkpoint: F46b +// Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +// Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///////////////////// Sections 1 & 2 ///////////////////////////// + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(ee.Image(years).rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import point of interest over California, USA. +var roi = ee.Geometry.Point([-121.059, 37.9242]); + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center over the ROI. +Map.centerObject(roi, 6); + +// Plot a time series of NDVI at a single location. +var landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat 8 NDVI time series at ROI', + lineWidth: 1, + pointSize: 3, + }); +print(landsat8Chart); + +// Plot a time series of NDVI with a linear trend line +// at a single location. +var landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat 8 NDVI time series at ROI', + trendlines: { + 0: { + color: 'CC0000' + } + }, + lineWidth: 1, + pointSize: 3, + }); +print(landsat8ChartTL); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///////////////////// Section 3 ///////////////////////////// + +// List of the independent variable names +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('NDVI'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 (Array Image) band called 'coefficients'. +// (Columns are for dependent variables) +var trend = landsat8sr.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); +Map.addLayer(trend, {}, 'trend array image'); + +// Flatten the coefficients into a 2-band image. +var coefficients = trend.select('coefficients') + // Get rid of extra dimensions and convert back to a regular image + .arrayProject([0]) + .arrayFlatten([independents]); +Map.addLayer(coefficients, {}, 'coefficients image'); + +// Compute a detrended series. +var detrended = landsat8sr.map(function(image) { + return image.select(dependent).subtract( + image.select(independents).multiply(coefficients) + .reduce('sum')) + .rename(dependent) + .copyProperties(image, ['system:time_start']); +}); + +// Plot the detrended results. +var detrendedChart = ui.Chart.image.series(detrended, roi, null, 30) + .setOptions({ + title: 'Detrended Landsat time series at ROI', + lineWidth: 1, + pointSize: 3, + trendlines: { + 0: { + color: 'CC0000' + } + }, + }); +print(detrendedChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46b Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46b Checkpoint.py new file mode 100644 index 0000000..91a45e0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46b Checkpoint.py @@ -0,0 +1,153 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.6 Fitting Functions to Time Series +# Checkpoint: F46b +# Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +# Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##########/ Sections 1 & 2 ##############/ + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(ee.Image(years).rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Import point of interest over California, USA. +roi = ee.Geometry.Point([-121.059, 37.9242]) + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +# filter, mask clouds, scale, and add variables. +landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .filterDate('2013-01-01', '2018-01-01') \ + .map(maskScaleAndAddVariable) + +# Set map center over the ROI. +Map.centerObject(roi, 6) + +# Plot a time series of NDVI at a single location. +landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat 8 NDVI time series at ROI', + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsat8Chart) + +# Plot a time series of NDVI with a linear trend line +# at a single location. +landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat 8 NDVI time series at ROI', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsat8ChartTL) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##########/ Section 3 ##############/ + +# List of the independent variable names +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('NDVI') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 (Array Image) band called 'coefficients'. +# (Columns are for dependent variables) +trend = landsat8sr.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) +Map.addLayer(trend, {}, 'trend array image') + +# Flatten the coefficients into a 2-band image. +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) +Map.addLayer(coefficients, {}, 'coefficients image') + +# Compute a detrended series. + +def func_hvg(image): + return image.select(dependent).subtract( + image.select(independents).multiply(coefficients) \ + .reduce('sum')) \ + .rename(dependent) \ + .copyProperties(image, ['system:time_start']) + +detrended = landsat8sr.map(func_hvg) + + + + + + + + +# Plot the detrended results. +detrendedChart = ui.Chart.image.series(detrended, roi, None, 30) \ + .setOptions({ + 'title': 'Detrended Landsat time series at ROI', + 'lineWidth': 1, + 'pointSize': 3, + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + }) +print(detrendedChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46c Checkpoint.ipynb new file mode 100644 index 0000000..fc058ad --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46c Checkpoint.ipynb @@ -0,0 +1,325 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.6 Fitting Functions to Time Series\n", + "# Checkpoint: F46c\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah,\n", + "# Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##########/ Sections 1 & 2 ##############/\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(ee.Image(years).rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Import point of interest over California, USA.\n", + "roi = ee.Geometry.Point([-121.059, 37.9242])\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection),\n", + "# filter, mask clouds, scale, and add variables.\n", + "landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2013-01-01', '2018-01-01') \\\n", + " .map(maskScaleAndAddVariable)\n", + "\n", + "# Set map center over the ROI.\n", + "Map.centerObject(roi, 6)\n", + "\n", + "# Plot a time series of NDVI at a single location.\n", + "landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat 8 NDVI time series at ROI',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsat8Chart)\n", + "\n", + "# Plot a time series of NDVI with a linear trend line\n", + "# at a single location.\n", + "landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat 8 NDVI time series at ROI',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsat8ChartTL)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##########/ Section 3 ##############/\n", + "\n", + "# List of the independent variable names\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('NDVI')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 (Array Image) band called 'coefficients'.\n", + "# (Columns are for dependent variables)\n", + "trend = landsat8sr.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "Map.addLayer(trend, {}, 'trend array image')\n", + "\n", + "# Flatten the coefficients into a 2-band image.\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "Map.addLayer(coefficients, {}, 'coefficients image')\n", + "\n", + "# Compute a detrended series.\n", + "\n", + "def func_zcs(image):\n", + " return image.select(dependent).subtract(\n", + " image.select(independents).multiply(coefficients) \\\n", + " .reduce('sum')) \\\n", + " .rename(dependent) \\\n", + " .copyProperties(image, ['system:time_start'])\n", + "\n", + "detrended = landsat8sr.map(func_zcs)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Plot the detrended results.\n", + "detrendedChart = ui.Chart.image.series(detrended, roi, None, 30) \\\n", + " .setOptions({\n", + " 'title': 'Detrended Landsat time series at ROI',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " })\n", + "print(detrendedChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##########/ Section 4 ##############/\n", + "\n", + "# Use these independent variables in the harmonic regression.\n", + "harmonicIndependents = ee.List(['constant', 't', 'cos', 'sin'])\n", + "\n", + "# Add harmonic terms as new image bands.\n", + "\n", + "def func_yrj(image):\n", + " timeRadians = image.select('t').multiply(2 * math.pi)\n", + " return image \\\n", + " .addBands(timeRadians.cos().rename('cos')) \\\n", + " .addBands(timeRadians.sin().rename('sin'))\n", + "\n", + "harmonicLandsat = landsat8sr.map(func_yrj)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Fit the model.\n", + "harmonicTrend = harmonicLandsat \\\n", + " .select(harmonicIndependents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(harmonicIndependents.length(),\n", + " 1))\n", + "\n", + "# Turn the array image into a multi-band image of coefficients.\n", + "harmonicTrendCoefficients = harmonicTrend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([harmonicIndependents])\n", + "\n", + "# Compute fitted values.\n", + "\n", + "def func_xur(image):\n", + " return image.addBands(\n", + " image.select(harmonicIndependents) \\\n", + " .multiply(harmonicTrendCoefficients) \\\n", + " .reduce('sum') \\\n", + " .rename('fitted'))\n", + "\n", + "fittedHarmonic = harmonicLandsat.map(func_xur)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Plot the fitted model and the original data at the ROI.\n", + "print(ui.Chart.image.series(\n", + " fittedHarmonic.select(['fitted', 'NDVI']), roi, ee.Reducer \\\n", + " .mean(), 30) \\\n", + " .setSeriesNames(['NDVI', 'fitted']) \\\n", + " .setOptions({\n", + " 'title': 'Harmonic model: original and fitted values',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " }))\n", + "\n", + "# Compute phase and amplitude.\n", + "phase = harmonicTrendCoefficients.select('sin') \\\n", + " .atan2(harmonicTrendCoefficients.select('cos')) \\\n", + " .unitScale(-math.pi, math.pi)\n", + "\n", + "amplitude = harmonicTrendCoefficients.select('sin') \\\n", + " .hypot(harmonicTrendCoefficients.select('cos')) \\\n", + " .multiply(5)\n", + "\n", + "# Compute the mean NDVI.\n", + "meanNdvi = landsat8sr.select('NDVI').mean()\n", + "\n", + "# Use the HSV to RGB transformation to display phase and amplitude.\n", + "rgb = ee.Image.cat([\n", + " phase, # hue\n", + " amplitude, # saturation (difference from white)\n", + " meanNdvi # value (difference from black)\n", + "]).hsvToRgb()\n", + "\n", + "Map.addLayer(rgb, {}, 'phase (hue), amplitude (sat), ndvi (val)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46c Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46c Checkpoint.js new file mode 100644 index 0000000..4124bd6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46c Checkpoint.js @@ -0,0 +1,214 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.6 Fitting Functions to Time Series +// Checkpoint: F46c +// Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +// Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///////////////////// Sections 1 & 2 ///////////////////////////// + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(ee.Image(years).rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import point of interest over California, USA. +var roi = ee.Geometry.Point([-121.059, 37.9242]); + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center over the ROI. +Map.centerObject(roi, 6); + +// Plot a time series of NDVI at a single location. +var landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat 8 NDVI time series at ROI', + lineWidth: 1, + pointSize: 3, + }); +print(landsat8Chart); + +// Plot a time series of NDVI with a linear trend line +// at a single location. +var landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat 8 NDVI time series at ROI', + trendlines: { + 0: { + color: 'CC0000' + } + }, + lineWidth: 1, + pointSize: 3, + }); +print(landsat8ChartTL); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///////////////////// Section 3 ///////////////////////////// + +// List of the independent variable names +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('NDVI'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 (Array Image) band called 'coefficients'. +// (Columns are for dependent variables) +var trend = landsat8sr.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); +Map.addLayer(trend, {}, 'trend array image'); + +// Flatten the coefficients into a 2-band image. +var coefficients = trend.select('coefficients') + // Get rid of extra dimensions and convert back to a regular image + .arrayProject([0]) + .arrayFlatten([independents]); +Map.addLayer(coefficients, {}, 'coefficients image'); + +// Compute a detrended series. +var detrended = landsat8sr.map(function(image) { + return image.select(dependent).subtract( + image.select(independents).multiply(coefficients) + .reduce('sum')) + .rename(dependent) + .copyProperties(image, ['system:time_start']); +}); + +// Plot the detrended results. +var detrendedChart = ui.Chart.image.series(detrended, roi, null, 30) + .setOptions({ + title: 'Detrended Landsat time series at ROI', + lineWidth: 1, + pointSize: 3, + trendlines: { + 0: { + color: 'CC0000' + } + }, + }); +print(detrendedChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///////////////////// Section 4 ///////////////////////////// + +// Use these independent variables in the harmonic regression. +var harmonicIndependents = ee.List(['constant', 't', 'cos', 'sin']); + +// Add harmonic terms as new image bands. +var harmonicLandsat = landsat8sr.map(function(image) { + var timeRadians = image.select('t').multiply(2 * Math.PI); + return image + .addBands(timeRadians.cos().rename('cos')) + .addBands(timeRadians.sin().rename('sin')); +}); + +// Fit the model. +var harmonicTrend = harmonicLandsat + .select(harmonicIndependents.add(dependent)) + // The output of this reducer is a 4x1 array image. + .reduce(ee.Reducer.linearRegression(harmonicIndependents.length(), + 1)); + +// Turn the array image into a multi-band image of coefficients. +var harmonicTrendCoefficients = harmonicTrend.select('coefficients') + .arrayProject([0]) + .arrayFlatten([harmonicIndependents]); + +// Compute fitted values. +var fittedHarmonic = harmonicLandsat.map(function(image) { + return image.addBands( + image.select(harmonicIndependents) + .multiply(harmonicTrendCoefficients) + .reduce('sum') + .rename('fitted')); +}); + +// Plot the fitted model and the original data at the ROI. +print(ui.Chart.image.series( + fittedHarmonic.select(['fitted', 'NDVI']), roi, ee.Reducer + .mean(), 30) + .setSeriesNames(['NDVI', 'fitted']) + .setOptions({ + title: 'Harmonic model: original and fitted values', + lineWidth: 1, + pointSize: 3, + })); + +// Compute phase and amplitude. +var phase = harmonicTrendCoefficients.select('sin') + .atan2(harmonicTrendCoefficients.select('cos')) + // Scale to [0, 1] from radians. + .unitScale(-Math.PI, Math.PI); + +var amplitude = harmonicTrendCoefficients.select('sin') + .hypot(harmonicTrendCoefficients.select('cos')) + // Add a scale factor for visualization. + .multiply(5); + +// Compute the mean NDVI. +var meanNdvi = landsat8sr.select('NDVI').mean(); + +// Use the HSV to RGB transformation to display phase and amplitude. +var rgb = ee.Image.cat([ + phase, // hue + amplitude, // saturation (difference from white) + meanNdvi // value (difference from black) +]).hsvToRgb(); + +Map.addLayer(rgb, {}, 'phase (hue), amplitude (sat), ndvi (val)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46c Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46c Checkpoint.py new file mode 100644 index 0000000..da125ed --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46c Checkpoint.py @@ -0,0 +1,240 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.6 Fitting Functions to Time Series +# Checkpoint: F46c +# Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +# Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##########/ Sections 1 & 2 ##############/ + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(ee.Image(years).rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Import point of interest over California, USA. +roi = ee.Geometry.Point([-121.059, 37.9242]) + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +# filter, mask clouds, scale, and add variables. +landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .filterDate('2013-01-01', '2018-01-01') \ + .map(maskScaleAndAddVariable) + +# Set map center over the ROI. +Map.centerObject(roi, 6) + +# Plot a time series of NDVI at a single location. +landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat 8 NDVI time series at ROI', + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsat8Chart) + +# Plot a time series of NDVI with a linear trend line +# at a single location. +landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat 8 NDVI time series at ROI', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsat8ChartTL) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##########/ Section 3 ##############/ + +# List of the independent variable names +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('NDVI') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 (Array Image) band called 'coefficients'. +# (Columns are for dependent variables) +trend = landsat8sr.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) +Map.addLayer(trend, {}, 'trend array image') + +# Flatten the coefficients into a 2-band image. +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) +Map.addLayer(coefficients, {}, 'coefficients image') + +# Compute a detrended series. + +def func_zcs(image): + return image.select(dependent).subtract( + image.select(independents).multiply(coefficients) \ + .reduce('sum')) \ + .rename(dependent) \ + .copyProperties(image, ['system:time_start']) + +detrended = landsat8sr.map(func_zcs) + + + + + + + + +# Plot the detrended results. +detrendedChart = ui.Chart.image.series(detrended, roi, None, 30) \ + .setOptions({ + 'title': 'Detrended Landsat time series at ROI', + 'lineWidth': 1, + 'pointSize': 3, + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + }) +print(detrendedChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##########/ Section 4 ##############/ + +# Use these independent variables in the harmonic regression. +harmonicIndependents = ee.List(['constant', 't', 'cos', 'sin']) + +# Add harmonic terms as new image bands. + +def func_yrj(image): + timeRadians = image.select('t').multiply(2 * math.pi) + return image \ + .addBands(timeRadians.cos().rename('cos')) \ + .addBands(timeRadians.sin().rename('sin')) + +harmonicLandsat = landsat8sr.map(func_yrj) + + + + + + + +# Fit the model. +harmonicTrend = harmonicLandsat \ + .select(harmonicIndependents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(harmonicIndependents.length(), + 1)) + +# Turn the array image into a multi-band image of coefficients. +harmonicTrendCoefficients = harmonicTrend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([harmonicIndependents]) + +# Compute fitted values. + +def func_xur(image): + return image.addBands( + image.select(harmonicIndependents) \ + .multiply(harmonicTrendCoefficients) \ + .reduce('sum') \ + .rename('fitted')) + +fittedHarmonic = harmonicLandsat.map(func_xur) + + + + + + + + +# Plot the fitted model and the original data at the ROI. +print(ui.Chart.image.series( + fittedHarmonic.select(['fitted', 'NDVI']), roi, ee.Reducer \ + .mean(), 30) \ + .setSeriesNames(['NDVI', 'fitted']) \ + .setOptions({ + 'title': 'Harmonic model: original and fitted values', + 'lineWidth': 1, + 'pointSize': 3, + })) + +# Compute phase and amplitude. +phase = harmonicTrendCoefficients.select('sin') \ + .atan2(harmonicTrendCoefficients.select('cos')) \ + .unitScale(-math.pi, math.pi) + +amplitude = harmonicTrendCoefficients.select('sin') \ + .hypot(harmonicTrendCoefficients.select('cos')) \ + .multiply(5) + +# Compute the mean NDVI. +meanNdvi = landsat8sr.select('NDVI').mean() + +# Use the HSV to RGB transformation to display phase and amplitude. +rgb = ee.Image.cat([ + phase, # hue + amplitude, # saturation (difference from white) + meanNdvi # value (difference from black) +]).hsvToRgb() + +Map.addLayer(rgb, {}, 'phase (hue), amplitude (sat), ndvi (val)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46d Checkpoint.ipynb new file mode 100644 index 0000000..2611559 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46d Checkpoint.ipynb @@ -0,0 +1,351 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.6 Fitting Functions to Time Series\n", + "# Checkpoint: F46d\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah,\n", + "# Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "##########/ Sections 1 & 2 ##############/\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(ee.Image(years).rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Import point of interest over California, USA.\n", + "roi = ee.Geometry.Point([-121.059, 37.9242])\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection),\n", + "# filter, mask clouds, scale, and add variables.\n", + "landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2013-01-01', '2018-01-01') \\\n", + " .map(maskScaleAndAddVariable)\n", + "\n", + "# Set map center over the ROI.\n", + "Map.centerObject(roi, 6)\n", + "\n", + "# Plot a time series of NDVI at a single location.\n", + "landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat 8 NDVI time series at ROI',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsat8Chart)\n", + "\n", + "# Plot a time series of NDVI with a linear trend line\n", + "# at a single location.\n", + "landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \\\n", + " .setChartType('ScatterChart') \\\n", + " .setOptions({\n", + " 'title': 'Landsat 8 NDVI time series at ROI',\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " })\n", + "print(landsat8ChartTL)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##########/ Section 3 ##############/\n", + "\n", + "# List of the independent variable names\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('NDVI')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 (Array Image) band called 'coefficients'.\n", + "# (Columns are for dependent variables)\n", + "trend = landsat8sr.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "Map.addLayer(trend, {}, 'trend array image')\n", + "\n", + "# Flatten the coefficients into a 2-band image.\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "Map.addLayer(coefficients, {}, 'coefficients image')\n", + "\n", + "# Compute a detrended series.\n", + "\n", + "def func_xnd(image):\n", + " return image.select(dependent).subtract(\n", + " image.select(independents).multiply(coefficients) \\\n", + " .reduce('sum')) \\\n", + " .rename(dependent) \\\n", + " .copyProperties(image, ['system:time_start'])\n", + "\n", + "detrended = landsat8sr.map(func_xnd)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Plot the detrended results.\n", + "detrendedChart = ui.Chart.image.series(detrended, roi, None, 30) \\\n", + " .setOptions({\n", + " 'title': 'Detrended Landsat time series at ROI',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " 'trendlines': {\n", + " '0': {\n", + " 'color': 'CC0000'\n", + " }\n", + " },\n", + " })\n", + "print(detrendedChart)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##########/ Section 4 ##############/\n", + "\n", + "# Use these independent variables in the harmonic regression.\n", + "harmonicIndependents = ee.List(['constant', 't', 'cos', 'sin'])\n", + "\n", + "# Add harmonic terms as new image bands.\n", + "\n", + "def func_egc(image):\n", + " timeRadians = image.select('t').multiply(2 * math.pi)\n", + " return image \\\n", + " .addBands(timeRadians.cos().rename('cos')) \\\n", + " .addBands(timeRadians.sin().rename('sin'))\n", + "\n", + "harmonicLandsat = landsat8sr.map(func_egc)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Fit the model.\n", + "harmonicTrend = harmonicLandsat \\\n", + " .select(harmonicIndependents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(harmonicIndependents.length(),\n", + " 1))\n", + "\n", + "# Turn the array image into a multi-band image of coefficients.\n", + "harmonicTrendCoefficients = harmonicTrend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([harmonicIndependents])\n", + "\n", + "# Compute fitted values.\n", + "\n", + "def func_mws(image):\n", + " return image.addBands(\n", + " image.select(harmonicIndependents) \\\n", + " .multiply(harmonicTrendCoefficients) \\\n", + " .reduce('sum') \\\n", + " .rename('fitted'))\n", + "\n", + "fittedHarmonic = harmonicLandsat.map(func_mws)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Plot the fitted model and the original data at the ROI.\n", + "print(ui.Chart.image.series(\n", + " fittedHarmonic.select(['fitted', 'NDVI']), roi, ee.Reducer \\\n", + " .mean(), 30) \\\n", + " .setSeriesNames(['NDVI', 'fitted']) \\\n", + " .setOptions({\n", + " 'title': 'Harmonic model: original and fitted values',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " }))\n", + "\n", + "# Compute phase and amplitude.\n", + "phase = harmonicTrendCoefficients.select('sin') \\\n", + " .atan2(harmonicTrendCoefficients.select('cos')) \\\n", + " .unitScale(-math.pi, math.pi)\n", + "\n", + "amplitude = harmonicTrendCoefficients.select('sin') \\\n", + " .hypot(harmonicTrendCoefficients.select('cos')) \\\n", + " .multiply(5)\n", + "\n", + "# Compute the mean NDVI.\n", + "meanNdvi = landsat8sr.select('NDVI').mean()\n", + "\n", + "# Use the HSV to RGB transformation to display phase and amplitude.\n", + "rgb = ee.Image.cat([\n", + " phase, # hue\n", + " amplitude, # saturation (difference from white)\n", + " meanNdvi # value (difference from black)\n", + "]).hsvToRgb()\n", + "\n", + "Map.addLayer(rgb, {}, 'phase (hue), amplitude (sat), ndvi (val)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "##########/ Section 5 ##############/\n", + "\n", + "# Import point of interest over California, USA.\n", + "roi = ee.Geometry.Point([-121.04, 37.641])\n", + "\n", + "# Set map center over the ROI.\n", + "Map.centerObject(roi, 14)\n", + "\n", + "trend0D = trend.select('coefficients').arrayProject([0]) \\\n", + " .arrayFlatten([independents]).select('t')\n", + "\n", + "anotherView = ee.Image(harmonicTrendCoefficients.select('sin')) \\\n", + " .addBands(trend0D) \\\n", + " .addBands(harmonicTrendCoefficients.select('cos'))\n", + "\n", + "Map.addLayer(anotherView,\n", + " {\n", + " 'min': -0.03,\n", + " 'max': 0.03\n", + " },\n", + " 'Another combination of fit characteristics')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46d Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46d Checkpoint.js new file mode 100644 index 0000000..68a5017 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46d Checkpoint.js @@ -0,0 +1,239 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.6 Fitting Functions to Time Series +// Checkpoint: F46d +// Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +// Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +///////////////////// Sections 1 & 2 ///////////////////////////// + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(ee.Image(years).rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import point of interest over California, USA. +var roi = ee.Geometry.Point([-121.059, 37.9242]); + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center over the ROI. +Map.centerObject(roi, 6); + +// Plot a time series of NDVI at a single location. +var landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat 8 NDVI time series at ROI', + lineWidth: 1, + pointSize: 3, + }); +print(landsat8Chart); + +// Plot a time series of NDVI with a linear trend line +// at a single location. +var landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) + .setChartType('ScatterChart') + .setOptions({ + title: 'Landsat 8 NDVI time series at ROI', + trendlines: { + 0: { + color: 'CC0000' + } + }, + lineWidth: 1, + pointSize: 3, + }); +print(landsat8ChartTL); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///////////////////// Section 3 ///////////////////////////// + +// List of the independent variable names +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('NDVI'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 (Array Image) band called 'coefficients'. +// (Columns are for dependent variables) +var trend = landsat8sr.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); +Map.addLayer(trend, {}, 'trend array image'); + +// Flatten the coefficients into a 2-band image. +var coefficients = trend.select('coefficients') + // Get rid of extra dimensions and convert back to a regular image + .arrayProject([0]) + .arrayFlatten([independents]); +Map.addLayer(coefficients, {}, 'coefficients image'); + +// Compute a detrended series. +var detrended = landsat8sr.map(function(image) { + return image.select(dependent).subtract( + image.select(independents).multiply(coefficients) + .reduce('sum')) + .rename(dependent) + .copyProperties(image, ['system:time_start']); +}); + +// Plot the detrended results. +var detrendedChart = ui.Chart.image.series(detrended, roi, null, 30) + .setOptions({ + title: 'Detrended Landsat time series at ROI', + lineWidth: 1, + pointSize: 3, + trendlines: { + 0: { + color: 'CC0000' + } + }, + }); +print(detrendedChart); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///////////////////// Section 4 ///////////////////////////// + +// Use these independent variables in the harmonic regression. +var harmonicIndependents = ee.List(['constant', 't', 'cos', 'sin']); + +// Add harmonic terms as new image bands. +var harmonicLandsat = landsat8sr.map(function(image) { + var timeRadians = image.select('t').multiply(2 * Math.PI); + return image + .addBands(timeRadians.cos().rename('cos')) + .addBands(timeRadians.sin().rename('sin')); +}); + +// Fit the model. +var harmonicTrend = harmonicLandsat + .select(harmonicIndependents.add(dependent)) + // The output of this reducer is a 4x1 array image. + .reduce(ee.Reducer.linearRegression(harmonicIndependents.length(), + 1)); + +// Turn the array image into a multi-band image of coefficients. +var harmonicTrendCoefficients = harmonicTrend.select('coefficients') + .arrayProject([0]) + .arrayFlatten([harmonicIndependents]); + +// Compute fitted values. +var fittedHarmonic = harmonicLandsat.map(function(image) { + return image.addBands( + image.select(harmonicIndependents) + .multiply(harmonicTrendCoefficients) + .reduce('sum') + .rename('fitted')); +}); + +// Plot the fitted model and the original data at the ROI. +print(ui.Chart.image.series( + fittedHarmonic.select(['fitted', 'NDVI']), roi, ee.Reducer + .mean(), 30) + .setSeriesNames(['NDVI', 'fitted']) + .setOptions({ + title: 'Harmonic model: original and fitted values', + lineWidth: 1, + pointSize: 3, + })); + +// Compute phase and amplitude. +var phase = harmonicTrendCoefficients.select('sin') + .atan2(harmonicTrendCoefficients.select('cos')) + // Scale to [0, 1] from radians. + .unitScale(-Math.PI, Math.PI); + +var amplitude = harmonicTrendCoefficients.select('sin') + .hypot(harmonicTrendCoefficients.select('cos')) + // Add a scale factor for visualization. + .multiply(5); + +// Compute the mean NDVI. +var meanNdvi = landsat8sr.select('NDVI').mean(); + +// Use the HSV to RGB transformation to display phase and amplitude. +var rgb = ee.Image.cat([ + phase, // hue + amplitude, // saturation (difference from white) + meanNdvi // value (difference from black) +]).hsvToRgb(); + +Map.addLayer(rgb, {}, 'phase (hue), amplitude (sat), ndvi (val)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///////////////////// Section 5 ///////////////////////////// + +// Import point of interest over California, USA. +var roi = ee.Geometry.Point([-121.04, 37.641]); + +// Set map center over the ROI. +Map.centerObject(roi, 14); + +var trend0D = trend.select('coefficients').arrayProject([0]) + .arrayFlatten([independents]).select('t'); + +var anotherView = ee.Image(harmonicTrendCoefficients.select('sin')) + .addBands(trend0D) + .addBands(harmonicTrendCoefficients.select('cos')); + +Map.addLayer(anotherView, + { + min: -0.03, + max: 0.03 + }, + 'Another combination of fit characteristics'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46d Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46d Checkpoint.py new file mode 100644 index 0000000..0d70eb1 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46d Checkpoint.py @@ -0,0 +1,265 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.6 Fitting Functions to Time Series +# Checkpoint: F46d +# Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +# Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +##########/ Sections 1 & 2 ##############/ + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(ee.Image(years).rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Import point of interest over California, USA. +roi = ee.Geometry.Point([-121.059, 37.9242]) + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +# filter, mask clouds, scale, and add variables. +landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .filterDate('2013-01-01', '2018-01-01') \ + .map(maskScaleAndAddVariable) + +# Set map center over the ROI. +Map.centerObject(roi, 6) + +# Plot a time series of NDVI at a single location. +landsat8Chart = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat 8 NDVI time series at ROI', + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsat8Chart) + +# Plot a time series of NDVI with a linear trend line +# at a single location. +landsat8ChartTL = ui.Chart.image.series(landsat8sr.select('NDVI'), roi) \ + .setChartType('ScatterChart') \ + .setOptions({ + 'title': 'Landsat 8 NDVI time series at ROI', + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + 'lineWidth': 1, + 'pointSize': 3, + }) +print(landsat8ChartTL) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##########/ Section 3 ##############/ + +# List of the independent variable names +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('NDVI') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 (Array Image) band called 'coefficients'. +# (Columns are for dependent variables) +trend = landsat8sr.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) +Map.addLayer(trend, {}, 'trend array image') + +# Flatten the coefficients into a 2-band image. +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) +Map.addLayer(coefficients, {}, 'coefficients image') + +# Compute a detrended series. + +def func_xnd(image): + return image.select(dependent).subtract( + image.select(independents).multiply(coefficients) \ + .reduce('sum')) \ + .rename(dependent) \ + .copyProperties(image, ['system:time_start']) + +detrended = landsat8sr.map(func_xnd) + + + + + + + + +# Plot the detrended results. +detrendedChart = ui.Chart.image.series(detrended, roi, None, 30) \ + .setOptions({ + 'title': 'Detrended Landsat time series at ROI', + 'lineWidth': 1, + 'pointSize': 3, + 'trendlines': { + '0': { + 'color': 'CC0000' + } + }, + }) +print(detrendedChart) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##########/ Section 4 ##############/ + +# Use these independent variables in the harmonic regression. +harmonicIndependents = ee.List(['constant', 't', 'cos', 'sin']) + +# Add harmonic terms as new image bands. + +def func_egc(image): + timeRadians = image.select('t').multiply(2 * math.pi) + return image \ + .addBands(timeRadians.cos().rename('cos')) \ + .addBands(timeRadians.sin().rename('sin')) + +harmonicLandsat = landsat8sr.map(func_egc) + + + + + + + +# Fit the model. +harmonicTrend = harmonicLandsat \ + .select(harmonicIndependents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(harmonicIndependents.length(), + 1)) + +# Turn the array image into a multi-band image of coefficients. +harmonicTrendCoefficients = harmonicTrend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([harmonicIndependents]) + +# Compute fitted values. + +def func_mws(image): + return image.addBands( + image.select(harmonicIndependents) \ + .multiply(harmonicTrendCoefficients) \ + .reduce('sum') \ + .rename('fitted')) + +fittedHarmonic = harmonicLandsat.map(func_mws) + + + + + + + + +# Plot the fitted model and the original data at the ROI. +print(ui.Chart.image.series( + fittedHarmonic.select(['fitted', 'NDVI']), roi, ee.Reducer \ + .mean(), 30) \ + .setSeriesNames(['NDVI', 'fitted']) \ + .setOptions({ + 'title': 'Harmonic model: original and fitted values', + 'lineWidth': 1, + 'pointSize': 3, + })) + +# Compute phase and amplitude. +phase = harmonicTrendCoefficients.select('sin') \ + .atan2(harmonicTrendCoefficients.select('cos')) \ + .unitScale(-math.pi, math.pi) + +amplitude = harmonicTrendCoefficients.select('sin') \ + .hypot(harmonicTrendCoefficients.select('cos')) \ + .multiply(5) + +# Compute the mean NDVI. +meanNdvi = landsat8sr.select('NDVI').mean() + +# Use the HSV to RGB transformation to display phase and amplitude. +rgb = ee.Image.cat([ + phase, # hue + amplitude, # saturation (difference from white) + meanNdvi # value (difference from black) +]).hsvToRgb() + +Map.addLayer(rgb, {}, 'phase (hue), amplitude (sat), ndvi (val)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +##########/ Section 5 ##############/ + +# Import point of interest over California, USA. +roi = ee.Geometry.Point([-121.04, 37.641]) + +# Set map center over the ROI. +Map.centerObject(roi, 14) + +trend0D = trend.select('coefficients').arrayProject([0]) \ + .arrayFlatten([independents]).select('t') + +anotherView = ee.Image(harmonicTrendCoefficients.select('sin')) \ + .addBands(trend0D) \ + .addBands(harmonicTrendCoefficients.select('cos')) + +Map.addLayer(anotherView, + { + 'min': -0.03, + 'max': 0.03 + }, + 'Another combination of fit characteristics') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46e Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46e Checkpoint.ipynb new file mode 100644 index 0000000..bc44b15 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46e Checkpoint.ipynb @@ -0,0 +1,239 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.6 Fitting Functions to Time Series\n", + "# Checkpoint: F46e\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah,\n", + "# Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Region of interest - a point over California, USA.\n", + "roi = ee.Geometry.Point([-121.059, 37.9242])\n", + "\n", + "# The dependent variable we are modeling.\n", + "dependent = 'NDVI'\n", + "\n", + "# The number of cycles per year to model.\n", + "harmonics = 3\n", + "\n", + "# Make a list of harmonic frequencies to model.\n", + "# These also serve as band name suffixes.\n", + "harmonicFrequencies = ee.List.sequence(1, harmonics)\n", + "\n", + "# Function to get a sequence of band names for harmonic terms.\n", + "def getNames(base, list):\n", + "\n", + "def func_ubp(i):\n", + " return ee.String(base).cat(ee.Number(i).int())\n", + "\n", + " return ee.List(list).map(func_ubp)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Construct lists of names for the harmonic terms.\n", + "cosNames = getNames('cos_', harmonicFrequencies)\n", + "sinNames = getNames('sin_', harmonicFrequencies)\n", + "\n", + "# Independent variables.\n", + "independents = ee.List(['constant', 't']) \\\n", + " .cat(cosNames).cat(sinNames)\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " timeRadians = ee.Image(years.multiply(2 * math.pi))\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(timeRadians.rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Function to compute the specified number of harmonics\n", + "# and add them as bands. Assumes the time band is present.\n", + "def addHarmonics(freqs):\n", + " return function(image) {\n", + " # Make an image of frequencies.\n", + " frequencies = ee.Image.constant(freqs)\n", + " # This band should represent time in radians.\n", + " time = ee.Image(image).select('t')\n", + " # Get the cosine terms.\n", + " cosines = time.multiply(frequencies).cos() \\\n", + " .rename(cosNames)\n", + " # Get the sin terms.\n", + " sines = time.multiply(frequencies).sin() \\\n", + " .rename(sinNames)\n", + " return image.addBands(cosines).addBands(sines)\n", + " }\n", + "\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection),\n", + "# filter, and map functions.\n", + "harmonicLandsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2013-01-01', '2018-01-01') \\\n", + " .map(maskScaleAndAddVariable) \\\n", + " .map(addHarmonics(harmonicFrequencies))\n", + "\n", + "# The output of the regression reduction is a 4x1 array image.\n", + "harmonicTrend = harmonicLandsat \\\n", + " .select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Turn the array image into a multi-band image of coefficients.\n", + "harmonicTrendCoefficients = harmonicTrend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Compute fitted values.\n", + "\n", + "def func_fqp(image):\n", + " return image.addBands(\n", + " image.select(independents) \\\n", + " .multiply(harmonicTrendCoefficients) \\\n", + " .reduce('sum') \\\n", + " .rename('fitted'))\n", + "\n", + "fittedHarmonic = harmonicLandsat.map(func_fqp)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Plot the fitted model and the original data at the ROI.\n", + "print(ui.Chart.image.series(\n", + " fittedHarmonic.select(['fitted', 'NDVI']), roi, ee.Reducer \\\n", + " .mean(), 30) \\\n", + " .setOptions({\n", + " 'title': 'Harmonic model: original and fitted values',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " }))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46e Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46e Checkpoint.js new file mode 100644 index 0000000..85d50a1 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46e Checkpoint.js @@ -0,0 +1,135 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.6 Fitting Functions to Time Series +// Checkpoint: F46e +// Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +// Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Region of interest - a point over California, USA. +var roi = ee.Geometry.Point([-121.059, 37.9242]); + +// The dependent variable we are modeling. +var dependent = 'NDVI'; + +// The number of cycles per year to model. +var harmonics = 3; + +// Make a list of harmonic frequencies to model. +// These also serve as band name suffixes. +var harmonicFrequencies = ee.List.sequence(1, harmonics); + +// Function to get a sequence of band names for harmonic terms. +var getNames = function(base, list) { + return ee.List(list).map(function(i) { + return ee.String(base).cat(ee.Number(i).int()); + }); +}; + +// Construct lists of names for the harmonic terms. +var cosNames = getNames('cos_', harmonicFrequencies); +var sinNames = getNames('sin_', harmonicFrequencies); + +// Independent variables. +var independents = ee.List(['constant', 't']) + .cat(cosNames).cat(sinNames); + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + var timeRadians = ee.Image(years.multiply(2 * Math.PI)); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(timeRadians.rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Function to compute the specified number of harmonics +// and add them as bands. Assumes the time band is present. +var addHarmonics = function(freqs) { + return function(image) { + // Make an image of frequencies. + var frequencies = ee.Image.constant(freqs); + // This band should represent time in radians. + var time = ee.Image(image).select('t'); + // Get the cosine terms. + var cosines = time.multiply(frequencies).cos() + .rename(cosNames); + // Get the sin terms. + var sines = time.multiply(frequencies).sin() + .rename(sinNames); + return image.addBands(cosines).addBands(sines); + }; +}; + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +// filter, and map functions. +var harmonicLandsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable) + .map(addHarmonics(harmonicFrequencies)); + +// The output of the regression reduction is a 4x1 array image. +var harmonicTrend = harmonicLandsat + .select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Turn the array image into a multi-band image of coefficients. +var harmonicTrendCoefficients = harmonicTrend.select('coefficients') + .arrayProject([0]) + .arrayFlatten([independents]); + +// Compute fitted values. +var fittedHarmonic = harmonicLandsat.map(function(image) { + return image.addBands( + image.select(independents) + .multiply(harmonicTrendCoefficients) + .reduce('sum') + .rename('fitted')); +}); + +// Plot the fitted model and the original data at the ROI. +print(ui.Chart.image.series( + fittedHarmonic.select(['fitted', 'NDVI']), roi, ee.Reducer + .mean(), 30) + .setOptions({ + title: 'Harmonic model: original and fitted values', + lineWidth: 1, + pointSize: 3, + })); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46e Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46e Checkpoint.py new file mode 100644 index 0000000..30b1aa8 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46e Checkpoint.py @@ -0,0 +1,153 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.6 Fitting Functions to Time Series +# Checkpoint: F46e +# Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +# Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Region of interest - a point over California, USA. +roi = ee.Geometry.Point([-121.059, 37.9242]) + +# The dependent variable we are modeling. +dependent = 'NDVI' + +# The number of cycles per year to model. +harmonics = 3 + +# Make a list of harmonic frequencies to model. +# These also serve as band name suffixes. +harmonicFrequencies = ee.List.sequence(1, harmonics) + +# Function to get a sequence of band names for harmonic terms. +def getNames(base, list): + +def func_ubp(i): + return ee.String(base).cat(ee.Number(i).int()) + + return ee.List(list).map(func_ubp) + + + + + +# Construct lists of names for the harmonic terms. +cosNames = getNames('cos_', harmonicFrequencies) +sinNames = getNames('sin_', harmonicFrequencies) + +# Independent variables. +independents = ee.List(['constant', 't']) \ + .cat(cosNames).cat(sinNames) + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + timeRadians = ee.Image(years.multiply(2 * math.pi)) + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(timeRadians.rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Function to compute the specified number of harmonics +# and add them as bands. Assumes the time band is present. +def addHarmonics(freqs): + return function(image) { + # Make an image of frequencies. + frequencies = ee.Image.constant(freqs) + # This band should represent time in radians. + time = ee.Image(image).select('t') + # Get the cosine terms. + cosines = time.multiply(frequencies).cos() \ + .rename(cosNames) + # Get the sin terms. + sines = time.multiply(frequencies).sin() \ + .rename(sinNames) + return image.addBands(cosines).addBands(sines) + } + + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +# filter, and map functions. +harmonicLandsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .filterDate('2013-01-01', '2018-01-01') \ + .map(maskScaleAndAddVariable) \ + .map(addHarmonics(harmonicFrequencies)) + +# The output of the regression reduction is a 4x1 array image. +harmonicTrend = harmonicLandsat \ + .select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Turn the array image into a multi-band image of coefficients. +harmonicTrendCoefficients = harmonicTrend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Compute fitted values. + +def func_fqp(image): + return image.addBands( + image.select(independents) \ + .multiply(harmonicTrendCoefficients) \ + .reduce('sum') \ + .rename('fitted')) + +fittedHarmonic = harmonicLandsat.map(func_fqp) + + + + + + + + +# Plot the fitted model and the original data at the ROI. +print(ui.Chart.image.series( + fittedHarmonic.select(['fitted', 'NDVI']), roi, ee.Reducer \ + .mean(), 30) \ + .setOptions({ + 'title': 'Harmonic model: original and fitted values', + 'lineWidth': 1, + 'pointSize': 3, + })) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s1 Synthesis.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s1 Synthesis.ipynb new file mode 100644 index 0000000..4f1518c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s1 Synthesis.ipynb @@ -0,0 +1,209 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.6 Fitting Functions to Time Series\n", + "# Checkpoint: F46s1\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah,\n", + "# Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Satellite basemap.\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Define roi, a point over the Brazilian Amazon.\n", + "roi = ee.Geometry.Point([-59.985146, -2.871413])\n", + "\n", + "# Add the point to the map.\n", + "Map.addLayer(roi, {\n", + " 'color': 'red'\n", + "}, 'roi')\n", + "Map.centerObject(roi, 16)\n", + "\n", + "# The dependent variable we are modeling.\n", + "dependent = 'NDVI'\n", + "\n", + "# The number of cycles per year to model.\n", + "harmonics = 1\n", + "\n", + "# Make a list of harmonic frequencies to model.\n", + "# These also serve as band name suffixes.\n", + "harmonicFrequencies = ee.List.sequence(1, harmonics)\n", + "\n", + "# Function to get a sequence of band names for harmonic terms.\n", + "def getNames(base, list):\n", + "\n", + "def func_cht(i):\n", + " return ee.String(base).cat(ee.Number(i).int())\n", + "\n", + " return ee.List(list).map(func_cht)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Construct lists of names for the harmonic terms.\n", + "cosNames = getNames('cos_', harmonicFrequencies)\n", + "sinNames = getNames('sin_', harmonicFrequencies)\n", + "\n", + "# Independent variables.\n", + "independents = ee.List(['constant', 't']) \\\n", + " .cat(cosNames).cat(sinNames)\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " timeRadians = ee.Image(years.multiply(2 * math.pi))\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(timeRadians.rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Function to compute the specified number of harmonics\n", + "# and add them as bands. Assumes the time band is present.\n", + "def addHarmonics(freqs):\n", + " return function(image) {\n", + " # Make an image of frequencies.\n", + " frequencies = ee.Image.constant(freqs)\n", + " # This band should represent time in radians.\n", + " time = ee.Image(image).select('t')\n", + " # Get the cosine terms.\n", + " cosines = time.multiply(frequencies).cos() \\\n", + " .rename(cosNames)\n", + " # Get the sin terms.\n", + " sines = time.multiply(frequencies).sin() \\\n", + " .rename(sinNames)\n", + " return image.addBands(cosines).addBands(sines)\n", + " }\n", + "\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection),\n", + "# and map functions.\n", + "harmonicLandsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .map(maskScaleAndAddVariable) \\\n", + " .map(addHarmonics(harmonicFrequencies))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s1 Synthesis.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s1 Synthesis.js new file mode 100644 index 0000000..7e428ed --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s1 Synthesis.js @@ -0,0 +1,114 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.6 Fitting Functions to Time Series +// Checkpoint: F46s1 +// Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +// Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Satellite basemap. +Map.setOptions('SATELLITE'); + +// Define roi, a point over the Brazilian Amazon. +var roi = ee.Geometry.Point([-59.985146, -2.871413]); + +// Add the point to the map. +Map.addLayer(roi, { + color: 'red' +}, 'roi'); +Map.centerObject(roi, 16); + +// The dependent variable we are modeling. +var dependent = 'NDVI'; + +// The number of cycles per year to model. +var harmonics = 1; + +// Make a list of harmonic frequencies to model. +// These also serve as band name suffixes. +var harmonicFrequencies = ee.List.sequence(1, harmonics); + +// Function to get a sequence of band names for harmonic terms. +var getNames = function(base, list) { + return ee.List(list).map(function(i) { + return ee.String(base).cat(ee.Number(i).int()); + }); +}; + +// Construct lists of names for the harmonic terms. +var cosNames = getNames('cos_', harmonicFrequencies); +var sinNames = getNames('sin_', harmonicFrequencies); + +// Independent variables. +var independents = ee.List(['constant', 't']) + .cat(cosNames).cat(sinNames); + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + var timeRadians = ee.Image(years.multiply(2 * Math.PI)); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(timeRadians.rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Function to compute the specified number of harmonics +// and add them as bands. Assumes the time band is present. +var addHarmonics = function(freqs) { + return function(image) { + // Make an image of frequencies. + var frequencies = ee.Image.constant(freqs); + // This band should represent time in radians. + var time = ee.Image(image).select('t'); + // Get the cosine terms. + var cosines = time.multiply(frequencies).cos() + .rename(cosNames); + // Get the sin terms. + var sines = time.multiply(frequencies).sin() + .rename(sinNames); + return image.addBands(cosines).addBands(sines); + }; +}; + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +// and map functions. +var harmonicLandsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .map(maskScaleAndAddVariable) + .map(addHarmonics(harmonicFrequencies)); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s1 Synthesis.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s1 Synthesis.py new file mode 100644 index 0000000..331d064 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s1 Synthesis.py @@ -0,0 +1,123 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.6 Fitting Functions to Time Series +# Checkpoint: F46s1 +# Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +# Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Satellite basemap. +Map.setOptions('SATELLITE') + +# Define roi, a point over the Brazilian Amazon. +roi = ee.Geometry.Point([-59.985146, -2.871413]) + +# Add the point to the map. +Map.addLayer(roi, { + 'color': 'red' +}, 'roi') +Map.centerObject(roi, 16) + +# The dependent variable we are modeling. +dependent = 'NDVI' + +# The number of cycles per year to model. +harmonics = 1 + +# Make a list of harmonic frequencies to model. +# These also serve as band name suffixes. +harmonicFrequencies = ee.List.sequence(1, harmonics) + +# Function to get a sequence of band names for harmonic terms. +def getNames(base, list): + +def func_cht(i): + return ee.String(base).cat(ee.Number(i).int()) + + return ee.List(list).map(func_cht) + + + + + +# Construct lists of names for the harmonic terms. +cosNames = getNames('cos_', harmonicFrequencies) +sinNames = getNames('sin_', harmonicFrequencies) + +# Independent variables. +independents = ee.List(['constant', 't']) \ + .cat(cosNames).cat(sinNames) + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + timeRadians = ee.Image(years.multiply(2 * math.pi)) + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(timeRadians.rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Function to compute the specified number of harmonics +# and add them as bands. Assumes the time band is present. +def addHarmonics(freqs): + return function(image) { + # Make an image of frequencies. + frequencies = ee.Image.constant(freqs) + # This band should represent time in radians. + time = ee.Image(image).select('t') + # Get the cosine terms. + cosines = time.multiply(frequencies).cos() \ + .rename(cosNames) + # Get the sin terms. + sines = time.multiply(frequencies).sin() \ + .rename(sinNames) + return image.addBands(cosines).addBands(sines) + } + + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +# and map functions. +harmonicLandsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .map(maskScaleAndAddVariable) \ + .map(addHarmonics(harmonicFrequencies)) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s2 Synthesis.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s2 Synthesis.ipynb new file mode 100644 index 0000000..8e46ee3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s2 Synthesis.ipynb @@ -0,0 +1,288 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.6 Fitting Functions to Time Series\n", + "# Checkpoint: F46s2\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah,\n", + "# Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Satellite basemap.\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Define roi, a point over the Brazilian Amazon.\n", + "roi = ee.Geometry.Point([-59.985146, -2.871413])\n", + "\n", + "# Add the point to the map.\n", + "Map.addLayer(roi, {\n", + " 'color': 'red'\n", + "}, 'roi')\n", + "Map.centerObject(roi, 16)\n", + "\n", + "# The dependent variable we are modeling.\n", + "dependent = 'NDVI'\n", + "\n", + "# The number of cycles per year to model.\n", + "harmonics = 1\n", + "\n", + "# Make a list of harmonic frequencies to model.\n", + "# These also serve as band name suffixes.\n", + "harmonicFrequencies = ee.List.sequence(1, harmonics)\n", + "\n", + "# Function to get a sequence of band names for harmonic terms.\n", + "def getNames(base, list):\n", + "\n", + "def func_xyi(i):\n", + " return ee.String(base).cat(ee.Number(i).int())\n", + "\n", + " return ee.List(list).map(func_xyi)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Construct lists of names for the harmonic terms.\n", + "cosNames = getNames('cos_', harmonicFrequencies)\n", + "sinNames = getNames('sin_', harmonicFrequencies)\n", + "\n", + "# Independent variables.\n", + "independents = ee.List(['constant', 't']) \\\n", + " .cat(cosNames).cat(sinNames)\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " timeRadians = ee.Image(years.multiply(2 * math.pi))\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(timeRadians.rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Function to compute the specified number of harmonics\n", + "# and add them as bands. Assumes the time band is present.\n", + "def addHarmonics(freqs):\n", + " return function(image) {\n", + " # Make an image of frequencies.\n", + " frequencies = ee.Image.constant(freqs)\n", + " # This band should represent time in radians.\n", + " time = ee.Image(image).select('t')\n", + " # Get the cosine terms.\n", + " cosines = time.multiply(frequencies).cos() \\\n", + " .rename(cosNames)\n", + " # Get the sin terms.\n", + " sines = time.multiply(frequencies).sin() \\\n", + " .rename(sinNames)\n", + " return image.addBands(cosines).addBands(sines)\n", + " }\n", + "\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection),\n", + "# and map functions.\n", + "harmonicLandsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .map(maskScaleAndAddVariable) \\\n", + " .map(addHarmonics(harmonicFrequencies))\n", + "\n", + "# Filter for the pre-disturbance period.\n", + "harmonicLandsatPre = harmonicLandsat.filterDate('2013-01-01',\n", + " '2014-12-12')\n", + "\n", + "# The output of the regression reduction is a 4x1 array image.\n", + "harmonicTrendPre = harmonicLandsatPre \\\n", + " .select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Turn the array image into a multi-band image of coefficients.\n", + "harmonicTrendCoefficientsPre = harmonicTrendPre.select(\n", + " 'coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Compute fitted values.\n", + "\n", + "def func_cvr(image):\n", + " return image.addBands(\n", + " image.select(independents) \\\n", + " .multiply(harmonicTrendCoefficientsPre) \\\n", + " .reduce('sum') \\\n", + " .rename('fitted'))\n", + "\n", + "fittedHarmonicPre = harmonicLandsatPre.map(func_cvr)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Filter for the disturbance period.\n", + "harmonicLandsatDist = harmonicLandsat.filterDate('2014-12-13',\n", + " '2019-01-01')\n", + "\n", + "# The output of the regression reduction is a 4x1 array image.\n", + "harmonicTrendDist = harmonicLandsatDist \\\n", + " .select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Turn the array image into a multi-band image of coefficients.\n", + "harmonicTrendCoefficientsDist = harmonicTrendDist.select(\n", + " 'coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Compute fitted values.\n", + "\n", + "def func_ovx(image):\n", + " return image.addBands(\n", + " image.select(independents) \\\n", + " .multiply(harmonicTrendCoefficientsDist) \\\n", + " .reduce('sum') \\\n", + " .rename('fitted'))\n", + "\n", + "fittedHarmonicDist = harmonicLandsatDist.map(func_ovx)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Merge fitted models.\n", + "mergedFitted = fittedHarmonicPre.merge(fittedHarmonicDist)\n", + "\n", + "# Plot the fitted models and the original data at the ROI.\n", + "print(ui.Chart.image.series(\n", + " mergedFitted.select(['fitted', 'NDVI']), roi, ee.Reducer \\\n", + " .mean(), 30) \\\n", + " .setOptions({\n", + " 'title': 'Harmonic model: original and fitted values Merged models',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " }))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s2 Synthesis.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s2 Synthesis.js new file mode 100644 index 0000000..5fafe24 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s2 Synthesis.js @@ -0,0 +1,175 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.6 Fitting Functions to Time Series +// Checkpoint: F46s2 +// Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +// Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Satellite basemap. +Map.setOptions('SATELLITE'); + +// Define roi, a point over the Brazilian Amazon. +var roi = ee.Geometry.Point([-59.985146, -2.871413]); + +// Add the point to the map. +Map.addLayer(roi, { + color: 'red' +}, 'roi'); +Map.centerObject(roi, 16); + +// The dependent variable we are modeling. +var dependent = 'NDVI'; + +// The number of cycles per year to model. +var harmonics = 1; + +// Make a list of harmonic frequencies to model. +// These also serve as band name suffixes. +var harmonicFrequencies = ee.List.sequence(1, harmonics); + +// Function to get a sequence of band names for harmonic terms. +var getNames = function(base, list) { + return ee.List(list).map(function(i) { + return ee.String(base).cat(ee.Number(i).int()); + }); +}; + +// Construct lists of names for the harmonic terms. +var cosNames = getNames('cos_', harmonicFrequencies); +var sinNames = getNames('sin_', harmonicFrequencies); + +// Independent variables. +var independents = ee.List(['constant', 't']) + .cat(cosNames).cat(sinNames); + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + var timeRadians = ee.Image(years.multiply(2 * Math.PI)); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(timeRadians.rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Function to compute the specified number of harmonics +// and add them as bands. Assumes the time band is present. +var addHarmonics = function(freqs) { + return function(image) { + // Make an image of frequencies. + var frequencies = ee.Image.constant(freqs); + // This band should represent time in radians. + var time = ee.Image(image).select('t'); + // Get the cosine terms. + var cosines = time.multiply(frequencies).cos() + .rename(cosNames); + // Get the sin terms. + var sines = time.multiply(frequencies).sin() + .rename(sinNames); + return image.addBands(cosines).addBands(sines); + }; +}; + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +// and map functions. +var harmonicLandsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .map(maskScaleAndAddVariable) + .map(addHarmonics(harmonicFrequencies)); + +// Filter for the pre-disturbance period. +var harmonicLandsatPre = harmonicLandsat.filterDate('2013-01-01', + '2014-12-12'); + +// The output of the regression reduction is a 4x1 array image. +var harmonicTrendPre = harmonicLandsatPre + .select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Turn the array image into a multi-band image of coefficients. +var harmonicTrendCoefficientsPre = harmonicTrendPre.select( + 'coefficients') + .arrayProject([0]) + .arrayFlatten([independents]); + +// Compute fitted values. +var fittedHarmonicPre = harmonicLandsatPre.map(function(image) { + return image.addBands( + image.select(independents) + .multiply(harmonicTrendCoefficientsPre) + .reduce('sum') + .rename('fitted')); +}); + +// Filter for the disturbance period. +var harmonicLandsatDist = harmonicLandsat.filterDate('2014-12-13', + '2019-01-01'); + +// The output of the regression reduction is a 4x1 array image. +var harmonicTrendDist = harmonicLandsatDist + .select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Turn the array image into a multi-band image of coefficients. +var harmonicTrendCoefficientsDist = harmonicTrendDist.select( + 'coefficients') + .arrayProject([0]) + .arrayFlatten([independents]); + +// Compute fitted values. +var fittedHarmonicDist = harmonicLandsatDist.map(function(image) { + return image.addBands( + image.select(independents) + .multiply(harmonicTrendCoefficientsDist) + .reduce('sum') + .rename('fitted')); +}); + +// Merge fitted models. +var mergedFitted = fittedHarmonicPre.merge(fittedHarmonicDist); + +// Plot the fitted models and the original data at the ROI. +print(ui.Chart.image.series( + mergedFitted.select(['fitted', 'NDVI']), roi, ee.Reducer + .mean(), 30) + .setOptions({ + title: 'Harmonic model: original and fitted values Merged models', + lineWidth: 1, + pointSize: 3, + })); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s2 Synthesis.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s2 Synthesis.py new file mode 100644 index 0000000..8ddb4a1 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.6 Fitting Functions to Time Series/F46s2 Synthesis.py @@ -0,0 +1,202 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.6 Fitting Functions to Time Series +# Checkpoint: F46s2 +# Authors: Andréa Puzzi Nicolau, Karen Dyson, Biplov Bhandari, David Saah, +# Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Satellite basemap. +Map.setOptions('SATELLITE') + +# Define roi, a point over the Brazilian Amazon. +roi = ee.Geometry.Point([-59.985146, -2.871413]) + +# Add the point to the map. +Map.addLayer(roi, { + 'color': 'red' +}, 'roi') +Map.centerObject(roi, 16) + +# The dependent variable we are modeling. +dependent = 'NDVI' + +# The number of cycles per year to model. +harmonics = 1 + +# Make a list of harmonic frequencies to model. +# These also serve as band name suffixes. +harmonicFrequencies = ee.List.sequence(1, harmonics) + +# Function to get a sequence of band names for harmonic terms. +def getNames(base, list): + +def func_xyi(i): + return ee.String(base).cat(ee.Number(i).int()) + + return ee.List(list).map(func_xyi) + + + + + +# Construct lists of names for the harmonic terms. +cosNames = getNames('cos_', harmonicFrequencies) +sinNames = getNames('sin_', harmonicFrequencies) + +# Independent variables. +independents = ee.List(['constant', 't']) \ + .cat(cosNames).cat(sinNames) + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + timeRadians = ee.Image(years.multiply(2 * math.pi)) + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(timeRadians.rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Function to compute the specified number of harmonics +# and add them as bands. Assumes the time band is present. +def addHarmonics(freqs): + return function(image) { + # Make an image of frequencies. + frequencies = ee.Image.constant(freqs) + # This band should represent time in radians. + time = ee.Image(image).select('t') + # Get the cosine terms. + cosines = time.multiply(frequencies).cos() \ + .rename(cosNames) + # Get the sin terms. + sines = time.multiply(frequencies).sin() \ + .rename(sinNames) + return image.addBands(cosines).addBands(sines) + } + + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +# and map functions. +harmonicLandsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .map(maskScaleAndAddVariable) \ + .map(addHarmonics(harmonicFrequencies)) + +# Filter for the pre-disturbance period. +harmonicLandsatPre = harmonicLandsat.filterDate('2013-01-01', + '2014-12-12') + +# The output of the regression reduction is a 4x1 array image. +harmonicTrendPre = harmonicLandsatPre \ + .select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Turn the array image into a multi-band image of coefficients. +harmonicTrendCoefficientsPre = harmonicTrendPre.select( + 'coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Compute fitted values. + +def func_cvr(image): + return image.addBands( + image.select(independents) \ + .multiply(harmonicTrendCoefficientsPre) \ + .reduce('sum') \ + .rename('fitted')) + +fittedHarmonicPre = harmonicLandsatPre.map(func_cvr) + + + + + + + + +# Filter for the disturbance period. +harmonicLandsatDist = harmonicLandsat.filterDate('2014-12-13', + '2019-01-01') + +# The output of the regression reduction is a 4x1 array image. +harmonicTrendDist = harmonicLandsatDist \ + .select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Turn the array image into a multi-band image of coefficients. +harmonicTrendCoefficientsDist = harmonicTrendDist.select( + 'coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Compute fitted values. + +def func_ovx(image): + return image.addBands( + image.select(independents) \ + .multiply(harmonicTrendCoefficientsDist) \ + .reduce('sum') \ + .rename('fitted')) + +fittedHarmonicDist = harmonicLandsatDist.map(func_ovx) + + + + + + + + +# Merge fitted models. +mergedFitted = fittedHarmonicPre.merge(fittedHarmonicDist) + +# Plot the fitted models and the original data at the ROI. +print(ui.Chart.image.series( + mergedFitted.select(['fitted', 'NDVI']), roi, ee.Reducer \ + .mean(), 30) \ + .setOptions({ + 'title': 'Harmonic model: original and fitted values Merged models', + 'lineWidth': 1, + 'pointSize': 3, + })) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47a Checkpoint.ipynb new file mode 100644 index 0000000..709d56c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47a Checkpoint.ipynb @@ -0,0 +1,112 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.7 Interpreting Time Series with CCDC\n", + "# Checkpoint: F47a\n", + "# Authors: Paulo Ar\u00e9valo, Pontus Olofsson\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Access the CCDC interface at the following link,\n", + "# by copy-pasting the line below into your browser.\n", + "\n", + "\n", + "'https':#parevalo-bu.users.earthengine.app/view/advanced-tstools\n", + "\n", + "This will open an app that you can use to explore time series and familiarize\n", + "yourself with CCDC capabilities\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47a Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47a Checkpoint.js new file mode 100644 index 0000000..c2d4250 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47a Checkpoint.js @@ -0,0 +1,20 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.7 Interpreting Time Series with CCDC +// Checkpoint: F47a +// Authors: Paulo Arévalo, Pontus Olofsson +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Access the CCDC interface at the following link, +// by copy-pasting the line below into your browser. + + +https://parevalo-bu.users.earthengine.app/view/advanced-tstools + +This will open an app that you can use to explore time series and familiarize +yourself with CCDC capabilities + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47a Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47a Checkpoint.py new file mode 100644 index 0000000..88bc45e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47a Checkpoint.py @@ -0,0 +1,26 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.7 Interpreting Time Series with CCDC +# Checkpoint: F47a +# Authors: Paulo Arévalo, Pontus Olofsson +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Access the CCDC interface at the following link, +# by copy-pasting the line below into your browser. + + +'https':#parevalo-bu.users.earthengine.app/view/advanced-tstools + +This will open an app that you can use to explore time series and familiarize +yourself with CCDC capabilities + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47b Checkpoint.ipynb new file mode 100644 index 0000000..2722cfc --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47b Checkpoint.ipynb @@ -0,0 +1,164 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.7 Interpreting Time Series with CCDC\n", + "# Checkpoint: F47b\n", + "# Authors: Paulo Ar\u00e9valo, Pontus Olofsson\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "utils = require(\n", + " 'users/parevalo_bu/gee-ccdc-tools:ccdcUtilities/api')\n", + "\n", + "studyRegion = ee.Geometry.Rectangle([\n", + " [-63.9533, -10.1315],\n", + " [-64.9118, -10.6813]\n", + "])\n", + "\n", + "# Define start, end dates and Landsat bands to use.\n", + "startDate = '2000-01-01'\n", + "endDate = '2020-01-01'\n", + "bands = ['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2']\n", + "\n", + "# Retrieve all clear, Landsat 4, 5, 7 and 8 observations (Collection 2, Tier 1).\n", + "filteredLandsat = utils.Inputs.getLandsat({\n", + " 'collection': 2\n", + " }) \\\n", + " .filterBounds(studyRegion) \\\n", + " .filterDate(startDate, endDate) \\\n", + " .select(bands)\n", + "\n", + "print(filteredLandsat.first())\n", + "\n", + "# Set CCD params to use.\n", + "ccdParams = {\n", + " 'breakpointBands': ['GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'],\n", + " 'tmaskBands': ['GREEN', 'SWIR1'],\n", + " 'minObservations': 6,\n", + " 'chiSquareProbability': 0.99,\n", + " 'minNumOfYearsScaler': 1.33,\n", + " 'dateFormat': 1,\n", + " 'lambda': 0.002,\n", + " 'maxIterations': 10000,\n", + " 'collection': filteredLandsat\n", + "}\n", + "\n", + "# Run CCD.\n", + "ccdResults = ee.Algorithms.TemporalSegmentation.Ccdc(ccdParams)\n", + "print(ccdResults)\n", + "\n", + "exportResults = False\n", + "if (exportResults) {\n", + " # Create a metadata dictionary with the parameters and arguments used.\n", + " metadata = ccdParams\n", + " metadata['breakpointBands'] = metadata['breakpointBands'].toString()\n", + " metadata['tmaskBands'] = metadata['tmaskBands'].toString()\n", + " metadata['startDate'] = startDate\n", + " metadata['endDate'] = endDate\n", + " metadata['bands'] = bands.toString()\n", + "\n", + " # Export results, assigning the metadata as image properties.\n", + " #\n", + " Export.image.toAsset({\n", + " 'image': ccdResults.set(metadata),\n", + " 'region': studyRegion,\n", + " 'pyramidingPolicy': {\n", + " \".default\": 'sample'\n", + " },\n", + " 'scale': 30\n", + " })\n", + "}\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47b Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47b Checkpoint.js new file mode 100644 index 0000000..d0f6708 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47b Checkpoint.js @@ -0,0 +1,71 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.7 Interpreting Time Series with CCDC +// Checkpoint: F47b +// Authors: Paulo Arévalo, Pontus Olofsson +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var utils = require( + 'users/parevalo_bu/gee-ccdc-tools:ccdcUtilities/api'); + +var studyRegion = ee.Geometry.Rectangle([ + [-63.9533, -10.1315], + [-64.9118, -10.6813] +]); + +// Define start, end dates and Landsat bands to use. +var startDate = '2000-01-01'; +var endDate = '2020-01-01'; +var bands = ['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2']; + +// Retrieve all clear, Landsat 4, 5, 7 and 8 observations (Collection 2, Tier 1). +var filteredLandsat = utils.Inputs.getLandsat({ + collection: 2 + }) + .filterBounds(studyRegion) + .filterDate(startDate, endDate) + .select(bands); + +print(filteredLandsat.first()); + +// Set CCD params to use. +var ccdParams = { + breakpointBands: ['GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'], + tmaskBands: ['GREEN', 'SWIR1'], + minObservations: 6, + chiSquareProbability: 0.99, + minNumOfYearsScaler: 1.33, + dateFormat: 1, + lambda: 0.002, + maxIterations: 10000, + collection: filteredLandsat +}; + +// Run CCD. +var ccdResults = ee.Algorithms.TemporalSegmentation.Ccdc(ccdParams); +print(ccdResults); + +var exportResults = false; +if (exportResults) { + // Create a metadata dictionary with the parameters and arguments used. + var metadata = ccdParams; + metadata['breakpointBands'] = metadata['breakpointBands'].toString(); + metadata['tmaskBands'] = metadata['tmaskBands'].toString(); + metadata['startDate'] = startDate; + metadata['endDate'] = endDate; + metadata['bands'] = bands.toString(); + + // Export results, assigning the metadata as image properties. + // + Export.image.toAsset({ + image: ccdResults.set(metadata), + region: studyRegion, + pyramidingPolicy: { + ".default": 'sample' + }, + scale: 30 + }); +} + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47b Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47b Checkpoint.py new file mode 100644 index 0000000..9e38efc --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47b Checkpoint.py @@ -0,0 +1,77 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.7 Interpreting Time Series with CCDC +# Checkpoint: F47b +# Authors: Paulo Arévalo, Pontus Olofsson +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +utils = require( + 'users/parevalo_bu/gee-ccdc-tools:ccdcUtilities/api') + +studyRegion = ee.Geometry.Rectangle([ + [-63.9533, -10.1315], + [-64.9118, -10.6813] +]) + +# Define start, end dates and Landsat bands to use. +startDate = '2000-01-01' +endDate = '2020-01-01' +bands = ['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'] + +# Retrieve all clear, Landsat 4, 5, 7 and 8 observations (Collection 2, Tier 1). +filteredLandsat = utils.Inputs.getLandsat({ + 'collection': 2 + }) \ + .filterBounds(studyRegion) \ + .filterDate(startDate, endDate) \ + .select(bands) + +print(filteredLandsat.first()) + +# Set CCD params to use. +ccdParams = { + 'breakpointBands': ['GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'], + 'tmaskBands': ['GREEN', 'SWIR1'], + 'minObservations': 6, + 'chiSquareProbability': 0.99, + 'minNumOfYearsScaler': 1.33, + 'dateFormat': 1, + 'lambda': 0.002, + 'maxIterations': 10000, + 'collection': filteredLandsat +} + +# Run CCD. +ccdResults = ee.Algorithms.TemporalSegmentation.Ccdc(ccdParams) +print(ccdResults) + +exportResults = False +if (exportResults) { + # Create a metadata dictionary with the parameters and arguments used. + metadata = ccdParams + metadata['breakpointBands'] = metadata['breakpointBands'].toString() + metadata['tmaskBands'] = metadata['tmaskBands'].toString() + metadata['startDate'] = startDate + metadata['endDate'] = endDate + metadata['bands'] = bands.toString() + + # Export results, assigning the metadata as image properties. + # + Export.image.toAsset({ + 'image': ccdResults.set(metadata), + 'region': studyRegion, + 'pyramidingPolicy': { + ".default": 'sample' + }, + 'scale': 30 + }) +} + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47c Checkpoint.ipynb new file mode 100644 index 0000000..d48ead3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47c Checkpoint.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.7 Interpreting Time Series with CCDC\n", + "# Checkpoint: F47c\n", + "# Authors: Paulo Ar\u00e9valo, Pontus Olofsson\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "palettes = require('users/gena/packages:palettes')\n", + "\n", + "resultsPath =\n", + " 'projects/gee-book/assets/F4-7/Rondonia_example_small'\n", + "ccdResults = ee.Image(resultsPath)\n", + "Map.centerObject(ccdResults, 10)\n", + "print(ccdResults)\n", + "\n", + "# Select time of break and change probability array images.\n", + "change = ccdResults.select('tBreak')\n", + "changeProb = ccdResults.select('changeProb')\n", + "\n", + "# Set the time range we want to use and get as mask of\n", + "# places that meet the condition.\n", + "start = 2000\n", + "end = 2021\n", + "mask = change.gt(start).And(change.lte(end)).And(changeProb.eq(\n", + "1))\n", + "Map.addLayer(changeProb, {}, 'change prob')\n", + "\n", + "# Obtain the number of breaks for the time range.\n", + "numBreaks = mask.arrayReduce(ee.Reducer.sum(), [0])\n", + "Map.addLayer(numBreaks, {\n", + " 'min': 0,\n", + " 'max': 5\n", + "}, 'Number of breaks')\n", + "\n", + "# Obtain the first change in that time period.\n", + "dates = change.arrayMask(mask).arrayPad([1])\n", + "firstChange = dates \\\n", + " .arraySlice(0, 0, 1) \\\n", + " .arrayFlatten([\n", + " ['firstChange']\n", + " ]) \\\n", + " .selfMask()\n", + "\n", + "timeVisParams = {\n", + " 'palette': palettes.colorbrewer.YlOrRd[9],\n", + " 'min': start,\n", + " 'max': end\n", + "}\n", + "Map.addLayer(firstChange, timeVisParams, 'First change')\n", + "\n", + "# Obtain the last change in that time period.\n", + "lastChange = dates \\\n", + " .arraySlice(0, -1) \\\n", + " .arrayFlatten([\n", + " ['lastChange']\n", + " ]) \\\n", + " .selfMask()\n", + "Map.addLayer(lastChange, timeVisParams, 'Last change')\n", + "\n", + "# Get masked magnitudes.\n", + "magnitudes = ccdResults \\\n", + " .select('SWIR1_magnitude') \\\n", + " .arrayMask(mask) \\\n", + " .arrayPad([1])\n", + "\n", + "# Get index of max abs magnitude of change.\n", + "maxIndex = magnitudes \\\n", + " .abs() \\\n", + " .arrayArgmax() \\\n", + " .arrayFlatten([\n", + " ['index']\n", + " ])\n", + "\n", + "# Select max magnitude and its timing\n", + "selectedMag = magnitudes.arrayGet(maxIndex)\n", + "selectedTbreak = dates.arrayGet(maxIndex).selfMask()\n", + "\n", + "magVisParams = {\n", + " 'palette': palettes.matplotlib.viridis[7],\n", + " 'min': -0.15,\n", + " 'max': 0.15\n", + "}\n", + "Map.addLayer(selectedMag, magVisParams, 'Max mag')\n", + "Map.addLayer(selectedTbreak, timeVisParams, 'Time of max mag')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47c Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47c Checkpoint.js new file mode 100644 index 0000000..2dcb576 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47c Checkpoint.js @@ -0,0 +1,88 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.7 Interpreting Time Series with CCDC +// Checkpoint: F47c +// Authors: Paulo Arévalo, Pontus Olofsson +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var palettes = require('users/gena/packages:palettes'); + +var resultsPath = + 'projects/gee-book/assets/F4-7/Rondonia_example_small'; +var ccdResults = ee.Image(resultsPath); +Map.centerObject(ccdResults, 10); +print(ccdResults); + +// Select time of break and change probability array images. +var change = ccdResults.select('tBreak'); +var changeProb = ccdResults.select('changeProb'); + +// Set the time range we want to use and get as mask of +// places that meet the condition. +var start = 2000; +var end = 2021; +var mask = change.gt(start).and(change.lte(end)).and(changeProb.eq( +1)); +Map.addLayer(changeProb, {}, 'change prob'); + +// Obtain the number of breaks for the time range. +var numBreaks = mask.arrayReduce(ee.Reducer.sum(), [0]); +Map.addLayer(numBreaks, { + min: 0, + max: 5 +}, 'Number of breaks'); + +// Obtain the first change in that time period. +var dates = change.arrayMask(mask).arrayPad([1]); +var firstChange = dates + .arraySlice(0, 0, 1) + .arrayFlatten([ + ['firstChange'] + ]) + .selfMask(); + +var timeVisParams = { + palette: palettes.colorbrewer.YlOrRd[9], + min: start, + max: end +}; +Map.addLayer(firstChange, timeVisParams, 'First change'); + +// Obtain the last change in that time period. +var lastChange = dates + .arraySlice(0, -1) + .arrayFlatten([ + ['lastChange'] + ]) + .selfMask(); +Map.addLayer(lastChange, timeVisParams, 'Last change'); + +// Get masked magnitudes. +var magnitudes = ccdResults + .select('SWIR1_magnitude') + .arrayMask(mask) + .arrayPad([1]); + +// Get index of max abs magnitude of change. +var maxIndex = magnitudes + .abs() + .arrayArgmax() + .arrayFlatten([ + ['index'] + ]); + +// Select max magnitude and its timing +var selectedMag = magnitudes.arrayGet(maxIndex); +var selectedTbreak = dates.arrayGet(maxIndex).selfMask(); + +var magVisParams = { + palette: palettes.matplotlib.viridis[7], + min: -0.15, + max: 0.15 +}; +Map.addLayer(selectedMag, magVisParams, 'Max mag'); +Map.addLayer(selectedTbreak, timeVisParams, 'Time of max mag'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47c Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47c Checkpoint.py new file mode 100644 index 0000000..5c1dd21 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47c Checkpoint.py @@ -0,0 +1,94 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.7 Interpreting Time Series with CCDC +# Checkpoint: F47c +# Authors: Paulo Arévalo, Pontus Olofsson +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +palettes = require('users/gena/packages:palettes') + +resultsPath = + 'projects/gee-book/assets/F4-7/Rondonia_example_small' +ccdResults = ee.Image(resultsPath) +Map.centerObject(ccdResults, 10) +print(ccdResults) + +# Select time of break and change probability array images. +change = ccdResults.select('tBreak') +changeProb = ccdResults.select('changeProb') + +# Set the time range we want to use and get as mask of +# places that meet the condition. +start = 2000 +end = 2021 +mask = change.gt(start).And(change.lte(end)).And(changeProb.eq( +1)) +Map.addLayer(changeProb, {}, 'change prob') + +# Obtain the number of breaks for the time range. +numBreaks = mask.arrayReduce(ee.Reducer.sum(), [0]) +Map.addLayer(numBreaks, { + 'min': 0, + 'max': 5 +}, 'Number of breaks') + +# Obtain the first change in that time period. +dates = change.arrayMask(mask).arrayPad([1]) +firstChange = dates \ + .arraySlice(0, 0, 1) \ + .arrayFlatten([ + ['firstChange'] + ]) \ + .selfMask() + +timeVisParams = { + 'palette': palettes.colorbrewer.YlOrRd[9], + 'min': start, + 'max': end +} +Map.addLayer(firstChange, timeVisParams, 'First change') + +# Obtain the last change in that time period. +lastChange = dates \ + .arraySlice(0, -1) \ + .arrayFlatten([ + ['lastChange'] + ]) \ + .selfMask() +Map.addLayer(lastChange, timeVisParams, 'Last change') + +# Get masked magnitudes. +magnitudes = ccdResults \ + .select('SWIR1_magnitude') \ + .arrayMask(mask) \ + .arrayPad([1]) + +# Get index of max abs magnitude of change. +maxIndex = magnitudes \ + .abs() \ + .arrayArgmax() \ + .arrayFlatten([ + ['index'] + ]) + +# Select max magnitude and its timing +selectedMag = magnitudes.arrayGet(maxIndex) +selectedTbreak = dates.arrayGet(maxIndex).selfMask() + +magVisParams = { + 'palette': palettes.matplotlib.viridis[7], + 'min': -0.15, + 'max': 0.15 +} +Map.addLayer(selectedMag, magVisParams, 'Max mag') +Map.addLayer(selectedTbreak, timeVisParams, 'Time of max mag') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47d Checkpoint.ipynb new file mode 100644 index 0000000..33235ae --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47d Checkpoint.ipynb @@ -0,0 +1,150 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.7 Interpreting Time Series with CCDC\n", + "# Checkpoint: F47d\n", + "# Authors: Paulo Ar\u00e9valo, Pontus Olofsson\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "palettes = require('users/gena/packages:palettes')\n", + "\n", + "resultsPath =\n", + " 'projects/gee-book/assets/F4-7/Rondonia_example_small'\n", + "ccdResults = ee.Image(resultsPath)\n", + "Map.centerObject(ccdResults, 10)\n", + "print(ccdResults)\n", + "\n", + "# Display segment start and end times.\n", + "start = ccdResults.select('tStart')\n", + "end = ccdResults.select('tEnd')\n", + "Map.addLayer(start, {\n", + " 'min': 1999,\n", + " 'max': 2001\n", + "}, 'Segment start')\n", + "Map.addLayer(end, {\n", + " 'min': 2010,\n", + " 'max': 2020\n", + "}, 'Segment end')\n", + "\n", + "# Find the segment that intersects a given date.\n", + "targetDate = 2005.5\n", + "selectSegment = start.lte(targetDate).And(end.gt(targetDate))\n", + "Map.addLayer(selectSegment, {}, 'Identified segment')\n", + "\n", + "# Get all coefs in the SWIR1 band.\n", + "SWIR1Coefs = ccdResults.select('SWIR1_coefs')\n", + "Map.addLayer(SWIR1Coefs, {}, 'SWIR1 coefs')\n", + "\n", + "# Select only those for the segment that we identified previously.\n", + "sliceStart = selectSegment.arrayArgmax().arrayFlatten([\n", + " ['index']\n", + "])\n", + "sliceEnd = sliceStart.add(1)\n", + "selectedCoefs = SWIR1Coefs.arraySlice(0, sliceStart, sliceEnd)\n", + "Map.addLayer(selectedCoefs, {}, 'Selected SWIR1 coefs')\n", + "\n", + "# Retrieve only the intercept coefficient.\n", + "intercept = selectedCoefs.arraySlice(1, 0, 1).arrayProject([1])\n", + "intVisParams = {\n", + " 'palette': palettes.matplotlib.viridis[7],\n", + " 'min': -6,\n", + " 'max': 6\n", + "}\n", + "Map.addLayer(intercept.arrayFlatten([\n", + " ['INTP']\n", + "]), intVisParams, 'INTP_SWIR1')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47d Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47d Checkpoint.js new file mode 100644 index 0000000..eb6f5c3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47d Checkpoint.js @@ -0,0 +1,58 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.7 Interpreting Time Series with CCDC +// Checkpoint: F47d +// Authors: Paulo Arévalo, Pontus Olofsson +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var palettes = require('users/gena/packages:palettes'); + +var resultsPath = + 'projects/gee-book/assets/F4-7/Rondonia_example_small'; +var ccdResults = ee.Image(resultsPath); +Map.centerObject(ccdResults, 10); +print(ccdResults); + +// Display segment start and end times. +var start = ccdResults.select('tStart'); +var end = ccdResults.select('tEnd'); +Map.addLayer(start, { + min: 1999, + max: 2001 +}, 'Segment start'); +Map.addLayer(end, { + min: 2010, + max: 2020 +}, 'Segment end'); + +// Find the segment that intersects a given date. +var targetDate = 2005.5; +var selectSegment = start.lte(targetDate).and(end.gt(targetDate)); +Map.addLayer(selectSegment, {}, 'Identified segment'); + +// Get all coefs in the SWIR1 band. +var SWIR1Coefs = ccdResults.select('SWIR1_coefs'); +Map.addLayer(SWIR1Coefs, {}, 'SWIR1 coefs'); + +// Select only those for the segment that we identified previously. +var sliceStart = selectSegment.arrayArgmax().arrayFlatten([ + ['index'] +]); +var sliceEnd = sliceStart.add(1); +var selectedCoefs = SWIR1Coefs.arraySlice(0, sliceStart, sliceEnd); +Map.addLayer(selectedCoefs, {}, 'Selected SWIR1 coefs'); + +// Retrieve only the intercept coefficient. +var intercept = selectedCoefs.arraySlice(1, 0, 1).arrayProject([1]); +var intVisParams = { + palette: palettes.matplotlib.viridis[7], + min: -6, + max: 6 +}; +Map.addLayer(intercept.arrayFlatten([ + ['INTP'] +]), intVisParams, 'INTP_SWIR1'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47d Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47d Checkpoint.py new file mode 100644 index 0000000..ca59f76 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47d Checkpoint.py @@ -0,0 +1,64 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.7 Interpreting Time Series with CCDC +# Checkpoint: F47d +# Authors: Paulo Arévalo, Pontus Olofsson +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +palettes = require('users/gena/packages:palettes') + +resultsPath = + 'projects/gee-book/assets/F4-7/Rondonia_example_small' +ccdResults = ee.Image(resultsPath) +Map.centerObject(ccdResults, 10) +print(ccdResults) + +# Display segment start and end times. +start = ccdResults.select('tStart') +end = ccdResults.select('tEnd') +Map.addLayer(start, { + 'min': 1999, + 'max': 2001 +}, 'Segment start') +Map.addLayer(end, { + 'min': 2010, + 'max': 2020 +}, 'Segment end') + +# Find the segment that intersects a given date. +targetDate = 2005.5 +selectSegment = start.lte(targetDate).And(end.gt(targetDate)) +Map.addLayer(selectSegment, {}, 'Identified segment') + +# Get all coefs in the SWIR1 band. +SWIR1Coefs = ccdResults.select('SWIR1_coefs') +Map.addLayer(SWIR1Coefs, {}, 'SWIR1 coefs') + +# Select only those for the segment that we identified previously. +sliceStart = selectSegment.arrayArgmax().arrayFlatten([ + ['index'] +]) +sliceEnd = sliceStart.add(1) +selectedCoefs = SWIR1Coefs.arraySlice(0, sliceStart, sliceEnd) +Map.addLayer(selectedCoefs, {}, 'Selected SWIR1 coefs') + +# Retrieve only the intercept coefficient. +intercept = selectedCoefs.arraySlice(1, 0, 1).arrayProject([1]) +intVisParams = { + 'palette': palettes.matplotlib.viridis[7], + 'min': -6, + 'max': 6 +} +Map.addLayer(intercept.arrayFlatten([ + ['INTP'] +]), intVisParams, 'INTP_SWIR1') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47e Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47e Checkpoint.ipynb new file mode 100644 index 0000000..e5e55c7 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47e Checkpoint.ipynb @@ -0,0 +1,173 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.7 Interpreting Time Series with CCDC\n", + "# Checkpoint: F47e\n", + "# Authors: Paulo Ar\u00e9valo, Pontus Olofsson\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load the required libraries.\n", + "palettes = require('users/gena/packages:palettes')\n", + "utils = require(\n", + " 'users/parevalo_bu/gee-ccdc-tools:ccdcUtilities/api')\n", + "\n", + "# Load the results.\n", + "resultsPath =\n", + " 'projects/gee-book/assets/F4-7/Rondonia_example_small'\n", + "ccdResults = ee.Image(resultsPath)\n", + "Map.centerObject(ccdResults, 10)\n", + "\n", + "# Convert a date into fractional years.\n", + "inputDate = '2005-09-25'\n", + "dateParams = {\n", + " 'inputFormat': 3,\n", + " 'inputDate': inputDate,\n", + " 'outputFormat': 1\n", + "}\n", + "formattedDate = utils.Dates.convertDate(dateParams)\n", + "\n", + "# Band names originally used as inputs to the CCD algorithm.\n", + "BANDS = ['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2']\n", + "\n", + "# Names for the time segments to retrieve.\n", + "SEGS = ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7', 'S8', 'S9',\n", + " 'S10'\n", + "]\n", + "\n", + "# Transform CCD results into a multiband image.\n", + "ccdImage = utils.CCDC.buildCcdImage(ccdResults, SEGS.length,\n", + " BANDS)\n", + "print(ccdImage)\n", + "\n", + "# Define bands to select.\n", + "SELECT_BANDS = ['RED', 'GREEN', 'BLUE', 'NIR']\n", + "\n", + "# Define coefficients to select.\n", + "# This list contains all possible coefficients, and the RMSE\n", + "SELECT_COEFS = ['INTP', 'SLP', 'RMSE']\n", + "\n", + "# Obtain coefficients.\n", + "coefs = utils.CCDC.getMultiCoefs(\n", + " ccdImage, formattedDate, SELECT_BANDS, SELECT_COEFS, True,\n", + " SEGS, 'after')\n", + "print(coefs)\n", + "\n", + "# Show a single coefficient.\n", + "slpVisParams = {\n", + " 'palette': palettes.matplotlib.viridis[7],\n", + " 'min': -0.0005,\n", + " 'max': 0.005\n", + "}\n", + "Map.addLayer(coefs.select('RED_SLP'), slpVisParams,\n", + " 'RED SLOPE 2005-09-25')\n", + "\n", + "rmseVisParams = {\n", + " 'palette': palettes.matplotlib.viridis[7],\n", + " 'min': 0,\n", + " 'max': 0.1\n", + "}\n", + "Map.addLayer(coefs.select('NIR_RMSE'), rmseVisParams,\n", + " 'NIR RMSE 2005-09-25')\n", + "\n", + "# Show an RGB with three coefficients.\n", + "rgbVisParams = {\n", + " 'bands': ['RED_INTP', 'GREEN_INTP', 'BLUE_INTP'],\n", + " 'min': 0,\n", + " 'max': 0.1\n", + "}\n", + "Map.addLayer(coefs, rgbVisParams, 'RGB 2005-09-25')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47e Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47e Checkpoint.js new file mode 100644 index 0000000..5c2b3c0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47e Checkpoint.js @@ -0,0 +1,81 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.7 Interpreting Time Series with CCDC +// Checkpoint: F47e +// Authors: Paulo Arévalo, Pontus Olofsson +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load the required libraries. +var palettes = require('users/gena/packages:palettes'); +var utils = require( + 'users/parevalo_bu/gee-ccdc-tools:ccdcUtilities/api'); + +// Load the results. +var resultsPath = + 'projects/gee-book/assets/F4-7/Rondonia_example_small'; +var ccdResults = ee.Image(resultsPath); +Map.centerObject(ccdResults, 10); + +// Convert a date into fractional years. +var inputDate = '2005-09-25'; +var dateParams = { + inputFormat: 3, + inputDate: inputDate, + outputFormat: 1 +}; +var formattedDate = utils.Dates.convertDate(dateParams); + +// Band names originally used as inputs to the CCD algorithm. +var BANDS = ['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2']; + +// Names for the time segments to retrieve. +var SEGS = ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7', 'S8', 'S9', + 'S10' +]; + +// Transform CCD results into a multiband image. +var ccdImage = utils.CCDC.buildCcdImage(ccdResults, SEGS.length, + BANDS); +print(ccdImage); + +// Define bands to select. +var SELECT_BANDS = ['RED', 'GREEN', 'BLUE', 'NIR']; + +// Define coefficients to select. +// This list contains all possible coefficients, and the RMSE +var SELECT_COEFS = ['INTP', 'SLP', 'RMSE']; + +// Obtain coefficients. +var coefs = utils.CCDC.getMultiCoefs( + ccdImage, formattedDate, SELECT_BANDS, SELECT_COEFS, true, + SEGS, 'after'); +print(coefs); + +// Show a single coefficient. +var slpVisParams = { + palette: palettes.matplotlib.viridis[7], + min: -0.0005, + max: 0.005 +}; +Map.addLayer(coefs.select('RED_SLP'), slpVisParams, + 'RED SLOPE 2005-09-25'); + +var rmseVisParams = { + palette: palettes.matplotlib.viridis[7], + min: 0, + max: 0.1 +}; +Map.addLayer(coefs.select('NIR_RMSE'), rmseVisParams, + 'NIR RMSE 2005-09-25'); + +// Show an RGB with three coefficients. +var rgbVisParams = { + bands: ['RED_INTP', 'GREEN_INTP', 'BLUE_INTP'], + min: 0, + max: 0.1 +}; +Map.addLayer(coefs, rgbVisParams, 'RGB 2005-09-25'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47e Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47e Checkpoint.py new file mode 100644 index 0000000..a2241c5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.7 Interpreting Time Series with CCDC/F47e Checkpoint.py @@ -0,0 +1,87 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.7 Interpreting Time Series with CCDC +# Checkpoint: F47e +# Authors: Paulo Arévalo, Pontus Olofsson +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load the required libraries. +palettes = require('users/gena/packages:palettes') +utils = require( + 'users/parevalo_bu/gee-ccdc-tools:ccdcUtilities/api') + +# Load the results. +resultsPath = + 'projects/gee-book/assets/F4-7/Rondonia_example_small' +ccdResults = ee.Image(resultsPath) +Map.centerObject(ccdResults, 10) + +# Convert a date into fractional years. +inputDate = '2005-09-25' +dateParams = { + 'inputFormat': 3, + 'inputDate': inputDate, + 'outputFormat': 1 +} +formattedDate = utils.Dates.convertDate(dateParams) + +# Band names originally used as inputs to the CCD algorithm. +BANDS = ['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'] + +# Names for the time segments to retrieve. +SEGS = ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7', 'S8', 'S9', + 'S10' +] + +# Transform CCD results into a multiband image. +ccdImage = utils.CCDC.buildCcdImage(ccdResults, SEGS.length, + BANDS) +print(ccdImage) + +# Define bands to select. +SELECT_BANDS = ['RED', 'GREEN', 'BLUE', 'NIR'] + +# Define coefficients to select. +# This list contains all possible coefficients, and the RMSE +SELECT_COEFS = ['INTP', 'SLP', 'RMSE'] + +# Obtain coefficients. +coefs = utils.CCDC.getMultiCoefs( + ccdImage, formattedDate, SELECT_BANDS, SELECT_COEFS, True, + SEGS, 'after') +print(coefs) + +# Show a single coefficient. +slpVisParams = { + 'palette': palettes.matplotlib.viridis[7], + 'min': -0.0005, + 'max': 0.005 +} +Map.addLayer(coefs.select('RED_SLP'), slpVisParams, + 'RED SLOPE 2005-09-25') + +rmseVisParams = { + 'palette': palettes.matplotlib.viridis[7], + 'min': 0, + 'max': 0.1 +} +Map.addLayer(coefs.select('NIR_RMSE'), rmseVisParams, + 'NIR RMSE 2005-09-25') + +# Show an RGB with three coefficients. +rgbVisParams = { + 'bands': ['RED_INTP', 'GREEN_INTP', 'BLUE_INTP'], + 'min': 0, + 'max': 0.1 +} +Map.addLayer(coefs, rgbVisParams, 'RGB 2005-09-25') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48a Checkpoint.ipynb new file mode 100644 index 0000000..a237ced --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48a Checkpoint.ipynb @@ -0,0 +1,116 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.8 Data Fusion: Merging Classification Streams\n", + "# Checkpoint: F48a\n", + "# Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez,\n", + "# Eidan Willis, Flavie Pelletier\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "events = ee.ImageCollection(\n", + " 'projects/gee-book/assets/F4-8/cleanEvents')\n", + "print(events, 'List of Events')\n", + "print('Number of events:', events.size())\n", + "\n", + "print(ui.Thumbnail(events, {\n", + " 'min': 0,\n", + " 'max': 3,\n", + " 'palette': ['black', 'green', 'blue', 'yellow'],\n", + " 'framesPerSecond': 1,\n", + " 'dimensions': 1000\n", + "}))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48a Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48a Checkpoint.js new file mode 100644 index 0000000..ba0b12f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48a Checkpoint.js @@ -0,0 +1,23 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.8 Data Fusion: Merging Classification Streams +// Checkpoint: F48a +// Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez, +// Eidan Willis, Flavie Pelletier +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var events = ee.ImageCollection( + 'projects/gee-book/assets/F4-8/cleanEvents'); +print(events, 'List of Events'); +print('Number of events:', events.size()); + +print(ui.Thumbnail(events, { + min: 0, + max: 3, + palette: ['black', 'green', 'blue', 'yellow'], + framesPerSecond: 1, + dimensions: 1000 +})); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48a Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48a Checkpoint.py new file mode 100644 index 0000000..1d7123e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48a Checkpoint.py @@ -0,0 +1,29 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.8 Data Fusion: Merging Classification Streams +# Checkpoint: F48a +# Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez, +# Eidan Willis, Flavie Pelletier +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +events = ee.ImageCollection( + 'projects/gee-book/assets/F4-8/cleanEvents') +print(events, 'List of Events') +print('Number of events:', events.size()) + +print(ui.Thumbnail(events, { + 'min': 0, + 'max': 3, + 'palette': ['black', 'green', 'blue', 'yellow'], + 'framesPerSecond': 1, + 'dimensions': 1000 +})) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48b Checkpoint - BULC interface link.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48b Checkpoint - BULC interface link.ipynb new file mode 100644 index 0000000..f889db8 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48b Checkpoint - BULC interface link.ipynb @@ -0,0 +1,109 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.8 Data Fusion: Merging Classification Streams\n", + "# Checkpoint: F48b\n", + "# Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez,\n", + "# Eidan Willis, Flavie Pelletier\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Access the BULC interface at the following link,\n", + "# by copy-pasting the line below into your browser.\n", + "# Run the script that loads.\n", + "\n", + "'https':#code.earthengine.google.com/?scriptPath=users%2Falemlakes%2Fr-2909-BULC-Releases%3AInterfaces%2FBULC-Interface%2FCurrent%2FBULC-Interface-Current\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48b Checkpoint - BULC interface link.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48b Checkpoint - BULC interface link.js new file mode 100644 index 0000000..43ec742 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48b Checkpoint - BULC interface link.js @@ -0,0 +1,16 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.8 Data Fusion: Merging Classification Streams +// Checkpoint: F48b +// Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez, +// Eidan Willis, Flavie Pelletier +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Access the BULC interface at the following link, +// by copy-pasting the line below into your browser. +// Run the script that loads. + +https://code.earthengine.google.com/?scriptPath=users%2Falemlakes%2Fr-2909-BULC-Releases%3AInterfaces%2FBULC-Interface%2FCurrent%2FBULC-Interface-Current + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48b Checkpoint - BULC interface link.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48b Checkpoint - BULC interface link.py new file mode 100644 index 0000000..9bbef4b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48b Checkpoint - BULC interface link.py @@ -0,0 +1,22 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.8 Data Fusion: Merging Classification Streams +# Checkpoint: F48b +# Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez, +# Eidan Willis, Flavie Pelletier +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Access the BULC interface at the following link, +# by copy-pasting the line below into your browser. +# Run the script that loads. + +'https':#code.earthengine.google.com/?scriptPath=users%2Falemlakes%2Fr-2909-BULC-Releases%3AInterfaces%2FBULC-Interface%2FCurrent%2FBULC-Interface-Current + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48c Checkpoint - BULC-D Interface Link.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48c Checkpoint - BULC-D Interface Link.ipynb new file mode 100644 index 0000000..dca9466 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48c Checkpoint - BULC-D Interface Link.ipynb @@ -0,0 +1,112 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.8 Data Fusion: Merging Classification Streams\n", + "# Checkpoint: F48c\n", + "# Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez,\n", + "# Eidan Willis, Flavie Pelletier\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Access the BULC-D interface at the following link,\n", + "# by copy-pasting the line below into your browser.\n", + "# Run the script that loads.\n", + "\n", + "\n", + "'Current link':\n", + "'https':#code.earthengine.google.com/?scriptPath=users/alemlakes/r-2909-BULC-Releases%3AInterfaces%2FBULC-D-Interface%2FCurrent%2FBULCD-Interface-Current\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48c Checkpoint - BULC-D Interface Link.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48c Checkpoint - BULC-D Interface Link.js new file mode 100644 index 0000000..d93f77b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48c Checkpoint - BULC-D Interface Link.js @@ -0,0 +1,19 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.8 Data Fusion: Merging Classification Streams +// Checkpoint: F48c +// Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez, +// Eidan Willis, Flavie Pelletier +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Access the BULC-D interface at the following link, +// by copy-pasting the line below into your browser. +// Run the script that loads. + + +Current link: +https://code.earthengine.google.com/?scriptPath=users/alemlakes/r-2909-BULC-Releases%3AInterfaces%2FBULC-D-Interface%2FCurrent%2FBULCD-Interface-Current + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48c Checkpoint - BULC-D Interface Link.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48c Checkpoint - BULC-D Interface Link.py new file mode 100644 index 0000000..543be8c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48c Checkpoint - BULC-D Interface Link.py @@ -0,0 +1,25 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.8 Data Fusion: Merging Classification Streams +# Checkpoint: F48c +# Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez, +# Eidan Willis, Flavie Pelletier +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Access the BULC-D interface at the following link, +# by copy-pasting the line below into your browser. +# Run the script that loads. + + +'Current link': +'https':#code.earthengine.google.com/?scriptPath=users/alemlakes/r-2909-BULC-Releases%3AInterfaces%2FBULC-D-Interface%2FCurrent%2FBULCD-Interface-Current + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48s1 - Supplemental - BULC explainer.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48s1 - Supplemental - BULC explainer.ipynb new file mode 100644 index 0000000..b34f6c6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48s1 - Supplemental - BULC explainer.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.8 Data Fusion: Merging Classification Streams\n", + "# Checkpoint: F48s1\n", + "# Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez,\n", + "# Eidan Willis, Flavie Pelletier\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# You can learn more about the operation of BULC at\n", + "# the following link: enter it into your browser.\n", + "\n", + "'https':#docs.google.com/spreadsheets/d/1Xo7UllSWFade4_lh9sLc2mqeYwHxJ-JEJGV7mInAILU/edit#gid=0\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48s1 - Supplemental - BULC explainer.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48s1 - Supplemental - BULC explainer.js new file mode 100644 index 0000000..bb45ac0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48s1 - Supplemental - BULC explainer.js @@ -0,0 +1,16 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.8 Data Fusion: Merging Classification Streams +// Checkpoint: F48s1 +// Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez, +// Eidan Willis, Flavie Pelletier +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// You can learn more about the operation of BULC at +// the following link: enter it into your browser. + +https://docs.google.com/spreadsheets/d/1Xo7UllSWFade4_lh9sLc2mqeYwHxJ-JEJGV7mInAILU/edit#gid=0 + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48s1 - Supplemental - BULC explainer.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48s1 - Supplemental - BULC explainer.py new file mode 100644 index 0000000..af2312c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.8 Data Fusion- Merging Classification Streams/F48s1 - Supplemental - BULC explainer.py @@ -0,0 +1,22 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.8 Data Fusion: Merging Classification Streams +# Checkpoint: F48s1 +# Authors: Jeff Cardille, Rylan Boothman, Mary Villamor, Elijah Perez, +# Eidan Willis, Flavie Pelletier +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# You can learn more about the operation of BULC at +# the following link: enter it into your browser. + +'https':#docs.google.com/spreadsheets/d/1Xo7UllSWFade4_lh9sLc2mqeYwHxJ-JEJGV7mInAILU/edit#gid=0 + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49a Checkpoint.ipynb new file mode 100644 index 0000000..d3c12a1 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49a Checkpoint.ipynb @@ -0,0 +1,280 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.9 Exploring Lagged Effects in Time Series\n", + "# Checkpoint: F49a\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " timeRadians = ee.Image(years.multiply(2 * math.pi))\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(timeRadians.rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Import region of interest. Area over California.\n", + "roi = ee.Geometry.Polygon([\n", + " [-119.44617458417066,35.92639730653253],\n", + " [-119.07675930096754,35.92639730653253],\n", + " [-119.07675930096754,36.201704711823844],\n", + " [-119.44617458417066,36.201704711823844],\n", + " [-119.44617458417066,35.92639730653253]\n", + "])\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection,\n", + "# filter, mask clouds, scale, and add variables.\n", + "landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2013-01-01', '2018-01-01') \\\n", + " .map(maskScaleAndAddVariable)\n", + "\n", + "# Set map center.\n", + "Map.centerObject(roi, 10)\n", + "\n", + "# List of the independent variable names.\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('NDVI')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 band called coefficients (columns are for dependent variables).\n", + "trend = landsat8sr.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Flatten the coefficients into a 2-band image\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Compute a detrended series.\n", + "\n", + "def func_mrd(image):\n", + " return image.select(dependent) \\\n", + " .subtract(image.select(independents).multiply(\n", + " coefficients) \\\n", + " .reduce('sum')) \\\n", + " .rename(dependent) \\\n", + " .copyProperties(image, ['system:time_start'])\n", + "\n", + "detrended = landsat8sr.map(func_mrd)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Function that creates a lagged collection.\n", + "def lag(leftCollection, rightCollection, lagDays):\n", + " filter = ee.Filter.And(\n", + " ee.Filter.maxDifference({\n", + " 'difference': 1000 * 60 * 60 * 24 * lagDays,\n", + " 'leftField': 'system:time_start',\n", + " 'rightField': 'system:time_start'\n", + " }),\n", + " ee.Filter.greaterThan({\n", + " 'leftField': 'system:time_start',\n", + " 'rightField': 'system:time_start'\n", + " }))\n", + "\n", + " return ee.Join.saveAll({\n", + " 'matchesKey': 'images',\n", + " 'measureKey': 'delta_t',\n", + " 'ordering': 'system:time_start',\n", + " 'ascending': False, # Sort reverse chronologically\n", + " }).apply({\n", + " 'primary': leftCollection,\n", + " 'secondary': rightCollection,\n", + " 'condition': filter\n", + " })\n", + "\n", + "\n", + "# Create a lagged collection of the detrended imagery.\n", + "lagged17 = lag(detrended, detrended, 17)\n", + "\n", + "# Function to stack bands.\n", + "def merge(image):\n", + " # Function to be passed to iterate.\n", + " def merger(current, previous):\n", + " return ee.Image(previous).addBands(current)\n", + " \n", + " return ee.ImageCollection.fromImages(image.get('images')) \\\n", + " .iterate(merger, image)\n", + "\n", + "\n", + "# Apply merge function to the lagged collection.\n", + "merged17 = ee.ImageCollection(lagged17.map(merge))\n", + "\n", + "# Function to compute covariance.\n", + "def covariance(mergedCollection, band, lagBand):\n", + " image) {\n", + " return image.toArray()\n", + " }).reduce(ee.Reducer.covariance(), 8)\n", + "\n", + "\n", + "# Concatenate the suffix to the NDVI band.\n", + "lagBand = dependent.cat('_1')\n", + "\n", + "# Compute covariance.\n", + "covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) \\\n", + " .clip(roi)\n", + "\n", + "# The output of the covariance reducer is an array image,\n", + "# in which each pixel stores a 2x2 variance-covariance array.\n", + "# The off diagonal elements are covariance, which you can map\n", + "# directly using:\n", + "Map.addLayer(covariance17.arrayGet([0, 1]),\n", + " {\n", + " 'min': 0,\n", + " 'max': 0.02\n", + " },\n", + " 'covariance (lag = 17 days)')\n", + "\n", + "# Define the correlation function.\n", + "def correlation(vcArrayImage):\n", + " covariance = ee.Image(vcArrayImage).arrayGet([0, 1])\n", + " sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt()\n", + " sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt()\n", + " return covariance.divide(sd0).divide(sd1).rename(\n", + " 'correlation')\n", + "\n", + "\n", + "# Apply the correlation function.\n", + "correlation17 = correlation(covariance17).clip(roi)\n", + "Map.addLayer(correlation17,\n", + " {\n", + " 'min': -1,\n", + " 'max': 1\n", + " },\n", + " 'correlation (lag = 17 days)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49a Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49a Checkpoint.js new file mode 100644 index 0000000..b27cde3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49a Checkpoint.js @@ -0,0 +1,182 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.9 Exploring Lagged Effects in Time Series +// Checkpoint: F49a +// Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + var timeRadians = ee.Image(years.multiply(2 * Math.PI)); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(timeRadians.rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import region of interest. Area over California. +var roi = ee.Geometry.Polygon([ + [-119.44617458417066,35.92639730653253], + [-119.07675930096754,35.92639730653253], + [-119.07675930096754,36.201704711823844], + [-119.44617458417066,36.201704711823844], + [-119.44617458417066,35.92639730653253] +]); + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center. +Map.centerObject(roi, 10); + +// List of the independent variable names. +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('NDVI'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = landsat8sr.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image +var coefficients = trend.select('coefficients') + // Get rid of extra dimensions and convert back to a regular image + .arrayProject([0]) + .arrayFlatten([independents]); + +// Compute a detrended series. +var detrended = landsat8sr.map(function(image) { + return image.select(dependent) + .subtract(image.select(independents).multiply( + coefficients) + .reduce('sum')) + .rename(dependent) + .copyProperties(image, ['system:time_start']); +}); + +// Function that creates a lagged collection. +var lag = function(leftCollection, rightCollection, lagDays) { + var filter = ee.Filter.and( + ee.Filter.maxDifference({ + difference: 1000 * 60 * 60 * 24 * lagDays, + leftField: 'system:time_start', + rightField: 'system:time_start' + }), + ee.Filter.greaterThan({ + leftField: 'system:time_start', + rightField: 'system:time_start' + })); + + return ee.Join.saveAll({ + matchesKey: 'images', + measureKey: 'delta_t', + ordering: 'system:time_start', + ascending: false, // Sort reverse chronologically + }).apply({ + primary: leftCollection, + secondary: rightCollection, + condition: filter + }); +}; + +// Create a lagged collection of the detrended imagery. +var lagged17 = lag(detrended, detrended, 17); + +// Function to stack bands. +var merge = function(image) { + // Function to be passed to iterate. + var merger = function(current, previous) { + return ee.Image(previous).addBands(current); + }; + return ee.ImageCollection.fromImages(image.get('images')) + .iterate(merger, image); +}; + +// Apply merge function to the lagged collection. +var merged17 = ee.ImageCollection(lagged17.map(merge)); + +// Function to compute covariance. +var covariance = function(mergedCollection, band, lagBand) { + return mergedCollection.select([band, lagBand]).map(function( + image) { + return image.toArray(); + }).reduce(ee.Reducer.covariance(), 8); +}; + +// Concatenate the suffix to the NDVI band. +var lagBand = dependent.cat('_1'); + +// Compute covariance. +var covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) + .clip(roi); + +// The output of the covariance reducer is an array image, +// in which each pixel stores a 2x2 variance-covariance array. +// The off diagonal elements are covariance, which you can map +// directly using: +Map.addLayer(covariance17.arrayGet([0, 1]), + { + min: 0, + max: 0.02 + }, + 'covariance (lag = 17 days)'); + +// Define the correlation function. +var correlation = function(vcArrayImage) { + var covariance = ee.Image(vcArrayImage).arrayGet([0, 1]); + var sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt(); + var sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt(); + return covariance.divide(sd0).divide(sd1).rename( + 'correlation'); +}; + +// Apply the correlation function. +var correlation17 = correlation(covariance17).clip(roi); +Map.addLayer(correlation17, + { + min: -1, + max: 1 + }, + 'correlation (lag = 17 days)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49a Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49a Checkpoint.py new file mode 100644 index 0000000..270cafd --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49a Checkpoint.py @@ -0,0 +1,194 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.9 Exploring Lagged Effects in Time Series +# Checkpoint: F49a +# Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + timeRadians = ee.Image(years.multiply(2 * math.pi)) + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(timeRadians.rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Import region of interest. Area over California. +roi = ee.Geometry.Polygon([ + [-119.44617458417066,35.92639730653253], + [-119.07675930096754,35.92639730653253], + [-119.07675930096754,36.201704711823844], + [-119.44617458417066,36.201704711823844], + [-119.44617458417066,35.92639730653253] +]) + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, +# filter, mask clouds, scale, and add variables. +landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .filterDate('2013-01-01', '2018-01-01') \ + .map(maskScaleAndAddVariable) + +# Set map center. +Map.centerObject(roi, 10) + +# List of the independent variable names. +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('NDVI') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 band called coefficients (columns are for dependent variables). +trend = landsat8sr.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Flatten the coefficients into a 2-band image +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Compute a detrended series. + +def func_mrd(image): + return image.select(dependent) \ + .subtract(image.select(independents).multiply( + coefficients) \ + .reduce('sum')) \ + .rename(dependent) \ + .copyProperties(image, ['system:time_start']) + +detrended = landsat8sr.map(func_mrd) + + + + + + + + + +# Function that creates a lagged collection. +def lag(leftCollection, rightCollection, lagDays): + filter = ee.Filter.And( + ee.Filter.maxDifference({ + 'difference': 1000 * 60 * 60 * 24 * lagDays, + 'leftField': 'system:time_start', + 'rightField': 'system:time_start' + }), + ee.Filter.greaterThan({ + 'leftField': 'system:time_start', + 'rightField': 'system:time_start' + })) + + return ee.Join.saveAll({ + 'matchesKey': 'images', + 'measureKey': 'delta_t', + 'ordering': 'system:time_start', + 'ascending': False, # Sort reverse chronologically + }).apply({ + 'primary': leftCollection, + 'secondary': rightCollection, + 'condition': filter + }) + + +# Create a lagged collection of the detrended imagery. +lagged17 = lag(detrended, detrended, 17) + +# Function to stack bands. +def merge(image): + # Function to be passed to iterate. + def merger(current, previous): + return ee.Image(previous).addBands(current) + + return ee.ImageCollection.fromImages(image.get('images')) \ + .iterate(merger, image) + + +# Apply merge function to the lagged collection. +merged17 = ee.ImageCollection(lagged17.map(merge)) + +# Function to compute covariance. +def covariance(mergedCollection, band, lagBand): + image) { + return image.toArray() + }).reduce(ee.Reducer.covariance(), 8) + + +# Concatenate the suffix to the NDVI band. +lagBand = dependent.cat('_1') + +# Compute covariance. +covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) \ + .clip(roi) + +# The output of the covariance reducer is an array image, +# in which each pixel stores a 2x2 variance-covariance array. +# The off diagonal elements are covariance, which you can map +# directly using: +Map.addLayer(covariance17.arrayGet([0, 1]), + { + 'min': 0, + 'max': 0.02 + }, + 'covariance (lag = 17 days)') + +# Define the correlation function. +def correlation(vcArrayImage): + covariance = ee.Image(vcArrayImage).arrayGet([0, 1]) + sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt() + sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt() + return covariance.divide(sd0).divide(sd1).rename( + 'correlation') + + +# Apply the correlation function. +correlation17 = correlation(covariance17).clip(roi) +Map.addLayer(correlation17, + { + 'min': -1, + 'max': 1 + }, + 'correlation (lag = 17 days)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49b Checkpoint.ipynb new file mode 100644 index 0000000..4119db8 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49b Checkpoint.ipynb @@ -0,0 +1,331 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.9 Exploring Lagged Effects in Time Series\n", + "# Checkpoint: F49b\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " timeRadians = ee.Image(years.multiply(2 * math.pi))\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(timeRadians.rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Import region of interest. Area over California.\n", + "roi = ee.Geometry.Polygon([\n", + " [-119.44617458417066,35.92639730653253],\n", + " [-119.07675930096754,35.92639730653253],\n", + " [-119.07675930096754,36.201704711823844],\n", + " [-119.44617458417066,36.201704711823844],\n", + " [-119.44617458417066,35.92639730653253]\n", + "])\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection,\n", + "# filter, mask clouds, scale, and add variables.\n", + "landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2013-01-01', '2018-01-01') \\\n", + " .map(maskScaleAndAddVariable)\n", + "\n", + "# Set map center.\n", + "Map.centerObject(roi, 10)\n", + "\n", + "# List of the independent variable names.\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('NDVI')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 band called coefficients (columns are for dependent variables).\n", + "trend = landsat8sr.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Flatten the coefficients into a 2-band image\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Compute a detrended series.\n", + "\n", + "def func_zrr(image):\n", + " return image.select(dependent) \\\n", + " .subtract(image.select(independents).multiply(\n", + " coefficients) \\\n", + " .reduce('sum')) \\\n", + " .rename(dependent) \\\n", + " .copyProperties(image, ['system:time_start'])\n", + "\n", + "detrended = landsat8sr.map(func_zrr)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Function that creates a lagged collection.\n", + "def lag(leftCollection, rightCollection, lagDays):\n", + " filter = ee.Filter.And(\n", + " ee.Filter.maxDifference({\n", + " 'difference': 1000 * 60 * 60 * 24 * lagDays,\n", + " 'leftField': 'system:time_start',\n", + " 'rightField': 'system:time_start'\n", + " }),\n", + " ee.Filter.greaterThan({\n", + " 'leftField': 'system:time_start',\n", + " 'rightField': 'system:time_start'\n", + " }))\n", + "\n", + " return ee.Join.saveAll({\n", + " 'matchesKey': 'images',\n", + " 'measureKey': 'delta_t',\n", + " 'ordering': 'system:time_start',\n", + " 'ascending': False, # Sort reverse chronologically\n", + " }).apply({\n", + " 'primary': leftCollection,\n", + " 'secondary': rightCollection,\n", + " 'condition': filter\n", + " })\n", + "\n", + "\n", + "# Create a lagged collection of the detrended imagery.\n", + "lagged17 = lag(detrended, detrended, 17)\n", + "\n", + "# Function to stack bands.\n", + "def merge(image):\n", + " # Function to be passed to iterate.\n", + " def merger(current, previous):\n", + " return ee.Image(previous).addBands(current)\n", + " \n", + " return ee.ImageCollection.fromImages(image.get('images')) \\\n", + " .iterate(merger, image)\n", + "\n", + "\n", + "# Apply merge function to the lagged collection.\n", + "merged17 = ee.ImageCollection(lagged17.map(merge))\n", + "\n", + "# Function to compute covariance.\n", + "def covariance(mergedCollection, band, lagBand):\n", + " image) {\n", + " return image.toArray()\n", + " }).reduce(ee.Reducer.covariance(), 8)\n", + "\n", + "\n", + "# Concatenate the suffix to the NDVI band.\n", + "lagBand = dependent.cat('_1')\n", + "\n", + "# Compute covariance.\n", + "covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) \\\n", + " .clip(roi)\n", + "\n", + "# The output of the covariance reducer is an array image,\n", + "# in which each pixel stores a 2x2 variance-covariance array.\n", + "# The off diagonal elements are covariance, which you can map\n", + "# directly using:\n", + "Map.addLayer(covariance17.arrayGet([0, 1]),\n", + " {\n", + " 'min': 0,\n", + " 'max': 0.02\n", + " },\n", + " 'covariance (lag = 17 days)')\n", + "\n", + "# Define the correlation function.\n", + "def correlation(vcArrayImage):\n", + " covariance = ee.Image(vcArrayImage).arrayGet([0, 1])\n", + " sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt()\n", + " sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt()\n", + " return covariance.divide(sd0).divide(sd1).rename(\n", + " 'correlation')\n", + "\n", + "\n", + "# Apply the correlation function.\n", + "correlation17 = correlation(covariance17).clip(roi)\n", + "Map.addLayer(correlation17,\n", + " {\n", + " 'min': -1,\n", + " 'max': 1\n", + " },\n", + " 'correlation (lag = 17 days)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "########### Cross-covariance and Cross-correlation ##########/\n", + "\n", + "# Precipitation (covariate)\n", + "chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "\n", + "# Join the t-l (l=1 pentad) precipitation images to the Landsat.\n", + "lag1PrecipNDVI = lag(landsat8sr, chirps, 5)\n", + "\n", + "# Add the precipitation images as bands.\n", + "merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge))\n", + "\n", + "# Compute and display cross-covariance.\n", + "cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI',\n", + " 'precipitation').clip(roi)\n", + "Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {},\n", + " 'NDVI - PRECIP cov (lag = 5)')\n", + "\n", + "# Compute and display cross-correlation.\n", + "corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi)\n", + "Map.addLayer(corr1PrecipNDVI, {\n", + " 'min': -0.5,\n", + " 'max': 0.5\n", + "}, 'NDVI - PRECIP corr (lag = 5)')\n", + "\n", + "# Join the precipitation images from the previous month.\n", + "lag30PrecipNDVI = lag(landsat8sr, chirps, 30)\n", + "\n", + " image) {\n", + " laggedImages = ee.ImageCollection.fromImages(image \\\n", + " .get('images'))\n", + " return ee.Image(image).addBands(laggedImages.sum() \\\n", + " .rename('sum'))\n", + "}))\n", + "\n", + "# Compute covariance.\n", + "cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip(\n", + " roi)\n", + "Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {},\n", + " 'NDVI - sum cov (lag = 30)')\n", + "\n", + "# Correlation.\n", + "corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi)\n", + "Map.addLayer(corr30PrecipNDVI, {\n", + " 'min': -0.5,\n", + " 'max': 0.5\n", + "}, 'NDVI - sum corr (lag = 30)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49b Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49b Checkpoint.js new file mode 100644 index 0000000..cd8e430 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49b Checkpoint.js @@ -0,0 +1,234 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.9 Exploring Lagged Effects in Time Series +// Checkpoint: F49b +// Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + var timeRadians = ee.Image(years.multiply(2 * Math.PI)); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(timeRadians.rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import region of interest. Area over California. +var roi = ee.Geometry.Polygon([ + [-119.44617458417066,35.92639730653253], + [-119.07675930096754,35.92639730653253], + [-119.07675930096754,36.201704711823844], + [-119.44617458417066,36.201704711823844], + [-119.44617458417066,35.92639730653253] +]); + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center. +Map.centerObject(roi, 10); + +// List of the independent variable names. +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('NDVI'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = landsat8sr.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image +var coefficients = trend.select('coefficients') + // Get rid of extra dimensions and convert back to a regular image + .arrayProject([0]) + .arrayFlatten([independents]); + +// Compute a detrended series. +var detrended = landsat8sr.map(function(image) { + return image.select(dependent) + .subtract(image.select(independents).multiply( + coefficients) + .reduce('sum')) + .rename(dependent) + .copyProperties(image, ['system:time_start']); +}); + +// Function that creates a lagged collection. +var lag = function(leftCollection, rightCollection, lagDays) { + var filter = ee.Filter.and( + ee.Filter.maxDifference({ + difference: 1000 * 60 * 60 * 24 * lagDays, + leftField: 'system:time_start', + rightField: 'system:time_start' + }), + ee.Filter.greaterThan({ + leftField: 'system:time_start', + rightField: 'system:time_start' + })); + + return ee.Join.saveAll({ + matchesKey: 'images', + measureKey: 'delta_t', + ordering: 'system:time_start', + ascending: false, // Sort reverse chronologically + }).apply({ + primary: leftCollection, + secondary: rightCollection, + condition: filter + }); +}; + +// Create a lagged collection of the detrended imagery. +var lagged17 = lag(detrended, detrended, 17); + +// Function to stack bands. +var merge = function(image) { + // Function to be passed to iterate. + var merger = function(current, previous) { + return ee.Image(previous).addBands(current); + }; + return ee.ImageCollection.fromImages(image.get('images')) + .iterate(merger, image); +}; + +// Apply merge function to the lagged collection. +var merged17 = ee.ImageCollection(lagged17.map(merge)); + +// Function to compute covariance. +var covariance = function(mergedCollection, band, lagBand) { + return mergedCollection.select([band, lagBand]).map(function( + image) { + return image.toArray(); + }).reduce(ee.Reducer.covariance(), 8); +}; + +// Concatenate the suffix to the NDVI band. +var lagBand = dependent.cat('_1'); + +// Compute covariance. +var covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) + .clip(roi); + +// The output of the covariance reducer is an array image, +// in which each pixel stores a 2x2 variance-covariance array. +// The off diagonal elements are covariance, which you can map +// directly using: +Map.addLayer(covariance17.arrayGet([0, 1]), + { + min: 0, + max: 0.02 + }, + 'covariance (lag = 17 days)'); + +// Define the correlation function. +var correlation = function(vcArrayImage) { + var covariance = ee.Image(vcArrayImage).arrayGet([0, 1]); + var sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt(); + var sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt(); + return covariance.divide(sd0).divide(sd1).rename( + 'correlation'); +}; + +// Apply the correlation function. +var correlation17 = correlation(covariance17).clip(roi); +Map.addLayer(correlation17, + { + min: -1, + max: 1 + }, + 'correlation (lag = 17 days)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +////////////////////// Cross-covariance and Cross-correlation ///////////////////// + +// Precipitation (covariate) +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Join the t-l (l=1 pentad) precipitation images to the Landsat. +var lag1PrecipNDVI = lag(landsat8sr, chirps, 5); + +// Add the precipitation images as bands. +var merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge)); + +// Compute and display cross-covariance. +var cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI', + 'precipitation').clip(roi); +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - PRECIP cov (lag = 5)'); + +// Compute and display cross-correlation. +var corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi); +Map.addLayer(corr1PrecipNDVI, { + min: -0.5, + max: 0.5 +}, 'NDVI - PRECIP corr (lag = 5)'); + +// Join the precipitation images from the previous month. +var lag30PrecipNDVI = lag(landsat8sr, chirps, 30); + +var sum30PrecipNDVI = ee.ImageCollection(lag30PrecipNDVI.map(function( + image) { + var laggedImages = ee.ImageCollection.fromImages(image + .get('images')); + return ee.Image(image).addBands(laggedImages.sum() + .rename('sum')); +})); + +// Compute covariance. +var cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip( + roi); +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - sum cov (lag = 30)'); + +// Correlation. +var corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi); +Map.addLayer(corr30PrecipNDVI, { + min: -0.5, + max: 0.5 +}, 'NDVI - sum corr (lag = 30)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49b Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49b Checkpoint.py new file mode 100644 index 0000000..d38a4b7 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49b Checkpoint.py @@ -0,0 +1,245 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.9 Exploring Lagged Effects in Time Series +# Checkpoint: F49b +# Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + timeRadians = ee.Image(years.multiply(2 * math.pi)) + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(timeRadians.rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Import region of interest. Area over California. +roi = ee.Geometry.Polygon([ + [-119.44617458417066,35.92639730653253], + [-119.07675930096754,35.92639730653253], + [-119.07675930096754,36.201704711823844], + [-119.44617458417066,36.201704711823844], + [-119.44617458417066,35.92639730653253] +]) + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, +# filter, mask clouds, scale, and add variables. +landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .filterDate('2013-01-01', '2018-01-01') \ + .map(maskScaleAndAddVariable) + +# Set map center. +Map.centerObject(roi, 10) + +# List of the independent variable names. +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('NDVI') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 band called coefficients (columns are for dependent variables). +trend = landsat8sr.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Flatten the coefficients into a 2-band image +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Compute a detrended series. + +def func_zrr(image): + return image.select(dependent) \ + .subtract(image.select(independents).multiply( + coefficients) \ + .reduce('sum')) \ + .rename(dependent) \ + .copyProperties(image, ['system:time_start']) + +detrended = landsat8sr.map(func_zrr) + + + + + + + + + +# Function that creates a lagged collection. +def lag(leftCollection, rightCollection, lagDays): + filter = ee.Filter.And( + ee.Filter.maxDifference({ + 'difference': 1000 * 60 * 60 * 24 * lagDays, + 'leftField': 'system:time_start', + 'rightField': 'system:time_start' + }), + ee.Filter.greaterThan({ + 'leftField': 'system:time_start', + 'rightField': 'system:time_start' + })) + + return ee.Join.saveAll({ + 'matchesKey': 'images', + 'measureKey': 'delta_t', + 'ordering': 'system:time_start', + 'ascending': False, # Sort reverse chronologically + }).apply({ + 'primary': leftCollection, + 'secondary': rightCollection, + 'condition': filter + }) + + +# Create a lagged collection of the detrended imagery. +lagged17 = lag(detrended, detrended, 17) + +# Function to stack bands. +def merge(image): + # Function to be passed to iterate. + def merger(current, previous): + return ee.Image(previous).addBands(current) + + return ee.ImageCollection.fromImages(image.get('images')) \ + .iterate(merger, image) + + +# Apply merge function to the lagged collection. +merged17 = ee.ImageCollection(lagged17.map(merge)) + +# Function to compute covariance. +def covariance(mergedCollection, band, lagBand): + image) { + return image.toArray() + }).reduce(ee.Reducer.covariance(), 8) + + +# Concatenate the suffix to the NDVI band. +lagBand = dependent.cat('_1') + +# Compute covariance. +covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) \ + .clip(roi) + +# The output of the covariance reducer is an array image, +# in which each pixel stores a 2x2 variance-covariance array. +# The off diagonal elements are covariance, which you can map +# directly using: +Map.addLayer(covariance17.arrayGet([0, 1]), + { + 'min': 0, + 'max': 0.02 + }, + 'covariance (lag = 17 days)') + +# Define the correlation function. +def correlation(vcArrayImage): + covariance = ee.Image(vcArrayImage).arrayGet([0, 1]) + sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt() + sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt() + return covariance.divide(sd0).divide(sd1).rename( + 'correlation') + + +# Apply the correlation function. +correlation17 = correlation(covariance17).clip(roi) +Map.addLayer(correlation17, + { + 'min': -1, + 'max': 1 + }, + 'correlation (lag = 17 days)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +########### Cross-covariance and Cross-correlation ##########/ + +# Precipitation (covariate) +chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') + +# Join the t-l (l=1 pentad) precipitation images to the Landsat. +lag1PrecipNDVI = lag(landsat8sr, chirps, 5) + +# Add the precipitation images as bands. +merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge)) + +# Compute and display cross-covariance. +cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI', + 'precipitation').clip(roi) +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - PRECIP cov (lag = 5)') + +# Compute and display cross-correlation. +corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi) +Map.addLayer(corr1PrecipNDVI, { + 'min': -0.5, + 'max': 0.5 +}, 'NDVI - PRECIP corr (lag = 5)') + +# Join the precipitation images from the previous month. +lag30PrecipNDVI = lag(landsat8sr, chirps, 30) + + image) { + laggedImages = ee.ImageCollection.fromImages(image \ + .get('images')) + return ee.Image(image).addBands(laggedImages.sum() \ + .rename('sum')) +})) + +# Compute covariance. +cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip( + roi) +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - sum cov (lag = 30)') + +# Correlation. +corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi) +Map.addLayer(corr30PrecipNDVI, { + 'min': -0.5, + 'max': 0.5 +}, 'NDVI - sum corr (lag = 30)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49c Checkpoint.ipynb new file mode 100644 index 0000000..21580b9 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49c Checkpoint.ipynb @@ -0,0 +1,400 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.9 Exploring Lagged Effects in Time Series\n", + "# Checkpoint: F49c\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " timeRadians = ee.Image(years.multiply(2 * math.pi))\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(timeRadians.rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Import region of interest. Area over California.\n", + "roi = ee.Geometry.Polygon([\n", + " [-119.44617458417066,35.92639730653253],\n", + " [-119.07675930096754,35.92639730653253],\n", + " [-119.07675930096754,36.201704711823844],\n", + " [-119.44617458417066,36.201704711823844],\n", + " [-119.44617458417066,35.92639730653253]\n", + "])\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection,\n", + "# filter, mask clouds, scale, and add variables.\n", + "landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2013-01-01', '2018-01-01') \\\n", + " .map(maskScaleAndAddVariable)\n", + "\n", + "# Set map center.\n", + "Map.centerObject(roi, 10)\n", + "\n", + "# List of the independent variable names.\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('NDVI')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 band called coefficients (columns are for dependent variables).\n", + "trend = landsat8sr.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Flatten the coefficients into a 2-band image\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Compute a detrended series.\n", + "\n", + "def func_pkf(image):\n", + " return image.select(dependent) \\\n", + " .subtract(image.select(independents).multiply(\n", + " coefficients) \\\n", + " .reduce('sum')) \\\n", + " .rename(dependent) \\\n", + " .copyProperties(image, ['system:time_start'])\n", + "\n", + "detrended = landsat8sr.map(func_pkf)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Function that creates a lagged collection.\n", + "def lag(leftCollection, rightCollection, lagDays):\n", + " filter = ee.Filter.And(\n", + " ee.Filter.maxDifference({\n", + " 'difference': 1000 * 60 * 60 * 24 * lagDays,\n", + " 'leftField': 'system:time_start',\n", + " 'rightField': 'system:time_start'\n", + " }),\n", + " ee.Filter.greaterThan({\n", + " 'leftField': 'system:time_start',\n", + " 'rightField': 'system:time_start'\n", + " }))\n", + "\n", + " return ee.Join.saveAll({\n", + " 'matchesKey': 'images',\n", + " 'measureKey': 'delta_t',\n", + " 'ordering': 'system:time_start',\n", + " 'ascending': False, # Sort reverse chronologically\n", + " }).apply({\n", + " 'primary': leftCollection,\n", + " 'secondary': rightCollection,\n", + " 'condition': filter\n", + " })\n", + "\n", + "\n", + "# Create a lagged collection of the detrended imagery.\n", + "lagged17 = lag(detrended, detrended, 17)\n", + "\n", + "# Function to stack bands.\n", + "def merge(image):\n", + " # Function to be passed to iterate.\n", + " def merger(current, previous):\n", + " return ee.Image(previous).addBands(current)\n", + " \n", + " return ee.ImageCollection.fromImages(image.get('images')) \\\n", + " .iterate(merger, image)\n", + "\n", + "\n", + "# Apply merge function to the lagged collection.\n", + "merged17 = ee.ImageCollection(lagged17.map(merge))\n", + "\n", + "# Function to compute covariance.\n", + "def covariance(mergedCollection, band, lagBand):\n", + " image) {\n", + " return image.toArray()\n", + " }).reduce(ee.Reducer.covariance(), 8)\n", + "\n", + "\n", + "# Concatenate the suffix to the NDVI band.\n", + "lagBand = dependent.cat('_1')\n", + "\n", + "# Compute covariance.\n", + "covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) \\\n", + " .clip(roi)\n", + "\n", + "# The output of the covariance reducer is an array image,\n", + "# in which each pixel stores a 2x2 variance-covariance array.\n", + "# The off diagonal elements are covariance, which you can map\n", + "# directly using:\n", + "Map.addLayer(covariance17.arrayGet([0, 1]),\n", + " {\n", + " 'min': 0,\n", + " 'max': 0.02\n", + " },\n", + " 'covariance (lag = 17 days)')\n", + "\n", + "# Define the correlation function.\n", + "def correlation(vcArrayImage):\n", + " covariance = ee.Image(vcArrayImage).arrayGet([0, 1])\n", + " sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt()\n", + " sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt()\n", + " return covariance.divide(sd0).divide(sd1).rename(\n", + " 'correlation')\n", + "\n", + "\n", + "# Apply the correlation function.\n", + "correlation17 = correlation(covariance17).clip(roi)\n", + "Map.addLayer(correlation17,\n", + " {\n", + " 'min': -1,\n", + " 'max': 1\n", + " },\n", + " 'correlation (lag = 17 days)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "########### Cross-covariance and Cross-correlation ##########/\n", + "\n", + "# Precipitation (covariate)\n", + "chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "\n", + "# Join the t-l (l=1 pentad) precipitation images to the Landsat.\n", + "lag1PrecipNDVI = lag(landsat8sr, chirps, 5)\n", + "\n", + "# Add the precipitation images as bands.\n", + "merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge))\n", + "\n", + "# Compute and display cross-covariance.\n", + "cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI',\n", + " 'precipitation').clip(roi)\n", + "Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {},\n", + " 'NDVI - PRECIP cov (lag = 5)')\n", + "\n", + "# Compute and display cross-correlation.\n", + "corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi)\n", + "Map.addLayer(corr1PrecipNDVI, {\n", + " 'min': -0.5,\n", + " 'max': 0.5\n", + "}, 'NDVI - PRECIP corr (lag = 5)')\n", + "\n", + "# Join the precipitation images from the previous month.\n", + "lag30PrecipNDVI = lag(landsat8sr, chirps, 30)\n", + "\n", + " image) {\n", + " laggedImages = ee.ImageCollection.fromImages(image \\\n", + " .get('images'))\n", + " return ee.Image(image).addBands(laggedImages.sum() \\\n", + " .rename('sum'))\n", + "}))\n", + "\n", + "# Compute covariance.\n", + "cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip(\n", + " roi)\n", + "Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {},\n", + " 'NDVI - sum cov (lag = 30)')\n", + "\n", + "# Correlation.\n", + "corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi)\n", + "Map.addLayer(corr30PrecipNDVI, {\n", + " 'min': -0.5,\n", + " 'max': 0.5\n", + "}, 'NDVI - sum corr (lag = 30)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "########### Auto-regressive models ##########/\n", + "\n", + "lagged34 = ee.ImageCollection(lag(landsat8sr, landsat8sr, 34))\n", + "\n", + "\n", + "def func_iog(image):\n", + " return image.set('n', ee.List(image.get('images')) \\\n", + " .length())\n", + "\n", + "merged34 = lagged34.map(merge).map(func_iog\n", + ").filter(ee.Filter.gt('n', 1))\n", + "\n", + "\n", + ").filter(ee.Filter.gt('n', 1))\n", + "\n", + "arIndependents = ee.List(['constant', 'NDVI_1', 'NDVI_2'])\n", + "\n", + "ar2 = merged34 \\\n", + " .select(arIndependents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(arIndependents.length(), 1))\n", + "\n", + "# Turn the array image into a multi-band image of coefficients.\n", + "arCoefficients = ar2.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([arIndependents])\n", + "\n", + "# Compute fitted values.\n", + "\n", + "def func_gce(image):\n", + " return image.addBands(\n", + " image.expression(\n", + " 'beta0 + beta1 * p1 + beta2 * p2', {\n", + " 'p1': image.select('NDVI_1'),\n", + " 'p2': image.select('NDVI_2'),\n", + " 'beta0': arCoefficients.select('constant'),\n", + " 'beta1': arCoefficients.select('NDVI_1'),\n", + " 'beta2': arCoefficients.select('NDVI_2')\n", + " }).rename('fitted'))\n", + "\n", + "fittedAR = merged34.map(func_gce)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Create an Earth Engine point object to print the time series chart.\n", + "pt = ee.Geometry.Point([-119.0955, 35.9909])\n", + "\n", + "print(ui.Chart.image.series(\n", + " fittedAR.select(['fitted', 'NDVI']), pt, ee.Reducer \\\n", + " .mean(), 30) \\\n", + " .setSeriesNames(['NDVI', 'fitted']) \\\n", + " .setOptions({\n", + " 'title': 'AR(2) model: original and fitted values',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " }))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49c Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49c Checkpoint.js new file mode 100644 index 0000000..7441a94 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49c Checkpoint.js @@ -0,0 +1,284 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.9 Exploring Lagged Effects in Time Series +// Checkpoint: F49c +// Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + var timeRadians = ee.Image(years.multiply(2 * Math.PI)); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(timeRadians.rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import region of interest. Area over California. +var roi = ee.Geometry.Polygon([ + [-119.44617458417066,35.92639730653253], + [-119.07675930096754,35.92639730653253], + [-119.07675930096754,36.201704711823844], + [-119.44617458417066,36.201704711823844], + [-119.44617458417066,35.92639730653253] +]); + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center. +Map.centerObject(roi, 10); + +// List of the independent variable names. +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('NDVI'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = landsat8sr.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image +var coefficients = trend.select('coefficients') + // Get rid of extra dimensions and convert back to a regular image + .arrayProject([0]) + .arrayFlatten([independents]); + +// Compute a detrended series. +var detrended = landsat8sr.map(function(image) { + return image.select(dependent) + .subtract(image.select(independents).multiply( + coefficients) + .reduce('sum')) + .rename(dependent) + .copyProperties(image, ['system:time_start']); +}); + +// Function that creates a lagged collection. +var lag = function(leftCollection, rightCollection, lagDays) { + var filter = ee.Filter.and( + ee.Filter.maxDifference({ + difference: 1000 * 60 * 60 * 24 * lagDays, + leftField: 'system:time_start', + rightField: 'system:time_start' + }), + ee.Filter.greaterThan({ + leftField: 'system:time_start', + rightField: 'system:time_start' + })); + + return ee.Join.saveAll({ + matchesKey: 'images', + measureKey: 'delta_t', + ordering: 'system:time_start', + ascending: false, // Sort reverse chronologically + }).apply({ + primary: leftCollection, + secondary: rightCollection, + condition: filter + }); +}; + +// Create a lagged collection of the detrended imagery. +var lagged17 = lag(detrended, detrended, 17); + +// Function to stack bands. +var merge = function(image) { + // Function to be passed to iterate. + var merger = function(current, previous) { + return ee.Image(previous).addBands(current); + }; + return ee.ImageCollection.fromImages(image.get('images')) + .iterate(merger, image); +}; + +// Apply merge function to the lagged collection. +var merged17 = ee.ImageCollection(lagged17.map(merge)); + +// Function to compute covariance. +var covariance = function(mergedCollection, band, lagBand) { + return mergedCollection.select([band, lagBand]).map(function( + image) { + return image.toArray(); + }).reduce(ee.Reducer.covariance(), 8); +}; + +// Concatenate the suffix to the NDVI band. +var lagBand = dependent.cat('_1'); + +// Compute covariance. +var covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) + .clip(roi); + +// The output of the covariance reducer is an array image, +// in which each pixel stores a 2x2 variance-covariance array. +// The off diagonal elements are covariance, which you can map +// directly using: +Map.addLayer(covariance17.arrayGet([0, 1]), + { + min: 0, + max: 0.02 + }, + 'covariance (lag = 17 days)'); + +// Define the correlation function. +var correlation = function(vcArrayImage) { + var covariance = ee.Image(vcArrayImage).arrayGet([0, 1]); + var sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt(); + var sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt(); + return covariance.divide(sd0).divide(sd1).rename( + 'correlation'); +}; + +// Apply the correlation function. +var correlation17 = correlation(covariance17).clip(roi); +Map.addLayer(correlation17, + { + min: -1, + max: 1 + }, + 'correlation (lag = 17 days)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +////////////////////// Cross-covariance and Cross-correlation ///////////////////// + +// Precipitation (covariate) +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Join the t-l (l=1 pentad) precipitation images to the Landsat. +var lag1PrecipNDVI = lag(landsat8sr, chirps, 5); + +// Add the precipitation images as bands. +var merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge)); + +// Compute and display cross-covariance. +var cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI', + 'precipitation').clip(roi); +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - PRECIP cov (lag = 5)'); + +// Compute and display cross-correlation. +var corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi); +Map.addLayer(corr1PrecipNDVI, { + min: -0.5, + max: 0.5 +}, 'NDVI - PRECIP corr (lag = 5)'); + +// Join the precipitation images from the previous month. +var lag30PrecipNDVI = lag(landsat8sr, chirps, 30); + +var sum30PrecipNDVI = ee.ImageCollection(lag30PrecipNDVI.map(function( + image) { + var laggedImages = ee.ImageCollection.fromImages(image + .get('images')); + return ee.Image(image).addBands(laggedImages.sum() + .rename('sum')); +})); + +// Compute covariance. +var cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip( + roi); +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - sum cov (lag = 30)'); + +// Correlation. +var corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi); +Map.addLayer(corr30PrecipNDVI, { + min: -0.5, + max: 0.5 +}, 'NDVI - sum corr (lag = 30)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +////////////////////// Auto-regressive models ///////////////////// + +var lagged34 = ee.ImageCollection(lag(landsat8sr, landsat8sr, 34)); + +var merged34 = lagged34.map(merge).map(function(image) { + return image.set('n', ee.List(image.get('images')) + .length()); +}).filter(ee.Filter.gt('n', 1)); + +var arIndependents = ee.List(['constant', 'NDVI_1', 'NDVI_2']); + +var ar2 = merged34 + .select(arIndependents.add(dependent)) + .reduce(ee.Reducer.linearRegression(arIndependents.length(), 1)); + +// Turn the array image into a multi-band image of coefficients. +var arCoefficients = ar2.select('coefficients') + .arrayProject([0]) + .arrayFlatten([arIndependents]); + +// Compute fitted values. +var fittedAR = merged34.map(function(image) { + return image.addBands( + image.expression( + 'beta0 + beta1 * p1 + beta2 * p2', { + p1: image.select('NDVI_1'), + p2: image.select('NDVI_2'), + beta0: arCoefficients.select('constant'), + beta1: arCoefficients.select('NDVI_1'), + beta2: arCoefficients.select('NDVI_2') + }).rename('fitted')); +}); + +// Create an Earth Engine point object to print the time series chart. +var pt = ee.Geometry.Point([-119.0955, 35.9909]); + +print(ui.Chart.image.series( + fittedAR.select(['fitted', 'NDVI']), pt, ee.Reducer + .mean(), 30) + .setSeriesNames(['NDVI', 'fitted']) + .setOptions({ + title: 'AR(2) model: original and fitted values', + lineWidth: 1, + pointSize: 3, + })); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49c Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49c Checkpoint.py new file mode 100644 index 0000000..f851eed --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49c Checkpoint.py @@ -0,0 +1,314 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.9 Exploring Lagged Effects in Time Series +# Checkpoint: F49c +# Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + timeRadians = ee.Image(years.multiply(2 * math.pi)) + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(timeRadians.rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Import region of interest. Area over California. +roi = ee.Geometry.Polygon([ + [-119.44617458417066,35.92639730653253], + [-119.07675930096754,35.92639730653253], + [-119.07675930096754,36.201704711823844], + [-119.44617458417066,36.201704711823844], + [-119.44617458417066,35.92639730653253] +]) + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, +# filter, mask clouds, scale, and add variables. +landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .filterDate('2013-01-01', '2018-01-01') \ + .map(maskScaleAndAddVariable) + +# Set map center. +Map.centerObject(roi, 10) + +# List of the independent variable names. +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('NDVI') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 band called coefficients (columns are for dependent variables). +trend = landsat8sr.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Flatten the coefficients into a 2-band image +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Compute a detrended series. + +def func_pkf(image): + return image.select(dependent) \ + .subtract(image.select(independents).multiply( + coefficients) \ + .reduce('sum')) \ + .rename(dependent) \ + .copyProperties(image, ['system:time_start']) + +detrended = landsat8sr.map(func_pkf) + + + + + + + + + +# Function that creates a lagged collection. +def lag(leftCollection, rightCollection, lagDays): + filter = ee.Filter.And( + ee.Filter.maxDifference({ + 'difference': 1000 * 60 * 60 * 24 * lagDays, + 'leftField': 'system:time_start', + 'rightField': 'system:time_start' + }), + ee.Filter.greaterThan({ + 'leftField': 'system:time_start', + 'rightField': 'system:time_start' + })) + + return ee.Join.saveAll({ + 'matchesKey': 'images', + 'measureKey': 'delta_t', + 'ordering': 'system:time_start', + 'ascending': False, # Sort reverse chronologically + }).apply({ + 'primary': leftCollection, + 'secondary': rightCollection, + 'condition': filter + }) + + +# Create a lagged collection of the detrended imagery. +lagged17 = lag(detrended, detrended, 17) + +# Function to stack bands. +def merge(image): + # Function to be passed to iterate. + def merger(current, previous): + return ee.Image(previous).addBands(current) + + return ee.ImageCollection.fromImages(image.get('images')) \ + .iterate(merger, image) + + +# Apply merge function to the lagged collection. +merged17 = ee.ImageCollection(lagged17.map(merge)) + +# Function to compute covariance. +def covariance(mergedCollection, band, lagBand): + image) { + return image.toArray() + }).reduce(ee.Reducer.covariance(), 8) + + +# Concatenate the suffix to the NDVI band. +lagBand = dependent.cat('_1') + +# Compute covariance. +covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) \ + .clip(roi) + +# The output of the covariance reducer is an array image, +# in which each pixel stores a 2x2 variance-covariance array. +# The off diagonal elements are covariance, which you can map +# directly using: +Map.addLayer(covariance17.arrayGet([0, 1]), + { + 'min': 0, + 'max': 0.02 + }, + 'covariance (lag = 17 days)') + +# Define the correlation function. +def correlation(vcArrayImage): + covariance = ee.Image(vcArrayImage).arrayGet([0, 1]) + sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt() + sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt() + return covariance.divide(sd0).divide(sd1).rename( + 'correlation') + + +# Apply the correlation function. +correlation17 = correlation(covariance17).clip(roi) +Map.addLayer(correlation17, + { + 'min': -1, + 'max': 1 + }, + 'correlation (lag = 17 days)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +########### Cross-covariance and Cross-correlation ##########/ + +# Precipitation (covariate) +chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') + +# Join the t-l (l=1 pentad) precipitation images to the Landsat. +lag1PrecipNDVI = lag(landsat8sr, chirps, 5) + +# Add the precipitation images as bands. +merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge)) + +# Compute and display cross-covariance. +cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI', + 'precipitation').clip(roi) +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - PRECIP cov (lag = 5)') + +# Compute and display cross-correlation. +corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi) +Map.addLayer(corr1PrecipNDVI, { + 'min': -0.5, + 'max': 0.5 +}, 'NDVI - PRECIP corr (lag = 5)') + +# Join the precipitation images from the previous month. +lag30PrecipNDVI = lag(landsat8sr, chirps, 30) + + image) { + laggedImages = ee.ImageCollection.fromImages(image \ + .get('images')) + return ee.Image(image).addBands(laggedImages.sum() \ + .rename('sum')) +})) + +# Compute covariance. +cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip( + roi) +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - sum cov (lag = 30)') + +# Correlation. +corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi) +Map.addLayer(corr30PrecipNDVI, { + 'min': -0.5, + 'max': 0.5 +}, 'NDVI - sum corr (lag = 30)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +########### Auto-regressive models ##########/ + +lagged34 = ee.ImageCollection(lag(landsat8sr, landsat8sr, 34)) + + +def func_iog(image): + return image.set('n', ee.List(image.get('images')) \ + .length()) + +merged34 = lagged34.map(merge).map(func_iog +).filter(ee.Filter.gt('n', 1)) + + +).filter(ee.Filter.gt('n', 1)) + +arIndependents = ee.List(['constant', 'NDVI_1', 'NDVI_2']) + +ar2 = merged34 \ + .select(arIndependents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(arIndependents.length(), 1)) + +# Turn the array image into a multi-band image of coefficients. +arCoefficients = ar2.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([arIndependents]) + +# Compute fitted values. + +def func_gce(image): + return image.addBands( + image.expression( + 'beta0 + beta1 * p1 + beta2 * p2', { + 'p1': image.select('NDVI_1'), + 'p2': image.select('NDVI_2'), + 'beta0': arCoefficients.select('constant'), + 'beta1': arCoefficients.select('NDVI_1'), + 'beta2': arCoefficients.select('NDVI_2') + }).rename('fitted')) + +fittedAR = merged34.map(func_gce) + + + + + + + + + + + + +# Create an Earth Engine point object to print the time series chart. +pt = ee.Geometry.Point([-119.0955, 35.9909]) + +print(ui.Chart.image.series( + fittedAR.select(['fitted', 'NDVI']), pt, ee.Reducer \ + .mean(), 30) \ + .setSeriesNames(['NDVI', 'fitted']) \ + .setOptions({ + 'title': 'AR(2) model: original and fitted values', + 'lineWidth': 1, + 'pointSize': 3, + })) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49d Checkpoint.ipynb new file mode 100644 index 0000000..26ef74e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49d Checkpoint.ipynb @@ -0,0 +1,514 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F4.9 Exploring Lagged Effects in Time Series\n", + "# Checkpoint: F49d\n", + "# Authors: Andr\u00e9a Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Define function to mask clouds, scale, and add variables\n", + "# (NDVI, time and a constant) to Landsat 8 imagery.\n", + "def maskScaleAndAddVariable(image):\n", + " # Bit 0 - Fill\n", + " # Bit 1 - Dilated Cloud\n", + " # Bit 2 - Cirrus\n", + " # Bit 3 - Cloud\n", + " # Bit 4 - Cloud Shadow\n", + " qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = image.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " opticalBands = image.select('SR_B.').multiply(0.0000275).add(-\n", + " 0.2)\n", + " thermalBands = image.select('ST_B.*').multiply(0.00341802) \\\n", + " .add(149.0)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " img = image.addBands(opticalBands, None, True) \\\n", + " .addBands(thermalBands, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + " imgScaled = image.addBands(img, None, True)\n", + "\n", + " # Now we start to add variables of interest.\n", + " # Compute time in fractional years since the epoch.\n", + " date = ee.Date(image.get('system:time_start'))\n", + " years = date.difference(ee.Date('1970-01-01'), 'year')\n", + " timeRadians = ee.Image(years.multiply(2 * math.pi))\n", + " # Return the image with the added bands.\n", + " return imgScaled \\\n", + " .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \\\n", + " .rename('NDVI')) \\\n", + " .addBands(timeRadians.rename('t')) \\\n", + " .float() \\\n", + " .addBands(ee.Image.constant(1))\n", + "\n", + "\n", + "# Import region of interest. Area over California.\n", + "roi = ee.Geometry.Polygon([\n", + " [-119.44617458417066,35.92639730653253],\n", + " [-119.07675930096754,35.92639730653253],\n", + " [-119.07675930096754,36.201704711823844],\n", + " [-119.44617458417066,36.201704711823844],\n", + " [-119.44617458417066,35.92639730653253]\n", + "])\n", + "\n", + "# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection,\n", + "# filter, mask clouds, scale, and add variables.\n", + "landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate('2013-01-01', '2018-01-01') \\\n", + " .map(maskScaleAndAddVariable)\n", + "\n", + "# Set map center.\n", + "Map.centerObject(roi, 10)\n", + "\n", + "# List of the independent variable names.\n", + "independents = ee.List(['constant', 't'])\n", + "\n", + "# Name of the dependent variable.\n", + "dependent = ee.String('NDVI')\n", + "\n", + "# Compute a linear trend. This will have two bands: 'residuals' and\n", + "# a 2x1 band called coefficients (columns are for dependent variables).\n", + "trend = landsat8sr.select(independents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(independents.length(), 1))\n", + "\n", + "# Flatten the coefficients into a 2-band image\n", + "coefficients = trend.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([independents])\n", + "\n", + "# Compute a detrended series.\n", + "\n", + "def func_hhj(image):\n", + " return image.select(dependent) \\\n", + " .subtract(image.select(independents).multiply(\n", + " coefficients) \\\n", + " .reduce('sum')) \\\n", + " .rename(dependent) \\\n", + " .copyProperties(image, ['system:time_start'])\n", + "\n", + "detrended = landsat8sr.map(func_hhj)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Function that creates a lagged collection.\n", + "def lag(leftCollection, rightCollection, lagDays):\n", + " filter = ee.Filter.And(\n", + " ee.Filter.maxDifference({\n", + " 'difference': 1000 * 60 * 60 * 24 * lagDays,\n", + " 'leftField': 'system:time_start',\n", + " 'rightField': 'system:time_start'\n", + " }),\n", + " ee.Filter.greaterThan({\n", + " 'leftField': 'system:time_start',\n", + " 'rightField': 'system:time_start'\n", + " }))\n", + "\n", + " return ee.Join.saveAll({\n", + " 'matchesKey': 'images',\n", + " 'measureKey': 'delta_t',\n", + " 'ordering': 'system:time_start',\n", + " 'ascending': False, # Sort reverse chronologically\n", + " }).apply({\n", + " 'primary': leftCollection,\n", + " 'secondary': rightCollection,\n", + " 'condition': filter\n", + " })\n", + "\n", + "\n", + "# Create a lagged collection of the detrended imagery.\n", + "lagged17 = lag(detrended, detrended, 17)\n", + "\n", + "# Function to stack bands.\n", + "def merge(image):\n", + " # Function to be passed to iterate.\n", + " def merger(current, previous):\n", + " return ee.Image(previous).addBands(current)\n", + " \n", + " return ee.ImageCollection.fromImages(image.get('images')) \\\n", + " .iterate(merger, image)\n", + "\n", + "\n", + "# Apply merge function to the lagged collection.\n", + "merged17 = ee.ImageCollection(lagged17.map(merge))\n", + "\n", + "# Function to compute covariance.\n", + "def covariance(mergedCollection, band, lagBand):\n", + " image) {\n", + " return image.toArray()\n", + " }).reduce(ee.Reducer.covariance(), 8)\n", + "\n", + "\n", + "# Concatenate the suffix to the NDVI band.\n", + "lagBand = dependent.cat('_1')\n", + "\n", + "# Compute covariance.\n", + "covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) \\\n", + " .clip(roi)\n", + "\n", + "# The output of the covariance reducer is an array image,\n", + "# in which each pixel stores a 2x2 variance-covariance array.\n", + "# The off diagonal elements are covariance, which you can map\n", + "# directly using:\n", + "Map.addLayer(covariance17.arrayGet([0, 1]),\n", + " {\n", + " 'min': 0,\n", + " 'max': 0.02\n", + " },\n", + " 'covariance (lag = 17 days)')\n", + "\n", + "# Define the correlation function.\n", + "def correlation(vcArrayImage):\n", + " covariance = ee.Image(vcArrayImage).arrayGet([0, 1])\n", + " sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt()\n", + " sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt()\n", + " return covariance.divide(sd0).divide(sd1).rename(\n", + " 'correlation')\n", + "\n", + "\n", + "# Apply the correlation function.\n", + "correlation17 = correlation(covariance17).clip(roi)\n", + "Map.addLayer(correlation17,\n", + " {\n", + " 'min': -1,\n", + " 'max': 1\n", + " },\n", + " 'correlation (lag = 17 days)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "########### Cross-covariance and Cross-correlation ##########/\n", + "\n", + "# Precipitation (covariate)\n", + "chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')\n", + "\n", + "# Join the t-l (l=1 pentad) precipitation images to the Landsat.\n", + "lag1PrecipNDVI = lag(landsat8sr, chirps, 5)\n", + "\n", + "# Add the precipitation images as bands.\n", + "merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge))\n", + "\n", + "# Compute and display cross-covariance.\n", + "cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI',\n", + " 'precipitation').clip(roi)\n", + "Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {},\n", + " 'NDVI - PRECIP cov (lag = 5)')\n", + "\n", + "# Compute and display cross-correlation.\n", + "corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi)\n", + "Map.addLayer(corr1PrecipNDVI, {\n", + " 'min': -0.5,\n", + " 'max': 0.5\n", + "}, 'NDVI - PRECIP corr (lag = 5)')\n", + "\n", + "# Join the precipitation images from the previous month.\n", + "lag30PrecipNDVI = lag(landsat8sr, chirps, 30)\n", + "\n", + " image) {\n", + " laggedImages = ee.ImageCollection.fromImages(image \\\n", + " .get('images'))\n", + " return ee.Image(image).addBands(laggedImages.sum() \\\n", + " .rename('sum'))\n", + "}))\n", + "\n", + "# Compute covariance.\n", + "cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip(\n", + " roi)\n", + "Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {},\n", + " 'NDVI - sum cov (lag = 30)')\n", + "\n", + "# Correlation.\n", + "corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi)\n", + "Map.addLayer(corr30PrecipNDVI, {\n", + " 'min': -0.5,\n", + " 'max': 0.5\n", + "}, 'NDVI - sum corr (lag = 30)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "########### Auto-regressive models ##########/\n", + "\n", + "lagged34 = ee.ImageCollection(lag(landsat8sr, landsat8sr, 34))\n", + "\n", + "\n", + "def func_trh(image):\n", + " return image.set('n', ee.List(image.get('images')) \\\n", + " .length())\n", + "\n", + "merged34 = lagged34.map(merge).map(func_trh\n", + ").filter(ee.Filter.gt('n', 1))\n", + "\n", + "\n", + ").filter(ee.Filter.gt('n', 1))\n", + "\n", + "arIndependents = ee.List(['constant', 'NDVI_1', 'NDVI_2'])\n", + "\n", + "ar2 = merged34 \\\n", + " .select(arIndependents.add(dependent)) \\\n", + " .reduce(ee.Reducer.linearRegression(arIndependents.length(), 1))\n", + "\n", + "# Turn the array image into a multi-band image of coefficients.\n", + "arCoefficients = ar2.select('coefficients') \\\n", + " .arrayProject([0]) \\\n", + " .arrayFlatten([arIndependents])\n", + "\n", + "# Compute fitted values.\n", + "\n", + "def func_gnj(image):\n", + " return image.addBands(\n", + " image.expression(\n", + " 'beta0 + beta1 * p1 + beta2 * p2', {\n", + " 'p1': image.select('NDVI_1'),\n", + " 'p2': image.select('NDVI_2'),\n", + " 'beta0': arCoefficients.select('constant'),\n", + " 'beta1': arCoefficients.select('NDVI_1'),\n", + " 'beta2': arCoefficients.select('NDVI_2')\n", + " }).rename('fitted'))\n", + "\n", + "fittedAR = merged34.map(func_gnj)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Create an Earth Engine point object to print the time series chart.\n", + "pt = ee.Geometry.Point([-119.0955, 35.9909])\n", + "\n", + "print(ui.Chart.image.series(\n", + " fittedAR.select(['fitted', 'NDVI']), pt, ee.Reducer \\\n", + " .mean(), 30) \\\n", + " .setSeriesNames(['NDVI', 'fitted']) \\\n", + " .setOptions({\n", + " 'title': 'AR(2) model: original and fitted values',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " }))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "########/ Forecasting ############/\n", + "\n", + "# Forecasting\n", + "def fill(current, list):\n", + " # Get the date of the last image in the list.\n", + " latestDate = ee.Image(ee.List(list).get(-1)).date()\n", + " # Get the date of the current image being processed.\n", + " currentDate = ee.Image(current).date()\n", + " # If those two dates are more than 16 days apart, there's\n", + " # a temporal gap in the sequence. To fill in the gap, compute\n", + " # the potential starting and ending dates of the gap.\n", + " start = latestDate.advance(16, 'day').millis()\n", + " end = currentDate.advance(-16, 'day').millis()\n", + " # Determine if the start and end dates are chronological.\n", + " blankImages = ee.Algorithms.If({\n", + " # Watch out for this. Might need a tolerance here.\n", + " 'condition': start.lt(end),\n", + " # Make a sequence of dates to fill in with empty images.\n", + " 'TrueCase': ee.List.sequence({\n", + " 'start': start,\n", + " 'end': end,\n", + " 'step': 1000 * 60 * 60 * 24 * 16\n", + "\n", + "def func_qlc(date):\n", + " # Return a dummy image with a masked NDVI band and a date.\n", + " return ee.Image(0).mask(0).rename(\n", + " 'NDVI').set({\n", + " 'dummy': True,\n", + " 'system:time_start': ee \\\n", + " .Date(date).millis()\n", + " })\n", + "\n", + " }).map(func_qlc\n", + "),\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "),\n", + " # If there's no gap, return an empty list.\n", + " 'FalseCase': []\n", + " })\n", + " # Add any dummy images and the current image to the list.\n", + " return ee.List(list).cat(blankImages).add(current)\n", + "\n", + "\n", + "# The first image is the starting image.\n", + "first = landsat8sr.first()\n", + "\n", + "# The first image is duplicated in this list, so slice it off.\n", + "filled = ee.List(landsat8sr.iterate(fill, [first])).slice(1)\n", + "\n", + "# Now, map a function over this list to do the prediction.\n", + "indices = ee.List.sequence(5, filled.length().subtract(1))\n", + "\n", + "# A function to forecast from the previous two images.\n", + "def forecast(current, list):\n", + " ndvi = ee.Image(current).select('NDVI')\n", + " # Get the t-1 and t-2 images.\n", + " size = ee.List(list).size()\n", + " image1 = ee.Image(ee.List(list).get(size.subtract(1)))\n", + " image2 = ee.Image(ee.List(list).get(size.subtract(2)))\n", + "\n", + " predicted = ee.Image().expression(\n", + " 'beta0 + beta1 * p1 + beta2 * p2', {\n", + " 'p1': image1.select('NDVI'),\n", + " 'p2': image2.select('NDVI'),\n", + " 'beta0': arCoefficients.select('constant'),\n", + " 'beta1': arCoefficients.select('NDVI_1'),\n", + " 'beta2': arCoefficients.select('NDVI_2')\n", + " }).rename('NDVI') \\\n", + " .set('system:time_start', current.get(\n", + " 'system:time_start'))\n", + "\n", + " # Replace the entire image if it's a dummy.\n", + " replaced = ee.Algorithms.If({\n", + " 'condition': current.get('dummy'),\n", + " 'TrueCase': predicted,\n", + " # Otherwise replace only masked pixels.\n", + " 'FalseCase': current.addBands({\n", + " 'srcImg': ndvi.unmask().where(ndvi \\\n", + " .mask().Not(), predicted).rename(\n", + " 'NDVI'),\n", + " 'overwrite': True\n", + " })\n", + " })\n", + " # Add the predicted image to the list.\n", + " return ee.List(list).add(replaced)\n", + "\n", + "\n", + "# Start at a point in the sequence with three consecutive real images.\n", + "startList = filled.slice(4, 5)\n", + "\n", + "# Iterate over the filled series to replace dummy images with predictions.\n", + "modeled = ee.ImageCollection.fromImages(\n", + " ee.ImageCollection(filled).iterate(forecast, startList)) \\\n", + " .select('NDVI')\n", + "\n", + "print(ui.Chart.image.series(\n", + " modeled, pt, ee.Reducer.mean(), 30) \\\n", + " .setSeriesNames(['NDVI']) \\\n", + " .setOptions({\n", + " 'title': 'Forecast',\n", + " 'lineWidth': 1,\n", + " 'pointSize': 3,\n", + " }))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49d Checkpoint.js b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49d Checkpoint.js new file mode 100644 index 0000000..9ac7f98 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49d Checkpoint.js @@ -0,0 +1,387 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F4.9 Exploring Lagged Effects in Time Series +// Checkpoint: F49d +// Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + var timeRadians = ee.Image(years.multiply(2 * Math.PI)); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(timeRadians.rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import region of interest. Area over California. +var roi = ee.Geometry.Polygon([ + [-119.44617458417066,35.92639730653253], + [-119.07675930096754,35.92639730653253], + [-119.07675930096754,36.201704711823844], + [-119.44617458417066,36.201704711823844], + [-119.44617458417066,35.92639730653253] +]); + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center. +Map.centerObject(roi, 10); + +// List of the independent variable names. +var independents = ee.List(['constant', 't']); + +// Name of the dependent variable. +var dependent = ee.String('NDVI'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = landsat8sr.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image +var coefficients = trend.select('coefficients') + // Get rid of extra dimensions and convert back to a regular image + .arrayProject([0]) + .arrayFlatten([independents]); + +// Compute a detrended series. +var detrended = landsat8sr.map(function(image) { + return image.select(dependent) + .subtract(image.select(independents).multiply( + coefficients) + .reduce('sum')) + .rename(dependent) + .copyProperties(image, ['system:time_start']); +}); + +// Function that creates a lagged collection. +var lag = function(leftCollection, rightCollection, lagDays) { + var filter = ee.Filter.and( + ee.Filter.maxDifference({ + difference: 1000 * 60 * 60 * 24 * lagDays, + leftField: 'system:time_start', + rightField: 'system:time_start' + }), + ee.Filter.greaterThan({ + leftField: 'system:time_start', + rightField: 'system:time_start' + })); + + return ee.Join.saveAll({ + matchesKey: 'images', + measureKey: 'delta_t', + ordering: 'system:time_start', + ascending: false, // Sort reverse chronologically + }).apply({ + primary: leftCollection, + secondary: rightCollection, + condition: filter + }); +}; + +// Create a lagged collection of the detrended imagery. +var lagged17 = lag(detrended, detrended, 17); + +// Function to stack bands. +var merge = function(image) { + // Function to be passed to iterate. + var merger = function(current, previous) { + return ee.Image(previous).addBands(current); + }; + return ee.ImageCollection.fromImages(image.get('images')) + .iterate(merger, image); +}; + +// Apply merge function to the lagged collection. +var merged17 = ee.ImageCollection(lagged17.map(merge)); + +// Function to compute covariance. +var covariance = function(mergedCollection, band, lagBand) { + return mergedCollection.select([band, lagBand]).map(function( + image) { + return image.toArray(); + }).reduce(ee.Reducer.covariance(), 8); +}; + +// Concatenate the suffix to the NDVI band. +var lagBand = dependent.cat('_1'); + +// Compute covariance. +var covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) + .clip(roi); + +// The output of the covariance reducer is an array image, +// in which each pixel stores a 2x2 variance-covariance array. +// The off diagonal elements are covariance, which you can map +// directly using: +Map.addLayer(covariance17.arrayGet([0, 1]), + { + min: 0, + max: 0.02 + }, + 'covariance (lag = 17 days)'); + +// Define the correlation function. +var correlation = function(vcArrayImage) { + var covariance = ee.Image(vcArrayImage).arrayGet([0, 1]); + var sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt(); + var sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt(); + return covariance.divide(sd0).divide(sd1).rename( + 'correlation'); +}; + +// Apply the correlation function. +var correlation17 = correlation(covariance17).clip(roi); +Map.addLayer(correlation17, + { + min: -1, + max: 1 + }, + 'correlation (lag = 17 days)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +////////////////////// Cross-covariance and Cross-correlation ///////////////////// + +// Precipitation (covariate) +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); + +// Join the t-l (l=1 pentad) precipitation images to the Landsat. +var lag1PrecipNDVI = lag(landsat8sr, chirps, 5); + +// Add the precipitation images as bands. +var merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge)); + +// Compute and display cross-covariance. +var cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI', + 'precipitation').clip(roi); +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - PRECIP cov (lag = 5)'); + +// Compute and display cross-correlation. +var corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi); +Map.addLayer(corr1PrecipNDVI, { + min: -0.5, + max: 0.5 +}, 'NDVI - PRECIP corr (lag = 5)'); + +// Join the precipitation images from the previous month. +var lag30PrecipNDVI = lag(landsat8sr, chirps, 30); + +var sum30PrecipNDVI = ee.ImageCollection(lag30PrecipNDVI.map(function( + image) { + var laggedImages = ee.ImageCollection.fromImages(image + .get('images')); + return ee.Image(image).addBands(laggedImages.sum() + .rename('sum')); +})); + +// Compute covariance. +var cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip( + roi); +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - sum cov (lag = 30)'); + +// Correlation. +var corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi); +Map.addLayer(corr30PrecipNDVI, { + min: -0.5, + max: 0.5 +}, 'NDVI - sum corr (lag = 30)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +////////////////////// Auto-regressive models ///////////////////// + +var lagged34 = ee.ImageCollection(lag(landsat8sr, landsat8sr, 34)); + +var merged34 = lagged34.map(merge).map(function(image) { + return image.set('n', ee.List(image.get('images')) + .length()); +}).filter(ee.Filter.gt('n', 1)); + +var arIndependents = ee.List(['constant', 'NDVI_1', 'NDVI_2']); + +var ar2 = merged34 + .select(arIndependents.add(dependent)) + .reduce(ee.Reducer.linearRegression(arIndependents.length(), 1)); + +// Turn the array image into a multi-band image of coefficients. +var arCoefficients = ar2.select('coefficients') + .arrayProject([0]) + .arrayFlatten([arIndependents]); + +// Compute fitted values. +var fittedAR = merged34.map(function(image) { + return image.addBands( + image.expression( + 'beta0 + beta1 * p1 + beta2 * p2', { + p1: image.select('NDVI_1'), + p2: image.select('NDVI_2'), + beta0: arCoefficients.select('constant'), + beta1: arCoefficients.select('NDVI_1'), + beta2: arCoefficients.select('NDVI_2') + }).rename('fitted')); +}); + +// Create an Earth Engine point object to print the time series chart. +var pt = ee.Geometry.Point([-119.0955, 35.9909]); + +print(ui.Chart.image.series( + fittedAR.select(['fitted', 'NDVI']), pt, ee.Reducer + .mean(), 30) + .setSeriesNames(['NDVI', 'fitted']) + .setOptions({ + title: 'AR(2) model: original and fitted values', + lineWidth: 1, + pointSize: 3, + })); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +///////////////// Forecasting ///////////////////////// + +// Forecasting +var fill = function(current, list) { + // Get the date of the last image in the list. + var latestDate = ee.Image(ee.List(list).get(-1)).date(); + // Get the date of the current image being processed. + var currentDate = ee.Image(current).date(); + // If those two dates are more than 16 days apart, there's + // a temporal gap in the sequence. To fill in the gap, compute + // the potential starting and ending dates of the gap. + var start = latestDate.advance(16, 'day').millis(); + var end = currentDate.advance(-16, 'day').millis(); + // Determine if the start and end dates are chronological. + var blankImages = ee.Algorithms.If({ + // Watch out for this. Might need a tolerance here. + condition: start.lt(end), + // Make a sequence of dates to fill in with empty images. + trueCase: ee.List.sequence({ + start: start, + end: end, + step: 1000 * 60 * 60 * 24 * 16 + }).map(function(date) { + // Return a dummy image with a masked NDVI band and a date. + return ee.Image(0).mask(0).rename( + 'NDVI').set({ + 'dummy': true, + 'system:time_start': ee + .Date(date).millis() + }); + }), + // If there's no gap, return an empty list. + falseCase: [] + }); + // Add any dummy images and the current image to the list. + return ee.List(list).cat(blankImages).add(current); +}; + +// The first image is the starting image. +var first = landsat8sr.first(); + +// The first image is duplicated in this list, so slice it off. +var filled = ee.List(landsat8sr.iterate(fill, [first])).slice(1); + +// Now, map a function over this list to do the prediction. +var indices = ee.List.sequence(5, filled.length().subtract(1)); + +// A function to forecast from the previous two images. +var forecast = function(current, list) { + var ndvi = ee.Image(current).select('NDVI'); + // Get the t-1 and t-2 images. + var size = ee.List(list).size(); + var image1 = ee.Image(ee.List(list).get(size.subtract(1))); + var image2 = ee.Image(ee.List(list).get(size.subtract(2))); + + var predicted = ee.Image().expression( + 'beta0 + beta1 * p1 + beta2 * p2', { + p1: image1.select('NDVI'), + p2: image2.select('NDVI'), + beta0: arCoefficients.select('constant'), + beta1: arCoefficients.select('NDVI_1'), + beta2: arCoefficients.select('NDVI_2') + }).rename('NDVI') + .set('system:time_start', current.get( + 'system:time_start')); + + // Replace the entire image if it's a dummy. + var replaced = ee.Algorithms.If({ + condition: current.get('dummy'), + trueCase: predicted, + // Otherwise replace only masked pixels. + falseCase: current.addBands({ + srcImg: ndvi.unmask().where(ndvi + .mask().not(), predicted).rename( + 'NDVI'), + overwrite: true + }) + }); + // Add the predicted image to the list. + return ee.List(list).add(replaced); +}; + +// Start at a point in the sequence with three consecutive real images. +var startList = filled.slice(4, 5); + +// Iterate over the filled series to replace dummy images with predictions. +var modeled = ee.ImageCollection.fromImages( + ee.ImageCollection(filled).iterate(forecast, startList)) + .select('NDVI'); + +print(ui.Chart.image.series( + modeled, pt, ee.Reducer.mean(), 30) + .setSeriesNames(['NDVI']) + .setOptions({ + title: 'Forecast', + lineWidth: 1, + pointSize: 3, + })); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49d Checkpoint.py b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49d Checkpoint.py new file mode 100644 index 0000000..cdf35ac --- /dev/null +++ b/docs/book/Part F - Fundamentals/F4 - Interpreting Image Series/F4.9 Exploring Lagged Effects in Time Series/F49d Checkpoint.py @@ -0,0 +1,428 @@ +import ee +import math +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F4.9 Exploring Lagged Effects in Time Series +# Checkpoint: F49d +# Authors: Andréa Puzzi Nicolau, Karen Dyson, David Saah, Nicholas Clinton +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define function to mask clouds, scale, and add variables +# (NDVI, time and a constant) to Landsat 8 imagery. +def maskScaleAndAddVariable(image): + # Bit 0 - Fill + # Bit 1 - Dilated Cloud + # Bit 2 - Cirrus + # Bit 3 - Cloud + # Bit 4 - Cloud Shadow + qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = image.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2) + thermalBands = image.select('ST_B.*').multiply(0.00341802) \ + .add(149.0) + + # Replace the original bands with the scaled ones and apply the masks. + img = image.addBands(opticalBands, None, True) \ + .addBands(thermalBands, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + imgScaled = image.addBands(img, None, True) + + # Now we start to add variables of interest. + # Compute time in fractional years since the epoch. + date = ee.Date(image.get('system:time_start')) + years = date.difference(ee.Date('1970-01-01'), 'year') + timeRadians = ee.Image(years.multiply(2 * math.pi)) + # Return the image with the added bands. + return imgScaled \ + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) \ + .rename('NDVI')) \ + .addBands(timeRadians.rename('t')) \ + .float() \ + .addBands(ee.Image.constant(1)) + + +# Import region of interest. Area over California. +roi = ee.Geometry.Polygon([ + [-119.44617458417066,35.92639730653253], + [-119.07675930096754,35.92639730653253], + [-119.07675930096754,36.201704711823844], + [-119.44617458417066,36.201704711823844], + [-119.44617458417066,35.92639730653253] +]) + +# Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, +# filter, mask clouds, scale, and add variables. +landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(roi) \ + .filterDate('2013-01-01', '2018-01-01') \ + .map(maskScaleAndAddVariable) + +# Set map center. +Map.centerObject(roi, 10) + +# List of the independent variable names. +independents = ee.List(['constant', 't']) + +# Name of the dependent variable. +dependent = ee.String('NDVI') + +# Compute a linear trend. This will have two bands: 'residuals' and +# a 2x1 band called coefficients (columns are for dependent variables). +trend = landsat8sr.select(independents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(independents.length(), 1)) + +# Flatten the coefficients into a 2-band image +coefficients = trend.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([independents]) + +# Compute a detrended series. + +def func_hhj(image): + return image.select(dependent) \ + .subtract(image.select(independents).multiply( + coefficients) \ + .reduce('sum')) \ + .rename(dependent) \ + .copyProperties(image, ['system:time_start']) + +detrended = landsat8sr.map(func_hhj) + + + + + + + + + +# Function that creates a lagged collection. +def lag(leftCollection, rightCollection, lagDays): + filter = ee.Filter.And( + ee.Filter.maxDifference({ + 'difference': 1000 * 60 * 60 * 24 * lagDays, + 'leftField': 'system:time_start', + 'rightField': 'system:time_start' + }), + ee.Filter.greaterThan({ + 'leftField': 'system:time_start', + 'rightField': 'system:time_start' + })) + + return ee.Join.saveAll({ + 'matchesKey': 'images', + 'measureKey': 'delta_t', + 'ordering': 'system:time_start', + 'ascending': False, # Sort reverse chronologically + }).apply({ + 'primary': leftCollection, + 'secondary': rightCollection, + 'condition': filter + }) + + +# Create a lagged collection of the detrended imagery. +lagged17 = lag(detrended, detrended, 17) + +# Function to stack bands. +def merge(image): + # Function to be passed to iterate. + def merger(current, previous): + return ee.Image(previous).addBands(current) + + return ee.ImageCollection.fromImages(image.get('images')) \ + .iterate(merger, image) + + +# Apply merge function to the lagged collection. +merged17 = ee.ImageCollection(lagged17.map(merge)) + +# Function to compute covariance. +def covariance(mergedCollection, band, lagBand): + image) { + return image.toArray() + }).reduce(ee.Reducer.covariance(), 8) + + +# Concatenate the suffix to the NDVI band. +lagBand = dependent.cat('_1') + +# Compute covariance. +covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) \ + .clip(roi) + +# The output of the covariance reducer is an array image, +# in which each pixel stores a 2x2 variance-covariance array. +# The off diagonal elements are covariance, which you can map +# directly using: +Map.addLayer(covariance17.arrayGet([0, 1]), + { + 'min': 0, + 'max': 0.02 + }, + 'covariance (lag = 17 days)') + +# Define the correlation function. +def correlation(vcArrayImage): + covariance = ee.Image(vcArrayImage).arrayGet([0, 1]) + sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt() + sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt() + return covariance.divide(sd0).divide(sd1).rename( + 'correlation') + + +# Apply the correlation function. +correlation17 = correlation(covariance17).clip(roi) +Map.addLayer(correlation17, + { + 'min': -1, + 'max': 1 + }, + 'correlation (lag = 17 days)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +########### Cross-covariance and Cross-correlation ##########/ + +# Precipitation (covariate) +chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD') + +# Join the t-l (l=1 pentad) precipitation images to the Landsat. +lag1PrecipNDVI = lag(landsat8sr, chirps, 5) + +# Add the precipitation images as bands. +merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge)) + +# Compute and display cross-covariance. +cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI', + 'precipitation').clip(roi) +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - PRECIP cov (lag = 5)') + +# Compute and display cross-correlation. +corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi) +Map.addLayer(corr1PrecipNDVI, { + 'min': -0.5, + 'max': 0.5 +}, 'NDVI - PRECIP corr (lag = 5)') + +# Join the precipitation images from the previous month. +lag30PrecipNDVI = lag(landsat8sr, chirps, 30) + + image) { + laggedImages = ee.ImageCollection.fromImages(image \ + .get('images')) + return ee.Image(image).addBands(laggedImages.sum() \ + .rename('sum')) +})) + +# Compute covariance. +cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip( + roi) +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - sum cov (lag = 30)') + +# Correlation. +corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi) +Map.addLayer(corr30PrecipNDVI, { + 'min': -0.5, + 'max': 0.5 +}, 'NDVI - sum corr (lag = 30)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +########### Auto-regressive models ##########/ + +lagged34 = ee.ImageCollection(lag(landsat8sr, landsat8sr, 34)) + + +def func_trh(image): + return image.set('n', ee.List(image.get('images')) \ + .length()) + +merged34 = lagged34.map(merge).map(func_trh +).filter(ee.Filter.gt('n', 1)) + + +).filter(ee.Filter.gt('n', 1)) + +arIndependents = ee.List(['constant', 'NDVI_1', 'NDVI_2']) + +ar2 = merged34 \ + .select(arIndependents.add(dependent)) \ + .reduce(ee.Reducer.linearRegression(arIndependents.length(), 1)) + +# Turn the array image into a multi-band image of coefficients. +arCoefficients = ar2.select('coefficients') \ + .arrayProject([0]) \ + .arrayFlatten([arIndependents]) + +# Compute fitted values. + +def func_gnj(image): + return image.addBands( + image.expression( + 'beta0 + beta1 * p1 + beta2 * p2', { + 'p1': image.select('NDVI_1'), + 'p2': image.select('NDVI_2'), + 'beta0': arCoefficients.select('constant'), + 'beta1': arCoefficients.select('NDVI_1'), + 'beta2': arCoefficients.select('NDVI_2') + }).rename('fitted')) + +fittedAR = merged34.map(func_gnj) + + + + + + + + + + + + +# Create an Earth Engine point object to print the time series chart. +pt = ee.Geometry.Point([-119.0955, 35.9909]) + +print(ui.Chart.image.series( + fittedAR.select(['fitted', 'NDVI']), pt, ee.Reducer \ + .mean(), 30) \ + .setSeriesNames(['NDVI', 'fitted']) \ + .setOptions({ + 'title': 'AR(2) model: original and fitted values', + 'lineWidth': 1, + 'pointSize': 3, + })) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +########/ Forecasting ############/ + +# Forecasting +def fill(current, list): + # Get the date of the last image in the list. + latestDate = ee.Image(ee.List(list).get(-1)).date() + # Get the date of the current image being processed. + currentDate = ee.Image(current).date() + # If those two dates are more than 16 days apart, there's + # a temporal gap in the sequence. To fill in the gap, compute + # the potential starting and ending dates of the gap. + start = latestDate.advance(16, 'day').millis() + end = currentDate.advance(-16, 'day').millis() + # Determine if the start and end dates are chronological. + blankImages = ee.Algorithms.If({ + # Watch out for this. Might need a tolerance here. + 'condition': start.lt(end), + # Make a sequence of dates to fill in with empty images. + 'TrueCase': ee.List.sequence({ + 'start': start, + 'end': end, + 'step': 1000 * 60 * 60 * 24 * 16 + +def func_qlc(date): + # Return a dummy image with a masked NDVI band and a date. + return ee.Image(0).mask(0).rename( + 'NDVI').set({ + 'dummy': True, + 'system:time_start': ee \ + .Date(date).millis() + }) + + }).map(func_qlc +), + + + + + + + +), + # If there's no gap, return an empty list. + 'FalseCase': [] + }) + # Add any dummy images and the current image to the list. + return ee.List(list).cat(blankImages).add(current) + + +# The first image is the starting image. +first = landsat8sr.first() + +# The first image is duplicated in this list, so slice it off. +filled = ee.List(landsat8sr.iterate(fill, [first])).slice(1) + +# Now, map a function over this list to do the prediction. +indices = ee.List.sequence(5, filled.length().subtract(1)) + +# A function to forecast from the previous two images. +def forecast(current, list): + ndvi = ee.Image(current).select('NDVI') + # Get the t-1 and t-2 images. + size = ee.List(list).size() + image1 = ee.Image(ee.List(list).get(size.subtract(1))) + image2 = ee.Image(ee.List(list).get(size.subtract(2))) + + predicted = ee.Image().expression( + 'beta0 + beta1 * p1 + beta2 * p2', { + 'p1': image1.select('NDVI'), + 'p2': image2.select('NDVI'), + 'beta0': arCoefficients.select('constant'), + 'beta1': arCoefficients.select('NDVI_1'), + 'beta2': arCoefficients.select('NDVI_2') + }).rename('NDVI') \ + .set('system:time_start', current.get( + 'system:time_start')) + + # Replace the entire image if it's a dummy. + replaced = ee.Algorithms.If({ + 'condition': current.get('dummy'), + 'TrueCase': predicted, + # Otherwise replace only masked pixels. + 'FalseCase': current.addBands({ + 'srcImg': ndvi.unmask().where(ndvi \ + .mask().Not(), predicted).rename( + 'NDVI'), + 'overwrite': True + }) + }) + # Add the predicted image to the list. + return ee.List(list).add(replaced) + + +# Start at a point in the sequence with three consecutive real images. +startList = filled.slice(4, 5) + +# Iterate over the filled series to replace dummy images with predictions. +modeled = ee.ImageCollection.fromImages( + ee.ImageCollection(filled).iterate(forecast, startList)) \ + .select('NDVI') + +print(ui.Chart.image.series( + modeled, pt, ee.Reducer.mean(), 30) \ + .setSeriesNames(['NDVI']) \ + .setOptions({ + 'title': 'Forecast', + 'lineWidth': 1, + 'pointSize': 3, + })) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50a Checkpoint.ipynb new file mode 100644 index 0000000..b9bfab7 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50a Checkpoint.ipynb @@ -0,0 +1,143 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "usf_building =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Polygon(\n", + " [[[-122.45136729605188, 37.77692986089728],\n", + " [-122.45126000769129, 37.77633201208984],\n", + " [-122.45136193163385, 37.77631505176946],\n", + " [-122.45131901628962, 37.776132728079645],\n", + " [-122.45086840517511, 37.776187849242575],\n", + " [-122.4509005916833, 37.77637017279647],\n", + " [-122.45101860887995, 37.77635321248484],\n", + " [-122.45112053282251, 37.776789939269314],\n", + " [-122.4506484640359, 37.776849299992314],\n", + " [-122.45067528612604, 37.777014661755025]]]),\n", + " usf_campus =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.MultiPolygon(\n", + " [[[[-122.45387746358996, 37.78025485651328],\n", + " [-122.4534697678197, 37.77791441971873],\n", + " [-122.4489851143468, 37.77849105595329],\n", + " [-122.44962884451037, 37.78076363731525]]],\n", + " [[[-122.45295922018377, 37.775902746563965],\n", + " [-122.45270172811834, 37.77512256326928],\n", + " [-122.44941870428411, 37.77552113619849],\n", + " [-122.44960109449713, 37.77630979544932],\n", + " [-122.44678009874097, 37.776725234224465],\n", + " [-122.44701613313428, 37.777590200803616],\n", + " [-122.45311011201612, 37.776860915925724]]],\n", + " [[[-122.45492520933641, 37.77589822903132],\n", + " [-122.45316568022264, 37.7761356745013],\n", + " [-122.45350900297655, 37.77776385146553],\n", + " [-122.45511832838548, 37.77756033130608]]]]),\n", + " usf_point =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([-122.45124246920876, 37.77652242316423])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.0 Exploring Vectors\n", + "# Checkpoint: F50a\n", + "# Authors: AJ Purdy, Ellen Brock, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# This script contains the Imports, but no code (yet).\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50a Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50a Checkpoint.js new file mode 100644 index 0000000..8f44171 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50a Checkpoint.js @@ -0,0 +1,51 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var usf_building = + /* color: #bf04c2 */ + /* shown: false */ + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + /* color: #ff0000 */ + /* shown: false */ + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + /* color: #00ffff */ + /* shown: false */ + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.0 Exploring Vectors +// Checkpoint: F50a +// Authors: AJ Purdy, Ellen Brock, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// This script contains the Imports, but no code (yet). + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50a Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50a Checkpoint.py new file mode 100644 index 0000000..5ab4075 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50a Checkpoint.py @@ -0,0 +1,57 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +usf_building = + + # shown: False # + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + + # shown: False # + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + + # shown: False # + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.0 Exploring Vectors +# Checkpoint: F50a +# Authors: AJ Purdy, Ellen Brock, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# This script contains the Imports, but no code (yet). + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50b Checkpoint.ipynb new file mode 100644 index 0000000..f5ff58c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50b Checkpoint.ipynb @@ -0,0 +1,165 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "usf_building =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Polygon(\n", + " [[[-122.45136729605188, 37.77692986089728],\n", + " [-122.45126000769129, 37.77633201208984],\n", + " [-122.45136193163385, 37.77631505176946],\n", + " [-122.45131901628962, 37.776132728079645],\n", + " [-122.45086840517511, 37.776187849242575],\n", + " [-122.4509005916833, 37.77637017279647],\n", + " [-122.45101860887995, 37.77635321248484],\n", + " [-122.45112053282251, 37.776789939269314],\n", + " [-122.4506484640359, 37.776849299992314],\n", + " [-122.45067528612604, 37.777014661755025]]]),\n", + " usf_campus =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.MultiPolygon(\n", + " [[[[-122.45387746358996, 37.78025485651328],\n", + " [-122.4534697678197, 37.77791441971873],\n", + " [-122.4489851143468, 37.77849105595329],\n", + " [-122.44962884451037, 37.78076363731525]]],\n", + " [[[-122.45295922018377, 37.775902746563965],\n", + " [-122.45270172811834, 37.77512256326928],\n", + " [-122.44941870428411, 37.77552113619849],\n", + " [-122.44960109449713, 37.77630979544932],\n", + " [-122.44678009874097, 37.776725234224465],\n", + " [-122.44701613313428, 37.777590200803616],\n", + " [-122.45311011201612, 37.776860915925724]]],\n", + " [[[-122.45492520933641, 37.77589822903132],\n", + " [-122.45316568022264, 37.7761356745013],\n", + " [-122.45350900297655, 37.77776385146553],\n", + " [-122.45511832838548, 37.77756033130608]]]]),\n", + " usf_point =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([-122.45124246920876, 37.77652242316423])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.0 Exploring Vectors\n", + "# Checkpoint: F50b\n", + "# Authors: AJ Purdy, Ellen Brock, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Census Tiger Boundaries from GEE.\n", + "tiger = ee.FeatureCollection('TIGER/2010/Blocks')\n", + "\n", + "# Add the new feature collection to the map, but do not display.\n", + "Map.addLayer(tiger, {\n", + " 'color': 'black'\n", + "}, 'Tiger', False)\n", + "\n", + "# Assign the feature collection to the variable sfNeighborhoods.\n", + "sfNeighborhoods = ee.FeatureCollection(\n", + " 'path/to/your/asset/assetname')\n", + "\n", + "# Note: if you are unable to load the feature collection, you\n", + "# can access the data by uncommenting out the following two lines:\n", + "# tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods'\n", + "# sfNeighborhoods = ee.FeatureCollection(tablePath)\n", + "\n", + "# Print the size of the feature collection.\n", + "# (Answers the question: how many features?)\n", + "print(sfNeighborhoods.size())\n", + "Map.addLayer(sfNeighborhoods, {\n", + " 'color': 'blue'\n", + "}, 'sfNeighborhoods')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50b Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50b Checkpoint.js new file mode 100644 index 0000000..ee99984 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50b Checkpoint.js @@ -0,0 +1,72 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var usf_building = + /* color: #bf04c2 */ + /* shown: false */ + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + /* color: #ff0000 */ + /* shown: false */ + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + /* color: #00ffff */ + /* shown: false */ + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.0 Exploring Vectors +// Checkpoint: F50b +// Authors: AJ Purdy, Ellen Brock, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Census Tiger Boundaries from GEE. +var tiger = ee.FeatureCollection('TIGER/2010/Blocks'); + +// Add the new feature collection to the map, but do not display. +Map.addLayer(tiger, { + 'color': 'black' +}, 'Tiger', false); + +// Assign the feature collection to the variable sfNeighborhoods. +var sfNeighborhoods = ee.FeatureCollection( + 'path/to/your/asset/assetname'); + +// Note: if you are unable to load the feature collection, you +// can access the data by uncommenting out the following two lines: +// var tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods'; +// var sfNeighborhoods = ee.FeatureCollection(tablePath); + +// Print the size of the feature collection. +// (Answers the question: how many features?) +print(sfNeighborhoods.size()); +Map.addLayer(sfNeighborhoods, { + 'color': 'blue' +}, 'sfNeighborhoods'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50b Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50b Checkpoint.py new file mode 100644 index 0000000..da8673a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50b Checkpoint.py @@ -0,0 +1,78 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +usf_building = + + # shown: False # + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + + # shown: False # + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + + # shown: False # + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.0 Exploring Vectors +# Checkpoint: F50b +# Authors: AJ Purdy, Ellen Brock, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Census Tiger Boundaries from GEE. +tiger = ee.FeatureCollection('TIGER/2010/Blocks') + +# Add the new feature collection to the map, but do not display. +Map.addLayer(tiger, { + 'color': 'black' +}, 'Tiger', False) + +# Assign the feature collection to the variable sfNeighborhoods. +sfNeighborhoods = ee.FeatureCollection( + 'path/to/your/asset/assetname') + +# Note: if you are unable to load the feature collection, you +# can access the data by uncommenting out the following two lines: +# tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods' +# sfNeighborhoods = ee.FeatureCollection(tablePath) + +# Print the size of the feature collection. +# (Answers the question: how many features?) +print(sfNeighborhoods.size()) +Map.addLayer(sfNeighborhoods, { + 'color': 'blue' +}, 'sfNeighborhoods') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50c Checkpoint.ipynb new file mode 100644 index 0000000..12ea94c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50c Checkpoint.ipynb @@ -0,0 +1,201 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "usf_building =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Polygon(\n", + " [[[-122.45136729605188, 37.77692986089728],\n", + " [-122.45126000769129, 37.77633201208984],\n", + " [-122.45136193163385, 37.77631505176946],\n", + " [-122.45131901628962, 37.776132728079645],\n", + " [-122.45086840517511, 37.776187849242575],\n", + " [-122.4509005916833, 37.77637017279647],\n", + " [-122.45101860887995, 37.77635321248484],\n", + " [-122.45112053282251, 37.776789939269314],\n", + " [-122.4506484640359, 37.776849299992314],\n", + " [-122.45067528612604, 37.777014661755025]]]),\n", + " usf_campus =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.MultiPolygon(\n", + " [[[[-122.45387746358996, 37.78025485651328],\n", + " [-122.4534697678197, 37.77791441971873],\n", + " [-122.4489851143468, 37.77849105595329],\n", + " [-122.44962884451037, 37.78076363731525]]],\n", + " [[[-122.45295922018377, 37.775902746563965],\n", + " [-122.45270172811834, 37.77512256326928],\n", + " [-122.44941870428411, 37.77552113619849],\n", + " [-122.44960109449713, 37.77630979544932],\n", + " [-122.44678009874097, 37.776725234224465],\n", + " [-122.44701613313428, 37.777590200803616],\n", + " [-122.45311011201612, 37.776860915925724]]],\n", + " [[[-122.45492520933641, 37.77589822903132],\n", + " [-122.45316568022264, 37.7761356745013],\n", + " [-122.45350900297655, 37.77776385146553],\n", + " [-122.45511832838548, 37.77756033130608]]]]),\n", + " usf_point =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([-122.45124246920876, 37.77652242316423])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.0 Exploring Vectors\n", + "# Checkpoint: F50c\n", + "# Authors: AJ Purdy, Ellen Brock, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Census Tiger Boundaries from GEE.\n", + "tiger = ee.FeatureCollection('TIGER/2010/Blocks')\n", + "\n", + "# Add the new feature collection to the map, but do not display.\n", + "Map.addLayer(tiger, {\n", + " 'color': 'black'\n", + "}, 'Tiger', False)\n", + "\n", + "# Assign the feature collection to the variable sfNeighborhoods.\n", + "sfNeighborhoods = ee.FeatureCollection(\n", + " 'path/to/your/asset/assetname')\n", + "\n", + "# Note: if you are unable to load the feature collection, you\n", + "# can access the data by uncommenting out the following two lines:\n", + "# tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods'\n", + "# sfNeighborhoods = ee.FeatureCollection(tablePath)\n", + "\n", + "\n", + "\n", + "# Print the size of the feature collection.\n", + "# (Answers the question: how many features?)\n", + "print(sfNeighborhoods.size())\n", + "Map.addLayer(sfNeighborhoods, {\n", + " 'color': 'blue'\n", + "}, 'sfNeighborhoods')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Filter sfNeighborhoods by USF.\n", + "usfNeighborhood = sfNeighborhoods.filterBounds(usf_point)\n", + "\n", + "# Filter the Census blocks by the boundary of the neighborhood layer.\n", + "usfTiger = tiger.filterBounds(usfNeighborhood)\n", + "Map.addLayer(usfTiger, {}, 'usf_Tiger')\n", + "\n", + "print(usfTiger)\n", + "\n", + "# Filter for census blocks by housing units\n", + "housing10_l250 = usfTiger \\\n", + " .filter(ee.Filter.lt('housing10', 250))\n", + "\n", + "housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt(\n", + " 'housing10', 50))\n", + "\n", + "Map.addLayer(housing10_g50_l250, {\n", + " 'color': 'Magenta'\n", + "}, 'housing')\n", + "\n", + "housing_area = housing10_g50_l250.geometry().area()\n", + "print('housing_area:', housing_area)\n", + "\n", + "housing10_mean = usfTiger.reduceColumns({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'selectors': ['housing10']\n", + "})\n", + "\n", + "print('housing10_mean', housing10_mean)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50c Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50c Checkpoint.js new file mode 100644 index 0000000..f0801cc --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50c Checkpoint.js @@ -0,0 +1,108 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var usf_building = + /* color: #bf04c2 */ + /* shown: false */ + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + /* color: #ff0000 */ + /* shown: false */ + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + /* color: #00ffff */ + /* shown: false */ + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.0 Exploring Vectors +// Checkpoint: F50c +// Authors: AJ Purdy, Ellen Brock, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Census Tiger Boundaries from GEE. +var tiger = ee.FeatureCollection('TIGER/2010/Blocks'); + +// Add the new feature collection to the map, but do not display. +Map.addLayer(tiger, { + 'color': 'black' +}, 'Tiger', false); + +// Assign the feature collection to the variable sfNeighborhoods. +var sfNeighborhoods = ee.FeatureCollection( + 'path/to/your/asset/assetname'); + +// Note: if you are unable to load the feature collection, you +// can access the data by uncommenting out the following two lines: +// var tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods'; +// var sfNeighborhoods = ee.FeatureCollection(tablePath); + + + +// Print the size of the feature collection. +// (Answers the question: how many features?) +print(sfNeighborhoods.size()); +Map.addLayer(sfNeighborhoods, { + 'color': 'blue' +}, 'sfNeighborhoods'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Filter sfNeighborhoods by USF. +var usfNeighborhood = sfNeighborhoods.filterBounds(usf_point); + +// Filter the Census blocks by the boundary of the neighborhood layer. +var usfTiger = tiger.filterBounds(usfNeighborhood); +Map.addLayer(usfTiger, {}, 'usf_Tiger'); + +print(usfTiger); + +// Filter for census blocks by housing units +var housing10_l250 = usfTiger + .filter(ee.Filter.lt('housing10', 250)); + +var housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt( + 'housing10', 50)); + +Map.addLayer(housing10_g50_l250, { + 'color': 'Magenta' +}, 'housing'); + +var housing_area = housing10_g50_l250.geometry().area(); +print('housing_area:', housing_area); + +var housing10_mean = usfTiger.reduceColumns({ + reducer: ee.Reducer.mean(), + selectors: ['housing10'] +}); + +print('housing10_mean', housing10_mean); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50c Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50c Checkpoint.py new file mode 100644 index 0000000..f40626f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50c Checkpoint.py @@ -0,0 +1,114 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +usf_building = + + # shown: False # + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + + # shown: False # + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + + # shown: False # + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.0 Exploring Vectors +# Checkpoint: F50c +# Authors: AJ Purdy, Ellen Brock, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Census Tiger Boundaries from GEE. +tiger = ee.FeatureCollection('TIGER/2010/Blocks') + +# Add the new feature collection to the map, but do not display. +Map.addLayer(tiger, { + 'color': 'black' +}, 'Tiger', False) + +# Assign the feature collection to the variable sfNeighborhoods. +sfNeighborhoods = ee.FeatureCollection( + 'path/to/your/asset/assetname') + +# Note: if you are unable to load the feature collection, you +# can access the data by uncommenting out the following two lines: +# tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods' +# sfNeighborhoods = ee.FeatureCollection(tablePath) + + + +# Print the size of the feature collection. +# (Answers the question: how many features?) +print(sfNeighborhoods.size()) +Map.addLayer(sfNeighborhoods, { + 'color': 'blue' +}, 'sfNeighborhoods') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Filter sfNeighborhoods by USF. +usfNeighborhood = sfNeighborhoods.filterBounds(usf_point) + +# Filter the Census blocks by the boundary of the neighborhood layer. +usfTiger = tiger.filterBounds(usfNeighborhood) +Map.addLayer(usfTiger, {}, 'usf_Tiger') + +print(usfTiger) + +# Filter for census blocks by housing units +housing10_l250 = usfTiger \ + .filter(ee.Filter.lt('housing10', 250)) + +housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt( + 'housing10', 50)) + +Map.addLayer(housing10_g50_l250, { + 'color': 'Magenta' +}, 'housing') + +housing_area = housing10_g50_l250.geometry().area() +print('housing_area:', housing_area) + +housing10_mean = usfTiger.reduceColumns({ + 'reducer': ee.Reducer.mean(), + 'selectors': ['housing10'] +}) + +print('housing10_mean', housing10_mean) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50d Checkpoint.ipynb new file mode 100644 index 0000000..9b3d978 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50d Checkpoint.ipynb @@ -0,0 +1,242 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "usf_building =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Polygon(\n", + " [[[-122.45136729605188, 37.77692986089728],\n", + " [-122.45126000769129, 37.77633201208984],\n", + " [-122.45136193163385, 37.77631505176946],\n", + " [-122.45131901628962, 37.776132728079645],\n", + " [-122.45086840517511, 37.776187849242575],\n", + " [-122.4509005916833, 37.77637017279647],\n", + " [-122.45101860887995, 37.77635321248484],\n", + " [-122.45112053282251, 37.776789939269314],\n", + " [-122.4506484640359, 37.776849299992314],\n", + " [-122.45067528612604, 37.777014661755025]]]),\n", + " usf_campus =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.MultiPolygon(\n", + " [[[[-122.45387746358996, 37.78025485651328],\n", + " [-122.4534697678197, 37.77791441971873],\n", + " [-122.4489851143468, 37.77849105595329],\n", + " [-122.44962884451037, 37.78076363731525]]],\n", + " [[[-122.45295922018377, 37.775902746563965],\n", + " [-122.45270172811834, 37.77512256326928],\n", + " [-122.44941870428411, 37.77552113619849],\n", + " [-122.44960109449713, 37.77630979544932],\n", + " [-122.44678009874097, 37.776725234224465],\n", + " [-122.44701613313428, 37.777590200803616],\n", + " [-122.45311011201612, 37.776860915925724]]],\n", + " [[[-122.45492520933641, 37.77589822903132],\n", + " [-122.45316568022264, 37.7761356745013],\n", + " [-122.45350900297655, 37.77776385146553],\n", + " [-122.45511832838548, 37.77756033130608]]]]),\n", + " usf_point =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([-122.45124246920876, 37.77652242316423])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.0 Exploring Vectors\n", + "# Checkpoint: F50d\n", + "# Authors: AJ Purdy, Ellen Brock, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Census Tiger Boundaries from GEE.\n", + "tiger = ee.FeatureCollection('TIGER/2010/Blocks')\n", + "\n", + "# Add the new feature collection to the map, but do not display.\n", + "Map.addLayer(tiger, {\n", + " 'color': 'black'\n", + "}, 'Tiger', False)\n", + "\n", + "# Assign the feature collection to the variable sfNeighborhoods.\n", + "sfNeighborhoods = ee.FeatureCollection(\n", + " 'path/to/your/asset/assetname')\n", + "\n", + "# Note: if you are unable to load the feature collection, you\n", + "# can access the data by uncommenting out the following two lines:\n", + "# tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods'\n", + "# sfNeighborhoods = ee.FeatureCollection(tablePath)\n", + "\n", + "\n", + "\n", + "# Print the size of the feature collection.\n", + "# (Answers the question: how many features?)\n", + "print(sfNeighborhoods.size())\n", + "Map.addLayer(sfNeighborhoods, {\n", + " 'color': 'blue'\n", + "}, 'sfNeighborhoods')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Filter sfNeighborhoods by USF.\n", + "usfNeighborhood = sfNeighborhoods.filterBounds(usf_point)\n", + "\n", + "# Filter the Census blocks by the boundary of the neighborhood layer.\n", + "usfTiger = tiger.filterBounds(usfNeighborhood)\n", + "Map.addLayer(usfTiger, {}, 'usf_Tiger')\n", + "\n", + "print(usfTiger)\n", + "\n", + "# Filter for census blocks by housing units\n", + "housing10_l250 = usfTiger \\\n", + " .filter(ee.Filter.lt('housing10', 250))\n", + "\n", + "housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt(\n", + " 'housing10', 50))\n", + "\n", + "Map.addLayer(housing10_g50_l250, {\n", + " 'color': 'Magenta'\n", + "}, 'housing')\n", + "\n", + "housing_area = housing10_g50_l250.geometry().area()\n", + "print('housing_area:', housing_area)\n", + "\n", + "housing10_mean = usfTiger.reduceColumns({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'selectors': ['housing10']\n", + "})\n", + "\n", + "print('housing10_mean', housing10_mean)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Import the Landsat 8 TOA image collection.\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')\n", + "\n", + "# Get the least cloudy image in 2015.\n", + "image = ee.Image(landsat8 \\\n", + " .filterBounds(usf_point) \\\n", + " .filterDate('2015-01-01', '2015-12-31') \\\n", + " .sort('CLOUD_COVER') \\\n", + " .first())\n", + "\n", + "nir = image.select('B5')\n", + "red = image.select('B4')\n", + "ndvi = nir.subtract(red).divide(nir.add(red)).rename('NDVI')\n", + "\n", + "ndviParams = {\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + "}\n", + "\n", + "ndviUSFblocks = ndvi.clip(housing10_g50_l250)\n", + "Map.addLayer(ndviUSFblocks, ndviParams, 'NDVI image')\n", + "Map.centerObject(usf_point, 14)\n", + "\n", + "# Reduce image by feature to compute a statistic e.g. mean, max, min etc.\n", + "ndviPerBlock = ndviUSFblocks.reduceRegions({\n", + " 'collection': housing10_g50_l250,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 30,\n", + "})\n", + "\n", + "# Get a table of data out of Google Earth Engine.\n", + "Export.table.toDrive({\n", + " 'collection': ndviPerBlock,\n", + " 'description': 'NDVI_by_block_near_USF'\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50d Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50d Checkpoint.js new file mode 100644 index 0000000..1be0630 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50d Checkpoint.js @@ -0,0 +1,150 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var usf_building = + /* color: #bf04c2 */ + /* shown: false */ + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + /* color: #ff0000 */ + /* shown: false */ + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + /* color: #00ffff */ + /* shown: false */ + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.0 Exploring Vectors +// Checkpoint: F50d +// Authors: AJ Purdy, Ellen Brock, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Census Tiger Boundaries from GEE. +var tiger = ee.FeatureCollection('TIGER/2010/Blocks'); + +// Add the new feature collection to the map, but do not display. +Map.addLayer(tiger, { + 'color': 'black' +}, 'Tiger', false); + +// Assign the feature collection to the variable sfNeighborhoods. +var sfNeighborhoods = ee.FeatureCollection( + 'path/to/your/asset/assetname'); + +// Note: if you are unable to load the feature collection, you +// can access the data by uncommenting out the following two lines: +// var tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods'; +// var sfNeighborhoods = ee.FeatureCollection(tablePath); + + + +// Print the size of the feature collection. +// (Answers the question: how many features?) +print(sfNeighborhoods.size()); +Map.addLayer(sfNeighborhoods, { + 'color': 'blue' +}, 'sfNeighborhoods'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Filter sfNeighborhoods by USF. +var usfNeighborhood = sfNeighborhoods.filterBounds(usf_point); + +// Filter the Census blocks by the boundary of the neighborhood layer. +var usfTiger = tiger.filterBounds(usfNeighborhood); +Map.addLayer(usfTiger, {}, 'usf_Tiger'); + +print(usfTiger); + +// Filter for census blocks by housing units +var housing10_l250 = usfTiger + .filter(ee.Filter.lt('housing10', 250)); + +var housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt( + 'housing10', 50)); + +Map.addLayer(housing10_g50_l250, { + 'color': 'Magenta' +}, 'housing'); + +var housing_area = housing10_g50_l250.geometry().area(); +print('housing_area:', housing_area); + +var housing10_mean = usfTiger.reduceColumns({ + reducer: ee.Reducer.mean(), + selectors: ['housing10'] +}); + +print('housing10_mean', housing10_mean); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Import the Landsat 8 TOA image collection. +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA'); + +// Get the least cloudy image in 2015. +var image = ee.Image(landsat8 + .filterBounds(usf_point) + .filterDate('2015-01-01', '2015-12-31') + .sort('CLOUD_COVER') + .first()); + +var nir = image.select('B5'); +var red = image.select('B4'); +var ndvi = nir.subtract(red).divide(nir.add(red)).rename('NDVI'); + +var ndviParams = { + min: -1, + max: 1, + palette: ['blue', 'white', 'green'] +}; + +var ndviUSFblocks = ndvi.clip(housing10_g50_l250); +Map.addLayer(ndviUSFblocks, ndviParams, 'NDVI image'); +Map.centerObject(usf_point, 14); + +// Reduce image by feature to compute a statistic e.g. mean, max, min etc. +var ndviPerBlock = ndviUSFblocks.reduceRegions({ + collection: housing10_g50_l250, + reducer: ee.Reducer.mean(), + scale: 30, +}); + +// Get a table of data out of Google Earth Engine. +Export.table.toDrive({ + collection: ndviPerBlock, + description: 'NDVI_by_block_near_USF' +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50d Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50d Checkpoint.py new file mode 100644 index 0000000..214b936 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50d Checkpoint.py @@ -0,0 +1,156 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +usf_building = + + # shown: False # + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + + # shown: False # + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + + # shown: False # + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.0 Exploring Vectors +# Checkpoint: F50d +# Authors: AJ Purdy, Ellen Brock, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Census Tiger Boundaries from GEE. +tiger = ee.FeatureCollection('TIGER/2010/Blocks') + +# Add the new feature collection to the map, but do not display. +Map.addLayer(tiger, { + 'color': 'black' +}, 'Tiger', False) + +# Assign the feature collection to the variable sfNeighborhoods. +sfNeighborhoods = ee.FeatureCollection( + 'path/to/your/asset/assetname') + +# Note: if you are unable to load the feature collection, you +# can access the data by uncommenting out the following two lines: +# tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods' +# sfNeighborhoods = ee.FeatureCollection(tablePath) + + + +# Print the size of the feature collection. +# (Answers the question: how many features?) +print(sfNeighborhoods.size()) +Map.addLayer(sfNeighborhoods, { + 'color': 'blue' +}, 'sfNeighborhoods') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Filter sfNeighborhoods by USF. +usfNeighborhood = sfNeighborhoods.filterBounds(usf_point) + +# Filter the Census blocks by the boundary of the neighborhood layer. +usfTiger = tiger.filterBounds(usfNeighborhood) +Map.addLayer(usfTiger, {}, 'usf_Tiger') + +print(usfTiger) + +# Filter for census blocks by housing units +housing10_l250 = usfTiger \ + .filter(ee.Filter.lt('housing10', 250)) + +housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt( + 'housing10', 50)) + +Map.addLayer(housing10_g50_l250, { + 'color': 'Magenta' +}, 'housing') + +housing_area = housing10_g50_l250.geometry().area() +print('housing_area:', housing_area) + +housing10_mean = usfTiger.reduceColumns({ + 'reducer': ee.Reducer.mean(), + 'selectors': ['housing10'] +}) + +print('housing10_mean', housing10_mean) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Import the Landsat 8 TOA image collection. +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + +# Get the least cloudy image in 2015. +image = ee.Image(landsat8 \ + .filterBounds(usf_point) \ + .filterDate('2015-01-01', '2015-12-31') \ + .sort('CLOUD_COVER') \ + .first()) + +nir = image.select('B5') +red = image.select('B4') +ndvi = nir.subtract(red).divide(nir.add(red)).rename('NDVI') + +ndviParams = { + 'min': -1, + 'max': 1, + 'palette': ['blue', 'white', 'green'] +} + +ndviUSFblocks = ndvi.clip(housing10_g50_l250) +Map.addLayer(ndviUSFblocks, ndviParams, 'NDVI image') +Map.centerObject(usf_point, 14) + +# Reduce image by feature to compute a statistic e.g. mean, max, min etc. +ndviPerBlock = ndviUSFblocks.reduceRegions({ + 'collection': housing10_g50_l250, + 'reducer': ee.Reducer.mean(), + 'scale': 30, +}) + +# Get a table of data out of Google Earth Engine. +Export.table.toDrive({ + 'collection': ndviPerBlock, + 'description': 'NDVI_by_block_near_USF' +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50e Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50e Checkpoint.ipynb new file mode 100644 index 0000000..c6acaa3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50e Checkpoint.ipynb @@ -0,0 +1,261 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "usf_building =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Polygon(\n", + " [[[-122.45136729605188, 37.77692986089728],\n", + " [-122.45126000769129, 37.77633201208984],\n", + " [-122.45136193163385, 37.77631505176946],\n", + " [-122.45131901628962, 37.776132728079645],\n", + " [-122.45086840517511, 37.776187849242575],\n", + " [-122.4509005916833, 37.77637017279647],\n", + " [-122.45101860887995, 37.77635321248484],\n", + " [-122.45112053282251, 37.776789939269314],\n", + " [-122.4506484640359, 37.776849299992314],\n", + " [-122.45067528612604, 37.777014661755025]]]),\n", + " usf_campus =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.MultiPolygon(\n", + " [[[[-122.45387746358996, 37.78025485651328],\n", + " [-122.4534697678197, 37.77791441971873],\n", + " [-122.4489851143468, 37.77849105595329],\n", + " [-122.44962884451037, 37.78076363731525]]],\n", + " [[[-122.45295922018377, 37.775902746563965],\n", + " [-122.45270172811834, 37.77512256326928],\n", + " [-122.44941870428411, 37.77552113619849],\n", + " [-122.44960109449713, 37.77630979544932],\n", + " [-122.44678009874097, 37.776725234224465],\n", + " [-122.44701613313428, 37.777590200803616],\n", + " [-122.45311011201612, 37.776860915925724]]],\n", + " [[[-122.45492520933641, 37.77589822903132],\n", + " [-122.45316568022264, 37.7761356745013],\n", + " [-122.45350900297655, 37.77776385146553],\n", + " [-122.45511832838548, 37.77756033130608]]]]),\n", + " usf_point =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([-122.45124246920876, 37.77652242316423])\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.0 Exploring Vectors\n", + "# Checkpoint: F50e\n", + "# Authors: AJ Purdy, Ellen Brock, David Saah\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Import the Census Tiger Boundaries from GEE.\n", + "tiger = ee.FeatureCollection('TIGER/2010/Blocks')\n", + "\n", + "# Add the new feature collection to the map, but do not display.\n", + "Map.addLayer(tiger, {\n", + " 'color': 'black'\n", + "}, 'Tiger', False)\n", + "\n", + "# Assign the feature collection to the variable sfNeighborhoods.\n", + "sfNeighborhoods = ee.FeatureCollection(\n", + " 'path/to/your/asset/assetname')\n", + "\n", + "# Note: if you are unable to load the feature collection, you\n", + "# can access the data by uncommenting out the following two lines:\n", + "# tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods'\n", + "# sfNeighborhoods = ee.FeatureCollection(tablePath)\n", + "\n", + "\n", + "\n", + "# Print the size of the feature collection.\n", + "# (Answers the question: how many features?)\n", + "print(sfNeighborhoods.size())\n", + "Map.addLayer(sfNeighborhoods, {\n", + " 'color': 'blue'\n", + "}, 'sfNeighborhoods')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Filter sfNeighborhoods by USF.\n", + "usfNeighborhood = sfNeighborhoods.filterBounds(usf_point)\n", + "\n", + "# Filter the Census blocks by the boundary of the neighborhood layer.\n", + "usfTiger = tiger.filterBounds(usfNeighborhood)\n", + "Map.addLayer(usfTiger, {}, 'usf_Tiger')\n", + "\n", + "print(usfTiger)\n", + "\n", + "# Filter for census blocks by housing units\n", + "housing10_l250 = usfTiger \\\n", + " .filter(ee.Filter.lt('housing10', 250))\n", + "\n", + "housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt(\n", + " 'housing10', 50))\n", + "\n", + "Map.addLayer(housing10_g50_l250, {\n", + " 'color': 'Magenta'\n", + "}, 'housing')\n", + "\n", + "housing_area = housing10_g50_l250.geometry().area()\n", + "print('housing_area:', housing_area)\n", + "\n", + "housing10_mean = usfTiger.reduceColumns({\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'selectors': ['housing10']\n", + "})\n", + "\n", + "print('housing10_mean', housing10_mean)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Import the Landsat 8 TOA image collection.\n", + "landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')\n", + "\n", + "# Get the least cloudy image in 2015.\n", + "image = ee.Image(landsat8 \\\n", + " .filterBounds(usf_point) \\\n", + " .filterDate('2015-01-01', '2015-12-31') \\\n", + " .sort('CLOUD_COVER') \\\n", + " .first())\n", + "\n", + "nir = image.select('B5')\n", + "red = image.select('B4')\n", + "ndvi = nir.subtract(red).divide(nir.add(red)).rename('NDVI')\n", + "\n", + "ndviParams = {\n", + " 'min': -1,\n", + " 'max': 1,\n", + " 'palette': ['blue', 'white', 'green']\n", + "}\n", + "\n", + "ndviUSFblocks = ndvi.clip(housing10_g50_l250)\n", + "Map.addLayer(ndviUSFblocks, ndviParams, 'NDVI image')\n", + "Map.centerObject(usf_point, 14)\n", + "\n", + "# Reduce image by feature to compute a statistic e.g. mean, max, min etc.\n", + "ndviPerBlock = ndviUSFblocks.reduceRegions({\n", + " 'collection': housing10_g50_l250,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': 30,\n", + "})\n", + "\n", + "# Get a table of data out of Google Earth Engine.\n", + "Export.table.toDrive({\n", + " 'collection': ndviPerBlock,\n", + " 'description': 'NDVI_by_block_near_USF'\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "ndviPerBlock = ndviPerBlock.select(['blockid10', 'mean'])\n", + "print('ndviPerBlock', ndviPerBlock)\n", + "ndviPerBlockSorted = ndviPerBlock.sort('mean', False)\n", + "ndviPerBlockSortedFirst = ee.Feature(ndviPerBlock.sort('mean',\n", + " False) # Sort by NDVI mean in descending order. \\\n", + " .first()); \n", + "print('ndviPerBlockSortedFirst', ndviPerBlockSortedFirst)\n", + "\n", + "# Now filter by block and show on map!\n", + "GreenHousing = usfTiger.filter(ee.Filter.eq('blockid10',\n", + "'#####')); #< Put your id here prepend a 0!\n", + "Map.addLayer(GreenHousing, {\n", + " 'color': 'yellow'\n", + "}, 'Green Housing!')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50e Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50e Checkpoint.js new file mode 100644 index 0000000..6afcc04 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50e Checkpoint.js @@ -0,0 +1,168 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var usf_building = + /* color: #bf04c2 */ + /* shown: false */ + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + /* color: #ff0000 */ + /* shown: false */ + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + /* color: #00ffff */ + /* shown: false */ + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.0 Exploring Vectors +// Checkpoint: F50e +// Authors: AJ Purdy, Ellen Brock, David Saah +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Import the Census Tiger Boundaries from GEE. +var tiger = ee.FeatureCollection('TIGER/2010/Blocks'); + +// Add the new feature collection to the map, but do not display. +Map.addLayer(tiger, { + 'color': 'black' +}, 'Tiger', false); + +// Assign the feature collection to the variable sfNeighborhoods. +var sfNeighborhoods = ee.FeatureCollection( + 'path/to/your/asset/assetname'); + +// Note: if you are unable to load the feature collection, you +// can access the data by uncommenting out the following two lines: +// var tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods'; +// var sfNeighborhoods = ee.FeatureCollection(tablePath); + + + +// Print the size of the feature collection. +// (Answers the question: how many features?) +print(sfNeighborhoods.size()); +Map.addLayer(sfNeighborhoods, { + 'color': 'blue' +}, 'sfNeighborhoods'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Filter sfNeighborhoods by USF. +var usfNeighborhood = sfNeighborhoods.filterBounds(usf_point); + +// Filter the Census blocks by the boundary of the neighborhood layer. +var usfTiger = tiger.filterBounds(usfNeighborhood); +Map.addLayer(usfTiger, {}, 'usf_Tiger'); + +print(usfTiger); + +// Filter for census blocks by housing units +var housing10_l250 = usfTiger + .filter(ee.Filter.lt('housing10', 250)); + +var housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt( + 'housing10', 50)); + +Map.addLayer(housing10_g50_l250, { + 'color': 'Magenta' +}, 'housing'); + +var housing_area = housing10_g50_l250.geometry().area(); +print('housing_area:', housing_area); + +var housing10_mean = usfTiger.reduceColumns({ + reducer: ee.Reducer.mean(), + selectors: ['housing10'] +}); + +print('housing10_mean', housing10_mean); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Import the Landsat 8 TOA image collection. +var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA'); + +// Get the least cloudy image in 2015. +var image = ee.Image(landsat8 + .filterBounds(usf_point) + .filterDate('2015-01-01', '2015-12-31') + .sort('CLOUD_COVER') + .first()); + +var nir = image.select('B5'); +var red = image.select('B4'); +var ndvi = nir.subtract(red).divide(nir.add(red)).rename('NDVI'); + +var ndviParams = { + min: -1, + max: 1, + palette: ['blue', 'white', 'green'] +}; + +var ndviUSFblocks = ndvi.clip(housing10_g50_l250); +Map.addLayer(ndviUSFblocks, ndviParams, 'NDVI image'); +Map.centerObject(usf_point, 14); + +// Reduce image by feature to compute a statistic e.g. mean, max, min etc. +var ndviPerBlock = ndviUSFblocks.reduceRegions({ + collection: housing10_g50_l250, + reducer: ee.Reducer.mean(), + scale: 30, +}); + +// Get a table of data out of Google Earth Engine. +Export.table.toDrive({ + collection: ndviPerBlock, + description: 'NDVI_by_block_near_USF' +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +ndviPerBlock = ndviPerBlock.select(['blockid10', 'mean']); +print('ndviPerBlock', ndviPerBlock); +var ndviPerBlockSorted = ndviPerBlock.sort('mean', false); +var ndviPerBlockSortedFirst = ee.Feature(ndviPerBlock.sort('mean', + false) // Sort by NDVI mean in descending order. + .first()); // Select the block with the highest NDVI. +print('ndviPerBlockSortedFirst', ndviPerBlockSortedFirst); + +// Now filter by block and show on map! +var GreenHousing = usfTiger.filter(ee.Filter.eq('blockid10', +'#####')); //< Put your id here prepend a 0! +Map.addLayer(GreenHousing, { + 'color': 'yellow' +}, 'Green Housing!'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50e Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50e Checkpoint.py new file mode 100644 index 0000000..f79fd88 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.0 Exploring Vectors/F50e Checkpoint.py @@ -0,0 +1,174 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +usf_building = + + # shown: False # + ee.Geometry.Polygon( + [[[-122.45136729605188, 37.77692986089728], + [-122.45126000769129, 37.77633201208984], + [-122.45136193163385, 37.77631505176946], + [-122.45131901628962, 37.776132728079645], + [-122.45086840517511, 37.776187849242575], + [-122.4509005916833, 37.77637017279647], + [-122.45101860887995, 37.77635321248484], + [-122.45112053282251, 37.776789939269314], + [-122.4506484640359, 37.776849299992314], + [-122.45067528612604, 37.777014661755025]]]), + usf_campus = + + # shown: False # + ee.Geometry.MultiPolygon( + [[[[-122.45387746358996, 37.78025485651328], + [-122.4534697678197, 37.77791441971873], + [-122.4489851143468, 37.77849105595329], + [-122.44962884451037, 37.78076363731525]]], + [[[-122.45295922018377, 37.775902746563965], + [-122.45270172811834, 37.77512256326928], + [-122.44941870428411, 37.77552113619849], + [-122.44960109449713, 37.77630979544932], + [-122.44678009874097, 37.776725234224465], + [-122.44701613313428, 37.777590200803616], + [-122.45311011201612, 37.776860915925724]]], + [[[-122.45492520933641, 37.77589822903132], + [-122.45316568022264, 37.7761356745013], + [-122.45350900297655, 37.77776385146553], + [-122.45511832838548, 37.77756033130608]]]]), + usf_point = + + # shown: False # + ee.Geometry.Point([-122.45124246920876, 37.77652242316423]) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.0 Exploring Vectors +# Checkpoint: F50e +# Authors: AJ Purdy, Ellen Brock, David Saah +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Import the Census Tiger Boundaries from GEE. +tiger = ee.FeatureCollection('TIGER/2010/Blocks') + +# Add the new feature collection to the map, but do not display. +Map.addLayer(tiger, { + 'color': 'black' +}, 'Tiger', False) + +# Assign the feature collection to the variable sfNeighborhoods. +sfNeighborhoods = ee.FeatureCollection( + 'path/to/your/asset/assetname') + +# Note: if you are unable to load the feature collection, you +# can access the data by uncommenting out the following two lines: +# tablePath = 'projects/gee-book/assets/F5-0/SFneighborhoods' +# sfNeighborhoods = ee.FeatureCollection(tablePath) + + + +# Print the size of the feature collection. +# (Answers the question: how many features?) +print(sfNeighborhoods.size()) +Map.addLayer(sfNeighborhoods, { + 'color': 'blue' +}, 'sfNeighborhoods') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Filter sfNeighborhoods by USF. +usfNeighborhood = sfNeighborhoods.filterBounds(usf_point) + +# Filter the Census blocks by the boundary of the neighborhood layer. +usfTiger = tiger.filterBounds(usfNeighborhood) +Map.addLayer(usfTiger, {}, 'usf_Tiger') + +print(usfTiger) + +# Filter for census blocks by housing units +housing10_l250 = usfTiger \ + .filter(ee.Filter.lt('housing10', 250)) + +housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt( + 'housing10', 50)) + +Map.addLayer(housing10_g50_l250, { + 'color': 'Magenta' +}, 'housing') + +housing_area = housing10_g50_l250.geometry().area() +print('housing_area:', housing_area) + +housing10_mean = usfTiger.reduceColumns({ + 'reducer': ee.Reducer.mean(), + 'selectors': ['housing10'] +}) + +print('housing10_mean', housing10_mean) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Import the Landsat 8 TOA image collection. +landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') + +# Get the least cloudy image in 2015. +image = ee.Image(landsat8 \ + .filterBounds(usf_point) \ + .filterDate('2015-01-01', '2015-12-31') \ + .sort('CLOUD_COVER') \ + .first()) + +nir = image.select('B5') +red = image.select('B4') +ndvi = nir.subtract(red).divide(nir.add(red)).rename('NDVI') + +ndviParams = { + 'min': -1, + 'max': 1, + 'palette': ['blue', 'white', 'green'] +} + +ndviUSFblocks = ndvi.clip(housing10_g50_l250) +Map.addLayer(ndviUSFblocks, ndviParams, 'NDVI image') +Map.centerObject(usf_point, 14) + +# Reduce image by feature to compute a statistic e.g. mean, max, min etc. +ndviPerBlock = ndviUSFblocks.reduceRegions({ + 'collection': housing10_g50_l250, + 'reducer': ee.Reducer.mean(), + 'scale': 30, +}) + +# Get a table of data out of Google Earth Engine. +Export.table.toDrive({ + 'collection': ndviPerBlock, + 'description': 'NDVI_by_block_near_USF' +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +ndviPerBlock = ndviPerBlock.select(['blockid10', 'mean']) +print('ndviPerBlock', ndviPerBlock) +ndviPerBlockSorted = ndviPerBlock.sort('mean', False) +ndviPerBlockSortedFirst = ee.Feature(ndviPerBlock.sort('mean', + False) # Sort by NDVI mean in descending order. \ + .first()); +print('ndviPerBlockSortedFirst', ndviPerBlockSortedFirst) + +# Now filter by block and show on map! +GreenHousing = usfTiger.filter(ee.Filter.eq('blockid10', +'#####')); #< Put your id here prepend a 0! +Map.addLayer(GreenHousing, { + 'color': 'yellow' +}, 'Green Housing!') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51a Checkpoint.ipynb new file mode 100644 index 0000000..00204a6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51a Checkpoint.ipynb @@ -0,0 +1,254 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.1 Raster/Vector Conversions\n", + "# Checkpoint: F51a\n", + "# Authors: Keiko Nomura, Samuel Bowers\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#-------------#\n", + "# Section 1.1 #\n", + "#-------------#\n", + "\n", + "# Load raster (elevation) and vector (colombia) datasets.\n", + "elevation = ee.Image('USGS/GMTED2010').rename('elevation')\n", + "colombia = ee.FeatureCollection(\n", + " 'FAO/GAUL_SIMPLIFIED_500m/2015/level0') \\\n", + " .filter(ee.Filter.equals('ADM0_NAME', 'Colombia'))\n", + "\n", + "# Display elevation image.\n", + "Map.centerObject(colombia, 7)\n", + "Map.addLayer(elevation, {\n", + " 'min': 0,\n", + " 'max': 4000\n", + "}, 'Elevation')\n", + "\n", + "# Initialize image with zeros and define elevation zones.\n", + "zones = ee.Image(0) \\\n", + " .where(elevation.gt(100), 1) \\\n", + " .where(elevation.gt(200), 2) \\\n", + " .where(elevation.gt(500), 3)\n", + "\n", + "# Mask pixels below sea level (<= 0 m) to retain only land areas.\n", + "# Name the band with values 0-3 as 'zone'.\n", + "zones = zones.updateMask(elevation.gt(0)).rename('zone')\n", + "\n", + "Map.addLayer(zones, {\n", + " 'min': 0,\n", + " 'max': 3,\n", + " 'palette': ['white', 'yellow', 'lime', 'green'],\n", + " 'opacity': 0.7\n", + "}, 'Elevation zones')\n", + "\n", + "projection = elevation.projection()\n", + "scale = elevation.projection().nominalScale()\n", + "\n", + "elevationVector = zones.reduceToVectors({\n", + " 'geometry': colombia.geometry(),\n", + " 'crs': projection,\n", + " 'scale': 1000, # scale\n", + " 'geometryType': 'polygon',\n", + " 'eightConnected': False,\n", + " 'labelProperty': 'zone',\n", + " 'bestEffort': False,\n", + " 'maxPixels': 1e13,\n", + " 'tileScale': 3 # In case of error.\n", + "})\n", + "\n", + "print(elevationVector.limit(10))\n", + "\n", + "elevationDrawn = elevationVector.draw({\n", + " 'color': 'black',\n", + " 'strokeWidth': 1\n", + "})\n", + "Map.addLayer(elevationDrawn, {}, 'Elevation zone polygon')\n", + "\n", + "zonesSmooth = zones.focalMode(4, 'square')\n", + "\n", + "zonesSmooth = zonesSmooth.reproject(projection.atScale(scale))\n", + "\n", + "Map.addLayer(zonesSmooth, {\n", + " 'min': 0,\n", + " 'max': 3,\n", + " 'palette': ['white', 'yellow', 'lime', 'green'],\n", + " 'opacity': 0.7\n", + "}, 'Elevation zones (smooth)')\n", + "\n", + "elevationVectorSmooth = zonesSmooth.reduceToVectors({\n", + " 'geometry': colombia.geometry(),\n", + " 'crs': projection,\n", + " 'scale': scale,\n", + " 'geometryType': 'polygon',\n", + " 'eightConnected': False,\n", + " 'labelProperty': 'zone',\n", + " 'bestEffort': False,\n", + " 'maxPixels': 1e13,\n", + " 'tileScale': 3\n", + "})\n", + "\n", + "smoothDrawn = elevationVectorSmooth.draw({\n", + " 'color': 'black',\n", + " 'strokeWidth': 1\n", + "})\n", + "Map.addLayer(smoothDrawn, {}, 'Elevation zone polygon (smooth)')\n", + "\n", + "#-------------#\n", + "# Section 1.2 #\n", + "#-------------#\n", + "\n", + "geometry = ee.Geometry.Polygon([\n", + " [-89.553, -0.929],\n", + " [-89.436, -0.929],\n", + " [-89.436, -0.866],\n", + " [-89.553, -0.866],\n", + " [-89.553, -0.929]\n", + "])\n", + "\n", + "# To zoom into the area, un-comment and run below\n", + "# Map.centerObject(geometry,12)\n", + "Map.addLayer(geometry, {}, 'Areas to extract points')\n", + "\n", + "elevationSamples = elevation.sample({\n", + " 'region': geometry,\n", + " 'projection': projection,\n", + " 'scale': scale,\n", + " 'geometries': True,\n", + "})\n", + "\n", + "Map.addLayer(elevationSamples, {}, 'Points extracted')\n", + "\n", + "# Add three properties to the output table:\n", + "# 'Elevation', 'Longitude', and 'Latitude'.\n", + "\n", + "def func_psx(feature):\n", + " geom = feature.geometry().coordinates()\n", + " return ee.Feature(None, {\n", + " 'Elevation': ee.Number(feature.get(\n", + " 'elevation')),\n", + " 'Long': ee.Number(geom.get(0)),\n", + " 'Lat': ee.Number(geom.get(1))\n", + " })\n", + "\n", + "elevationSamples = elevationSamples.map(func_psx)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Export as CSV.\n", + "Export.table.toDrive({\n", + " 'collection': elevationSamples,\n", + " 'description': 'extracted_points',\n", + " 'fileFormat': 'CSV'\n", + "})\n", + "\n", + "elevationSamplesStratified = zones.stratifiedSample({\n", + " 'numPoints': 10,\n", + " 'classBand': 'zone',\n", + " 'region': geometry,\n", + " 'scale': scale,\n", + " 'projection': projection,\n", + " 'geometries': True\n", + "})\n", + "\n", + "Map.addLayer(elevationSamplesStratified, {}, 'Stratified samples')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51a Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51a Checkpoint.js new file mode 100644 index 0000000..98694bf --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51a Checkpoint.js @@ -0,0 +1,150 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.1 Raster/Vector Conversions +// Checkpoint: F51a +// Authors: Keiko Nomura, Samuel Bowers +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//-------------// +// Section 1.1 // +//-------------// + +// Load raster (elevation) and vector (colombia) datasets. +var elevation = ee.Image('USGS/GMTED2010').rename('elevation'); +var colombia = ee.FeatureCollection( + 'FAO/GAUL_SIMPLIFIED_500m/2015/level0') + .filter(ee.Filter.equals('ADM0_NAME', 'Colombia')); + +// Display elevation image. +Map.centerObject(colombia, 7); +Map.addLayer(elevation, { + min: 0, + max: 4000 +}, 'Elevation'); + +// Initialize image with zeros and define elevation zones. +var zones = ee.Image(0) + .where(elevation.gt(100), 1) + .where(elevation.gt(200), 2) + .where(elevation.gt(500), 3); + +// Mask pixels below sea level (<= 0 m) to retain only land areas. +// Name the band with values 0-3 as 'zone'. +zones = zones.updateMask(elevation.gt(0)).rename('zone'); + +Map.addLayer(zones, { + min: 0, + max: 3, + palette: ['white', 'yellow', 'lime', 'green'], + opacity: 0.7 +}, 'Elevation zones'); + +var projection = elevation.projection(); +var scale = elevation.projection().nominalScale(); + +var elevationVector = zones.reduceToVectors({ + geometry: colombia.geometry(), + crs: projection, + scale: 1000, // scale + geometryType: 'polygon', + eightConnected: false, + labelProperty: 'zone', + bestEffort: false, + maxPixels: 1e13, + tileScale: 3 // In case of error. +}); + +print(elevationVector.limit(10)); + +var elevationDrawn = elevationVector.draw({ + color: 'black', + strokeWidth: 1 +}); +Map.addLayer(elevationDrawn, {}, 'Elevation zone polygon'); + +var zonesSmooth = zones.focalMode(4, 'square'); + +zonesSmooth = zonesSmooth.reproject(projection.atScale(scale)); + +Map.addLayer(zonesSmooth, { + min: 0, + max: 3, + palette: ['white', 'yellow', 'lime', 'green'], + opacity: 0.7 +}, 'Elevation zones (smooth)'); + +var elevationVectorSmooth = zonesSmooth.reduceToVectors({ + geometry: colombia.geometry(), + crs: projection, + scale: scale, + geometryType: 'polygon', + eightConnected: false, + labelProperty: 'zone', + bestEffort: false, + maxPixels: 1e13, + tileScale: 3 +}); + +var smoothDrawn = elevationVectorSmooth.draw({ + color: 'black', + strokeWidth: 1 +}); +Map.addLayer(smoothDrawn, {}, 'Elevation zone polygon (smooth)'); + +//-------------// +// Section 1.2 // +//-------------// + +var geometry = ee.Geometry.Polygon([ + [-89.553, -0.929], + [-89.436, -0.929], + [-89.436, -0.866], + [-89.553, -0.866], + [-89.553, -0.929] +]); + +// To zoom into the area, un-comment and run below +// Map.centerObject(geometry,12); +Map.addLayer(geometry, {}, 'Areas to extract points'); + +var elevationSamples = elevation.sample({ + region: geometry, + projection: projection, + scale: scale, + geometries: true, +}); + +Map.addLayer(elevationSamples, {}, 'Points extracted'); + +// Add three properties to the output table: +// 'Elevation', 'Longitude', and 'Latitude'. +elevationSamples = elevationSamples.map(function(feature) { + var geom = feature.geometry().coordinates(); + return ee.Feature(null, { + 'Elevation': ee.Number(feature.get( + 'elevation')), + 'Long': ee.Number(geom.get(0)), + 'Lat': ee.Number(geom.get(1)) + }); +}); + +// Export as CSV. +Export.table.toDrive({ + collection: elevationSamples, + description: 'extracted_points', + fileFormat: 'CSV' +}); + +var elevationSamplesStratified = zones.stratifiedSample({ + numPoints: 10, + classBand: 'zone', + region: geometry, + scale: scale, + projection: projection, + geometries: true +}); + +Map.addLayer(elevationSamplesStratified, {}, 'Stratified samples'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51a Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51a Checkpoint.py new file mode 100644 index 0000000..e6cbedb --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51a Checkpoint.py @@ -0,0 +1,167 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.1 Raster/Vector Conversions +# Checkpoint: F51a +# Authors: Keiko Nomura, Samuel Bowers +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#-------------# +# Section 1.1 # +#-------------# + +# Load raster (elevation) and vector (colombia) datasets. +elevation = ee.Image('USGS/GMTED2010').rename('elevation') +colombia = ee.FeatureCollection( + 'FAO/GAUL_SIMPLIFIED_500m/2015/level0') \ + .filter(ee.Filter.equals('ADM0_NAME', 'Colombia')) + +# Display elevation image. +Map.centerObject(colombia, 7) +Map.addLayer(elevation, { + 'min': 0, + 'max': 4000 +}, 'Elevation') + +# Initialize image with zeros and define elevation zones. +zones = ee.Image(0) \ + .where(elevation.gt(100), 1) \ + .where(elevation.gt(200), 2) \ + .where(elevation.gt(500), 3) + +# Mask pixels below sea level (<= 0 m) to retain only land areas. +# Name the band with values 0-3 as 'zone'. +zones = zones.updateMask(elevation.gt(0)).rename('zone') + +Map.addLayer(zones, { + 'min': 0, + 'max': 3, + 'palette': ['white', 'yellow', 'lime', 'green'], + 'opacity': 0.7 +}, 'Elevation zones') + +projection = elevation.projection() +scale = elevation.projection().nominalScale() + +elevationVector = zones.reduceToVectors({ + 'geometry': colombia.geometry(), + 'crs': projection, + 'scale': 1000, # scale + 'geometryType': 'polygon', + 'eightConnected': False, + 'labelProperty': 'zone', + 'bestEffort': False, + 'maxPixels': 1e13, + 'tileScale': 3 # In case of error. +}) + +print(elevationVector.limit(10)) + +elevationDrawn = elevationVector.draw({ + 'color': 'black', + 'strokeWidth': 1 +}) +Map.addLayer(elevationDrawn, {}, 'Elevation zone polygon') + +zonesSmooth = zones.focalMode(4, 'square') + +zonesSmooth = zonesSmooth.reproject(projection.atScale(scale)) + +Map.addLayer(zonesSmooth, { + 'min': 0, + 'max': 3, + 'palette': ['white', 'yellow', 'lime', 'green'], + 'opacity': 0.7 +}, 'Elevation zones (smooth)') + +elevationVectorSmooth = zonesSmooth.reduceToVectors({ + 'geometry': colombia.geometry(), + 'crs': projection, + 'scale': scale, + 'geometryType': 'polygon', + 'eightConnected': False, + 'labelProperty': 'zone', + 'bestEffort': False, + 'maxPixels': 1e13, + 'tileScale': 3 +}) + +smoothDrawn = elevationVectorSmooth.draw({ + 'color': 'black', + 'strokeWidth': 1 +}) +Map.addLayer(smoothDrawn, {}, 'Elevation zone polygon (smooth)') + +#-------------# +# Section 1.2 # +#-------------# + +geometry = ee.Geometry.Polygon([ + [-89.553, -0.929], + [-89.436, -0.929], + [-89.436, -0.866], + [-89.553, -0.866], + [-89.553, -0.929] +]) + +# To zoom into the area, un-comment and run below +# Map.centerObject(geometry,12) +Map.addLayer(geometry, {}, 'Areas to extract points') + +elevationSamples = elevation.sample({ + 'region': geometry, + 'projection': projection, + 'scale': scale, + 'geometries': True, +}) + +Map.addLayer(elevationSamples, {}, 'Points extracted') + +# Add three properties to the output table: +# 'Elevation', 'Longitude', and 'Latitude'. + +def func_psx(feature): + geom = feature.geometry().coordinates() + return ee.Feature(None, { + 'Elevation': ee.Number(feature.get( + 'elevation')), + 'Long': ee.Number(geom.get(0)), + 'Lat': ee.Number(geom.get(1)) + }) + +elevationSamples = elevationSamples.map(func_psx) + + + + + + + + + + +# Export as CSV. +Export.table.toDrive({ + 'collection': elevationSamples, + 'description': 'extracted_points', + 'fileFormat': 'CSV' +}) + +elevationSamplesStratified = zones.stratifiedSample({ + 'numPoints': 10, + 'classBand': 'zone', + 'region': geometry, + 'scale': scale, + 'projection': projection, + 'geometries': True +}) + +Map.addLayer(elevationSamplesStratified, {}, 'Stratified samples') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51b Checkpoint.ipynb new file mode 100644 index 0000000..5b9eaba --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51b Checkpoint.ipynb @@ -0,0 +1,233 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.1 Raster/Vector Conversions\n", + "# Checkpoint: F51b\n", + "# Authors: Keiko Nomura, Samuel Bowers\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#-------------#\n", + "# Section 1.3 #\n", + "#-------------#\n", + "\n", + "# Read input data.\n", + "# Note: these datasets are periodically updated.\n", + "# Consider searching the Data Catalog for newer versions.\n", + "gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8')\n", + "wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons')\n", + "\n", + "# Print assets to show available layers and properties.\n", + "print(gfc)\n", + "print(wdpa.limit(10)); # Show first 10 records.\n", + "\n", + "\n", + "# Display deforestation.\n", + "deforestation = gfc.select('lossyear')\n", + "\n", + "Map.addLayer(deforestation, {\n", + " 'min': 1,\n", + " 'max': 20,\n", + " 'palette': ['yellow', 'orange', 'red']\n", + "}, 'Deforestation raster')\n", + "\n", + "# Display WDPA data.\n", + "protectedArea = wdpa.filter(ee.Filter.equals('NAME', 'La Paya'))\n", + "\n", + "# Display protected area as an outline (see F5.3 for paint()).\n", + "protectedAreaOutline = ee.Image().byte().paint({\n", + " 'featureCollection': protectedArea,\n", + " 'color': 1,\n", + " 'width': 3\n", + "})\n", + "\n", + "Map.addLayer(protectedAreaOutline, {\n", + " 'palette': 'white'\n", + "}, 'Protected area')\n", + "\n", + "# Set up map display.\n", + "Map.centerObject(protectedArea)\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "# Convert from a deforestation raster to vector.\n", + "deforestationVector = deforestation.reduceToVectors({\n", + " 'scale': deforestation.projection().nominalScale(),\n", + " 'geometry': protectedArea.geometry(),\n", + " 'labelProperty': 'lossyear', # Label polygons with a change year.\n", + " 'maxPixels': 1e13\n", + "})\n", + "\n", + "# Count the number of individual change events\n", + "print('Number of change events:', deforestationVector.size())\n", + "\n", + "# Display deforestation polygons. Color outline by change year.\n", + "deforestationVectorOutline = ee.Image().byte().paint({\n", + " 'featureCollection': deforestationVector,\n", + " 'color': 'lossyear',\n", + " 'width': 1\n", + "})\n", + "\n", + "Map.addLayer(deforestationVectorOutline, {\n", + " 'palette': ['yellow', 'orange', 'red'],\n", + " 'min': 1,\n", + " 'max': 20\n", + "}, 'Deforestation vector')\n", + "\n", + "chart = ui.Chart.feature \\\n", + " .histogram({\n", + " 'features': deforestationVector,\n", + " 'property': 'lossyear'\n", + " }) \\\n", + " .setOptions({\n", + " 'hAxis': {\n", + " 'title': 'Year'\n", + " },\n", + " 'vAxis': {\n", + " 'title': 'Number of deforestation events'\n", + " },\n", + " 'legend': {\n", + " 'position': 'none'\n", + " }\n", + " })\n", + "\n", + "print(chart)\n", + "\n", + "# Generate deforestation point locations.\n", + "\n", + "def func_hoz(feat):\n", + " return feat.centroid()\n", + "\n", + "deforestationCentroids = deforestationVector.map(func_hoz)\n", + "\n", + "\n", + "\n", + "\n", + "Map.addLayer(deforestationCentroids, {\n", + " 'color': 'darkblue'\n", + "}, 'Deforestation centroids')\n", + "\n", + "# Add a new property to the deforestation FeatureCollection\n", + "# describing the area of the change polygon.\n", + "\n", + "def func_opk(feat):\n", + " return feat.set('area', feat.geometry().area({\n", + " 'maxError': 10\n", + " }).divide(10000)); # Convert m^2 to hectare.\n", + "\n", + "deforestationVector = deforestationVector.map(func_opk)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Filter the deforestation FeatureCollection for only large-scale (>10 ha) changes\n", + "deforestationLarge = deforestationVector.filter(ee.Filter.gt(\n", + " 'area', 10))\n", + "\n", + "# Display deforestation area outline by year.\n", + "deforestationLargeOutline = ee.Image().byte().paint({\n", + " 'featureCollection': deforestationLarge,\n", + " 'color': 'lossyear',\n", + " 'width': 1\n", + "})\n", + "\n", + "Map.addLayer(deforestationLargeOutline, {\n", + " 'palette': ['yellow', 'orange', 'red'],\n", + " 'min': 1,\n", + " 'max': 20\n", + "}, 'Deforestation (>10 ha)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51b Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51b Checkpoint.js new file mode 100644 index 0000000..7c845ca --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51b Checkpoint.js @@ -0,0 +1,128 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.1 Raster/Vector Conversions +// Checkpoint: F51b +// Authors: Keiko Nomura, Samuel Bowers +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//-------------// +// Section 1.3 // +//-------------// + +// Read input data. +// Note: these datasets are periodically updated. +// Consider searching the Data Catalog for newer versions. +var gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8'); +var wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons'); + +// Print assets to show available layers and properties. +print(gfc); +print(wdpa.limit(10)); // Show first 10 records. + + +// Display deforestation. +var deforestation = gfc.select('lossyear'); + +Map.addLayer(deforestation, { + min: 1, + max: 20, + palette: ['yellow', 'orange', 'red'] +}, 'Deforestation raster'); + +// Display WDPA data. +var protectedArea = wdpa.filter(ee.Filter.equals('NAME', 'La Paya')); + +// Display protected area as an outline (see F5.3 for paint()). +var protectedAreaOutline = ee.Image().byte().paint({ + featureCollection: protectedArea, + color: 1, + width: 3 +}); + +Map.addLayer(protectedAreaOutline, { + palette: 'white' +}, 'Protected area'); + +// Set up map display. +Map.centerObject(protectedArea); +Map.setOptions('SATELLITE'); + +// Convert from a deforestation raster to vector. +var deforestationVector = deforestation.reduceToVectors({ + scale: deforestation.projection().nominalScale(), + geometry: protectedArea.geometry(), + labelProperty: 'lossyear', // Label polygons with a change year. + maxPixels: 1e13 +}); + +// Count the number of individual change events +print('Number of change events:', deforestationVector.size()); + +// Display deforestation polygons. Color outline by change year. +var deforestationVectorOutline = ee.Image().byte().paint({ + featureCollection: deforestationVector, + color: 'lossyear', + width: 1 +}); + +Map.addLayer(deforestationVectorOutline, { + palette: ['yellow', 'orange', 'red'], + min: 1, + max: 20 +}, 'Deforestation vector'); + +var chart = ui.Chart.feature + .histogram({ + features: deforestationVector, + property: 'lossyear' + }) + .setOptions({ + hAxis: { + title: 'Year' + }, + vAxis: { + title: 'Number of deforestation events' + }, + legend: { + position: 'none' + } + }); + +print(chart); + +// Generate deforestation point locations. +var deforestationCentroids = deforestationVector.map(function(feat) { + return feat.centroid(); +}); + +Map.addLayer(deforestationCentroids, { + color: 'darkblue' +}, 'Deforestation centroids'); + +// Add a new property to the deforestation FeatureCollection +// describing the area of the change polygon. +deforestationVector = deforestationVector.map(function(feat) { + return feat.set('area', feat.geometry().area({ + maxError: 10 + }).divide(10000)); // Convert m^2 to hectare. +}); + +// Filter the deforestation FeatureCollection for only large-scale (>10 ha) changes +var deforestationLarge = deforestationVector.filter(ee.Filter.gt( + 'area', 10)); + +// Display deforestation area outline by year. +var deforestationLargeOutline = ee.Image().byte().paint({ + featureCollection: deforestationLarge, + color: 'lossyear', + width: 1 +}); + +Map.addLayer(deforestationLargeOutline, { + palette: ['yellow', 'orange', 'red'], + min: 1, + max: 20 +}, 'Deforestation (>10 ha)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51b Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51b Checkpoint.py new file mode 100644 index 0000000..2fc6eca --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51b Checkpoint.py @@ -0,0 +1,146 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.1 Raster/Vector Conversions +# Checkpoint: F51b +# Authors: Keiko Nomura, Samuel Bowers +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#-------------# +# Section 1.3 # +#-------------# + +# Read input data. +# Note: these datasets are periodically updated. +# Consider searching the Data Catalog for newer versions. +gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') +wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons') + +# Print assets to show available layers and properties. +print(gfc) +print(wdpa.limit(10)); # Show first 10 records. + + +# Display deforestation. +deforestation = gfc.select('lossyear') + +Map.addLayer(deforestation, { + 'min': 1, + 'max': 20, + 'palette': ['yellow', 'orange', 'red'] +}, 'Deforestation raster') + +# Display WDPA data. +protectedArea = wdpa.filter(ee.Filter.equals('NAME', 'La Paya')) + +# Display protected area as an outline (see F5.3 for paint()). +protectedAreaOutline = ee.Image().byte().paint({ + 'featureCollection': protectedArea, + 'color': 1, + 'width': 3 +}) + +Map.addLayer(protectedAreaOutline, { + 'palette': 'white' +}, 'Protected area') + +# Set up map display. +Map.centerObject(protectedArea) +Map.setOptions('SATELLITE') + +# Convert from a deforestation raster to vector. +deforestationVector = deforestation.reduceToVectors({ + 'scale': deforestation.projection().nominalScale(), + 'geometry': protectedArea.geometry(), + 'labelProperty': 'lossyear', # Label polygons with a change year. + 'maxPixels': 1e13 +}) + +# Count the number of individual change events +print('Number of change events:', deforestationVector.size()) + +# Display deforestation polygons. Color outline by change year. +deforestationVectorOutline = ee.Image().byte().paint({ + 'featureCollection': deforestationVector, + 'color': 'lossyear', + 'width': 1 +}) + +Map.addLayer(deforestationVectorOutline, { + 'palette': ['yellow', 'orange', 'red'], + 'min': 1, + 'max': 20 +}, 'Deforestation vector') + +chart = ui.Chart.feature \ + .histogram({ + 'features': deforestationVector, + 'property': 'lossyear' + }) \ + .setOptions({ + 'hAxis': { + 'title': 'Year' + }, + 'vAxis': { + 'title': 'Number of deforestation events' + }, + 'legend': { + 'position': 'none' + } + }) + +print(chart) + +# Generate deforestation point locations. + +def func_hoz(feat): + return feat.centroid() + +deforestationCentroids = deforestationVector.map(func_hoz) + + + + +Map.addLayer(deforestationCentroids, { + 'color': 'darkblue' +}, 'Deforestation centroids') + +# Add a new property to the deforestation FeatureCollection +# describing the area of the change polygon. + +def func_opk(feat): + return feat.set('area', feat.geometry().area({ + 'maxError': 10 + }).divide(10000)); # Convert m^2 to hectare. + +deforestationVector = deforestationVector.map(func_opk) + + + + + + +# Filter the deforestation FeatureCollection for only large-scale (>10 ha) changes +deforestationLarge = deforestationVector.filter(ee.Filter.gt( + 'area', 10)) + +# Display deforestation area outline by year. +deforestationLargeOutline = ee.Image().byte().paint({ + 'featureCollection': deforestationLarge, + 'color': 'lossyear', + 'width': 1 +}) + +Map.addLayer(deforestationLargeOutline, { + 'palette': ['yellow', 'orange', 'red'], + 'min': 1, + 'max': 20 +}, 'Deforestation (>10 ha)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51c Checkpoint.ipynb new file mode 100644 index 0000000..a82b98a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51c Checkpoint.ipynb @@ -0,0 +1,174 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.1 Raster/Vector Conversions\n", + "# Checkpoint: F51c\n", + "# Authors: Keiko Nomura, Samuel Bowers\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#-------------#\n", + "# Section 1.4 #\n", + "#-------------#\n", + "\n", + "# Load required datasets.\n", + "gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8')\n", + "wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons')\n", + "\n", + "# Display deforestation.\n", + "deforestation = gfc.select('lossyear')\n", + "\n", + "Map.addLayer(deforestation, {\n", + " 'min': 1,\n", + " 'max': 20,\n", + " 'palette': ['yellow', 'orange', 'red']\n", + "}, 'Deforestation raster')\n", + "\n", + "# Select protected areas in the Colombian Amazon.\n", + "amazonianProtectedAreas = [\n", + " 'Cordillera de los Picachos', 'La Paya', 'Nukak',\n", + " 'Serrania de Chiribiquete',\n", + " 'Sierra de la Macarena', 'Tinigua'\n", + "]\n", + "\n", + "wdpaSubset = wdpa.filter(ee.Filter.inList('NAME',\n", + " amazonianProtectedAreas))\n", + "\n", + "# Display protected areas as an outline.\n", + "protectedAreasOutline = ee.Image().byte().paint({\n", + " 'featureCollection': wdpaSubset,\n", + " 'color': 1,\n", + " 'width': 1\n", + "})\n", + "\n", + "Map.addLayer(protectedAreasOutline, {\n", + " 'palette': 'white'\n", + "}, 'Amazonian protected areas')\n", + "\n", + "# Set up map display.\n", + "Map.centerObject(wdpaSubset)\n", + "Map.setOptions('SATELLITE')\n", + "\n", + "scale = deforestation.projection().nominalScale()\n", + "\n", + "# Use 'reduceRegions' to sum together pixel areas in each protected area.\n", + "wdpaSubset = deforestation.gte(1) \\\n", + " .multiply(ee.Image.pixelArea().divide(10000)).reduceRegions({\n", + " 'collection': wdpaSubset,\n", + " 'reducer': ee.Reducer.sum().setOutputs([\n", + " 'deforestation_area']),\n", + " 'scale': scale\n", + " })\n", + "\n", + "print(wdpaSubset); # Note the new 'deforestation_area' property.\n", + "\n", + "# Normalize by area.\n", + "wdpaSubset = wdpaSubset.map(\n", + " def function(feat):\n", + " return feat.set('deforestation_rate',\n", + " ee.Number(feat.get('deforestation_area')) \\\n", + " .divide(feat.area().divide(10000)) \\\n", + " .divide(20) \\\n", + " .multiply(100)); \n", + " )\n", + "\n", + "# Print to identify rates of change per protected area.\n", + "# Which has the fastest rate of loss?\n", + "print(wdpaSubset.reduceColumns({\n", + " 'reducer': ee.Reducer.toList().repeat(2),\n", + " 'selectors': ['NAME', 'deforestation_rate']\n", + "}))\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51c Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51c Checkpoint.js new file mode 100644 index 0000000..b0b1242 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51c Checkpoint.js @@ -0,0 +1,81 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.1 Raster/Vector Conversions +// Checkpoint: F51c +// Authors: Keiko Nomura, Samuel Bowers +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//-------------// +// Section 1.4 // +//-------------// + +// Load required datasets. +var gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8'); +var wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons'); + +// Display deforestation. +var deforestation = gfc.select('lossyear'); + +Map.addLayer(deforestation, { + min: 1, + max: 20, + palette: ['yellow', 'orange', 'red'] +}, 'Deforestation raster'); + +// Select protected areas in the Colombian Amazon. +var amazonianProtectedAreas = [ + 'Cordillera de los Picachos', 'La Paya', 'Nukak', + 'Serrania de Chiribiquete', + 'Sierra de la Macarena', 'Tinigua' +]; + +var wdpaSubset = wdpa.filter(ee.Filter.inList('NAME', + amazonianProtectedAreas)); + +// Display protected areas as an outline. +var protectedAreasOutline = ee.Image().byte().paint({ + featureCollection: wdpaSubset, + color: 1, + width: 1 +}); + +Map.addLayer(protectedAreasOutline, { + palette: 'white' +}, 'Amazonian protected areas'); + +// Set up map display. +Map.centerObject(wdpaSubset); +Map.setOptions('SATELLITE'); + +var scale = deforestation.projection().nominalScale(); + +// Use 'reduceRegions' to sum together pixel areas in each protected area. +wdpaSubset = deforestation.gte(1) + .multiply(ee.Image.pixelArea().divide(10000)).reduceRegions({ + collection: wdpaSubset, + reducer: ee.Reducer.sum().setOutputs([ + 'deforestation_area']), + scale: scale + }); + +print(wdpaSubset); // Note the new 'deforestation_area' property. + +// Normalize by area. +wdpaSubset = wdpaSubset.map( + function(feat) { + return feat.set('deforestation_rate', + ee.Number(feat.get('deforestation_area')) + .divide(feat.area().divide(10000)) // m2 to ha + .divide(20) // number of years + .multiply(100)); // to percentage points + }); + +// Print to identify rates of change per protected area. +// Which has the fastest rate of loss? +print(wdpaSubset.reduceColumns({ + reducer: ee.Reducer.toList().repeat(2), + selectors: ['NAME', 'deforestation_rate'] +})); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51c Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51c Checkpoint.py new file mode 100644 index 0000000..efb3955 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51c Checkpoint.py @@ -0,0 +1,87 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.1 Raster/Vector Conversions +# Checkpoint: F51c +# Authors: Keiko Nomura, Samuel Bowers +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#-------------# +# Section 1.4 # +#-------------# + +# Load required datasets. +gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') +wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons') + +# Display deforestation. +deforestation = gfc.select('lossyear') + +Map.addLayer(deforestation, { + 'min': 1, + 'max': 20, + 'palette': ['yellow', 'orange', 'red'] +}, 'Deforestation raster') + +# Select protected areas in the Colombian Amazon. +amazonianProtectedAreas = [ + 'Cordillera de los Picachos', 'La Paya', 'Nukak', + 'Serrania de Chiribiquete', + 'Sierra de la Macarena', 'Tinigua' +] + +wdpaSubset = wdpa.filter(ee.Filter.inList('NAME', + amazonianProtectedAreas)) + +# Display protected areas as an outline. +protectedAreasOutline = ee.Image().byte().paint({ + 'featureCollection': wdpaSubset, + 'color': 1, + 'width': 1 +}) + +Map.addLayer(protectedAreasOutline, { + 'palette': 'white' +}, 'Amazonian protected areas') + +# Set up map display. +Map.centerObject(wdpaSubset) +Map.setOptions('SATELLITE') + +scale = deforestation.projection().nominalScale() + +# Use 'reduceRegions' to sum together pixel areas in each protected area. +wdpaSubset = deforestation.gte(1) \ + .multiply(ee.Image.pixelArea().divide(10000)).reduceRegions({ + 'collection': wdpaSubset, + 'reducer': ee.Reducer.sum().setOutputs([ + 'deforestation_area']), + 'scale': scale + }) + +print(wdpaSubset); # Note the new 'deforestation_area' property. + +# Normalize by area. +wdpaSubset = wdpaSubset.map( + def function(feat): + return feat.set('deforestation_rate', + ee.Number(feat.get('deforestation_area')) \ + .divide(feat.area().divide(10000)) \ + .divide(20) \ + .multiply(100)); + ) + +# Print to identify rates of change per protected area. +# Which has the fastest rate of loss? +print(wdpaSubset.reduceColumns({ + 'reducer': ee.Reducer.toList().repeat(2), + 'selectors': ['NAME', 'deforestation_rate'] +})) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51d Checkpoint.ipynb new file mode 100644 index 0000000..79caa49 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51d Checkpoint.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.1 Raster/Vector Conversions\n", + "# Checkpoint: F51d\n", + "# Authors: Keiko Nomura, Samuel Bowers\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#-------------#\n", + "# Section 2.1 #\n", + "#-------------#\n", + "\n", + "# Load required datasets.\n", + "gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8')\n", + "wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons')\n", + "\n", + "# Get deforestation.\n", + "deforestation = gfc.select('lossyear')\n", + "\n", + "# Generate a new property called 'protected' to apply to the output mask.\n", + "\n", + "def func_hmy(feat):\n", + " return feat.set('protected', 1)\n", + "\n", + "wdpa = wdpa.map(func_hmy)\n", + "\n", + "\n", + "\n", + "\n", + "# Rasterize using the new property.\n", + "# unmask() sets areas outside protected area polygons to 0.\n", + "wdpaMask = wdpa.reduceToImage(['protected'], ee.Reducer.first()) \\\n", + " .unmask()\n", + "\n", + "# Center on Colombia.\n", + "Map.setCenter(-75, 3, 6)\n", + "\n", + "# Display on map.\n", + "Map.addLayer(wdpaMask, {\n", + " 'min': 0,\n", + " 'max': 1\n", + "}, 'Protected areas (mask)')\n", + "\n", + "# Set the deforestation layer to 0 where outside a protected area.\n", + "deforestationProtected = deforestation.where(wdpaMask.eq(0), 0)\n", + "\n", + "# Update mask to hide where deforestation layer = 0\n", + "deforestationProtected = deforestationProtected \\\n", + " .updateMask(deforestationProtected.gt(0))\n", + "\n", + "# Display deforestation in protected areas\n", + "Map.addLayer(deforestationProtected, {\n", + " 'min': 1,\n", + " 'max': 20,\n", + " 'palette': ['yellow', 'orange', 'red']\n", + "}, 'Deforestation protected')\n", + "\n", + "# Produce an image with unique ID of protected areas.\n", + "wdpaId = wdpa.reduceToImage(['WDPAID'], ee.Reducer.first())\n", + "\n", + "Map.addLayer(wdpaId, {\n", + " 'min': 1,\n", + " 'max': 100000\n", + "}, 'Protected area ID')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51d Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51d Checkpoint.js new file mode 100644 index 0000000..3bcfb56 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51d Checkpoint.js @@ -0,0 +1,61 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.1 Raster/Vector Conversions +// Checkpoint: F51d +// Authors: Keiko Nomura, Samuel Bowers +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//-------------// +// Section 2.1 // +//-------------// + +// Load required datasets. +var gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8'); +var wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons'); + +// Get deforestation. +var deforestation = gfc.select('lossyear'); + +// Generate a new property called 'protected' to apply to the output mask. +var wdpa = wdpa.map(function(feat) { + return feat.set('protected', 1); +}); + +// Rasterize using the new property. +// unmask() sets areas outside protected area polygons to 0. +var wdpaMask = wdpa.reduceToImage(['protected'], ee.Reducer.first()) + .unmask(); + +// Center on Colombia. +Map.setCenter(-75, 3, 6); + +// Display on map. +Map.addLayer(wdpaMask, { + min: 0, + max: 1 +}, 'Protected areas (mask)'); + +// Set the deforestation layer to 0 where outside a protected area. +var deforestationProtected = deforestation.where(wdpaMask.eq(0), 0); + +// Update mask to hide where deforestation layer = 0 +var deforestationProtected = deforestationProtected + .updateMask(deforestationProtected.gt(0)); + +// Display deforestation in protected areas +Map.addLayer(deforestationProtected, { + min: 1, + max: 20, + palette: ['yellow', 'orange', 'red'] +}, 'Deforestation protected'); + +// Produce an image with unique ID of protected areas. +var wdpaId = wdpa.reduceToImage(['WDPAID'], ee.Reducer.first()); + +Map.addLayer(wdpaId, { + min: 1, + max: 100000 +}, 'Protected area ID'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51d Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51d Checkpoint.py new file mode 100644 index 0000000..50dc869 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51d Checkpoint.py @@ -0,0 +1,72 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.1 Raster/Vector Conversions +# Checkpoint: F51d +# Authors: Keiko Nomura, Samuel Bowers +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#-------------# +# Section 2.1 # +#-------------# + +# Load required datasets. +gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') +wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons') + +# Get deforestation. +deforestation = gfc.select('lossyear') + +# Generate a new property called 'protected' to apply to the output mask. + +def func_hmy(feat): + return feat.set('protected', 1) + +wdpa = wdpa.map(func_hmy) + + + + +# Rasterize using the new property. +# unmask() sets areas outside protected area polygons to 0. +wdpaMask = wdpa.reduceToImage(['protected'], ee.Reducer.first()) \ + .unmask() + +# Center on Colombia. +Map.setCenter(-75, 3, 6) + +# Display on map. +Map.addLayer(wdpaMask, { + 'min': 0, + 'max': 1 +}, 'Protected areas (mask)') + +# Set the deforestation layer to 0 where outside a protected area. +deforestationProtected = deforestation.where(wdpaMask.eq(0), 0) + +# Update mask to hide where deforestation layer = 0 +deforestationProtected = deforestationProtected \ + .updateMask(deforestationProtected.gt(0)) + +# Display deforestation in protected areas +Map.addLayer(deforestationProtected, { + 'min': 1, + 'max': 20, + 'palette': ['yellow', 'orange', 'red'] +}, 'Deforestation protected') + +# Produce an image with unique ID of protected areas. +wdpaId = wdpa.reduceToImage(['WDPAID'], ee.Reducer.first()) + +Map.addLayer(wdpaId, { + 'min': 1, + 'max': 100000 +}, 'Protected area ID') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51e Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51e Checkpoint.ipynb new file mode 100644 index 0000000..906b9e4 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51e Checkpoint.ipynb @@ -0,0 +1,194 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.1 Raster/Vector Conversions\n", + "# Checkpoint: F51e\n", + "# Authors: Keiko Nomura, Samuel Bowers\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#-------------#\n", + "# Section 2.2 #\n", + "#-------------#\n", + "\n", + "# Load required datasets.\n", + "gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8')\n", + "wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons')\n", + "\n", + "# Select a single protected area.\n", + "protectedArea = wdpa.filter(ee.Filter.equals('NAME', 'La Paya'))\n", + "\n", + "# Maximum distance in meters is set in the brackets.\n", + "distance = protectedArea.distance(1000000)\n", + "\n", + "Map.addLayer(distance, {\n", + " 'min': 0,\n", + " 'max': 20000,\n", + " 'palette': ['white', 'grey', 'black'],\n", + " 'opacity': 0.6\n", + "}, 'Distance')\n", + "\n", + "Map.centerObject(protectedArea)\n", + "\n", + "# Produce a raster of inside/outside the protected area.\n", + "\n", + "def func_azl(feat):\n", + " return feat.set('protected', 1)\n", + "\n", + "protectedAreaRaster = protectedArea.map(func_azl\n", + ").reduceToImage(['protected'], ee.Reducer.first())\n", + "\n", + ").reduceToImage(['protected'], ee.Reducer.first())\n", + "\n", + "Map.addLayer(distance.updateMask(protectedAreaRaster), {\n", + " 'min': 0,\n", + " 'max': 20000\n", + "}, 'Distance inside protected area')\n", + "\n", + "Map.addLayer(distance.updateMask(protectedAreaRaster.unmask() \\\n", + ".Not()), {\n", + " 'min': 0,\n", + " 'max': 20000\n", + "}, 'Distance outside protected area')\n", + "\n", + "distanceZones = ee.Image(0) \\\n", + " .where(distance.gt(0), 1) \\\n", + " .where(distance.gt(1000), 2) \\\n", + " .where(distance.gt(3000), 3) \\\n", + " .updateMask(distance.lte(5000))\n", + "\n", + "Map.addLayer(distanceZones, {}, 'Distance zones')\n", + "\n", + "deforestation = gfc.select('loss')\n", + "deforestation1km = deforestation.updateMask(distanceZones.eq(1))\n", + "deforestation3km = deforestation.updateMask(distanceZones.lte(2))\n", + "deforestation5km = deforestation.updateMask(distanceZones.lte(3))\n", + "\n", + "Map.addLayer(deforestation1km, {\n", + " 'min': 0,\n", + " 'max': 1\n", + "}, 'Deforestation within a 1km buffer')\n", + "Map.addLayer(deforestation3km, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'opacity': 0.5\n", + "}, 'Deforestation within a 3km buffer')\n", + "Map.addLayer(deforestation5km, {\n", + " 'min': 0,\n", + " 'max': 1,\n", + " 'opacity': 0.5\n", + "}, 'Deforestation within a 5km buffer')\n", + "\n", + "deforestation1kmOutside = deforestation1km \\\n", + " .updateMask(protectedAreaRaster.unmask().Not())\n", + "\n", + "# Get the value of each pixel in square meters\n", + "# and divide by 10000 to convert to hectares.\n", + "deforestation1kmOutsideArea = deforestation1kmOutside.eq(1) \\\n", + " .multiply(ee.Image.pixelArea()).divide(10000)\n", + "\n", + "# We need to set a larger geometry than the protected area\n", + "# for the geometry parameter in reduceRegion().\n", + "deforestationEstimate = deforestation1kmOutsideArea \\\n", + " .reduceRegion({\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'geometry': protectedArea.geometry().buffer(1000),\n", + " 'scale': deforestation.projection().nominalScale()\n", + " })\n", + "\n", + "print('Deforestation within a 1km buffer outside the protected area (ha)',\n", + " deforestationEstimate)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51e Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51e Checkpoint.js new file mode 100644 index 0000000..d4a8816 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51e Checkpoint.js @@ -0,0 +1,96 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.1 Raster/Vector Conversions +// Checkpoint: F51e +// Authors: Keiko Nomura, Samuel Bowers +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//-------------// +// Section 2.2 // +//-------------// + +// Load required datasets. +var gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8'); +var wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons'); + +// Select a single protected area. +var protectedArea = wdpa.filter(ee.Filter.equals('NAME', 'La Paya')); + +// Maximum distance in meters is set in the brackets. +var distance = protectedArea.distance(1000000); + +Map.addLayer(distance, { + min: 0, + max: 20000, + palette: ['white', 'grey', 'black'], + opacity: 0.6 +}, 'Distance'); + +Map.centerObject(protectedArea); + +// Produce a raster of inside/outside the protected area. +var protectedAreaRaster = protectedArea.map(function(feat) { + return feat.set('protected', 1); +}).reduceToImage(['protected'], ee.Reducer.first()); + +Map.addLayer(distance.updateMask(protectedAreaRaster), { + min: 0, + max: 20000 +}, 'Distance inside protected area'); + +Map.addLayer(distance.updateMask(protectedAreaRaster.unmask() +.not()), { + min: 0, + max: 20000 +}, 'Distance outside protected area'); + +var distanceZones = ee.Image(0) + .where(distance.gt(0), 1) + .where(distance.gt(1000), 2) + .where(distance.gt(3000), 3) + .updateMask(distance.lte(5000)); + +Map.addLayer(distanceZones, {}, 'Distance zones'); + +var deforestation = gfc.select('loss'); +var deforestation1km = deforestation.updateMask(distanceZones.eq(1)); +var deforestation3km = deforestation.updateMask(distanceZones.lte(2)); +var deforestation5km = deforestation.updateMask(distanceZones.lte(3)); + +Map.addLayer(deforestation1km, { + min: 0, + max: 1 +}, 'Deforestation within a 1km buffer'); +Map.addLayer(deforestation3km, { + min: 0, + max: 1, + opacity: 0.5 +}, 'Deforestation within a 3km buffer'); +Map.addLayer(deforestation5km, { + min: 0, + max: 1, + opacity: 0.5 +}, 'Deforestation within a 5km buffer'); + +var deforestation1kmOutside = deforestation1km + .updateMask(protectedAreaRaster.unmask().not()); + +// Get the value of each pixel in square meters +// and divide by 10000 to convert to hectares. +var deforestation1kmOutsideArea = deforestation1kmOutside.eq(1) + .multiply(ee.Image.pixelArea()).divide(10000); + +// We need to set a larger geometry than the protected area +// for the geometry parameter in reduceRegion(). +var deforestationEstimate = deforestation1kmOutsideArea + .reduceRegion({ + reducer: ee.Reducer.sum(), + geometry: protectedArea.geometry().buffer(1000), + scale: deforestation.projection().nominalScale() + }); + +print('Deforestation within a 1km buffer outside the protected area (ha)', + deforestationEstimate); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51e Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51e Checkpoint.py new file mode 100644 index 0000000..4e10159 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.1 Vector Raster Conversion/F51e Checkpoint.py @@ -0,0 +1,107 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.1 Raster/Vector Conversions +# Checkpoint: F51e +# Authors: Keiko Nomura, Samuel Bowers +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#-------------# +# Section 2.2 # +#-------------# + +# Load required datasets. +gfc = ee.Image('UMD/hansen/global_forest_change_2020_v1_8') +wdpa = ee.FeatureCollection('WCMC/WDPA/current/polygons') + +# Select a single protected area. +protectedArea = wdpa.filter(ee.Filter.equals('NAME', 'La Paya')) + +# Maximum distance in meters is set in the brackets. +distance = protectedArea.distance(1000000) + +Map.addLayer(distance, { + 'min': 0, + 'max': 20000, + 'palette': ['white', 'grey', 'black'], + 'opacity': 0.6 +}, 'Distance') + +Map.centerObject(protectedArea) + +# Produce a raster of inside/outside the protected area. + +def func_azl(feat): + return feat.set('protected', 1) + +protectedAreaRaster = protectedArea.map(func_azl +).reduceToImage(['protected'], ee.Reducer.first()) + +).reduceToImage(['protected'], ee.Reducer.first()) + +Map.addLayer(distance.updateMask(protectedAreaRaster), { + 'min': 0, + 'max': 20000 +}, 'Distance inside protected area') + +Map.addLayer(distance.updateMask(protectedAreaRaster.unmask() \ +.Not()), { + 'min': 0, + 'max': 20000 +}, 'Distance outside protected area') + +distanceZones = ee.Image(0) \ + .where(distance.gt(0), 1) \ + .where(distance.gt(1000), 2) \ + .where(distance.gt(3000), 3) \ + .updateMask(distance.lte(5000)) + +Map.addLayer(distanceZones, {}, 'Distance zones') + +deforestation = gfc.select('loss') +deforestation1km = deforestation.updateMask(distanceZones.eq(1)) +deforestation3km = deforestation.updateMask(distanceZones.lte(2)) +deforestation5km = deforestation.updateMask(distanceZones.lte(3)) + +Map.addLayer(deforestation1km, { + 'min': 0, + 'max': 1 +}, 'Deforestation within a 1km buffer') +Map.addLayer(deforestation3km, { + 'min': 0, + 'max': 1, + 'opacity': 0.5 +}, 'Deforestation within a 3km buffer') +Map.addLayer(deforestation5km, { + 'min': 0, + 'max': 1, + 'opacity': 0.5 +}, 'Deforestation within a 5km buffer') + +deforestation1kmOutside = deforestation1km \ + .updateMask(protectedAreaRaster.unmask().Not()) + +# Get the value of each pixel in square meters +# and divide by 10000 to convert to hectares. +deforestation1kmOutsideArea = deforestation1kmOutside.eq(1) \ + .multiply(ee.Image.pixelArea()).divide(10000) + +# We need to set a larger geometry than the protected area +# for the geometry parameter in reduceRegion(). +deforestationEstimate = deforestation1kmOutsideArea \ + .reduceRegion({ + 'reducer': ee.Reducer.sum(), + 'geometry': protectedArea.geometry().buffer(1000), + 'scale': deforestation.projection().nominalScale() + }) + +print('Deforestation within a 1km buffer outside the protected area (ha)', + deforestationEstimate) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52a Checkpoint.ipynb new file mode 100644 index 0000000..c93163b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52a Checkpoint.ipynb @@ -0,0 +1,250 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.2 Zonal Statistics\n", + "# Checkpoint: F52a\n", + "# Authors: Sara Winsemius and Justin Braaten\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Functions that the rest of the chapter is based on.\n", + "\n", + "# Returns a function for adding a buffer to points and optionally transforming\n", + "# to rectangular bounds\n", + "def bufferPoints(radius, bounds):\n", + " return function(pt) {\n", + " pt = ee.Feature(pt)\n", + " 'return bounds ? pt.buffer(radius).bounds()' : pt.buffer(\n", + " radius)\n", + " }\n", + "\n", + "\n", + "# Reduces images in an ImageCollection by regions defined in a\n", + "# FeatureCollection. Similar to mapping reduceRegions over an ImageCollection,\n", + "# but breaks the task up a bit more and includes parameters for managing\n", + "# property names.\n", + "def zonalStats(ic, fc, params):\n", + " # Initialize internal params dictionary.\n", + " _params = {\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': None,\n", + " 'crs': None,\n", + " 'bands': None,\n", + " 'bandsRename': None,\n", + " 'imgProps': None,\n", + " 'imgPropsRename': None,\n", + " 'datetimeName': 'datetime',\n", + " 'datetimeFormat': 'YYYY-MM-dd HH:'mm':ss'\n", + " }\n", + "\n", + " # Replace initialized params with provided params.\n", + " if (params) {\n", + " for param in params:\n", + " _params[param] = params[param] || _params[param]\n", + "\n", + " }\n", + "\n", + " # Set default parameters based on an image representative.\n", + " imgRep = ic.first()\n", + " nonSystemImgProps = ee.Feature(None) \\\n", + " .copyProperties(imgRep).propertyNames()\n", + " if (!_params.bands) _params.bands = imgRep.bandNames()\n", + " if (!_params.bandsRename) _params.bandsRename = _params.bands\n", + " if (!_params.imgProps) _params.imgProps = nonSystemImgProps\n", + " if (!_params.imgPropsRename) _params.imgPropsRename = _params \\\n", + " .imgProps\n", + "\n", + " # Map the reduceRegions function over the image collection.\n", + "\n", + "def func_jaw(img):\n", + " # Select bands (optionally rename), set a datetime & timestamp property.\n", + " img = ee.Image(img.select(_params.bands, _params \\\n", + " .bandsRename)) \\\n", + " .set(_params.datetimeName, img.date().format(\n", + " _params.datetimeFormat)) \\\n", + " .set('timestamp', img.get('system:time_start'))\n", + "\n", + " # Define final image property dictionary to set in output features.\n", + " propsFrom = ee.List(_params.imgProps) \\\n", + " .cat(ee.List([_params.datetimeName,\n", + " 'timestamp']))\n", + " propsTo = ee.List(_params.imgPropsRename) \\\n", + " .cat(ee.List([_params.datetimeName,\n", + " 'timestamp']))\n", + " imgProps = img.toDictionary(propsFrom).rename(\n", + " propsFrom, propsTo)\n", + "\n", + " # Subset points that intersect the given image.\n", + " fcSub = fc.filterBounds(img.geometry())\n", + "\n", + " # Reduce the image by regions.\n", + " return img.reduceRegions({\n", + " 'collection': fcSub,\n", + " 'reducer': _params.reducer,\n", + " 'scale': _params.scale,\n", + " 'crs': _params.crs\n", + " }) \\\n", + " .map(function(f) {\n", + " return f.set(imgProps)\n", + " })\n", + "\n", + " # Converts the feature collection of feature collections to a single\n", + " #feature collection.\n", + "\n", + " results = ic.map(func_jaw\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + "\n", + " return results\n", + "\n", + "\n", + "# Creating points that will be used for the rest of the chapter.\n", + "# Alternatively, you could load your own points.\n", + "pts = ee.FeatureCollection([\n", + " ee.Feature(ee.Geometry.Point([-118.6010, 37.0777]), {\n", + " 'plot_id': 1\n", + " }),\n", + " ee.Feature(ee.Geometry.Point([-118.5896, 37.0778]), {\n", + " 'plot_id': 2\n", + " }),\n", + " ee.Feature(ee.Geometry.Point([-118.5842, 37.0805]), {\n", + " 'plot_id': 3\n", + " }),\n", + " ee.Feature(ee.Geometry.Point([-118.5994, 37.0936]), {\n", + " 'plot_id': 4\n", + " }),\n", + " ee.Feature(ee.Geometry.Point([-118.5861, 37.0567]), {\n", + " 'plot_id': 5\n", + " })\n", + "])\n", + "\n", + "print('Points of interest', pts)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52a Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52a Checkpoint.js new file mode 100644 index 0000000..9d76ecd --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52a Checkpoint.js @@ -0,0 +1,120 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.2 Zonal Statistics +// Checkpoint: F52a +// Authors: Sara Winsemius and Justin Braaten +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Functions that the rest of the chapter is based on. + +// Returns a function for adding a buffer to points and optionally transforming +// to rectangular bounds +function bufferPoints(radius, bounds) { + return function(pt) { + pt = ee.Feature(pt); + return bounds ? pt.buffer(radius).bounds() : pt.buffer( + radius); + }; +} + +// Reduces images in an ImageCollection by regions defined in a +// FeatureCollection. Similar to mapping reduceRegions over an ImageCollection, +// but breaks the task up a bit more and includes parameters for managing +// property names. +function zonalStats(ic, fc, params) { + // Initialize internal params dictionary. + var _params = { + reducer: ee.Reducer.mean(), + scale: null, + crs: null, + bands: null, + bandsRename: null, + imgProps: null, + imgPropsRename: null, + datetimeName: 'datetime', + datetimeFormat: 'YYYY-MM-dd HH:mm:ss' + }; + + // Replace initialized params with provided params. + if (params) { + for (var param in params) { + _params[param] = params[param] || _params[param]; + } + } + + // Set default parameters based on an image representative. + var imgRep = ic.first(); + var nonSystemImgProps = ee.Feature(null) + .copyProperties(imgRep).propertyNames(); + if (!_params.bands) _params.bands = imgRep.bandNames(); + if (!_params.bandsRename) _params.bandsRename = _params.bands; + if (!_params.imgProps) _params.imgProps = nonSystemImgProps; + if (!_params.imgPropsRename) _params.imgPropsRename = _params + .imgProps; + + // Map the reduceRegions function over the image collection. + var results = ic.map(function(img) { + // Select bands (optionally rename), set a datetime & timestamp property. + img = ee.Image(img.select(_params.bands, _params + .bandsRename)) + // Add datetime and timestamp features. + .set(_params.datetimeName, img.date().format( + _params.datetimeFormat)) + .set('timestamp', img.get('system:time_start')); + + // Define final image property dictionary to set in output features. + var propsFrom = ee.List(_params.imgProps) + .cat(ee.List([_params.datetimeName, + 'timestamp'])); + var propsTo = ee.List(_params.imgPropsRename) + .cat(ee.List([_params.datetimeName, + 'timestamp'])); + var imgProps = img.toDictionary(propsFrom).rename( + propsFrom, propsTo); + + // Subset points that intersect the given image. + var fcSub = fc.filterBounds(img.geometry()); + + // Reduce the image by regions. + return img.reduceRegions({ + collection: fcSub, + reducer: _params.reducer, + scale: _params.scale, + crs: _params.crs + }) + // Add metadata to each feature. + .map(function(f) { + return f.set(imgProps); + }); + + // Converts the feature collection of feature collections to a single + //feature collection. + }).flatten(); + + return results; +} + +// Creating points that will be used for the rest of the chapter. +// Alternatively, you could load your own points. +var pts = ee.FeatureCollection([ + ee.Feature(ee.Geometry.Point([-118.6010, 37.0777]), { + plot_id: 1 + }), + ee.Feature(ee.Geometry.Point([-118.5896, 37.0778]), { + plot_id: 2 + }), + ee.Feature(ee.Geometry.Point([-118.5842, 37.0805]), { + plot_id: 3 + }), + ee.Feature(ee.Geometry.Point([-118.5994, 37.0936]), { + plot_id: 4 + }), + ee.Feature(ee.Geometry.Point([-118.5861, 37.0567]), { + plot_id: 5 + }) +]); + +print('Points of interest', pts); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52a Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52a Checkpoint.py new file mode 100644 index 0000000..b9b9270 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52a Checkpoint.py @@ -0,0 +1,163 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.2 Zonal Statistics +# Checkpoint: F52a +# Authors: Sara Winsemius and Justin Braaten +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Functions that the rest of the chapter is based on. + +# Returns a function for adding a buffer to points and optionally transforming +# to rectangular bounds +def bufferPoints(radius, bounds): + return function(pt) { + pt = ee.Feature(pt) + 'return bounds ? pt.buffer(radius).bounds()' : pt.buffer( + radius) + } + + +# Reduces images in an ImageCollection by regions defined in a +# FeatureCollection. Similar to mapping reduceRegions over an ImageCollection, +# but breaks the task up a bit more and includes parameters for managing +# property names. +def zonalStats(ic, fc, params): + # Initialize internal params dictionary. + _params = { + 'reducer': ee.Reducer.mean(), + 'scale': None, + 'crs': None, + 'bands': None, + 'bandsRename': None, + 'imgProps': None, + 'imgPropsRename': None, + 'datetimeName': 'datetime', + 'datetimeFormat': 'YYYY-MM-dd HH:'mm':ss' + } + + # Replace initialized params with provided params. + if (params) { + for param in params: + _params[param] = params[param] || _params[param] + + } + + # Set default parameters based on an image representative. + imgRep = ic.first() + nonSystemImgProps = ee.Feature(None) \ + .copyProperties(imgRep).propertyNames() + if (!_params.bands) _params.bands = imgRep.bandNames() + if (!_params.bandsRename) _params.bandsRename = _params.bands + if (!_params.imgProps) _params.imgProps = nonSystemImgProps + if (!_params.imgPropsRename) _params.imgPropsRename = _params \ + .imgProps + + # Map the reduceRegions function over the image collection. + +def func_jaw(img): + # Select bands (optionally rename), set a datetime & timestamp property. + img = ee.Image(img.select(_params.bands, _params \ + .bandsRename)) \ + .set(_params.datetimeName, img.date().format( + _params.datetimeFormat)) \ + .set('timestamp', img.get('system:time_start')) + + # Define final image property dictionary to set in output features. + propsFrom = ee.List(_params.imgProps) \ + .cat(ee.List([_params.datetimeName, + 'timestamp'])) + propsTo = ee.List(_params.imgPropsRename) \ + .cat(ee.List([_params.datetimeName, + 'timestamp'])) + imgProps = img.toDictionary(propsFrom).rename( + propsFrom, propsTo) + + # Subset points that intersect the given image. + fcSub = fc.filterBounds(img.geometry()) + + # Reduce the image by regions. + return img.reduceRegions({ + 'collection': fcSub, + 'reducer': _params.reducer, + 'scale': _params.scale, + 'crs': _params.crs + }) \ + .map(function(f) { + return f.set(imgProps) + }) + + # Converts the feature collection of feature collections to a single + #feature collection. + + results = ic.map(func_jaw +).flatten() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +).flatten() + + return results + + +# Creating points that will be used for the rest of the chapter. +# Alternatively, you could load your own points. +pts = ee.FeatureCollection([ + ee.Feature(ee.Geometry.Point([-118.6010, 37.0777]), { + 'plot_id': 1 + }), + ee.Feature(ee.Geometry.Point([-118.5896, 37.0778]), { + 'plot_id': 2 + }), + ee.Feature(ee.Geometry.Point([-118.5842, 37.0805]), { + 'plot_id': 3 + }), + ee.Feature(ee.Geometry.Point([-118.5994, 37.0936]), { + 'plot_id': 4 + }), + ee.Feature(ee.Geometry.Point([-118.5861, 37.0567]), { + 'plot_id': 5 + }) +]) + +print('Points of interest', pts) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52b Checkpoint.ipynb new file mode 100644 index 0000000..18cc68b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52b Checkpoint.ipynb @@ -0,0 +1,436 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.2 Zonal Statistics\n", + "# Checkpoint: F52b\n", + "# Authors: Sara Winsemius and Justin Braaten\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Functions that the rest of the chapter is based on.\n", + "\n", + "# Returns a function for adding a buffer to points and optionally transforming\n", + "# to rectangular bounds\n", + "def bufferPoints(radius, bounds):\n", + " return function(pt) {\n", + " pt = ee.Feature(pt)\n", + " 'return bounds ? pt.buffer(radius).bounds()' : pt.buffer(\n", + " radius)\n", + " }\n", + "\n", + "\n", + "# Reduces images in an ImageCollection by regions defined in a\n", + "# FeatureCollection. Similar to mapping reduceRegions over an ImageCollection,\n", + "# but breaks the task up a bit more and includes parameters for managing\n", + "# property names.\n", + "def zonalStats(ic, fc, params):\n", + " # Initialize internal params dictionary.\n", + " _params = {\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': None,\n", + " 'crs': None,\n", + " 'bands': None,\n", + " 'bandsRename': None,\n", + " 'imgProps': None,\n", + " 'imgPropsRename': None,\n", + " 'datetimeName': 'datetime',\n", + " 'datetimeFormat': 'YYYY-MM-dd HH:'mm':ss'\n", + " }\n", + "\n", + " # Replace initialized params with provided params.\n", + " if (params) {\n", + " for param in params:\n", + " _params[param] = params[param] || _params[param]\n", + "\n", + " }\n", + "\n", + " # Set default parameters based on an image representative.\n", + " imgRep = ic.first()\n", + " nonSystemImgProps = ee.Feature(None) \\\n", + " .copyProperties(imgRep).propertyNames()\n", + " if (!_params.bands) _params.bands = imgRep.bandNames()\n", + " if (!_params.bandsRename) _params.bandsRename = _params.bands\n", + " if (!_params.imgProps) _params.imgProps = nonSystemImgProps\n", + " if (!_params.imgPropsRename) _params.imgPropsRename = _params \\\n", + " .imgProps\n", + "\n", + " # Map the reduceRegions function over the image collection.\n", + "\n", + "def func_fpj(img):\n", + " # Select bands (optionally rename), set a datetime & timestamp property.\n", + " img = ee.Image(img.select(_params.bands, _params \\\n", + " .bandsRename)) \\\n", + " .set(_params.datetimeName, img.date().format(\n", + " _params.datetimeFormat)) \\\n", + " .set('timestamp', img.get('system:time_start'))\n", + "\n", + " # Define final image property dictionary to set in output features.\n", + " propsFrom = ee.List(_params.imgProps) \\\n", + " .cat(ee.List([_params.datetimeName,\n", + " 'timestamp']))\n", + " propsTo = ee.List(_params.imgPropsRename) \\\n", + " .cat(ee.List([_params.datetimeName,\n", + " 'timestamp']))\n", + " imgProps = img.toDictionary(propsFrom).rename(\n", + " propsFrom, propsTo)\n", + "\n", + " # Subset points that intersect the given image.\n", + " fcSub = fc.filterBounds(img.geometry())\n", + "\n", + " # Reduce the image by regions.\n", + " return img.reduceRegions({\n", + " 'collection': fcSub,\n", + " 'reducer': _params.reducer,\n", + " 'scale': _params.scale,\n", + " 'crs': _params.crs\n", + " }) \\\n", + " .map(function(f) {\n", + " return f.set(imgProps)\n", + " })\n", + "\n", + " # Converts the feature collection of feature collections to a single\n", + " #feature collection.\n", + "\n", + " results = ic.map(func_fpj\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + "\n", + " return results\n", + "\n", + "\n", + "# Creating points that will be used for the rest of the chapter.\n", + "# Alternatively, you could load your own points.\n", + "pts = ee.FeatureCollection([\n", + " ee.Feature(ee.Geometry.Point([-118.6010, 37.0777]), {\n", + " 'plot_id': 1\n", + " }),\n", + " ee.Feature(ee.Geometry.Point([-118.5896, 37.0778]), {\n", + " 'plot_id': 2\n", + " }),\n", + " ee.Feature(ee.Geometry.Point([-118.5842, 37.0805]), {\n", + " 'plot_id': 3\n", + " }),\n", + " ee.Feature(ee.Geometry.Point([-118.5994, 37.0936]), {\n", + " 'plot_id': 4\n", + " }),\n", + " ee.Feature(ee.Geometry.Point([-118.5861, 37.0567]), {\n", + " 'plot_id': 5\n", + " })\n", + "])\n", + "\n", + "print('Points of interest', pts)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Example 1: Topographic variables\n", + "\n", + "# Buffer the points.\n", + "ptsTopo = pts.map(bufferPoints(45, False))\n", + "\n", + "# Import the MERIT global elevation dataset.\n", + "elev = ee.Image('MERIT/DEM/v1_0_3')\n", + "\n", + "# Calculate slope from the DEM.\n", + "slope = ee.Terrain.slope(elev)\n", + "\n", + "# Concatenate elevation and slope as two bands of an image.\n", + "topo = ee.Image.cat(elev, slope)\n", + " # Computed images do not have a 'system:time_start' property; add one based \\\n", + " .set('system:time_start', ee.Date('2000-01-01').millis())\n", + "\n", + "# Wrap the single image in an ImageCollection for use in the\n", + "# zonalStats function.\n", + "topoCol = ee.ImageCollection([topo])\n", + "\n", + "# Define parameters for the zonalStats function.\n", + "params = {\n", + " 'bands': [0, 1],\n", + " 'bandsRename': ['elevation', 'slope']\n", + "}\n", + "\n", + "# Extract zonal statistics per point per image.\n", + "ptsTopoStats = zonalStats(topoCol, ptsTopo, params)\n", + "print('Topo zonal stats table', ptsTopoStats)\n", + "\n", + "# Display the layers on the map.\n", + "Map.setCenter(-118.5957, 37.0775, 13)\n", + "Map.addLayer(topoCol.select(0), {\n", + " 'min': 2400,\n", + " 'max': 4200\n", + "}, 'Elevation')\n", + "Map.addLayer(topoCol.select(1), {\n", + " 'min': 0,\n", + " 'max': 60\n", + "}, 'Slope')\n", + "Map.addLayer(pts, {\n", + " 'color': 'purple'\n", + "}, 'Points')\n", + "Map.addLayer(ptsTopo, {\n", + " 'color': 'yellow'\n", + "}, 'Points w/ buffer')\n", + "\n", + "\n", + "########################################\n", + "\n", + "# Example 2: MODIS\n", + "\n", + "ptsModis = pts.map(bufferPoints(50, True))\n", + "\n", + "# Load MODIS time series\n", + "modisCol = ee.ImageCollection('MODIS/006/MOD09A1') \\\n", + " .filterDate('2015-01-01', '2020-01-01') \\\n", + " .filter(ee.Filter.calendarRange(183, 245, 'DAY_OF_YEAR'))\n", + "\n", + "# Define parameters for the zonalStats function.\n", + "params = {\n", + " 'reducer': ee.Reducer.median(),\n", + " 'scale': 500,\n", + " 'crs': 'EPSG:5070',\n", + " 'bands': ['sur_refl_b01', 'sur_refl_b02', 'sur_refl_b06'],\n", + " 'bandsRename': ['modis_red', 'modis_nir', 'modis_swir'],\n", + " 'datetimeName': 'date',\n", + " 'datetimeFormat': 'YYYY-MM-dd'\n", + "}\n", + "\n", + "# Extract zonal statistics per point per image.\n", + "ptsModisStats = zonalStats(modisCol, ptsModis, params)\n", + "print('Limited MODIS zonal stats table', ptsModisStats.limit(50))\n", + "\n", + "########################################\n", + "\n", + "# Example 3: Landsat timeseries\n", + "\n", + "# Mask clouds from images and apply scaling factors.\n", + "def maskScale(img):\n", + " qaMask = img.select('QA_PIXEL').bitwiseAnd(parseInt('11111',\n", + " 2)).eq(0)\n", + " saturationMask = img.select('QA_RADSAT').eq(0)\n", + "\n", + " # Apply the scaling factors to the appropriate bands.\n", + " def getFactorImg(factorNames):\n", + " factorList = img.toDictionary().select(factorNames) \\\n", + " .values()\n", + " return ee.Image.constant(factorList)\n", + " \n", + " scaleImg = getFactorImg(['REFLECTANCE_MULT_BAND_.'])\n", + " offsetImg = getFactorImg(['REFLECTANCE_ADD_BAND_.'])\n", + " scaled = img.select('SR_B.').multiply(scaleImg).add(\n", + " offsetImg)\n", + "\n", + " # Replace the original bands with the scaled ones and apply the masks.\n", + " return img.addBands(scaled, None, True) \\\n", + " .updateMask(qaMask) \\\n", + " .updateMask(saturationMask)\n", + "\n", + "\n", + "# Selects and renames bands of interest for Landsat OLI.\n", + "def renameOli(img):\n", + " return img.select(\n", + " ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'],\n", + " ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'])\n", + "\n", + "\n", + "# Selects and renames bands of interest for TM/ETM+.\n", + "def renameEtm(img):\n", + " return img.select(\n", + " ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'],\n", + " ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'])\n", + "\n", + "\n", + "# Prepares (cloud masks and renames) OLI images.\n", + "def prepOli(img):\n", + " img = maskScale(img)\n", + " img = renameOli(img)\n", + " return img\n", + "\n", + "\n", + "# Prepares (cloud masks and renames) TM/ETM+ images.\n", + "def prepEtm(img):\n", + " img = maskScale(img)\n", + " img = renameEtm(img)\n", + " return img\n", + "\n", + "\n", + "ptsLandsat = pts.map(bufferPoints(15, True))\n", + "\n", + "oliCol = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \\\n", + " .filterBounds(ptsLandsat) \\\n", + " .map(prepOli)\n", + "\n", + "etmCol = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') \\\n", + " .filterBounds(ptsLandsat) \\\n", + " .map(prepEtm)\n", + "\n", + "tmCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2') \\\n", + " .filterBounds(ptsLandsat) \\\n", + " .map(prepEtm)\n", + "\n", + "# Merge the sensor collections\n", + "landsatCol = oliCol.merge(etmCol).merge(tmCol)\n", + "\n", + "# Define parameters for the zonalStats function.\n", + "params = {\n", + " 'reducer': ee.Reducer.max(),\n", + " 'scale': 30,\n", + " 'crs': 'EPSG:5070',\n", + " 'bands': ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'],\n", + " 'bandsRename': ['ls_blue', 'ls_green', 'ls_red', 'ls_nir',\n", + " 'ls_swir1', 'ls_swir2'\n", + " ],\n", + " 'imgProps': ['SENSOR_ID', 'SPACECRAFT_ID'],\n", + " 'imgPropsRename': ['img_id', 'satellite'],\n", + " 'datetimeName': 'date',\n", + " 'datetimeFormat': 'YYYY-MM-dd'\n", + "}\n", + "\n", + "# Extract zonal statistics per point per image.\n", + "ptsLandsatStats = zonalStats(landsatCol, ptsLandsat, params) \\\n", + " .filter(ee.Filter.NotNull(params.bandsRename))\n", + "print('Limited Landsat zonal stats table', ptsLandsatStats.limit(50))\n", + "\n", + "Export.table.toAsset({\n", + " 'collection': ptsLandsatStats,\n", + " 'description': 'EEFA_export_Landsat_to_points',\n", + " 'assetId': 'EEFA_export_values_to_points'\n", + "})\n", + "\n", + "Export.table.toDrive({\n", + " 'collection': ptsLandsatStats,\n", + " 'folder': 'EEFA_outputs', # this will create a new folder if it doesn't exist\n", + " 'description': 'EEFA_export_values_to_points',\n", + " 'fileFormat': 'CSV'\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52b Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52b Checkpoint.js new file mode 100644 index 0000000..15b3ca8 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52b Checkpoint.js @@ -0,0 +1,309 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.2 Zonal Statistics +// Checkpoint: F52b +// Authors: Sara Winsemius and Justin Braaten +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Functions that the rest of the chapter is based on. + +// Returns a function for adding a buffer to points and optionally transforming +// to rectangular bounds +function bufferPoints(radius, bounds) { + return function(pt) { + pt = ee.Feature(pt); + return bounds ? pt.buffer(radius).bounds() : pt.buffer( + radius); + }; +} + +// Reduces images in an ImageCollection by regions defined in a +// FeatureCollection. Similar to mapping reduceRegions over an ImageCollection, +// but breaks the task up a bit more and includes parameters for managing +// property names. +function zonalStats(ic, fc, params) { + // Initialize internal params dictionary. + var _params = { + reducer: ee.Reducer.mean(), + scale: null, + crs: null, + bands: null, + bandsRename: null, + imgProps: null, + imgPropsRename: null, + datetimeName: 'datetime', + datetimeFormat: 'YYYY-MM-dd HH:mm:ss' + }; + + // Replace initialized params with provided params. + if (params) { + for (var param in params) { + _params[param] = params[param] || _params[param]; + } + } + + // Set default parameters based on an image representative. + var imgRep = ic.first(); + var nonSystemImgProps = ee.Feature(null) + .copyProperties(imgRep).propertyNames(); + if (!_params.bands) _params.bands = imgRep.bandNames(); + if (!_params.bandsRename) _params.bandsRename = _params.bands; + if (!_params.imgProps) _params.imgProps = nonSystemImgProps; + if (!_params.imgPropsRename) _params.imgPropsRename = _params + .imgProps; + + // Map the reduceRegions function over the image collection. + var results = ic.map(function(img) { + // Select bands (optionally rename), set a datetime & timestamp property. + img = ee.Image(img.select(_params.bands, _params + .bandsRename)) + // Add datetime and timestamp features. + .set(_params.datetimeName, img.date().format( + _params.datetimeFormat)) + .set('timestamp', img.get('system:time_start')); + + // Define final image property dictionary to set in output features. + var propsFrom = ee.List(_params.imgProps) + .cat(ee.List([_params.datetimeName, + 'timestamp'])); + var propsTo = ee.List(_params.imgPropsRename) + .cat(ee.List([_params.datetimeName, + 'timestamp'])); + var imgProps = img.toDictionary(propsFrom).rename( + propsFrom, propsTo); + + // Subset points that intersect the given image. + var fcSub = fc.filterBounds(img.geometry()); + + // Reduce the image by regions. + return img.reduceRegions({ + collection: fcSub, + reducer: _params.reducer, + scale: _params.scale, + crs: _params.crs + }) + // Add metadata to each feature. + .map(function(f) { + return f.set(imgProps); + }); + + // Converts the feature collection of feature collections to a single + //feature collection. + }).flatten(); + + return results; +} + +// Creating points that will be used for the rest of the chapter. +// Alternatively, you could load your own points. +var pts = ee.FeatureCollection([ + ee.Feature(ee.Geometry.Point([-118.6010, 37.0777]), { + plot_id: 1 + }), + ee.Feature(ee.Geometry.Point([-118.5896, 37.0778]), { + plot_id: 2 + }), + ee.Feature(ee.Geometry.Point([-118.5842, 37.0805]), { + plot_id: 3 + }), + ee.Feature(ee.Geometry.Point([-118.5994, 37.0936]), { + plot_id: 4 + }), + ee.Feature(ee.Geometry.Point([-118.5861, 37.0567]), { + plot_id: 5 + }) +]); + +print('Points of interest', pts); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Example 1: Topographic variables + +// Buffer the points. +var ptsTopo = pts.map(bufferPoints(45, false)); + +// Import the MERIT global elevation dataset. +var elev = ee.Image('MERIT/DEM/v1_0_3'); + +// Calculate slope from the DEM. +var slope = ee.Terrain.slope(elev); + +// Concatenate elevation and slope as two bands of an image. +var topo = ee.Image.cat(elev, slope) + // Computed images do not have a 'system:time_start' property; add one based + // on when the data were collected. + .set('system:time_start', ee.Date('2000-01-01').millis()); + +// Wrap the single image in an ImageCollection for use in the +// zonalStats function. +var topoCol = ee.ImageCollection([topo]); + +// Define parameters for the zonalStats function. +var params = { + bands: [0, 1], + bandsRename: ['elevation', 'slope'] +}; + +// Extract zonal statistics per point per image. +var ptsTopoStats = zonalStats(topoCol, ptsTopo, params); +print('Topo zonal stats table', ptsTopoStats); + +// Display the layers on the map. +Map.setCenter(-118.5957, 37.0775, 13); +Map.addLayer(topoCol.select(0), { + min: 2400, + max: 4200 +}, 'Elevation'); +Map.addLayer(topoCol.select(1), { + min: 0, + max: 60 +}, 'Slope'); +Map.addLayer(pts, { + color: 'purple' +}, 'Points'); +Map.addLayer(ptsTopo, { + color: 'yellow' +}, 'Points w/ buffer'); + + +//////////////////////////////////////////////////////////////////////////////// + +// Example 2: MODIS + +var ptsModis = pts.map(bufferPoints(50, true)); + +// Load MODIS time series +var modisCol = ee.ImageCollection('MODIS/006/MOD09A1') + .filterDate('2015-01-01', '2020-01-01') + .filter(ee.Filter.calendarRange(183, 245, 'DAY_OF_YEAR')); + +// Define parameters for the zonalStats function. +var params = { + reducer: ee.Reducer.median(), + scale: 500, + crs: 'EPSG:5070', + bands: ['sur_refl_b01', 'sur_refl_b02', 'sur_refl_b06'], + bandsRename: ['modis_red', 'modis_nir', 'modis_swir'], + datetimeName: 'date', + datetimeFormat: 'YYYY-MM-dd' +}; + +// Extract zonal statistics per point per image. +var ptsModisStats = zonalStats(modisCol, ptsModis, params); +print('Limited MODIS zonal stats table', ptsModisStats.limit(50)); + +//////////////////////////////////////////////////////////////////////////////// + +// Example 3: Landsat timeseries + +// Mask clouds from images and apply scaling factors. +function maskScale(img) { + var qaMask = img.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = img.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var getFactorImg = function(factorNames) { + var factorList = img.toDictionary().select(factorNames) + .values(); + return ee.Image.constant(factorList); + }; + var scaleImg = getFactorImg(['REFLECTANCE_MULT_BAND_.']); + var offsetImg = getFactorImg(['REFLECTANCE_ADD_BAND_.']); + var scaled = img.select('SR_B.').multiply(scaleImg).add( + offsetImg); + + // Replace the original bands with the scaled ones and apply the masks. + return img.addBands(scaled, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); +} + +// Selects and renames bands of interest for Landsat OLI. +function renameOli(img) { + return img.select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']); +} + +// Selects and renames bands of interest for TM/ETM+. +function renameEtm(img) { + return img.select( + ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'], + ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']); +} + +// Prepares (cloud masks and renames) OLI images. +function prepOli(img) { + img = maskScale(img); + img = renameOli(img); + return img; +} + +// Prepares (cloud masks and renames) TM/ETM+ images. +function prepEtm(img) { + img = maskScale(img); + img = renameEtm(img); + return img; +} + +var ptsLandsat = pts.map(bufferPoints(15, true)); + +var oliCol = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(ptsLandsat) + .map(prepOli); + +var etmCol = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') + .filterBounds(ptsLandsat) + .map(prepEtm); + +var tmCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2') + .filterBounds(ptsLandsat) + .map(prepEtm); + +// Merge the sensor collections +var landsatCol = oliCol.merge(etmCol).merge(tmCol); + +// Define parameters for the zonalStats function. +var params = { + reducer: ee.Reducer.max(), + scale: 30, + crs: 'EPSG:5070', + bands: ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'], + bandsRename: ['ls_blue', 'ls_green', 'ls_red', 'ls_nir', + 'ls_swir1', 'ls_swir2' + ], + imgProps: ['SENSOR_ID', 'SPACECRAFT_ID'], + imgPropsRename: ['img_id', 'satellite'], + datetimeName: 'date', + datetimeFormat: 'YYYY-MM-dd' +}; + +// Extract zonal statistics per point per image. +var ptsLandsatStats = zonalStats(landsatCol, ptsLandsat, params) + // Filter out observations where image pixels were all masked. + .filter(ee.Filter.notNull(params.bandsRename)); +print('Limited Landsat zonal stats table', ptsLandsatStats.limit(50)); + +Export.table.toAsset({ + collection: ptsLandsatStats, + description: 'EEFA_export_Landsat_to_points', + assetId: 'EEFA_export_values_to_points' +}); + +Export.table.toDrive({ + collection: ptsLandsatStats, + folder: 'EEFA_outputs', // this will create a new folder if it doesn't exist + description: 'EEFA_export_values_to_points', + fileFormat: 'CSV' +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + + diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52b Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52b Checkpoint.py new file mode 100644 index 0000000..8345038 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52b Checkpoint.py @@ -0,0 +1,350 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.2 Zonal Statistics +# Checkpoint: F52b +# Authors: Sara Winsemius and Justin Braaten +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Functions that the rest of the chapter is based on. + +# Returns a function for adding a buffer to points and optionally transforming +# to rectangular bounds +def bufferPoints(radius, bounds): + return function(pt) { + pt = ee.Feature(pt) + 'return bounds ? pt.buffer(radius).bounds()' : pt.buffer( + radius) + } + + +# Reduces images in an ImageCollection by regions defined in a +# FeatureCollection. Similar to mapping reduceRegions over an ImageCollection, +# but breaks the task up a bit more and includes parameters for managing +# property names. +def zonalStats(ic, fc, params): + # Initialize internal params dictionary. + _params = { + 'reducer': ee.Reducer.mean(), + 'scale': None, + 'crs': None, + 'bands': None, + 'bandsRename': None, + 'imgProps': None, + 'imgPropsRename': None, + 'datetimeName': 'datetime', + 'datetimeFormat': 'YYYY-MM-dd HH:'mm':ss' + } + + # Replace initialized params with provided params. + if (params) { + for param in params: + _params[param] = params[param] || _params[param] + + } + + # Set default parameters based on an image representative. + imgRep = ic.first() + nonSystemImgProps = ee.Feature(None) \ + .copyProperties(imgRep).propertyNames() + if (!_params.bands) _params.bands = imgRep.bandNames() + if (!_params.bandsRename) _params.bandsRename = _params.bands + if (!_params.imgProps) _params.imgProps = nonSystemImgProps + if (!_params.imgPropsRename) _params.imgPropsRename = _params \ + .imgProps + + # Map the reduceRegions function over the image collection. + +def func_fpj(img): + # Select bands (optionally rename), set a datetime & timestamp property. + img = ee.Image(img.select(_params.bands, _params \ + .bandsRename)) \ + .set(_params.datetimeName, img.date().format( + _params.datetimeFormat)) \ + .set('timestamp', img.get('system:time_start')) + + # Define final image property dictionary to set in output features. + propsFrom = ee.List(_params.imgProps) \ + .cat(ee.List([_params.datetimeName, + 'timestamp'])) + propsTo = ee.List(_params.imgPropsRename) \ + .cat(ee.List([_params.datetimeName, + 'timestamp'])) + imgProps = img.toDictionary(propsFrom).rename( + propsFrom, propsTo) + + # Subset points that intersect the given image. + fcSub = fc.filterBounds(img.geometry()) + + # Reduce the image by regions. + return img.reduceRegions({ + 'collection': fcSub, + 'reducer': _params.reducer, + 'scale': _params.scale, + 'crs': _params.crs + }) \ + .map(function(f) { + return f.set(imgProps) + }) + + # Converts the feature collection of feature collections to a single + #feature collection. + + results = ic.map(func_fpj +).flatten() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +).flatten() + + return results + + +# Creating points that will be used for the rest of the chapter. +# Alternatively, you could load your own points. +pts = ee.FeatureCollection([ + ee.Feature(ee.Geometry.Point([-118.6010, 37.0777]), { + 'plot_id': 1 + }), + ee.Feature(ee.Geometry.Point([-118.5896, 37.0778]), { + 'plot_id': 2 + }), + ee.Feature(ee.Geometry.Point([-118.5842, 37.0805]), { + 'plot_id': 3 + }), + ee.Feature(ee.Geometry.Point([-118.5994, 37.0936]), { + 'plot_id': 4 + }), + ee.Feature(ee.Geometry.Point([-118.5861, 37.0567]), { + 'plot_id': 5 + }) +]) + +print('Points of interest', pts) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Example 1: Topographic variables + +# Buffer the points. +ptsTopo = pts.map(bufferPoints(45, False)) + +# Import the MERIT global elevation dataset. +elev = ee.Image('MERIT/DEM/v1_0_3') + +# Calculate slope from the DEM. +slope = ee.Terrain.slope(elev) + +# Concatenate elevation and slope as two bands of an image. +topo = ee.Image.cat(elev, slope) + # Computed images do not have a 'system:time_start' property; add one based \ + .set('system:time_start', ee.Date('2000-01-01').millis()) + +# Wrap the single image in an ImageCollection for use in the +# zonalStats function. +topoCol = ee.ImageCollection([topo]) + +# Define parameters for the zonalStats function. +params = { + 'bands': [0, 1], + 'bandsRename': ['elevation', 'slope'] +} + +# Extract zonal statistics per point per image. +ptsTopoStats = zonalStats(topoCol, ptsTopo, params) +print('Topo zonal stats table', ptsTopoStats) + +# Display the layers on the map. +Map.setCenter(-118.5957, 37.0775, 13) +Map.addLayer(topoCol.select(0), { + 'min': 2400, + 'max': 4200 +}, 'Elevation') +Map.addLayer(topoCol.select(1), { + 'min': 0, + 'max': 60 +}, 'Slope') +Map.addLayer(pts, { + 'color': 'purple' +}, 'Points') +Map.addLayer(ptsTopo, { + 'color': 'yellow' +}, 'Points w/ buffer') + + +######################################## + +# Example 2: MODIS + +ptsModis = pts.map(bufferPoints(50, True)) + +# Load MODIS time series +modisCol = ee.ImageCollection('MODIS/006/MOD09A1') \ + .filterDate('2015-01-01', '2020-01-01') \ + .filter(ee.Filter.calendarRange(183, 245, 'DAY_OF_YEAR')) + +# Define parameters for the zonalStats function. +params = { + 'reducer': ee.Reducer.median(), + 'scale': 500, + 'crs': 'EPSG:5070', + 'bands': ['sur_refl_b01', 'sur_refl_b02', 'sur_refl_b06'], + 'bandsRename': ['modis_red', 'modis_nir', 'modis_swir'], + 'datetimeName': 'date', + 'datetimeFormat': 'YYYY-MM-dd' +} + +# Extract zonal statistics per point per image. +ptsModisStats = zonalStats(modisCol, ptsModis, params) +print('Limited MODIS zonal stats table', ptsModisStats.limit(50)) + +######################################## + +# Example 3: Landsat timeseries + +# Mask clouds from images and apply scaling factors. +def maskScale(img): + qaMask = img.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0) + saturationMask = img.select('QA_RADSAT').eq(0) + + # Apply the scaling factors to the appropriate bands. + def getFactorImg(factorNames): + factorList = img.toDictionary().select(factorNames) \ + .values() + return ee.Image.constant(factorList) + + scaleImg = getFactorImg(['REFLECTANCE_MULT_BAND_.']) + offsetImg = getFactorImg(['REFLECTANCE_ADD_BAND_.']) + scaled = img.select('SR_B.').multiply(scaleImg).add( + offsetImg) + + # Replace the original bands with the scaled ones and apply the masks. + return img.addBands(scaled, None, True) \ + .updateMask(qaMask) \ + .updateMask(saturationMask) + + +# Selects and renames bands of interest for Landsat OLI. +def renameOli(img): + return img.select( + ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], + ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']) + + +# Selects and renames bands of interest for TM/ETM+. +def renameEtm(img): + return img.select( + ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'], + ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']) + + +# Prepares (cloud masks and renames) OLI images. +def prepOli(img): + img = maskScale(img) + img = renameOli(img) + return img + + +# Prepares (cloud masks and renames) TM/ETM+ images. +def prepEtm(img): + img = maskScale(img) + img = renameEtm(img) + return img + + +ptsLandsat = pts.map(bufferPoints(15, True)) + +oliCol = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \ + .filterBounds(ptsLandsat) \ + .map(prepOli) + +etmCol = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') \ + .filterBounds(ptsLandsat) \ + .map(prepEtm) + +tmCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2') \ + .filterBounds(ptsLandsat) \ + .map(prepEtm) + +# Merge the sensor collections +landsatCol = oliCol.merge(etmCol).merge(tmCol) + +# Define parameters for the zonalStats function. +params = { + 'reducer': ee.Reducer.max(), + 'scale': 30, + 'crs': 'EPSG:5070', + 'bands': ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'], + 'bandsRename': ['ls_blue', 'ls_green', 'ls_red', 'ls_nir', + 'ls_swir1', 'ls_swir2' + ], + 'imgProps': ['SENSOR_ID', 'SPACECRAFT_ID'], + 'imgPropsRename': ['img_id', 'satellite'], + 'datetimeName': 'date', + 'datetimeFormat': 'YYYY-MM-dd' +} + +# Extract zonal statistics per point per image. +ptsLandsatStats = zonalStats(landsatCol, ptsLandsat, params) \ + .filter(ee.Filter.NotNull(params.bandsRename)) +print('Limited Landsat zonal stats table', ptsLandsatStats.limit(50)) + +Export.table.toAsset({ + 'collection': ptsLandsatStats, + 'description': 'EEFA_export_Landsat_to_points', + 'assetId': 'EEFA_export_values_to_points' +}) + +Export.table.toDrive({ + 'collection': ptsLandsatStats, + 'folder': 'EEFA_outputs', # this will create a new folder if it doesn't exist + 'description': 'EEFA_export_values_to_points', + 'fileFormat': 'CSV' +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52c Checkpoint.ipynb new file mode 100644 index 0000000..b3c6e94 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52c Checkpoint.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.2 Zonal Statistics\n", + "# Checkpoint: F52c\n", + "# Authors: Sara Winsemius and Justin Braaten\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Copy properties to computed images\n", + "\n", + "# Define a Landsat image.\n", + "img = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2').first()\n", + "\n", + "# Print its properties.\n", + "print('All image properties', img.propertyNames())\n", + "\n", + "# Subset the reflectance bands and unscale them.\n", + "computedImg = img.select('SR_B.').multiply(0.0000275).add(-0.2)\n", + "\n", + "# Print the unscaled image's properties.\n", + "print('Lost original image properties', computedImg.propertyNames())\n", + "\n", + "# Subset the reflectance bands and unscale them, keeping selected\n", + "# source properties.\n", + "computedImg = img.select('SR_B.').multiply(0.0000275).add(-0.2) \\\n", + " .copyProperties(img, ['system:time_start', 'LANDSAT_PRODUCT_ID'])\n", + "\n", + "# Print the unscaled image's properties.\n", + "print('Selected image properties retained', computedImg \\\n", + ".propertyNames())\n", + "\n", + "# Understanding which pixels are included in polygon statistics\n", + "\n", + "# Define polygon geometry.\n", + "geometry = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-118.6019835717645, 37.079867782687884],\n", + " [-118.6019835717645, 37.07838698844939],\n", + " [-118.60036351751951, 37.07838698844939],\n", + " [-118.60036351751951, 37.079867782687884]\n", + " ]\n", + " ], None, False)\n", + "\n", + "# Import the MERIT global elevation dataset.\n", + "elev = ee.Image('MERIT/DEM/v1_0_3')\n", + "\n", + "# Define desired scale and crs for region reduction (for image display too).\n", + "proj = {\n", + " 'scale': 90,\n", + " 'crs': 'EPSG:5070'\n", + "}\n", + "\n", + "# A count reducer will return how many pixel centers are overlapped by the\n", + "# polygon region.\n", + "count = elev.select(0).reduceRegion({\n", + " 'reducer': ee.Reducer.count(),\n", + " 'geometry': geometry,\n", + " 'scale': proj.scale,\n", + " 'crs': proj.crs\n", + "})\n", + "print('n pixels in the reduction', count.get('dem'))\n", + "\n", + "# Make a feature collection of pixel center points for those that are\n", + "# included in the reduction.\n", + "pixels = ee.Image.pixelLonLat().reduceRegion({\n", + " 'reducer': ee.Reducer.toCollection(['lon', 'lat']),\n", + " 'geometry': geometry,\n", + " 'scale': proj.scale,\n", + " 'crs': proj.crs\n", + "})\n", + "pixelsFc = ee.FeatureCollection(pixels.get('features')).map(\n", + " def function(f):\n", + " return f.setGeometry(ee.Geometry.Point([f.get('lon'), f \\\n", + " .get('lat')\n", + " ]))\n", + " )\n", + "\n", + "# Display layers on the map.\n", + "Map.centerObject(geometry, 18)\n", + "Map.addLayer(\n", + " elev.reproject({\n", + " 'crs': proj.crs,\n", + " 'scale': proj.scale\n", + " }),\n", + " {\n", + " 'min': 2500,\n", + " 'max': 3000,\n", + " 'palette': ['blue', 'white', 'red']\n", + " }, 'Image')\n", + "Map.addLayer(geometry, {\n", + " 'color': 'white'\n", + "}, 'Geometry')\n", + "Map.addLayer(pixelsFc, {\n", + " 'color': 'purple'\n", + "}, 'Pixels in reduction')\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52c Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52c Checkpoint.js new file mode 100644 index 0000000..bae032b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52c Checkpoint.js @@ -0,0 +1,104 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.2 Zonal Statistics +// Checkpoint: F52c +// Authors: Sara Winsemius and Justin Braaten +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Copy properties to computed images + +// Define a Landsat image. +var img = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2').first(); + +// Print its properties. +print('All image properties', img.propertyNames()); + +// Subset the reflectance bands and unscale them. +var computedImg = img.select('SR_B.').multiply(0.0000275).add(-0.2); + +// Print the unscaled image's properties. +print('Lost original image properties', computedImg.propertyNames()); + +// Subset the reflectance bands and unscale them, keeping selected +// source properties. +var computedImg = img.select('SR_B.').multiply(0.0000275).add(-0.2) + .copyProperties(img, ['system:time_start', 'LANDSAT_PRODUCT_ID']); + +// Print the unscaled image's properties. +print('Selected image properties retained', computedImg +.propertyNames()); + +// Understanding which pixels are included in polygon statistics + +// Define polygon geometry. +var geometry = ee.Geometry.Polygon( + [ + [ + [-118.6019835717645, 37.079867782687884], + [-118.6019835717645, 37.07838698844939], + [-118.60036351751951, 37.07838698844939], + [-118.60036351751951, 37.079867782687884] + ] + ], null, false); + +// Import the MERIT global elevation dataset. +var elev = ee.Image('MERIT/DEM/v1_0_3'); + +// Define desired scale and crs for region reduction (for image display too). +var proj = { + scale: 90, + crs: 'EPSG:5070' +}; + +// A count reducer will return how many pixel centers are overlapped by the +// polygon region. +var count = elev.select(0).reduceRegion({ + reducer: ee.Reducer.count(), + geometry: geometry, + scale: proj.scale, + crs: proj.crs +}); +print('n pixels in the reduction', count.get('dem')); + +// Make a feature collection of pixel center points for those that are +// included in the reduction. +var pixels = ee.Image.pixelLonLat().reduceRegion({ + reducer: ee.Reducer.toCollection(['lon', 'lat']), + geometry: geometry, + scale: proj.scale, + crs: proj.crs +}); +var pixelsFc = ee.FeatureCollection(pixels.get('features')).map( + function(f) { + return f.setGeometry(ee.Geometry.Point([f.get('lon'), f + .get('lat') + ])); + }); + +// Display layers on the map. +Map.centerObject(geometry, 18); +Map.addLayer( + elev.reproject({ + crs: proj.crs, + scale: proj.scale + }), + { + min: 2500, + max: 3000, + palette: ['blue', 'white', 'red'] + }, 'Image'); +Map.addLayer(geometry, { + color: 'white' +}, 'Geometry'); +Map.addLayer(pixelsFc, { + color: 'purple' +}, 'Pixels in reduction'); + + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + + diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52c Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52c Checkpoint.py new file mode 100644 index 0000000..73b0f78 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.2 Zonal Statistics/F52c Checkpoint.py @@ -0,0 +1,110 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.2 Zonal Statistics +# Checkpoint: F52c +# Authors: Sara Winsemius and Justin Braaten +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Copy properties to computed images + +# Define a Landsat image. +img = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2').first() + +# Print its properties. +print('All image properties', img.propertyNames()) + +# Subset the reflectance bands and unscale them. +computedImg = img.select('SR_B.').multiply(0.0000275).add(-0.2) + +# Print the unscaled image's properties. +print('Lost original image properties', computedImg.propertyNames()) + +# Subset the reflectance bands and unscale them, keeping selected +# source properties. +computedImg = img.select('SR_B.').multiply(0.0000275).add(-0.2) \ + .copyProperties(img, ['system:time_start', 'LANDSAT_PRODUCT_ID']) + +# Print the unscaled image's properties. +print('Selected image properties retained', computedImg \ +.propertyNames()) + +# Understanding which pixels are included in polygon statistics + +# Define polygon geometry. +geometry = ee.Geometry.Polygon( + [ + [ + [-118.6019835717645, 37.079867782687884], + [-118.6019835717645, 37.07838698844939], + [-118.60036351751951, 37.07838698844939], + [-118.60036351751951, 37.079867782687884] + ] + ], None, False) + +# Import the MERIT global elevation dataset. +elev = ee.Image('MERIT/DEM/v1_0_3') + +# Define desired scale and crs for region reduction (for image display too). +proj = { + 'scale': 90, + 'crs': 'EPSG:5070' +} + +# A count reducer will return how many pixel centers are overlapped by the +# polygon region. +count = elev.select(0).reduceRegion({ + 'reducer': ee.Reducer.count(), + 'geometry': geometry, + 'scale': proj.scale, + 'crs': proj.crs +}) +print('n pixels in the reduction', count.get('dem')) + +# Make a feature collection of pixel center points for those that are +# included in the reduction. +pixels = ee.Image.pixelLonLat().reduceRegion({ + 'reducer': ee.Reducer.toCollection(['lon', 'lat']), + 'geometry': geometry, + 'scale': proj.scale, + 'crs': proj.crs +}) +pixelsFc = ee.FeatureCollection(pixels.get('features')).map( + def function(f): + return f.setGeometry(ee.Geometry.Point([f.get('lon'), f \ + .get('lat') + ])) + ) + +# Display layers on the map. +Map.centerObject(geometry, 18) +Map.addLayer( + elev.reproject({ + 'crs': proj.crs, + 'scale': proj.scale + }), + { + 'min': 2500, + 'max': 3000, + 'palette': ['blue', 'white', 'red'] + }, 'Image') +Map.addLayer(geometry, { + 'color': 'white' +}, 'Geometry') +Map.addLayer(pixelsFc, { + 'color': 'purple' +}, 'Pixels in reduction') + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53a Checkpoint.ipynb new file mode 100644 index 0000000..2930492 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53a Checkpoint.ipynb @@ -0,0 +1,225 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.3 Advanced Vector Operations\n", + "# Checkpoint: F53a\n", + "# Author: Ujaval Gandhi\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "blocks = ee.FeatureCollection('TIGER/2010/Blocks')\n", + "roads = ee.FeatureCollection('TIGER/2016/Roads')\n", + "sfNeighborhoods = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/F5-0/SFneighborhoods')\n", + "\n", + "geometry = sfNeighborhoods.geometry()\n", + "Map.centerObject(geometry)\n", + "\n", + "# Creating a Choropleth Map\n", + "\n", + "# Filter blocks to the San Francisco boundary.\n", + "sfBlocks = blocks.filter(ee.Filter.bounds(geometry))\n", + "\n", + "# Visualize with a single color.\n", + "Map.addLayer(sfBlocks, {\n", + " 'color': '#de2d26'\n", + "}, 'Census Blocks (single color)')\n", + "\n", + "# Visualize with values in a column using paint().\n", + "\n", + "# Add a pop_density column.\n", + "\n", + "def func_gvn(f):\n", + " # Get the polygon area in square miles.\n", + " area_sqmi = f.area().divide(2.59e6)\n", + " population = f.get('pop10')\n", + " # Calculate population density.\n", + " density = ee.Number(population).divide(area_sqmi)\n", + " return f.set({\n", + " 'area_sqmi': area_sqmi,\n", + " 'pop_density': density\n", + " })\n", + "\n", + "sfBlocks = sfBlocks.map(func_gvn)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Calculate the statistics of the newly computed column.\n", + "stats = sfBlocks.aggregate_stats('pop_density')\n", + "print(stats)\n", + "\n", + "# Create an empty image into which to paint the features.\n", + "# Cast to 32-bit integer which supports storing values\n", + "# up to 2,147,483,647.\n", + "\n", + "empty = ee.Image().int32()\n", + "\n", + "# use paint() to color image with the values from the\n", + "# 'pop_density' column.\n", + "sfBlocksPaint = empty.paint({\n", + " 'featureCollection': sfBlocks,\n", + " 'color': 'pop_density',\n", + "})\n", + "\n", + "palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15']\n", + "visParams = {\n", + " 'min': 0,\n", + " 'max': 50000,\n", + " 'palette': palette\n", + "}\n", + "Map.addLayer(sfBlocksPaint.clip(geometry), visParams,\n", + " 'Population Density')\n", + "\n", + "# Filter roads to San Francisco boundary.\n", + "sfRoads = roads.filter(ee.Filter.bounds(geometry))\n", + "\n", + "Map.addLayer(sfRoads, {\n", + " 'color': 'blue'\n", + "}, 'Roads (default)')\n", + "\n", + "# Visualize with draw().\n", + "sfRoadsDraw = sfRoads.draw({\n", + " 'color': 'blue',\n", + " 'strokeWidth': 1\n", + "})\n", + "Map.addLayer(sfRoadsDraw, {}, 'Roads (Draw)')\n", + "\n", + "styles = ee.Dictionary({\n", + " 'S1100': {\n", + " 'color': 'blue',\n", + " 'width': 3\n", + " },\n", + " 'S1200': {\n", + " 'color': 'green',\n", + " 'width': 2\n", + " },\n", + " 'S1400': {\n", + " 'color': 'orange',\n", + " 'width': 1\n", + " }\n", + "})\n", + "defaultStyle = {\n", + " 'color': 'gray',\n", + " 'width': 1\n", + "}\n", + "\n", + "\n", + "def func_wwf(f):\n", + " classcode = f.get('mtfcc')\n", + " style = styles.get(classcode, defaultStyle)\n", + " return f.set('style', style)\n", + "\n", + "sfRoads = sfRoads.map(func_wwf)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sfRoadsStyle = sfRoads.style(**{\n", + " 'styleProperty': 'style'\n", + "})\n", + "Map.addLayer(sfRoadsStyle.clip(geometry), {}, 'Roads (Style)')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53a Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53a Checkpoint.js new file mode 100644 index 0000000..776be72 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53a Checkpoint.js @@ -0,0 +1,112 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.3 Advanced Vector Operations +// Checkpoint: F53a +// Author: Ujaval Gandhi +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var blocks = ee.FeatureCollection('TIGER/2010/Blocks'); +var roads = ee.FeatureCollection('TIGER/2016/Roads'); +var sfNeighborhoods = ee.FeatureCollection( + 'projects/gee-book/assets/F5-0/SFneighborhoods'); + +var geometry = sfNeighborhoods.geometry(); +Map.centerObject(geometry); + +// Creating a Choropleth Map + +// Filter blocks to the San Francisco boundary. +var sfBlocks = blocks.filter(ee.Filter.bounds(geometry)); + +// Visualize with a single color. +Map.addLayer(sfBlocks, { + color: '#de2d26' +}, 'Census Blocks (single color)'); + +// Visualize with values in a column using paint(). + +// Add a pop_density column. +var sfBlocks = sfBlocks.map(function(f) { + // Get the polygon area in square miles. + var area_sqmi = f.area().divide(2.59e6); + var population = f.get('pop10'); + // Calculate population density. + var density = ee.Number(population).divide(area_sqmi); + return f.set({ + 'area_sqmi': area_sqmi, + 'pop_density': density + }); +}); + +// Calculate the statistics of the newly computed column. +var stats = sfBlocks.aggregate_stats('pop_density'); +print(stats); + +// Create an empty image into which to paint the features. +// Cast to 32-bit integer which supports storing values +// up to 2,147,483,647. + +var empty = ee.Image().int32(); + +// use paint() to color image with the values from the +// 'pop_density' column. +var sfBlocksPaint = empty.paint({ + featureCollection: sfBlocks, + color: 'pop_density', +}); + +var palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15']; +var visParams = { + min: 0, + max: 50000, + palette: palette +}; +Map.addLayer(sfBlocksPaint.clip(geometry), visParams, + 'Population Density'); + +// Filter roads to San Francisco boundary. +var sfRoads = roads.filter(ee.Filter.bounds(geometry)); + +Map.addLayer(sfRoads, { + color: 'blue' +}, 'Roads (default)'); + +// Visualize with draw(). +var sfRoadsDraw = sfRoads.draw({ + color: 'blue', + strokeWidth: 1 +}); +Map.addLayer(sfRoadsDraw, {}, 'Roads (Draw)'); + +var styles = ee.Dictionary({ + 'S1100': { + 'color': 'blue', + 'width': 3 + }, + 'S1200': { + 'color': 'green', + 'width': 2 + }, + 'S1400': { + 'color': 'orange', + 'width': 1 + } +}); +var defaultStyle = { + color: 'gray', + 'width': 1 +}; + +var sfRoads = sfRoads.map(function(f) { + var classcode = f.get('mtfcc'); + var style = styles.get(classcode, defaultStyle); + return f.set('style', style); +}); + +var sfRoadsStyle = sfRoads.style({ + styleProperty: 'style' +}); +Map.addLayer(sfRoadsStyle.clip(geometry), {}, 'Roads (Style)'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53a Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53a Checkpoint.py new file mode 100644 index 0000000..f40eab5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53a Checkpoint.py @@ -0,0 +1,138 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.3 Advanced Vector Operations +# Checkpoint: F53a +# Author: Ujaval Gandhi +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +blocks = ee.FeatureCollection('TIGER/2010/Blocks') +roads = ee.FeatureCollection('TIGER/2016/Roads') +sfNeighborhoods = ee.FeatureCollection( + 'projects/gee-book/assets/F5-0/SFneighborhoods') + +geometry = sfNeighborhoods.geometry() +Map.centerObject(geometry) + +# Creating a Choropleth Map + +# Filter blocks to the San Francisco boundary. +sfBlocks = blocks.filter(ee.Filter.bounds(geometry)) + +# Visualize with a single color. +Map.addLayer(sfBlocks, { + 'color': '#de2d26' +}, 'Census Blocks (single color)') + +# Visualize with values in a column using paint(). + +# Add a pop_density column. + +def func_gvn(f): + # Get the polygon area in square miles. + area_sqmi = f.area().divide(2.59e6) + population = f.get('pop10') + # Calculate population density. + density = ee.Number(population).divide(area_sqmi) + return f.set({ + 'area_sqmi': area_sqmi, + 'pop_density': density + }) + +sfBlocks = sfBlocks.map(func_gvn) + + + + + + + + + + + + +# Calculate the statistics of the newly computed column. +stats = sfBlocks.aggregate_stats('pop_density') +print(stats) + +# Create an empty image into which to paint the features. +# Cast to 32-bit integer which supports storing values +# up to 2,147,483,647. + +empty = ee.Image().int32() + +# use paint() to color image with the values from the +# 'pop_density' column. +sfBlocksPaint = empty.paint({ + 'featureCollection': sfBlocks, + 'color': 'pop_density', +}) + +palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15'] +visParams = { + 'min': 0, + 'max': 50000, + 'palette': palette +} +Map.addLayer(sfBlocksPaint.clip(geometry), visParams, + 'Population Density') + +# Filter roads to San Francisco boundary. +sfRoads = roads.filter(ee.Filter.bounds(geometry)) + +Map.addLayer(sfRoads, { + 'color': 'blue' +}, 'Roads (default)') + +# Visualize with draw(). +sfRoadsDraw = sfRoads.draw({ + 'color': 'blue', + 'strokeWidth': 1 +}) +Map.addLayer(sfRoadsDraw, {}, 'Roads (Draw)') + +styles = ee.Dictionary({ + 'S1100': { + 'color': 'blue', + 'width': 3 + }, + 'S1200': { + 'color': 'green', + 'width': 2 + }, + 'S1400': { + 'color': 'orange', + 'width': 1 + } +}) +defaultStyle = { + 'color': 'gray', + 'width': 1 +} + + +def func_wwf(f): + classcode = f.get('mtfcc') + style = styles.get(classcode, defaultStyle) + return f.set('style', style) + +sfRoads = sfRoads.map(func_wwf) + + + + + + +sfRoadsStyle = sfRoads.style(**{ + 'styleProperty': 'style' +}) +Map.addLayer(sfRoadsStyle.clip(geometry), {}, 'Roads (Style)') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53b Checkpoint.ipynb new file mode 100644 index 0000000..bd781a7 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53b Checkpoint.ipynb @@ -0,0 +1,226 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F5.3 Advanced Vector Operations\n", + "# Checkpoint: F53b\n", + "# Author: Ujaval Gandhi\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "blocks = ee.FeatureCollection('TIGER/2010/Blocks')\n", + "roads = ee.FeatureCollection('TIGER/2016/Roads')\n", + "sfNeighborhoods = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/F5-0/SFneighborhoods')\n", + "\n", + "geometry = sfNeighborhoods.geometry()\n", + "Map.centerObject(geometry)\n", + "\n", + "# Filter blocks and roads to the San Francisco boundary.\n", + "sfBlocks = blocks.filter(ee.Filter.bounds(geometry))\n", + "sfRoads = roads.filter(ee.Filter.bounds(geometry))\n", + "\n", + "# Select by Location\n", + "# Select all census blocks within 1km of an interstate.\n", + "interstateRoads = sfRoads.filter(ee.Filter.eq('rttyp', 'I'))\n", + "\n", + "# Visualize the layers\n", + "sfBlocksDrawn = sfBlocks.draw({\n", + " 'color': 'gray',\n", + " 'strokeWidth': 1\n", + " }) \\\n", + " .clip(geometry)\n", + "Map.addLayer(sfBlocksDrawn, {}, 'All Blocks')\n", + "interstateRoadsDrawn = interstateRoads.draw({\n", + " 'color': 'blue',\n", + " 'strokeWidth': 3\n", + " }) \\\n", + " .clip(geometry)\n", + "Map.addLayer(interstateRoadsDrawn, {}, 'Interstate Roads')\n", + "\n", + "# Define a spatial filter, with distance 1 km.\n", + "joinFilter = ee.Filter.withinDistance({\n", + " 'distance': 1000,\n", + " 'leftField': '.geo',\n", + " 'rightField': '.geo',\n", + " 'maxError': 10\n", + "})\n", + "\n", + "closeBlocks = ee.Join.simple().apply({\n", + " 'primary': sfBlocks,\n", + " 'secondary': interstateRoads,\n", + " 'condition': joinFilter\n", + "})\n", + "\n", + "closeBlocksDrawn = closeBlocks.draw({\n", + " 'color': 'orange',\n", + " 'strokeWidth': 1\n", + " }) \\\n", + " .clip(geometry)\n", + "Map.addLayer(closeBlocksDrawn, {}, 'Blocks within 1km')\n", + "\n", + "# Spatial Join (Summary)\n", + "# Calculate Tree Counts.\n", + "\n", + "sfNeighborhoods = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/F5-0/SFneighborhoods')\n", + "sfTrees = ee.FeatureCollection(\n", + " 'projects/gee-book/assets/F5-3/SFTrees')\n", + "\n", + "# Visualize the layers\n", + "\n", + "# Use paint() to visualize the polygons with only outline\n", + "sfNeighborhoodsOutline = ee.Image().byte().paint({\n", + " 'featureCollection': sfNeighborhoods,\n", + " 'color': 1,\n", + " 'width': 3\n", + "})\n", + "Map.addLayer(sfNeighborhoodsOutline, {\n", + " 'palette': ['blue']\n", + " },\n", + " 'SF Neighborhoods')\n", + "\n", + "# Use style() to visualize the points\n", + "sfTreesStyled = sfTrees.style(**{\n", + " 'color': 'green',\n", + " 'pointSize': 2,\n", + " 'pointShape': 'triangle',\n", + " 'width': 2\n", + "})\n", + "Map.addLayer(sfTreesStyled, {}, 'SF Trees')\n", + "\n", + "# Define a spatial intersection filter\n", + "intersectFilter = ee.Filter.intersects({\n", + " 'leftField': '.geo',\n", + " 'rightField': '.geo',\n", + " 'maxError': 10\n", + "})\n", + "\n", + "# Define a saveAll join.\n", + "saveAllJoin = ee.Join.saveAll({\n", + " 'matchesKey': 'trees',\n", + "})\n", + "\n", + "# Apply the join.\n", + "joined = saveAllJoin \\\n", + " .apply(sfNeighborhoods, sfTrees, intersectFilter)\n", + "print(joined.first())\n", + "\n", + "# Calculate total number of trees within each feature.\n", + "\n", + "def func_gjj(f):\n", + " treesWithin = ee.List(f.get('trees'))\n", + " totalTrees = ee.FeatureCollection(treesWithin).size()\n", + " return f.set('total_trees', totalTrees)\n", + "\n", + "sfNeighborhoods = joined.map(func_gjj)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "print(sfNeighborhoods.first())\n", + "\n", + "# Export the results as a CSV.\n", + "Export.table.toDrive({\n", + " 'collection': sfNeighborhoods,\n", + " 'description': 'SF_Neighborhood_Tree_Count',\n", + " 'folder': 'earthengine',\n", + " 'fileNamePrefix': 'tree_count',\n", + " 'fileFormat': 'CSV',\n", + " 'selectors': ['nhood', 'total_trees']\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53b Checkpoint.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53b Checkpoint.js new file mode 100644 index 0000000..43091e2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53b Checkpoint.js @@ -0,0 +1,126 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F5.3 Advanced Vector Operations +// Checkpoint: F53b +// Author: Ujaval Gandhi +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var blocks = ee.FeatureCollection('TIGER/2010/Blocks'); +var roads = ee.FeatureCollection('TIGER/2016/Roads'); +var sfNeighborhoods = ee.FeatureCollection( + 'projects/gee-book/assets/F5-0/SFneighborhoods'); + +var geometry = sfNeighborhoods.geometry(); +Map.centerObject(geometry); + +// Filter blocks and roads to the San Francisco boundary. +var sfBlocks = blocks.filter(ee.Filter.bounds(geometry)); +var sfRoads = roads.filter(ee.Filter.bounds(geometry)); + +// Select by Location +// Select all census blocks within 1km of an interstate. +var interstateRoads = sfRoads.filter(ee.Filter.eq('rttyp', 'I')); + +// Visualize the layers +var sfBlocksDrawn = sfBlocks.draw({ + color: 'gray', + strokeWidth: 1 + }) + .clip(geometry); +Map.addLayer(sfBlocksDrawn, {}, 'All Blocks'); +var interstateRoadsDrawn = interstateRoads.draw({ + color: 'blue', + strokeWidth: 3 + }) + .clip(geometry); +Map.addLayer(interstateRoadsDrawn, {}, 'Interstate Roads'); + +// Define a spatial filter, with distance 1 km. +var joinFilter = ee.Filter.withinDistance({ + distance: 1000, + leftField: '.geo', + rightField: '.geo', + maxError: 10 +}); + +var closeBlocks = ee.Join.simple().apply({ + primary: sfBlocks, + secondary: interstateRoads, + condition: joinFilter +}); + +var closeBlocksDrawn = closeBlocks.draw({ + color: 'orange', + strokeWidth: 1 + }) + .clip(geometry); +Map.addLayer(closeBlocksDrawn, {}, 'Blocks within 1km'); + +// Spatial Join (Summary) +// Calculate Tree Counts. + +var sfNeighborhoods = ee.FeatureCollection( + 'projects/gee-book/assets/F5-0/SFneighborhoods'); +var sfTrees = ee.FeatureCollection( + 'projects/gee-book/assets/F5-3/SFTrees'); + +// Visualize the layers + +// Use paint() to visualize the polygons with only outline +var sfNeighborhoodsOutline = ee.Image().byte().paint({ + featureCollection: sfNeighborhoods, + color: 1, + width: 3 +}); +Map.addLayer(sfNeighborhoodsOutline, { + palette: ['blue'] + }, + 'SF Neighborhoods'); + +// Use style() to visualize the points +var sfTreesStyled = sfTrees.style({ + color: 'green', + pointSize: 2, + pointShape: 'triangle', + width: 2 +}); +Map.addLayer(sfTreesStyled, {}, 'SF Trees'); + +// Define a spatial intersection filter +var intersectFilter = ee.Filter.intersects({ + leftField: '.geo', + rightField: '.geo', + maxError: 10 +}); + +// Define a saveAll join. +var saveAllJoin = ee.Join.saveAll({ + matchesKey: 'trees', +}); + +// Apply the join. +var joined = saveAllJoin + .apply(sfNeighborhoods, sfTrees, intersectFilter); +print(joined.first()); + +// Calculate total number of trees within each feature. +var sfNeighborhoods = joined.map(function(f) { + var treesWithin = ee.List(f.get('trees')); + var totalTrees = ee.FeatureCollection(treesWithin).size(); + return f.set('total_trees', totalTrees); +}); + +print(sfNeighborhoods.first()); + +// Export the results as a CSV. +Export.table.toDrive({ + collection: sfNeighborhoods, + description: 'SF_Neighborhood_Tree_Count', + folder: 'earthengine', + fileNamePrefix: 'tree_count', + fileFormat: 'CSV', + selectors: ['nhood', 'total_trees'] +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53b Checkpoint.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53b Checkpoint.py new file mode 100644 index 0000000..5d02f6f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.3 Advanced Vector Operations/F53b Checkpoint.py @@ -0,0 +1,139 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F5.3 Advanced Vector Operations +# Checkpoint: F53b +# Author: Ujaval Gandhi +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +blocks = ee.FeatureCollection('TIGER/2010/Blocks') +roads = ee.FeatureCollection('TIGER/2016/Roads') +sfNeighborhoods = ee.FeatureCollection( + 'projects/gee-book/assets/F5-0/SFneighborhoods') + +geometry = sfNeighborhoods.geometry() +Map.centerObject(geometry) + +# Filter blocks and roads to the San Francisco boundary. +sfBlocks = blocks.filter(ee.Filter.bounds(geometry)) +sfRoads = roads.filter(ee.Filter.bounds(geometry)) + +# Select by Location +# Select all census blocks within 1km of an interstate. +interstateRoads = sfRoads.filter(ee.Filter.eq('rttyp', 'I')) + +# Visualize the layers +sfBlocksDrawn = sfBlocks.draw({ + 'color': 'gray', + 'strokeWidth': 1 + }) \ + .clip(geometry) +Map.addLayer(sfBlocksDrawn, {}, 'All Blocks') +interstateRoadsDrawn = interstateRoads.draw({ + 'color': 'blue', + 'strokeWidth': 3 + }) \ + .clip(geometry) +Map.addLayer(interstateRoadsDrawn, {}, 'Interstate Roads') + +# Define a spatial filter, with distance 1 km. +joinFilter = ee.Filter.withinDistance({ + 'distance': 1000, + 'leftField': '.geo', + 'rightField': '.geo', + 'maxError': 10 +}) + +closeBlocks = ee.Join.simple().apply({ + 'primary': sfBlocks, + 'secondary': interstateRoads, + 'condition': joinFilter +}) + +closeBlocksDrawn = closeBlocks.draw({ + 'color': 'orange', + 'strokeWidth': 1 + }) \ + .clip(geometry) +Map.addLayer(closeBlocksDrawn, {}, 'Blocks within 1km') + +# Spatial Join (Summary) +# Calculate Tree Counts. + +sfNeighborhoods = ee.FeatureCollection( + 'projects/gee-book/assets/F5-0/SFneighborhoods') +sfTrees = ee.FeatureCollection( + 'projects/gee-book/assets/F5-3/SFTrees') + +# Visualize the layers + +# Use paint() to visualize the polygons with only outline +sfNeighborhoodsOutline = ee.Image().byte().paint({ + 'featureCollection': sfNeighborhoods, + 'color': 1, + 'width': 3 +}) +Map.addLayer(sfNeighborhoodsOutline, { + 'palette': ['blue'] + }, + 'SF Neighborhoods') + +# Use style() to visualize the points +sfTreesStyled = sfTrees.style(**{ + 'color': 'green', + 'pointSize': 2, + 'pointShape': 'triangle', + 'width': 2 +}) +Map.addLayer(sfTreesStyled, {}, 'SF Trees') + +# Define a spatial intersection filter +intersectFilter = ee.Filter.intersects({ + 'leftField': '.geo', + 'rightField': '.geo', + 'maxError': 10 +}) + +# Define a saveAll join. +saveAllJoin = ee.Join.saveAll({ + 'matchesKey': 'trees', +}) + +# Apply the join. +joined = saveAllJoin \ + .apply(sfNeighborhoods, sfTrees, intersectFilter) +print(joined.first()) + +# Calculate total number of trees within each feature. + +def func_gjj(f): + treesWithin = ee.List(f.get('trees')) + totalTrees = ee.FeatureCollection(treesWithin).size() + return f.set('total_trees', totalTrees) + +sfNeighborhoods = joined.map(func_gjj) + + + + + + +print(sfNeighborhoods.first()) + +# Export the results as a CSV. +Export.table.toDrive({ + 'collection': sfNeighborhoods, + 'description': 'SF_Neighborhood_Tree_Count', + 'folder': 'earthengine', + 'fileNamePrefix': 'tree_count', + 'fileFormat': 'CSV', + 'selectors': ['nhood', 'total_trees'] +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.4 GEEDiT/F54a Checkpoint Links and Info.ipynb b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.4 GEEDiT/F54a Checkpoint Links and Info.ipynb new file mode 100644 index 0000000..4eb69b3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.4 GEEDiT/F54a Checkpoint Links and Info.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "'To access the latest version of GEEDiT (and legacy versions), use the following link':\n", + "'https':#liverpoolgee.wordpress.com/geedit-geedit-reviewer/\n", + "\n", + "This tutorial was built using GEEDiT v2.02, and should also be valid for any later versions of version 2 that become available in the future. On this page you will see that there are actually two different GEEDiTs for each version. The first accesses Landsat Tier 1 imagery, and the second Landsat Tier 2. The former represent the highest quality imagery with respect to both spectral properties and geolocation accuracy, whereas the latter contains imagery that does not meet Tier 1 criteria. For some regions (e.g., Antarctica and some smaller islands) Tier 2 does provide a greater volume of imagery compared to Tier 1 that may be usable for particular research questions. However, in most cases, you will find that Tier 1 imagery is available." + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.4 GEEDiT/F54a Checkpoint Links and Info.js b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.4 GEEDiT/F54a Checkpoint Links and Info.js new file mode 100644 index 0000000..74ae6cc --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.4 GEEDiT/F54a Checkpoint Links and Info.js @@ -0,0 +1,4 @@ +To access the latest version of GEEDiT (and legacy versions), use the following link: +https://liverpoolgee.wordpress.com/geedit-geedit-reviewer/ + +This tutorial was built using GEEDiT v2.02, and should also be valid for any later versions of version 2 that become available in the future. On this page you will see that there are actually two different GEEDiTs for each version. The first accesses Landsat Tier 1 imagery, and the second Landsat Tier 2. The former represent the highest quality imagery with respect to both spectral properties and geolocation accuracy, whereas the latter contains imagery that does not meet Tier 1 criteria. For some regions (e.g., Antarctica and some smaller islands) Tier 2 does provide a greater volume of imagery compared to Tier 1 that may be usable for particular research questions. However, in most cases, you will find that Tier 1 imagery is available. diff --git a/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.4 GEEDiT/F54a Checkpoint Links and Info.py b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.4 GEEDiT/F54a Checkpoint Links and Info.py new file mode 100644 index 0000000..b0fdb44 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F5 - Vectors and Tables/F5.4 GEEDiT/F54a Checkpoint Links and Info.py @@ -0,0 +1,10 @@ +import ee +import geemap + +Map = geemap.Map() + +'To access the latest version of GEEDiT (and legacy versions), use the following link': +'https':#liverpoolgee.wordpress.com/geedit-geedit-reviewer/ + +This tutorial was built using GEEDiT v2.02, and should also be valid for any later versions of version 2 that become available in the future. On this page you will see that there are actually two different GEEDiTs for each version. The first accesses Landsat Tier 1 imagery, and the second Landsat Tier 2. The former represent the highest quality imagery with respect to both spectral properties and geolocation accuracy, whereas the latter contains imagery that does not meet Tier 1 criteria. For some regions (e.g., Antarctica and some smaller islands) Tier 2 does provide a greater volume of imagery compared to Tier 1 that may be usable for particular research questions. However, in most cases, you will find that Tier 1 imagery is available. +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60a Checkpoint.ipynb new file mode 100644 index 0000000..9ffcdd6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60a Checkpoint.ipynb @@ -0,0 +1,139 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60a\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load the ERA5 reanalysis monthly means.\n", + "era5 = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY')\n", + "\n", + "# Load the palettes package.\n", + "palettes = require('users/gena/packages:palettes')\n", + "\n", + "# Select temperature near ground.\n", + "era5 = era5.select('temperature_2m')\n", + "\n", + "# Choose a diverging colormap for anomalies.\n", + "balancePalette = palettes.cmocean.Balance[7]\n", + "threeColorPalette = ['blue', 'white', 'red']\n", + "\n", + "# Show the palette in the Inspector window.\n", + "palettes.showPalette('temperature anomaly', balancePalette)\n", + "palettes.showPalette('temperature anomaly', threeColorPalette)\n", + "\n", + "# Select 2 time windows of 10 years.\n", + "era5_1980 = era5.filterDate('1981-01-01', '1991-01-01').mean()\n", + "era5_2010 = era5.filterDate('2011-01-01', '2020-01-01').mean()\n", + "\n", + "# Compute the temperature change.\n", + "era5_diff = era5_2010.subtract(era5_1980)\n", + "\n", + "# Show it on the map.\n", + "Map.addLayer(era5_diff, {\n", + " 'palette': threeColorPalette,\n", + " 'min': -2,\n", + " 'max': 2\n", + "}, 'Blue White Red palette')\n", + "\n", + "Map.addLayer(era5_diff, {\n", + " 'palette': balancePalette,\n", + " 'min': -2,\n", + " 'max': 2\n", + "}, 'Balance palette')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60a Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60a Checkpoint.js new file mode 100644 index 0000000..3e54643 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60a Checkpoint.js @@ -0,0 +1,46 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60a +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load the ERA5 reanalysis monthly means. +var era5 = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY'); + +// Load the palettes package. +var palettes = require('users/gena/packages:palettes'); + +// Select temperature near ground. +era5 = era5.select('temperature_2m'); + +// Choose a diverging colormap for anomalies. +var balancePalette = palettes.cmocean.Balance[7]; +var threeColorPalette = ['blue', 'white', 'red']; + +// Show the palette in the Inspector window. +palettes.showPalette('temperature anomaly', balancePalette); +palettes.showPalette('temperature anomaly', threeColorPalette); + +// Select 2 time windows of 10 years. +var era5_1980 = era5.filterDate('1981-01-01', '1991-01-01').mean(); +var era5_2010 = era5.filterDate('2011-01-01', '2020-01-01').mean(); + +// Compute the temperature change. +var era5_diff = era5_2010.subtract(era5_1980); + +// Show it on the map. +Map.addLayer(era5_diff, { + palette: threeColorPalette, + min: -2, + max: 2 +}, 'Blue White Red palette'); + +Map.addLayer(era5_diff, { + palette: balancePalette, + min: -2, + max: 2 +}, 'Balance palette'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60a Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60a Checkpoint.py new file mode 100644 index 0000000..0e78088 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60a Checkpoint.py @@ -0,0 +1,52 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60a +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load the ERA5 reanalysis monthly means. +era5 = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY') + +# Load the palettes package. +palettes = require('users/gena/packages:palettes') + +# Select temperature near ground. +era5 = era5.select('temperature_2m') + +# Choose a diverging colormap for anomalies. +balancePalette = palettes.cmocean.Balance[7] +threeColorPalette = ['blue', 'white', 'red'] + +# Show the palette in the Inspector window. +palettes.showPalette('temperature anomaly', balancePalette) +palettes.showPalette('temperature anomaly', threeColorPalette) + +# Select 2 time windows of 10 years. +era5_1980 = era5.filterDate('1981-01-01', '1991-01-01').mean() +era5_2010 = era5.filterDate('2011-01-01', '2020-01-01').mean() + +# Compute the temperature change. +era5_diff = era5_2010.subtract(era5_1980) + +# Show it on the map. +Map.addLayer(era5_diff, { + 'palette': threeColorPalette, + 'min': -2, + 'max': 2 +}, 'Blue White Red palette') + +Map.addLayer(era5_diff, { + 'palette': balancePalette, + 'min': -2, + 'max': 2 +}, 'Balance palette') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60b Checkpoint.ipynb new file mode 100644 index 0000000..63cb13b --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60b Checkpoint.ipynb @@ -0,0 +1,130 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60b\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# An image of the Thwaites glacier.\n", + "imageId =\n", + " 'COPERNICUS/S1_GRD/S1B_EW_GRDM_1SSH_20211216T041925_20211216T042029_030045_03965B_AF0A'\n", + "\n", + "# Look it up and select the HH band.\n", + "img = ee.Image(imageId).select('HH')\n", + "\n", + "# Use the palette library.\n", + "palettes = require('users/gena/packages:palettes')\n", + "\n", + "# Access the ice palette.\n", + "icePalette = palettes.cmocean.Ice[7]\n", + "\n", + "# Show it in the console.\n", + "palettes.showPalette('Ice', icePalette)\n", + "\n", + "# Use it to visualize the radar data.\n", + "Map.addLayer(img, {\n", + " 'palette': icePalette,\n", + " 'min': -15,\n", + " 'max': 1\n", + "}, 'Sentinel-1 radar')\n", + "\n", + "# Zoom to the grounding line of the Thwaites Glacier.\n", + "Map.centerObject(ee.Geometry.Point([-105.45882094907664, -\n", + " 74.90419580705336\n", + "]), 8)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60b Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60b Checkpoint.js new file mode 100644 index 0000000..c24a485 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60b Checkpoint.js @@ -0,0 +1,37 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60b +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// An image of the Thwaites glacier. +var imageId = + 'COPERNICUS/S1_GRD/S1B_EW_GRDM_1SSH_20211216T041925_20211216T042029_030045_03965B_AF0A'; + +// Look it up and select the HH band. +var img = ee.Image(imageId).select('HH'); + +// Use the palette library. +var palettes = require('users/gena/packages:palettes'); + +// Access the ice palette. +var icePalette = palettes.cmocean.Ice[7]; + +// Show it in the console. +palettes.showPalette('Ice', icePalette); + +// Use it to visualize the radar data. +Map.addLayer(img, { + palette: icePalette, + min: -15, + max: 1 +}, 'Sentinel-1 radar'); + +// Zoom to the grounding line of the Thwaites Glacier. +Map.centerObject(ee.Geometry.Point([-105.45882094907664, - + 74.90419580705336 +]), 8); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60b Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60b Checkpoint.py new file mode 100644 index 0000000..15aba2a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60b Checkpoint.py @@ -0,0 +1,43 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60b +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# An image of the Thwaites glacier. +imageId = + 'COPERNICUS/S1_GRD/S1B_EW_GRDM_1SSH_20211216T041925_20211216T042029_030045_03965B_AF0A' + +# Look it up and select the HH band. +img = ee.Image(imageId).select('HH') + +# Use the palette library. +palettes = require('users/gena/packages:palettes') + +# Access the ice palette. +icePalette = palettes.cmocean.Ice[7] + +# Show it in the console. +palettes.showPalette('Ice', icePalette) + +# Use it to visualize the radar data. +Map.addLayer(img, { + 'palette': icePalette, + 'min': -15, + 'max': 1 +}, 'Sentinel-1 radar') + +# Zoom to the grounding line of the Thwaites Glacier. +Map.centerObject(ee.Geometry.Point([-105.45882094907664, - + 74.90419580705336 +]), 8) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60c Checkpoint.ipynb new file mode 100644 index 0000000..bad13af --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60c Checkpoint.ipynb @@ -0,0 +1,156 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60c\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Advanced remapping using NLCD.\n", + "# Import NLCD.\n", + "nlcd = ee.ImageCollection('USGS/NLCD_RELEASES/2016_REL')\n", + "\n", + "# Use Filter to select the 2016 dataset.\n", + "nlcd2016 = nlcd.filter(ee.Filter.eq('system:index', '2016')) \\\n", + " .first()\n", + "\n", + "# Select the land cover band.\n", + "landcover = nlcd2016.select('landcover')\n", + "\n", + "# Map the NLCD land cover.\n", + "Map.addLayer(landcover, None, 'NLCD Landcover')\n", + "\n", + "\n", + "# Now suppose we want to change the color palette.\n", + "newPalette = ['466b9f', 'd1def8', 'dec5c5',\n", + " 'ab0000', 'ab0000', 'ab0000',\n", + " 'b3ac9f', '68ab5f', '1c5f2c',\n", + " 'b5c58f', 'af963c', 'ccb879',\n", + " 'dfdfc2', 'd1d182', 'a3cc51',\n", + " '82ba9e', 'dcd939', 'ab6c28',\n", + " 'b8d9eb', '6c9fb8'\n", + "]\n", + "\n", + "# Try mapping with the new color palette.\n", + "Map.addLayer(landcover, {\n", + " 'palette': newPalette\n", + "}, 'NLCD New Palette')\n", + "\n", + "# Extract the class values and save them as a list.\n", + "values = ee.List(landcover.get('landcover_class_values'))\n", + "\n", + "# Print the class values to console.\n", + "print('raw class values', values)\n", + "\n", + "# Determine the maximum index value\n", + "maxIndex = values.size().subtract(1)\n", + "\n", + "# Create a new index for the remap\n", + "indexes = ee.List.sequence(0, maxIndex)\n", + "\n", + "# Print the updated class values to console.\n", + "print('updated class values', indexes)\n", + "\n", + "# Remap NLCD and display it in the map.\n", + "colorized = landcover.remap(values, indexes) \\\n", + " .visualize(**{\n", + " 'min': 0,\n", + " 'max': maxIndex,\n", + " 'palette': newPalette\n", + " })\n", + "Map.addLayer(colorized, {}, 'NLCD Remapped Colors')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60c Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60c Checkpoint.js new file mode 100644 index 0000000..f5744c3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60c Checkpoint.js @@ -0,0 +1,63 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60c +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Advanced remapping using NLCD. +// Import NLCD. +var nlcd = ee.ImageCollection('USGS/NLCD_RELEASES/2016_REL'); + +// Use Filter to select the 2016 dataset. +var nlcd2016 = nlcd.filter(ee.Filter.eq('system:index', '2016')) + .first(); + +// Select the land cover band. +var landcover = nlcd2016.select('landcover'); + +// Map the NLCD land cover. +Map.addLayer(landcover, null, 'NLCD Landcover'); + + +// Now suppose we want to change the color palette. +var newPalette = ['466b9f', 'd1def8', 'dec5c5', + 'ab0000', 'ab0000', 'ab0000', + 'b3ac9f', '68ab5f', '1c5f2c', + 'b5c58f', 'af963c', 'ccb879', + 'dfdfc2', 'd1d182', 'a3cc51', + '82ba9e', 'dcd939', 'ab6c28', + 'b8d9eb', '6c9fb8' +]; + +// Try mapping with the new color palette. +Map.addLayer(landcover, { + palette: newPalette +}, 'NLCD New Palette'); + +// Extract the class values and save them as a list. +var values = ee.List(landcover.get('landcover_class_values')); + +// Print the class values to console. +print('raw class values', values); + +// Determine the maximum index value +var maxIndex = values.size().subtract(1); + +// Create a new index for the remap +var indexes = ee.List.sequence(0, maxIndex); + +// Print the updated class values to console. +print('updated class values', indexes); + +// Remap NLCD and display it in the map. +var colorized = landcover.remap(values, indexes) + .visualize({ + min: 0, + max: maxIndex, + palette: newPalette + }); +Map.addLayer(colorized, {}, 'NLCD Remapped Colors'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60c Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60c Checkpoint.py new file mode 100644 index 0000000..44850b4 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60c Checkpoint.py @@ -0,0 +1,69 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60c +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Advanced remapping using NLCD. +# Import NLCD. +nlcd = ee.ImageCollection('USGS/NLCD_RELEASES/2016_REL') + +# Use Filter to select the 2016 dataset. +nlcd2016 = nlcd.filter(ee.Filter.eq('system:index', '2016')) \ + .first() + +# Select the land cover band. +landcover = nlcd2016.select('landcover') + +# Map the NLCD land cover. +Map.addLayer(landcover, None, 'NLCD Landcover') + + +# Now suppose we want to change the color palette. +newPalette = ['466b9f', 'd1def8', 'dec5c5', + 'ab0000', 'ab0000', 'ab0000', + 'b3ac9f', '68ab5f', '1c5f2c', + 'b5c58f', 'af963c', 'ccb879', + 'dfdfc2', 'd1d182', 'a3cc51', + '82ba9e', 'dcd939', 'ab6c28', + 'b8d9eb', '6c9fb8' +] + +# Try mapping with the new color palette. +Map.addLayer(landcover, { + 'palette': newPalette +}, 'NLCD New Palette') + +# Extract the class values and save them as a list. +values = ee.List(landcover.get('landcover_class_values')) + +# Print the class values to console. +print('raw class values', values) + +# Determine the maximum index value +maxIndex = values.size().subtract(1) + +# Create a new index for the remap +indexes = ee.List.sequence(0, maxIndex) + +# Print the updated class values to console. +print('updated class values', indexes) + +# Remap NLCD and display it in the map. +colorized = landcover.remap(values, indexes) \ + .visualize(**{ + 'min': 0, + 'max': maxIndex, + 'palette': newPalette + }) +Map.addLayer(colorized, {}, 'NLCD Remapped Colors') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60d Checkpoint.ipynb new file mode 100644 index 0000000..0dd6bba --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60d Checkpoint.ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60d\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#*\n", + " # Draws a string as a raster image at a given point.\n", + " #\n", + " # @param {string} str - string to draw\n", + " # @param {ee.Geometry} point - location the the string will be drawn\n", + " # @param {{string, Object}} options - optional properties used to style text\n", + " #\n", + " # The options dictionary may include one or more of the following:\n", + " # fontSize - 16|18|24|32 - the size of the font (default: 16)\n", + " # fontType - Arial|Consolas - the type of the font (default: Arial)\n", + " # alignX - left|center|right (default: left)\n", + " # alignY - top|center|bottom (default: top)\n", + " # textColor - text color string (default: ffffff - white)\n", + " # textOpacity - 0-1, opacity of the text (default: 0.9)\n", + " # textWidth - width of the text (default: 1)\n", + " # outlineColor - text outline color string (default: 000000 - black)\n", + " # outlineOpacity - 0-1, opacity of the text outline (default: 0.4)\n", + " # outlineWidth - width of the text outlines (default: 0)\n", + " #\n", + "\n", + "# Include the text package.\n", + "text = require('users/gena/packages:text')\n", + "\n", + "# Configure map (change center and map type).\n", + "Map.setCenter(0, 0, 10)\n", + "Map.setOptions('HYBRID')\n", + "\n", + "# Draw text string and add to map.\n", + "pt = Map.getCenter()\n", + "scale = Map.getScale()\n", + "image = text.draw('Hello World!', pt, scale)\n", + "Map.addLayer(image)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60d Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60d Checkpoint.js new file mode 100644 index 0000000..5452bab --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60d Checkpoint.js @@ -0,0 +1,42 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60d +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +/** + * Draws a string as a raster image at a given point. + * + * @param {string} str - string to draw + * @param {ee.Geometry} point - location the the string will be drawn + * @param {{string, Object}} options - optional properties used to style text + * + * The options dictionary may include one or more of the following: + * fontSize - 16|18|24|32 - the size of the font (default: 16) + * fontType - Arial|Consolas - the type of the font (default: Arial) + * alignX - left|center|right (default: left) + * alignY - top|center|bottom (default: top) + * textColor - text color string (default: ffffff - white) + * textOpacity - 0-1, opacity of the text (default: 0.9) + * textWidth - width of the text (default: 1) + * outlineColor - text outline color string (default: 000000 - black) + * outlineOpacity - 0-1, opacity of the text outline (default: 0.4) + * outlineWidth - width of the text outlines (default: 0) + */ + +// Include the text package. +var text = require('users/gena/packages:text'); + +// Configure map (change center and map type). +Map.setCenter(0, 0, 10); +Map.setOptions('HYBRID'); + +// Draw text string and add to map. +var pt = Map.getCenter(); +var scale = Map.getScale(); +var image = text.draw('Hello World!', pt, scale); +Map.addLayer(image); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60d Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60d Checkpoint.py new file mode 100644 index 0000000..de0e0e2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60d Checkpoint.py @@ -0,0 +1,48 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60d +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#* + # Draws a string as a raster image at a given point. + # + # @param {string} str - string to draw + # @param {ee.Geometry} point - location the the string will be drawn + # @param {{string, Object}} options - optional properties used to style text + # + # The options dictionary may include one or more of the following: + # fontSize - 16|18|24|32 - the size of the font (default: 16) + # fontType - Arial|Consolas - the type of the font (default: Arial) + # alignX - left|center|right (default: left) + # alignY - top|center|bottom (default: top) + # textColor - text color string (default: ffffff - white) + # textOpacity - 0-1, opacity of the text (default: 0.9) + # textWidth - width of the text (default: 1) + # outlineColor - text outline color string (default: 000000 - black) + # outlineOpacity - 0-1, opacity of the text outline (default: 0.4) + # outlineWidth - width of the text outlines (default: 0) + # + +# Include the text package. +text = require('users/gena/packages:text') + +# Configure map (change center and map type). +Map.setCenter(0, 0, 10) +Map.setOptions('HYBRID') + +# Draw text string and add to map. +pt = Map.getCenter() +scale = Map.getScale() +image = text.draw('Hello World!', pt, scale) +Map.addLayer(image) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60e Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60e Checkpoint.ipynb new file mode 100644 index 0000000..bc382da --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60e Checkpoint.ipynb @@ -0,0 +1,150 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60e\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "#*\n", + " # Draws a string as a raster image at a given point.\n", + " #\n", + " # @param {string} str - string to draw\n", + " # @param {ee.Geometry} point - location the the string will be drawn\n", + " # @param {{string, Object}} options - optional properties used to style text\n", + " #\n", + " # The options dictionary may include one or more of the following:\n", + " # fontSize - 16|18|24|32 - the size of the font (default: 16)\n", + " # fontType - Arial|Consolas - the type of the font (default: Arial)\n", + " # alignX - left|center|right (default: left)\n", + " # alignY - top|center|bottom (default: top)\n", + " # textColor - text color string (default: ffffff - white)\n", + " # textOpacity - 0-1, opacity of the text (default: 0.9)\n", + " # textWidth - width of the text (default: 1)\n", + " # outlineColor - text outline color string (default: 000000 - black)\n", + " # outlineOpacity - 0-1, opacity of the text outline (default: 0.4)\n", + " # outlineWidth - width of the text outlines (default: 0)\n", + " #\n", + "\n", + "# Include the text package.\n", + "text = require('users/gena/packages:text')\n", + "\n", + "# Configure map (change center and map type).\n", + "Map.setCenter(0, 0, 10)\n", + "Map.setOptions('HYBRID')\n", + "\n", + "# Draw text string and add to map.\n", + "pt = Map.getCenter()\n", + "scale = Map.getScale()\n", + "image = text.draw('Hello World!', pt, scale)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "image = text.draw('Hello World!', pt, scale, {\n", + " 'fontSize': 32,\n", + " 'fontType': 'Consolas',\n", + " 'textColor': 'black',\n", + " 'outlineColor': 'white',\n", + " 'outlineWidth': 1,\n", + " 'outlineOpacity': 0.8\n", + "})\n", + "\n", + "# Add the text image to the map.\n", + "Map.addLayer(image)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60e Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60e Checkpoint.js new file mode 100644 index 0000000..eac26dc --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60e Checkpoint.js @@ -0,0 +1,57 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60e +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +/** + * Draws a string as a raster image at a given point. + * + * @param {string} str - string to draw + * @param {ee.Geometry} point - location the the string will be drawn + * @param {{string, Object}} options - optional properties used to style text + * + * The options dictionary may include one or more of the following: + * fontSize - 16|18|24|32 - the size of the font (default: 16) + * fontType - Arial|Consolas - the type of the font (default: Arial) + * alignX - left|center|right (default: left) + * alignY - top|center|bottom (default: top) + * textColor - text color string (default: ffffff - white) + * textOpacity - 0-1, opacity of the text (default: 0.9) + * textWidth - width of the text (default: 1) + * outlineColor - text outline color string (default: 000000 - black) + * outlineOpacity - 0-1, opacity of the text outline (default: 0.4) + * outlineWidth - width of the text outlines (default: 0) + */ + +// Include the text package. +var text = require('users/gena/packages:text'); + +// Configure map (change center and map type). +Map.setCenter(0, 0, 10); +Map.setOptions('HYBRID'); + +// Draw text string and add to map. +var pt = Map.getCenter(); +var scale = Map.getScale(); +var image = text.draw('Hello World!', pt, scale); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +var image = text.draw('Hello World!', pt, scale, { + fontSize: 32, + fontType: 'Consolas', + textColor: 'black', + outlineColor: 'white', + outlineWidth: 1, + outlineOpacity: 0.8 +}); + +// Add the text image to the map. +Map.addLayer(image); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60e Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60e Checkpoint.py new file mode 100644 index 0000000..4c77757 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60e Checkpoint.py @@ -0,0 +1,63 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60e +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#* + # Draws a string as a raster image at a given point. + # + # @param {string} str - string to draw + # @param {ee.Geometry} point - location the the string will be drawn + # @param {{string, Object}} options - optional properties used to style text + # + # The options dictionary may include one or more of the following: + # fontSize - 16|18|24|32 - the size of the font (default: 16) + # fontType - Arial|Consolas - the type of the font (default: Arial) + # alignX - left|center|right (default: left) + # alignY - top|center|bottom (default: top) + # textColor - text color string (default: ffffff - white) + # textOpacity - 0-1, opacity of the text (default: 0.9) + # textWidth - width of the text (default: 1) + # outlineColor - text outline color string (default: 000000 - black) + # outlineOpacity - 0-1, opacity of the text outline (default: 0.4) + # outlineWidth - width of the text outlines (default: 0) + # + +# Include the text package. +text = require('users/gena/packages:text') + +# Configure map (change center and map type). +Map.setCenter(0, 0, 10) +Map.setOptions('HYBRID') + +# Draw text string and add to map. +pt = Map.getCenter() +scale = Map.getScale() +image = text.draw('Hello World!', pt, scale) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +image = text.draw('Hello World!', pt, scale, { + 'fontSize': 32, + 'fontType': 'Consolas', + 'textColor': 'black', + 'outlineColor': 'white', + 'outlineWidth': 1, + 'outlineOpacity': 0.8 +}) + +# Add the text image to the map. +Map.addLayer(image) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60f Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60f Checkpoint.ipynb new file mode 100644 index 0000000..9101ba0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60f Checkpoint.ipynb @@ -0,0 +1,177 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60f\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "text = require('users/gena/packages:text')\n", + "\n", + "geometry = ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-109.248, 43.3913],\n", + " [-109.248, 33.2689],\n", + " [-86.5283, 33.2689],\n", + " [-86.5283, 43.3913]\n", + " ]\n", + " ], None, False)\n", + "\n", + "Map.centerObject(geometry, 6)\n", + "\n", + "def annotate(image):\n", + " # Annotates an image by adding outline border and cloudiness\n", + " # Cloudiness is shown as a text string rendered at the image center.\n", + "\n", + " # Add an edge around the image.\n", + " edge = ee.FeatureCollection([image]) \\\n", + " .style(**{\n", + " 'color': 'cccc00cc',\n", + " 'fillColor': '00000000'\n", + " })\n", + "\n", + " # Draw cloudiness as text.\n", + " props = {\n", + " 'textColor': '0000aa',\n", + " 'outlineColor': 'ffffff',\n", + " 'outlineWidth': 2,\n", + " 'outlineOpacity': 0.6,\n", + " 'fontSize': 24,\n", + " 'fontType': 'Consolas'\n", + " }\n", + " center = image.geometry().centroid(1)\n", + " str = ee.Number(image.get('CLOUD_COVER')).format('%.2f')\n", + " scale = Map.getScale()\n", + " textCloudiness = text.draw(str, center, scale, props)\n", + "\n", + " # Shift left 25 pixels.\n", + " textCloudiness = textCloudiness \\\n", + " .translate(-scale * 25, 0, 'meters', 'EPSG:3857')\n", + "\n", + " # Merge results.\n", + " return ee.ImageCollection([edge, textCloudiness]).mosaic()\n", + "\n", + "\n", + "# Select images.\n", + "images = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT_TOA') \\\n", + " .select([5, 4, 2]) \\\n", + " .filterBounds(geometry) \\\n", + " .filterDate('2018-01-01', '2018-01-7')\n", + "\n", + "# dim background.\n", + "Map.addLayer(ee.Image(1), {\n", + " 'palette': ['black']\n", + "}, 'black', True, 0.5)\n", + "\n", + "# Show images.\n", + "Map.addLayer(images, {\n", + " 'min': 0.05,\n", + " 'max': 1,\n", + " 'gamma': 1.4\n", + "}, 'images')\n", + "\n", + "# Show annotations.\n", + "labels = images.map(annotate)\n", + "labelsLayer = ui.Map.Layer(labels, {}, 'annotations')\n", + "Map.layers().add(labelsLayer)\n", + "\n", + "# re-render (rescale) annotations when map zoom changes.\n", + "Map.onChangeZoom(function(zoom) {\n", + " labelsLayer.setEeObject(images.map(annotate))\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60f Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60f Checkpoint.js new file mode 100644 index 0000000..991b4b2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60f Checkpoint.js @@ -0,0 +1,84 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60f +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var text = require('users/gena/packages:text'); + +var geometry = ee.Geometry.Polygon( + [ + [ + [-109.248, 43.3913], + [-109.248, 33.2689], + [-86.5283, 33.2689], + [-86.5283, 43.3913] + ] + ], null, false); + +Map.centerObject(geometry, 6); + +function annotate(image) { + // Annotates an image by adding outline border and cloudiness + // Cloudiness is shown as a text string rendered at the image center. + + // Add an edge around the image. + var edge = ee.FeatureCollection([image]) + .style({ + color: 'cccc00cc', + fillColor: '00000000' + }); + + // Draw cloudiness as text. + var props = { + textColor: '0000aa', + outlineColor: 'ffffff', + outlineWidth: 2, + outlineOpacity: 0.6, + fontSize: 24, + fontType: 'Consolas' + }; + var center = image.geometry().centroid(1); + var str = ee.Number(image.get('CLOUD_COVER')).format('%.2f'); + var scale = Map.getScale(); + var textCloudiness = text.draw(str, center, scale, props); + + // Shift left 25 pixels. + textCloudiness = textCloudiness + .translate(-scale * 25, 0, 'meters', 'EPSG:3857'); + + // Merge results. + return ee.ImageCollection([edge, textCloudiness]).mosaic(); +} + +// Select images. +var images = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT_TOA') + .select([5, 4, 2]) + .filterBounds(geometry) + .filterDate('2018-01-01', '2018-01-7'); + +// dim background. +Map.addLayer(ee.Image(1), { + palette: ['black'] +}, 'black', true, 0.5); + +// Show images. +Map.addLayer(images, { + min: 0.05, + max: 1, + gamma: 1.4 +}, 'images'); + +// Show annotations. +var labels = images.map(annotate); +var labelsLayer = ui.Map.Layer(labels, {}, 'annotations'); +Map.layers().add(labelsLayer); + +// re-render (rescale) annotations when map zoom changes. +Map.onChangeZoom(function(zoom) { + labelsLayer.setEeObject(images.map(annotate)); +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60f Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60f Checkpoint.py new file mode 100644 index 0000000..bbf10ac --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60f Checkpoint.py @@ -0,0 +1,90 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60f +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +text = require('users/gena/packages:text') + +geometry = ee.Geometry.Polygon( + [ + [ + [-109.248, 43.3913], + [-109.248, 33.2689], + [-86.5283, 33.2689], + [-86.5283, 43.3913] + ] + ], None, False) + +Map.centerObject(geometry, 6) + +def annotate(image): + # Annotates an image by adding outline border and cloudiness + # Cloudiness is shown as a text string rendered at the image center. + + # Add an edge around the image. + edge = ee.FeatureCollection([image]) \ + .style(**{ + 'color': 'cccc00cc', + 'fillColor': '00000000' + }) + + # Draw cloudiness as text. + props = { + 'textColor': '0000aa', + 'outlineColor': 'ffffff', + 'outlineWidth': 2, + 'outlineOpacity': 0.6, + 'fontSize': 24, + 'fontType': 'Consolas' + } + center = image.geometry().centroid(1) + str = ee.Number(image.get('CLOUD_COVER')).format('%.2f') + scale = Map.getScale() + textCloudiness = text.draw(str, center, scale, props) + + # Shift left 25 pixels. + textCloudiness = textCloudiness \ + .translate(-scale * 25, 0, 'meters', 'EPSG:3857') + + # Merge results. + return ee.ImageCollection([edge, textCloudiness]).mosaic() + + +# Select images. +images = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT_TOA') \ + .select([5, 4, 2]) \ + .filterBounds(geometry) \ + .filterDate('2018-01-01', '2018-01-7') + +# dim background. +Map.addLayer(ee.Image(1), { + 'palette': ['black'] +}, 'black', True, 0.5) + +# Show images. +Map.addLayer(images, { + 'min': 0.05, + 'max': 1, + 'gamma': 1.4 +}, 'images') + +# Show annotations. +labels = images.map(annotate) +labelsLayer = ui.Map.Layer(labels, {}, 'annotations') +Map.layers().add(labelsLayer) + +# re-render (rescale) annotations when map zoom changes. +Map.onChangeZoom(function(zoom) { + labelsLayer.setEeObject(images.map(annotate)) +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60g Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60g Checkpoint.ipynb new file mode 100644 index 0000000..388f680 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60g Checkpoint.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometry = ee.Geometry.MultiPoint()\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60g\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Include packages.\n", + "palettes = require('users/gena/packages:palettes')\n", + "text = require('users/gena/packages:text')\n", + "\n", + "point = ee.Geometry.Point([-\n", + " 106.15944300895228, -74.58262940096245\n", + "])\n", + "\n", + "rect =\n", + " ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-106.19789515738981, -74.56509549360152],\n", + " [-106.19789515738981, -74.78071448733921],\n", + " [-104.98115931754606, -74.78071448733921],\n", + " [-104.98115931754606, -74.56509549360152]\n", + " ]\n", + " ], None, False)\n", + "\n", + "# Lookup the ice palette.\n", + "palette = palettes.cmocean.Ice[7]\n", + "\n", + "# Show it in the console.\n", + "palettes.showPalette('Ice', palette)\n", + "\n", + "# Center map on geometry.\n", + "Map.centerObject(point, 9)\n", + "\n", + "# Select S1 images for the Thwaites glacier.\n", + "images = ee.ImageCollection('COPERNICUS/S1_GRD') \\\n", + " .filterBounds(rect) \\\n", + " .filterDate('2021-01-01', '2021-03-01') \\\n", + " .select('HH') \\\n", + " .filter(ee.Filter.isContained({\n", + " 'leftValue': rect,\n", + " 'rightField': '.geo'\n", + " })) \\\n", + " .sort('system:time_start')\n", + "\n", + "# Print number of images.\n", + "print(images.size())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60g Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60g Checkpoint.js new file mode 100644 index 0000000..ed4a80a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60g Checkpoint.js @@ -0,0 +1,55 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometry = /* color: #d63000 */ee.Geometry.MultiPoint(); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60g +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Include packages. +var palettes = require('users/gena/packages:palettes'); +var text = require('users/gena/packages:text'); + +var point = /* color: #98ff00 */ ee.Geometry.Point([- + 106.15944300895228, -74.58262940096245 +]); + +var rect = /* color: #d63000 */ + ee.Geometry.Polygon( + [ + [ + [-106.19789515738981, -74.56509549360152], + [-106.19789515738981, -74.78071448733921], + [-104.98115931754606, -74.78071448733921], + [-104.98115931754606, -74.56509549360152] + ] + ], null, false); + +// Lookup the ice palette. +var palette = palettes.cmocean.Ice[7]; + +// Show it in the console. +palettes.showPalette('Ice', palette); + +// Center map on geometry. +Map.centerObject(point, 9); + +// Select S1 images for the Thwaites glacier. +var images = ee.ImageCollection('COPERNICUS/S1_GRD') + .filterBounds(rect) + .filterDate('2021-01-01', '2021-03-01') + .select('HH') + // Make sure we include only images which fully contain the region geometry. + .filter(ee.Filter.isContained({ + leftValue: rect, + rightField: '.geo' + })) + .sort('system:time_start'); + +// Print number of images. +print(images.size()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60g Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60g Checkpoint.py new file mode 100644 index 0000000..d029d63 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60g Checkpoint.py @@ -0,0 +1,60 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometry = ee.Geometry.MultiPoint() +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60g +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include packages. +palettes = require('users/gena/packages:palettes') +text = require('users/gena/packages:text') + +point = ee.Geometry.Point([- + 106.15944300895228, -74.58262940096245 +]) + +rect = + ee.Geometry.Polygon( + [ + [ + [-106.19789515738981, -74.56509549360152], + [-106.19789515738981, -74.78071448733921], + [-104.98115931754606, -74.78071448733921], + [-104.98115931754606, -74.56509549360152] + ] + ], None, False) + +# Lookup the ice palette. +palette = palettes.cmocean.Ice[7] + +# Show it in the console. +palettes.showPalette('Ice', palette) + +# Center map on geometry. +Map.centerObject(point, 9) + +# Select S1 images for the Thwaites glacier. +images = ee.ImageCollection('COPERNICUS/S1_GRD') \ + .filterBounds(rect) \ + .filterDate('2021-01-01', '2021-03-01') \ + .select('HH') \ + .filter(ee.Filter.isContained({ + 'leftValue': rect, + 'rightField': '.geo' + })) \ + .sort('system:time_start') + +# Print number of images. +print(images.size()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60h Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60h Checkpoint.ipynb new file mode 100644 index 0000000..3f72f5d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60h Checkpoint.ipynb @@ -0,0 +1,194 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometry = ee.Geometry.MultiPoint()\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60h\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Include packages.\n", + "palettes = require('users/gena/packages:palettes')\n", + "text = require('users/gena/packages:text')\n", + "\n", + "point = ee.Geometry.Point([-\n", + " 106.15944300895228, -74.58262940096245\n", + "])\n", + "\n", + "rect =\n", + " ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-106.19789515738981, -74.56509549360152],\n", + " [-106.19789515738981, -74.78071448733921],\n", + " [-104.98115931754606, -74.78071448733921],\n", + " [-104.98115931754606, -74.56509549360152]\n", + " ]\n", + " ], None, False)\n", + "\n", + "# Lookup the ice palette.\n", + "palette = palettes.cmocean.Ice[7]\n", + "\n", + "# Show it in the console.\n", + "palettes.showPalette('Ice', palette)\n", + "\n", + "# Center map on geometry.\n", + "Map.centerObject(point, 9)\n", + "\n", + "# Select S1 images for the Thwaites glacier.\n", + "images = ee.ImageCollection('COPERNICUS/S1_GRD') \\\n", + " .filterBounds(rect) \\\n", + " .filterDate('2021-01-01', '2021-03-01') \\\n", + " .select('HH') \\\n", + " .filter(ee.Filter.isContained({\n", + " 'leftValue': rect,\n", + " 'rightField': '.geo'\n", + " })) \\\n", + " .sort('system:time_start')\n", + "\n", + "# Print number of images.\n", + "print(images.size())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Render images.\n", + "vis = {\n", + " 'palette': palette,\n", + " 'min': -15,\n", + " 'max': 1\n", + "}\n", + "\n", + "scale = Map.getScale()\n", + "textProperties = {\n", + " 'outlineColor': '000000',\n", + " 'outlineWidth': 3,\n", + " 'outlineOpacity': 0.6\n", + "}\n", + "\n", + "\n", + "def func_kbg(i):\n", + " # Use the date as the label.\n", + " label = i.date().format('YYYY-MM-dd')\n", + " labelImage = text.draw(label, point, scale,\n", + " textProperties)\n", + "\n", + " return i.visualize(vis) \\\n", + " .blend(labelImage) \\\n", + " .set({\n", + " 'label': label\n", + " }); # Keep the text property.\n", + "\n", + "imagesRgb = images.map(func_kbg)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Map.addLayer(imagesRgb.first())\n", + "Map.addLayer(rect, {'color':'blue'}, 'rect', 1, 0.5)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60h Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60h Checkpoint.js new file mode 100644 index 0000000..f125495 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60h Checkpoint.js @@ -0,0 +1,88 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometry = /* color: #d63000 */ee.Geometry.MultiPoint(); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60h +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Include packages. +var palettes = require('users/gena/packages:palettes'); +var text = require('users/gena/packages:text'); + +var point = /* color: #98ff00 */ ee.Geometry.Point([- + 106.15944300895228, -74.58262940096245 +]); + +var rect = /* color: #d63000 */ + ee.Geometry.Polygon( + [ + [ + [-106.19789515738981, -74.56509549360152], + [-106.19789515738981, -74.78071448733921], + [-104.98115931754606, -74.78071448733921], + [-104.98115931754606, -74.56509549360152] + ] + ], null, false); + +// Lookup the ice palette. +var palette = palettes.cmocean.Ice[7]; + +// Show it in the console. +palettes.showPalette('Ice', palette); + +// Center map on geometry. +Map.centerObject(point, 9); + +// Select S1 images for the Thwaites glacier. +var images = ee.ImageCollection('COPERNICUS/S1_GRD') + .filterBounds(rect) + .filterDate('2021-01-01', '2021-03-01') + .select('HH') + // Make sure we include only images which fully contain the region geometry. + .filter(ee.Filter.isContained({ + leftValue: rect, + rightField: '.geo' + })) + .sort('system:time_start'); + +// Print number of images. +print(images.size()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Render images. +var vis = { + palette: palette, + min: -15, + max: 1 +}; + +var scale = Map.getScale(); +var textProperties = { + outlineColor: '000000', + outlineWidth: 3, + outlineOpacity: 0.6 +}; + +var imagesRgb = images.map(function(i) { + // Use the date as the label. + var label = i.date().format('YYYY-MM-dd'); + var labelImage = text.draw(label, point, scale, + textProperties); + + return i.visualize(vis) + .blend(labelImage) // Blend label image on top. + .set({ + label: label + }); // Keep the text property. +}); +Map.addLayer(imagesRgb.first()); +Map.addLayer(rect, {color:'blue'}, 'rect', 1, 0.5); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60h Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60h Checkpoint.py new file mode 100644 index 0000000..cc5a97d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60h Checkpoint.py @@ -0,0 +1,107 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometry = ee.Geometry.MultiPoint() +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60h +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include packages. +palettes = require('users/gena/packages:palettes') +text = require('users/gena/packages:text') + +point = ee.Geometry.Point([- + 106.15944300895228, -74.58262940096245 +]) + +rect = + ee.Geometry.Polygon( + [ + [ + [-106.19789515738981, -74.56509549360152], + [-106.19789515738981, -74.78071448733921], + [-104.98115931754606, -74.78071448733921], + [-104.98115931754606, -74.56509549360152] + ] + ], None, False) + +# Lookup the ice palette. +palette = palettes.cmocean.Ice[7] + +# Show it in the console. +palettes.showPalette('Ice', palette) + +# Center map on geometry. +Map.centerObject(point, 9) + +# Select S1 images for the Thwaites glacier. +images = ee.ImageCollection('COPERNICUS/S1_GRD') \ + .filterBounds(rect) \ + .filterDate('2021-01-01', '2021-03-01') \ + .select('HH') \ + .filter(ee.Filter.isContained({ + 'leftValue': rect, + 'rightField': '.geo' + })) \ + .sort('system:time_start') + +# Print number of images. +print(images.size()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Render images. +vis = { + 'palette': palette, + 'min': -15, + 'max': 1 +} + +scale = Map.getScale() +textProperties = { + 'outlineColor': '000000', + 'outlineWidth': 3, + 'outlineOpacity': 0.6 +} + + +def func_kbg(i): + # Use the date as the label. + label = i.date().format('YYYY-MM-dd') + labelImage = text.draw(label, point, scale, + textProperties) + + return i.visualize(vis) \ + .blend(labelImage) \ + .set({ + 'label': label + }); # Keep the text property. + +imagesRgb = images.map(func_kbg) + + + + + + + + + + + + +Map.addLayer(imagesRgb.first()) +Map.addLayer(rect, {'color':'blue'}, 'rect', 1, 0.5) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60i Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60i Checkpoint.ipynb new file mode 100644 index 0000000..5cee27e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60i Checkpoint.ipynb @@ -0,0 +1,241 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometry = ee.Geometry.MultiPoint()\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60i\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Include packages.\n", + "palettes = require('users/gena/packages:palettes')\n", + "text = require('users/gena/packages:text')\n", + "\n", + "point = ee.Geometry.Point([-\n", + " 106.15944300895228, -74.58262940096245\n", + "])\n", + "\n", + "rect =\n", + " ee.Geometry.Polygon(\n", + " [\n", + " [\n", + " [-106.19789515738981, -74.56509549360152],\n", + " [-106.19789515738981, -74.78071448733921],\n", + " [-104.98115931754606, -74.78071448733921],\n", + " [-104.98115931754606, -74.56509549360152]\n", + " ]\n", + " ], None, False)\n", + "\n", + "# Lookup the ice palette.\n", + "palette = palettes.cmocean.Ice[7]\n", + "\n", + "# Show it in the console.\n", + "palettes.showPalette('Ice', palette)\n", + "\n", + "# Center map on geometry.\n", + "Map.centerObject(point, 9)\n", + "\n", + "# Select S1 images for the Thwaites glacier.\n", + "images = ee.ImageCollection('COPERNICUS/S1_GRD') \\\n", + " .filterBounds(rect) \\\n", + " .filterDate('2021-01-01', '2021-03-01') \\\n", + " .select('HH') \\\n", + " .filter(ee.Filter.isContained({\n", + " 'leftValue': rect,\n", + " 'rightField': '.geo'\n", + " })) \\\n", + " .sort('system:time_start')\n", + "\n", + "# Print number of images.\n", + "print(images.size())\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# Render images.\n", + "vis = {\n", + " 'palette': palette,\n", + " 'min': -15,\n", + " 'max': 1\n", + "}\n", + "\n", + "scale = Map.getScale()\n", + "textProperties = {\n", + " 'outlineColor': '000000',\n", + " 'outlineWidth': 3,\n", + " 'outlineOpacity': 0.6\n", + "}\n", + "\n", + "\n", + "def func_bss(i):\n", + " # Use the date as the label.\n", + " label = i.date().format('YYYY-MM-dd')\n", + " labelImage = text.draw(label, point, scale,\n", + " textProperties)\n", + "\n", + " return i.visualize(vis) \\\n", + " .blend(labelImage) \\\n", + " .set({\n", + " 'label': label\n", + " }); # Keep the text property.\n", + "\n", + "imagesRgb = images.map(func_bss)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Map.addLayer(imagesRgb.first())\n", + "Map.addLayer(rect, {'color':'blue'}, 'rect', 1, 0.5)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "# ==================================\n", + "# 1. Animate as a GIF\n", + "\n", + "# Define GIF visualization parameters.\n", + "gifParams = {\n", + " 'region': rect,\n", + " 'dimensions': 600,\n", + " 'crs': 'EPSG:3857',\n", + " 'framesPerSecond': 10\n", + "}\n", + "\n", + "# Print the GIF URL to the console.\n", + "print(imagesRgb.getVideoThumbURL(gifParams))\n", + "\n", + "# Render the GIF animation in the console.\n", + "print(ui.Thumbnail(imagesRgb, gifParams))\n", + "\n", + "# ==================================\n", + "# 2. Export animation as a video file to Google Drive.\n", + "\n", + "Export.video.toDrive({\n", + " 'collection': imagesRgb,\n", + " 'description': 'ice-animation',\n", + " 'fileNamePrefix': 'ice-animation',\n", + " 'framesPerSecond': 10,\n", + " 'dimensions': 600,\n", + " 'region': rect,\n", + " 'crs': 'EPSG:3857'\n", + "})\n", + "\n", + "# ==================================\n", + "# 3. Animate multiple images as map layers,\n", + "# Use image date as labels (layer names).\n", + "\n", + "# include the animation package\n", + "animation = require('users/gena/packages:animation')\n", + "\n", + "# show animation controls\n", + "animation.animate(imagesRgb, {\n", + " 'label': 'label',\n", + " 'maxFrames': 50\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60i Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60i Checkpoint.js new file mode 100644 index 0000000..bcd54e5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60i Checkpoint.js @@ -0,0 +1,135 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometry = /* color: #d63000 */ee.Geometry.MultiPoint(); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60i +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Include packages. +var palettes = require('users/gena/packages:palettes'); +var text = require('users/gena/packages:text'); + +var point = /* color: #98ff00 */ ee.Geometry.Point([- + 106.15944300895228, -74.58262940096245 +]) + +var rect = /* color: #d63000 */ + ee.Geometry.Polygon( + [ + [ + [-106.19789515738981, -74.56509549360152], + [-106.19789515738981, -74.78071448733921], + [-104.98115931754606, -74.78071448733921], + [-104.98115931754606, -74.56509549360152] + ] + ], null, false); + +// Lookup the ice palette. +var palette = palettes.cmocean.Ice[7]; + +// Show it in the console. +palettes.showPalette('Ice', palette); + +// Center map on geometry. +Map.centerObject(point, 9); + +// Select S1 images for the Thwaites glacier. +var images = ee.ImageCollection('COPERNICUS/S1_GRD') + .filterBounds(rect) + .filterDate('2021-01-01', '2021-03-01') + .select('HH') + // Make sure we include only images which fully contain the region geometry. + .filter(ee.Filter.isContained({ + leftValue: rect, + rightField: '.geo' + })) + .sort('system:time_start'); + +// Print number of images. +print(images.size()); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// Render images. +var vis = { + palette: palette, + min: -15, + max: 1 +}; + +var scale = Map.getScale(); +var textProperties = { + outlineColor: '000000', + outlineWidth: 3, + outlineOpacity: 0.6 +}; + +var imagesRgb = images.map(function(i) { + // Use the date as the label. + var label = i.date().format('YYYY-MM-dd'); + var labelImage = text.draw(label, point, scale, + textProperties); + + return i.visualize(vis) + .blend(labelImage) // Blend label image on top. + .set({ + label: label + }); // Keep the text property. +}); +Map.addLayer(imagesRgb.first()); +Map.addLayer(rect, {color:'blue'}, 'rect', 1, 0.5); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + +// ================================== +// 1. Animate as a GIF + +// Define GIF visualization parameters. +var gifParams = { + region: rect, + dimensions: 600, + crs: 'EPSG:3857', + framesPerSecond: 10 +}; + +// Print the GIF URL to the console. +print(imagesRgb.getVideoThumbURL(gifParams)); + +// Render the GIF animation in the console. +print(ui.Thumbnail(imagesRgb, gifParams)); + +// ================================== +// 2. Export animation as a video file to Google Drive. + +Export.video.toDrive({ + collection: imagesRgb, + description: 'ice-animation', + fileNamePrefix: 'ice-animation', + framesPerSecond: 10, + dimensions: 600, + region: rect, + crs: 'EPSG:3857' +}); + +// ================================== +// 3. Animate multiple images as map layers, +// Use image date as labels (layer names). + +// include the animation package +var animation = require('users/gena/packages:animation'); + +// show animation controls +animation.animate(imagesRgb, { + label: 'label', + maxFrames: 50 +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60i Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60i Checkpoint.py new file mode 100644 index 0000000..3250027 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60i Checkpoint.py @@ -0,0 +1,154 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometry = ee.Geometry.MultiPoint() +#**** End of imports. If edited, may not auto-convert in the playground. ****# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60i +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include packages. +palettes = require('users/gena/packages:palettes') +text = require('users/gena/packages:text') + +point = ee.Geometry.Point([- + 106.15944300895228, -74.58262940096245 +]) + +rect = + ee.Geometry.Polygon( + [ + [ + [-106.19789515738981, -74.56509549360152], + [-106.19789515738981, -74.78071448733921], + [-104.98115931754606, -74.78071448733921], + [-104.98115931754606, -74.56509549360152] + ] + ], None, False) + +# Lookup the ice palette. +palette = palettes.cmocean.Ice[7] + +# Show it in the console. +palettes.showPalette('Ice', palette) + +# Center map on geometry. +Map.centerObject(point, 9) + +# Select S1 images for the Thwaites glacier. +images = ee.ImageCollection('COPERNICUS/S1_GRD') \ + .filterBounds(rect) \ + .filterDate('2021-01-01', '2021-03-01') \ + .select('HH') \ + .filter(ee.Filter.isContained({ + 'leftValue': rect, + 'rightField': '.geo' + })) \ + .sort('system:time_start') + +# Print number of images. +print(images.size()) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# Render images. +vis = { + 'palette': palette, + 'min': -15, + 'max': 1 +} + +scale = Map.getScale() +textProperties = { + 'outlineColor': '000000', + 'outlineWidth': 3, + 'outlineOpacity': 0.6 +} + + +def func_bss(i): + # Use the date as the label. + label = i.date().format('YYYY-MM-dd') + labelImage = text.draw(label, point, scale, + textProperties) + + return i.visualize(vis) \ + .blend(labelImage) \ + .set({ + 'label': label + }); # Keep the text property. + +imagesRgb = images.map(func_bss) + + + + + + + + + + + + +Map.addLayer(imagesRgb.first()) +Map.addLayer(rect, {'color':'blue'}, 'rect', 1, 0.5) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + +# ================================== +# 1. Animate as a GIF + +# Define GIF visualization parameters. +gifParams = { + 'region': rect, + 'dimensions': 600, + 'crs': 'EPSG:3857', + 'framesPerSecond': 10 +} + +# Print the GIF URL to the console. +print(imagesRgb.getVideoThumbURL(gifParams)) + +# Render the GIF animation in the console. +print(ui.Thumbnail(imagesRgb, gifParams)) + +# ================================== +# 2. Export animation as a video file to Google Drive. + +Export.video.toDrive({ + 'collection': imagesRgb, + 'description': 'ice-animation', + 'fileNamePrefix': 'ice-animation', + 'framesPerSecond': 10, + 'dimensions': 600, + 'region': rect, + 'crs': 'EPSG:3857' +}) + +# ================================== +# 3. Animate multiple images as map layers, +# Use image date as labels (layer names). + +# include the animation package +animation = require('users/gena/packages:animation') + +# show animation controls +animation.animate(imagesRgb, { + 'label': 'label', + 'maxFrames': 50 +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60j Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60j Checkpoint.ipynb new file mode 100644 index 0000000..e985e53 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60j Checkpoint.ipynb @@ -0,0 +1,156 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.0 Advanced Raster Visualization\n", + "# Checkpoint: F60j\n", + "# Authors: Gennadii Donchyts, Fedor Baart\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "dem = ee.Image('AHN/AHN2_05M_RUW')\n", + "\n", + "# Change map style to HYBRID and center map on the Netherlands\n", + "Map.setOptions('HYBRID')\n", + "Map.setCenter(4.4082, 52.1775, 18)\n", + "\n", + "# Visualize DEM using black-white color palette\n", + "palette = ['black', 'white']\n", + "demRGB = dem.visualize(**{\n", + " 'min': -5,\n", + " 'max': 5,\n", + " 'palette': palette\n", + "})\n", + "Map.addLayer(demRGB, {}, 'DEM')\n", + "\n", + "utils = require('users/gena/packages:utils')\n", + "\n", + "weight =\n", + " 0.4; # Weight of Hillshade vs RGB (0 - flat, 1 - hillshaded).\n", + "exaggeration = 5; # Vertical exaggeration.\n", + "azimuth = 315; # Sun azimuth.\n", + "zenith = 20; # Sun elevation.\n", + "brightness = -0.05; # 0 - default.\n", + "contrast = 0.05; # 0 - default.\n", + "saturation = 0.8; # 1 - default.\n", + "castShadows = False\n", + "\n", + "rgb = utils.hillshadeRGB(\n", + " demRGB, dem, weight, exaggeration, azimuth, zenith,\n", + " contrast, brightness, saturation, castShadows)\n", + "\n", + "Map.addLayer(rgb, {}, 'DEM (no shadows)')\n", + "\n", + "castShadows = True\n", + "\n", + "rgb = utils.hillshadeRGB(\n", + " demRGB, dem, weight, exaggeration, azimuth, zenith,\n", + " contrast, brightness, saturation, castShadows)\n", + "\n", + "Map.addLayer(rgb, {}, 'DEM (with shadows)')\n", + "\n", + "palettes = require('users/gena/packages:palettes')\n", + "palette = palettes.crameri.oleron[50]\n", + "\n", + "demRGB = dem.visualize(**{'min': -5, 'max': 5, 'palette': palette})\n", + "\n", + "castShadows = True\n", + "\n", + "rgb = utils.hillshadeRGB(\n", + " demRGB, dem, weight, exaggeration, azimuth, zenith,\n", + " contrast, brightness, saturation, castShadows)\n", + "\n", + "Map.addLayer(rgb, {}, 'DEM colormap')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60j Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60j Checkpoint.js new file mode 100644 index 0000000..2e1c626 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60j Checkpoint.js @@ -0,0 +1,63 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.0 Advanced Raster Visualization +// Checkpoint: F60j +// Authors: Gennadii Donchyts, Fedor Baart +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var dem = ee.Image('AHN/AHN2_05M_RUW'); + +// Change map style to HYBRID and center map on the Netherlands +Map.setOptions('HYBRID'); +Map.setCenter(4.4082, 52.1775, 18); + +// Visualize DEM using black-white color palette +var palette = ['black', 'white']; +var demRGB = dem.visualize({ + min: -5, + max: 5, + palette: palette +}); +Map.addLayer(demRGB, {}, 'DEM'); + +var utils = require('users/gena/packages:utils'); + +var weight = + 0.4; // Weight of Hillshade vs RGB (0 - flat, 1 - hillshaded). +var exaggeration = 5; // Vertical exaggeration. +var azimuth = 315; // Sun azimuth. +var zenith = 20; // Sun elevation. +var brightness = -0.05; // 0 - default. +var contrast = 0.05; // 0 - default. +var saturation = 0.8; // 1 - default. +var castShadows = false; + +var rgb = utils.hillshadeRGB( + demRGB, dem, weight, exaggeration, azimuth, zenith, + contrast, brightness, saturation, castShadows); + +Map.addLayer(rgb, {}, 'DEM (no shadows)'); + +var castShadows = true; + +var rgb = utils.hillshadeRGB( + demRGB, dem, weight, exaggeration, azimuth, zenith, + contrast, brightness, saturation, castShadows); + +Map.addLayer(rgb, {}, 'DEM (with shadows)'); + +var palettes = require('users/gena/packages:palettes'); +var palette = palettes.crameri.oleron[50]; + +var demRGB = dem.visualize({min: -5, max: 5, palette: palette}); + +var castShadows = true; + +var rgb = utils.hillshadeRGB( + demRGB, dem, weight, exaggeration, azimuth, zenith, + contrast, brightness, saturation, castShadows); + +Map.addLayer(rgb, {}, 'DEM colormap'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60j Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60j Checkpoint.py new file mode 100644 index 0000000..7808913 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60j Checkpoint.py @@ -0,0 +1,69 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.0 Advanced Raster Visualization +# Checkpoint: F60j +# Authors: Gennadii Donchyts, Fedor Baart +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +dem = ee.Image('AHN/AHN2_05M_RUW') + +# Change map style to HYBRID and center map on the Netherlands +Map.setOptions('HYBRID') +Map.setCenter(4.4082, 52.1775, 18) + +# Visualize DEM using black-white color palette +palette = ['black', 'white'] +demRGB = dem.visualize(**{ + 'min': -5, + 'max': 5, + 'palette': palette +}) +Map.addLayer(demRGB, {}, 'DEM') + +utils = require('users/gena/packages:utils') + +weight = + 0.4; # Weight of Hillshade vs RGB (0 - flat, 1 - hillshaded). +exaggeration = 5; # Vertical exaggeration. +azimuth = 315; # Sun azimuth. +zenith = 20; # Sun elevation. +brightness = -0.05; # 0 - default. +contrast = 0.05; # 0 - default. +saturation = 0.8; # 1 - default. +castShadows = False + +rgb = utils.hillshadeRGB( + demRGB, dem, weight, exaggeration, azimuth, zenith, + contrast, brightness, saturation, castShadows) + +Map.addLayer(rgb, {}, 'DEM (no shadows)') + +castShadows = True + +rgb = utils.hillshadeRGB( + demRGB, dem, weight, exaggeration, azimuth, zenith, + contrast, brightness, saturation, castShadows) + +Map.addLayer(rgb, {}, 'DEM (with shadows)') + +palettes = require('users/gena/packages:palettes') +palette = palettes.crameri.oleron[50] + +demRGB = dem.visualize(**{'min': -5, 'max': 5, 'palette': palette}) + +castShadows = True + +rgb = utils.hillshadeRGB( + demRGB, dem, weight, exaggeration, azimuth, zenith, + contrast, brightness, saturation, castShadows) + +Map.addLayer(rgb, {}, 'DEM colormap') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60s1 - Supplemental - Gallery View.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60s1 - Supplemental - Gallery View.ipynb new file mode 100644 index 0000000..c345e81 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60s1 - Supplemental - Gallery View.ipynb @@ -0,0 +1,177 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "#*** Start of imports. If edited, may not auto-convert in the playground. ***#\n", + "geometryLabel =\n", + "\n", + " # shown: False #\n", + " ee.Geometry.Point([-104.81854696562625, 38.291704822204]),\n", + " geometryGallery =\n", + "\n", + " # shown: False #\n", + " # displayProperties: [\n", + " {\n", + " \"type\": \"rectangle\"\n", + " }\n", + " ] #\n", + " ee.Geometry.Polygon(\n", + " [[[-104.82125520585478, 38.294351019931455],\n", + " [-104.82125520585478, 38.23194594511732],\n", + " [-104.71980333207549, 38.23194594511732],\n", + " [-104.71980333207549, 38.294351019931455]]], None, False)\n", + "#**** End of imports. If edited, may not auto-convert in the playground. ****#\n", + "text = require('users/gena/packages:text')\n", + "gallery = require('users/gena/packages:gallery')\n", + "\n", + "Map.centerObject(geometryGallery, 12)\n", + "\n", + "images = ee.ImageCollection('COPERNICUS/S2') \\\n", + " .filterDate('2020-01-01', '2022-01-01') \\\n", + " .filterBounds(geometryLabel)\n", + "\n", + "\n", + "def func_wpn(month):\n", + " month = ee.Number(month)\n", + " return images.filter(ee.Filter.calendarRange(month, month.add(1), 'month')) \\\n", + " .select(['B12', 'B8', 'B4']) \\\n", + " .reduce(ee.Reducer.percentile([15])) \\\n", + " .set({\n", + " 'label': ee.Date.fromYMD(2000, month.add(1), 1).format('MMM')\n", + " })\n", + "\n", + "imagesMonthly = ee.List.sequence(0, 11).map(func_wpn)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "imagesMonthly = ee.ImageCollection(imagesMonthly)\n", + "\n", + "# Render monthly images + label.\n", + "\n", + "def func_dua(i):\n", + " label = text.draw(i.get('label'), geometryLabel, Map.getScale(), {\n", + " 'fontSize': 24,\n", + " 'textColor': 'ffffff',\n", + " 'outlineColor': '000000',\n", + " 'outlineWidth': 3,\n", + " 'outlineOpacity': 0.6\n", + " })\n", + " return i.visualize(**{'min': 300, 'max': 3500}).blend(label)\n", + "\n", + "imagesRGB = imagesMonthly.map(func_dua)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Generate a single filmstrip image (rows x columns).\n", + "rows = 3\n", + "columns = 4\n", + "imageFilmstrip = gallery \\\n", + " .draw(imagesRGB, geometryGallery.bounds(), rows, columns)\n", + "\n", + "Map.addLayer(imageFilmstrip)\n", + "\n", + "# LGTM (nclinton)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60s1 - Supplemental - Gallery View.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60s1 - Supplemental - Gallery View.js new file mode 100644 index 0000000..b3ac8af --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60s1 - Supplemental - Gallery View.js @@ -0,0 +1,61 @@ +/**** Start of imports. If edited, may not auto-convert in the playground. ****/ +var geometryLabel = + /* color: #d63000 */ + /* shown: false */ + ee.Geometry.Point([-104.81854696562625, 38.291704822204]), + geometryGallery = + /* color: #98ff00 */ + /* shown: false */ + /* displayProperties: [ + { + "type": "rectangle" + } + ] */ + ee.Geometry.Polygon( + [[[-104.82125520585478, 38.294351019931455], + [-104.82125520585478, 38.23194594511732], + [-104.71980333207549, 38.23194594511732], + [-104.71980333207549, 38.294351019931455]]], null, false); +/***** End of imports. If edited, may not auto-convert in the playground. *****/ +var text = require('users/gena/packages:text'); +var gallery = require('users/gena/packages:gallery'); + +Map.centerObject(geometryGallery, 12); + +var images = ee.ImageCollection('COPERNICUS/S2') + .filterDate('2020-01-01', '2022-01-01') + .filterBounds(geometryLabel); + +var imagesMonthly = ee.List.sequence(0, 11).map(function(month) { + month = ee.Number(month); + return images.filter(ee.Filter.calendarRange(month, month.add(1), 'month')) + .select(['B12', 'B8', 'B4']) + .reduce(ee.Reducer.percentile([15])) + .set({ + label: ee.Date.fromYMD(2000, month.add(1), 1).format('MMM') + }); +}); + +imagesMonthly = ee.ImageCollection(imagesMonthly); + +// Render monthly images + label. +var imagesRGB = imagesMonthly.map(function(i) { + var label = text.draw(i.get('label'), geometryLabel, Map.getScale(), { + fontSize: 24, + textColor: 'ffffff', + outlineColor: '000000', + outlineWidth: 3, + outlineOpacity: 0.6 + }); + return i.visualize({min: 300, max: 3500}).blend(label); +}); + +// Generate a single filmstrip image (rows x columns). +var rows = 3; +var columns = 4; +var imageFilmstrip = gallery + .draw(imagesRGB, geometryGallery.bounds(), rows, columns); + +Map.addLayer(imageFilmstrip); + +// LGTM (nclinton) diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60s1 - Supplemental - Gallery View.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60s1 - Supplemental - Gallery View.py new file mode 100644 index 0000000..4aa136d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.0 Advanced Raster Visualizations/F60s1 - Supplemental - Gallery View.py @@ -0,0 +1,90 @@ +import ee +import geemap + +Map = geemap.Map() + +#*** Start of imports. If edited, may not auto-convert in the playground. ***# +geometryLabel = + + # shown: False # + ee.Geometry.Point([-104.81854696562625, 38.291704822204]), + geometryGallery = + + # shown: False # + # displayProperties: [ + { + "type": "rectangle" + } + ] # + ee.Geometry.Polygon( + [[[-104.82125520585478, 38.294351019931455], + [-104.82125520585478, 38.23194594511732], + [-104.71980333207549, 38.23194594511732], + [-104.71980333207549, 38.294351019931455]]], None, False) +#**** End of imports. If edited, may not auto-convert in the playground. ****# +text = require('users/gena/packages:text') +gallery = require('users/gena/packages:gallery') + +Map.centerObject(geometryGallery, 12) + +images = ee.ImageCollection('COPERNICUS/S2') \ + .filterDate('2020-01-01', '2022-01-01') \ + .filterBounds(geometryLabel) + + +def func_wpn(month): + month = ee.Number(month) + return images.filter(ee.Filter.calendarRange(month, month.add(1), 'month')) \ + .select(['B12', 'B8', 'B4']) \ + .reduce(ee.Reducer.percentile([15])) \ + .set({ + 'label': ee.Date.fromYMD(2000, month.add(1), 1).format('MMM') + }) + +imagesMonthly = ee.List.sequence(0, 11).map(func_wpn) + + + + + + + + + + +imagesMonthly = ee.ImageCollection(imagesMonthly) + +# Render monthly images + label. + +def func_dua(i): + label = text.draw(i.get('label'), geometryLabel, Map.getScale(), { + 'fontSize': 24, + 'textColor': 'ffffff', + 'outlineColor': '000000', + 'outlineWidth': 3, + 'outlineOpacity': 0.6 + }) + return i.visualize(**{'min': 300, 'max': 3500}).blend(label) + +imagesRGB = imagesMonthly.map(func_dua) + + + + + + + + + + + +# Generate a single filmstrip image (rows x columns). +rows = 3 +columns = 4 +imageFilmstrip = gallery \ + .draw(imagesRGB, geometryGallery.bounds(), rows, columns) + +Map.addLayer(imageFilmstrip) + +# LGTM (nclinton) +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62a Checkpoint.ipynb new file mode 100644 index 0000000..aae360f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62a Checkpoint.ipynb @@ -0,0 +1,193 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.2 Scaling Up in Earth Engine\n", + "# Checkpoint: F62a\n", + "# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load county dataset.\n", + "# Filter counties in Indiana, Illinois, and Iowa by state FIPS code.\n", + "# Select only the unique ID column for simplicity.\n", + "countiesAll = ee.FeatureCollection('TIGER/2018/Counties')\n", + "states = ['17', '18', '19']\n", + "uniqueID = 'GEOID'\n", + "featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states)) \\\n", + " .select(uniqueID)\n", + "\n", + "print(featColl.size())\n", + "print(featColl.limit(1))\n", + "\n", + "# Visualize target features (create Figure F6.2.1).\n", + "Map.centerObject(featColl, 5)\n", + "Map.addLayer(featColl)\n", + "\n", + "# specify years of interest\n", + "startYear = 2020\n", + "endYear = 2020\n", + "\n", + "# climate dataset info\n", + "imageCollectionName = 'IDAHO_EPSCOR/GRIDMET'\n", + "bandsWanted = ['pr', 'tmmn', 'tmmx']\n", + "scale = 4000\n", + "\n", + "# Load and format climate data.\n", + "startDate = startYear + '-01-01'\n", + "\n", + "endYear_adj = endYear + 1\n", + "endDate = endYear_adj + '-01-01'\n", + "\n", + "imageCollection = ee.ImageCollection(imageCollectionName) \\\n", + " .select(bandsWanted) \\\n", + " .filterBounds(featColl) \\\n", + " .filterDate(startDate, endDate)\n", + "\n", + "# get values at features\n", + "\n", + "def func_tar(image):\n", + " return image.reduceRegions({\n", + " 'collection': featColl,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'scale': scale\n", + " }).filter(ee.Filter.NotNull(\n", + " bandsWanted)) # drop rows with no data \\\n", + " .map(function(f) { \n", + " time_start = image.get(\n", + " 'system:time_start')\n", + " dte = ee.Date(time_start).format(\n", + " 'YYYYMMdd')\n", + " return f.set('date_ymd', dte)\n", + " })\n", + "\n", + "sampledFeatures = imageCollection.map(func_tar\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + "\n", + "print(sampledFeatures.limit(1))\n", + "\n", + "# export info\n", + "exportFolder = 'GEE_scalingUp'\n", + "filename = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_' + \\\n", + " startYear + '-' + endYear\n", + "\n", + "# prepare export: specify properties/columns to include\n", + "columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted)\n", + "print(columnsWanted)\n", + "\n", + "Export.table.toDrive({\n", + " 'collection': sampledFeatures,\n", + " 'description': filename,\n", + " 'folder': exportFolder,\n", + " 'fileFormat': 'CSV',\n", + " 'selectors': columnsWanted\n", + "})\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62a Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62a Checkpoint.js new file mode 100644 index 0000000..38114e2 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62a Checkpoint.js @@ -0,0 +1,84 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.2 Scaling Up in Earth Engine +// Checkpoint: F62a +// Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load county dataset. +// Filter counties in Indiana, Illinois, and Iowa by state FIPS code. +// Select only the unique ID column for simplicity. +var countiesAll = ee.FeatureCollection('TIGER/2018/Counties'); +var states = ['17', '18', '19']; +var uniqueID = 'GEOID'; +var featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states)) + .select(uniqueID); + +print(featColl.size()); +print(featColl.limit(1)); + +// Visualize target features (create Figure F6.2.1). +Map.centerObject(featColl, 5); +Map.addLayer(featColl); + +// specify years of interest +var startYear = 2020; +var endYear = 2020; + +// climate dataset info +var imageCollectionName = 'IDAHO_EPSCOR/GRIDMET'; +var bandsWanted = ['pr', 'tmmn', 'tmmx']; +var scale = 4000; + +// Load and format climate data. +var startDate = startYear + '-01-01'; + +var endYear_adj = endYear + 1; +var endDate = endYear_adj + '-01-01'; + +var imageCollection = ee.ImageCollection(imageCollectionName) + .select(bandsWanted) + .filterBounds(featColl) + .filterDate(startDate, endDate); + +// get values at features +var sampledFeatures = imageCollection.map(function(image) { + return image.reduceRegions({ + collection: featColl, + reducer: ee.Reducer.mean(), + scale: scale + }).filter(ee.Filter.notNull( + bandsWanted)) // drop rows with no data + .map(function(f) { // add date property + var time_start = image.get( + 'system:time_start'); + var dte = ee.Date(time_start).format( + 'YYYYMMdd'); + return f.set('date_ymd', dte); + }); +}).flatten(); + +print(sampledFeatures.limit(1)); + +// export info +var exportFolder = 'GEE_scalingUp'; +var filename = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_' + + startYear + '-' + endYear; + +// prepare export: specify properties/columns to include +var columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted); +print(columnsWanted); + +Export.table.toDrive({ + collection: sampledFeatures, + description: filename, + folder: exportFolder, + fileFormat: 'CSV', + selectors: columnsWanted +}); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62a Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62a Checkpoint.py new file mode 100644 index 0000000..4dc835e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62a Checkpoint.py @@ -0,0 +1,107 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.2 Scaling Up in Earth Engine +# Checkpoint: F62a +# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load county dataset. +# Filter counties in Indiana, Illinois, and Iowa by state FIPS code. +# Select only the unique ID column for simplicity. +countiesAll = ee.FeatureCollection('TIGER/2018/Counties') +states = ['17', '18', '19'] +uniqueID = 'GEOID' +featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states)) \ + .select(uniqueID) + +print(featColl.size()) +print(featColl.limit(1)) + +# Visualize target features (create Figure F6.2.1). +Map.centerObject(featColl, 5) +Map.addLayer(featColl) + +# specify years of interest +startYear = 2020 +endYear = 2020 + +# climate dataset info +imageCollectionName = 'IDAHO_EPSCOR/GRIDMET' +bandsWanted = ['pr', 'tmmn', 'tmmx'] +scale = 4000 + +# Load and format climate data. +startDate = startYear + '-01-01' + +endYear_adj = endYear + 1 +endDate = endYear_adj + '-01-01' + +imageCollection = ee.ImageCollection(imageCollectionName) \ + .select(bandsWanted) \ + .filterBounds(featColl) \ + .filterDate(startDate, endDate) + +# get values at features + +def func_tar(image): + return image.reduceRegions({ + 'collection': featColl, + 'reducer': ee.Reducer.mean(), + 'scale': scale + }).filter(ee.Filter.NotNull( + bandsWanted)) # drop rows with no data \ + .map(function(f) { + time_start = image.get( + 'system:time_start') + dte = ee.Date(time_start).format( + 'YYYYMMdd') + return f.set('date_ymd', dte) + }) + +sampledFeatures = imageCollection.map(func_tar +).flatten() + + + + + + + + + + + + + +).flatten() + +print(sampledFeatures.limit(1)) + +# export info +exportFolder = 'GEE_scalingUp' +filename = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_' + \ + startYear + '-' + endYear + +# prepare export: specify properties/columns to include +columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted) +print(columnsWanted) + +Export.table.toDrive({ + 'collection': sampledFeatures, + 'description': filename, + 'folder': exportFolder, + 'fileFormat': 'CSV', + 'selectors': columnsWanted +}) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62b Checkpoint.ipynb new file mode 100644 index 0000000..7327ee6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62b Checkpoint.ipynb @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.2 Scaling Up in Earth Engine\n", + "# Checkpoint: F62b\n", + "# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Load county dataset.\n", + "# Filter counties in Indiana, Illinois, and Iowa by state FIPS code.\n", + "# Select only the unique ID column for simplicity.\n", + "countiesAll = ee.FeatureCollection('TIGER/2018/Counties')\n", + "states = ['17', '18', '19']\n", + "uniqueID = 'GEOID'\n", + "featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states)) \\\n", + " .select(uniqueID)\n", + "\n", + "print(featColl.size())\n", + "print(featColl.limit(1))\n", + "Map.addLayer(featColl)\n", + "\n", + "# Specify years of interest.\n", + "startYear = 2001\n", + "endYear = 2020\n", + "\n", + "# Climate dataset info.\n", + "imageCollectionName = 'IDAHO_EPSCOR/GRIDMET'\n", + "bandsWanted = ['pr', 'tmmn', 'tmmx']\n", + "scale = 4000\n", + "\n", + "# Export info.\n", + "exportFolder = 'GEE_scalingUp'\n", + "filenameBase = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_'\n", + "\n", + "# Initiate a loop, in which the variable i takes on values of each year.\n", + "for i in range(startYear, endYear, 1): # for each year....\n", + "\n", + " # Load climate collection for that year.\n", + " startDate = i + '-01-01'\n", + "\n", + " endYear_adj = i + 1\n", + " endDate = endYear_adj + '-01-01'\n", + "\n", + " imageCollection = ee.ImageCollection(imageCollectionName) \\\n", + " .select(bandsWanted) \\\n", + " .filterBounds(featColl) \\\n", + " .filterDate(startDate, endDate)\n", + "\n", + " # Get values at feature collection.\n", + "\n", + "def func_rsk(image):\n", + " return image.reduceRegions({\n", + " 'collection': featColl,\n", + " 'reducer': ee.Reducer.mean(),\n", + " 'tileScale': 1,\n", + " 'scale': scale\n", + " }).filter(ee.Filter.NotNull(bandsWanted)) # remove rows without data \\\n", + " .map(function(f) { \n", + " time_start = image.get('system:time_start')\n", + " dte = ee.Date(time_start).format('YYYYMMdd')\n", + " return f.set('date_ymd', dte)\n", + " })\n", + "\n", + " sampledFeatures = imageCollection.map(func_rsk\n", + ").flatten()\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + ").flatten()\n", + "\n", + " # Prepare export: specify properties and filename.\n", + " columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted)\n", + " filename = filenameBase + i\n", + "\n", + " Export.table.toDrive({\n", + " 'collection': sampledFeatures,\n", + " 'description': filename,\n", + " 'folder': exportFolder,\n", + " 'fileFormat': 'CSV',\n", + " 'selectors': columnsWanted\n", + " })\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62b Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62b Checkpoint.js new file mode 100644 index 0000000..bc12e45 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62b Checkpoint.js @@ -0,0 +1,80 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.2 Scaling Up in Earth Engine +// Checkpoint: F62b +// Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Load county dataset. +// Filter counties in Indiana, Illinois, and Iowa by state FIPS code. +// Select only the unique ID column for simplicity. +var countiesAll = ee.FeatureCollection('TIGER/2018/Counties'); +var states = ['17', '18', '19']; +var uniqueID = 'GEOID'; +var featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states)) + .select(uniqueID); + +print(featColl.size()); +print(featColl.limit(1)); +Map.addLayer(featColl); + +// Specify years of interest. +var startYear = 2001; +var endYear = 2020; + +// Climate dataset info. +var imageCollectionName = 'IDAHO_EPSCOR/GRIDMET'; +var bandsWanted = ['pr', 'tmmn', 'tmmx']; +var scale = 4000; + +// Export info. +var exportFolder = 'GEE_scalingUp'; +var filenameBase = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_'; + +// Initiate a loop, in which the variable i takes on values of each year. +for (var i = startYear; i <= endYear; i++) { // for each year.... + + // Load climate collection for that year. + var startDate = i + '-01-01'; + + var endYear_adj = i + 1; + var endDate = endYear_adj + '-01-01'; + + var imageCollection = ee.ImageCollection(imageCollectionName) + .select(bandsWanted) + .filterBounds(featColl) + .filterDate(startDate, endDate); + + // Get values at feature collection. + var sampledFeatures = imageCollection.map(function(image) { + return image.reduceRegions({ + collection: featColl, + reducer: ee.Reducer.mean(), + tileScale: 1, + scale: scale + }).filter(ee.Filter.notNull(bandsWanted)) // remove rows without data + .map(function(f) { // add date property + var time_start = image.get('system:time_start'); + var dte = ee.Date(time_start).format('YYYYMMdd'); + return f.set('date_ymd', dte); + }); + }).flatten(); + + // Prepare export: specify properties and filename. + var columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted); + var filename = filenameBase + i; + + Export.table.toDrive({ + collection: sampledFeatures, + description: filename, + folder: exportFolder, + fileFormat: 'CSV', + selectors: columnsWanted + }); + +} +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62b Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62b Checkpoint.py new file mode 100644 index 0000000..94fef78 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62b Checkpoint.py @@ -0,0 +1,101 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.2 Scaling Up in Earth Engine +# Checkpoint: F62b +# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Load county dataset. +# Filter counties in Indiana, Illinois, and Iowa by state FIPS code. +# Select only the unique ID column for simplicity. +countiesAll = ee.FeatureCollection('TIGER/2018/Counties') +states = ['17', '18', '19'] +uniqueID = 'GEOID' +featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states)) \ + .select(uniqueID) + +print(featColl.size()) +print(featColl.limit(1)) +Map.addLayer(featColl) + +# Specify years of interest. +startYear = 2001 +endYear = 2020 + +# Climate dataset info. +imageCollectionName = 'IDAHO_EPSCOR/GRIDMET' +bandsWanted = ['pr', 'tmmn', 'tmmx'] +scale = 4000 + +# Export info. +exportFolder = 'GEE_scalingUp' +filenameBase = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_' + +# Initiate a loop, in which the variable i takes on values of each year. +for i in range(startYear, endYear, 1): # for each year.... + + # Load climate collection for that year. + startDate = i + '-01-01' + + endYear_adj = i + 1 + endDate = endYear_adj + '-01-01' + + imageCollection = ee.ImageCollection(imageCollectionName) \ + .select(bandsWanted) \ + .filterBounds(featColl) \ + .filterDate(startDate, endDate) + + # Get values at feature collection. + +def func_rsk(image): + return image.reduceRegions({ + 'collection': featColl, + 'reducer': ee.Reducer.mean(), + 'tileScale': 1, + 'scale': scale + }).filter(ee.Filter.NotNull(bandsWanted)) # remove rows without data \ + .map(function(f) { + time_start = image.get('system:time_start') + dte = ee.Date(time_start).format('YYYYMMdd') + return f.set('date_ymd', dte) + }) + + sampledFeatures = imageCollection.map(func_rsk +).flatten() + + + + + + + + + + + +).flatten() + + # Prepare export: specify properties and filename. + columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted) + filename = filenameBase + i + + Export.table.toDrive({ + 'collection': sampledFeatures, + 'description': filename, + 'folder': exportFolder, + 'fileFormat': 'CSV', + 'selectors': columnsWanted + }) + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62c Checkpoint.ipynb new file mode 100644 index 0000000..6311647 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62c Checkpoint.ipynb @@ -0,0 +1,170 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.2 Scaling Up in Earth Engine\n", + "# Checkpoint: F62c\n", + "# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Set the Region of Interest:Seattle, Washington, United States\n", + "roi = ee.Geometry.Point([-122.33524518034544, 47.61356183942883])\n", + "\n", + "# Dates over which to create a median composite.\n", + "start = ee.Date('2019-03-01')\n", + "end = ee.Date('2019-09-01')\n", + "\n", + "# Specify module with cloud mask functions.\n", + "s2mask_tools = require(\n", + " 'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js'\n", + ")\n", + "\n", + "\n", + "# Specify S2 collections and filter.\n", + "\n", + "# Sentinel-2 surface reflectance data for the composite.\n", + "s2Sr = ee.ImageCollection('COPERNICUS/S2_SR') \\\n", + " .filterDate(start, end) \\\n", + " .filterBounds(roi) \\\n", + " .select(['B2', 'B3', 'B4', 'B5'])\n", + "\n", + "# Sentinel-2 Level 1C data (top-of-atmosphere).\n", + "# Bands B7, B8, B8A and B10 needed for CDI and the cloud mask function.\n", + "s2 = ee.ImageCollection('COPERNICUS/S2') \\\n", + " .filterBounds(roi) \\\n", + " .filterDate(start, end) \\\n", + " .select(['B7', 'B8', 'B8A', 'B10'])\n", + "\n", + "# Cloud probability dataset - used in cloud mask function\n", + "s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') \\\n", + " .filterDate(start, end) \\\n", + " .filterBounds(roi)\n", + "\n", + "# Apply the cloud mask.\n", + "\n", + "# Join the cloud probability dataset to surface reflectance.\n", + "withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c,\n", + " 'cloud_probability')\n", + "\n", + "# Join the L1C data to get the bands needed for CDI.\n", + "withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2,\n", + " 'l1c')\n", + "\n", + "# Map the cloud masking function over the joined collection.\n", + "# Cast output to ImageCollection\n", + "masked = ee.ImageCollection(withS2L1C.map(s2mask_tools \\\n", + ".maskImage))\n", + "\n", + "# Take the median, specifying a tileScale to avoid memory errors.\n", + "median = masked.reduce(ee.Reducer.median(), 8)\n", + "\n", + "# Display the results.\n", + "Map.centerObject(roi, 12)\n", + "Map.addLayer(roi)\n", + "\n", + "viz = {\n", + " 'bands': ['B4_median', 'B3_median', 'B2_median'],\n", + " 'min': 0,\n", + " 'max': 3000\n", + "}\n", + "Map.addLayer(median, viz, 'median')\n", + "\n", + "Map.centerObject(roi, 9)\n", + "Map.addLayer(roi)\n", + "Map.addLayer(median, viz, 'median')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62c Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62c Checkpoint.js new file mode 100644 index 0000000..a126bd6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62c Checkpoint.js @@ -0,0 +1,78 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.2 Scaling Up in Earth Engine +// Checkpoint: F62c +// Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Set the Region of Interest:Seattle, Washington, United States +var roi = ee.Geometry.Point([-122.33524518034544, 47.61356183942883]); + +// Dates over which to create a median composite. +var start = ee.Date('2019-03-01'); +var end = ee.Date('2019-09-01'); + +// Specify module with cloud mask functions. +var s2mask_tools = require( + 'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js' +); + + +// Specify S2 collections and filter. + +// Sentinel-2 surface reflectance data for the composite. +var s2Sr = ee.ImageCollection('COPERNICUS/S2_SR') + .filterDate(start, end) + .filterBounds(roi) + .select(['B2', 'B3', 'B4', 'B5']); + +// Sentinel-2 Level 1C data (top-of-atmosphere). +// Bands B7, B8, B8A and B10 needed for CDI and the cloud mask function. +var s2 = ee.ImageCollection('COPERNICUS/S2') + .filterBounds(roi) + .filterDate(start, end) + .select(['B7', 'B8', 'B8A', 'B10']); + +// Cloud probability dataset - used in cloud mask function +var s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') + .filterDate(start, end) + .filterBounds(roi); + +// Apply the cloud mask. + +// Join the cloud probability dataset to surface reflectance. +var withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c, + 'cloud_probability'); + +// Join the L1C data to get the bands needed for CDI. +var withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2, + 'l1c'); + +// Map the cloud masking function over the joined collection. +// Cast output to ImageCollection +var masked = ee.ImageCollection(withS2L1C.map(s2mask_tools +.maskImage)); + +// Take the median, specifying a tileScale to avoid memory errors. +var median = masked.reduce(ee.Reducer.median(), 8); + +// Display the results. +Map.centerObject(roi, 12); +Map.addLayer(roi); + +var viz = { + bands: ['B4_median', 'B3_median', 'B2_median'], + min: 0, + max: 3000 +}; +Map.addLayer(median, viz, 'median'); + +Map.centerObject(roi, 9); +Map.addLayer(roi); +Map.addLayer(median, viz, 'median'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62c Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62c Checkpoint.py new file mode 100644 index 0000000..3aa0717 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62c Checkpoint.py @@ -0,0 +1,84 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.2 Scaling Up in Earth Engine +# Checkpoint: F62c +# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the Region of Interest:Seattle, Washington, United States +roi = ee.Geometry.Point([-122.33524518034544, 47.61356183942883]) + +# Dates over which to create a median composite. +start = ee.Date('2019-03-01') +end = ee.Date('2019-09-01') + +# Specify module with cloud mask functions. +s2mask_tools = require( + 'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js' +) + + +# Specify S2 collections and filter. + +# Sentinel-2 surface reflectance data for the composite. +s2Sr = ee.ImageCollection('COPERNICUS/S2_SR') \ + .filterDate(start, end) \ + .filterBounds(roi) \ + .select(['B2', 'B3', 'B4', 'B5']) + +# Sentinel-2 Level 1C data (top-of-atmosphere). +# Bands B7, B8, B8A and B10 needed for CDI and the cloud mask function. +s2 = ee.ImageCollection('COPERNICUS/S2') \ + .filterBounds(roi) \ + .filterDate(start, end) \ + .select(['B7', 'B8', 'B8A', 'B10']) + +# Cloud probability dataset - used in cloud mask function +s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') \ + .filterDate(start, end) \ + .filterBounds(roi) + +# Apply the cloud mask. + +# Join the cloud probability dataset to surface reflectance. +withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c, + 'cloud_probability') + +# Join the L1C data to get the bands needed for CDI. +withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2, + 'l1c') + +# Map the cloud masking function over the joined collection. +# Cast output to ImageCollection +masked = ee.ImageCollection(withS2L1C.map(s2mask_tools \ +.maskImage)) + +# Take the median, specifying a tileScale to avoid memory errors. +median = masked.reduce(ee.Reducer.median(), 8) + +# Display the results. +Map.centerObject(roi, 12) +Map.addLayer(roi) + +viz = { + 'bands': ['B4_median', 'B3_median', 'B2_median'], + 'min': 0, + 'max': 3000 +} +Map.addLayer(median, viz, 'median') + +Map.centerObject(roi, 9) +Map.addLayer(roi) +Map.addLayer(median, viz, 'median') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62d Checkpoint.ipynb new file mode 100644 index 0000000..474e94f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62d Checkpoint.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.2 Scaling Up in Earth Engine\n", + "# Checkpoint: F62d\n", + "# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Specify helper functions.\n", + "s2mask_tools = require(\n", + " 'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js'\n", + ")\n", + "\n", + "# Set the Region of Interest: Washington, USA.\n", + "roi = ee.FeatureCollection('TIGER/2018/States') \\\n", + " .filter(ee.Filter.equals('NAME', 'Washington'))\n", + "\n", + "# Specify grid size in projection, x and y units (based on projection).\n", + "projection = 'EPSG:4326'\n", + "dx = 2.5\n", + "dy = 1.5\n", + "\n", + "# Dates over which to create a median composite.\n", + "start = ee.Date('2019-03-01')\n", + "end = ee.Date('2019-09-01')\n", + "\n", + "# Make grid and visualize.\n", + "proj = ee.Projection(projection).scale(dx, dy)\n", + "grid = roi.geometry().coveringGrid(proj)\n", + "\n", + "Map.addLayer(roi, {}, 'roi')\n", + "Map.addLayer(grid, {}, 'grid')\n", + "\n", + "# Export info.\n", + "assetCollection = 'path/to/your/asset/s2_composite_WA'\n", + "imageBaseName = 'S2_median_'\n", + "\n", + "# Get a list based on grid number.\n", + "gridSize = grid.size().getInfo()\n", + "gridList = grid.toList(gridSize)\n", + "\n", + "# In each grid cell, export a composite\n", + "for i in range(0, gridSize, 1):\n", + "\n", + " # Extract grid polygon and filter S2 datasets for this region.\n", + " gridCell = ee.Feature(gridList.get(i)).geometry()\n", + "\n", + " s2Sr = ee.ImageCollection('COPERNICUS/S2_SR') \\\n", + " .filterDate(start, end) \\\n", + " .filterBounds(gridCell) \\\n", + " .select(['B2', 'B3', 'B4', 'B5'])\n", + "\n", + " s2 = ee.ImageCollection('COPERNICUS/S2') \\\n", + " .filterDate(start, end) \\\n", + " .filterBounds(gridCell) \\\n", + " .select(['B7', 'B8', 'B8A', 'B10'])\n", + "\n", + " s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') \\\n", + " .filterDate(start, end) \\\n", + " .filterBounds(gridCell)\n", + "\n", + " # Apply the cloud mask.\n", + " withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c,\n", + " 'cloud_probability')\n", + " withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2,\n", + " 'l1c')\n", + " masked = ee.ImageCollection(withS2L1C.map(s2mask_tools \\\n", + " .maskImage))\n", + "\n", + " # Generate a median composite and export.\n", + " median = masked.reduce(ee.Reducer.median(), 8)\n", + "\n", + " # Export.\n", + " imagename = imageBaseName + 'tile' + i\n", + " Export.image.toAsset({\n", + " 'image': median,\n", + " 'description': imagename,\n", + " 'assetId': assetCollection + '/' + imagename,\n", + " 'scale': 10,\n", + " 'region': gridCell,\n", + " 'maxPixels': 1e13\n", + " })\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62d Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62d Checkpoint.js new file mode 100644 index 0000000..b4f2597 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62d Checkpoint.js @@ -0,0 +1,88 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.2 Scaling Up in Earth Engine +// Checkpoint: F62d +// Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Specify helper functions. +var s2mask_tools = require( + 'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js' +); + +// Set the Region of Interest: Washington, USA. +var roi = ee.FeatureCollection('TIGER/2018/States') + .filter(ee.Filter.equals('NAME', 'Washington')); + +// Specify grid size in projection, x and y units (based on projection). +var projection = 'EPSG:4326'; +var dx = 2.5; +var dy = 1.5; + +// Dates over which to create a median composite. +var start = ee.Date('2019-03-01'); +var end = ee.Date('2019-09-01'); + +// Make grid and visualize. +var proj = ee.Projection(projection).scale(dx, dy); +var grid = roi.geometry().coveringGrid(proj); + +Map.addLayer(roi, {}, 'roi'); +Map.addLayer(grid, {}, 'grid'); + +// Export info. +var assetCollection = 'path/to/your/asset/s2_composite_WA'; +var imageBaseName = 'S2_median_'; + +// Get a list based on grid number. +var gridSize = grid.size().getInfo(); +var gridList = grid.toList(gridSize); + +// In each grid cell, export a composite +for (var i = 0; i < gridSize; i++) { + + // Extract grid polygon and filter S2 datasets for this region. + var gridCell = ee.Feature(gridList.get(i)).geometry(); + + var s2Sr = ee.ImageCollection('COPERNICUS/S2_SR') + .filterDate(start, end) + .filterBounds(gridCell) + .select(['B2', 'B3', 'B4', 'B5']); + + var s2 = ee.ImageCollection('COPERNICUS/S2') + .filterDate(start, end) + .filterBounds(gridCell) + .select(['B7', 'B8', 'B8A', 'B10']); + + var s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') + .filterDate(start, end) + .filterBounds(gridCell); + + // Apply the cloud mask. + var withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c, + 'cloud_probability'); + var withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2, + 'l1c'); + var masked = ee.ImageCollection(withS2L1C.map(s2mask_tools + .maskImage)); + + // Generate a median composite and export. + var median = masked.reduce(ee.Reducer.median(), 8); + + // Export. + var imagename = imageBaseName + 'tile' + i; + Export.image.toAsset({ + image: median, + description: imagename, + assetId: assetCollection + '/' + imagename, + scale: 10, + region: gridCell, + maxPixels: 1e13 + }); +} + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62d Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62d Checkpoint.py new file mode 100644 index 0000000..50f107f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62d Checkpoint.py @@ -0,0 +1,94 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.2 Scaling Up in Earth Engine +# Checkpoint: F62d +# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Specify helper functions. +s2mask_tools = require( + 'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js' +) + +# Set the Region of Interest: Washington, USA. +roi = ee.FeatureCollection('TIGER/2018/States') \ + .filter(ee.Filter.equals('NAME', 'Washington')) + +# Specify grid size in projection, x and y units (based on projection). +projection = 'EPSG:4326' +dx = 2.5 +dy = 1.5 + +# Dates over which to create a median composite. +start = ee.Date('2019-03-01') +end = ee.Date('2019-09-01') + +# Make grid and visualize. +proj = ee.Projection(projection).scale(dx, dy) +grid = roi.geometry().coveringGrid(proj) + +Map.addLayer(roi, {}, 'roi') +Map.addLayer(grid, {}, 'grid') + +# Export info. +assetCollection = 'path/to/your/asset/s2_composite_WA' +imageBaseName = 'S2_median_' + +# Get a list based on grid number. +gridSize = grid.size().getInfo() +gridList = grid.toList(gridSize) + +# In each grid cell, export a composite +for i in range(0, gridSize, 1): + + # Extract grid polygon and filter S2 datasets for this region. + gridCell = ee.Feature(gridList.get(i)).geometry() + + s2Sr = ee.ImageCollection('COPERNICUS/S2_SR') \ + .filterDate(start, end) \ + .filterBounds(gridCell) \ + .select(['B2', 'B3', 'B4', 'B5']) + + s2 = ee.ImageCollection('COPERNICUS/S2') \ + .filterDate(start, end) \ + .filterBounds(gridCell) \ + .select(['B7', 'B8', 'B8A', 'B10']) + + s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') \ + .filterDate(start, end) \ + .filterBounds(gridCell) + + # Apply the cloud mask. + withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c, + 'cloud_probability') + withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2, + 'l1c') + masked = ee.ImageCollection(withS2L1C.map(s2mask_tools \ + .maskImage)) + + # Generate a median composite and export. + median = masked.reduce(ee.Reducer.median(), 8) + + # Export. + imagename = imageBaseName + 'tile' + i + Export.image.toAsset({ + 'image': median, + 'description': imagename, + 'assetId': assetCollection + '/' + imagename, + 'scale': 10, + 'region': gridCell, + 'maxPixels': 1e13 + }) + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62e Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62e Checkpoint.ipynb new file mode 100644 index 0000000..189a5c0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62e Checkpoint.ipynb @@ -0,0 +1,120 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.2 Scaling Up in Earth Engine\n", + "# Checkpoint: F62e\n", + "# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# load image collection and mosaic into single image\n", + "assetCollection = 'projects/gee-book/assets/F6-2/s2_composite_WA'\n", + "composite = ee.ImageCollection(assetCollection).mosaic()\n", + "\n", + "# Display the results\n", + "geometry = ee.Geometry.Point([-120.5873563817392,\n", + " 47.39035206888694\n", + "])\n", + "Map.centerObject(geometry, 6)\n", + "vizParams = {\n", + " 'bands': ['B4_median', 'B3_median', 'B2_median'],\n", + " 'min': 0,\n", + " 'max': 3000\n", + "}\n", + "Map.addLayer(composite, vizParams, 'median')\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62e Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62e Checkpoint.js new file mode 100644 index 0000000..8a4e1b6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62e Checkpoint.js @@ -0,0 +1,28 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.2 Scaling Up in Earth Engine +// Checkpoint: F62e +// Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// load image collection and mosaic into single image +var assetCollection = 'projects/gee-book/assets/F6-2/s2_composite_WA'; +var composite = ee.ImageCollection(assetCollection).mosaic(); + +// Display the results +var geometry = ee.Geometry.Point([-120.5873563817392, + 47.39035206888694 +]); +Map.centerObject(geometry, 6); +var vizParams = { + bands: ['B4_median', 'B3_median', 'B2_median'], + min: 0, + max: 3000 +}; +Map.addLayer(composite, vizParams, 'median'); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62e Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62e Checkpoint.py new file mode 100644 index 0000000..c1a1ea0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/F62e Checkpoint.py @@ -0,0 +1,34 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.2 Scaling Up in Earth Engine +# Checkpoint: F62e +# Authors: Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# load image collection and mosaic into single image +assetCollection = 'projects/gee-book/assets/F6-2/s2_composite_WA' +composite = ee.ImageCollection(assetCollection).mosaic() + +# Display the results +geometry = ee.Geometry.Point([-120.5873563817392, + 47.39035206888694 +]) +Map.centerObject(geometry, 6) +vizParams = { + 'bands': ['B4_median', 'B3_median', 'B2_median'], + 'min': 0, + 'max': 3000 +} +Map.addLayer(composite, vizParams, 'median') + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.ipynb new file mode 100644 index 0000000..8aa2b7c --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.ipynb @@ -0,0 +1,152 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# Functions for implementing a Sentinel II cloud mask.\n", + "\n", + "# Join two collections on their 'system:index' property.\n", + "# The propertyName parameter is the name of the property\n", + "# that references the joined image.\n", + "def indexJoin(collectionA, collectionB, propertyName):\n", + " joined = ee.ImageCollection(ee.Join.saveFirst(propertyName).apply({\n", + " 'primary': collectionA,\n", + " 'secondary': collectionB,\n", + " 'condition': ee.Filter.equals({\n", + " 'leftField': 'system:index',\n", + " 'rightField': 'system:index'})\n", + " }))\n", + " # Merge the bands of the joined image.\n", + "\n", + "def func_oxa(image):\n", + " return image.addBands(ee.Image(image.get(propertyName)))\n", + "\n", + " return joined.map(func_oxa)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Aggressively mask clouds and shadows.\n", + "def maskImage(image):\n", + " # Compute the cloud displacement index from the L1C bands.\n", + " cdi = ee.Algorithms.Sentinel2.CDI(image)\n", + " s2c = image.select('probability')\n", + " cirrus = image.select('B10').multiply(0.0001)\n", + "\n", + " # Assume low-to-mid atmospheric clouds to be pixels where probability\n", + " # is greater than 65%, and CDI is less than -0.5. For higher atmosphere\n", + " # cirrus clouds, assume the cirrus band is greater than 0.01.\n", + " # The final cloud mask is one or both of these conditions.\n", + " isCloud = s2c.gt(65).And(cdi.lt(-0.5)).Or(cirrus.gt(0.01))\n", + "\n", + " # Reproject is required to perform spatial operations at 20m scale.\n", + " # 20m scale is for speed, and assumes clouds don't require 10m precision.\n", + " isCloud = isCloud.focal_min(3).focal_max(16)\n", + " isCloud = isCloud.reproject({'crs': cdi.projection(), 'scale': 20})\n", + "\n", + " # Project shadows from clouds we found in the last step. This assumes we're working in\n", + " # a UTM projection.\n", + " shadowAzimuth = ee.Number(90) \\\n", + " .subtract(ee.Number(image.get('MEAN_SOLAR_AZIMUTH_ANGLE')))\n", + "\n", + " # With the following reproject, the shadows are projected 5km.\n", + " isCloud = isCloud.directionalDistanceTransform(shadowAzimuth, 50)\n", + " isCloud = isCloud.reproject({'crs': cdi.projection(), 'scale': 100})\n", + "\n", + " isCloud = isCloud.select('distance').mask()\n", + " return image.select('B2', 'B3', 'B4').updateMask(isCloud.Not())\n", + "\n", + "\n", + "exports.maskImage = maskImage\n", + "exports.indexJoin = indexJoin\n", + "\n", + "# LGTM (nclinton)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js new file mode 100644 index 0000000..6266642 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js @@ -0,0 +1,54 @@ +// Functions for implementing a Sentinel II cloud mask. + +// Join two collections on their 'system:index' property. +// The propertyName parameter is the name of the property +// that references the joined image. +function indexJoin(collectionA, collectionB, propertyName) { + var joined = ee.ImageCollection(ee.Join.saveFirst(propertyName).apply({ + primary: collectionA, + secondary: collectionB, + condition: ee.Filter.equals({ + leftField: 'system:index', + rightField: 'system:index'}) + })); + // Merge the bands of the joined image. + return joined.map(function(image) { + return image.addBands(ee.Image(image.get(propertyName))); + }); +} + +// Aggressively mask clouds and shadows. +function maskImage(image) { + // Compute the cloud displacement index from the L1C bands. + var cdi = ee.Algorithms.Sentinel2.CDI(image); + var s2c = image.select('probability'); + var cirrus = image.select('B10').multiply(0.0001); + + // Assume low-to-mid atmospheric clouds to be pixels where probability + // is greater than 65%, and CDI is less than -0.5. For higher atmosphere + // cirrus clouds, assume the cirrus band is greater than 0.01. + // The final cloud mask is one or both of these conditions. + var isCloud = s2c.gt(65).and(cdi.lt(-0.5)).or(cirrus.gt(0.01)); + + // Reproject is required to perform spatial operations at 20m scale. + // 20m scale is for speed, and assumes clouds don't require 10m precision. + isCloud = isCloud.focal_min(3).focal_max(16); + isCloud = isCloud.reproject({crs: cdi.projection(), scale: 20}); + + // Project shadows from clouds we found in the last step. This assumes we're working in + // a UTM projection. + var shadowAzimuth = ee.Number(90) + .subtract(ee.Number(image.get('MEAN_SOLAR_AZIMUTH_ANGLE'))); + + // With the following reproject, the shadows are projected 5km. + isCloud = isCloud.directionalDistanceTransform(shadowAzimuth, 50); + isCloud = isCloud.reproject({crs: cdi.projection(), scale: 100}); + + isCloud = isCloud.select('distance').mask(); + return image.select('B2', 'B3', 'B4').updateMask(isCloud.not()); +} + +exports.maskImage = maskImage; +exports.indexJoin = indexJoin; + +// LGTM (nclinton) \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.py new file mode 100644 index 0000000..627c62e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.py @@ -0,0 +1,65 @@ +import ee +import geemap + +Map = geemap.Map() + +# Functions for implementing a Sentinel II cloud mask. + +# Join two collections on their 'system:index' property. +# The propertyName parameter is the name of the property +# that references the joined image. +def indexJoin(collectionA, collectionB, propertyName): + joined = ee.ImageCollection(ee.Join.saveFirst(propertyName).apply({ + 'primary': collectionA, + 'secondary': collectionB, + 'condition': ee.Filter.equals({ + 'leftField': 'system:index', + 'rightField': 'system:index'}) + })) + # Merge the bands of the joined image. + +def func_oxa(image): + return image.addBands(ee.Image(image.get(propertyName))) + + return joined.map(func_oxa) + + + + + +# Aggressively mask clouds and shadows. +def maskImage(image): + # Compute the cloud displacement index from the L1C bands. + cdi = ee.Algorithms.Sentinel2.CDI(image) + s2c = image.select('probability') + cirrus = image.select('B10').multiply(0.0001) + + # Assume low-to-mid atmospheric clouds to be pixels where probability + # is greater than 65%, and CDI is less than -0.5. For higher atmosphere + # cirrus clouds, assume the cirrus band is greater than 0.01. + # The final cloud mask is one or both of these conditions. + isCloud = s2c.gt(65).And(cdi.lt(-0.5)).Or(cirrus.gt(0.01)) + + # Reproject is required to perform spatial operations at 20m scale. + # 20m scale is for speed, and assumes clouds don't require 10m precision. + isCloud = isCloud.focal_min(3).focal_max(16) + isCloud = isCloud.reproject({'crs': cdi.projection(), 'scale': 20}) + + # Project shadows from clouds we found in the last step. This assumes we're working in + # a UTM projection. + shadowAzimuth = ee.Number(90) \ + .subtract(ee.Number(image.get('MEAN_SOLAR_AZIMUTH_ANGLE'))) + + # With the following reproject, the shadows are projected 5km. + isCloud = isCloud.directionalDistanceTransform(shadowAzimuth, 50) + isCloud = isCloud.reproject({'crs': cdi.projection(), 'scale': 100}) + + isCloud = isCloud.select('distance').mask() + return image.select('B2', 'B3', 'B4').updateMask(isCloud.Not()) + + +exports.maskImage = maskImage +exports.indexJoin = indexJoin + +# LGTM (nclinton) +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/A38s1 - Supplemental.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/A38s1 - Supplemental.ipynb new file mode 100644 index 0000000..12ba228 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/A38s1 - Supplemental.ipynb @@ -0,0 +1,92 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/A38s1 - Supplemental.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/A38s1 - Supplemental.js new file mode 100644 index 0000000..e69de29 diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/A38s1 - Supplemental.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/A38s1 - Supplemental.py new file mode 100644 index 0000000..6571a1f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/A38s1 - Supplemental.py @@ -0,0 +1,6 @@ +import ee +import geemap + +Map = geemap.Map() + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63a Checkpoint.ipynb new file mode 100644 index 0000000..afce8d0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63a Checkpoint.ipynb @@ -0,0 +1,306 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps\n", + "# Checkpoint: F63a\n", + "# Author: Qiusheng Wu\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "# Get an NLCD image by year.\n", + "def getNLCD(year):\n", + " # Import the NLCD collection.\n", + " dataset = ee.ImageCollection(\n", + " 'USGS/NLCD_RELEASES/2019_REL/NLCD')\n", + "\n", + " # Filter the collection by year.\n", + " nlcd = dataset.filter(ee.Filter.eq('system:index', year)) \\\n", + " .first()\n", + "\n", + " # Select the land cover band.\n", + " landcover = nlcd.select('landcover')\n", + " return ui.Map.Layer(landcover, {}, year)\n", + "\n", + "\n", + "# Create a dictionary with each year as the key\n", + "# and its corresponding NLCD image layer as the value.\n", + "images = {\n", + " '2001': getNLCD('2001'),\n", + " '2004': getNLCD('2004'),\n", + " '2006': getNLCD('2006'),\n", + " '2008': getNLCD('2008'),\n", + " '2011': getNLCD('2011'),\n", + " '2013': getNLCD('2013'),\n", + " '2016': getNLCD('2016'),\n", + " '2019': getNLCD('2019'),\n", + "}\n", + "\n", + "#\n", + "# Set up the maps and control widgets\n", + "#\n", + "\n", + "# Create the left map, and have it display the first layer.\n", + "leftMap = ui.Map()\n", + "leftMap.setControlVisibility(False)\n", + "leftSelector = addLayerSelector(leftMap, 0, 'top-left')\n", + "\n", + "# Create the right map, and have it display the last layer.\n", + "rightMap = ui.Map()\n", + "rightMap.setControlVisibility(True)\n", + "rightSelector = addLayerSelector(rightMap, 7, 'top-right')\n", + "\n", + "# Adds a layer selection widget to the given map, to allow users to\n", + "# change which image is displayed in the associated map.\n", + "def addLayerSelector(mapToChange, defaultValue, position):\n", + " label = ui.Label('Select a year:')\n", + "\n", + " # This function changes the given map to show the selected image.\n", + " def updateMap(selection):\n", + " mapToChange.layers().set(0, images[selection])\n", + "\n", + "\n", + " # Configure a selection dropdown to allow the user to choose\n", + " # between images, and set the map to update when a user\n", + " # makes a selection.\n", + " select = ui.Select({\n", + " 'items': Object.keys(images),\n", + " 'onChange': updateMap\n", + " })\n", + " select.setValue(Object.keys(images)[defaultValue], True)\n", + "\n", + " controlPanel =\n", + " ui.Panel({\n", + " 'widgets': [label, select],\n", + " 'style': {\n", + " 'position': position\n", + " }\n", + " })\n", + "\n", + " mapToChange.add(controlPanel)\n", + "\n", + "\n", + "# Set the legend title.\n", + "title = 'NLCD Land Cover Classification'\n", + "\n", + "# Set the legend position.\n", + "position = 'bottom-right'\n", + "\n", + "# Define a dictionary that will be used to make a legend\n", + "# Reference: https:#code.earthengine.google.com/74ffc1eb0caabbbfaea535537829dda5\n", + "dict = {\n", + " 'names': [\n", + " '11\tOpen Water',\n", + " '12\tPerennial Ice/Snow',\n", + " '21\tDeveloped, Open Space',\n", + " '22\tDeveloped, Low Intensity',\n", + " '23\tDeveloped, Medium Intensity',\n", + " '24\tDeveloped, High Intensity',\n", + " '31\tBarren Land (Rock/Sand/Clay)',\n", + " '41\tDeciduous Forest',\n", + " '42\tEvergreen Forest',\n", + " '43\tMixed Forest',\n", + " '51\tDwarf Scrub',\n", + " '52\tShrub/Scrub',\n", + " '71\tGrassland/Herbaceous',\n", + " '72\tSedge/Herbaceous',\n", + " '73\tLichens',\n", + " '74\tMoss',\n", + " '81\tPasture/Hay',\n", + " '82\tCultivated Crops',\n", + " '90\tWoody Wetlands',\n", + " '95\tEmergent Herbaceous Wetlands',\n", + " ],\n", + "\n", + " 'colors': [\n", + " '#466b9f', '#d1def8', '#dec5c5', '#d99282', '#eb0000',\n", + " '#ab0000',\n", + " '#b3ac9f', '#68ab5f', '#1c5f2c', '#b5c58f', '#af963c',\n", + " '#ccb879',\n", + " '#dfdfc2', '#d1d182', '#a3cc51', '#82ba9e', '#dcd939',\n", + " '#ab6c28',\n", + " '#b8d9eb', '#6c9fb8',\n", + " ]\n", + "}\n", + "\n", + "# Create a panel to hold the legend widget.\n", + "legend = ui.Panel({\n", + " 'style': {\n", + " 'position': position,\n", + " 'padding': '8px 15px'\n", + " }\n", + "})\n", + "\n", + "# Function to generate the legend.\n", + "def addCategoricalLegend(panel, dict, title):\n", + "\n", + " # Create and add the legend title.\n", + " legendTitle = ui.Label({\n", + " 'value': title,\n", + " 'style': {\n", + " 'fontWeight': 'bold',\n", + " 'fontSize': '18px',\n", + " 'margin': '0 0 4px 0',\n", + " 'padding': '0'\n", + " }\n", + " })\n", + " panel.add(legendTitle)\n", + "\n", + " loading = ui.Label('Loading legend...', {\n", + " 'margin': '2px 0 4px 0'\n", + " })\n", + " panel.add(loading)\n", + "\n", + " # Creates and styles 1 row of the legend.\n", + " def makeRow(color, name):\n", + " # Create the label that is actually the colored box.\n", + " colorBox = ui.Label({\n", + " 'style': {\n", + " 'backgroundColor': color,\n", + " # Use padding to give the box height and width.\n", + " 'padding': '8px',\n", + " 'margin': '0 0 4px 0'\n", + " }\n", + " })\n", + "\n", + " # Create the label filled with the description text.\n", + " description = ui.Label({\n", + " 'value': name,\n", + " 'style': {\n", + " 'margin': '0 0 4px 6px'\n", + " }\n", + " })\n", + "\n", + " return ui.Panel({\n", + " 'widgets': [colorBox, description],\n", + " 'layout': ui.Panel.Layout.Flow('horizontal')\n", + " })\n", + " \n", + "\n", + " # Get the list of palette colors and class names from the image.\n", + " palette = dict.colors\n", + " names = dict.names\n", + " loading.style(**).set('shown', False)\n", + "\n", + " for i in range(0, names.length, 1):\n", + " panel.add(makeRow(palette[i], names[i]))\n", + "\n", + "\n", + " rightMap.add(panel)\n", + "\n", + "\n", + "\n", + "addCategoricalLegend(legend, dict, title)\n", + "\n", + "#\n", + "# Tie everything together\n", + "#\n", + "\n", + "# Create a SplitPanel to hold the adjacent, linked maps.\n", + "splitPanel = ui.SplitPanel({\n", + " 'firstPanel': leftMap,\n", + " 'secondPanel': rightMap,\n", + " 'wipe': True,\n", + " 'style': {\n", + " 'stretch': 'both'\n", + " }\n", + "})\n", + "\n", + "# Set the SplitPanel as the only thing in the UI root.\n", + "ui.root.widgets().reset([splitPanel])\n", + "linker = ui.Map.Linker([leftMap, rightMap])\n", + "leftMap.setCenter(-100, 40, 4)\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63a Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63a Checkpoint.js new file mode 100644 index 0000000..dda60ec --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63a Checkpoint.js @@ -0,0 +1,214 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps +// Checkpoint: F63a +// Author: Qiusheng Wu +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// Get an NLCD image by year. +var getNLCD = function(year) { + // Import the NLCD collection. + var dataset = ee.ImageCollection( + 'USGS/NLCD_RELEASES/2019_REL/NLCD'); + + // Filter the collection by year. + var nlcd = dataset.filter(ee.Filter.eq('system:index', year)) + .first(); + + // Select the land cover band. + var landcover = nlcd.select('landcover'); + return ui.Map.Layer(landcover, {}, year); +}; + +// Create a dictionary with each year as the key +// and its corresponding NLCD image layer as the value. +var images = { + '2001': getNLCD('2001'), + '2004': getNLCD('2004'), + '2006': getNLCD('2006'), + '2008': getNLCD('2008'), + '2011': getNLCD('2011'), + '2013': getNLCD('2013'), + '2016': getNLCD('2016'), + '2019': getNLCD('2019'), +}; + +/* +* Set up the maps and control widgets +*/ + +// Create the left map, and have it display the first layer. +var leftMap = ui.Map(); +leftMap.setControlVisibility(false); +var leftSelector = addLayerSelector(leftMap, 0, 'top-left'); + +// Create the right map, and have it display the last layer. +var rightMap = ui.Map(); +rightMap.setControlVisibility(true); +var rightSelector = addLayerSelector(rightMap, 7, 'top-right'); + +// Adds a layer selection widget to the given map, to allow users to +// change which image is displayed in the associated map. +function addLayerSelector(mapToChange, defaultValue, position) { + var label = ui.Label('Select a year:'); + + // This function changes the given map to show the selected image. + function updateMap(selection) { + mapToChange.layers().set(0, images[selection]); + } + + // Configure a selection dropdown to allow the user to choose + // between images, and set the map to update when a user + // makes a selection. + var select = ui.Select({ + items: Object.keys(images), + onChange: updateMap + }); + select.setValue(Object.keys(images)[defaultValue], true); + + var controlPanel = + ui.Panel({ + widgets: [label, select], + style: { + position: position + } + }); + + mapToChange.add(controlPanel); +} + +// Set the legend title. +var title = 'NLCD Land Cover Classification'; + +// Set the legend position. +var position = 'bottom-right'; + +// Define a dictionary that will be used to make a legend +// Reference: https://code.earthengine.google.com/74ffc1eb0caabbbfaea535537829dda5 +var dict = { + 'names': [ + '11 Open Water', + '12 Perennial Ice/Snow', + '21 Developed, Open Space', + '22 Developed, Low Intensity', + '23 Developed, Medium Intensity', + '24 Developed, High Intensity', + '31 Barren Land (Rock/Sand/Clay)', + '41 Deciduous Forest', + '42 Evergreen Forest', + '43 Mixed Forest', + '51 Dwarf Scrub', + '52 Shrub/Scrub', + '71 Grassland/Herbaceous', + '72 Sedge/Herbaceous', + '73 Lichens', + '74 Moss', + '81 Pasture/Hay', + '82 Cultivated Crops', + '90 Woody Wetlands', + '95 Emergent Herbaceous Wetlands', + ], + + 'colors': [ + '#466b9f', '#d1def8', '#dec5c5', '#d99282', '#eb0000', + '#ab0000', + '#b3ac9f', '#68ab5f', '#1c5f2c', '#b5c58f', '#af963c', + '#ccb879', + '#dfdfc2', '#d1d182', '#a3cc51', '#82ba9e', '#dcd939', + '#ab6c28', + '#b8d9eb', '#6c9fb8', + ] +}; + +// Create a panel to hold the legend widget. +var legend = ui.Panel({ + style: { + position: position, + padding: '8px 15px' + } +}); + +// Function to generate the legend. +function addCategoricalLegend(panel, dict, title) { + + // Create and add the legend title. + var legendTitle = ui.Label({ + value: title, + style: { + fontWeight: 'bold', + fontSize: '18px', + margin: '0 0 4px 0', + padding: '0' + } + }); + panel.add(legendTitle); + + var loading = ui.Label('Loading legend...', { + margin: '2px 0 4px 0' + }); + panel.add(loading); + + // Creates and styles 1 row of the legend. + var makeRow = function(color, name) { + // Create the label that is actually the colored box. + var colorBox = ui.Label({ + style: { + backgroundColor: color, + // Use padding to give the box height and width. + padding: '8px', + margin: '0 0 4px 0' + } + }); + + // Create the label filled with the description text. + var description = ui.Label({ + value: name, + style: { + margin: '0 0 4px 6px' + } + }); + + return ui.Panel({ + widgets: [colorBox, description], + layout: ui.Panel.Layout.Flow('horizontal') + }); + }; + + // Get the list of palette colors and class names from the image. + var palette = dict.colors; + var names = dict.names; + loading.style().set('shown', false); + + for (var i = 0; i < names.length; i++) { + panel.add(makeRow(palette[i], names[i])); + } + + rightMap.add(panel); + +} + +addCategoricalLegend(legend, dict, title); + +/* +* Tie everything together +*/ + +// Create a SplitPanel to hold the adjacent, linked maps. +var splitPanel = ui.SplitPanel({ + firstPanel: leftMap, + secondPanel: rightMap, + wipe: true, + style: { + stretch: 'both' + } +}); + +// Set the SplitPanel as the only thing in the UI root. +ui.root.widgets().reset([splitPanel]); +var linker = ui.Map.Linker([leftMap, rightMap]); +leftMap.setCenter(-100, 40, 4); + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63a Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63a Checkpoint.py new file mode 100644 index 0000000..8822c6f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63a Checkpoint.py @@ -0,0 +1,220 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps +# Checkpoint: F63a +# Author: Qiusheng Wu +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Get an NLCD image by year. +def getNLCD(year): + # Import the NLCD collection. + dataset = ee.ImageCollection( + 'USGS/NLCD_RELEASES/2019_REL/NLCD') + + # Filter the collection by year. + nlcd = dataset.filter(ee.Filter.eq('system:index', year)) \ + .first() + + # Select the land cover band. + landcover = nlcd.select('landcover') + return ui.Map.Layer(landcover, {}, year) + + +# Create a dictionary with each year as the key +# and its corresponding NLCD image layer as the value. +images = { + '2001': getNLCD('2001'), + '2004': getNLCD('2004'), + '2006': getNLCD('2006'), + '2008': getNLCD('2008'), + '2011': getNLCD('2011'), + '2013': getNLCD('2013'), + '2016': getNLCD('2016'), + '2019': getNLCD('2019'), +} + +# +# Set up the maps and control widgets +# + +# Create the left map, and have it display the first layer. +leftMap = ui.Map() +leftMap.setControlVisibility(False) +leftSelector = addLayerSelector(leftMap, 0, 'top-left') + +# Create the right map, and have it display the last layer. +rightMap = ui.Map() +rightMap.setControlVisibility(True) +rightSelector = addLayerSelector(rightMap, 7, 'top-right') + +# Adds a layer selection widget to the given map, to allow users to +# change which image is displayed in the associated map. +def addLayerSelector(mapToChange, defaultValue, position): + label = ui.Label('Select a year:') + + # This function changes the given map to show the selected image. + def updateMap(selection): + mapToChange.layers().set(0, images[selection]) + + + # Configure a selection dropdown to allow the user to choose + # between images, and set the map to update when a user + # makes a selection. + select = ui.Select({ + 'items': Object.keys(images), + 'onChange': updateMap + }) + select.setValue(Object.keys(images)[defaultValue], True) + + controlPanel = + ui.Panel({ + 'widgets': [label, select], + 'style': { + 'position': position + } + }) + + mapToChange.add(controlPanel) + + +# Set the legend title. +title = 'NLCD Land Cover Classification' + +# Set the legend position. +position = 'bottom-right' + +# Define a dictionary that will be used to make a legend +# Reference: https:#code.earthengine.google.com/74ffc1eb0caabbbfaea535537829dda5 +dict = { + 'names': [ + '11 Open Water', + '12 Perennial Ice/Snow', + '21 Developed, Open Space', + '22 Developed, Low Intensity', + '23 Developed, Medium Intensity', + '24 Developed, High Intensity', + '31 Barren Land (Rock/Sand/Clay)', + '41 Deciduous Forest', + '42 Evergreen Forest', + '43 Mixed Forest', + '51 Dwarf Scrub', + '52 Shrub/Scrub', + '71 Grassland/Herbaceous', + '72 Sedge/Herbaceous', + '73 Lichens', + '74 Moss', + '81 Pasture/Hay', + '82 Cultivated Crops', + '90 Woody Wetlands', + '95 Emergent Herbaceous Wetlands', + ], + + 'colors': [ + '#466b9f', '#d1def8', '#dec5c5', '#d99282', '#eb0000', + '#ab0000', + '#b3ac9f', '#68ab5f', '#1c5f2c', '#b5c58f', '#af963c', + '#ccb879', + '#dfdfc2', '#d1d182', '#a3cc51', '#82ba9e', '#dcd939', + '#ab6c28', + '#b8d9eb', '#6c9fb8', + ] +} + +# Create a panel to hold the legend widget. +legend = ui.Panel({ + 'style': { + 'position': position, + 'padding': '8px 15px' + } +}) + +# Function to generate the legend. +def addCategoricalLegend(panel, dict, title): + + # Create and add the legend title. + legendTitle = ui.Label({ + 'value': title, + 'style': { + 'fontWeight': 'bold', + 'fontSize': '18px', + 'margin': '0 0 4px 0', + 'padding': '0' + } + }) + panel.add(legendTitle) + + loading = ui.Label('Loading legend...', { + 'margin': '2px 0 4px 0' + }) + panel.add(loading) + + # Creates and styles 1 row of the legend. + def makeRow(color, name): + # Create the label that is actually the colored box. + colorBox = ui.Label({ + 'style': { + 'backgroundColor': color, + # Use padding to give the box height and width. + 'padding': '8px', + 'margin': '0 0 4px 0' + } + }) + + # Create the label filled with the description text. + description = ui.Label({ + 'value': name, + 'style': { + 'margin': '0 0 4px 6px' + } + }) + + return ui.Panel({ + 'widgets': [colorBox, description], + 'layout': ui.Panel.Layout.Flow('horizontal') + }) + + + # Get the list of palette colors and class names from the image. + palette = dict.colors + names = dict.names + loading.style(**).set('shown', False) + + for i in range(0, names.length, 1): + panel.add(makeRow(palette[i], names[i])) + + + rightMap.add(panel) + + + +addCategoricalLegend(legend, dict, title) + +# +# Tie everything together +# + +# Create a SplitPanel to hold the adjacent, linked maps. +splitPanel = ui.SplitPanel({ + 'firstPanel': leftMap, + 'secondPanel': rightMap, + 'wipe': True, + 'style': { + 'stretch': 'both' + } +}) + +# Set the SplitPanel as the only thing in the UI root. +ui.root.widgets().reset([splitPanel]) +linker = ui.Map.Linker([leftMap, rightMap]) +leftMap.setCenter(-100, 40, 4) + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63b Checkpoint.ipynb new file mode 100644 index 0000000..9bba5a5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63b Checkpoint.ipynb @@ -0,0 +1,122 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps\n", + "# Checkpoint: F63b\n", + "# Author: Qiusheng Wu\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "\n", + "'Follow the steps below to set up a conda environment and install geemap. More information about the geemap installation can be found at https':#geemap.Org/installation.\n", + "\n", + "First, you need to download and install Miniconda or Anaconda on your computer. After installation, open the Anaconda Prompt. If you are using Windows, go to Start Menu > Anaconda3 > Anaconda Prompt. If you are using macOS or Linux, open the Terminal. Enter the following commands into the Anaconda Prompt or Terminal and follow the on-screen instructions to create a conda environment and install geemap.\n", + "\n", + "conda create -n gee python=3.9\n", + "conda activate gee\n", + "conda install mamba -c conda-forge\n", + "mamba install geemap voila -c conda-forge\n", + "\n", + "\n", + "Note that mamba is a reimplementation of the conda package manager in C++. It enables the parallel downloading of repository data and package files using multithreading and usually resolves dependencies much faster than conda. Once geemap has been installed successfully, enter the following commands into the Terminal and press Enter to launch a Jupyter notebook in your browser.\n", + "\n", + "conda activate gee\n", + "jupyter notebook\n", + "\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63b Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63b Checkpoint.js new file mode 100644 index 0000000..424fc04 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63b Checkpoint.js @@ -0,0 +1,30 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps +// Checkpoint: F63b +// Author: Qiusheng Wu +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Follow the steps below to set up a conda environment and install geemap. More information about the geemap installation can be found at https://geemap.org/installation. + +First, you need to download and install Miniconda or Anaconda on your computer. After installation, open the Anaconda Prompt. If you are using Windows, go to Start Menu > Anaconda3 > Anaconda Prompt. If you are using macOS or Linux, open the Terminal. Enter the following commands into the Anaconda Prompt or Terminal and follow the on-screen instructions to create a conda environment and install geemap. + +conda create -n gee python=3.9 +conda activate gee +conda install mamba -c conda-forge +mamba install geemap voila -c conda-forge + + +Note that mamba is a reimplementation of the conda package manager in C++. It enables the parallel downloading of repository data and package files using multithreading and usually resolves dependencies much faster than conda. Once geemap has been installed successfully, enter the following commands into the Terminal and press Enter to launch a Jupyter notebook in your browser. + +conda activate gee +jupyter notebook + + + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63b Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63b Checkpoint.py new file mode 100644 index 0000000..a1ec3aa --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63b Checkpoint.py @@ -0,0 +1,36 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps +# Checkpoint: F63b +# Author: Qiusheng Wu +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +'Follow the steps below to set up a conda environment and install geemap. More information about the geemap installation can be found at https':#geemap.Org/installation. + +First, you need to download and install Miniconda or Anaconda on your computer. After installation, open the Anaconda Prompt. If you are using Windows, go to Start Menu > Anaconda3 > Anaconda Prompt. If you are using macOS or Linux, open the Terminal. Enter the following commands into the Anaconda Prompt or Terminal and follow the on-screen instructions to create a conda environment and install geemap. + +conda create -n gee python=3.9 +conda activate gee +conda install mamba -c conda-forge +mamba install geemap voila -c conda-forge + + +Note that mamba is a reimplementation of the conda package manager in C++. It enables the parallel downloading of repository data and package files using multithreading and usually resolves dependencies much faster than conda. Once geemap has been installed successfully, enter the following commands into the Terminal and press Enter to launch a Jupyter notebook in your browser. + +conda activate gee +jupyter notebook + + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63c Checkpoint.ipynb new file mode 100644 index 0000000..97ba77d --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63c Checkpoint.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps\n", + "# Checkpoint: F63c\n", + "# Author: Qiusheng Wu\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "\n", + "Enter the link below into your browser to see how your code should look at this point\n", + "\n", + "'https':#geemap.Org/notebooks/nlcd_app\n", + "\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63c Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63c Checkpoint.js new file mode 100644 index 0000000..00f66ed --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63c Checkpoint.js @@ -0,0 +1,19 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps +// Checkpoint: F63c +// Author: Qiusheng Wu +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Enter the link below into your browser to see how your code should look at this point + +https://geemap.org/notebooks/nlcd_app + + + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63c Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63c Checkpoint.py new file mode 100644 index 0000000..a92c88a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63c Checkpoint.py @@ -0,0 +1,25 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps +# Checkpoint: F63c +# Author: Qiusheng Wu +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Enter the link below into your browser to see how your code should look at this point + +'https':#geemap.Org/notebooks/nlcd_app + + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63d Checkpoint.ipynb new file mode 100644 index 0000000..a6c2258 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63d Checkpoint.ipynb @@ -0,0 +1,118 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps\n", + "# Checkpoint: F63d\n", + "# Author: Qiusheng Wu\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "\n", + "Enter the link below into your browser to see how your code should look at this point\n", + "\n", + "'https':#github.com/giswqs/earthengine-apps\n", + "\n", + "\n", + "'Note from Ellen below': \"Congratulations! You have successfully deployed the Earth Engine App on Heroku. \"\n", + " 'Does not work although I followed the instructions':'). https':#docs.google.com/document/d/197jvxxajqEfCHbuw_2EcxHAv83Pjka36/edit?usp=sharing&ouid=101065852418423274055&rtpof=True&sd=True\n", + "Author will have to test. I can test it if desired. Others are also welcome to test this.\n", + "Was tested and closed by author in beginning of March. Feel bad that is happening right now.\n", + "@jeffcardille@gmail.com\n", + "Show less\n", + "Hi, I am also tagging Quisheng @qwu18@utk.edu here. Perhaps this got missed due to the editing comments. Hi Qiusheng, I ran into an issue here. Can you please check once more please? Thanks.\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63d Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63d Checkpoint.js new file mode 100644 index 0000000..1b6512e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63d Checkpoint.js @@ -0,0 +1,26 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps +// Checkpoint: F63d +// Author: Qiusheng Wu +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Enter the link below into your browser to see how your code should look at this point + +https://github.com/giswqs/earthengine-apps + + +Note from Ellen below: "Congratulations! You have successfully deployed the Earth Engine App on Heroku. " +Does not work although I followed the instructions :). https://docs.google.com/document/d/197jvxxajqEfCHbuw_2EcxHAv83Pjka36/edit?usp=sharing&ouid=101065852418423274055&rtpof=true&sd=true +Author will have to test. I can test it if desired. Others are also welcome to test this. +Was tested and closed by author in beginning of March. Feel bad that is happening right now. +@jeffcardille@gmail.com +Show less +Hi, I am also tagging Quisheng @qwu18@utk.edu here. Perhaps this got missed due to the editing comments. Hi Qiusheng, I ran into an issue here. Can you please check once more please? Thanks. + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63d Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63d Checkpoint.py new file mode 100644 index 0000000..9400ac9 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.3 Basic UI and Apps/F63d Checkpoint.py @@ -0,0 +1,32 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.3 Sharing Work in Earth Engine: Basic UI and Apps +# Checkpoint: F63d +# Author: Qiusheng Wu +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Enter the link below into your browser to see how your code should look at this point + +'https':#github.com/giswqs/earthengine-apps + + +'Note from Ellen below': "Congratulations! You have successfully deployed the Earth Engine App on Heroku. " + 'Does not work although I followed the instructions':'). https':#docs.google.com/document/d/197jvxxajqEfCHbuw_2EcxHAv83Pjka36/edit?usp=sharing&ouid=101065852418423274055&rtpof=True&sd=True +Author will have to test. I can test it if desired. Others are also welcome to test this. +Was tested and closed by author in beginning of March. Feel bad that is happening right now. +@jeffcardille@gmail.com +Show less +Hi, I am also tagging Quisheng @qwu18@utk.edu here. Perhaps this got missed due to the editing comments. Hi Qiusheng, I ran into an issue here. Can you please check once more please? Thanks. + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64a Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64a Checkpoint.ipynb new file mode 100644 index 0000000..713f472 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64a Checkpoint.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.4 Combining R and Earth Engine\n", + "# Checkpoint: F64a\n", + "# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "'Comment from Ellen':\n", + "If possible, perhaps put this into a checkpoint? Also, one option (if links are allowed in that), 'to refer to the link': 'https':#r-spatial.github.io/rgee/reference/ee_install_set_pyenv.html\n", + "Installation is always tricky.\n", + "'Till today I am still having issue with the Anaconda install in Windows' :).\n", + "\n", + "Installing rgee can be challenging, since it has dependencies in both R and Python. Thanks to the fantastic work of CRAN managing R packages, installation in R should not be a problem. Nevertheless, some difficulties can appear when users try to connect both languages. If you are a new Python user, we recommend using the built-in ee_install function. In Rstudio, press Ctrl + Enter (or just Enter on macOS) to execute the code line by line.\n", + "\n", + "library(rgee)\n", + "'rgee':'':ee_install()\n", + "\n", + "\n", + "'The ee_install function will set up everything for you. In short, it performs the following tasks': (1) Creating a Python environment, (2) creating an environment variable, EARTHENGINE_PYTHON, that stores your Python interpreter path (which will help rgee know where to look the next time you log in), and (3) installing the dependencies in the previously created environment. Alternatively, users who want to use their own Python environment could run, instead of ee_install, one of the following options, depending on their operating system.\n", + "\n", + "# IMPORTANT: Change 'py_path' argument according to your own Python PATH\n", + "## For Anaconda users - Windows OS\n", + "## Anaconda users must run \"where anaconda\" in the console.\n", + "win_py_path = paste0(\n", + " \"C:/Users/UNICORN/AppData/Local/Programs/Python/\",\n", + " \"Python37/python.exe\"\n", + ")\n", + "ee_install_set_pyenv(\n", + " py_path = win_py_path,\n", + " py_env = NULL # Change it for your own Python ENV\n", + ")\n", + "\n", + "## For Anaconda users - MacOS users\n", + "## Anaconda users must run \"where anaconda\" in the console.\n", + "ee_install_set_pyenv(\n", + " py_path = \"/Users/UNICORN/opt/anaconda3/bin/python\",\n", + " py_env = NULL # Change it for your own Python ENV\n", + ")\n", + "\n", + "## For Miniconda users - Windows OS\n", + "win_py_path = paste0(\n", + " \"C:/Users/UNICORN/AppData/Local/r-miniconda/envs/rgee/\",\n", + " \"python.exe\"\n", + ")\n", + "ee_install_set_pyenv(\n", + " py_path = win_py_path,\n", + " py_env = \"rgee\" # Change it for your own Python ENV\n", + ")\n", + "\n", + "## For Miniconda users - Linux/MacOS users\n", + "unix_py_path = paste0(\n", + " \"/home/UNICORN/.local/share/r-miniconda/envs/\",\n", + " \"rgee/bin/python3\"\n", + ")\n", + "ee_install_set_pyenv(\n", + " py_path = unix_py_path,\n", + " py_env = \"rgee\" # Change it for your own Python ENV\n", + ")\n", + "\n", + "## For virtualenv users - Linux/MacOS users\n", + "ee_install_set_pyenv(\n", + " py_path = \"/home/UNICORN/.virtualenvs/rgee/bin/python\",\n", + " py_env = \"rgee\" # Change it for your own Python ENV\n", + ")\n", + "\n", + "## For Python root user - Linux/MacOS users\n", + "ee_install_set_pyenv(\n", + " py_path = \"/usr/bin/python3\",\n", + " py_env = NULL,\n", + " Renviron = \"global\" # Save ENV variables in the global .Renv file\n", + ")\n", + "\n", + "ee_install_set_pyenv(\n", + " py_path = \"/usr/bin/python3\",\n", + " py_env = NULL,\n", + " Renviron = \"local\" # Save ENV variables in a local .Renv file\n", + ")\n", + "\n", + "\n", + "'Regardless of whether you are using ee_install or ee_install_set_pyenv, this only needs to be run once. Also, take into account that the Python PATH you set must have installed the rgee Python dependencies. The use of Miniconda/Anaconda is mandatory for Windows users; Linux and MacOS users could instead use virtualenv. After setting up your Python environment, you can use the function below to check the status of rgee. If you find any issue in the installation procedure, consider opening an issue at https':#github.com/r-spatial/rgee/issues/.\n", + "\n", + "ee_check() # Check non-R dependencies\n", + "\n", + "\n", + "\n", + "\n", + "Enter the link below into your browser to see how your code should look at this point\n", + "\n", + "'https':#github.com/giswqs/earthengine-apps\n", + "\n", + "\n", + "'Note from Ellen below': \"Congratulations! You have successfully deployed the Earth Engine App on Heroku. \"\n", + " 'Does not work although I followed the instructions':'). https':#docs.google.com/document/d/197jvxxajqEfCHbuw_2EcxHAv83Pjka36/edit?usp=sharing&ouid=101065852418423274055&rtpof=True&sd=True\n", + "Author will have to test. I can test it if desired. Others are also welcome to test this.\n", + "Was tested and closed by author in beginning of March. Feel bad that is happening right now.\n", + "@jeffcardille@gmail.com\n", + "Show less\n", + "Hi, I am also tagging Quisheng @qwu18@utk.edu here. Perhaps this got missed due to the editing comments. Hi Qiusheng, I ran into an issue here. Can you please check once more please? Thanks.\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64a Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64a Checkpoint.js new file mode 100644 index 0000000..b65e4f0 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64a Checkpoint.js @@ -0,0 +1,104 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.4 Combining R and Earth Engine +// Checkpoint: F64a +// Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Comment from Ellen: +If possible, perhaps put this into a checkpoint? Also, one option (if links are allowed in that), to refer to the link: https://r-spatial.github.io/rgee/reference/ee_install_set_pyenv.html +Installation is always tricky. +Till today I am still having issue with the Anaconda install in Windows :). + +Installing rgee can be challenging, since it has dependencies in both R and Python. Thanks to the fantastic work of CRAN managing R packages, installation in R should not be a problem. Nevertheless, some difficulties can appear when users try to connect both languages. If you are a new Python user, we recommend using the built-in ee_install function. In Rstudio, press Ctrl + Enter (or just Enter on macOS) to execute the code line by line. + +library(rgee) +rgee::ee_install() + + +The ee_install function will set up everything for you. In short, it performs the following tasks: (1) Creating a Python environment, (2) creating an environment variable, EARTHENGINE_PYTHON, that stores your Python interpreter path (which will help rgee know where to look the next time you log in), and (3) installing the dependencies in the previously created environment. Alternatively, users who want to use their own Python environment could run, instead of ee_install, one of the following options, depending on their operating system. + +# IMPORTANT: Change 'py_path' argument according to your own Python PATH +## For Anaconda users - Windows OS +## Anaconda users must run "where anaconda" in the console. +win_py_path = paste0( + "C:/Users/UNICORN/AppData/Local/Programs/Python/", + "Python37/python.exe" +) +ee_install_set_pyenv( + py_path = win_py_path, + py_env = NULL # Change it for your own Python ENV +) + +## For Anaconda users - MacOS users +## Anaconda users must run "where anaconda" in the console. +ee_install_set_pyenv( + py_path = "/Users/UNICORN/opt/anaconda3/bin/python", + py_env = NULL # Change it for your own Python ENV +) + +## For Miniconda users - Windows OS +win_py_path = paste0( + "C:/Users/UNICORN/AppData/Local/r-miniconda/envs/rgee/", + "python.exe" +) +ee_install_set_pyenv( + py_path = win_py_path, + py_env = "rgee" # Change it for your own Python ENV +) + +## For Miniconda users - Linux/MacOS users +unix_py_path = paste0( + "/home/UNICORN/.local/share/r-miniconda/envs/", + "rgee/bin/python3" +) +ee_install_set_pyenv( + py_path = unix_py_path, + py_env = "rgee" # Change it for your own Python ENV +) + +## For virtualenv users - Linux/MacOS users +ee_install_set_pyenv( + py_path = "/home/UNICORN/.virtualenvs/rgee/bin/python", + py_env = "rgee" # Change it for your own Python ENV +) + +## For Python root user - Linux/MacOS users +ee_install_set_pyenv( + py_path = "/usr/bin/python3", + py_env = NULL, + Renviron = "global" # Save ENV variables in the global .Renv file +) + +ee_install_set_pyenv( + py_path = "/usr/bin/python3", + py_env = NULL, + Renviron = "local" # Save ENV variables in a local .Renv file +) + + +Regardless of whether you are using ee_install or ee_install_set_pyenv, this only needs to be run once. Also, take into account that the Python PATH you set must have installed the rgee Python dependencies. The use of Miniconda/Anaconda is mandatory for Windows users; Linux and MacOS users could instead use virtualenv. After setting up your Python environment, you can use the function below to check the status of rgee. If you find any issue in the installation procedure, consider opening an issue at https://github.com/r-spatial/rgee/issues/. + +ee_check() # Check non-R dependencies + + + + +Enter the link below into your browser to see how your code should look at this point + +https://github.com/giswqs/earthengine-apps + + +Note from Ellen below: "Congratulations! You have successfully deployed the Earth Engine App on Heroku. " +Does not work although I followed the instructions :). https://docs.google.com/document/d/197jvxxajqEfCHbuw_2EcxHAv83Pjka36/edit?usp=sharing&ouid=101065852418423274055&rtpof=true&sd=true +Author will have to test. I can test it if desired. Others are also welcome to test this. +Was tested and closed by author in beginning of March. Feel bad that is happening right now. +@jeffcardille@gmail.com +Show less +Hi, I am also tagging Quisheng @qwu18@utk.edu here. Perhaps this got missed due to the editing comments. Hi Qiusheng, I ran into an issue here. Can you please check once more please? Thanks. + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64a Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64a Checkpoint.py new file mode 100644 index 0000000..698793e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64a Checkpoint.py @@ -0,0 +1,110 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.4 Combining R and Earth Engine +# Checkpoint: F64a +# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +'Comment from Ellen': +If possible, perhaps put this into a checkpoint? Also, one option (if links are allowed in that), 'to refer to the link': 'https':#r-spatial.github.io/rgee/reference/ee_install_set_pyenv.html +Installation is always tricky. +'Till today I am still having issue with the Anaconda install in Windows' :). + +Installing rgee can be challenging, since it has dependencies in both R and Python. Thanks to the fantastic work of CRAN managing R packages, installation in R should not be a problem. Nevertheless, some difficulties can appear when users try to connect both languages. If you are a new Python user, we recommend using the built-in ee_install function. In Rstudio, press Ctrl + Enter (or just Enter on macOS) to execute the code line by line. + +library(rgee) +'rgee':'':ee_install() + + +'The ee_install function will set up everything for you. In short, it performs the following tasks': (1) Creating a Python environment, (2) creating an environment variable, EARTHENGINE_PYTHON, that stores your Python interpreter path (which will help rgee know where to look the next time you log in), and (3) installing the dependencies in the previously created environment. Alternatively, users who want to use their own Python environment could run, instead of ee_install, one of the following options, depending on their operating system. + +# IMPORTANT: Change 'py_path' argument according to your own Python PATH +## For Anaconda users - Windows OS +## Anaconda users must run "where anaconda" in the console. +win_py_path = paste0( + "C:/Users/UNICORN/AppData/Local/Programs/Python/", + "Python37/python.exe" +) +ee_install_set_pyenv( + py_path = win_py_path, + py_env = NULL # Change it for your own Python ENV +) + +## For Anaconda users - MacOS users +## Anaconda users must run "where anaconda" in the console. +ee_install_set_pyenv( + py_path = "/Users/UNICORN/opt/anaconda3/bin/python", + py_env = NULL # Change it for your own Python ENV +) + +## For Miniconda users - Windows OS +win_py_path = paste0( + "C:/Users/UNICORN/AppData/Local/r-miniconda/envs/rgee/", + "python.exe" +) +ee_install_set_pyenv( + py_path = win_py_path, + py_env = "rgee" # Change it for your own Python ENV +) + +## For Miniconda users - Linux/MacOS users +unix_py_path = paste0( + "/home/UNICORN/.local/share/r-miniconda/envs/", + "rgee/bin/python3" +) +ee_install_set_pyenv( + py_path = unix_py_path, + py_env = "rgee" # Change it for your own Python ENV +) + +## For virtualenv users - Linux/MacOS users +ee_install_set_pyenv( + py_path = "/home/UNICORN/.virtualenvs/rgee/bin/python", + py_env = "rgee" # Change it for your own Python ENV +) + +## For Python root user - Linux/MacOS users +ee_install_set_pyenv( + py_path = "/usr/bin/python3", + py_env = NULL, + Renviron = "global" # Save ENV variables in the global .Renv file +) + +ee_install_set_pyenv( + py_path = "/usr/bin/python3", + py_env = NULL, + Renviron = "local" # Save ENV variables in a local .Renv file +) + + +'Regardless of whether you are using ee_install or ee_install_set_pyenv, this only needs to be run once. Also, take into account that the Python PATH you set must have installed the rgee Python dependencies. The use of Miniconda/Anaconda is mandatory for Windows users; Linux and MacOS users could instead use virtualenv. After setting up your Python environment, you can use the function below to check the status of rgee. If you find any issue in the installation procedure, consider opening an issue at https':#github.com/r-spatial/rgee/issues/. + +ee_check() # Check non-R dependencies + + + + +Enter the link below into your browser to see how your code should look at this point + +'https':#github.com/giswqs/earthengine-apps + + +'Note from Ellen below': "Congratulations! You have successfully deployed the Earth Engine App on Heroku. " + 'Does not work although I followed the instructions':'). https':#docs.google.com/document/d/197jvxxajqEfCHbuw_2EcxHAv83Pjka36/edit?usp=sharing&ouid=101065852418423274055&rtpof=True&sd=True +Author will have to test. I can test it if desired. Others are also welcome to test this. +Was tested and closed by author in beginning of March. Feel bad that is happening right now. +@jeffcardille@gmail.com +Show less +Hi, I am also tagging Quisheng @qwu18@utk.edu here. Perhaps this got missed due to the editing comments. Hi Qiusheng, I ran into an issue here. Can you please check once more please? Thanks. + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64b Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64b Checkpoint.ipynb new file mode 100644 index 0000000..cb87df8 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64b Checkpoint.ipynb @@ -0,0 +1,110 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.4 Combining R and Earth Engine\n", + "# Checkpoint: F64b\n", + "# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "Enter the link below into your browser to see how your code should look at this point\n", + "\n", + "'https':#github.com/csaybar/rgee_examples/blob/main/script01.R\n", + "\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64b Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64b Checkpoint.js new file mode 100644 index 0000000..5347900 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64b Checkpoint.js @@ -0,0 +1,18 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.4 Combining R and Earth Engine +// Checkpoint: F64b +// Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +https://github.com/csaybar/rgee_examples/blob/main/script01.R + + + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64b Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64b Checkpoint.py new file mode 100644 index 0000000..461ae46 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64b Checkpoint.py @@ -0,0 +1,24 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.4 Combining R and Earth Engine +# Checkpoint: F64b +# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +'https':#github.com/csaybar/rgee_examples/blob/main/script01.R + + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64c Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64c Checkpoint.ipynb new file mode 100644 index 0000000..c5969e9 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64c Checkpoint.ipynb @@ -0,0 +1,110 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.4 Combining R and Earth Engine\n", + "# Checkpoint: F64c\n", + "# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "Enter the link below into your browser to see how your code should look at this point\n", + "\n", + "'https':#github.com/csaybar/rgee_examples/blob/main/script02.R\n", + "\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64c Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64c Checkpoint.js new file mode 100644 index 0000000..c243120 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64c Checkpoint.js @@ -0,0 +1,18 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.4 Combining R and Earth Engine +// Checkpoint: F64c +// Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +https://github.com/csaybar/rgee_examples/blob/main/script02.R + + + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64c Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64c Checkpoint.py new file mode 100644 index 0000000..6c552e5 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64c Checkpoint.py @@ -0,0 +1,24 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.4 Combining R and Earth Engine +# Checkpoint: F64c +# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +'https':#github.com/csaybar/rgee_examples/blob/main/script02.R + + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64d Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64d Checkpoint.ipynb new file mode 100644 index 0000000..b8b050f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64d Checkpoint.ipynb @@ -0,0 +1,110 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.4 Combining R and Earth Engine\n", + "# Checkpoint: F64d\n", + "# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "Enter the link below into your browser to see how your code should look at this point\n", + "\n", + "'https':#github.com/csaybar/rgee_examples/blob/main/script03.R\n", + "\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64d Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64d Checkpoint.js new file mode 100644 index 0000000..1a7540f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64d Checkpoint.js @@ -0,0 +1,18 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.4 Combining R and Earth Engine +// Checkpoint: F64d +// Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +https://github.com/csaybar/rgee_examples/blob/main/script03.R + + + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64d Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64d Checkpoint.py new file mode 100644 index 0000000..7489c8a --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64d Checkpoint.py @@ -0,0 +1,24 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.4 Combining R and Earth Engine +# Checkpoint: F64d +# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +'https':#github.com/csaybar/rgee_examples/blob/main/script03.R + + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64e Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64e Checkpoint.ipynb new file mode 100644 index 0000000..7a788cd --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64e Checkpoint.ipynb @@ -0,0 +1,110 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.4 Combining R and Earth Engine\n", + "# Checkpoint: F64e\n", + "# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "Enter the link below into your browser to see how your code should look at this point\n", + "\n", + "'https':#github.com/csaybar/rgee_examples/blob/main/script04.R\n", + "\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64e Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64e Checkpoint.js new file mode 100644 index 0000000..47029d3 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64e Checkpoint.js @@ -0,0 +1,18 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.4 Combining R and Earth Engine +// Checkpoint: F64e +// Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +https://github.com/csaybar/rgee_examples/blob/main/script04.R + + + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64e Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64e Checkpoint.py new file mode 100644 index 0000000..fa48fb4 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64e Checkpoint.py @@ -0,0 +1,24 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.4 Combining R and Earth Engine +# Checkpoint: F64e +# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +'https':#github.com/csaybar/rgee_examples/blob/main/script04.R + + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64f Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64f Checkpoint.ipynb new file mode 100644 index 0000000..f069200 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64f Checkpoint.ipynb @@ -0,0 +1,130 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.4 Combining R and Earth Engine\n", + "# Checkpoint: F64f\n", + "# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "LandsatLST = require(\n", + " 'users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js')\n", + "\n", + "geometry = ee.Geometry.Rectangle([-8.91, 40.0, -8.3, 40.4])\n", + "satellite = 'L8'\n", + "date_start = '2018-05-15'\n", + "date_end = '2018-05-31'\n", + "use_ndvi = True\n", + "\n", + "LandsatColl = LandsatLST.collection(satellite, date_start,\n", + " date_end, geometry, use_ndvi)\n", + "\n", + "exImage = LandsatColl.first()\n", + "\n", + "cmap = ['blue', 'cyan', 'green', 'yellow', 'red']\n", + "\n", + "Map.centerObject(geometry)\n", + "\n", + "Map.addLayer(exImage.select('LST'), {\n", + " 'min': 290,\n", + " 'max': 320,\n", + " 'palette': cmap\n", + "}, 'LST')\n", + "\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64f Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64f Checkpoint.js new file mode 100644 index 0000000..d678a53 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64f Checkpoint.js @@ -0,0 +1,38 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.4 Combining R and Earth Engine +// Checkpoint: F64f +// Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +var LandsatLST = require( + 'users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js'); + +var geometry = ee.Geometry.Rectangle([-8.91, 40.0, -8.3, 40.4]); +var satellite = 'L8'; +var date_start = '2018-05-15'; +var date_end = '2018-05-31'; +var use_ndvi = true; + +var LandsatColl = LandsatLST.collection(satellite, date_start, + date_end, geometry, use_ndvi); + +var exImage = LandsatColl.first(); + +var cmap = ['blue', 'cyan', 'green', 'yellow', 'red']; + +Map.centerObject(geometry); + +Map.addLayer(exImage.select('LST'), { + min: 290, + max: 320, + palette: cmap +}, 'LST') + + + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64f Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64f Checkpoint.py new file mode 100644 index 0000000..a5265b6 --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64f Checkpoint.py @@ -0,0 +1,44 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.4 Combining R and Earth Engine +# Checkpoint: F64f +# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LandsatLST = require( + 'users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js') + +geometry = ee.Geometry.Rectangle([-8.91, 40.0, -8.3, 40.4]) +satellite = 'L8' +date_start = '2018-05-15' +date_end = '2018-05-31' +use_ndvi = True + +LandsatColl = LandsatLST.collection(satellite, date_start, + date_end, geometry, use_ndvi) + +exImage = LandsatColl.first() + +cmap = ['blue', 'cyan', 'green', 'yellow', 'red'] + +Map.centerObject(geometry) + +Map.addLayer(exImage.select('LST'), { + 'min': 290, + 'max': 320, + 'palette': cmap +}, 'LST') + + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64g Checkpoint.ipynb b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64g Checkpoint.ipynb new file mode 100644 index 0000000..c4a515e --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64g Checkpoint.ipynb @@ -0,0 +1,110 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "import ee\n", + "import geemap" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map = geemap.Map(center=[40, -100], zoom=4)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Earth Engine Python script" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# Add Earth Engine dataset\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "# Chapter: F6.4 Combining R and Earth Engine\n", + "# Checkpoint: F64g\n", + "# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza\n", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "\n", + "Enter the link below into your browser to see how your code should look at this point\n", + "\n", + "'https':#github.com/csaybar/rgee_examples/blob/main/script05.R\n", + "\n", + "\n", + "\n", + "\n", + "# -----------------------------------------------------------------------\n", + "# CHECKPOINT\n", + "# -----------------------------------------------------------------------\n", + "\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display the interactive map" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "Map" + ], + "outputs": [], + "execution_count": null + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64g Checkpoint.js b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64g Checkpoint.js new file mode 100644 index 0000000..105d3cc --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64g Checkpoint.js @@ -0,0 +1,18 @@ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Chapter: F6.4 Combining R and Earth Engine +// Checkpoint: F64g +// Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +https://github.com/csaybar/rgee_examples/blob/main/script05.R + + + + +// ----------------------------------------------------------------------- +// CHECKPOINT +// ----------------------------------------------------------------------- + + diff --git a/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64g Checkpoint.py b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64g Checkpoint.py new file mode 100644 index 0000000..a0af77f --- /dev/null +++ b/docs/book/Part F - Fundamentals/F6 - Advanced Topics/F6.4 Combining R and Earth Engine/F64g Checkpoint.py @@ -0,0 +1,24 @@ +import ee +import geemap + +Map = geemap.Map() + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Chapter: F6.4 Combining R and Earth Engine +# Checkpoint: F64g +# Authors: Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter the link below into your browser to see how your code should look at this point + +'https':#github.com/csaybar/rgee_examples/blob/main/script05.R + + + + +# ----------------------------------------------------------------------- +# CHECKPOINT +# ----------------------------------------------------------------------- + + +Map \ No newline at end of file diff --git a/docs/book/js_to_py.py b/docs/book/js_to_py.py new file mode 100644 index 0000000..81d9432 --- /dev/null +++ b/docs/book/js_to_py.py @@ -0,0 +1,17 @@ +import os +from geemap.conversion import * + +# Clone the repository +# git clone https://earthengine.googlesource.com/projects/gee-edu/book + +# Add .js file extension to all files in a directory +# find . -type f ! -name "*.*" -exec mv {} {}.js \; + + +out_dir = os.getcwd() +js_dir = out_dir +js_to_python_dir(in_dir=js_dir, out_dir=out_dir, use_qgis=False, import_geemap=True) +py_to_ipynb_dir(js_dir) + +# Remove _geemap suffix from all files in a directory +# find . -type f -name '*_geemap*' -exec sh -c 'mv "$1" "${1//_geemap/}"' _ {} \;