From b115dfb3e73c6c69a95f786d06606c983a93678c Mon Sep 17 00:00:00 2001 From: Qiusheng Wu Date: Wed, 8 May 2024 17:15:13 -0400 Subject: [PATCH] Add IGIC workshop notebook (#2007) --- docs/workshops/IGIC_2024.ipynb | 5260 ++++++++++++++++++++++++++++ examples/workshops/IGIC_2024.ipynb | 5260 ++++++++++++++++++++++++++++ mkdocs.yml | 1 + 3 files changed, 10521 insertions(+) create mode 100644 docs/workshops/IGIC_2024.ipynb create mode 100644 examples/workshops/IGIC_2024.ipynb diff --git a/docs/workshops/IGIC_2024.ipynb b/docs/workshops/IGIC_2024.ipynb new file mode 100644 index 0000000000..27bdee78e5 --- /dev/null +++ b/docs/workshops/IGIC_2024.ipynb @@ -0,0 +1,5260 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/gee-community/geemap/blob/master/docs/workshops/IGIC_2024.ipynb)\n", + "\n", + "**Intro to Earth Engine in Python**\n", + "\n", + "- Notebook: \n", + "- Earth Engine: \n", + "- Geemap: \n", + "\n", + "## Introduction\n", + "\n", + "This notebook contains the materials for the workshop **Intro to Earth Engine in Python** at the 2024 Indiana Geographic Information Council (IGIC) Annual Conference.\n", + "\n", + "This workshop provides an introduction to cloud-based geospatial analysis using the Earth Engine Python API. Attendees will learn the basics of Earth Engine data types and how to visualize, analyze, and export Earth Engine data in a Jupyter environment with geemap. In addition, attendees will learn how to develop and deploy interactive Earth Engine web apps with Python. Through practical examples and hands-on exercises, attendees will enhance their learning experience. It is recommended that attendees have a basic understanding of Python and Jupyter Notebook. Familiarity with the Earth Engine JavaScript API is not required but will be helpful. Attendees can use Google Colab to follow this workshop without installing anything on their computer.\n", + "\n", + "### Agenda\n", + "\n", + "The workshop is divided into three parts.\n", + "\n", + "#### Part 1\n", + "\n", + "The first part will cover the following topics:\n", + "\n", + "- Introduction to Google Earth Engine\n", + "- Getting started with Geemap\n", + "- Introduction to Geemap core features\n", + "- Finding help on GEE and Geemap technical issues\n", + "- Search Earth Engine API documentation within Jupyter notebooks\n", + "- Introduction to interactive maps and tools\n", + "- Using Earth Data Catalog to access Image and Image collections\n", + "- Using Earth Data Catalog to access Feature and Feature collections\n", + "- Display EE images and feature data and explore their properties\n", + "\n", + "#### Part 2\n", + "\n", + "The second part will cover the following topics:\n", + "\n", + "- Processing of vector data\n", + "- Processing of raster data\n", + "- Working with local geospatial data in Geemap\n", + "- Accessing Cloud Optimized GeoTIFF\n", + "- Exporting EE Image and Feature data\n", + "- Creating timelapse animations using Landsat or Sentinel 2\n", + "- Time series analysis: Forest cover change\n", + "\n", + "#### Part 3\n", + "\n", + "The third part will cover the following topics:\n", + "\n", + "- Image Classification\n", + "- Accuracy assessment\n", + "- Create and export maps\n", + "- Building interactive web apps\n", + "\n", + "### Prerequisites\n", + "\n", + "- To use geemap and the Earth Engine Python API, you must [register](https://code.earthengine.google.com/register) for an Earth Engine account and follow the instructions [here](https://docs.google.com/document/d/1ZGSmrNm6_baqd8CHt33kIBWOlvkh-HLr46bODgJN1h0/edit?usp=sharing) to create a Cloud Project. Earth Engine is free for [noncommercial and research use](https://earthengine.google.com/noncommercial). To test whether you can use authenticate the Earth Engine Python API, please run [this notebook](https://colab.research.google.com/github/giswqs/geemap/blob/master/examples/notebooks/geemap_colab.ipynb) on Google Colab.\n", + "\n", + "## Introduction to Google Earth Engine\n", + "\n", + "### Google Earth Engine\n", + "\n", + "[Google Earth Engine](https://earthengine.google.com) is a cloud-computing platform for scientific analysis and visualization of geospatial datasets. It is free for [noncommercial and research use](https://earthengine.google.com/noncommercial). For more than a decade, Earth Engine has enabled planetary-scale Earth data science and analysis by nonprofit organizations, research scientists, and other impact users.\n", + "\n", + "With the launch of Earth Engine for [commercial use](https://earthengine.google.com/commercial), commercial customers will be charged for Earth Engine services. However, Earth Engine will remain free of charge for noncommercial use and research projects. Nonprofit organizations, academic institutions, educators, news media, Indigenous governments, and government researchers are eligible to use Earth Engine free of charge, just as they have done for over a decade.\n", + "\n", + "![](https://i.imgur.com/1XtOTwN.png)\n", + "\n", + "### The Earth Engine Public Data Catalog\n", + "\n", + "[![](https://i.imgur.com/pDyd7yH.png)](https://developers.google.com/earth-engine/datasets/)\n", + "\n", + "### The Awesome GEE Community Data Catalog\n", + "\n", + "[![](https://i.imgur.com/h6Dnlhb.png)](https://gee-community-catalog.org/)\n", + "\n", + "### The Earth Engine APIs\n", + "\n", + "![](https://i.imgur.com/RHPEQzF.png)\n", + "\n", + "### Geemap\n", + "\n", + "[![](https://i.imgur.com/cEfc1iV.png)](https://geemap.org/)\n", + "\n", + "## Getting started with Geemap\n", + "\n", + "[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/gee-community/geemap/blob/master/docs/workshops/IGIC_2024.ipynb)\n", + "\n", + "### Change Colab dark theme\n", + "\n", + "Currently, ipywidgets does not work well with Colab dark theme. Some of the geemap widgets may not display properly in Colab dark theme.It is recommended that you change Colab to the light theme.\n", + "\n", + "![](https://i.imgur.com/EJ0GDP8.png)\n", + "\n", + "### Install geemap\n", + "\n", + "The geemap package is pre-installed in Google Colab and is updated to the latest minor or major release every few weeks. Some optional dependencies of geemap being used by this notebook are not pre-installed in Colab. Uncomment the following line to install geemap and some optional dependencies." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install -U \"geemap[workshop]\" cartopy solara flask==2.3.3" + ] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "Note that some geemap features do not work properly with Google Colab. If you are familiar with [Anaconda](https://www.anaconda.com/download) or [Miniconda](https://docs.anaconda.com/free/miniconda), it is recommended to create a new conda environment to install geemap and its optional dependencies on your local computer.\n", + "\n", + "```bash\n", + "conda create -n gee python=3.11\n", + "conda activate gee\n", + "conda install -c conda-forge mamba\n", + "mamba install -c conda-forge geemap pygis cartopy solara flask==2.3.3\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "### Import libraries\n", + "\n", + "Import the earthengine-api and geemap." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "import ee\n", + "import geemap" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "### Authenticate and initialize Earth Engine\n", + "\n", + "You will need to create a [Google Cloud Project](https://console.cloud.google.com/projectcreate) and enable the [Earth Engine API](https://console.cloud.google.com/apis/api/earthengine.googleapis.com) for the project. You can find detailed instructions [here](https://book.geemap.org/chapters/01_introduction.html#earth-engine-authentication)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_initialize()" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "### Creating interactive maps\n", + "\n", + "Let's create an interactive map using the `ipyleaflet` plotting backend. The [`geemap.Map`](https://geemap.org/geemap/#geemap.geemap.m) class inherits the [`ipyleaflet.Map`](https://ipyleaflet.readthedocs.io/en/latest/map_and_basemaps/map.html) class. Therefore, you can use the same syntax to create an interactive map as you would with `ipyleaflet.Map`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "To display it in a Jupyter notebook, simply ask for the object representation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "m" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "To customize the map, you can specify various keyword arguments, such as `center` ([lat, lon]), `zoom`, `width`, and `height`. The default `width` is `100%`, which takes up the entire cell width of the Jupyter notebook. The `height` argument accepts a number or a string. If a number is provided, it represents the height of the map in pixels. If a string is provided, the string must be in the format of a number followed by `px`, e.g., `600px`.\n", + "\n", + "Generate a map that focuses on the contiguous United States." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "Generate a map that focuses on Indiana." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[39.814613, -86.117887], zoom=7)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "Generate a map that focuses on Michigan City, IN." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[41.701756, -86.895448], zoom=13)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "To hide a control, set `control_name` to `False`, e.g., `draw_ctrl=False`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(data_ctrl=False, toolbar_ctrl=False, draw_ctrl=False)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "### Adding basemaps\n", + "\n", + "There are several ways to add basemaps to a map. You can specify the basemap to use in the `basemap` keyword argument when creating the map. Alternatively, you can add basemap layers to the map using the `add_basemap` method. Geemap has hundreds of built-in basemaps available that can be easily added to the map with only one line of code.\n", + "\n", + "Create a map by specifying the basemap to use as follows. For example, the `Esri.WorldImagery` basemap represents the Esri world imagery basemap." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(basemap=\"Esri.WorldImagery\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "21", + "metadata": {}, + "source": [ + "You can add as many basemaps as you like to the map. For example, the following code adds the `OpenTopoMap` basemap to the map above:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_basemap(\"Esri.WorldTopoMap\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_basemap(\"OpenTopoMap\")" + ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "Print out the first 10 basemaps:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "basemaps = list(geemap.basemaps.keys())\n", + "len(geemap.basemaps)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26", + "metadata": {}, + "outputs": [], + "source": [ + "basemaps[:10]" + ] + }, + { + "cell_type": "markdown", + "id": "27", + "metadata": {}, + "source": [ + "You can also change basemaps interactively using the basemap GUI." + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "### Google basemaps\n", + "\n", + "Google basemaps are not included in the geemap built-in basemaps due to license issues ([source](https://github.com/gee-community/geemap/pull/1681#issuecomment-1707109740)). Users can choose to add Google basemaps at their own risks as follows:\n", + "\n", + "```text\n", + "ROADMAP: https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}\n", + "SATELLITE: https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}\n", + "TERRAIN: https://mt1.google.com/vt/lyrs=p&x={x}&y={y}&z={z}\n", + "HYBRID: https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "url = \"https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}\"\n", + "m.add_tile_layer(url, name=\"Google Satellite\", attribution=\"Google\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "## Introduction to geemap features\n", + "\n", + "- Core features: maintained by the Earth Engine team at Google\n", + "- Extra features: maintained by the Earth Engine community\n", + "\n", + "### Core features\n", + "\n", + "- Basemap selector\n", + "- Layer manager\n", + "- Layer editor\n", + "- Inspector\n", + "- Draw control\n", + "\n", + "[![](https://i.imgur.com/SMaZtlm.png)](https://developers.google.com/earth-engine/guides/image_visualization#colab-python)\n", + "\n", + "[![](https://i.imgur.com/Y6Ut7yf.png)](https://youtu.be/EDSqGmNLOcU)\n", + "\n", + "### Extra features\n", + "\n", + "- Converting EE JavaScript to Python automatically\n", + "- Exploring the EE Data Catalog\n", + "- Creating color bars for Earth Engine images\n", + "- Plotting Earth Engine data\n", + "- Time slider\n", + "- Timeseries inspector\n", + "- Using geemap with ArcGIS Pro\n", + "- Custom map projections\n", + "- Timelapse animations\n", + "- Developing interactive web apps\n", + "\n", + "[![](https://i.imgur.com/qZXUUEI.png)](https://youtu.be/jVAGX7ibFis)" + ] + }, + { + "cell_type": "markdown", + "id": "31", + "metadata": {}, + "source": [ + "## Finding help on GEE and Geemap technical issues\n", + "\n", + "- Earth Engine Developer Guide: https://developers.google.com/earth-engine/guides\n", + "- Earth Engine Developers Forum: https://groups.google.com/forum/#!forum/google-earth-engine-developers\n", + "- Geemap website: https://geemap.org\n", + "- Bug reports and feature requests: https://github.com/gee-community/geemap/issues\n", + "- Q&A: https://github.com/gee-community/geemap/discussions" + ] + }, + { + "cell_type": "markdown", + "id": "32", + "metadata": {}, + "source": [ + "## Search Earth Engine API documentation within Jupyter notebooks\n", + "\n", + "### Geemap API reference\n", + "\n", + "1. Create a new code cell.\n", + "2. Type `geemap.` in the code cell.\n", + "3. Press the TAB key on your keyboard.\n", + "4. Utilize the Up/Down arrow keys to navigate through the available functions and classes.\n", + "5. Once you've selected the desired function or class, press Enter to insert it into your code.\n", + "\n", + "![](https://i.imgur.com/WWzImNv.png)\n", + "\n", + "6. Once you've selected a function or class, place the cursor within the parentheses of the function or class.\n", + "7. Press the TAB key again to display the API reference for the selected function or class.\n", + "\n", + "![](https://i.imgur.com/bSLCUrk.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "34", + "metadata": {}, + "source": [ + "### Earth Engine API reference\n", + "\n", + "1. Create a new code cell.\n", + "2. Type `ee.` in the code cell.\n", + "3. Press the TAB key on your keyboard.\n", + "4. Utilize the Up/Down arrow keys to navigate through the available functions and classes.\n", + "5. Once you've selected the desired function or class, press Enter to insert it into your code.\n", + "\n", + "![](https://i.imgur.com/TIRF1nD.png)\n", + "\n", + "6. Once you've selected a function or class, place the cursor within the parentheses of the function or class.\n", + "7. Press the TAB key again to display the API reference for the selected function or class.\n", + "\n", + "![](https://i.imgur.com/oVJR8Yt.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "36", + "metadata": {}, + "source": [ + "## Introduction to interactive maps and tools\n", + "\n", + "### Basemap selector\n", + "\n", + "Select a basemap from the dropdown list and add it to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add(\"basemap_selector\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "38", + "metadata": {}, + "source": [ + "### Layer Manager\n", + "\n", + "Toggle the checkbox to show or hide the layer. Drag and move the slider to change the transparency level of the layer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add_layer(states, {}, \"US States\")\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "40", + "metadata": {}, + "source": [ + "### Inspector\n", + "\n", + "Click on the map to query Earth Engine data at a specific location." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add_layer(\n", + " landsat7,\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 20, \"max\": 200, \"gamma\": 2.0},\n", + " \"Landsat 7\",\n", + ")\n", + "m.add_layer(states, {}, \"US States\")\n", + "m.add(\"inspector\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "42", + "metadata": {}, + "source": [ + "### Layer Editor\n", + "\n", + "You can change the visualization parameters of the Earth Engine data using the layer editor.\n", + "\n", + "#### Single-band image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add(\"layer_editor\", layer_dict=m.ee_layers[\"SRTM DEM\"])\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "44", + "metadata": {}, + "source": [ + "#### Multi-band image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "m.add_layer(\n", + " landsat7,\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 20, \"max\": 200, \"gamma\": 2.0},\n", + " \"Landsat 7\",\n", + ")\n", + "m.add(\"layer_editor\", layer_dict=m.ee_layers[\"Landsat 7\"])\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "46", + "metadata": {}, + "source": [ + "#### Feature collection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "m.add_layer(states, {}, \"US States\")\n", + "m.add(\"layer_editor\", layer_dict=m.ee_layers[\"US States\"])\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "48", + "metadata": {}, + "source": [ + "### Draw control\n", + "\n", + "You can draw shapes on the map using the draw control. The drawn features will be automatically converted to Earth Engine objects, which can be accessed in one of the following ways:\n", + "\n", + "- To return the last drawn feature as an `ee.Geometry()`, use: `m.user_roi`\n", + "- To return all the drawn features as an `ee.FeatureCollection()`, use: `m.user_rois`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": \"terrain\",\n", + "}\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50", + "metadata": {}, + "outputs": [], + "source": [ + "if m.user_roi is not None:\n", + " image = dem.clip(m.user_roi)\n", + " m.layers[1].visible = False\n", + " m.add_layer(image, vis_params, \"Clipped DEM\")" + ] + }, + { + "cell_type": "markdown", + "id": "51", + "metadata": {}, + "source": [ + "## The Earth Engine Data Catalog\n", + "\n", + "The [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets) hosts a variety of geospatial datasets. As of March 2024, the catalog contains over [1,100 datasets](https://github.com/opengeos/Earth-Engine-Catalog/blob/master/gee_catalog.tsv) with a total size of over 100 petabytes. Some notable datasets include: Landsat, Sentinel, MODIS, NAIP, etc. For a complete list of datasets in CSV or JSON formats, see the [Earth Engine Datasets List](https://github.com/giswqs/Earth-Engine-Catalog/blob/master/gee_catalog.tsv).\n", + "\n", + "### Searching datasets on the Earth Engine website\n", + "\n", + "- View all datasets: https://developers.google.com/earth-engine/datasets/catalog\n", + "- Search by tags: https://developers.google.com/earth-engine/datasets/tags\n", + "\n", + "### Searching datasets within geemap\n", + "\n", + "The [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets/catalog) is searchable. You can search datasets by name, keyword, or tag. For example, enter \"elevation\" in the search box will filter the catalog to show only datasets containing \"elevation\" in their name, description, or tags. 52 datasets are returned for this search query. Scroll down the list to find the [NASA SRTM Digital Elevation 30m](https://developers.google.com/earth-engine/datasets/catalog/USGS_SRTMGL1_003#description) dataset. On each dataset page, you can find the following information, including Dataset Availability, Dataset Provider, Earth Engine Snippet, Tags, Description, Code Example, and more. One important piece of information is the Image/ImageCollection/FeatureCollection ID of each dataset, which is essential for accessing the dataset through the Earth Engine JavaScript or Python APIs.\n", + "\n", + "![](https://i.imgur.com/B3rf4QN.jpg)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "53", + "metadata": {}, + "source": [ + "### Using the datasets module" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54", + "metadata": {}, + "outputs": [], + "source": [ + "from geemap.datasets import DATA" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "dataset = ee.Image(DATA.USGS_GAP_AK_2001)\n", + "m.add_layer(dataset, {}, \"GAP Alaska\")\n", + "m.centerObject(dataset, zoom=4)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56", + "metadata": {}, + "outputs": [], + "source": [ + "from geemap.datasets import get_metadata\n", + "\n", + "get_metadata(DATA.USGS_GAP_AK_2001)" + ] + }, + { + "cell_type": "markdown", + "id": "57", + "metadata": {}, + "source": [ + "## Earth Engine data types\n", + "\n", + "Earth Engine objects are server-side objects rather than client-side objects, which means that they are not stored locally on your computer. Similar to video streaming services (e.g., YouTube, Netflix, and Hulu), which store videos/movies on their servers, Earth Engine data are stored on the Earth Engine servers. We can stream geospatial data from Earth Engine on-the-fly without having to download the data just like we can watch videos from streaming services using a web browser without having to download the entire video to your computer.\n", + "\n", + "- **Image**: the fundamental raster data type in Earth Engine.\n", + "- **ImageCollection**: a stack or time-series of images.\n", + "- **Geometry**: the fundamental vector data type in Earth Engine.\n", + "- **Feature**: a Geometry with attributes.\n", + "- **FeatureCollection**: a set of features.\n", + "\n", + "![](https://i.imgur.com/XzsxUgD.jpg)\n", + "\n", + "![](https://i.imgur.com/165CykW.jpg)" + ] + }, + { + "cell_type": "markdown", + "id": "58", + "metadata": {}, + "source": [ + "## Earth Engine raster data\n", + "\n", + "### Image\n", + "\n", + "Raster data in Earth Engine are represented as **Image** objects. Images are composed of one or more bands and each band has its own name, data type, scale, mask and projection. Each image has metadata stored as a set of properties.\n", + "\n", + "#### Loading Earth Engine images\n", + "\n", + "Images can be loaded by passing an Earth Engine asset ID into the `ee.Image` constructor. You can find image IDs in the Earth Engine Data Catalog. For example, to load the NASA SRTM Digital Elevation you can use:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59", + "metadata": {}, + "outputs": [], + "source": [ + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "image" + ] + }, + { + "cell_type": "markdown", + "id": "60", + "metadata": {}, + "source": [ + "#### Visualizing Earth Engine images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[21.79, 70.87], zoom=3)\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 6000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"], # 'terrain'\n", + "}\n", + "m.add_layer(image, vis_params, \"SRTM\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "62", + "metadata": {}, + "source": [ + "### ImageCollection\n", + "\n", + "An `ImageCollection` is a stack or sequence of images. An `ImageCollection` can be loaded by passing an Earth Engine asset ID into the `ImageCollection` constructor. You can find `ImageCollection` IDs in the [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets).\n", + "\n", + "#### Loading image collections\n", + "\n", + "For example, to load the image collection of the [Sentinel-2 surface reflectance](https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2_SR):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63", + "metadata": {}, + "outputs": [], + "source": [ + "collection = ee.ImageCollection(\"COPERNICUS/S2_SR\")" + ] + }, + { + "cell_type": "markdown", + "id": "64", + "metadata": {}, + "source": [ + "#### Filtering image collections\n", + "\n", + "Let's find out how many Sentinel-2 images covering Blue Chip Casino Hotel Spa." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65", + "metadata": {}, + "outputs": [], + "source": [ + "geometry = ee.Geometry.Point([-86.893044, 41.718642])\n", + "images = collection.filterBounds(geometry)\n", + "images.size()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66", + "metadata": {}, + "outputs": [], + "source": [ + "images.first()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67", + "metadata": {}, + "outputs": [], + "source": [ + "images = (\n", + " collection.filterBounds(geometry)\n", + " .filterDate(\"2023-07-01\", \"2023-09-01\")\n", + " .filter(ee.Filter.lt(\"CLOUDY_PIXEL_PERCENTAGE\", 5))\n", + ")\n", + "images.size()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "image = images.first()\n", + "\n", + "vis = {\n", + " \"min\": 0.0,\n", + " \"max\": 3000,\n", + " \"bands\": [\"B4\", \"B3\", \"B2\"],\n", + "}\n", + "\n", + "m.add_layer(image, vis, \"Sentinel-2\")\n", + "m.centerObject(image, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "69", + "metadata": {}, + "source": [ + "#### Visualizing image collections\n", + "\n", + "To visualize an Earth Engine **ImageCollection**, we need to convert an **ImageCollection** to an **Image** by compositing all the images in the collection to a single image representing, for example, the min, max, median, mean or standard deviation of the images. For example, to create a median value image from a collection, use the `collection.median()` method. Let's create a median image from the Sentinel-2 surface reflectance collection:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "image = images.median()\n", + "\n", + "vis = {\n", + " \"min\": 0.0,\n", + " \"max\": 3000,\n", + " \"bands\": [\"B8\", \"B4\", \"B3\"],\n", + "}\n", + "\n", + "m.add_layer(image, vis, \"Sentinel-2\")\n", + "m.centerObject(geometry, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "71", + "metadata": {}, + "source": [ + "## Earth Engine vector data\n", + "\n", + "A **FeatureCollection** is a collection of Features. A FeatureCollection is analogous to a GeoJSON FeatureCollection object, i.e., a collection of features with associated properties/attributes. Data contained in a shapefile can be represented as a FeatureCollection.\n", + "\n", + "### Loading feature collections\n", + "\n", + "The [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets) hosts a variety of vector datasets (e.g,, US Census data, country boundaries, and more) as feature collections. You can find feature collection IDs by searching the data catalog. For example, to load the [TIGER roads data](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2016_Roads) by the U.S. Census Bureau:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "fc = ee.FeatureCollection(\"TIGER/2016/Roads\")\n", + "m.set_center(-86.894547, 41.718934, 12)\n", + "m.add_layer(fc, {}, \"Census roads\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "73", + "metadata": {}, + "source": [ + "### Filtering feature collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.eq(\"NAME\", \"Indiana\"))\n", + "m.add_layer(fc, {}, \"Indiana\")\n", + "m.center_object(fc, 7)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75", + "metadata": {}, + "outputs": [], + "source": [ + "feat = fc.first()\n", + "feat.toDictionary()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_df(fc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.inList(\"NAME\", [\"California\", \"Oregon\", \"Washington\"]))\n", + "m.add_layer(fc, {}, \"West Coast\")\n", + "m.center_object(fc, 5)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78", + "metadata": {}, + "outputs": [], + "source": [ + "region = m.user_roi\n", + "if region is None:\n", + " region = ee.Geometry.BBox(-88.40, 29.88, -77.90, 35.39)\n", + "\n", + "fc = ee.FeatureCollection(\"TIGER/2018/States\").filterBounds(region)\n", + "m.add_layer(fc, {}, \"Southeastern U.S.\")\n", + "m.center_object(fc, 6)" + ] + }, + { + "cell_type": "markdown", + "id": "79", + "metadata": {}, + "source": [ + "### Visualizing feature collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "m.add_layer(states, {}, \"US States\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "style = {\"color\": \"0000ffff\", \"width\": 2, \"lineType\": \"solid\", \"fillColor\": \"FF000080\"}\n", + "m.add_layer(states.style(**style), {}, \"US States\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "vis_params = {\n", + " \"color\": \"000000\",\n", + " \"colorOpacity\": 1,\n", + " \"pointSize\": 3,\n", + " \"pointShape\": \"circle\",\n", + " \"width\": 2,\n", + " \"lineType\": \"solid\",\n", + " \"fillColorOpacity\": 0.66,\n", + "}\n", + "palette = [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"]\n", + "m.add_styled_vector(\n", + " states, column=\"NAME\", palette=palette, layer_name=\"Styled vector\", **vis_params\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "83", + "metadata": {}, + "source": [ + "## Exercise 1 - Creating cloud-free imagery\n", + "\n", + "Create a cloud-free imagery for the state of Indiana. You can use Landsat 8/9 or Sentinel-2 imagery. Relevant Earth Engine assets:\n", + "\n", + "- [ee.FeatureCollection(\"TIGER/2018/States\")](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2018_States)\n", + "- [ee.ImageCollection(\"COPERNICUS/S2_SR\")](https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2_SR)\n", + "- [ee.ImageCollection(\"LANDSAT/LC08/C02/T1_L2\")](https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC08_C02_T1_L2)\n", + "- [ee.ImageCollection(\"LANDSAT/LC09/C02/T1_L2\")](https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC09_C02_T1_L2)" + ] + }, + { + "cell_type": "markdown", + "id": "84", + "metadata": {}, + "source": [ + "## More tools for visualizing Earth Engine data" + ] + }, + { + "cell_type": "markdown", + "id": "85", + "metadata": {}, + "source": [ + "### Using the plotting tool" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\").select(\n", + " [\"B1\", \"B2\", \"B3\", \"B4\", \"B5\", \"B7\"]\n", + ")\n", + "\n", + "landsat_vis = {\"bands\": [\"B4\", \"B3\", \"B2\"], \"gamma\": 1.4}\n", + "m.add_layer(landsat7, landsat_vis, \"Landsat\")\n", + "\n", + "hyperion = ee.ImageCollection(\"EO1/HYPERION\").filter(\n", + " ee.Filter.date(\"2016-01-01\", \"2017-03-01\")\n", + ")\n", + "\n", + "hyperion_vis = {\n", + " \"min\": 1000.0,\n", + " \"max\": 14000.0,\n", + " \"gamma\": 2.5,\n", + "}\n", + "m.add_layer(hyperion, hyperion_vis, \"Hyperion\")\n", + "m.add_plot_gui()\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "87", + "metadata": {}, + "source": [ + "Set plotting options for Landsat." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88", + "metadata": {}, + "outputs": [], + "source": [ + "m.set_plot_options(add_marker_cluster=True, overlay=True)" + ] + }, + { + "cell_type": "markdown", + "id": "89", + "metadata": {}, + "source": [ + "Set plotting options for Hyperion." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90", + "metadata": {}, + "outputs": [], + "source": [ + "m.set_plot_options(add_marker_cluster=True, plot_type=\"bar\")" + ] + }, + { + "cell_type": "markdown", + "id": "91", + "metadata": {}, + "source": [ + "### Legends\n", + "\n", + "#### Built-in legends" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92", + "metadata": {}, + "outputs": [], + "source": [ + "from geemap.legends import builtin_legends" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93", + "metadata": {}, + "outputs": [], + "source": [ + "for legend in builtin_legends:\n", + " print(legend)" + ] + }, + { + "cell_type": "markdown", + "id": "94", + "metadata": {}, + "source": [ + "Add NLCD WMS layer and legend to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "m.add_basemap(\"NLCD 2021 CONUS Land Cover\")\n", + "m.add_legend(builtin_legend=\"NLCD\", max_width=\"100px\", height=\"455px\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "96", + "metadata": {}, + "source": [ + "Add NLCD Earth Engine layer and legend to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "\n", + "nlcd = ee.Image(\"USGS/NLCD_RELEASES/2021_REL/NLCD/2021\")\n", + "landcover = nlcd.select(\"landcover\")\n", + "\n", + "m.add_layer(landcover, {}, \"NLCD Land Cover 2021\")\n", + "m.add_legend(\n", + " title=\"NLCD Land Cover Classification\", builtin_legend=\"NLCD\", height=\"455px\"\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "98", + "metadata": {}, + "source": [ + "#### Custom legends" + ] + }, + { + "cell_type": "markdown", + "id": "99", + "metadata": {}, + "source": [ + "Add a custom legend by specifying the colors and labels." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "100", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(add_google_map=False)\n", + "\n", + "keys = [\"One\", \"Two\", \"Three\", \"Four\", \"etc\"]\n", + "\n", + "# colors can be defined using either hex code or RGB (0-255, 0-255, 0-255)\n", + "colors = [\"#8DD3C7\", \"#FFFFB3\", \"#BEBADA\", \"#FB8072\", \"#80B1D3\"]\n", + "# legend_colors = [(255, 0, 0), (127, 255, 0), (127, 18, 25), (36, 70, 180), (96, 68 123)]\n", + "\n", + "m.add_legend(keys=keys, colors=colors, position=\"bottomright\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "101", + "metadata": {}, + "source": [ + "Add a custom legend by specifying a dictionary of colors and labels." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "102", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "\n", + "legend_dict = {\n", + " \"11 Open Water\": \"466b9f\",\n", + " \"12 Perennial Ice/Snow\": \"d1def8\",\n", + " \"21 Developed, Open Space\": \"dec5c5\",\n", + " \"22 Developed, Low Intensity\": \"d99282\",\n", + " \"23 Developed, Medium Intensity\": \"eb0000\",\n", + " \"24 Developed High Intensity\": \"ab0000\",\n", + " \"31 Barren Land (Rock/Sand/Clay)\": \"b3ac9f\",\n", + " \"41 Deciduous Forest\": \"68ab5f\",\n", + " \"42 Evergreen Forest\": \"1c5f2c\",\n", + " \"43 Mixed Forest\": \"b5c58f\",\n", + " \"51 Dwarf Scrub\": \"af963c\",\n", + " \"52 Shrub/Scrub\": \"ccb879\",\n", + " \"71 Grassland/Herbaceous\": \"dfdfc2\",\n", + " \"72 Sedge/Herbaceous\": \"d1d182\",\n", + " \"73 Lichens\": \"a3cc51\",\n", + " \"74 Moss\": \"82ba9e\",\n", + " \"81 Pasture/Hay\": \"dcd939\",\n", + " \"82 Cultivated Crops\": \"ab6c28\",\n", + " \"90 Woody Wetlands\": \"b8d9eb\",\n", + " \"95 Emergent Herbaceous Wetlands\": \"6c9fb8\",\n", + "}\n", + "\n", + "nlcd = ee.Image(\"USGS/NLCD_RELEASES/2021_REL/NLCD/2021\")\n", + "landcover = nlcd.select(\"landcover\")\n", + "\n", + "m.add_layer(landcover, {}, \"NLCD Land Cover 2021\")\n", + "m.add_legend(title=\"NLCD Land Cover Classification\", legend_dict=legend_dict)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "103", + "metadata": {}, + "source": [ + "### Color bars\n", + "\n", + "Add a horizontal color bar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "104", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add_colorbar(vis_params, label=\"Elevation (m)\", layer_name=\"SRTM DEM\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "105", + "metadata": {}, + "source": [ + "Add a vertical color bar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "106", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_colorbar(\n", + " vis_params,\n", + " label=\"Elevation (m)\",\n", + " layer_name=\"SRTM DEM\",\n", + " orientation=\"vertical\",\n", + " max_width=\"100px\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "107", + "metadata": {}, + "source": [ + "Make the color bar background transparent." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "108", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_colorbar(\n", + " vis_params,\n", + " label=\"Elevation (m)\",\n", + " layer_name=\"SRTM DEM\",\n", + " orientation=\"vertical\",\n", + " max_width=\"100px\",\n", + " transparent_bg=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "109", + "metadata": {}, + "source": [ + "### Split-panel maps\n", + "\n", + "Create a split map with basemaps. Note that ipyleaflet has a bug with the SplitControl. You can't pan the map, which should be resolved in the next ipyleaflet release." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "110", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.split_map(left_layer=\"Esri.WorldTopoMap\", right_layer=\"OpenTopoMap\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "111", + "metadata": {}, + "source": [ + "Create a split map with Earth Engine layers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "112", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4, height=600)\n", + "\n", + "nlcd_2001 = ee.Image(\"USGS/NLCD_RELEASES/2019_REL/NLCD/2001\").select(\"landcover\")\n", + "nlcd_2021 = ee.Image(\"USGS/NLCD_RELEASES/2021_REL/NLCD/2021\").select(\"landcover\")\n", + "\n", + "left_layer = geemap.ee_tile_layer(nlcd_2001, {}, \"NLCD 2001\")\n", + "right_layer = geemap.ee_tile_layer(nlcd_2021, {}, \"NLCD 2021\")\n", + "\n", + "m.split_map(left_layer, right_layer)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "113", + "metadata": {}, + "source": [ + "### Linked maps\n", + "\n", + "Create a 2x2 linked map for visualizing Sentinel-2 imagery with different band combinations. Note that this feature does not work properly with Colab. Panning one map would not pan other maps." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "114", + "metadata": {}, + "outputs": [], + "source": [ + "image = (\n", + " ee.ImageCollection(\"COPERNICUS/S2\")\n", + " .filterDate(\"2023-07-01\", \"2023-09-01\")\n", + " .filter(ee.Filter.lt(\"CLOUDY_PIXEL_PERCENTAGE\", 5))\n", + " .map(lambda img: img.divide(10000))\n", + " .median()\n", + ")\n", + "\n", + "vis_params = [\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 0, \"max\": 0.3, \"gamma\": 1.3},\n", + " {\"bands\": [\"B8\", \"B11\", \"B4\"], \"min\": 0, \"max\": 0.3, \"gamma\": 1.3},\n", + " {\"bands\": [\"B8\", \"B4\", \"B3\"], \"min\": 0, \"max\": 0.3, \"gamma\": 1.3},\n", + " {\"bands\": [\"B12\", \"B12\", \"B4\"], \"min\": 0, \"max\": 0.3, \"gamma\": 1.3},\n", + "]\n", + "\n", + "labels = [\n", + " \"Natural Color (B4/B3/B2)\",\n", + " \"Land/Water (B8/B11/B4)\",\n", + " \"Color Infrared (B8/B4/B3)\",\n", + " \"Vegetation (B12/B11/B4)\",\n", + "]\n", + "\n", + "geemap.linked_maps(\n", + " rows=2,\n", + " cols=2,\n", + " height=\"300px\",\n", + " center=[41.718934, -86.894547],\n", + " zoom=12,\n", + " ee_objects=[image],\n", + " vis_params=vis_params,\n", + " labels=labels,\n", + " label_position=\"topright\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "115", + "metadata": {}, + "source": [ + "### Timeseries inspector\n", + "\n", + "Check the available years of NLCD." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "116", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "collection = ee.ImageCollection(\"USGS/NLCD_RELEASES/2019_REL/NLCD\").select(\"landcover\")\n", + "vis_params = {\"bands\": [\"landcover\"]}\n", + "years = collection.aggregate_array(\"system:index\").getInfo()\n", + "years" + ] + }, + { + "cell_type": "markdown", + "id": "117", + "metadata": {}, + "source": [ + "Create a timeseries inspector for NLCD. Note that ipyleaflet has a bug with the SplitControl. You can't pan the map, which should be resolved in the next ipyleaflet release." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "118", + "metadata": {}, + "outputs": [], + "source": [ + "m.ts_inspector(\n", + " left_ts=collection,\n", + " right_ts=collection,\n", + " left_names=years,\n", + " right_names=years,\n", + " left_vis=vis_params,\n", + " right_vis=vis_params,\n", + " width=\"80px\",\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "119", + "metadata": {}, + "source": [ + "### Time slider\n", + "\n", + "Note that this feature may not work properly with Colab. Restart Colab runtime if the time slider does not work.\n", + "\n", + "Create a map for visualizing MODIS vegetation data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "120", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "collection = (\n", + " ee.ImageCollection(\"MODIS/MCD43A4_006_NDVI\")\n", + " .filter(ee.Filter.date(\"2018-06-01\", \"2018-07-01\"))\n", + " .select(\"NDVI\")\n", + ")\n", + "vis_params = {\n", + " \"min\": 0.0,\n", + " \"max\": 1.0,\n", + " \"palette\": \"ndvi\",\n", + "}\n", + "\n", + "m.add_time_slider(collection, vis_params, time_interval=2)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "121", + "metadata": {}, + "source": [ + "Create a map for visualizing weather data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "122", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "collection = (\n", + " ee.ImageCollection(\"NOAA/GFS0P25\")\n", + " .filterDate(\"2018-12-22\", \"2018-12-23\")\n", + " .limit(24)\n", + " .select(\"temperature_2m_above_ground\")\n", + ")\n", + "\n", + "vis_params = {\n", + " \"min\": -40.0,\n", + " \"max\": 35.0,\n", + " \"palette\": [\"blue\", \"purple\", \"cyan\", \"green\", \"yellow\", \"red\"],\n", + "}\n", + "\n", + "labels = [str(n).zfill(2) + \":00\" for n in range(0, 24)]\n", + "m.add_time_slider(collection, vis_params, labels=labels, time_interval=1, opacity=0.8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "123", + "metadata": {}, + "source": [ + "Visualizing Sentinel-2 imagery" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "124", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "collection = (\n", + " ee.ImageCollection(\"COPERNICUS/S2_SR\")\n", + " .filterBounds(ee.Geometry.Point([-86.894547, 41.718934]))\n", + " .filterMetadata(\"CLOUDY_PIXEL_PERCENTAGE\", \"less_than\", 10)\n", + " .filter(ee.Filter.calendarRange(6, 8, \"month\"))\n", + ")\n", + "\n", + "vis_params = {\"min\": 0, \"max\": 4000, \"bands\": [\"B8\", \"B4\", \"B3\"]}\n", + "\n", + "m.add_time_slider(collection, vis_params)\n", + "m.set_center(-86.894547, 41.718934, 12)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "125", + "metadata": {}, + "source": [ + "## Exercise 2 - Creating land cover maps with a legend\n", + "\n", + "Create a split map for visualizing the ESA WorldCover for the state of Alaska, with the `Esri.WorldImagery` as the left layer, and the ESA WorldCover as the right layer. Add the ESA land cover legend to the map. Relevant Earth Engine assets:\n", + "\n", + "- [ee.FeatureCollection(\"TIGER/2018/States\")](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2018_States)\n", + "- [ee.ImageCollection(\"ESA/WorldCover/v200\")](https://developers.google.com/earth-engine/datasets/catalog/ESA_WorldCover_v200)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "126", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "127", + "metadata": {}, + "source": [ + "## Processing of vector data\n", + "\n", + "### From GeoJSON" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "128", + "metadata": {}, + "outputs": [], + "source": [ + "in_geojson = \"https://github.com/gee-community/geemap/blob/master/examples/data/countries.geojson\"\n", + "m = geemap.Map()\n", + "fc = geemap.geojson_to_ee(in_geojson)\n", + "m.add_layer(fc.style(**{\"color\": \"ff0000\", \"fillColor\": \"00000000\"}), {}, \"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "129", + "metadata": {}, + "source": [ + "### From Shapefile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "130", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/gee-community/geemap/blob/master/examples/data/countries.zip\"\n", + "geemap.download_file(url, overwrite=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "131", + "metadata": {}, + "outputs": [], + "source": [ + "in_shp = \"countries.shp\"\n", + "fc = geemap.shp_to_ee(in_shp)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "132", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_layer(fc, {}, \"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "133", + "metadata": {}, + "source": [ + "### From GeoDataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "134", + "metadata": {}, + "outputs": [], + "source": [ + "import geopandas as gpd\n", + "\n", + "gdf = gpd.read_file(in_shp)\n", + "fc = geemap.gdf_to_ee(gdf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "135", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_layer(fc, {}, \"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "136", + "metadata": {}, + "source": [ + "### To GeoJSON" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "137", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.eq(\"NAME\", \"Indiana\"))\n", + "m.add_layer(fc, {}, \"Indiana\")\n", + "m.center_object(fc, 7)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "138", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_geojson(fc, filename=\"Indiana.geojson\")" + ] + }, + { + "cell_type": "markdown", + "id": "139", + "metadata": {}, + "source": [ + "### To Shapefile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "140", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_shp(fc, filename=\"Indiana.shp\")" + ] + }, + { + "cell_type": "markdown", + "id": "141", + "metadata": {}, + "source": [ + "### To GeoDataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "142", + "metadata": {}, + "outputs": [], + "source": [ + "gdf = geemap.ee_to_gdf(fc)\n", + "gdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "143", + "metadata": {}, + "outputs": [], + "source": [ + "gdf.explore()" + ] + }, + { + "cell_type": "markdown", + "id": "144", + "metadata": {}, + "source": [ + "### To DataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "145", + "metadata": {}, + "outputs": [], + "source": [ + "df = geemap.ee_to_df(fc)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "id": "146", + "metadata": {}, + "source": [ + "### To CSV" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "147", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_csv(fc, filename=\"Indiana.csv\")" + ] + }, + { + "cell_type": "markdown", + "id": "148", + "metadata": {}, + "source": [ + "## Processing of raster data\n", + "\n", + "### Extract pixel values\n", + "\n", + "#### Extracting values to points" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "149", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "\n", + "m.add_layer(\n", + " landsat7,\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 20, \"max\": 200, \"gamma\": 2},\n", + " \"Landsat 7\",\n", + ")\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\", True, 1)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "150", + "metadata": {}, + "outputs": [], + "source": [ + "in_shp = \"us_cities.shp\"\n", + "url = \"https://github.com/giswqs/data/raw/main/us/us_cities.zip\"\n", + "geemap.download_file(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "151", + "metadata": {}, + "outputs": [], + "source": [ + "in_fc = geemap.shp_to_ee(in_shp)\n", + "m.add_layer(in_fc, {}, \"Cities\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "152", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.extract_values_to_points(in_fc, dem, out_fc=\"dem.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "153", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.shp_to_gdf(\"dem.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "154", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.extract_values_to_points(in_fc, landsat7, \"landsat.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "155", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_df(\"landsat.csv\")" + ] + }, + { + "cell_type": "markdown", + "id": "156", + "metadata": {}, + "source": [ + "#### Extracting pixel values along a transect" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "157", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"TERRAIN\")\n", + "\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(image, vis_params, \"SRTM DEM\", True, 0.5)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "158", + "metadata": {}, + "outputs": [], + "source": [ + "line = m.user_roi\n", + "if line is None:\n", + " line = ee.Geometry.LineString(\n", + " [[-120.2232, 36.3148], [-118.9269, 36.7121], [-117.2022, 36.7562]]\n", + " )\n", + " m.add_layer(line, {}, \"ROI\")\n", + "m.centerObject(line)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "159", + "metadata": {}, + "outputs": [], + "source": [ + "reducer = \"mean\"\n", + "transect = geemap.extract_transect(\n", + " image, line, n_segments=100, reducer=reducer, to_pandas=True\n", + ")\n", + "transect" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "160", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.line_chart(\n", + " data=transect,\n", + " x=\"distance\",\n", + " y=\"mean\",\n", + " markers=True,\n", + " x_label=\"Distance (m)\",\n", + " y_label=\"Elevation (m)\",\n", + " height=400,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "161", + "metadata": {}, + "outputs": [], + "source": [ + "transect.to_csv(\"transect.csv\")" + ] + }, + { + "cell_type": "markdown", + "id": "162", + "metadata": {}, + "source": [ + "### Zonal statistics\n", + "\n", + "#### Zonal statistics with an image and a feature collection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "163", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "\n", + "# Add NASA SRTM\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "dem_vis = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(dem, dem_vis, \"SRTM DEM\")\n", + "\n", + "# Add 5-year Landsat TOA composite\n", + "landsat = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "landsat_vis = {\"bands\": [\"B4\", \"B3\", \"B2\"], \"gamma\": 1.4}\n", + "m.add_layer(landsat, landsat_vis, \"Landsat\", False)\n", + "\n", + "# Add US Census States\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "style = {\"fillColor\": \"00000000\"}\n", + "m.add_layer(states.style(**style), {}, \"US States\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "164", + "metadata": {}, + "outputs": [], + "source": [ + "out_dem_stats = \"dem_stats.csv\"\n", + "geemap.zonal_stats(\n", + " dem, states, out_dem_stats, statistics_type=\"MEAN\", scale=1000, return_fc=False\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "165", + "metadata": {}, + "outputs": [], + "source": [ + "out_landsat_stats = \"landsat_stats.csv\"\n", + "geemap.zonal_stats(\n", + " landsat,\n", + " states,\n", + " out_landsat_stats,\n", + " statistics_type=\"MEAN\",\n", + " scale=1000,\n", + " return_fc=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "166", + "metadata": {}, + "source": [ + "#### Zonal statistics by group" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "167", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "\n", + "# Add NLCD data\n", + "dataset = ee.Image(\"USGS/NLCD_RELEASES/2019_REL/NLCD/2019\")\n", + "landcover = dataset.select(\"landcover\")\n", + "m.add_layer(landcover, {}, \"NLCD 2019\")\n", + "\n", + "# Add US census states\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "style = {\"fillColor\": \"00000000\"}\n", + "m.add_layer(states.style(**style), {}, \"US States\")\n", + "\n", + "# Add NLCD legend\n", + "m.add_legend(title=\"NLCD Land Cover\", builtin_legend=\"NLCD\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "168", + "metadata": {}, + "outputs": [], + "source": [ + "nlcd_stats = \"nlcd_stats.csv\"\n", + "\n", + "geemap.zonal_stats_by_group(\n", + " landcover,\n", + " states,\n", + " nlcd_stats,\n", + " statistics_type=\"SUM\",\n", + " denominator=1e6,\n", + " decimal_places=2,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "169", + "metadata": {}, + "outputs": [], + "source": [ + "nlcd_stats = \"nlcd_stats_pct.csv\"\n", + "\n", + "geemap.zonal_stats_by_group(\n", + " landcover,\n", + " states,\n", + " nlcd_stats,\n", + " statistics_type=\"PERCENTAGE\",\n", + " denominator=1e6,\n", + " decimal_places=2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "170", + "metadata": {}, + "source": [ + "#### Zonal statistics with two images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "171", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "dem = ee.Image(\"USGS/3DEP/10m\")\n", + "vis = {\"min\": 0, \"max\": 4000, \"palette\": \"terrain\"}\n", + "m.add_layer(dem, vis, \"DEM\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "172", + "metadata": {}, + "outputs": [], + "source": [ + "landcover = ee.Image(\"USGS/NLCD_RELEASES/2019_REL/NLCD/2019\").select(\"landcover\")\n", + "m.add_layer(landcover, {}, \"NLCD 2019\")\n", + "m.add_legend(title=\"NLCD Land Cover Classification\", builtin_legend=\"NLCD\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "173", + "metadata": {}, + "outputs": [], + "source": [ + "stats = geemap.image_stats_by_zone(dem, landcover, reducer=\"MEAN\")\n", + "stats" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "174", + "metadata": {}, + "outputs": [], + "source": [ + "stats.to_csv(\"mean.csv\", index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "175", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.image_stats_by_zone(dem, landcover, out_csv=\"std.csv\", reducer=\"STD\")" + ] + }, + { + "cell_type": "markdown", + "id": "176", + "metadata": {}, + "source": [ + "### Map algebra" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "177", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "# Load a 5-year Landsat 7 composite 1999-2003.\n", + "landsat_1999 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "\n", + "# Compute NDVI.\n", + "ndvi_1999 = (\n", + " landsat_1999.select(\"B4\")\n", + " .subtract(landsat_1999.select(\"B3\"))\n", + " .divide(landsat_1999.select(\"B4\").add(landsat_1999.select(\"B3\")))\n", + ")\n", + "\n", + "vis = {\"min\": 0, \"max\": 1, \"palette\": \"ndvi\"}\n", + "m.add_layer(ndvi_1999, vis, \"NDVI\")\n", + "m.add_colorbar(vis, label=\"NDVI\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "178", + "metadata": {}, + "outputs": [], + "source": [ + "# Load a Landsat 8 image.\n", + "image = ee.Image(\"LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318\")\n", + "\n", + "# Compute the EVI using an expression.\n", + "evi = image.expression(\n", + " \"2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))\",\n", + " {\n", + " \"NIR\": image.select(\"B5\"),\n", + " \"RED\": image.select(\"B4\"),\n", + " \"BLUE\": image.select(\"B2\"),\n", + " },\n", + ")\n", + "\n", + "# Define a map centered on San Francisco Bay.\n", + "m = geemap.Map(center=[37.4675, -122.1363], zoom=9)\n", + "\n", + "vis = {\"min\": 0, \"max\": 1, \"palette\": \"ndvi\"}\n", + "m.add_layer(evi, vis, \"EVI\")\n", + "m.add_colorbar(vis, label=\"EVI\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "179", + "metadata": {}, + "source": [ + "## Exercise 3 - Zonal statistics\n", + "\n", + "Find out which state has the highest mean temperature in the United States on June 28, 2023. Relevant Earth Engine assets:\n", + "\n", + "- [ee.FeatureCollection(\"TIGER/2018/States\")](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2018_States)\n", + "- [ee.ImageCollection(\"NOAA/GFS0P25\")](https://developers.google.com/earth-engine/datasets/catalog/NOAA_GFS0P25)\n", + "\n", + "![](https://i.imgur.com/GZCHHz3.png)" + ] + }, + { + "cell_type": "markdown", + "id": "180", + "metadata": {}, + "source": [ + "## Working with local geospatial data\n", + "\n", + "### Raster data\n", + "\n", + "#### Single-band raster" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "181", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/giswqs/data/raw/main/raster/srtm90.tif\"\n", + "filename = \"dem.tif\"\n", + "geemap.download_file(url, filename)" + ] + }, + { + "cell_type": "markdown", + "id": "182", + "metadata": {}, + "source": [ + "#### Multi-band raster" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "183", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_raster(filename, cmap=\"terrain\", layer_name=\"DEM\")\n", + "vis_params = {\"min\": 0, \"max\": 4000, \"palette\": \"terrain\"}\n", + "m.add_colorbar(vis_params, label=\"Elevation (m)\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "184", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/giswqs/data/raw/main/raster/cog.tif\"\n", + "filename = \"cog.tif\"\n", + "geemap.download_file(url, filename)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "185", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_raster(filename, indexes=[4, 1, 2], layer_name=\"False color\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "186", + "metadata": {}, + "source": [ + "### Vector data\n", + "\n", + "#### GeoJSON" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "187", + "metadata": {}, + "outputs": [], + "source": [ + "in_geojson = (\n", + " \"https://github.com/opengeos/datasets/releases/download/vector/cables.geojson\"\n", + ")\n", + "m = geemap.Map()\n", + "m.add_geojson(in_geojson, layer_name=\"Cable lines\", info_mode=\"on_hover\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "188", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_basemap(\"CartoDB.DarkMatter\")\n", + "callback = lambda feat: {\"color\": feat[\"properties\"][\"color\"], \"weight\": 2}\n", + "m.add_geojson(in_geojson, layer_name=\"Cable lines\", style_callback=callback)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "189", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/opengeos/datasets/releases/download/world/countries.geojson\"\n", + "m = geemap.Map()\n", + "m.add_geojson(\n", + " url, layer_name=\"Countries\", fill_colors=[\"red\", \"yellow\", \"green\", \"orange\"]\n", + ")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "190", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "m = geemap.Map()\n", + "\n", + "\n", + "def random_color(feature):\n", + " return {\n", + " \"color\": \"black\",\n", + " \"weight\": 3,\n", + " \"fillColor\": random.choice([\"red\", \"yellow\", \"green\", \"orange\"]),\n", + " }\n", + "\n", + "\n", + "m.add_geojson(url, layer_name=\"Countries\", style_callback=random_color)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "191", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "style = {\n", + " \"stroke\": True,\n", + " \"color\": \"#0000ff\",\n", + " \"weight\": 2,\n", + " \"opacity\": 1,\n", + " \"fill\": True,\n", + " \"fillColor\": \"#0000ff\",\n", + " \"fillOpacity\": 0.1,\n", + "}\n", + "\n", + "hover_style = {\"fillOpacity\": 0.7}\n", + "\n", + "m.add_geojson(url, layer_name=\"Countries\", style=style, hover_style=hover_style)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "192", + "metadata": {}, + "source": [ + "#### Shapefile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "193", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/opengeos/datasets/releases/download/world/countries.zip\"\n", + "geemap.download_file(url, overwrite=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "194", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "in_shp = \"countries.shp\"\n", + "m.add_shp(in_shp, layer_name=\"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "195", + "metadata": {}, + "source": [ + "#### GeoDataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "196", + "metadata": {}, + "outputs": [], + "source": [ + "import geopandas as gpd\n", + "\n", + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "gdf = gpd.read_file(\"countries.shp\")\n", + "m.add_gdf(gdf, layer_name=\"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "197", + "metadata": {}, + "source": [ + "#### GeoPackage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "198", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "data = \"https://github.com/opengeos/datasets/releases/download/world/countries.gpkg\"\n", + "m.add_vector(data, layer_name=\"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "199", + "metadata": {}, + "source": [ + "#### CSV to vector" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "200", + "metadata": {}, + "outputs": [], + "source": [ + "data = \"https://github.com/gee-community/geemap/blob/master/examples/data/us_cities.csv\"\n", + "geemap.csv_to_df(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "201", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_geojson(\n", + " data, \"cities.geojson\", latitude=\"latitude\", longitude=\"longitude\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "202", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_shp(data, \"cities.shp\", latitude=\"latitude\", longitude=\"longitude\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "203", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_vector(data, \"cities.gpkg\", latitude=\"latitude\", longitude=\"longitude\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "204", + "metadata": {}, + "outputs": [], + "source": [ + "gdf = geemap.csv_to_gdf(data, latitude=\"latitude\", longitude=\"longitude\")\n", + "gdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "205", + "metadata": {}, + "outputs": [], + "source": [ + "cities = (\n", + " \"https://github.com/gee-community/geemap/blob/master/examples/data/us_cities.csv\"\n", + ")\n", + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_points_from_xy(cities, x=\"longitude\", y=\"latitude\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "206", + "metadata": {}, + "outputs": [], + "source": [ + "regions = \"https://github.com/gee-community/geemap/blob/master/examples/data/us_regions.geojson\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "207", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_geojson(regions, layer_name=\"US Regions\")\n", + "m.add_points_from_xy(\n", + " cities,\n", + " x=\"longitude\",\n", + " y=\"latitude\",\n", + " layer_name=\"US Cities\",\n", + " color_column=\"region\",\n", + " icon_names=[\"gear\", \"map\", \"leaf\", \"globe\"],\n", + " spin=True,\n", + " add_legend=True,\n", + ")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "208", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_circle_markers_from_xy(\n", + " data,\n", + " x=\"longitude\",\n", + " y=\"latitude\",\n", + " radius=8,\n", + " color=\"blue\",\n", + " fill_color=\"black\",\n", + " fill_opacity=0.5,\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "209", + "metadata": {}, + "source": [ + "## Accessing Cloud Optimized GeoTIFFs\n", + "\n", + "### COG" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "210", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "url = \"https://opendata.digitalglobe.com/events/california-fire-2020/pre-event/2018-02-16/pine-gulch-fire20/1030010076004E00.tif\"\n", + "m.add_cog_layer(url, name=\"Fire (pre-event)\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "211", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.cog_center(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "212", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.cog_bands(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "213", + "metadata": {}, + "outputs": [], + "source": [ + "url2 = \"https://opendata.digitalglobe.com/events/california-fire-2020/post-event/2020-08-14/pine-gulch-fire20/10300100AAC8DD00.tif\"\n", + "m.add_cog_layer(url2, name=\"Fire (post-event)\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "214", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[39.4568, -108.5107], zoom=12)\n", + "m.split_map(left_layer=url2, right_layer=url)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "215", + "metadata": {}, + "source": [ + "### SpatioTemporal Asset Catalog (STAC)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "216", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://tinyurl.com/22vptbws\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "217", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.stac_bounds(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "218", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.stac_center(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "219", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.stac_bands(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "220", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_stac_layer(url, bands=[\"pan\"], name=\"Panchromatic\")\n", + "m.add_stac_layer(url, bands=[\"B3\", \"B2\", \"B1\"], name=\"False color\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "221", + "metadata": {}, + "source": [ + "## Exporting Earth Engine data\n", + "\n", + "### Exporting images\n", + "\n", + "Add a Landsat image to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "222", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "image = ee.Image(\"LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318\").select(\n", + " [\"B5\", \"B4\", \"B3\"]\n", + ")\n", + "\n", + "vis_params = {\"min\": 0, \"max\": 0.5, \"gamma\": [0.95, 1.1, 1]}\n", + "\n", + "m.center_object(image)\n", + "m.add_layer(image, vis_params, \"Landsat\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "223", + "metadata": {}, + "source": [ + "Add a rectangle to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "224", + "metadata": {}, + "outputs": [], + "source": [ + "region = ee.Geometry.BBox(-122.5955, 37.5339, -122.0982, 37.8252)\n", + "fc = ee.FeatureCollection(region)\n", + "style = {\"color\": \"ffff00ff\", \"fillColor\": \"00000000\"}\n", + "m.add_layer(fc.style(**style), {}, \"ROI\")" + ] + }, + { + "cell_type": "markdown", + "id": "225", + "metadata": {}, + "source": [ + "To local drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "226", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image(image, filename=\"landsat.tif\", scale=30, region=region)" + ] + }, + { + "cell_type": "markdown", + "id": "227", + "metadata": {}, + "source": [ + "Check image projection." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "228", + "metadata": {}, + "outputs": [], + "source": [ + "projection = image.select(0).projection().getInfo()\n", + "projection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "229", + "metadata": {}, + "outputs": [], + "source": [ + "crs = projection[\"crs\"]\n", + "crs_transform = projection[\"transform\"]" + ] + }, + { + "cell_type": "markdown", + "id": "230", + "metadata": {}, + "source": [ + "Specify region, crs, and crs_transform." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "231", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image(\n", + " image,\n", + " filename=\"landsat_crs.tif\",\n", + " crs=crs,\n", + " crs_transform=crs_transform,\n", + " region=region,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "232", + "metadata": {}, + "source": [ + "To Google Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "233", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image_to_drive(\n", + " image, description=\"landsat\", folder=\"export\", region=region, scale=30\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "234", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.download_ee_image(image, \"landsat.tif\", scale=90)" + ] + }, + { + "cell_type": "markdown", + "id": "235", + "metadata": {}, + "source": [ + "### Exporting image collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "236", + "metadata": {}, + "outputs": [], + "source": [ + "point = ee.Geometry.Point(-99.2222, 46.7816)\n", + "collection = (\n", + " ee.ImageCollection(\"USDA/NAIP/DOQQ\")\n", + " .filterBounds(point)\n", + " .filterDate(\"2008-01-01\", \"2018-01-01\")\n", + " .filter(ee.Filter.listContains(\"system:band_names\", \"N\"))\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "237", + "metadata": {}, + "outputs": [], + "source": [ + "collection.aggregate_array(\"system:index\")" + ] + }, + { + "cell_type": "markdown", + "id": "238", + "metadata": {}, + "source": [ + "To local drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "239", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image_collection(collection, out_dir=\".\", scale=10)" + ] + }, + { + "cell_type": "markdown", + "id": "240", + "metadata": {}, + "source": [ + "To Google Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "241", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image_collection_to_drive(collection, folder=\"export\", scale=10)" + ] + }, + { + "cell_type": "markdown", + "id": "242", + "metadata": {}, + "source": [ + "### Exporting feature collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "243", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.eq(\"NAME\", \"Alaska\"))\n", + "m.add_layer(fc, {}, \"Alaska\")\n", + "m.center_object(fc, 4)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "244", + "metadata": {}, + "source": [ + "To local drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "245", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_shp(fc, filename=\"Alaska.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "246", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_vector(fc, filename=\"Alaska.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "247", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_geojson(fc, filename=\"Alaska.geojson\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "248", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_csv(fc, filename=\"Alaska.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "249", + "metadata": {}, + "outputs": [], + "source": [ + "gdf = geemap.ee_to_gdf(fc)\n", + "gdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "250", + "metadata": {}, + "outputs": [], + "source": [ + "df = geemap.ee_to_df(fc)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "id": "251", + "metadata": {}, + "source": [ + "To Google Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "252", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_vector_to_drive(\n", + " fc, description=\"Alaska\", fileFormat=\"SHP\", folder=\"export\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "253", + "metadata": {}, + "source": [ + "## Creating timelapse animations\n", + "\n", + "### Landsat timelapse" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "254", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[41.718934, -86.894547], zoom=11)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "255", + "metadata": {}, + "source": [ + "Pan and zoom the map to an area of interest. Use the drawing tools to draw a rectangle on the map. If no rectangle is drawn, the default rectangle shown below will be used." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "256", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-87.1492, 41.5812, -86.7145, 41.7531)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "257", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.landsat_timelapse(\n", + " roi,\n", + " out_gif=\"Fairbanks.gif\",\n", + " start_year=2000,\n", + " end_year=2023,\n", + " start_date=\"06-01\",\n", + " end_date=\"09-01\",\n", + " bands=[\"SWIR1\", \"NIR\", \"Red\"],\n", + " frames_per_second=5,\n", + " title=\"Landsat Timelapse\",\n", + " progress_bar_color=\"blue\",\n", + " mp4=True,\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "258", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[41.718934, -86.894547], zoom=11)\n", + "m.add_gui(\"timelapse\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "259", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "roi = ee.Geometry.BBox(-115.5541, 35.8044, -113.9035, 36.5581)\n", + "m.add_layer(roi)\n", + "m.center_object(roi)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "260", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.landsat_timelapse(\n", + " roi,\n", + " out_gif=\"las_vegas.gif\",\n", + " start_year=1984,\n", + " end_year=2023,\n", + " bands=[\"NIR\", \"Red\", \"Green\"],\n", + " frames_per_second=5,\n", + " title=\"Las Vegas, NV\",\n", + " font_color=\"blue\",\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "261", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "roi = ee.Geometry.BBox(113.8252, 22.1988, 114.0851, 22.3497)\n", + "m.add_layer(roi)\n", + "m.center_object(roi)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "262", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.landsat_timelapse(\n", + " roi,\n", + " out_gif=\"hong_kong.gif\",\n", + " start_year=1990,\n", + " end_year=2022,\n", + " start_date=\"01-01\",\n", + " end_date=\"12-31\",\n", + " bands=[\"SWIR1\", \"NIR\", \"Red\"],\n", + " frames_per_second=3,\n", + " title=\"Hong Kong\",\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "263", + "metadata": {}, + "source": [ + "### Sentinel-2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "264", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[41.718934, -86.894547], zoom=12)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "265", + "metadata": {}, + "source": [ + "Pan and zoom the map to an area of interest. Use the drawing tools to draw a rectangle on the map. If no rectangle is drawn, the default rectangle shown below will be used." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "266", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-87.0492, 41.6545, -86.7903, 41.7604)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "267", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.sentinel2_timelapse(\n", + " roi,\n", + " out_gif=\"sentinel2.gif\",\n", + " start_year=2017,\n", + " end_year=2023,\n", + " start_date=\"06-01\",\n", + " end_date=\"09-01\",\n", + " frequency=\"year\",\n", + " bands=[\"SWIR1\", \"NIR\", \"Red\"],\n", + " frames_per_second=3,\n", + " title=\"Sentinel-2 Timelapse\",\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "268", + "metadata": {}, + "source": [ + "### MODIS\n", + "\n", + "MODIS vegetation indices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "269", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "270", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-18.6983, -36.1630, 52.2293, 38.1446)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "271", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.modis_ndvi_timelapse(\n", + " roi,\n", + " out_gif=\"ndvi.gif\",\n", + " data=\"Terra\",\n", + " band=\"NDVI\",\n", + " start_date=\"2000-01-01\",\n", + " end_date=\"2022-12-31\",\n", + " frames_per_second=3,\n", + " title=\"MODIS NDVI Timelapse\",\n", + " overlay_data=\"countries\",\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "272", + "metadata": {}, + "source": [ + "MODIS temperature" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "273", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "274", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-171.21, -57.13, 177.53, 79.99)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "275", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.modis_ocean_color_timelapse(\n", + " satellite=\"Aqua\",\n", + " start_date=\"2018-01-01\",\n", + " end_date=\"2020-12-31\",\n", + " roi=roi,\n", + " frequency=\"month\",\n", + " out_gif=\"temperature.gif\",\n", + " overlay_data=\"continents\",\n", + " overlay_color=\"yellow\",\n", + " overlay_opacity=0.5,\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "276", + "metadata": {}, + "source": [ + "### GOES" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "277", + "metadata": {}, + "outputs": [], + "source": [ + "roi = ee.Geometry.BBox(167.1898, -28.5757, 202.6258, -12.4411)\n", + "start_date = \"2022-01-15T03:00:00\"\n", + "end_date = \"2022-01-15T07:00:00\"\n", + "data = \"GOES-17\"\n", + "scan = \"full_disk\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "278", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.goes_timelapse(\n", + " roi, \"goes.gif\", start_date, end_date, data, scan, framesPerSecond=5\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "279", + "metadata": {}, + "outputs": [], + "source": [ + "roi = ee.Geometry.BBox(-159.5954, 24.5178, -114.2438, 60.4088)\n", + "start_date = \"2021-10-24T14:00:00\"\n", + "end_date = \"2021-10-25T01:00:00\"\n", + "data = \"GOES-17\"\n", + "scan = \"full_disk\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "280", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.goes_timelapse(\n", + " roi, \"hurricane.gif\", start_date, end_date, data, scan, framesPerSecond=5\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "281", + "metadata": {}, + "outputs": [], + "source": [ + "roi = ee.Geometry.BBox(-121.0034, 36.8488, -117.9052, 39.0490)\n", + "start_date = \"2020-09-05T15:00:00\"\n", + "end_date = \"2020-09-06T02:00:00\"\n", + "data = \"GOES-17\"\n", + "scan = \"full_disk\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "282", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.goes_fire_timelapse(\n", + " roi, \"fire.gif\", start_date, end_date, data, scan, framesPerSecond=5\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "283", + "metadata": {}, + "source": [ + "## Exercise 4 - Creating timelapse animations\n", + "\n", + "Use the geemap timelapse GUI to create a timelapse animation for any location of your choice. Share the timelapse on social media and use the hashtagd such as #EarthEngine and #geemap. See [this](https://i.imgur.com/YaCHvKC.gif) example.\n", + "\n", + "![](https://i.imgur.com/ohrXeFC.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "284", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "285", + "metadata": {}, + "source": [ + "## Time series analysis\n", + "\n", + "### Visualizing forest cover\n", + "\n", + "We will use the [Hansen Global Forest Change v1.11 (2000-2023) dataset](https://developers.google.com/earth-engine/datasets/catalog/UMD_hansen_global_forest_change_2023_v1_11)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "286", + "metadata": {}, + "outputs": [], + "source": [ + "dataset = ee.Image(\"UMD/hansen/global_forest_change_2023_v1_11\")\n", + "dataset.bandNames()" + ] + }, + { + "cell_type": "markdown", + "id": "287", + "metadata": {}, + "source": [ + "Select the imagery for 2000." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "288", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "first_bands = [\"first_b50\", \"first_b40\", \"first_b30\"]\n", + "first_image = dataset.select(first_bands)\n", + "m.add_layer(first_image, {\"bands\": first_bands, \"gamma\": 1.5}, \"Landsat 2000\")" + ] + }, + { + "cell_type": "markdown", + "id": "289", + "metadata": {}, + "source": [ + "Select the imagery for 2023." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "290", + "metadata": {}, + "outputs": [], + "source": [ + "last_bands = [\"last_b50\", \"last_b40\", \"last_b30\"]\n", + "last_image = dataset.select(last_bands)\n", + "m.add_layer(last_image, {\"bands\": last_bands, \"gamma\": 1.5}, \"Landsat 2023\")" + ] + }, + { + "cell_type": "markdown", + "id": "291", + "metadata": {}, + "source": [ + "Select the tree cover imagery for 2000." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "292", + "metadata": {}, + "outputs": [], + "source": [ + "treecover = dataset.select([\"treecover2000\"])\n", + "treeCoverVisParam = {\"min\": 0, \"max\": 100, \"palette\": [\"black\", \"green\"]}\n", + "name = \"Tree cover (%)\"\n", + "m.add_layer(treecover, treeCoverVisParam, name)\n", + "m.add_colorbar(treeCoverVisParam, label=name, layer_name=name)\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "293", + "metadata": {}, + "source": [ + "Extract tree cover 2000 by using the threshold of 10%." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "294", + "metadata": {}, + "outputs": [], + "source": [ + "threshold = 10\n", + "treecover_bin = treecover.gte(threshold).selfMask()\n", + "treeVisParam = {\"palette\": [\"green\"]}\n", + "m.add_layer(treecover_bin, treeVisParam, \"Tree cover bin\")" + ] + }, + { + "cell_type": "markdown", + "id": "295", + "metadata": {}, + "source": [ + "### Visualizing forest gain and loss\n", + "\n", + "Visualize forest loss." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "296", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[64.864983, -147.840441], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "treeloss_year = dataset.select([\"lossyear\"])\n", + "treeLossVisParam = {\"min\": 0, \"max\": 22, \"palette\": [\"yellow\", \"red\"]}\n", + "layer_name = \"Tree loss year\"\n", + "m.add_layer(treeloss_year, treeLossVisParam, layer_name)\n", + "m.add_colorbar(treeLossVisParam, label=layer_name, layer_name=layer_name)\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "297", + "metadata": {}, + "source": [ + "Compare forest loss and gain." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "298", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[64.864983, -147.840441], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "treeloss = dataset.select([\"loss\"]).selfMask()\n", + "treegain = dataset.select([\"gain\"]).selfMask()\n", + "m.add_layer(treeloss, {\"palette\": \"red\"}, \"Tree loss\")\n", + "m.add_layer(treegain, {\"palette\": \"yellow\"}, \"Tree gain\")\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "299", + "metadata": {}, + "source": [ + "### Calculating forest cover change\n", + "\n", + "Compute zonal statistics to find out which county in Alaska has the largest forest area in 2000.\n", + "\n", + "Add a county boundary layer to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "300", + "metadata": {}, + "outputs": [], + "source": [ + "counties = ee.FeatureCollection(\"TIGER/2018/Counties\").filter(\n", + " ee.Filter.eq(\"STATEFP\", \"02\")\n", + ")\n", + "df = geemap.ee_to_df(counties)\n", + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "301", + "metadata": {}, + "outputs": [], + "source": [ + "style = {\"color\": \"0000FFFF\", \"fillColor\": \"00000000\"}\n", + "m.add_layer(counties, {}, \"Counties Vector\", False)\n", + "m.add_layer(counties.style(**style), {}, \"Counties Raster\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "302", + "metadata": {}, + "source": [ + "Compute zonal statistics by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "303", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.zonal_stats(\n", + " treecover_bin,\n", + " counties,\n", + " \"forest_cover.csv\",\n", + " stat_type=\"SUM\",\n", + " denominator=1e6,\n", + " scale=300,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "304", + "metadata": {}, + "source": [ + "Create a pie chart to visualize the forest area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "305", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.pie_chart(\n", + " \"forest_cover.csv\", names=\"NAME\", values=\"sum\", max_rows=20, height=400\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "306", + "metadata": {}, + "source": [ + "Create a bar chart to visualize the forest area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "307", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.bar_chart(\n", + " \"forest_cover.csv\",\n", + " x=\"NAME\",\n", + " y=\"sum\",\n", + " max_rows=20,\n", + " x_label=\"County\",\n", + " y_label=\"Forest area (km2)\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "308", + "metadata": {}, + "source": [ + "Calculate the forest loss area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "309", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.zonal_stats(\n", + " treeloss.gt(0),\n", + " counties,\n", + " \"treeloss.csv\",\n", + " stat_type=\"SUM\",\n", + " denominator=1e6,\n", + " scale=300,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "310", + "metadata": {}, + "source": [ + "Create a bar chart to visualize the forest loss area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "311", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.pie_chart(\"treeloss.csv\", names=\"NAME\", values=\"sum\", max_rows=20, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "312", + "metadata": {}, + "source": [ + "Create a bar chart to visualize the forest loss area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "313", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.bar_chart(\n", + " \"treeloss.csv\",\n", + " x=\"NAME\",\n", + " y=\"sum\",\n", + " max_rows=20,\n", + " x_label=\"County\",\n", + " y_label=\"Forest loss area (km2)\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "314", + "metadata": {}, + "source": [ + "## Exercise 5 - Analyzing forest cover gain and loss\n", + "\n", + "Find out which US state has the largest forest gain and loss between 2000 and 2022. Create pie charts and bar charts to show the results. Relevant Earth Engine assets:\n", + "\n", + "- [ee.FeatureCollection(\"TIGER/2018/States\")](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2018_States)\n", + "- [ee.Image(\"UMD/hansen/global_forest_change_2022_v1_10\")](https://developers.google.com/earth-engine/datasets/catalog/UMD_hansen_global_forest_change_2022_v1_10)\n", + "\n", + "![](https://i.imgur.com/NQ4UUnj.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "315", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "316", + "metadata": {}, + "source": [ + "## Image Classification\n", + "\n", + "### North American Land Change Monitoring System (NALCMS)\n", + "\n", + "The [2020 North American Land Cover 30-meter dataset](https://developers.google.com/earth-engine/datasets/catalog/USGS_NLCD_RELEASES_2020_REL_NALCMS) was produced as part of the North American Land Change Monitoring System (NALCMS), a trilateral effort between Natural Resources Canada, the United States Geological Survey, and three Mexican organizations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "317", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4, height=700)\n", + "m.add_basemap(\"Esri.WorldImagery\", False)\n", + "landcover = ee.Image(\"USGS/NLCD_RELEASES/2020_REL/NALCMS\")\n", + "\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.eq(\"NAME\", \"Alaska\"))\n", + "\n", + "legend_dict = {\n", + " \"1 Temperate forest\": \"033e00\",\n", + " \"2 Sub-polar forest\": \"939b71\",\n", + " \"3 Tropical evergreen forest\": \"196d12\",\n", + " \"4 Tropical deciduous forest\": \"1fab01\",\n", + " \"5 Temperate deciduous forest\": \"5b725c\",\n", + " \"6 Mixed forest\": \"6b7d2c\",\n", + " \"7 Tropical shrubland\": \"b29d29\",\n", + " \"8 Temperate shrubland\": \"b48833\",\n", + " \"9 Tropical grassland\": \"e9da5d\",\n", + " \"10 Temperate grassland\": \"e0cd88\",\n", + " \"11 Sub-polar shrubland\": \"a07451\",\n", + " \"12 Sub-polar grassland\": \"bad292\",\n", + " \"13 Sub-polar barren\": \"3f8970\",\n", + " \"14 Wetland\": \"6ca289\",\n", + " \"15 Cropland\": \"e6ad6a\",\n", + " \"16 Barren land\": \"a9abae\",\n", + " \"17 Urban and built-up\": \"db2126\",\n", + " \"18 Water\": \"4c73a1\",\n", + " \"19 Snow and ice \": \"fff7fe\",\n", + "}\n", + "\n", + "palette = list(legend_dict.values())\n", + "vis_params = {\"palette\": palette, \"min\": 1, \"max\": 19}\n", + "\n", + "m.add_layer(landcover, vis_params, \"NALCMS Land Cover\")\n", + "m.add_layer(fc, {}, \"Alaska\", False)\n", + "m.center_object(fc, 4)\n", + "m.add_legend(title=\"Land Cover Type\", legend_dict=legend_dict)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "318", + "metadata": {}, + "outputs": [], + "source": [ + "fig = geemap.image_histogram(\n", + " landcover, region=fc, x_label=\"Land cover type\", y_label=\"Pixels\"\n", + ")\n", + "fig" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "319", + "metadata": {}, + "outputs": [], + "source": [ + "values = list(fig.data[0][\"x\"])\n", + "values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "320", + "metadata": {}, + "outputs": [], + "source": [ + "classes = [list(legend_dict.keys())[int(value) - 1] for value in values]\n", + "classes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "321", + "metadata": {}, + "outputs": [], + "source": [ + "fig.update_xaxes(tickvals=values, ticktext=classes)\n", + "fig" + ] + }, + { + "cell_type": "markdown", + "id": "322", + "metadata": {}, + "source": [ + "### Unsupervised classification" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "323", + "metadata": {}, + "outputs": [], + "source": [ + "region = ee.Geometry.BBox(-149.352, 64.5532, -147.0976, 65.1277)\n", + "collection = geemap.landsat_timeseries(\n", + " region, start_year=2021, end_year=2021, start_date=\"06-01\", end_date=\"09-01\"\n", + ")\n", + "image = collection.first()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "324", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "vis_params = {\"min\": 0, \"max\": 0.3, \"bands\": [\"NIR\", \"Red\", \"Green\"]}\n", + "m.add_layer(image, vis_params, \"Image\")\n", + "m.add_layer(landcover.clip(region), {}, \"NALCMS land cover\", False)\n", + "# m.add_legend(title='Land Cover Type', legend_dict=legend_dict, layer_name='NALCMS land cover')\n", + "m.center_object(region, 9)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "325", + "metadata": {}, + "outputs": [], + "source": [ + "training = image.sample(\n", + " **{\n", + " \"region\": region,\n", + " \"scale\": 150,\n", + " \"numPixels\": 5000,\n", + " \"seed\": 1,\n", + " \"geometries\": True,\n", + " }\n", + ")\n", + "m.add_layer(training, {}, \"Training samples\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "326", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_df(training.limit(5))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "327", + "metadata": {}, + "outputs": [], + "source": [ + "clusterer = ee.Clusterer.wekaXMeans(minClusters=3, maxClusters=6).train(training)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "328", + "metadata": {}, + "outputs": [], + "source": [ + "result = image.cluster(clusterer)\n", + "m.add_layer(result.randomVisualizer(), {}, \"Clusters\")\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "329", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.image_histogram(landcover, region=region, scale=30)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "330", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.image_histogram(result, region=region, scale=300)" + ] + }, + { + "cell_type": "markdown", + "id": "331", + "metadata": {}, + "source": [ + "### Supervised classification" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "332", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "vis_params = {\"min\": 0, \"max\": 0.3, \"bands\": [\"NIR\", \"Red\", \"Green\"]}\n", + "m.add_layer(image, vis_params, \"Image\")\n", + "m.add_layer(landcover.clip(region), {}, \"NALCMS land cover\", False)\n", + "# m.add_legend(title='Land Cover Type', legend_dict=legend_dict, layer_name='NALCMS land cover')\n", + "m.center_object(region, 9)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "333", + "metadata": {}, + "outputs": [], + "source": [ + "points = landcover.sample(\n", + " **{\n", + " \"region\": region,\n", + " \"scale\": 150,\n", + " \"numPixels\": 5000,\n", + " \"seed\": 1,\n", + " \"geometries\": True,\n", + " }\n", + ")\n", + "\n", + "m.add_layer(points, {}, \"Training\", False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "334", + "metadata": {}, + "outputs": [], + "source": [ + "label = \"landcover\"\n", + "features = image.sampleRegions(\n", + " **{\"collection\": points, \"properties\": [label], \"scale\": 150}\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "335", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_df(features.limit(5))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "336", + "metadata": {}, + "outputs": [], + "source": [ + "bands = image.bandNames().getInfo()\n", + "params = {\n", + " \"features\": features,\n", + " \"classProperty\": label,\n", + " \"inputProperties\": bands,\n", + "}\n", + "classifier = ee.Classifier.smileCart(maxNodes=None).train(**params)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "337", + "metadata": {}, + "outputs": [], + "source": [ + "classified = image.classify(classifier).rename(\"landcover\")\n", + "m.add_layer(classified.randomVisualizer(), {}, \"Classified\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "338", + "metadata": {}, + "outputs": [], + "source": [ + "class_values = list(range(1, 20))\n", + "class_palette = list(legend_dict.values())\n", + "classified = classified.set(\n", + " {\"landcover_class_values\": class_values, \"landcover_class_palette\": class_palette}\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "339", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_layer(classified, {}, \"Land cover\")\n", + "m.add_legend(title=\"Land cover type\", builtin_legend=\"NLCD\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "340", + "metadata": {}, + "source": [ + "## Accuracy assessment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "341", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "point = ee.Geometry.Point([-122.4439, 37.7538])\n", + "\n", + "img = (\n", + " ee.ImageCollection(\"COPERNICUS/S2_SR\")\n", + " .filterBounds(point)\n", + " .filterDate(\"2020-01-01\", \"2021-01-01\")\n", + " .sort(\"CLOUDY_PIXEL_PERCENTAGE\")\n", + " .first()\n", + " .select(\"B.*\")\n", + ")\n", + "\n", + "vis_params = {\"min\": 100, \"max\": 3500, \"bands\": [\"B11\", \"B8\", \"B3\"]}\n", + "\n", + "m.centerObject(point, 9)\n", + "m.add_layer(img, vis_params, \"Sentinel-2\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "342", + "metadata": {}, + "outputs": [], + "source": [ + "lc = ee.Image(\"ESA/WorldCover/v100/2020\")\n", + "classValues = [10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 100]\n", + "remapValues = ee.List.sequence(0, 10)\n", + "label = \"lc\"\n", + "lc = lc.remap(classValues, remapValues).rename(label).toByte()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "343", + "metadata": {}, + "outputs": [], + "source": [ + "sample = img.addBands(lc).stratifiedSample(\n", + " **{\n", + " \"numPoints\": 100,\n", + " \"classBand\": label,\n", + " \"region\": img.geometry(),\n", + " \"scale\": 10,\n", + " \"geometries\": True,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "344", + "metadata": {}, + "outputs": [], + "source": [ + "sample = sample.randomColumn()\n", + "trainingSample = sample.filter(\"random <= 0.8\")\n", + "validationSample = sample.filter(\"random > 0.8\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "345", + "metadata": {}, + "outputs": [], + "source": [ + "trainedClassifier = ee.Classifier.smileRandomForest(numberOfTrees=10).train(\n", + " **{\n", + " \"features\": trainingSample,\n", + " \"classProperty\": label,\n", + " \"inputProperties\": img.bandNames(),\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "346", + "metadata": {}, + "outputs": [], + "source": [ + "# print('Results of trained classifier', trainedClassifier.explain().getInfo())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "347", + "metadata": {}, + "outputs": [], + "source": [ + "trainAccuracy = trainedClassifier.confusionMatrix()\n", + "trainAccuracy.getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "348", + "metadata": {}, + "outputs": [], + "source": [ + "trainAccuracy.accuracy().getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "349", + "metadata": {}, + "outputs": [], + "source": [ + "trainAccuracy.kappa().getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "350", + "metadata": {}, + "outputs": [], + "source": [ + "validationSample = validationSample.classify(trainedClassifier)\n", + "validationAccuracy = validationSample.errorMatrix(label, \"classification\")\n", + "validationAccuracy.getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "351", + "metadata": {}, + "outputs": [], + "source": [ + "validationAccuracy.accuracy()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "352", + "metadata": {}, + "outputs": [], + "source": [ + "validationAccuracy.producersAccuracy().getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "353", + "metadata": {}, + "outputs": [], + "source": [ + "validationAccuracy.consumersAccuracy().getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "354", + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "\n", + "with open(\"training.csv\", \"w\", newline=\"\") as f:\n", + " writer = csv.writer(f)\n", + " writer.writerows(trainAccuracy.getInfo())\n", + "\n", + "with open(\"validation.csv\", \"w\", newline=\"\") as f:\n", + " writer = csv.writer(f)\n", + " writer.writerows(validationAccuracy.getInfo())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "355", + "metadata": {}, + "outputs": [], + "source": [ + "imgClassified = img.classify(trainedClassifier)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "356", + "metadata": {}, + "outputs": [], + "source": [ + "classVis = {\n", + " \"min\": 0,\n", + " \"max\": 10,\n", + " \"palette\": [\n", + " \"006400\",\n", + " \"ffbb22\",\n", + " \"ffff4c\",\n", + " \"f096ff\",\n", + " \"fa0000\",\n", + " \"b4b4b4\",\n", + " \"f0f0f0\",\n", + " \"0064c8\",\n", + " \"0096a0\",\n", + " \"00cf75\",\n", + " \"fae6a0\",\n", + " ],\n", + "}\n", + "m.add_layer(lc, classVis, \"ESA Land Cover\", False)\n", + "m.add_layer(imgClassified, classVis, \"Classified\")\n", + "m.add_layer(trainingSample, {\"color\": \"black\"}, \"Training sample\")\n", + "m.add_layer(validationSample, {\"color\": \"white\"}, \"Validation sample\")\n", + "m.add_legend(title=\"Land Cover Type\", builtin_legend=\"ESA_WorldCover\")\n", + "m.centerObject(img)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "357", + "metadata": {}, + "source": [ + "## Exercise 6 - Unsupervised classification\n", + "\n", + "Perform an unsupervised classification of a Sentinel-2 imagery for your preferred area. Relevant Earth Engine assets:\n", + "\n", + "- [ee.ImageCollection(\"COPERNICUS/S2_HARMONIZED\")](https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2_HARMONIZED)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "358", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "359", + "metadata": {}, + "source": [ + "## Create and export maps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "360", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(41.0462, -109.7424), zoom=6)\n", + "\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\").select(\n", + " [\"B1\", \"B2\", \"B3\", \"B4\", \"B5\", \"B7\"]\n", + ")\n", + "\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "\n", + "m.add_layer(\n", + " landsat7,\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 20, \"max\": 200, \"gamma\": 2},\n", + " \"landsat\",\n", + ")\n", + "m.add_layer(dem, vis_params, \"dem\", True, 1)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "361", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " m.layer_to_image(\"dem\", output=\"dem.tif\", crs=\"EPSG:3857\", region=None, scale=None)\n", + " m.layer_to_image(\"dem\", output=\"dem.jpg\", scale=500)\n", + " geemap.show_image(\"dem.jpg\")\n", + "except:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "362", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " m.layer_to_image(\"landsat\", output=\"landsat.tif\")\n", + " geemap.geotiff_to_image(\"landsat.tif\", output=\"landsat.jpg\")\n", + " geemap.show_image(\"landsat.jpg\")\n", + "except:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "363", + "metadata": {}, + "outputs": [], + "source": [ + "from geemap import cartoee\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "364", + "metadata": {}, + "source": [ + "### Plotting single-band images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "365", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "from geemap import cartoee" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "366", + "metadata": {}, + "outputs": [], + "source": [ + "srtm = ee.Image(\"CGIAR/SRTM90_V4\")\n", + "\n", + "# define bounding box [east, south, west, north] to request data\n", + "region = [180, -60, -180, 85]\n", + "vis = {\"min\": 0, \"max\": 3000}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "367", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 9))\n", + "\n", + "# use cartoee to get a map\n", + "ax = cartoee.get_map(srtm, region=region, vis_params=vis)\n", + "\n", + "# add a color bar to the map using the visualization params we passed to the map\n", + "cartoee.add_colorbar(\n", + " ax, vis, loc=\"bottom\", label=\"Elevation (m)\", orientation=\"horizontal\"\n", + ")\n", + "\n", + "# add grid lines to the map at a specified interval\n", + "cartoee.add_gridlines(ax, interval=[60, 30], linestyle=\":\")\n", + "\n", + "# add coastlines using the cartopy api\n", + "ax.coastlines(color=\"red\")\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "368", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 7))\n", + "\n", + "cmap = \"terrain\"\n", + "\n", + "ax = cartoee.get_map(srtm, region=region, vis_params=vis, cmap=cmap)\n", + "cartoee.add_colorbar(\n", + " ax, vis, cmap=cmap, loc=\"right\", label=\"Elevation (m)\", orientation=\"vertical\"\n", + ")\n", + "\n", + "cartoee.add_gridlines(ax, interval=[60, 30], linestyle=\"--\")\n", + "ax.coastlines(color=\"red\")\n", + "ax.set_title(label=\"Global Elevation Map\", fontsize=15)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "369", + "metadata": {}, + "outputs": [], + "source": [ + "cartoee.savefig(fig, fname=\"srtm.jpg\", dpi=300, bbox_inches=\"tight\")" + ] + }, + { + "cell_type": "markdown", + "id": "370", + "metadata": {}, + "source": [ + "### Plotting multi-band images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "371", + "metadata": {}, + "outputs": [], + "source": [ + "image = ee.Image(\"LANDSAT/LC08/C01/T1_SR/LC08_044034_20140318\")\n", + "vis = {\"bands\": [\"B5\", \"B4\", \"B3\"], \"min\": 0, \"max\": 5000, \"gamma\": 1.3}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "372", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "ax = cartoee.get_map(image, vis_params=vis)\n", + "cartoee.pad_view(ax)\n", + "cartoee.add_gridlines(ax, interval=0.5, xtick_rotation=0, linestyle=\":\")\n", + "ax.coastlines(color=\"yellow\")\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "373", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "region = [-121.8025, 37.3458, -122.6265, 37.9178]\n", + "ax = cartoee.get_map(image, vis_params=vis, region=region)\n", + "cartoee.add_gridlines(ax, interval=0.15, xtick_rotation=0, linestyle=\":\")\n", + "ax.coastlines(color=\"yellow\")\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "374", + "metadata": {}, + "source": [ + "### Using custom projections\n", + "\n", + "#### The PlateCarree projection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "375", + "metadata": {}, + "outputs": [], + "source": [ + "ocean = (\n", + " ee.ImageCollection(\"NASA/OCEANDATA/MODIS-Terra/L3SMI\")\n", + " .filter(ee.Filter.date(\"2018-01-01\", \"2018-03-01\"))\n", + " .median()\n", + " .select([\"sst\"], [\"SST\"])\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "376", + "metadata": {}, + "outputs": [], + "source": [ + "visualization = {\"bands\": \"SST\", \"min\": -2, \"max\": 30}\n", + "bbox = [180, -88, -180, 88]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "377", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "ax = cartoee.get_map(ocean, cmap=\"plasma\", vis_params=visualization, region=bbox)\n", + "cb = cartoee.add_colorbar(ax, vis_params=visualization, loc=\"right\", cmap=\"plasma\")\n", + "\n", + "ax.set_title(label=\"Sea Surface Temperature\", fontsize=15)\n", + "\n", + "ax.coastlines()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "378", + "metadata": {}, + "outputs": [], + "source": [ + "cartoee.savefig(fig, \"SST.jpg\", dpi=300)" + ] + }, + { + "cell_type": "markdown", + "id": "379", + "metadata": {}, + "source": [ + "#### Custom projections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "380", + "metadata": {}, + "outputs": [], + "source": [ + "import cartopy.crs as ccrs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "381", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "projection = ccrs.Mollweide(central_longitude=-180)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"bottom\", cmap=\"plasma\", orientation=\"horizontal\"\n", + ")\n", + "ax.set_title(\"Mollweide projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "382", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "projection = ccrs.Robinson(central_longitude=-180)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"bottom\", cmap=\"plasma\", orientation=\"horizontal\"\n", + ")\n", + "ax.set_title(\"Robinson projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "383", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "projection = ccrs.InterruptedGoodeHomolosine(central_longitude=-180)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"bottom\", cmap=\"plasma\", orientation=\"horizontal\"\n", + ")\n", + "ax.set_title(\"Goode homolosine projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "384", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "projection = ccrs.EqualEarth(central_longitude=-180)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"right\", cmap=\"plasma\", orientation=\"vertical\"\n", + ")\n", + "ax.set_title(\"Equal Earth projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "385", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(11, 10))\n", + "\n", + "projection = ccrs.Orthographic(-130, -10)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"right\", cmap=\"plasma\", orientation=\"vertical\"\n", + ")\n", + "ax.set_title(\"Orographic projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "386", + "metadata": {}, + "source": [ + "## Exercise 7 - Creating NDVI maps\n", + "\n", + "Create and export a global NDVI map using MODIS data. Relevant Earth Engine assets:\n", + "\n", + "- [ee.ImageCollection(\"MODIS/MCD43A4_006_NDVI\")](https://developers.google.com/earth-engine/datasets/catalog/MODIS_MCD43A4_006_NDVI)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "387", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "388", + "metadata": {}, + "source": [ + "## Building interactive web apps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "389", + "metadata": {}, + "outputs": [], + "source": [ + "import ee\n", + "import geemap\n", + "import solara\n", + "\n", + "\n", + "class Map(geemap.Map):\n", + " def __init__(self, **kwargs):\n", + " super().__init__(**kwargs)\n", + " self.add_ee_data()\n", + "\n", + " def add_ee_data(self):\n", + " years = [\"2001\", \"2004\", \"2006\", \"2008\", \"2011\", \"2013\", \"2016\", \"2019\"]\n", + "\n", + " def getNLCD(year):\n", + " dataset = ee.ImageCollection(\"USGS/NLCD_RELEASES/2019_REL/NLCD\")\n", + " nlcd = dataset.filter(ee.Filter.eq(\"system:index\", year)).first()\n", + " landcover = nlcd.select(\"landcover\")\n", + " return landcover\n", + "\n", + " collection = ee.ImageCollection(ee.List(years).map(lambda year: getNLCD(year)))\n", + " labels = [f\"NLCD {year}\" for year in years]\n", + " self.ts_inspector(\n", + " left_ts=collection,\n", + " right_ts=collection,\n", + " left_names=labels,\n", + " right_names=labels,\n", + " )\n", + " self.add_legend(\n", + " title=\"NLCD Land Cover Type\",\n", + " builtin_legend=\"NLCD\",\n", + " height=\"460px\",\n", + " add_header=False,\n", + " )\n", + "\n", + "\n", + "@solara.component\n", + "def Page():\n", + " with solara.Column(style={\"min-width\": \"500px\"}):\n", + " Map.element(\n", + " center=[40, -100],\n", + " zoom=4,\n", + " height=\"800px\",\n", + " )\n", + "\n", + "\n", + "Page()" + ] + }, + { + "cell_type": "markdown", + "id": "390", + "metadata": {}, + "source": [ + "```bash\n", + "solara run ./pages\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "391", + "metadata": {}, + "outputs": [], + "source": [ + "# geemap.get_ee_token()" + ] + }, + { + "cell_type": "markdown", + "id": "392", + "metadata": {}, + "source": [ + "## Exercise 8 - Deploying an Earth Engine app on Hugging Face.\n", + "\n", + "Follow the instructions [here](https://huggingface.co/spaces/giswqs/solara-geemap) to deploy an Earth Engine web app on Hugging Face." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "393", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/workshops/IGIC_2024.ipynb b/examples/workshops/IGIC_2024.ipynb new file mode 100644 index 0000000000..27bdee78e5 --- /dev/null +++ b/examples/workshops/IGIC_2024.ipynb @@ -0,0 +1,5260 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/gee-community/geemap/blob/master/docs/workshops/IGIC_2024.ipynb)\n", + "\n", + "**Intro to Earth Engine in Python**\n", + "\n", + "- Notebook: \n", + "- Earth Engine: \n", + "- Geemap: \n", + "\n", + "## Introduction\n", + "\n", + "This notebook contains the materials for the workshop **Intro to Earth Engine in Python** at the 2024 Indiana Geographic Information Council (IGIC) Annual Conference.\n", + "\n", + "This workshop provides an introduction to cloud-based geospatial analysis using the Earth Engine Python API. Attendees will learn the basics of Earth Engine data types and how to visualize, analyze, and export Earth Engine data in a Jupyter environment with geemap. In addition, attendees will learn how to develop and deploy interactive Earth Engine web apps with Python. Through practical examples and hands-on exercises, attendees will enhance their learning experience. It is recommended that attendees have a basic understanding of Python and Jupyter Notebook. Familiarity with the Earth Engine JavaScript API is not required but will be helpful. Attendees can use Google Colab to follow this workshop without installing anything on their computer.\n", + "\n", + "### Agenda\n", + "\n", + "The workshop is divided into three parts.\n", + "\n", + "#### Part 1\n", + "\n", + "The first part will cover the following topics:\n", + "\n", + "- Introduction to Google Earth Engine\n", + "- Getting started with Geemap\n", + "- Introduction to Geemap core features\n", + "- Finding help on GEE and Geemap technical issues\n", + "- Search Earth Engine API documentation within Jupyter notebooks\n", + "- Introduction to interactive maps and tools\n", + "- Using Earth Data Catalog to access Image and Image collections\n", + "- Using Earth Data Catalog to access Feature and Feature collections\n", + "- Display EE images and feature data and explore their properties\n", + "\n", + "#### Part 2\n", + "\n", + "The second part will cover the following topics:\n", + "\n", + "- Processing of vector data\n", + "- Processing of raster data\n", + "- Working with local geospatial data in Geemap\n", + "- Accessing Cloud Optimized GeoTIFF\n", + "- Exporting EE Image and Feature data\n", + "- Creating timelapse animations using Landsat or Sentinel 2\n", + "- Time series analysis: Forest cover change\n", + "\n", + "#### Part 3\n", + "\n", + "The third part will cover the following topics:\n", + "\n", + "- Image Classification\n", + "- Accuracy assessment\n", + "- Create and export maps\n", + "- Building interactive web apps\n", + "\n", + "### Prerequisites\n", + "\n", + "- To use geemap and the Earth Engine Python API, you must [register](https://code.earthengine.google.com/register) for an Earth Engine account and follow the instructions [here](https://docs.google.com/document/d/1ZGSmrNm6_baqd8CHt33kIBWOlvkh-HLr46bODgJN1h0/edit?usp=sharing) to create a Cloud Project. Earth Engine is free for [noncommercial and research use](https://earthengine.google.com/noncommercial). To test whether you can use authenticate the Earth Engine Python API, please run [this notebook](https://colab.research.google.com/github/giswqs/geemap/blob/master/examples/notebooks/geemap_colab.ipynb) on Google Colab.\n", + "\n", + "## Introduction to Google Earth Engine\n", + "\n", + "### Google Earth Engine\n", + "\n", + "[Google Earth Engine](https://earthengine.google.com) is a cloud-computing platform for scientific analysis and visualization of geospatial datasets. It is free for [noncommercial and research use](https://earthengine.google.com/noncommercial). For more than a decade, Earth Engine has enabled planetary-scale Earth data science and analysis by nonprofit organizations, research scientists, and other impact users.\n", + "\n", + "With the launch of Earth Engine for [commercial use](https://earthengine.google.com/commercial), commercial customers will be charged for Earth Engine services. However, Earth Engine will remain free of charge for noncommercial use and research projects. Nonprofit organizations, academic institutions, educators, news media, Indigenous governments, and government researchers are eligible to use Earth Engine free of charge, just as they have done for over a decade.\n", + "\n", + "![](https://i.imgur.com/1XtOTwN.png)\n", + "\n", + "### The Earth Engine Public Data Catalog\n", + "\n", + "[![](https://i.imgur.com/pDyd7yH.png)](https://developers.google.com/earth-engine/datasets/)\n", + "\n", + "### The Awesome GEE Community Data Catalog\n", + "\n", + "[![](https://i.imgur.com/h6Dnlhb.png)](https://gee-community-catalog.org/)\n", + "\n", + "### The Earth Engine APIs\n", + "\n", + "![](https://i.imgur.com/RHPEQzF.png)\n", + "\n", + "### Geemap\n", + "\n", + "[![](https://i.imgur.com/cEfc1iV.png)](https://geemap.org/)\n", + "\n", + "## Getting started with Geemap\n", + "\n", + "[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/gee-community/geemap/blob/master/docs/workshops/IGIC_2024.ipynb)\n", + "\n", + "### Change Colab dark theme\n", + "\n", + "Currently, ipywidgets does not work well with Colab dark theme. Some of the geemap widgets may not display properly in Colab dark theme.It is recommended that you change Colab to the light theme.\n", + "\n", + "![](https://i.imgur.com/EJ0GDP8.png)\n", + "\n", + "### Install geemap\n", + "\n", + "The geemap package is pre-installed in Google Colab and is updated to the latest minor or major release every few weeks. Some optional dependencies of geemap being used by this notebook are not pre-installed in Colab. Uncomment the following line to install geemap and some optional dependencies." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install -U \"geemap[workshop]\" cartopy solara flask==2.3.3" + ] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "Note that some geemap features do not work properly with Google Colab. If you are familiar with [Anaconda](https://www.anaconda.com/download) or [Miniconda](https://docs.anaconda.com/free/miniconda), it is recommended to create a new conda environment to install geemap and its optional dependencies on your local computer.\n", + "\n", + "```bash\n", + "conda create -n gee python=3.11\n", + "conda activate gee\n", + "conda install -c conda-forge mamba\n", + "mamba install -c conda-forge geemap pygis cartopy solara flask==2.3.3\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "### Import libraries\n", + "\n", + "Import the earthengine-api and geemap." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "import ee\n", + "import geemap" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "### Authenticate and initialize Earth Engine\n", + "\n", + "You will need to create a [Google Cloud Project](https://console.cloud.google.com/projectcreate) and enable the [Earth Engine API](https://console.cloud.google.com/apis/api/earthengine.googleapis.com) for the project. You can find detailed instructions [here](https://book.geemap.org/chapters/01_introduction.html#earth-engine-authentication)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_initialize()" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "### Creating interactive maps\n", + "\n", + "Let's create an interactive map using the `ipyleaflet` plotting backend. The [`geemap.Map`](https://geemap.org/geemap/#geemap.geemap.m) class inherits the [`ipyleaflet.Map`](https://ipyleaflet.readthedocs.io/en/latest/map_and_basemaps/map.html) class. Therefore, you can use the same syntax to create an interactive map as you would with `ipyleaflet.Map`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "To display it in a Jupyter notebook, simply ask for the object representation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "m" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "To customize the map, you can specify various keyword arguments, such as `center` ([lat, lon]), `zoom`, `width`, and `height`. The default `width` is `100%`, which takes up the entire cell width of the Jupyter notebook. The `height` argument accepts a number or a string. If a number is provided, it represents the height of the map in pixels. If a string is provided, the string must be in the format of a number followed by `px`, e.g., `600px`.\n", + "\n", + "Generate a map that focuses on the contiguous United States." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "Generate a map that focuses on Indiana." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[39.814613, -86.117887], zoom=7)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "Generate a map that focuses on Michigan City, IN." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[41.701756, -86.895448], zoom=13)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "To hide a control, set `control_name` to `False`, e.g., `draw_ctrl=False`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(data_ctrl=False, toolbar_ctrl=False, draw_ctrl=False)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "### Adding basemaps\n", + "\n", + "There are several ways to add basemaps to a map. You can specify the basemap to use in the `basemap` keyword argument when creating the map. Alternatively, you can add basemap layers to the map using the `add_basemap` method. Geemap has hundreds of built-in basemaps available that can be easily added to the map with only one line of code.\n", + "\n", + "Create a map by specifying the basemap to use as follows. For example, the `Esri.WorldImagery` basemap represents the Esri world imagery basemap." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(basemap=\"Esri.WorldImagery\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "21", + "metadata": {}, + "source": [ + "You can add as many basemaps as you like to the map. For example, the following code adds the `OpenTopoMap` basemap to the map above:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_basemap(\"Esri.WorldTopoMap\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_basemap(\"OpenTopoMap\")" + ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "Print out the first 10 basemaps:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "basemaps = list(geemap.basemaps.keys())\n", + "len(geemap.basemaps)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26", + "metadata": {}, + "outputs": [], + "source": [ + "basemaps[:10]" + ] + }, + { + "cell_type": "markdown", + "id": "27", + "metadata": {}, + "source": [ + "You can also change basemaps interactively using the basemap GUI." + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "### Google basemaps\n", + "\n", + "Google basemaps are not included in the geemap built-in basemaps due to license issues ([source](https://github.com/gee-community/geemap/pull/1681#issuecomment-1707109740)). Users can choose to add Google basemaps at their own risks as follows:\n", + "\n", + "```text\n", + "ROADMAP: https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}\n", + "SATELLITE: https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}\n", + "TERRAIN: https://mt1.google.com/vt/lyrs=p&x={x}&y={y}&z={z}\n", + "HYBRID: https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "url = \"https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}\"\n", + "m.add_tile_layer(url, name=\"Google Satellite\", attribution=\"Google\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "## Introduction to geemap features\n", + "\n", + "- Core features: maintained by the Earth Engine team at Google\n", + "- Extra features: maintained by the Earth Engine community\n", + "\n", + "### Core features\n", + "\n", + "- Basemap selector\n", + "- Layer manager\n", + "- Layer editor\n", + "- Inspector\n", + "- Draw control\n", + "\n", + "[![](https://i.imgur.com/SMaZtlm.png)](https://developers.google.com/earth-engine/guides/image_visualization#colab-python)\n", + "\n", + "[![](https://i.imgur.com/Y6Ut7yf.png)](https://youtu.be/EDSqGmNLOcU)\n", + "\n", + "### Extra features\n", + "\n", + "- Converting EE JavaScript to Python automatically\n", + "- Exploring the EE Data Catalog\n", + "- Creating color bars for Earth Engine images\n", + "- Plotting Earth Engine data\n", + "- Time slider\n", + "- Timeseries inspector\n", + "- Using geemap with ArcGIS Pro\n", + "- Custom map projections\n", + "- Timelapse animations\n", + "- Developing interactive web apps\n", + "\n", + "[![](https://i.imgur.com/qZXUUEI.png)](https://youtu.be/jVAGX7ibFis)" + ] + }, + { + "cell_type": "markdown", + "id": "31", + "metadata": {}, + "source": [ + "## Finding help on GEE and Geemap technical issues\n", + "\n", + "- Earth Engine Developer Guide: https://developers.google.com/earth-engine/guides\n", + "- Earth Engine Developers Forum: https://groups.google.com/forum/#!forum/google-earth-engine-developers\n", + "- Geemap website: https://geemap.org\n", + "- Bug reports and feature requests: https://github.com/gee-community/geemap/issues\n", + "- Q&A: https://github.com/gee-community/geemap/discussions" + ] + }, + { + "cell_type": "markdown", + "id": "32", + "metadata": {}, + "source": [ + "## Search Earth Engine API documentation within Jupyter notebooks\n", + "\n", + "### Geemap API reference\n", + "\n", + "1. Create a new code cell.\n", + "2. Type `geemap.` in the code cell.\n", + "3. Press the TAB key on your keyboard.\n", + "4. Utilize the Up/Down arrow keys to navigate through the available functions and classes.\n", + "5. Once you've selected the desired function or class, press Enter to insert it into your code.\n", + "\n", + "![](https://i.imgur.com/WWzImNv.png)\n", + "\n", + "6. Once you've selected a function or class, place the cursor within the parentheses of the function or class.\n", + "7. Press the TAB key again to display the API reference for the selected function or class.\n", + "\n", + "![](https://i.imgur.com/bSLCUrk.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "34", + "metadata": {}, + "source": [ + "### Earth Engine API reference\n", + "\n", + "1. Create a new code cell.\n", + "2. Type `ee.` in the code cell.\n", + "3. Press the TAB key on your keyboard.\n", + "4. Utilize the Up/Down arrow keys to navigate through the available functions and classes.\n", + "5. Once you've selected the desired function or class, press Enter to insert it into your code.\n", + "\n", + "![](https://i.imgur.com/TIRF1nD.png)\n", + "\n", + "6. Once you've selected a function or class, place the cursor within the parentheses of the function or class.\n", + "7. Press the TAB key again to display the API reference for the selected function or class.\n", + "\n", + "![](https://i.imgur.com/oVJR8Yt.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "36", + "metadata": {}, + "source": [ + "## Introduction to interactive maps and tools\n", + "\n", + "### Basemap selector\n", + "\n", + "Select a basemap from the dropdown list and add it to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add(\"basemap_selector\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "38", + "metadata": {}, + "source": [ + "### Layer Manager\n", + "\n", + "Toggle the checkbox to show or hide the layer. Drag and move the slider to change the transparency level of the layer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add_layer(states, {}, \"US States\")\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "40", + "metadata": {}, + "source": [ + "### Inspector\n", + "\n", + "Click on the map to query Earth Engine data at a specific location." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add_layer(\n", + " landsat7,\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 20, \"max\": 200, \"gamma\": 2.0},\n", + " \"Landsat 7\",\n", + ")\n", + "m.add_layer(states, {}, \"US States\")\n", + "m.add(\"inspector\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "42", + "metadata": {}, + "source": [ + "### Layer Editor\n", + "\n", + "You can change the visualization parameters of the Earth Engine data using the layer editor.\n", + "\n", + "#### Single-band image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add(\"layer_editor\", layer_dict=m.ee_layers[\"SRTM DEM\"])\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "44", + "metadata": {}, + "source": [ + "#### Multi-band image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "m.add_layer(\n", + " landsat7,\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 20, \"max\": 200, \"gamma\": 2.0},\n", + " \"Landsat 7\",\n", + ")\n", + "m.add(\"layer_editor\", layer_dict=m.ee_layers[\"Landsat 7\"])\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "46", + "metadata": {}, + "source": [ + "#### Feature collection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "m.add_layer(states, {}, \"US States\")\n", + "m.add(\"layer_editor\", layer_dict=m.ee_layers[\"US States\"])\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "48", + "metadata": {}, + "source": [ + "### Draw control\n", + "\n", + "You can draw shapes on the map using the draw control. The drawn features will be automatically converted to Earth Engine objects, which can be accessed in one of the following ways:\n", + "\n", + "- To return the last drawn feature as an `ee.Geometry()`, use: `m.user_roi`\n", + "- To return all the drawn features as an `ee.FeatureCollection()`, use: `m.user_rois`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4)\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": \"terrain\",\n", + "}\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50", + "metadata": {}, + "outputs": [], + "source": [ + "if m.user_roi is not None:\n", + " image = dem.clip(m.user_roi)\n", + " m.layers[1].visible = False\n", + " m.add_layer(image, vis_params, \"Clipped DEM\")" + ] + }, + { + "cell_type": "markdown", + "id": "51", + "metadata": {}, + "source": [ + "## The Earth Engine Data Catalog\n", + "\n", + "The [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets) hosts a variety of geospatial datasets. As of March 2024, the catalog contains over [1,100 datasets](https://github.com/opengeos/Earth-Engine-Catalog/blob/master/gee_catalog.tsv) with a total size of over 100 petabytes. Some notable datasets include: Landsat, Sentinel, MODIS, NAIP, etc. For a complete list of datasets in CSV or JSON formats, see the [Earth Engine Datasets List](https://github.com/giswqs/Earth-Engine-Catalog/blob/master/gee_catalog.tsv).\n", + "\n", + "### Searching datasets on the Earth Engine website\n", + "\n", + "- View all datasets: https://developers.google.com/earth-engine/datasets/catalog\n", + "- Search by tags: https://developers.google.com/earth-engine/datasets/tags\n", + "\n", + "### Searching datasets within geemap\n", + "\n", + "The [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets/catalog) is searchable. You can search datasets by name, keyword, or tag. For example, enter \"elevation\" in the search box will filter the catalog to show only datasets containing \"elevation\" in their name, description, or tags. 52 datasets are returned for this search query. Scroll down the list to find the [NASA SRTM Digital Elevation 30m](https://developers.google.com/earth-engine/datasets/catalog/USGS_SRTMGL1_003#description) dataset. On each dataset page, you can find the following information, including Dataset Availability, Dataset Provider, Earth Engine Snippet, Tags, Description, Code Example, and more. One important piece of information is the Image/ImageCollection/FeatureCollection ID of each dataset, which is essential for accessing the dataset through the Earth Engine JavaScript or Python APIs.\n", + "\n", + "![](https://i.imgur.com/B3rf4QN.jpg)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "53", + "metadata": {}, + "source": [ + "### Using the datasets module" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54", + "metadata": {}, + "outputs": [], + "source": [ + "from geemap.datasets import DATA" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "dataset = ee.Image(DATA.USGS_GAP_AK_2001)\n", + "m.add_layer(dataset, {}, \"GAP Alaska\")\n", + "m.centerObject(dataset, zoom=4)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56", + "metadata": {}, + "outputs": [], + "source": [ + "from geemap.datasets import get_metadata\n", + "\n", + "get_metadata(DATA.USGS_GAP_AK_2001)" + ] + }, + { + "cell_type": "markdown", + "id": "57", + "metadata": {}, + "source": [ + "## Earth Engine data types\n", + "\n", + "Earth Engine objects are server-side objects rather than client-side objects, which means that they are not stored locally on your computer. Similar to video streaming services (e.g., YouTube, Netflix, and Hulu), which store videos/movies on their servers, Earth Engine data are stored on the Earth Engine servers. We can stream geospatial data from Earth Engine on-the-fly without having to download the data just like we can watch videos from streaming services using a web browser without having to download the entire video to your computer.\n", + "\n", + "- **Image**: the fundamental raster data type in Earth Engine.\n", + "- **ImageCollection**: a stack or time-series of images.\n", + "- **Geometry**: the fundamental vector data type in Earth Engine.\n", + "- **Feature**: a Geometry with attributes.\n", + "- **FeatureCollection**: a set of features.\n", + "\n", + "![](https://i.imgur.com/XzsxUgD.jpg)\n", + "\n", + "![](https://i.imgur.com/165CykW.jpg)" + ] + }, + { + "cell_type": "markdown", + "id": "58", + "metadata": {}, + "source": [ + "## Earth Engine raster data\n", + "\n", + "### Image\n", + "\n", + "Raster data in Earth Engine are represented as **Image** objects. Images are composed of one or more bands and each band has its own name, data type, scale, mask and projection. Each image has metadata stored as a set of properties.\n", + "\n", + "#### Loading Earth Engine images\n", + "\n", + "Images can be loaded by passing an Earth Engine asset ID into the `ee.Image` constructor. You can find image IDs in the Earth Engine Data Catalog. For example, to load the NASA SRTM Digital Elevation you can use:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59", + "metadata": {}, + "outputs": [], + "source": [ + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "image" + ] + }, + { + "cell_type": "markdown", + "id": "60", + "metadata": {}, + "source": [ + "#### Visualizing Earth Engine images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[21.79, 70.87], zoom=3)\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 6000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"], # 'terrain'\n", + "}\n", + "m.add_layer(image, vis_params, \"SRTM\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "62", + "metadata": {}, + "source": [ + "### ImageCollection\n", + "\n", + "An `ImageCollection` is a stack or sequence of images. An `ImageCollection` can be loaded by passing an Earth Engine asset ID into the `ImageCollection` constructor. You can find `ImageCollection` IDs in the [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets).\n", + "\n", + "#### Loading image collections\n", + "\n", + "For example, to load the image collection of the [Sentinel-2 surface reflectance](https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2_SR):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63", + "metadata": {}, + "outputs": [], + "source": [ + "collection = ee.ImageCollection(\"COPERNICUS/S2_SR\")" + ] + }, + { + "cell_type": "markdown", + "id": "64", + "metadata": {}, + "source": [ + "#### Filtering image collections\n", + "\n", + "Let's find out how many Sentinel-2 images covering Blue Chip Casino Hotel Spa." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65", + "metadata": {}, + "outputs": [], + "source": [ + "geometry = ee.Geometry.Point([-86.893044, 41.718642])\n", + "images = collection.filterBounds(geometry)\n", + "images.size()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66", + "metadata": {}, + "outputs": [], + "source": [ + "images.first()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67", + "metadata": {}, + "outputs": [], + "source": [ + "images = (\n", + " collection.filterBounds(geometry)\n", + " .filterDate(\"2023-07-01\", \"2023-09-01\")\n", + " .filter(ee.Filter.lt(\"CLOUDY_PIXEL_PERCENTAGE\", 5))\n", + ")\n", + "images.size()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "image = images.first()\n", + "\n", + "vis = {\n", + " \"min\": 0.0,\n", + " \"max\": 3000,\n", + " \"bands\": [\"B4\", \"B3\", \"B2\"],\n", + "}\n", + "\n", + "m.add_layer(image, vis, \"Sentinel-2\")\n", + "m.centerObject(image, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "69", + "metadata": {}, + "source": [ + "#### Visualizing image collections\n", + "\n", + "To visualize an Earth Engine **ImageCollection**, we need to convert an **ImageCollection** to an **Image** by compositing all the images in the collection to a single image representing, for example, the min, max, median, mean or standard deviation of the images. For example, to create a median value image from a collection, use the `collection.median()` method. Let's create a median image from the Sentinel-2 surface reflectance collection:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "image = images.median()\n", + "\n", + "vis = {\n", + " \"min\": 0.0,\n", + " \"max\": 3000,\n", + " \"bands\": [\"B8\", \"B4\", \"B3\"],\n", + "}\n", + "\n", + "m.add_layer(image, vis, \"Sentinel-2\")\n", + "m.centerObject(geometry, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "71", + "metadata": {}, + "source": [ + "## Earth Engine vector data\n", + "\n", + "A **FeatureCollection** is a collection of Features. A FeatureCollection is analogous to a GeoJSON FeatureCollection object, i.e., a collection of features with associated properties/attributes. Data contained in a shapefile can be represented as a FeatureCollection.\n", + "\n", + "### Loading feature collections\n", + "\n", + "The [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets) hosts a variety of vector datasets (e.g,, US Census data, country boundaries, and more) as feature collections. You can find feature collection IDs by searching the data catalog. For example, to load the [TIGER roads data](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2016_Roads) by the U.S. Census Bureau:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "fc = ee.FeatureCollection(\"TIGER/2016/Roads\")\n", + "m.set_center(-86.894547, 41.718934, 12)\n", + "m.add_layer(fc, {}, \"Census roads\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "73", + "metadata": {}, + "source": [ + "### Filtering feature collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.eq(\"NAME\", \"Indiana\"))\n", + "m.add_layer(fc, {}, \"Indiana\")\n", + "m.center_object(fc, 7)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75", + "metadata": {}, + "outputs": [], + "source": [ + "feat = fc.first()\n", + "feat.toDictionary()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_df(fc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.inList(\"NAME\", [\"California\", \"Oregon\", \"Washington\"]))\n", + "m.add_layer(fc, {}, \"West Coast\")\n", + "m.center_object(fc, 5)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78", + "metadata": {}, + "outputs": [], + "source": [ + "region = m.user_roi\n", + "if region is None:\n", + " region = ee.Geometry.BBox(-88.40, 29.88, -77.90, 35.39)\n", + "\n", + "fc = ee.FeatureCollection(\"TIGER/2018/States\").filterBounds(region)\n", + "m.add_layer(fc, {}, \"Southeastern U.S.\")\n", + "m.center_object(fc, 6)" + ] + }, + { + "cell_type": "markdown", + "id": "79", + "metadata": {}, + "source": [ + "### Visualizing feature collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "m.add_layer(states, {}, \"US States\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "style = {\"color\": \"0000ffff\", \"width\": 2, \"lineType\": \"solid\", \"fillColor\": \"FF000080\"}\n", + "m.add_layer(states.style(**style), {}, \"US States\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "vis_params = {\n", + " \"color\": \"000000\",\n", + " \"colorOpacity\": 1,\n", + " \"pointSize\": 3,\n", + " \"pointShape\": \"circle\",\n", + " \"width\": 2,\n", + " \"lineType\": \"solid\",\n", + " \"fillColorOpacity\": 0.66,\n", + "}\n", + "palette = [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"]\n", + "m.add_styled_vector(\n", + " states, column=\"NAME\", palette=palette, layer_name=\"Styled vector\", **vis_params\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "83", + "metadata": {}, + "source": [ + "## Exercise 1 - Creating cloud-free imagery\n", + "\n", + "Create a cloud-free imagery for the state of Indiana. You can use Landsat 8/9 or Sentinel-2 imagery. Relevant Earth Engine assets:\n", + "\n", + "- [ee.FeatureCollection(\"TIGER/2018/States\")](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2018_States)\n", + "- [ee.ImageCollection(\"COPERNICUS/S2_SR\")](https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2_SR)\n", + "- [ee.ImageCollection(\"LANDSAT/LC08/C02/T1_L2\")](https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC08_C02_T1_L2)\n", + "- [ee.ImageCollection(\"LANDSAT/LC09/C02/T1_L2\")](https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC09_C02_T1_L2)" + ] + }, + { + "cell_type": "markdown", + "id": "84", + "metadata": {}, + "source": [ + "## More tools for visualizing Earth Engine data" + ] + }, + { + "cell_type": "markdown", + "id": "85", + "metadata": {}, + "source": [ + "### Using the plotting tool" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\").select(\n", + " [\"B1\", \"B2\", \"B3\", \"B4\", \"B5\", \"B7\"]\n", + ")\n", + "\n", + "landsat_vis = {\"bands\": [\"B4\", \"B3\", \"B2\"], \"gamma\": 1.4}\n", + "m.add_layer(landsat7, landsat_vis, \"Landsat\")\n", + "\n", + "hyperion = ee.ImageCollection(\"EO1/HYPERION\").filter(\n", + " ee.Filter.date(\"2016-01-01\", \"2017-03-01\")\n", + ")\n", + "\n", + "hyperion_vis = {\n", + " \"min\": 1000.0,\n", + " \"max\": 14000.0,\n", + " \"gamma\": 2.5,\n", + "}\n", + "m.add_layer(hyperion, hyperion_vis, \"Hyperion\")\n", + "m.add_plot_gui()\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "87", + "metadata": {}, + "source": [ + "Set plotting options for Landsat." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88", + "metadata": {}, + "outputs": [], + "source": [ + "m.set_plot_options(add_marker_cluster=True, overlay=True)" + ] + }, + { + "cell_type": "markdown", + "id": "89", + "metadata": {}, + "source": [ + "Set plotting options for Hyperion." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90", + "metadata": {}, + "outputs": [], + "source": [ + "m.set_plot_options(add_marker_cluster=True, plot_type=\"bar\")" + ] + }, + { + "cell_type": "markdown", + "id": "91", + "metadata": {}, + "source": [ + "### Legends\n", + "\n", + "#### Built-in legends" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92", + "metadata": {}, + "outputs": [], + "source": [ + "from geemap.legends import builtin_legends" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93", + "metadata": {}, + "outputs": [], + "source": [ + "for legend in builtin_legends:\n", + " print(legend)" + ] + }, + { + "cell_type": "markdown", + "id": "94", + "metadata": {}, + "source": [ + "Add NLCD WMS layer and legend to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "m.add_basemap(\"NLCD 2021 CONUS Land Cover\")\n", + "m.add_legend(builtin_legend=\"NLCD\", max_width=\"100px\", height=\"455px\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "96", + "metadata": {}, + "source": [ + "Add NLCD Earth Engine layer and legend to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "\n", + "nlcd = ee.Image(\"USGS/NLCD_RELEASES/2021_REL/NLCD/2021\")\n", + "landcover = nlcd.select(\"landcover\")\n", + "\n", + "m.add_layer(landcover, {}, \"NLCD Land Cover 2021\")\n", + "m.add_legend(\n", + " title=\"NLCD Land Cover Classification\", builtin_legend=\"NLCD\", height=\"455px\"\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "98", + "metadata": {}, + "source": [ + "#### Custom legends" + ] + }, + { + "cell_type": "markdown", + "id": "99", + "metadata": {}, + "source": [ + "Add a custom legend by specifying the colors and labels." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "100", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(add_google_map=False)\n", + "\n", + "keys = [\"One\", \"Two\", \"Three\", \"Four\", \"etc\"]\n", + "\n", + "# colors can be defined using either hex code or RGB (0-255, 0-255, 0-255)\n", + "colors = [\"#8DD3C7\", \"#FFFFB3\", \"#BEBADA\", \"#FB8072\", \"#80B1D3\"]\n", + "# legend_colors = [(255, 0, 0), (127, 255, 0), (127, 18, 25), (36, 70, 180), (96, 68 123)]\n", + "\n", + "m.add_legend(keys=keys, colors=colors, position=\"bottomright\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "101", + "metadata": {}, + "source": [ + "Add a custom legend by specifying a dictionary of colors and labels." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "102", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "\n", + "legend_dict = {\n", + " \"11 Open Water\": \"466b9f\",\n", + " \"12 Perennial Ice/Snow\": \"d1def8\",\n", + " \"21 Developed, Open Space\": \"dec5c5\",\n", + " \"22 Developed, Low Intensity\": \"d99282\",\n", + " \"23 Developed, Medium Intensity\": \"eb0000\",\n", + " \"24 Developed High Intensity\": \"ab0000\",\n", + " \"31 Barren Land (Rock/Sand/Clay)\": \"b3ac9f\",\n", + " \"41 Deciduous Forest\": \"68ab5f\",\n", + " \"42 Evergreen Forest\": \"1c5f2c\",\n", + " \"43 Mixed Forest\": \"b5c58f\",\n", + " \"51 Dwarf Scrub\": \"af963c\",\n", + " \"52 Shrub/Scrub\": \"ccb879\",\n", + " \"71 Grassland/Herbaceous\": \"dfdfc2\",\n", + " \"72 Sedge/Herbaceous\": \"d1d182\",\n", + " \"73 Lichens\": \"a3cc51\",\n", + " \"74 Moss\": \"82ba9e\",\n", + " \"81 Pasture/Hay\": \"dcd939\",\n", + " \"82 Cultivated Crops\": \"ab6c28\",\n", + " \"90 Woody Wetlands\": \"b8d9eb\",\n", + " \"95 Emergent Herbaceous Wetlands\": \"6c9fb8\",\n", + "}\n", + "\n", + "nlcd = ee.Image(\"USGS/NLCD_RELEASES/2021_REL/NLCD/2021\")\n", + "landcover = nlcd.select(\"landcover\")\n", + "\n", + "m.add_layer(landcover, {}, \"NLCD Land Cover 2021\")\n", + "m.add_legend(title=\"NLCD Land Cover Classification\", legend_dict=legend_dict)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "103", + "metadata": {}, + "source": [ + "### Color bars\n", + "\n", + "Add a horizontal color bar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "104", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add_colorbar(vis_params, label=\"Elevation (m)\", layer_name=\"SRTM DEM\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "105", + "metadata": {}, + "source": [ + "Add a vertical color bar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "106", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_colorbar(\n", + " vis_params,\n", + " label=\"Elevation (m)\",\n", + " layer_name=\"SRTM DEM\",\n", + " orientation=\"vertical\",\n", + " max_width=\"100px\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "107", + "metadata": {}, + "source": [ + "Make the color bar background transparent." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "108", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_colorbar(\n", + " vis_params,\n", + " label=\"Elevation (m)\",\n", + " layer_name=\"SRTM DEM\",\n", + " orientation=\"vertical\",\n", + " max_width=\"100px\",\n", + " transparent_bg=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "109", + "metadata": {}, + "source": [ + "### Split-panel maps\n", + "\n", + "Create a split map with basemaps. Note that ipyleaflet has a bug with the SplitControl. You can't pan the map, which should be resolved in the next ipyleaflet release." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "110", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.split_map(left_layer=\"Esri.WorldTopoMap\", right_layer=\"OpenTopoMap\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "111", + "metadata": {}, + "source": [ + "Create a split map with Earth Engine layers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "112", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(40, -100), zoom=4, height=600)\n", + "\n", + "nlcd_2001 = ee.Image(\"USGS/NLCD_RELEASES/2019_REL/NLCD/2001\").select(\"landcover\")\n", + "nlcd_2021 = ee.Image(\"USGS/NLCD_RELEASES/2021_REL/NLCD/2021\").select(\"landcover\")\n", + "\n", + "left_layer = geemap.ee_tile_layer(nlcd_2001, {}, \"NLCD 2001\")\n", + "right_layer = geemap.ee_tile_layer(nlcd_2021, {}, \"NLCD 2021\")\n", + "\n", + "m.split_map(left_layer, right_layer)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "113", + "metadata": {}, + "source": [ + "### Linked maps\n", + "\n", + "Create a 2x2 linked map for visualizing Sentinel-2 imagery with different band combinations. Note that this feature does not work properly with Colab. Panning one map would not pan other maps." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "114", + "metadata": {}, + "outputs": [], + "source": [ + "image = (\n", + " ee.ImageCollection(\"COPERNICUS/S2\")\n", + " .filterDate(\"2023-07-01\", \"2023-09-01\")\n", + " .filter(ee.Filter.lt(\"CLOUDY_PIXEL_PERCENTAGE\", 5))\n", + " .map(lambda img: img.divide(10000))\n", + " .median()\n", + ")\n", + "\n", + "vis_params = [\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 0, \"max\": 0.3, \"gamma\": 1.3},\n", + " {\"bands\": [\"B8\", \"B11\", \"B4\"], \"min\": 0, \"max\": 0.3, \"gamma\": 1.3},\n", + " {\"bands\": [\"B8\", \"B4\", \"B3\"], \"min\": 0, \"max\": 0.3, \"gamma\": 1.3},\n", + " {\"bands\": [\"B12\", \"B12\", \"B4\"], \"min\": 0, \"max\": 0.3, \"gamma\": 1.3},\n", + "]\n", + "\n", + "labels = [\n", + " \"Natural Color (B4/B3/B2)\",\n", + " \"Land/Water (B8/B11/B4)\",\n", + " \"Color Infrared (B8/B4/B3)\",\n", + " \"Vegetation (B12/B11/B4)\",\n", + "]\n", + "\n", + "geemap.linked_maps(\n", + " rows=2,\n", + " cols=2,\n", + " height=\"300px\",\n", + " center=[41.718934, -86.894547],\n", + " zoom=12,\n", + " ee_objects=[image],\n", + " vis_params=vis_params,\n", + " labels=labels,\n", + " label_position=\"topright\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "115", + "metadata": {}, + "source": [ + "### Timeseries inspector\n", + "\n", + "Check the available years of NLCD." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "116", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "collection = ee.ImageCollection(\"USGS/NLCD_RELEASES/2019_REL/NLCD\").select(\"landcover\")\n", + "vis_params = {\"bands\": [\"landcover\"]}\n", + "years = collection.aggregate_array(\"system:index\").getInfo()\n", + "years" + ] + }, + { + "cell_type": "markdown", + "id": "117", + "metadata": {}, + "source": [ + "Create a timeseries inspector for NLCD. Note that ipyleaflet has a bug with the SplitControl. You can't pan the map, which should be resolved in the next ipyleaflet release." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "118", + "metadata": {}, + "outputs": [], + "source": [ + "m.ts_inspector(\n", + " left_ts=collection,\n", + " right_ts=collection,\n", + " left_names=years,\n", + " right_names=years,\n", + " left_vis=vis_params,\n", + " right_vis=vis_params,\n", + " width=\"80px\",\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "119", + "metadata": {}, + "source": [ + "### Time slider\n", + "\n", + "Note that this feature may not work properly with Colab. Restart Colab runtime if the time slider does not work.\n", + "\n", + "Create a map for visualizing MODIS vegetation data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "120", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "collection = (\n", + " ee.ImageCollection(\"MODIS/MCD43A4_006_NDVI\")\n", + " .filter(ee.Filter.date(\"2018-06-01\", \"2018-07-01\"))\n", + " .select(\"NDVI\")\n", + ")\n", + "vis_params = {\n", + " \"min\": 0.0,\n", + " \"max\": 1.0,\n", + " \"palette\": \"ndvi\",\n", + "}\n", + "\n", + "m.add_time_slider(collection, vis_params, time_interval=2)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "121", + "metadata": {}, + "source": [ + "Create a map for visualizing weather data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "122", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "collection = (\n", + " ee.ImageCollection(\"NOAA/GFS0P25\")\n", + " .filterDate(\"2018-12-22\", \"2018-12-23\")\n", + " .limit(24)\n", + " .select(\"temperature_2m_above_ground\")\n", + ")\n", + "\n", + "vis_params = {\n", + " \"min\": -40.0,\n", + " \"max\": 35.0,\n", + " \"palette\": [\"blue\", \"purple\", \"cyan\", \"green\", \"yellow\", \"red\"],\n", + "}\n", + "\n", + "labels = [str(n).zfill(2) + \":00\" for n in range(0, 24)]\n", + "m.add_time_slider(collection, vis_params, labels=labels, time_interval=1, opacity=0.8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "123", + "metadata": {}, + "source": [ + "Visualizing Sentinel-2 imagery" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "124", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "collection = (\n", + " ee.ImageCollection(\"COPERNICUS/S2_SR\")\n", + " .filterBounds(ee.Geometry.Point([-86.894547, 41.718934]))\n", + " .filterMetadata(\"CLOUDY_PIXEL_PERCENTAGE\", \"less_than\", 10)\n", + " .filter(ee.Filter.calendarRange(6, 8, \"month\"))\n", + ")\n", + "\n", + "vis_params = {\"min\": 0, \"max\": 4000, \"bands\": [\"B8\", \"B4\", \"B3\"]}\n", + "\n", + "m.add_time_slider(collection, vis_params)\n", + "m.set_center(-86.894547, 41.718934, 12)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "125", + "metadata": {}, + "source": [ + "## Exercise 2 - Creating land cover maps with a legend\n", + "\n", + "Create a split map for visualizing the ESA WorldCover for the state of Alaska, with the `Esri.WorldImagery` as the left layer, and the ESA WorldCover as the right layer. Add the ESA land cover legend to the map. Relevant Earth Engine assets:\n", + "\n", + "- [ee.FeatureCollection(\"TIGER/2018/States\")](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2018_States)\n", + "- [ee.ImageCollection(\"ESA/WorldCover/v200\")](https://developers.google.com/earth-engine/datasets/catalog/ESA_WorldCover_v200)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "126", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "127", + "metadata": {}, + "source": [ + "## Processing of vector data\n", + "\n", + "### From GeoJSON" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "128", + "metadata": {}, + "outputs": [], + "source": [ + "in_geojson = \"https://github.com/gee-community/geemap/blob/master/examples/data/countries.geojson\"\n", + "m = geemap.Map()\n", + "fc = geemap.geojson_to_ee(in_geojson)\n", + "m.add_layer(fc.style(**{\"color\": \"ff0000\", \"fillColor\": \"00000000\"}), {}, \"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "129", + "metadata": {}, + "source": [ + "### From Shapefile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "130", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/gee-community/geemap/blob/master/examples/data/countries.zip\"\n", + "geemap.download_file(url, overwrite=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "131", + "metadata": {}, + "outputs": [], + "source": [ + "in_shp = \"countries.shp\"\n", + "fc = geemap.shp_to_ee(in_shp)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "132", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_layer(fc, {}, \"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "133", + "metadata": {}, + "source": [ + "### From GeoDataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "134", + "metadata": {}, + "outputs": [], + "source": [ + "import geopandas as gpd\n", + "\n", + "gdf = gpd.read_file(in_shp)\n", + "fc = geemap.gdf_to_ee(gdf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "135", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_layer(fc, {}, \"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "136", + "metadata": {}, + "source": [ + "### To GeoJSON" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "137", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.eq(\"NAME\", \"Indiana\"))\n", + "m.add_layer(fc, {}, \"Indiana\")\n", + "m.center_object(fc, 7)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "138", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_geojson(fc, filename=\"Indiana.geojson\")" + ] + }, + { + "cell_type": "markdown", + "id": "139", + "metadata": {}, + "source": [ + "### To Shapefile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "140", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_shp(fc, filename=\"Indiana.shp\")" + ] + }, + { + "cell_type": "markdown", + "id": "141", + "metadata": {}, + "source": [ + "### To GeoDataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "142", + "metadata": {}, + "outputs": [], + "source": [ + "gdf = geemap.ee_to_gdf(fc)\n", + "gdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "143", + "metadata": {}, + "outputs": [], + "source": [ + "gdf.explore()" + ] + }, + { + "cell_type": "markdown", + "id": "144", + "metadata": {}, + "source": [ + "### To DataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "145", + "metadata": {}, + "outputs": [], + "source": [ + "df = geemap.ee_to_df(fc)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "id": "146", + "metadata": {}, + "source": [ + "### To CSV" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "147", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_csv(fc, filename=\"Indiana.csv\")" + ] + }, + { + "cell_type": "markdown", + "id": "148", + "metadata": {}, + "source": [ + "## Processing of raster data\n", + "\n", + "### Extract pixel values\n", + "\n", + "#### Extracting values to points" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "149", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "\n", + "m.add_layer(\n", + " landsat7,\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 20, \"max\": 200, \"gamma\": 2},\n", + " \"Landsat 7\",\n", + ")\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\", True, 1)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "150", + "metadata": {}, + "outputs": [], + "source": [ + "in_shp = \"us_cities.shp\"\n", + "url = \"https://github.com/giswqs/data/raw/main/us/us_cities.zip\"\n", + "geemap.download_file(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "151", + "metadata": {}, + "outputs": [], + "source": [ + "in_fc = geemap.shp_to_ee(in_shp)\n", + "m.add_layer(in_fc, {}, \"Cities\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "152", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.extract_values_to_points(in_fc, dem, out_fc=\"dem.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "153", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.shp_to_gdf(\"dem.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "154", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.extract_values_to_points(in_fc, landsat7, \"landsat.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "155", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_df(\"landsat.csv\")" + ] + }, + { + "cell_type": "markdown", + "id": "156", + "metadata": {}, + "source": [ + "#### Extracting pixel values along a transect" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "157", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"TERRAIN\")\n", + "\n", + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(image, vis_params, \"SRTM DEM\", True, 0.5)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "158", + "metadata": {}, + "outputs": [], + "source": [ + "line = m.user_roi\n", + "if line is None:\n", + " line = ee.Geometry.LineString(\n", + " [[-120.2232, 36.3148], [-118.9269, 36.7121], [-117.2022, 36.7562]]\n", + " )\n", + " m.add_layer(line, {}, \"ROI\")\n", + "m.centerObject(line)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "159", + "metadata": {}, + "outputs": [], + "source": [ + "reducer = \"mean\"\n", + "transect = geemap.extract_transect(\n", + " image, line, n_segments=100, reducer=reducer, to_pandas=True\n", + ")\n", + "transect" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "160", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.line_chart(\n", + " data=transect,\n", + " x=\"distance\",\n", + " y=\"mean\",\n", + " markers=True,\n", + " x_label=\"Distance (m)\",\n", + " y_label=\"Elevation (m)\",\n", + " height=400,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "161", + "metadata": {}, + "outputs": [], + "source": [ + "transect.to_csv(\"transect.csv\")" + ] + }, + { + "cell_type": "markdown", + "id": "162", + "metadata": {}, + "source": [ + "### Zonal statistics\n", + "\n", + "#### Zonal statistics with an image and a feature collection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "163", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "\n", + "# Add NASA SRTM\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "dem_vis = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "m.add_layer(dem, dem_vis, \"SRTM DEM\")\n", + "\n", + "# Add 5-year Landsat TOA composite\n", + "landsat = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "landsat_vis = {\"bands\": [\"B4\", \"B3\", \"B2\"], \"gamma\": 1.4}\n", + "m.add_layer(landsat, landsat_vis, \"Landsat\", False)\n", + "\n", + "# Add US Census States\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "style = {\"fillColor\": \"00000000\"}\n", + "m.add_layer(states.style(**style), {}, \"US States\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "164", + "metadata": {}, + "outputs": [], + "source": [ + "out_dem_stats = \"dem_stats.csv\"\n", + "geemap.zonal_stats(\n", + " dem, states, out_dem_stats, statistics_type=\"MEAN\", scale=1000, return_fc=False\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "165", + "metadata": {}, + "outputs": [], + "source": [ + "out_landsat_stats = \"landsat_stats.csv\"\n", + "geemap.zonal_stats(\n", + " landsat,\n", + " states,\n", + " out_landsat_stats,\n", + " statistics_type=\"MEAN\",\n", + " scale=1000,\n", + " return_fc=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "166", + "metadata": {}, + "source": [ + "#### Zonal statistics by group" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "167", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "\n", + "# Add NLCD data\n", + "dataset = ee.Image(\"USGS/NLCD_RELEASES/2019_REL/NLCD/2019\")\n", + "landcover = dataset.select(\"landcover\")\n", + "m.add_layer(landcover, {}, \"NLCD 2019\")\n", + "\n", + "# Add US census states\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "style = {\"fillColor\": \"00000000\"}\n", + "m.add_layer(states.style(**style), {}, \"US States\")\n", + "\n", + "# Add NLCD legend\n", + "m.add_legend(title=\"NLCD Land Cover\", builtin_legend=\"NLCD\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "168", + "metadata": {}, + "outputs": [], + "source": [ + "nlcd_stats = \"nlcd_stats.csv\"\n", + "\n", + "geemap.zonal_stats_by_group(\n", + " landcover,\n", + " states,\n", + " nlcd_stats,\n", + " statistics_type=\"SUM\",\n", + " denominator=1e6,\n", + " decimal_places=2,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "169", + "metadata": {}, + "outputs": [], + "source": [ + "nlcd_stats = \"nlcd_stats_pct.csv\"\n", + "\n", + "geemap.zonal_stats_by_group(\n", + " landcover,\n", + " states,\n", + " nlcd_stats,\n", + " statistics_type=\"PERCENTAGE\",\n", + " denominator=1e6,\n", + " decimal_places=2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "170", + "metadata": {}, + "source": [ + "#### Zonal statistics with two images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "171", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "dem = ee.Image(\"USGS/3DEP/10m\")\n", + "vis = {\"min\": 0, \"max\": 4000, \"palette\": \"terrain\"}\n", + "m.add_layer(dem, vis, \"DEM\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "172", + "metadata": {}, + "outputs": [], + "source": [ + "landcover = ee.Image(\"USGS/NLCD_RELEASES/2019_REL/NLCD/2019\").select(\"landcover\")\n", + "m.add_layer(landcover, {}, \"NLCD 2019\")\n", + "m.add_legend(title=\"NLCD Land Cover Classification\", builtin_legend=\"NLCD\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "173", + "metadata": {}, + "outputs": [], + "source": [ + "stats = geemap.image_stats_by_zone(dem, landcover, reducer=\"MEAN\")\n", + "stats" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "174", + "metadata": {}, + "outputs": [], + "source": [ + "stats.to_csv(\"mean.csv\", index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "175", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.image_stats_by_zone(dem, landcover, out_csv=\"std.csv\", reducer=\"STD\")" + ] + }, + { + "cell_type": "markdown", + "id": "176", + "metadata": {}, + "source": [ + "### Map algebra" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "177", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "# Load a 5-year Landsat 7 composite 1999-2003.\n", + "landsat_1999 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\")\n", + "\n", + "# Compute NDVI.\n", + "ndvi_1999 = (\n", + " landsat_1999.select(\"B4\")\n", + " .subtract(landsat_1999.select(\"B3\"))\n", + " .divide(landsat_1999.select(\"B4\").add(landsat_1999.select(\"B3\")))\n", + ")\n", + "\n", + "vis = {\"min\": 0, \"max\": 1, \"palette\": \"ndvi\"}\n", + "m.add_layer(ndvi_1999, vis, \"NDVI\")\n", + "m.add_colorbar(vis, label=\"NDVI\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "178", + "metadata": {}, + "outputs": [], + "source": [ + "# Load a Landsat 8 image.\n", + "image = ee.Image(\"LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318\")\n", + "\n", + "# Compute the EVI using an expression.\n", + "evi = image.expression(\n", + " \"2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))\",\n", + " {\n", + " \"NIR\": image.select(\"B5\"),\n", + " \"RED\": image.select(\"B4\"),\n", + " \"BLUE\": image.select(\"B2\"),\n", + " },\n", + ")\n", + "\n", + "# Define a map centered on San Francisco Bay.\n", + "m = geemap.Map(center=[37.4675, -122.1363], zoom=9)\n", + "\n", + "vis = {\"min\": 0, \"max\": 1, \"palette\": \"ndvi\"}\n", + "m.add_layer(evi, vis, \"EVI\")\n", + "m.add_colorbar(vis, label=\"EVI\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "179", + "metadata": {}, + "source": [ + "## Exercise 3 - Zonal statistics\n", + "\n", + "Find out which state has the highest mean temperature in the United States on June 28, 2023. Relevant Earth Engine assets:\n", + "\n", + "- [ee.FeatureCollection(\"TIGER/2018/States\")](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2018_States)\n", + "- [ee.ImageCollection(\"NOAA/GFS0P25\")](https://developers.google.com/earth-engine/datasets/catalog/NOAA_GFS0P25)\n", + "\n", + "![](https://i.imgur.com/GZCHHz3.png)" + ] + }, + { + "cell_type": "markdown", + "id": "180", + "metadata": {}, + "source": [ + "## Working with local geospatial data\n", + "\n", + "### Raster data\n", + "\n", + "#### Single-band raster" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "181", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/giswqs/data/raw/main/raster/srtm90.tif\"\n", + "filename = \"dem.tif\"\n", + "geemap.download_file(url, filename)" + ] + }, + { + "cell_type": "markdown", + "id": "182", + "metadata": {}, + "source": [ + "#### Multi-band raster" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "183", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_raster(filename, cmap=\"terrain\", layer_name=\"DEM\")\n", + "vis_params = {\"min\": 0, \"max\": 4000, \"palette\": \"terrain\"}\n", + "m.add_colorbar(vis_params, label=\"Elevation (m)\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "184", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/giswqs/data/raw/main/raster/cog.tif\"\n", + "filename = \"cog.tif\"\n", + "geemap.download_file(url, filename)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "185", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_raster(filename, indexes=[4, 1, 2], layer_name=\"False color\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "186", + "metadata": {}, + "source": [ + "### Vector data\n", + "\n", + "#### GeoJSON" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "187", + "metadata": {}, + "outputs": [], + "source": [ + "in_geojson = (\n", + " \"https://github.com/opengeos/datasets/releases/download/vector/cables.geojson\"\n", + ")\n", + "m = geemap.Map()\n", + "m.add_geojson(in_geojson, layer_name=\"Cable lines\", info_mode=\"on_hover\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "188", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_basemap(\"CartoDB.DarkMatter\")\n", + "callback = lambda feat: {\"color\": feat[\"properties\"][\"color\"], \"weight\": 2}\n", + "m.add_geojson(in_geojson, layer_name=\"Cable lines\", style_callback=callback)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "189", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/opengeos/datasets/releases/download/world/countries.geojson\"\n", + "m = geemap.Map()\n", + "m.add_geojson(\n", + " url, layer_name=\"Countries\", fill_colors=[\"red\", \"yellow\", \"green\", \"orange\"]\n", + ")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "190", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "m = geemap.Map()\n", + "\n", + "\n", + "def random_color(feature):\n", + " return {\n", + " \"color\": \"black\",\n", + " \"weight\": 3,\n", + " \"fillColor\": random.choice([\"red\", \"yellow\", \"green\", \"orange\"]),\n", + " }\n", + "\n", + "\n", + "m.add_geojson(url, layer_name=\"Countries\", style_callback=random_color)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "191", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "style = {\n", + " \"stroke\": True,\n", + " \"color\": \"#0000ff\",\n", + " \"weight\": 2,\n", + " \"opacity\": 1,\n", + " \"fill\": True,\n", + " \"fillColor\": \"#0000ff\",\n", + " \"fillOpacity\": 0.1,\n", + "}\n", + "\n", + "hover_style = {\"fillOpacity\": 0.7}\n", + "\n", + "m.add_geojson(url, layer_name=\"Countries\", style=style, hover_style=hover_style)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "192", + "metadata": {}, + "source": [ + "#### Shapefile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "193", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/opengeos/datasets/releases/download/world/countries.zip\"\n", + "geemap.download_file(url, overwrite=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "194", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "in_shp = \"countries.shp\"\n", + "m.add_shp(in_shp, layer_name=\"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "195", + "metadata": {}, + "source": [ + "#### GeoDataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "196", + "metadata": {}, + "outputs": [], + "source": [ + "import geopandas as gpd\n", + "\n", + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "gdf = gpd.read_file(\"countries.shp\")\n", + "m.add_gdf(gdf, layer_name=\"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "197", + "metadata": {}, + "source": [ + "#### GeoPackage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "198", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "data = \"https://github.com/opengeos/datasets/releases/download/world/countries.gpkg\"\n", + "m.add_vector(data, layer_name=\"Countries\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "199", + "metadata": {}, + "source": [ + "#### CSV to vector" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "200", + "metadata": {}, + "outputs": [], + "source": [ + "data = \"https://github.com/gee-community/geemap/blob/master/examples/data/us_cities.csv\"\n", + "geemap.csv_to_df(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "201", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_geojson(\n", + " data, \"cities.geojson\", latitude=\"latitude\", longitude=\"longitude\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "202", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_shp(data, \"cities.shp\", latitude=\"latitude\", longitude=\"longitude\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "203", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_vector(data, \"cities.gpkg\", latitude=\"latitude\", longitude=\"longitude\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "204", + "metadata": {}, + "outputs": [], + "source": [ + "gdf = geemap.csv_to_gdf(data, latitude=\"latitude\", longitude=\"longitude\")\n", + "gdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "205", + "metadata": {}, + "outputs": [], + "source": [ + "cities = (\n", + " \"https://github.com/gee-community/geemap/blob/master/examples/data/us_cities.csv\"\n", + ")\n", + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_points_from_xy(cities, x=\"longitude\", y=\"latitude\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "206", + "metadata": {}, + "outputs": [], + "source": [ + "regions = \"https://github.com/gee-community/geemap/blob/master/examples/data/us_regions.geojson\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "207", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_geojson(regions, layer_name=\"US Regions\")\n", + "m.add_points_from_xy(\n", + " cities,\n", + " x=\"longitude\",\n", + " y=\"latitude\",\n", + " layer_name=\"US Cities\",\n", + " color_column=\"region\",\n", + " icon_names=[\"gear\", \"map\", \"leaf\", \"globe\"],\n", + " spin=True,\n", + " add_legend=True,\n", + ")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "208", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4)\n", + "m.add_circle_markers_from_xy(\n", + " data,\n", + " x=\"longitude\",\n", + " y=\"latitude\",\n", + " radius=8,\n", + " color=\"blue\",\n", + " fill_color=\"black\",\n", + " fill_opacity=0.5,\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "209", + "metadata": {}, + "source": [ + "## Accessing Cloud Optimized GeoTIFFs\n", + "\n", + "### COG" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "210", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "url = \"https://opendata.digitalglobe.com/events/california-fire-2020/pre-event/2018-02-16/pine-gulch-fire20/1030010076004E00.tif\"\n", + "m.add_cog_layer(url, name=\"Fire (pre-event)\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "211", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.cog_center(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "212", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.cog_bands(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "213", + "metadata": {}, + "outputs": [], + "source": [ + "url2 = \"https://opendata.digitalglobe.com/events/california-fire-2020/post-event/2020-08-14/pine-gulch-fire20/10300100AAC8DD00.tif\"\n", + "m.add_cog_layer(url2, name=\"Fire (post-event)\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "214", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[39.4568, -108.5107], zoom=12)\n", + "m.split_map(left_layer=url2, right_layer=url)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "215", + "metadata": {}, + "source": [ + "### SpatioTemporal Asset Catalog (STAC)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "216", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://tinyurl.com/22vptbws\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "217", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.stac_bounds(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "218", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.stac_center(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "219", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.stac_bands(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "220", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_stac_layer(url, bands=[\"pan\"], name=\"Panchromatic\")\n", + "m.add_stac_layer(url, bands=[\"B3\", \"B2\", \"B1\"], name=\"False color\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "221", + "metadata": {}, + "source": [ + "## Exporting Earth Engine data\n", + "\n", + "### Exporting images\n", + "\n", + "Add a Landsat image to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "222", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "image = ee.Image(\"LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318\").select(\n", + " [\"B5\", \"B4\", \"B3\"]\n", + ")\n", + "\n", + "vis_params = {\"min\": 0, \"max\": 0.5, \"gamma\": [0.95, 1.1, 1]}\n", + "\n", + "m.center_object(image)\n", + "m.add_layer(image, vis_params, \"Landsat\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "223", + "metadata": {}, + "source": [ + "Add a rectangle to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "224", + "metadata": {}, + "outputs": [], + "source": [ + "region = ee.Geometry.BBox(-122.5955, 37.5339, -122.0982, 37.8252)\n", + "fc = ee.FeatureCollection(region)\n", + "style = {\"color\": \"ffff00ff\", \"fillColor\": \"00000000\"}\n", + "m.add_layer(fc.style(**style), {}, \"ROI\")" + ] + }, + { + "cell_type": "markdown", + "id": "225", + "metadata": {}, + "source": [ + "To local drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "226", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image(image, filename=\"landsat.tif\", scale=30, region=region)" + ] + }, + { + "cell_type": "markdown", + "id": "227", + "metadata": {}, + "source": [ + "Check image projection." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "228", + "metadata": {}, + "outputs": [], + "source": [ + "projection = image.select(0).projection().getInfo()\n", + "projection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "229", + "metadata": {}, + "outputs": [], + "source": [ + "crs = projection[\"crs\"]\n", + "crs_transform = projection[\"transform\"]" + ] + }, + { + "cell_type": "markdown", + "id": "230", + "metadata": {}, + "source": [ + "Specify region, crs, and crs_transform." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "231", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image(\n", + " image,\n", + " filename=\"landsat_crs.tif\",\n", + " crs=crs,\n", + " crs_transform=crs_transform,\n", + " region=region,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "232", + "metadata": {}, + "source": [ + "To Google Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "233", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image_to_drive(\n", + " image, description=\"landsat\", folder=\"export\", region=region, scale=30\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "234", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.download_ee_image(image, \"landsat.tif\", scale=90)" + ] + }, + { + "cell_type": "markdown", + "id": "235", + "metadata": {}, + "source": [ + "### Exporting image collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "236", + "metadata": {}, + "outputs": [], + "source": [ + "point = ee.Geometry.Point(-99.2222, 46.7816)\n", + "collection = (\n", + " ee.ImageCollection(\"USDA/NAIP/DOQQ\")\n", + " .filterBounds(point)\n", + " .filterDate(\"2008-01-01\", \"2018-01-01\")\n", + " .filter(ee.Filter.listContains(\"system:band_names\", \"N\"))\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "237", + "metadata": {}, + "outputs": [], + "source": [ + "collection.aggregate_array(\"system:index\")" + ] + }, + { + "cell_type": "markdown", + "id": "238", + "metadata": {}, + "source": [ + "To local drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "239", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image_collection(collection, out_dir=\".\", scale=10)" + ] + }, + { + "cell_type": "markdown", + "id": "240", + "metadata": {}, + "source": [ + "To Google Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "241", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image_collection_to_drive(collection, folder=\"export\", scale=10)" + ] + }, + { + "cell_type": "markdown", + "id": "242", + "metadata": {}, + "source": [ + "### Exporting feature collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "243", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.eq(\"NAME\", \"Alaska\"))\n", + "m.add_layer(fc, {}, \"Alaska\")\n", + "m.center_object(fc, 4)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "244", + "metadata": {}, + "source": [ + "To local drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "245", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_shp(fc, filename=\"Alaska.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "246", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_vector(fc, filename=\"Alaska.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "247", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_geojson(fc, filename=\"Alaska.geojson\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "248", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_csv(fc, filename=\"Alaska.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "249", + "metadata": {}, + "outputs": [], + "source": [ + "gdf = geemap.ee_to_gdf(fc)\n", + "gdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "250", + "metadata": {}, + "outputs": [], + "source": [ + "df = geemap.ee_to_df(fc)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "id": "251", + "metadata": {}, + "source": [ + "To Google Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "252", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_vector_to_drive(\n", + " fc, description=\"Alaska\", fileFormat=\"SHP\", folder=\"export\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "253", + "metadata": {}, + "source": [ + "## Creating timelapse animations\n", + "\n", + "### Landsat timelapse" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "254", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[41.718934, -86.894547], zoom=11)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "255", + "metadata": {}, + "source": [ + "Pan and zoom the map to an area of interest. Use the drawing tools to draw a rectangle on the map. If no rectangle is drawn, the default rectangle shown below will be used." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "256", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-87.1492, 41.5812, -86.7145, 41.7531)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "257", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.landsat_timelapse(\n", + " roi,\n", + " out_gif=\"Fairbanks.gif\",\n", + " start_year=2000,\n", + " end_year=2023,\n", + " start_date=\"06-01\",\n", + " end_date=\"09-01\",\n", + " bands=[\"SWIR1\", \"NIR\", \"Red\"],\n", + " frames_per_second=5,\n", + " title=\"Landsat Timelapse\",\n", + " progress_bar_color=\"blue\",\n", + " mp4=True,\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "258", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[41.718934, -86.894547], zoom=11)\n", + "m.add_gui(\"timelapse\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "259", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "roi = ee.Geometry.BBox(-115.5541, 35.8044, -113.9035, 36.5581)\n", + "m.add_layer(roi)\n", + "m.center_object(roi)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "260", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.landsat_timelapse(\n", + " roi,\n", + " out_gif=\"las_vegas.gif\",\n", + " start_year=1984,\n", + " end_year=2023,\n", + " bands=[\"NIR\", \"Red\", \"Green\"],\n", + " frames_per_second=5,\n", + " title=\"Las Vegas, NV\",\n", + " font_color=\"blue\",\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "261", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "roi = ee.Geometry.BBox(113.8252, 22.1988, 114.0851, 22.3497)\n", + "m.add_layer(roi)\n", + "m.center_object(roi)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "262", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.landsat_timelapse(\n", + " roi,\n", + " out_gif=\"hong_kong.gif\",\n", + " start_year=1990,\n", + " end_year=2022,\n", + " start_date=\"01-01\",\n", + " end_date=\"12-31\",\n", + " bands=[\"SWIR1\", \"NIR\", \"Red\"],\n", + " frames_per_second=3,\n", + " title=\"Hong Kong\",\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "263", + "metadata": {}, + "source": [ + "### Sentinel-2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "264", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[41.718934, -86.894547], zoom=12)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "265", + "metadata": {}, + "source": [ + "Pan and zoom the map to an area of interest. Use the drawing tools to draw a rectangle on the map. If no rectangle is drawn, the default rectangle shown below will be used." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "266", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-87.0492, 41.6545, -86.7903, 41.7604)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "267", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.sentinel2_timelapse(\n", + " roi,\n", + " out_gif=\"sentinel2.gif\",\n", + " start_year=2017,\n", + " end_year=2023,\n", + " start_date=\"06-01\",\n", + " end_date=\"09-01\",\n", + " frequency=\"year\",\n", + " bands=[\"SWIR1\", \"NIR\", \"Red\"],\n", + " frames_per_second=3,\n", + " title=\"Sentinel-2 Timelapse\",\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "268", + "metadata": {}, + "source": [ + "### MODIS\n", + "\n", + "MODIS vegetation indices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "269", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "270", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-18.6983, -36.1630, 52.2293, 38.1446)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "271", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.modis_ndvi_timelapse(\n", + " roi,\n", + " out_gif=\"ndvi.gif\",\n", + " data=\"Terra\",\n", + " band=\"NDVI\",\n", + " start_date=\"2000-01-01\",\n", + " end_date=\"2022-12-31\",\n", + " frames_per_second=3,\n", + " title=\"MODIS NDVI Timelapse\",\n", + " overlay_data=\"countries\",\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "272", + "metadata": {}, + "source": [ + "MODIS temperature" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "273", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "274", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-171.21, -57.13, 177.53, 79.99)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "275", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.modis_ocean_color_timelapse(\n", + " satellite=\"Aqua\",\n", + " start_date=\"2018-01-01\",\n", + " end_date=\"2020-12-31\",\n", + " roi=roi,\n", + " frequency=\"month\",\n", + " out_gif=\"temperature.gif\",\n", + " overlay_data=\"continents\",\n", + " overlay_color=\"yellow\",\n", + " overlay_opacity=0.5,\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "276", + "metadata": {}, + "source": [ + "### GOES" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "277", + "metadata": {}, + "outputs": [], + "source": [ + "roi = ee.Geometry.BBox(167.1898, -28.5757, 202.6258, -12.4411)\n", + "start_date = \"2022-01-15T03:00:00\"\n", + "end_date = \"2022-01-15T07:00:00\"\n", + "data = \"GOES-17\"\n", + "scan = \"full_disk\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "278", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.goes_timelapse(\n", + " roi, \"goes.gif\", start_date, end_date, data, scan, framesPerSecond=5\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "279", + "metadata": {}, + "outputs": [], + "source": [ + "roi = ee.Geometry.BBox(-159.5954, 24.5178, -114.2438, 60.4088)\n", + "start_date = \"2021-10-24T14:00:00\"\n", + "end_date = \"2021-10-25T01:00:00\"\n", + "data = \"GOES-17\"\n", + "scan = \"full_disk\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "280", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.goes_timelapse(\n", + " roi, \"hurricane.gif\", start_date, end_date, data, scan, framesPerSecond=5\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "281", + "metadata": {}, + "outputs": [], + "source": [ + "roi = ee.Geometry.BBox(-121.0034, 36.8488, -117.9052, 39.0490)\n", + "start_date = \"2020-09-05T15:00:00\"\n", + "end_date = \"2020-09-06T02:00:00\"\n", + "data = \"GOES-17\"\n", + "scan = \"full_disk\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "282", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.goes_fire_timelapse(\n", + " roi, \"fire.gif\", start_date, end_date, data, scan, framesPerSecond=5\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "markdown", + "id": "283", + "metadata": {}, + "source": [ + "## Exercise 4 - Creating timelapse animations\n", + "\n", + "Use the geemap timelapse GUI to create a timelapse animation for any location of your choice. Share the timelapse on social media and use the hashtagd such as #EarthEngine and #geemap. See [this](https://i.imgur.com/YaCHvKC.gif) example.\n", + "\n", + "![](https://i.imgur.com/ohrXeFC.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "284", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "285", + "metadata": {}, + "source": [ + "## Time series analysis\n", + "\n", + "### Visualizing forest cover\n", + "\n", + "We will use the [Hansen Global Forest Change v1.11 (2000-2023) dataset](https://developers.google.com/earth-engine/datasets/catalog/UMD_hansen_global_forest_change_2023_v1_11)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "286", + "metadata": {}, + "outputs": [], + "source": [ + "dataset = ee.Image(\"UMD/hansen/global_forest_change_2023_v1_11\")\n", + "dataset.bandNames()" + ] + }, + { + "cell_type": "markdown", + "id": "287", + "metadata": {}, + "source": [ + "Select the imagery for 2000." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "288", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "first_bands = [\"first_b50\", \"first_b40\", \"first_b30\"]\n", + "first_image = dataset.select(first_bands)\n", + "m.add_layer(first_image, {\"bands\": first_bands, \"gamma\": 1.5}, \"Landsat 2000\")" + ] + }, + { + "cell_type": "markdown", + "id": "289", + "metadata": {}, + "source": [ + "Select the imagery for 2023." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "290", + "metadata": {}, + "outputs": [], + "source": [ + "last_bands = [\"last_b50\", \"last_b40\", \"last_b30\"]\n", + "last_image = dataset.select(last_bands)\n", + "m.add_layer(last_image, {\"bands\": last_bands, \"gamma\": 1.5}, \"Landsat 2023\")" + ] + }, + { + "cell_type": "markdown", + "id": "291", + "metadata": {}, + "source": [ + "Select the tree cover imagery for 2000." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "292", + "metadata": {}, + "outputs": [], + "source": [ + "treecover = dataset.select([\"treecover2000\"])\n", + "treeCoverVisParam = {\"min\": 0, \"max\": 100, \"palette\": [\"black\", \"green\"]}\n", + "name = \"Tree cover (%)\"\n", + "m.add_layer(treecover, treeCoverVisParam, name)\n", + "m.add_colorbar(treeCoverVisParam, label=name, layer_name=name)\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "293", + "metadata": {}, + "source": [ + "Extract tree cover 2000 by using the threshold of 10%." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "294", + "metadata": {}, + "outputs": [], + "source": [ + "threshold = 10\n", + "treecover_bin = treecover.gte(threshold).selfMask()\n", + "treeVisParam = {\"palette\": [\"green\"]}\n", + "m.add_layer(treecover_bin, treeVisParam, \"Tree cover bin\")" + ] + }, + { + "cell_type": "markdown", + "id": "295", + "metadata": {}, + "source": [ + "### Visualizing forest gain and loss\n", + "\n", + "Visualize forest loss." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "296", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[64.864983, -147.840441], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "treeloss_year = dataset.select([\"lossyear\"])\n", + "treeLossVisParam = {\"min\": 0, \"max\": 22, \"palette\": [\"yellow\", \"red\"]}\n", + "layer_name = \"Tree loss year\"\n", + "m.add_layer(treeloss_year, treeLossVisParam, layer_name)\n", + "m.add_colorbar(treeLossVisParam, label=layer_name, layer_name=layer_name)\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "297", + "metadata": {}, + "source": [ + "Compare forest loss and gain." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "298", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[64.864983, -147.840441], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "treeloss = dataset.select([\"loss\"]).selfMask()\n", + "treegain = dataset.select([\"gain\"]).selfMask()\n", + "m.add_layer(treeloss, {\"palette\": \"red\"}, \"Tree loss\")\n", + "m.add_layer(treegain, {\"palette\": \"yellow\"}, \"Tree gain\")\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "299", + "metadata": {}, + "source": [ + "### Calculating forest cover change\n", + "\n", + "Compute zonal statistics to find out which county in Alaska has the largest forest area in 2000.\n", + "\n", + "Add a county boundary layer to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "300", + "metadata": {}, + "outputs": [], + "source": [ + "counties = ee.FeatureCollection(\"TIGER/2018/Counties\").filter(\n", + " ee.Filter.eq(\"STATEFP\", \"02\")\n", + ")\n", + "df = geemap.ee_to_df(counties)\n", + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "301", + "metadata": {}, + "outputs": [], + "source": [ + "style = {\"color\": \"0000FFFF\", \"fillColor\": \"00000000\"}\n", + "m.add_layer(counties, {}, \"Counties Vector\", False)\n", + "m.add_layer(counties.style(**style), {}, \"Counties Raster\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "302", + "metadata": {}, + "source": [ + "Compute zonal statistics by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "303", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.zonal_stats(\n", + " treecover_bin,\n", + " counties,\n", + " \"forest_cover.csv\",\n", + " stat_type=\"SUM\",\n", + " denominator=1e6,\n", + " scale=300,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "304", + "metadata": {}, + "source": [ + "Create a pie chart to visualize the forest area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "305", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.pie_chart(\n", + " \"forest_cover.csv\", names=\"NAME\", values=\"sum\", max_rows=20, height=400\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "306", + "metadata": {}, + "source": [ + "Create a bar chart to visualize the forest area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "307", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.bar_chart(\n", + " \"forest_cover.csv\",\n", + " x=\"NAME\",\n", + " y=\"sum\",\n", + " max_rows=20,\n", + " x_label=\"County\",\n", + " y_label=\"Forest area (km2)\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "308", + "metadata": {}, + "source": [ + "Calculate the forest loss area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "309", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.zonal_stats(\n", + " treeloss.gt(0),\n", + " counties,\n", + " \"treeloss.csv\",\n", + " stat_type=\"SUM\",\n", + " denominator=1e6,\n", + " scale=300,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "310", + "metadata": {}, + "source": [ + "Create a bar chart to visualize the forest loss area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "311", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.pie_chart(\"treeloss.csv\", names=\"NAME\", values=\"sum\", max_rows=20, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "312", + "metadata": {}, + "source": [ + "Create a bar chart to visualize the forest loss area by county." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "313", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.bar_chart(\n", + " \"treeloss.csv\",\n", + " x=\"NAME\",\n", + " y=\"sum\",\n", + " max_rows=20,\n", + " x_label=\"County\",\n", + " y_label=\"Forest loss area (km2)\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "314", + "metadata": {}, + "source": [ + "## Exercise 5 - Analyzing forest cover gain and loss\n", + "\n", + "Find out which US state has the largest forest gain and loss between 2000 and 2022. Create pie charts and bar charts to show the results. Relevant Earth Engine assets:\n", + "\n", + "- [ee.FeatureCollection(\"TIGER/2018/States\")](https://developers.google.com/earth-engine/datasets/catalog/TIGER_2018_States)\n", + "- [ee.Image(\"UMD/hansen/global_forest_change_2022_v1_10\")](https://developers.google.com/earth-engine/datasets/catalog/UMD_hansen_global_forest_change_2022_v1_10)\n", + "\n", + "![](https://i.imgur.com/NQ4UUnj.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "315", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "316", + "metadata": {}, + "source": [ + "## Image Classification\n", + "\n", + "### North American Land Change Monitoring System (NALCMS)\n", + "\n", + "The [2020 North American Land Cover 30-meter dataset](https://developers.google.com/earth-engine/datasets/catalog/USGS_NLCD_RELEASES_2020_REL_NALCMS) was produced as part of the North American Land Change Monitoring System (NALCMS), a trilateral effort between Natural Resources Canada, the United States Geological Survey, and three Mexican organizations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "317", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4, height=700)\n", + "m.add_basemap(\"Esri.WorldImagery\", False)\n", + "landcover = ee.Image(\"USGS/NLCD_RELEASES/2020_REL/NALCMS\")\n", + "\n", + "states = ee.FeatureCollection(\"TIGER/2018/States\")\n", + "fc = states.filter(ee.Filter.eq(\"NAME\", \"Alaska\"))\n", + "\n", + "legend_dict = {\n", + " \"1 Temperate forest\": \"033e00\",\n", + " \"2 Sub-polar forest\": \"939b71\",\n", + " \"3 Tropical evergreen forest\": \"196d12\",\n", + " \"4 Tropical deciduous forest\": \"1fab01\",\n", + " \"5 Temperate deciduous forest\": \"5b725c\",\n", + " \"6 Mixed forest\": \"6b7d2c\",\n", + " \"7 Tropical shrubland\": \"b29d29\",\n", + " \"8 Temperate shrubland\": \"b48833\",\n", + " \"9 Tropical grassland\": \"e9da5d\",\n", + " \"10 Temperate grassland\": \"e0cd88\",\n", + " \"11 Sub-polar shrubland\": \"a07451\",\n", + " \"12 Sub-polar grassland\": \"bad292\",\n", + " \"13 Sub-polar barren\": \"3f8970\",\n", + " \"14 Wetland\": \"6ca289\",\n", + " \"15 Cropland\": \"e6ad6a\",\n", + " \"16 Barren land\": \"a9abae\",\n", + " \"17 Urban and built-up\": \"db2126\",\n", + " \"18 Water\": \"4c73a1\",\n", + " \"19 Snow and ice \": \"fff7fe\",\n", + "}\n", + "\n", + "palette = list(legend_dict.values())\n", + "vis_params = {\"palette\": palette, \"min\": 1, \"max\": 19}\n", + "\n", + "m.add_layer(landcover, vis_params, \"NALCMS Land Cover\")\n", + "m.add_layer(fc, {}, \"Alaska\", False)\n", + "m.center_object(fc, 4)\n", + "m.add_legend(title=\"Land Cover Type\", legend_dict=legend_dict)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "318", + "metadata": {}, + "outputs": [], + "source": [ + "fig = geemap.image_histogram(\n", + " landcover, region=fc, x_label=\"Land cover type\", y_label=\"Pixels\"\n", + ")\n", + "fig" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "319", + "metadata": {}, + "outputs": [], + "source": [ + "values = list(fig.data[0][\"x\"])\n", + "values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "320", + "metadata": {}, + "outputs": [], + "source": [ + "classes = [list(legend_dict.keys())[int(value) - 1] for value in values]\n", + "classes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "321", + "metadata": {}, + "outputs": [], + "source": [ + "fig.update_xaxes(tickvals=values, ticktext=classes)\n", + "fig" + ] + }, + { + "cell_type": "markdown", + "id": "322", + "metadata": {}, + "source": [ + "### Unsupervised classification" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "323", + "metadata": {}, + "outputs": [], + "source": [ + "region = ee.Geometry.BBox(-149.352, 64.5532, -147.0976, 65.1277)\n", + "collection = geemap.landsat_timeseries(\n", + " region, start_year=2021, end_year=2021, start_date=\"06-01\", end_date=\"09-01\"\n", + ")\n", + "image = collection.first()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "324", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "vis_params = {\"min\": 0, \"max\": 0.3, \"bands\": [\"NIR\", \"Red\", \"Green\"]}\n", + "m.add_layer(image, vis_params, \"Image\")\n", + "m.add_layer(landcover.clip(region), {}, \"NALCMS land cover\", False)\n", + "# m.add_legend(title='Land Cover Type', legend_dict=legend_dict, layer_name='NALCMS land cover')\n", + "m.center_object(region, 9)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "325", + "metadata": {}, + "outputs": [], + "source": [ + "training = image.sample(\n", + " **{\n", + " \"region\": region,\n", + " \"scale\": 150,\n", + " \"numPixels\": 5000,\n", + " \"seed\": 1,\n", + " \"geometries\": True,\n", + " }\n", + ")\n", + "m.add_layer(training, {}, \"Training samples\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "326", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_df(training.limit(5))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "327", + "metadata": {}, + "outputs": [], + "source": [ + "clusterer = ee.Clusterer.wekaXMeans(minClusters=3, maxClusters=6).train(training)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "328", + "metadata": {}, + "outputs": [], + "source": [ + "result = image.cluster(clusterer)\n", + "m.add_layer(result.randomVisualizer(), {}, \"Clusters\")\n", + "m.add(\"layer_manager\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "329", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.image_histogram(landcover, region=region, scale=30)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "330", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.image_histogram(result, region=region, scale=300)" + ] + }, + { + "cell_type": "markdown", + "id": "331", + "metadata": {}, + "source": [ + "### Supervised classification" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "332", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "vis_params = {\"min\": 0, \"max\": 0.3, \"bands\": [\"NIR\", \"Red\", \"Green\"]}\n", + "m.add_layer(image, vis_params, \"Image\")\n", + "m.add_layer(landcover.clip(region), {}, \"NALCMS land cover\", False)\n", + "# m.add_legend(title='Land Cover Type', legend_dict=legend_dict, layer_name='NALCMS land cover')\n", + "m.center_object(region, 9)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "333", + "metadata": {}, + "outputs": [], + "source": [ + "points = landcover.sample(\n", + " **{\n", + " \"region\": region,\n", + " \"scale\": 150,\n", + " \"numPixels\": 5000,\n", + " \"seed\": 1,\n", + " \"geometries\": True,\n", + " }\n", + ")\n", + "\n", + "m.add_layer(points, {}, \"Training\", False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "334", + "metadata": {}, + "outputs": [], + "source": [ + "label = \"landcover\"\n", + "features = image.sampleRegions(\n", + " **{\"collection\": points, \"properties\": [label], \"scale\": 150}\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "335", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_df(features.limit(5))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "336", + "metadata": {}, + "outputs": [], + "source": [ + "bands = image.bandNames().getInfo()\n", + "params = {\n", + " \"features\": features,\n", + " \"classProperty\": label,\n", + " \"inputProperties\": bands,\n", + "}\n", + "classifier = ee.Classifier.smileCart(maxNodes=None).train(**params)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "337", + "metadata": {}, + "outputs": [], + "source": [ + "classified = image.classify(classifier).rename(\"landcover\")\n", + "m.add_layer(classified.randomVisualizer(), {}, \"Classified\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "338", + "metadata": {}, + "outputs": [], + "source": [ + "class_values = list(range(1, 20))\n", + "class_palette = list(legend_dict.values())\n", + "classified = classified.set(\n", + " {\"landcover_class_values\": class_values, \"landcover_class_palette\": class_palette}\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "339", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_layer(classified, {}, \"Land cover\")\n", + "m.add_legend(title=\"Land cover type\", builtin_legend=\"NLCD\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "340", + "metadata": {}, + "source": [ + "## Accuracy assessment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "341", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "point = ee.Geometry.Point([-122.4439, 37.7538])\n", + "\n", + "img = (\n", + " ee.ImageCollection(\"COPERNICUS/S2_SR\")\n", + " .filterBounds(point)\n", + " .filterDate(\"2020-01-01\", \"2021-01-01\")\n", + " .sort(\"CLOUDY_PIXEL_PERCENTAGE\")\n", + " .first()\n", + " .select(\"B.*\")\n", + ")\n", + "\n", + "vis_params = {\"min\": 100, \"max\": 3500, \"bands\": [\"B11\", \"B8\", \"B3\"]}\n", + "\n", + "m.centerObject(point, 9)\n", + "m.add_layer(img, vis_params, \"Sentinel-2\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "342", + "metadata": {}, + "outputs": [], + "source": [ + "lc = ee.Image(\"ESA/WorldCover/v100/2020\")\n", + "classValues = [10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 100]\n", + "remapValues = ee.List.sequence(0, 10)\n", + "label = \"lc\"\n", + "lc = lc.remap(classValues, remapValues).rename(label).toByte()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "343", + "metadata": {}, + "outputs": [], + "source": [ + "sample = img.addBands(lc).stratifiedSample(\n", + " **{\n", + " \"numPoints\": 100,\n", + " \"classBand\": label,\n", + " \"region\": img.geometry(),\n", + " \"scale\": 10,\n", + " \"geometries\": True,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "344", + "metadata": {}, + "outputs": [], + "source": [ + "sample = sample.randomColumn()\n", + "trainingSample = sample.filter(\"random <= 0.8\")\n", + "validationSample = sample.filter(\"random > 0.8\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "345", + "metadata": {}, + "outputs": [], + "source": [ + "trainedClassifier = ee.Classifier.smileRandomForest(numberOfTrees=10).train(\n", + " **{\n", + " \"features\": trainingSample,\n", + " \"classProperty\": label,\n", + " \"inputProperties\": img.bandNames(),\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "346", + "metadata": {}, + "outputs": [], + "source": [ + "# print('Results of trained classifier', trainedClassifier.explain().getInfo())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "347", + "metadata": {}, + "outputs": [], + "source": [ + "trainAccuracy = trainedClassifier.confusionMatrix()\n", + "trainAccuracy.getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "348", + "metadata": {}, + "outputs": [], + "source": [ + "trainAccuracy.accuracy().getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "349", + "metadata": {}, + "outputs": [], + "source": [ + "trainAccuracy.kappa().getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "350", + "metadata": {}, + "outputs": [], + "source": [ + "validationSample = validationSample.classify(trainedClassifier)\n", + "validationAccuracy = validationSample.errorMatrix(label, \"classification\")\n", + "validationAccuracy.getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "351", + "metadata": {}, + "outputs": [], + "source": [ + "validationAccuracy.accuracy()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "352", + "metadata": {}, + "outputs": [], + "source": [ + "validationAccuracy.producersAccuracy().getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "353", + "metadata": {}, + "outputs": [], + "source": [ + "validationAccuracy.consumersAccuracy().getInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "354", + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "\n", + "with open(\"training.csv\", \"w\", newline=\"\") as f:\n", + " writer = csv.writer(f)\n", + " writer.writerows(trainAccuracy.getInfo())\n", + "\n", + "with open(\"validation.csv\", \"w\", newline=\"\") as f:\n", + " writer = csv.writer(f)\n", + " writer.writerows(validationAccuracy.getInfo())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "355", + "metadata": {}, + "outputs": [], + "source": [ + "imgClassified = img.classify(trainedClassifier)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "356", + "metadata": {}, + "outputs": [], + "source": [ + "classVis = {\n", + " \"min\": 0,\n", + " \"max\": 10,\n", + " \"palette\": [\n", + " \"006400\",\n", + " \"ffbb22\",\n", + " \"ffff4c\",\n", + " \"f096ff\",\n", + " \"fa0000\",\n", + " \"b4b4b4\",\n", + " \"f0f0f0\",\n", + " \"0064c8\",\n", + " \"0096a0\",\n", + " \"00cf75\",\n", + " \"fae6a0\",\n", + " ],\n", + "}\n", + "m.add_layer(lc, classVis, \"ESA Land Cover\", False)\n", + "m.add_layer(imgClassified, classVis, \"Classified\")\n", + "m.add_layer(trainingSample, {\"color\": \"black\"}, \"Training sample\")\n", + "m.add_layer(validationSample, {\"color\": \"white\"}, \"Validation sample\")\n", + "m.add_legend(title=\"Land Cover Type\", builtin_legend=\"ESA_WorldCover\")\n", + "m.centerObject(img)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "357", + "metadata": {}, + "source": [ + "## Exercise 6 - Unsupervised classification\n", + "\n", + "Perform an unsupervised classification of a Sentinel-2 imagery for your preferred area. Relevant Earth Engine assets:\n", + "\n", + "- [ee.ImageCollection(\"COPERNICUS/S2_HARMONIZED\")](https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2_HARMONIZED)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "358", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "359", + "metadata": {}, + "source": [ + "## Create and export maps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "360", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=(41.0462, -109.7424), zoom=6)\n", + "\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\")\n", + "landsat7 = ee.Image(\"LANDSAT/LE7_TOA_5YEAR/1999_2003\").select(\n", + " [\"B1\", \"B2\", \"B3\", \"B4\", \"B5\", \"B7\"]\n", + ")\n", + "\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "\n", + "m.add_layer(\n", + " landsat7,\n", + " {\"bands\": [\"B4\", \"B3\", \"B2\"], \"min\": 20, \"max\": 200, \"gamma\": 2},\n", + " \"landsat\",\n", + ")\n", + "m.add_layer(dem, vis_params, \"dem\", True, 1)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "361", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " m.layer_to_image(\"dem\", output=\"dem.tif\", crs=\"EPSG:3857\", region=None, scale=None)\n", + " m.layer_to_image(\"dem\", output=\"dem.jpg\", scale=500)\n", + " geemap.show_image(\"dem.jpg\")\n", + "except:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "362", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " m.layer_to_image(\"landsat\", output=\"landsat.tif\")\n", + " geemap.geotiff_to_image(\"landsat.tif\", output=\"landsat.jpg\")\n", + " geemap.show_image(\"landsat.jpg\")\n", + "except:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "363", + "metadata": {}, + "outputs": [], + "source": [ + "from geemap import cartoee\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "364", + "metadata": {}, + "source": [ + "### Plotting single-band images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "365", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "from geemap import cartoee" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "366", + "metadata": {}, + "outputs": [], + "source": [ + "srtm = ee.Image(\"CGIAR/SRTM90_V4\")\n", + "\n", + "# define bounding box [east, south, west, north] to request data\n", + "region = [180, -60, -180, 85]\n", + "vis = {\"min\": 0, \"max\": 3000}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "367", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 9))\n", + "\n", + "# use cartoee to get a map\n", + "ax = cartoee.get_map(srtm, region=region, vis_params=vis)\n", + "\n", + "# add a color bar to the map using the visualization params we passed to the map\n", + "cartoee.add_colorbar(\n", + " ax, vis, loc=\"bottom\", label=\"Elevation (m)\", orientation=\"horizontal\"\n", + ")\n", + "\n", + "# add grid lines to the map at a specified interval\n", + "cartoee.add_gridlines(ax, interval=[60, 30], linestyle=\":\")\n", + "\n", + "# add coastlines using the cartopy api\n", + "ax.coastlines(color=\"red\")\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "368", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 7))\n", + "\n", + "cmap = \"terrain\"\n", + "\n", + "ax = cartoee.get_map(srtm, region=region, vis_params=vis, cmap=cmap)\n", + "cartoee.add_colorbar(\n", + " ax, vis, cmap=cmap, loc=\"right\", label=\"Elevation (m)\", orientation=\"vertical\"\n", + ")\n", + "\n", + "cartoee.add_gridlines(ax, interval=[60, 30], linestyle=\"--\")\n", + "ax.coastlines(color=\"red\")\n", + "ax.set_title(label=\"Global Elevation Map\", fontsize=15)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "369", + "metadata": {}, + "outputs": [], + "source": [ + "cartoee.savefig(fig, fname=\"srtm.jpg\", dpi=300, bbox_inches=\"tight\")" + ] + }, + { + "cell_type": "markdown", + "id": "370", + "metadata": {}, + "source": [ + "### Plotting multi-band images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "371", + "metadata": {}, + "outputs": [], + "source": [ + "image = ee.Image(\"LANDSAT/LC08/C01/T1_SR/LC08_044034_20140318\")\n", + "vis = {\"bands\": [\"B5\", \"B4\", \"B3\"], \"min\": 0, \"max\": 5000, \"gamma\": 1.3}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "372", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "ax = cartoee.get_map(image, vis_params=vis)\n", + "cartoee.pad_view(ax)\n", + "cartoee.add_gridlines(ax, interval=0.5, xtick_rotation=0, linestyle=\":\")\n", + "ax.coastlines(color=\"yellow\")\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "373", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "region = [-121.8025, 37.3458, -122.6265, 37.9178]\n", + "ax = cartoee.get_map(image, vis_params=vis, region=region)\n", + "cartoee.add_gridlines(ax, interval=0.15, xtick_rotation=0, linestyle=\":\")\n", + "ax.coastlines(color=\"yellow\")\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "374", + "metadata": {}, + "source": [ + "### Using custom projections\n", + "\n", + "#### The PlateCarree projection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "375", + "metadata": {}, + "outputs": [], + "source": [ + "ocean = (\n", + " ee.ImageCollection(\"NASA/OCEANDATA/MODIS-Terra/L3SMI\")\n", + " .filter(ee.Filter.date(\"2018-01-01\", \"2018-03-01\"))\n", + " .median()\n", + " .select([\"sst\"], [\"SST\"])\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "376", + "metadata": {}, + "outputs": [], + "source": [ + "visualization = {\"bands\": \"SST\", \"min\": -2, \"max\": 30}\n", + "bbox = [180, -88, -180, 88]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "377", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "ax = cartoee.get_map(ocean, cmap=\"plasma\", vis_params=visualization, region=bbox)\n", + "cb = cartoee.add_colorbar(ax, vis_params=visualization, loc=\"right\", cmap=\"plasma\")\n", + "\n", + "ax.set_title(label=\"Sea Surface Temperature\", fontsize=15)\n", + "\n", + "ax.coastlines()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "378", + "metadata": {}, + "outputs": [], + "source": [ + "cartoee.savefig(fig, \"SST.jpg\", dpi=300)" + ] + }, + { + "cell_type": "markdown", + "id": "379", + "metadata": {}, + "source": [ + "#### Custom projections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "380", + "metadata": {}, + "outputs": [], + "source": [ + "import cartopy.crs as ccrs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "381", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "projection = ccrs.Mollweide(central_longitude=-180)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"bottom\", cmap=\"plasma\", orientation=\"horizontal\"\n", + ")\n", + "ax.set_title(\"Mollweide projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "382", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "projection = ccrs.Robinson(central_longitude=-180)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"bottom\", cmap=\"plasma\", orientation=\"horizontal\"\n", + ")\n", + "ax.set_title(\"Robinson projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "383", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "projection = ccrs.InterruptedGoodeHomolosine(central_longitude=-180)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"bottom\", cmap=\"plasma\", orientation=\"horizontal\"\n", + ")\n", + "ax.set_title(\"Goode homolosine projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "384", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(15, 10))\n", + "\n", + "projection = ccrs.EqualEarth(central_longitude=-180)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"right\", cmap=\"plasma\", orientation=\"vertical\"\n", + ")\n", + "ax.set_title(\"Equal Earth projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "385", + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(11, 10))\n", + "\n", + "projection = ccrs.Orthographic(-130, -10)\n", + "ax = cartoee.get_map(\n", + " ocean, vis_params=visualization, region=bbox, cmap=\"plasma\", proj=projection\n", + ")\n", + "cb = cartoee.add_colorbar(\n", + " ax, vis_params=visualization, loc=\"right\", cmap=\"plasma\", orientation=\"vertical\"\n", + ")\n", + "ax.set_title(\"Orographic projection\")\n", + "ax.coastlines()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "386", + "metadata": {}, + "source": [ + "## Exercise 7 - Creating NDVI maps\n", + "\n", + "Create and export a global NDVI map using MODIS data. Relevant Earth Engine assets:\n", + "\n", + "- [ee.ImageCollection(\"MODIS/MCD43A4_006_NDVI\")](https://developers.google.com/earth-engine/datasets/catalog/MODIS_MCD43A4_006_NDVI)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "387", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "388", + "metadata": {}, + "source": [ + "## Building interactive web apps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "389", + "metadata": {}, + "outputs": [], + "source": [ + "import ee\n", + "import geemap\n", + "import solara\n", + "\n", + "\n", + "class Map(geemap.Map):\n", + " def __init__(self, **kwargs):\n", + " super().__init__(**kwargs)\n", + " self.add_ee_data()\n", + "\n", + " def add_ee_data(self):\n", + " years = [\"2001\", \"2004\", \"2006\", \"2008\", \"2011\", \"2013\", \"2016\", \"2019\"]\n", + "\n", + " def getNLCD(year):\n", + " dataset = ee.ImageCollection(\"USGS/NLCD_RELEASES/2019_REL/NLCD\")\n", + " nlcd = dataset.filter(ee.Filter.eq(\"system:index\", year)).first()\n", + " landcover = nlcd.select(\"landcover\")\n", + " return landcover\n", + "\n", + " collection = ee.ImageCollection(ee.List(years).map(lambda year: getNLCD(year)))\n", + " labels = [f\"NLCD {year}\" for year in years]\n", + " self.ts_inspector(\n", + " left_ts=collection,\n", + " right_ts=collection,\n", + " left_names=labels,\n", + " right_names=labels,\n", + " )\n", + " self.add_legend(\n", + " title=\"NLCD Land Cover Type\",\n", + " builtin_legend=\"NLCD\",\n", + " height=\"460px\",\n", + " add_header=False,\n", + " )\n", + "\n", + "\n", + "@solara.component\n", + "def Page():\n", + " with solara.Column(style={\"min-width\": \"500px\"}):\n", + " Map.element(\n", + " center=[40, -100],\n", + " zoom=4,\n", + " height=\"800px\",\n", + " )\n", + "\n", + "\n", + "Page()" + ] + }, + { + "cell_type": "markdown", + "id": "390", + "metadata": {}, + "source": [ + "```bash\n", + "solara run ./pages\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "391", + "metadata": {}, + "outputs": [], + "source": [ + "# geemap.get_ee_token()" + ] + }, + { + "cell_type": "markdown", + "id": "392", + "metadata": {}, + "source": [ + "## Exercise 8 - Deploying an Earth Engine app on Hugging Face.\n", + "\n", + "Follow the instructions [here](https://huggingface.co/spaces/giswqs/solara-geemap) to deploy an Earth Engine web app on Hugging Face." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "393", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/mkdocs.yml b/mkdocs.yml index ef13a26ebd..c983a7fcb3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -145,6 +145,7 @@ nav: - workshops/Alaska_2024_Part3.ipynb - workshops/GEE_Workshop_2024.ipynb - workshops/TNGIC_2024.ipynb + - workshops/IGIC_2024.ipynb - Notebooks: - notebooks/00_ee_auth_colab.ipynb - notebooks/00_geemap_colab.ipynb