From 1f166a3cfb22b6580cbc9d2f1174da94a3faa203 Mon Sep 17 00:00:00 2001 From: giswqs Date: Mon, 19 Aug 2024 01:12:20 +0000 Subject: [PATCH] deploy: 7b3230c1a6b78b2d7370d6203f1e1e68cccb9ae8 --- _sources/book/about/instructor.ipynb | 2 +- _sources/book/about/schedule.ipynb | 2 +- _sources/book/about/syllabus.ipynb | 2 +- _sources/book/geospatial/geemap.ipynb | 2025 +++++++++++++++ ...01_get_started.ipynb => get_started.ipynb} | 0 _sources/book/geospatial/hypercoast.ipynb | 440 ++++ _sources/book/geospatial/leafmap.ipynb | 259 ++ _sources/book/geospatial/maplibre.ipynb | 990 ++++++++ _sources/book/geospatial/raster_viz.ipynb | 475 ++++ _sources/book/geospatial/samgeo.ipynb | 1112 +++++++++ _sources/book/geospatial/vector_viz.ipynb | 381 +++ _sources/book/geospatial/whitebox.ipynb | 922 +++++++ _sources/book/software/miniconda.ipynb | 2 +- _sources/book/software/overview.ipynb | 2 +- book/about/instructor.html | 10 +- book/about/schedule.html | 10 +- book/about/syllabus.html | 10 +- book/geospatial/geemap.html | 2206 +++++++++++++++++ .../{01_get_started.html => get_started.html} | 208 +- book/geospatial/hypercoast.html | 876 +++++++ book/geospatial/leafmap.html | 795 ++++++ book/geospatial/maplibre.html | 1290 ++++++++++ book/geospatial/raster_viz.html | 857 +++++++ book/geospatial/samgeo.html | 1223 +++++++++ book/geospatial/vector_viz.html | 841 +++++++ book/geospatial/whitebox.html | 1196 +++++++++ book/labs/instructions.html | 16 +- book/labs/lab_01.html | 10 +- book/python/01_get_started.html | 10 +- book/python/02_variables.html | 10 +- book/python/03_data_structures.html | 14 +- book/python/04_string_operations.html | 10 +- book/python/05_looping.html | 10 +- book/python/06_functions_classes.html | 10 +- book/python/07_files.html | 14 +- book/software/colab.html | 10 +- book/software/git.html | 10 +- book/software/jupyterlab.html | 10 +- book/software/miniconda.html | 10 +- book/software/overview.html | 10 +- book/software/vscode.html | 10 +- genindex.html | 10 +- index.html | 10 +- objects.inv | Bin 652 -> 789 bytes search.html | 10 +- searchindex.js | 2 +- 46 files changed, 16108 insertions(+), 224 deletions(-) create mode 100644 _sources/book/geospatial/geemap.ipynb rename _sources/book/geospatial/{01_get_started.ipynb => get_started.ipynb} (100%) create mode 100644 _sources/book/geospatial/hypercoast.ipynb create mode 100644 _sources/book/geospatial/leafmap.ipynb create mode 100644 _sources/book/geospatial/maplibre.ipynb create mode 100644 _sources/book/geospatial/raster_viz.ipynb create mode 100644 _sources/book/geospatial/samgeo.ipynb create mode 100644 _sources/book/geospatial/vector_viz.ipynb create mode 100644 _sources/book/geospatial/whitebox.ipynb create mode 100644 book/geospatial/geemap.html rename book/geospatial/{01_get_started.html => get_started.html} (64%) create mode 100644 book/geospatial/hypercoast.html create mode 100644 book/geospatial/leafmap.html create mode 100644 book/geospatial/maplibre.html create mode 100644 book/geospatial/raster_viz.html create mode 100644 book/geospatial/samgeo.html create mode 100644 book/geospatial/vector_viz.html create mode 100644 book/geospatial/whitebox.html diff --git a/_sources/book/about/instructor.ipynb b/_sources/book/about/instructor.ipynb index 21603d9..cbe3f27 100644 --- a/_sources/book/about/instructor.ipynb +++ b/_sources/book/about/instructor.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "4c17efa7", + "id": "33ef918c", "metadata": {}, "source": [ "## Instructor\n", diff --git a/_sources/book/about/schedule.ipynb b/_sources/book/about/schedule.ipynb index de31f46..32ea0c6 100644 --- a/_sources/book/about/schedule.ipynb +++ b/_sources/book/about/schedule.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "cf8d046d", + "id": "a739c717", "metadata": {}, "source": [ "# Schedule\n", diff --git a/_sources/book/about/syllabus.ipynb b/_sources/book/about/syllabus.ipynb index dcbe244..8adfca0 100644 --- a/_sources/book/about/syllabus.ipynb +++ b/_sources/book/about/syllabus.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "4dad51c7", + "id": "2b659987", "metadata": {}, "source": [ "# Syllabus\n", diff --git a/_sources/book/geospatial/geemap.ipynb b/_sources/book/geospatial/geemap.ipynb new file mode 100644 index 0000000..f88f7e2 --- /dev/null +++ b/_sources/book/geospatial/geemap.ipynb @@ -0,0 +1,2025 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# Geemap\n", + "\n", + "## Introduction\n", + "\n", + "This notebook is designed for users who are new to Google Earth Engine and geemap. It provides an introduction to Earth Engine and geemap, and demonstrates how to use geemap to explore and analyze Earth Engine data.\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/gee-community/geemap/blob/master/docs/notebooks/geemap_colab.ipynb) on Google Colab.\n", + "\n", + "- It is recommended that attendees have a basic understanding of Python and Jupyter Notebook.\n", + "- Familiarity with the Earth Engine JavaScript API is not required but will be helpful.\n", + "- Attendees can use Google Colab to follow this short course without installing anything on their computer.\n", + "\n", + "\n", + "### Agenda\n", + "\n", + "The main topics to be covered in this workshop include:\n", + "\n", + "* Create interactive maps\n", + "* Visualize Earth Engine data\n", + "* Explore Earth Engine Data Catalogs\n", + "* Analyze Earth Engine data\n", + "* Export Earth Engine data\n", + "* Create timelapse animations\n", + "\n", + "\n", + "## Introduction to Earth Engine and geemap\n", + "\n", + "Earth Engine 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", + "The geemap Python package is built upon the Earth Engine Python API and open-source mapping libraries. It allows Earth Engine users to interactively manipulate, analyze, and visualize geospatial big data in a Jupyter environment. Since its creation in April 2020, geemap has received over 3,300 GitHub stars and is being used by over 2,700 projects on GitHub.\n", + "\n", + "## Google Colab and Earth Engine Python API authentication\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/Taiwan_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", + "\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 code block to install geemap and some optional dependencies." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install -U \"geemap[workshop]\"" + ] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "Note that some geemap features may not work properly in the Google Colab environmennt. 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\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": [ + "ee.Authenticate()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7", + "metadata": {}, + "outputs": [], + "source": [ + "ee.Initialize(project=\"YOUR-PROJECT-ID\")" + ] + }, + { + "cell_type": "markdown", + "id": "8", + "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": "9", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()" + ] + }, + { + "cell_type": "markdown", + "id": "10", + "metadata": {}, + "source": [ + "To display it in a Jupyter notebook, simply ask for the object representation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11", + "metadata": {}, + "outputs": [], + "source": [ + "m" + ] + }, + { + "cell_type": "markdown", + "id": "12", + "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`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[40, -100], zoom=4, height=\"600xp\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, + "source": [ + "To hide a control, set `control_name` to `False`, e.g., `draw_ctrl=False`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(data_ctrl=False, toolbar_ctrl=False, draw_ctrl=False)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "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": "17", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(basemap=\"Esri.WorldImagery\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "18", + "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": "19", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_basemap(\"OpenTopoMap\")" + ] + }, + { + "cell_type": "markdown", + "id": "20", + "metadata": {}, + "source": [ + "You can also change basemaps interactively using the basemap GUI." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add(\"basemap_selector\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "22", + "metadata": {}, + "source": [ + "## Using Earth Engine data\n", + "\n", + "### 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", + "### 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" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23", + "metadata": {}, + "outputs": [], + "source": [ + "image = ee.Image(\"USGS/SRTMGL1_003\")\n", + "image" + ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "#### Visualizing Earth Engine images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[23.5790, 121.4181], zoom=8)\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": "26", + "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": "27", + "metadata": {}, + "outputs": [], + "source": [ + "collection = ee.ImageCollection(\"COPERNICUS/S2_SR\")" + ] + }, + { + "cell_type": "markdown", + "id": "28", + "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": "29", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "collection = (\n", + " ee.ImageCollection(\"COPERNICUS/S2_SR\")\n", + " .filterDate(\"2023-01-01\", \"2024-01-01\")\n", + " .filter(ee.Filter.lt(\"CLOUDY_PIXEL_PERCENTAGE\", 5))\n", + ")\n", + "image = collection.median()\n", + "\n", + "vis = {\n", + " \"min\": 0.0,\n", + " \"max\": 3000,\n", + " \"bands\": [\"B4\", \"B3\", \"B2\"],\n", + "}\n", + "\n", + "m.set_center(121.4181, 23.5790, 8)\n", + "m.add_layer(image, vis, \"Sentinel-2\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "### FeatureCollection\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": "31", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "fc = ee.FeatureCollection(\"TIGER/2016/Roads\")\n", + "m.set_center(-73.9596, 40.7688, 12)\n", + "m.add_layer(fc, {}, \"Census roads\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "32", + "metadata": {}, + "source": [ + "#### Filtering feature collections\n", + "\n", + "* [geoBoundaries: Political administrative boundaries at Country level (ADM0)](https://developers.google.com/earth-engine/datasets/catalog/WM_geoLab_geoBoundaries_600_ADM0)\n", + "* [geoBoundaries: Political administrative boundaries at District level (ADM1)](https://developers.google.com/earth-engine/datasets/catalog/WM_geoLab_geoBoundaries_600_ADM1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM0\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeName\", \"Taiwan\"))\n", + "m.add_layer(fc, {}, \"Taiwan\")\n", + "m.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM1\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeGroup\", \"TWN\"))\n", + "m.add_layer(fc, {}, \"Taiwan\")\n", + "m.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", + "metadata": {}, + "outputs": [], + "source": [ + "region = m.user_roi\n", + "if region is None:\n", + " region = ee.Geometry.BBox(119.1687, 21.7799, 122.981, 25.4234)\n", + "\n", + "fc = fc.filterBounds(region)\n", + "m.add_layer(fc, {}, \"Taiwan 2\")\n", + "m.center_object(fc, 8)" + ] + }, + { + "cell_type": "markdown", + "id": "36", + "metadata": {}, + "source": [ + "#### Visualizing feature collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM1\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeGroup\", \"TWN\"))\n", + "m.add_layer(fc, {}, \"Taiwan\")\n", + "m.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM1\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeGroup\", \"TWN\"))\n", + "style = {\"color\": \"000000ff\", \"width\": 2, \"lineType\": \"solid\", \"fillColor\": \"FF000000\"}\n", + "m.add_layer(fc.style(**style), {}, \"Taiwan\")\n", + "m.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM1\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeGroup\", \"TWN\"))\n", + "style = {\"color\": \"0000ffff\", \"width\": 2, \"lineType\": \"solid\", \"fillColor\": \"FF000080\"}\n", + "m.add_layer(fc.style(**style), {}, \"Taiwan\")\n", + "m.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "40", + "metadata": {}, + "source": [ + "### 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 July 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 for datasets\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": "41", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\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" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "counties = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM0\")\n", + "fc = counties.filter(ee.Filter.eq(\"shapeName\", \"Taiwan\"))\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\").clipToCollection(fc)\n", + "vis_params = {\n", + " \"min\": 0,\n", + " \"max\": 4000,\n", + " \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n", + "}\n", + "\n", + "m.add_layer(fc, {}, \"Taiwan\")\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "44", + "metadata": {}, + "source": [ + "### Exercise 1 - Creating cloud-free imagery\n", + "\n", + "Create a cloud-free imagery of Taiwan for the year of 2023. You can use either Landsat 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/LC09/C02/T1_L2\")](https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC09_C02_T1_L2)\n", + "\n", + "A sample map of cloud-free imagery for the state of Texas is shown below:\n", + "\n", + "![](https://i.imgur.com/i3IT0lF.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45", + "metadata": {}, + "outputs": [], + "source": [ + "# Type your code here" + ] + }, + { + "cell_type": "markdown", + "id": "46", + "metadata": {}, + "source": [ + "## Visualizing Earth Engine data\n", + "\n", + "### Using the inspector tool\n", + "\n", + "Inspect pixel values and vector features using the inspector tool. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "counties = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM0\")\n", + "fc = counties.filter(ee.Filter.eq(\"shapeName\", \"Taiwan\"))\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.0},\n", + " \"Landsat 7\",\n", + ")\n", + "m.add_layer(dem, vis_params, \"SRTM DEM\")\n", + "m.add_layer(fc, {}, \"Taiwan\")\n", + "m.add(\"inspector\")\n", + "m.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "48", + "metadata": {}, + "source": [ + "### Using the plotting tool\n", + "\n", + "Plot spectral profiles of pixels using the plotting tool." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49", + "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.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "50", + "metadata": {}, + "source": [ + "Set plotting options for Landsat." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51", + "metadata": {}, + "outputs": [], + "source": [ + "m.set_plot_options(add_marker_cluster=True, overlay=True)" + ] + }, + { + "cell_type": "markdown", + "id": "52", + "metadata": {}, + "source": [ + "Set plotting options for Hyperion." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53", + "metadata": {}, + "outputs": [], + "source": [ + "m.set_plot_options(add_marker_cluster=True, plot_type=\"bar\")" + ] + }, + { + "cell_type": "markdown", + "id": "54", + "metadata": {}, + "source": [ + "### Legends, color bars, and labels\n", + "\n", + "#### Built-in legends" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55", + "metadata": {}, + "outputs": [], + "source": [ + "from geemap.legends import builtin_legends" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56", + "metadata": {}, + "outputs": [], + "source": [ + "for legend in builtin_legends:\n", + " print(legend)" + ] + }, + { + "cell_type": "markdown", + "id": "57", + "metadata": {}, + "source": [ + "Add ESA WorldCover and legend to the map.\n", + "\n", + "https://developers.google.com/earth-engine/datasets/catalog/ESA_WorldCover_v200" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "\n", + "dataset = ee.ImageCollection(\"ESA/WorldCover/v200\").first()\n", + "visualization = {\"bands\": [\"Map\"]}\n", + "m.add_layer(dataset, visualization, \"Landcover\")\n", + "m.add_legend(title=\"Land Cover Type\", builtin_legend=\"ESA_WorldCover\")\n", + "m.set_center(121.4181, 23.5790, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "59", + "metadata": {}, + "source": [ + "#### Custom legends" + ] + }, + { + "cell_type": "markdown", + "id": "60", + "metadata": {}, + "source": [ + "Add a custom legend by specifying a dictionary of colors and labels." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "\n", + "dataset = ee.ImageCollection(\"ESA/WorldCover/v200\").first()\n", + "visualization = {\"bands\": [\"Map\"]}\n", + "m.add_layer(dataset, visualization, \"Landcover\")\n", + "legend_dict = {\n", + " \"10 Trees\": \"006400\",\n", + " \"20 Shrubland\": \"ffbb22\",\n", + " \"30 Grassland\": \"ffff4c\",\n", + " \"40 Cropland\": \"f096ff\",\n", + " \"50 Built-up\": \"fa0000\",\n", + " \"60 Barren / sparse vegetation\": \"b4b4b4\",\n", + " \"70 Snow and ice\": \"f0f0f0\",\n", + " \"80 Open water\": \"0064c8\",\n", + " \"90 Herbaceous wetland\": \"0096a0\",\n", + " \"95 Mangroves\": \"00cf75\",\n", + " \"100 Moss and lichen\": \"fae6a0\",\n", + "}\n", + "m.add_legend(title=\"Land Cover Type\", legend_dict=legend_dict)\n", + "m.set_center(121.4181, 23.5790, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "62", + "metadata": {}, + "source": [ + "#### Creating color bars\n", + "\n", + "Add a horizontal color bar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM0\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeName\", \"Taiwan\"))\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\").clipToCollection(fc)\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.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "64", + "metadata": {}, + "source": [ + "Add a vertical color bar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65", + "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": "66", + "metadata": {}, + "source": [ + "Make the color bar background transparent." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67", + "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": "68", + "metadata": {}, + "source": [ + "### Split-panel map and linked maps\n", + "\n", + "### 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": "69", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.split_map(left_layer=\"Esri.WorldTopoMap\", right_layer=\"OpenTopoMap\")\n", + "m.set_center(121.4181, 23.5790, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "70", + "metadata": {}, + "source": [ + "Create a split map with Earth Engine layers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "\n", + "esa_2020 = ee.ImageCollection(\"ESA/WorldCover/v100\").first()\n", + "esa_2021 = ee.ImageCollection(\"ESA/WorldCover/v200\").first()\n", + "visualization = {\"bands\": [\"Map\"]}\n", + "\n", + "left_layer = geemap.ee_tile_layer(esa_2020, visualization, \"Land Cover 2020\")\n", + "right_layer = geemap.ee_tile_layer(esa_2021, visualization, \"Land Cover 2021\")\n", + "\n", + "m.split_map(\n", + " left_layer, right_layer, left_label=\"Land Cover 2020\", right_label=\"Land Cover 2021\"\n", + ")\n", + "m.add_legend(title=\"Land Cover Type\", builtin_legend=\"ESA_WorldCover\")\n", + "m.set_center(121.4181, 23.5790, 8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "72", + "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": "73", + "metadata": {}, + "outputs": [], + "source": [ + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM0\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeName\", \"Taiwan\"))\n", + "image = (\n", + " ee.ImageCollection(\"COPERNICUS/S2\")\n", + " .filterDate(\"2023-01-01\", \"2024-01-01\")\n", + " .filter(ee.Filter.lt(\"CLOUDY_PIXEL_PERCENTAGE\", 5))\n", + " .filterBounds(fc)\n", + " .map(lambda img: img.divide(10000))\n", + " .median()\n", + " .clipToCollection(fc)\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=\"400px\",\n", + " center=[23.5790, 121.4181],\n", + " zoom=8,\n", + " ee_objects=[image],\n", + " vis_params=vis_params,\n", + " labels=labels,\n", + " label_position=\"topright\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "74", + "metadata": {}, + "source": [ + "### Timeseries inspector and time slider\n", + "\n", + "#### Timeseries inspector\n", + "\n", + "Check the available years of NLCD." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75", + "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": "76", + "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 a future ipyleaflet release." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77", + "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": "78", + "metadata": {}, + "source": [ + "#### Time slider\n", + "\n", + "Note that this feature may not work properly with in the Colab environment. 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": "79", + "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": "80", + "metadata": {}, + "source": [ + "Create a map for visualizing weather data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81", + "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": "82", + "metadata": {}, + "source": [ + "Visualizing Sentinel-2 imagery" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map(center=[37.75, -122.45], zoom=12)\n", + "\n", + "collection = (\n", + " ee.ImageCollection(\"COPERNICUS/S2_SR\")\n", + " .filterBounds(ee.Geometry.Point([-122.45, 37.75]))\n", + " .filterMetadata(\"CLOUDY_PIXEL_PERCENTAGE\", \"less_than\", 10)\n", + ")\n", + "\n", + "vis_params = {\"min\": 0, \"max\": 4000, \"bands\": [\"B8\", \"B4\", \"B3\"]}\n", + "\n", + "m.add_time_slider(collection, vis_params)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "84", + "metadata": {}, + "source": [ + "### Exercise 2 - Visualizing satellite data for an area of interest\n", + "\n", + "Visualize the time series of [Sentinel-2](https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2_SR_HARMONIZED) imagery for an area of interest in Taiwan. You can use the following Earth Engine assets:\n", + "\n", + "- `ee.ImageCollection(\"COPERNICUS/S2_SR_HARMONIZED\")`" + ] + }, + { + "cell_type": "markdown", + "id": "85", + "metadata": {}, + "source": [ + "## Analyzing Earth Engine data\n", + "\n", + "### Zonal statistics" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM1\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeGroup\", \"TWN\"))\n", + "# Add NASA SRTM\n", + "dem = ee.Image(\"USGS/SRTMGL1_003\").clipToCollection(fc)\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\").clipToCollection(fc)\n", + "landsat_vis = {\"bands\": [\"B4\", \"B3\", \"B2\"], \"gamma\": 1.4, \"min\": 20, \"max\": 150}\n", + "m.add_layer(landsat, landsat_vis, \"Landsat\", False)\n", + "m.add_layer(fc, {}, \"Taiwan\")\n", + "m.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87", + "metadata": {}, + "outputs": [], + "source": [ + "out_dem_stats = \"dem_stats.csv\"\n", + "geemap.zonal_stats(dem, fc, out_dem_stats, stat_type=\"MEAN\", scale=30, return_fc=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_df(out_dem_stats).sort_values(by=[\"mean\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89", + "metadata": {}, + "outputs": [], + "source": [ + "out_landsat_stats = \"landsat_stats.csv\"\n", + "geemap.zonal_stats(\n", + " landsat,\n", + " fc,\n", + " out_landsat_stats,\n", + " stat_type=\"MEAN\",\n", + " scale=30,\n", + " return_fc=False,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_df(out_landsat_stats)" + ] + }, + { + "cell_type": "markdown", + "id": "91", + "metadata": {}, + "source": [ + "### Zonal statistics by group" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM1\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeGroup\", \"TWN\"))\n", + "dataset = ee.ImageCollection(\"ESA/WorldCover/v200\").first().clipToCollection(fc)\n", + "visualization = {\"bands\": [\"Map\"]}\n", + "m.add_layer(dataset, visualization, \"Landcover\")\n", + "m.add_legend(title=\"Land Cover Type\", builtin_legend=\"ESA_WorldCover\")\n", + "m.add_layer(fc, {}, \"Taiwan\")\n", + "m.set_center(121.4181, 23.5790, 8)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93", + "metadata": {}, + "outputs": [], + "source": [ + "landcover_stats = \"landcover_stats.csv\"\n", + "\n", + "geemap.zonal_stats_by_group(\n", + " dataset,\n", + " fc,\n", + " landcover_stats,\n", + " stat_type=\"SUM\",\n", + " denominator=1e6,\n", + " decimal_places=2,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_df(landcover_stats)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95", + "metadata": {}, + "outputs": [], + "source": [ + "landcover_stats = \"landcover_stats_pct.csv\"\n", + "\n", + "geemap.zonal_stats_by_group(\n", + " dataset,\n", + " fc,\n", + " landcover_stats,\n", + " stat_type=\"PERCENTAGE\",\n", + " denominator=1e6,\n", + " decimal_places=2,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.csv_to_df(landcover_stats)" + ] + }, + { + "cell_type": "markdown", + "id": "97", + "metadata": {}, + "source": [ + "## Exporting Earth Engine data\n", + "\n", + "### Exporting images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "roi = ee.Geometry.Point([121.615219, 25.041219])\n", + "image = (\n", + " ee.ImageCollection(\"COPERNICUS/S2_SR_HARMONIZED\")\n", + " .filterDate(\"2024-01-01\", \"2024-08-01\")\n", + " .filter(ee.Filter.lt(\"CLOUDY_PIXEL_PERCENTAGE\", 10))\n", + " .filterBounds(roi)\n", + " .sort(\"CLOUDY_PIXEL_PERCENTAGE\")\n", + " .first()\n", + " .select([\"B8\", \"B4\", \"B3\"])\n", + ")\n", + "\n", + "vis_params = {\"min\": 0, \"max\": 3000}\n", + "\n", + "m.add_layer(image, vis_params, \"Sentinel-2\")\n", + "m.center_object(roi, 8)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99", + "metadata": {}, + "outputs": [], + "source": [ + "region = ee.Geometry.BBox(121.3824, 24.9325, 121.6653, 25.1496)\n", + "fc = ee.FeatureCollection(region)\n", + "style = {\"color\": \"ffff00ff\", \"fillColor\": \"00000000\"}\n", + "m.add_layer(fc.style(**style), {}, \"ROI\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "100", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image(image, filename=\"sentinel-2.tif\", scale=30, region=region)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "101", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image_to_drive(\n", + " image, description=\"sentinel-2\", folder=\"export\", region=region, scale=30\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "102", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.download_ee_image(image, \"sentinel-2_10m.tif\", region=region, scale=10)" + ] + }, + { + "cell_type": "markdown", + "id": "103", + "metadata": {}, + "source": [ + "### Export image collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "104", + "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": "105", + "metadata": {}, + "outputs": [], + "source": [ + "collection.aggregate_array(\"system:index\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "106", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image_collection(collection, out_dir=\"naip\", scale=10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "107", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_image_collection_to_drive(collection, folder=\"export\", scale=10)" + ] + }, + { + "cell_type": "markdown", + "id": "108", + "metadata": {}, + "source": [ + "### Exporting feature collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "109", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "countries = ee.FeatureCollection(\"WM/geoLab/geoBoundaries/600/ADM0\")\n", + "fc = countries.filter(ee.Filter.eq(\"shapeName\", \"Taiwan\"))\n", + "m.add_layer(fc, {}, \"Taiwan\")\n", + "m.center_object(fc, 8)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "110", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_shp(fc, filename=\"Taiwan.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "111", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_vector(fc, filename=\"Taiwan.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "112", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_geojson(fc, filename=\"Taiwan.geojson\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "113", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_to_csv(fc, filename=\"Taiwan.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "114", + "metadata": {}, + "outputs": [], + "source": [ + "gdf = geemap.ee_to_gdf(fc)\n", + "gdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "115", + "metadata": {}, + "outputs": [], + "source": [ + "df = geemap.ee_to_df(fc)\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "116", + "metadata": {}, + "outputs": [], + "source": [ + "geemap.ee_export_vector_to_drive(\n", + " fc, description=\"Alaska\", fileFormat=\"SHP\", folder=\"export\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "117", + "metadata": {}, + "source": [ + "## Creating timelapse animations\n", + "\n", + "### Landsat timelapse" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "118", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.set_center(121.615219, 25.041219, 12)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "119", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(121.3824, 24.9325, 121.6653, 25.1496)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "120", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.landsat_timelapse(\n", + " roi,\n", + " out_gif=\"Taiwan.gif\",\n", + " start_year=1988,\n", + " end_year=2024,\n", + " start_date=\"01-01\",\n", + " end_date=\"12-31\",\n", + " bands=[\"SWIR1\", \"NIR\", \"Red\"],\n", + " frames_per_second=5,\n", + " title=\"Taipei\",\n", + " progress_bar_color=\"blue\",\n", + " mp4=True,\n", + ")\n", + "geemap.show_image(timelapse)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "121", + "metadata": {}, + "outputs": [], + "source": [ + "roi = ee.Geometry.BBox(113.8252, 22.1988, 114.0851, 22.3497)\n", + "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": "code", + "execution_count": null, + "id": "122", + "metadata": {}, + "outputs": [], + "source": [ + "roi = ee.Geometry.BBox(-115.5541, 35.8044, -113.9035, 36.5581)\n", + "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": "markdown", + "id": "123", + "metadata": {}, + "source": [ + "### Sentinel-2 timelapse" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "124", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.set_center(121.615219, 25.041219, 12)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "125", + "metadata": {}, + "outputs": [], + "source": [ + "roi = m.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(121.3824, 24.9325, 121.6653, 25.1496)\n", + " m.add_layer(roi)\n", + " m.center_object(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "126", + "metadata": {}, + "outputs": [], + "source": [ + "timelapse = geemap.sentinel2_timelapse(\n", + " roi,\n", + " out_gif=\"sentinel2.gif\",\n", + " start_year=2017,\n", + " end_year=2024,\n", + " start_date=\"01-01\",\n", + " end_date=\"12-31\",\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": "127", + "metadata": {}, + "source": [ + "### MODIS vegetation indices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "128", + "metadata": {}, + "outputs": [], + "source": [ + "Map = geemap.Map()\n", + "Map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "129", + "metadata": {}, + "outputs": [], + "source": [ + "roi = Map.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-18.6983, -36.1630, 52.2293, 38.1446)\n", + " Map.addLayer(roi)\n", + " Map.centerObject(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "130", + "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": "131", + "metadata": {}, + "source": [ + "### MODIS temperature data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "132", + "metadata": {}, + "outputs": [], + "source": [ + "Map = geemap.Map()\n", + "Map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "133", + "metadata": {}, + "outputs": [], + "source": [ + "roi = Map.user_roi\n", + "if roi is None:\n", + " roi = ee.Geometry.BBox(-171.21, -57.13, 177.53, 79.99)\n", + " Map.addLayer(roi)\n", + " Map.centerObject(roi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "134", + "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": "135", + "metadata": {}, + "source": [ + "### GOES timelapse" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "136", + "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": "137", + "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": "138", + "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": "139", + "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": "140", + "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": "141", + "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": "142", + "metadata": {}, + "source": [ + "### Exercise 3 - 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 hashtag 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": "143", + "metadata": {}, + "outputs": [], + "source": [ + "m = geemap.Map()\n", + "m.add_gui(\"timelapse\")\n", + "m" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/book/geospatial/01_get_started.ipynb b/_sources/book/geospatial/get_started.ipynb similarity index 100% rename from _sources/book/geospatial/01_get_started.ipynb rename to _sources/book/geospatial/get_started.ipynb diff --git a/_sources/book/geospatial/hypercoast.ipynb b/_sources/book/geospatial/hypercoast.ipynb new file mode 100644 index 0000000..bfc3965 --- /dev/null +++ b/_sources/book/geospatial/hypercoast.ipynb @@ -0,0 +1,440 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# HyperCoast\n", + "\n", + "## Environment setup\n", + "\n", + "Uncomment and run the following cell to install the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install \"hypercoast[extra]\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Import library." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import hypercoast" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To download and access the data, you will need to create an Earthdata login. You can register for an account at [urs.earthdata.nasa.gov](https://urs.earthdata.nasa.gov). Once you have an account, run the following cell and enter your NASA Earthdata login credentials." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hypercoast.nasa_earth_login()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Search for EMIT data\n", + "\n", + "Search for EMIT data programmatically. Specify the bounding box and time range of interest. Set `count=-1` to return all results or set `count=10` to return the first 10 results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "results, gdf = hypercoast.search_emit(\n", + " bbox=(-83, 25, -81, 28),\n", + " temporal=(\"2024-04-01\", \"2024-05-16\"),\n", + " count=10, # use -1 to return all datasets\n", + " return_gdf=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the footprints of the returned datasets on a map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "gdf.explore()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Uncomment the following cell to download the first dataset from the search results. Note that the download may take some time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# hypercoast.download_emit(results[:1], out_dir=\"data\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Search for EMIT data interactively. Specify pan and zoom to the area of interest. Specify the time range of interest from the search dialog, then click on the Search button." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m = hypercoast.Map(center=[30.0262, -90.1345], zoom=8)\n", + "m.search_emit()\n", + "m" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Uncomment the following cell to display the GeoDataFrame of the search results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# m._NASA_DATA_GDF.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similarly, you can download the first dataset from the search results by uncommenting the following cell." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# hypercoast.download_emit(results[:1], out_dir=\"data\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Download a sample EMIT dataset\n", + "\n", + "Let's download a sample EMIT dataset for the demonstration." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/opengeos/datasets/releases/download/hypercoast/EMIT_L2A_RFL_001_20240404T161230_2409511_009.nc\"\n", + "filepath = \"../examples/data/EMIT_L2A_RFL_001_20240404T161230_2409511_009.nc\"\n", + "hypercoast.download_file(url, filepath, quiet=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Read EMIT data\n", + "\n", + "Read the downloaded EMIT data and process it as an `xarray.Dataset`. Note that the dataset has 285 bands." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dataset = hypercoast.read_emit(filepath)\n", + "# dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/qn0B4fb.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize EMIT data\n", + "\n", + "Visualize the EMIT data on an interactive map. You can change the band combination and extract spectral profiles interactively. You can also export the spectral profiles as a CSV file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m = hypercoast.Map()\n", + "m.add_basemap(\"SATELLITE\")\n", + "m.add_emit(dataset, wavelengths=[1000, 600, 500], vmin=0, vmax=0.3, layer_name=\"EMIT\")\n", + "m.add(\"spectral\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/6pceRUz.gif)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create an image cube\n", + "\n", + "First, select a subset of the data to avoid nodata areas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds = dataset.sel(longitude=slice(-90.1482, -89.7321), latitude=slice(30.0225, 29.7451))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualize the EMIT data in 3D with an RGB image overlaid on top of the 3D plot." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p = hypercoast.image_cube(\n", + " ds,\n", + " variable=\"reflectance\",\n", + " cmap=\"jet\",\n", + " clim=(0, 0.4),\n", + " rgb_wavelengths=[1000, 700, 500],\n", + " rgb_gamma=2,\n", + " title=\"EMIT Reflectance\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Uncomment the following cell to create an image cube. Note that this function does not work in the Google Colab environment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# p.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/CvE9PN9.gif)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Interactive slicing\n", + "\n", + "First, select a subset of the data for demonstration purposes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds = dataset.sel(longitude=slice(-90.05, -89.99), latitude=slice(30.00, 29.93))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Drag the plane up and down to slice the data in 3D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p = hypercoast.image_cube(\n", + " ds,\n", + " variable=\"reflectance\",\n", + " cmap=\"jet\",\n", + " clim=(0, 0.5),\n", + " rgb_wavelengths=[1000, 700, 500],\n", + " rgb_gamma=2,\n", + " title=\"EMIT Reflectance\",\n", + " widget=\"plane\",\n", + ")\n", + "p.add_text(\"Band slicing\", position=\"upper_right\", font_size=14)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Uncomment the following cell to display the interactive slicing widget. Note that this function does not work in the Google Colab environment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# p.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/msK1liO.gif)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Interactive thresholding\n", + "\n", + "Drag the threshold slider to threshold the data in 3D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p = hypercoast.image_cube(\n", + " ds,\n", + " variable=\"reflectance\",\n", + " cmap=\"jet\",\n", + " clim=(0, 0.5),\n", + " rgb_wavelengths=[1000, 700, 500],\n", + " rgb_gamma=2,\n", + " title=\"EMIT Reflectance\",\n", + " widget=\"threshold\",\n", + ")\n", + "p.add_text(\"Thresholding\", position=\"upper_right\", font_size=14)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Uncomment the following cell to display the thresholded data. Note that this function does not work in the Google Colab environment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# p.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/TPd20Tn.gif)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hyper", + "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.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/_sources/book/geospatial/leafmap.ipynb b/_sources/book/geospatial/leafmap.ipynb new file mode 100644 index 0000000..72af941 --- /dev/null +++ b/_sources/book/geospatial/leafmap.ipynb @@ -0,0 +1,259 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# Leafmap" + ] + }, + { + "cell_type": "markdown", + "id": "1", + "metadata": {}, + "source": [ + "## Install leafmap" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install leafmap" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "import leafmap" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "## Create an interactive map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=(40, -100), zoom=4)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "## Customize map height" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(height=\"400px\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "## Set control visibility" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(\n", + " draw_control=False,\n", + " measure_control=False,\n", + " fullscreen_control=False,\n", + " attribution_control=True,\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "## Change basemaps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_basemap(\"OpenTopoMap\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "## Add XYZ tile layer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_tile_layer(\n", + " url=\"https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}\",\n", + " name=\"Google Satellite\",\n", + " attribution=\"Google\",\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "## Add WMS tile layer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40, -100], zoom=4)\n", + "url = \"https://imagery.nationalmap.gov/arcgis/services/USGSNAIPImagery/ImageServer/WMSServer?\"\n", + "m.add_wms_layer(\n", + " url=url,\n", + " layers=\"USGSNAIPImagery:FalseColorComposite\",\n", + " name=\"NAIP\",\n", + " attribution=\"USGS\",\n", + " format=\"image/png\",\n", + " shown=True,\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "## Add legend" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40, -100], zoom=4)\n", + "url = \"https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2021_Land_Cover_L48/wms?\"\n", + "m.add_wms_layer(\n", + " url=url,\n", + " layers=\"NLCD_2021_Land_Cover_L48\",\n", + " name=\"NLCD 2021\",\n", + " attribution=\"MRLC\",\n", + " format=\"image/png\",\n", + " shown=True,\n", + ")\n", + "m.add_legend(title=\"NLCD Land Cover Type\", builtin_legend=\"NLCD\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "## Add colorbar" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_basemap(\"OpenTopoMap\")\n", + "m.add_colormap(\n", + " \"terrain\",\n", + " label=\"Elevation\",\n", + " orientation=\"horizontal\",\n", + " vmin=0,\n", + " vmax=4000,\n", + ")\n", + "m" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/book/geospatial/maplibre.ipynb b/_sources/book/geospatial/maplibre.ipynb new file mode 100644 index 0000000..1a029dd --- /dev/null +++ b/_sources/book/geospatial/maplibre.ipynb @@ -0,0 +1,990 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# MapLibre\n", + "\n", + "The notebook demonstrates how to create 3D maps using the [MapLibre](https://github.com/eodaGmbH/py-maplibregl) Python package. The examples shown in this notebook are based on the [MapLibre documentation](https://eodagmbh.github.io/py-maplibregl/examples/vancouver_blocks/). \n", + "\n", + "## Installation\n", + "\n", + "Uncomment the following line to install [leafmap](https://leafmap.org) if needed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install \"leafmap[maplibre]\"" + ] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3", + "metadata": {}, + "outputs": [], + "source": [ + "import leafmap.maplibregl as leafmap" + ] + }, + { + "cell_type": "markdown", + "id": "4", + "metadata": {}, + "source": [ + "## Create maps\n", + "\n", + "Create an interactive map by specifying map center [lon, lat], zoom level, pitch, and bearing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[-100, 40], zoom=3, pitch=0, bearing=0)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "6", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/8ITaEZa.png)" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "To customize the basemap, you can specify the `style` parameter. It can be an URL or a string, such as `dark-matter`, `positron`, `voyager`, `demotiles`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(style=\"positron\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/9fImW21.png)" + ] + }, + { + "cell_type": "markdown", + "id": "10", + "metadata": {}, + "source": [ + "To create a map with a background color, use `style=\"background-\"`, such as `background-lightgray` and `background-green`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(style=\"background-lightgray\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "12", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/xFeDTkE.png)" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "Alternatively, you can provide a URL to a vector style." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "style = \"https://demotiles.maplibre.org/style.json\"\n", + "m = leafmap.Map(style=style)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/yaZYrr1.png)" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "metadata": {}, + "source": [ + "## Add controls\n", + "\n", + "The control to add to the map. Can be one of the following: `scale`, `fullscreen`, `geolocate`, `navigation`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_control(\"geolocate\", position=\"top-left\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "18", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/7LS5WAk.png)" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "## Add basemaps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_basemap()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_basemap(\"OpenTopoMap\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "23", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/MRRw1MW.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_basemap(\"Esri.WorldImagery\")" + ] + }, + { + "cell_type": "markdown", + "id": "25", + "metadata": {}, + "source": [ + "## XYZ tile layer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "url = \"https://tile.openstreetmap.org/{z}/{x}/{y}.png\"\n", + "m.add_tile_layer(\n", + " url, name=\"OpenStreetMap\", attribution=\"OpenStreetMap\", opacity=1.0, visible=True\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "27", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/V9wmsjl.png)" + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "## WMS layer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[-100, 40], zoom=3)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "url = \"https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2021_Land_Cover_L48/wms\"\n", + "layers = \"NLCD_2021_Land_Cover_L48\"\n", + "m.add_wms_layer(url, layers=layers, name=\"NLCD\", opacity=0.8)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/xcZ4VKv.png)" + ] + }, + { + "cell_type": "markdown", + "id": "31", + "metadata": {}, + "source": [ + "## COG layer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "url = (\n", + " \"https://github.com/opengeos/datasets/releases/download/raster/Libya-2023-07-01.tif\"\n", + ")\n", + "m.add_cog_layer(url, name=\"COG\", attribution=\"Maxar\", fit_bounds=True)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "33", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/ApGhjDp.png)" + ] + }, + { + "cell_type": "markdown", + "id": "34", + "metadata": {}, + "source": [ + "## STAC layer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "url = \"https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json\"\n", + "m.add_stac_layer(url, bands=[\"B4\", \"B3\", \"B2\"], name=\"SPOT\", vmin=0, vmax=150)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "36", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/RJAhsV5.png)" + ] + }, + { + "cell_type": "markdown", + "id": "37", + "metadata": {}, + "source": [ + "## Local raster" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://github.com/opengeos/datasets/releases/download/raster/srtm90.tif\"\n", + "filepath = \"srtm90.tif\"\n", + "leafmap.download_file(url, filepath)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_raster(filepath, colormap=\"terrain\", name=\"DEM\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "40", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/pMcuQAp.png)" + ] + }, + { + "cell_type": "markdown", + "id": "41", + "metadata": {}, + "source": [ + "## Vancouver Property Value" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(\n", + " center=[-123.13, 49.254], zoom=11, style=\"dark-matter\", pitch=45, bearing=0\n", + ")\n", + "url = \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json\"\n", + "paint_line = {\n", + " \"line-color\": \"white\",\n", + " \"line-width\": 2,\n", + "}\n", + "paint_fill = {\n", + " \"fill-extrusion-color\": {\n", + " \"property\": \"valuePerSqm\",\n", + " \"stops\": [\n", + " [0, \"grey\"],\n", + " [1000, \"yellow\"],\n", + " [5000, \"orange\"],\n", + " [10000, \"darkred\"],\n", + " [50000, \"lightblue\"],\n", + " ],\n", + " },\n", + " \"fill-extrusion-height\": [\"*\", 10, [\"sqrt\", [\"get\", \"valuePerSqm\"]]],\n", + " \"fill-extrusion-opacity\": 0.9,\n", + "}\n", + "m.add_geojson(url, layer_type=\"line\", paint=paint_line, name=\"blocks-line\")\n", + "m.add_geojson(url, layer_type=\"fill-extrusion\", paint=paint_fill, name=\"blocks-fill\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43", + "metadata": {}, + "outputs": [], + "source": [ + "m.layer_interact()" + ] + }, + { + "cell_type": "markdown", + "id": "44", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/IZXfgSz.gif)" + ] + }, + { + "cell_type": "markdown", + "id": "45", + "metadata": {}, + "source": [ + "## Earthquake Clusters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(style=\"positron\")\n", + "\n", + "data = \"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n", + "source_args = {\n", + " \"cluster\": True,\n", + " \"cluster_radius\": 50,\n", + " \"cluster_min_points\": 2,\n", + " \"cluster_max_zoom\": 14,\n", + " \"cluster_properties\": {\n", + " \"maxMag\": [\"max\", [\"get\", \"mag\"]],\n", + " \"minMag\": [\"min\", [\"get\", \"mag\"]],\n", + " },\n", + "}\n", + "\n", + "m.add_geojson(\n", + " data,\n", + " layer_type=\"circle\",\n", + " name=\"earthquake-circles\",\n", + " filter=[\"!\", [\"has\", \"point_count\"]],\n", + " paint={\"circle-color\": \"darkblue\"},\n", + " source_args=source_args,\n", + ")\n", + "\n", + "m.add_geojson(\n", + " data,\n", + " layer_type=\"circle\",\n", + " name=\"earthquake-clusters\",\n", + " filter=[\"has\", \"point_count\"],\n", + " paint={\n", + " \"circle-color\": [\n", + " \"step\",\n", + " [\"get\", \"point_count\"],\n", + " \"#51bbd6\",\n", + " 100,\n", + " \"#f1f075\",\n", + " 750,\n", + " \"#f28cb1\",\n", + " ],\n", + " \"circle-radius\": [\"step\", [\"get\", \"point_count\"], 20, 100, 30, 750, 40],\n", + " },\n", + " source_args=source_args,\n", + ")\n", + "\n", + "m.add_geojson(\n", + " data,\n", + " layer_type=\"symbol\",\n", + " name=\"earthquake-labels\",\n", + " filter=[\"has\", \"point_count\"],\n", + " layout={\n", + " \"text-field\": [\"get\", \"point_count_abbreviated\"],\n", + " \"text-size\": 12,\n", + " },\n", + " source_args=source_args,\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "47", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/vge4jF4.png)" + ] + }, + { + "cell_type": "markdown", + "id": "48", + "metadata": {}, + "source": [ + "## Airport Markers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49", + "metadata": {}, + "outputs": [], + "source": [ + "from maplibre.controls import Marker, MarkerOptions, Popup, PopupOptions\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(style=\"positron\")\n", + "\n", + "url = \"https://github.com/visgl/deck.gl-data/raw/master/examples/line/airports.json\"\n", + "data = leafmap.pandas_to_geojson(\n", + " url, \"coordinates\", properties=[\"type\", \"name\", \"abbrev\"]\n", + ")\n", + "\n", + "m.add_geojson(\n", + " data,\n", + " name=\"Airports\",\n", + " layer_type=\"circle\",\n", + " paint={\n", + " \"circle-color\": [\n", + " \"match\",\n", + " [\"get\", \"type\"],\n", + " \"mid\",\n", + " \"darkred\",\n", + " \"major\",\n", + " \"darkgreen\",\n", + " \"darkblue\",\n", + " ],\n", + " \"circle_radius\": 10,\n", + " \"circle-opacity\": 0.3,\n", + " },\n", + ")\n", + "\n", + "\n", + "def get_color(airport_type: str) -> str:\n", + " color = \"darkblue\"\n", + " if airport_type == \"mid\":\n", + " color = \"darkred\"\n", + " elif airport_type == \"major\":\n", + " color = \"darkgreen\"\n", + "\n", + " return color\n", + "\n", + "\n", + "airports_data = pd.read_json(url)\n", + "popup_options = PopupOptions(close_button=False)\n", + "\n", + "for _, r in airports_data.iterrows():\n", + " m.add_marker(\n", + " lng_lat=r[\"coordinates\"],\n", + " options=MarkerOptions(color=get_color(r[\"type\"])),\n", + " popup=Popup(\n", + " text=r[\"name\"],\n", + " options=popup_options,\n", + " ),\n", + " )\n", + "\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "51", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/q7nN1PW.png)" + ] + }, + { + "cell_type": "markdown", + "id": "52", + "metadata": {}, + "source": [ + "## 3D Indoor Mapping" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(\n", + " center=(-87.61694, 41.86625), zoom=17, pitch=40, bearing=20, style=\"positron\"\n", + ")\n", + "m.add_basemap(\"OpenStreetMap.Mapnik\")\n", + "data = \"https://maplibre.org/maplibre-gl-js/docs/assets/indoor-3d-map.geojson\"\n", + "m.add_geojson(\n", + " data,\n", + " layer_type=\"fill-extrusion\",\n", + " name=\"floorplan\",\n", + " paint={\n", + " \"fill-extrusion-color\": [\"get\", \"color\"],\n", + " \"fill-extrusion-height\": [\"get\", \"height\"],\n", + " \"fill-extrusion-base\": [\"get\", \"base_height\"],\n", + " \"fill-extrusion-opacity\": 0.5,\n", + " },\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "54", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/dteQlQC.png)" + ] + }, + { + "cell_type": "markdown", + "id": "55", + "metadata": {}, + "source": [ + "## Custom Basemap" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56", + "metadata": {}, + "outputs": [], + "source": [ + "import leafmap.maplibregl as leafmap\n", + "from maplibre.basemaps import construct_basemap_style\n", + "from maplibre import Layer, LayerType, Map, MapOptions\n", + "from maplibre.sources import GeoJSONSource\n", + "\n", + "\n", + "bg_layer = Layer(\n", + " type=LayerType.BACKGROUND,\n", + " id=\"background\",\n", + " source=None,\n", + " paint={\"background-color\": \"darkblue\", \"background-opacity\": 0.8},\n", + ")\n", + "\n", + "countries_source = GeoJSONSource(\n", + " data=\"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_110m_admin_0_countries.geojson\"\n", + ")\n", + "\n", + "lines_layer = Layer(\n", + " type=LayerType.LINE,\n", + " source=\"countries\",\n", + " paint={\"line-color\": \"white\", \"line-width\": 1.5},\n", + ")\n", + "\n", + "polygons_layer = Layer(\n", + " type=LayerType.FILL,\n", + " source=\"countries\",\n", + " paint={\"fill-color\": \"darkred\", \"fill-opacity\": 0.8},\n", + ")\n", + "\n", + "custom_basemap = construct_basemap_style(\n", + " layers=[bg_layer, polygons_layer, lines_layer],\n", + " sources={\"countries\": countries_source},\n", + ")\n", + "\n", + "\n", + "m = leafmap.Map(style=custom_basemap)\n", + "data = \"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n", + "m.add_geojson(\n", + " data,\n", + " layer_type=\"circle\",\n", + " name=\"earthquakes\",\n", + " paint={\"circle-color\": \"yellow\", \"circle-radius\": 5},\n", + ")\n", + "m.add_popup(\"earthquakes\", \"mag\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "57", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/Bn9Kwje.png)" + ] + }, + { + "cell_type": "markdown", + "id": "58", + "metadata": {}, + "source": [ + "## H3 Grid UK Road Safety" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import h3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60", + "metadata": {}, + "outputs": [], + "source": [ + "RESOLUTION = 7\n", + "COLORS = (\n", + " \"lightblue\",\n", + " \"turquoise\",\n", + " \"lightgreen\",\n", + " \"yellow\",\n", + " \"orange\",\n", + " \"darkred\",\n", + ")\n", + "\n", + "road_safety = pd.read_csv(\n", + " \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv\"\n", + ").dropna()\n", + "\n", + "\n", + "def create_h3_grid(res=RESOLUTION) -> dict:\n", + " road_safety[\"h3\"] = road_safety.apply(\n", + " lambda x: h3.geo_to_h3(x[\"lat\"], x[\"lng\"], resolution=res), axis=1\n", + " )\n", + " df = road_safety.groupby(\"h3\").h3.agg(\"count\").to_frame(\"count\").reset_index()\n", + " df[\"hexagon\"] = df.apply(\n", + " lambda x: [h3.h3_to_geo_boundary(x[\"h3\"], geo_json=True)], axis=1\n", + " )\n", + " df[\"color\"] = pd.cut(\n", + " df[\"count\"],\n", + " bins=len(COLORS),\n", + " labels=COLORS,\n", + " )\n", + " return leafmap.pandas_to_geojson(\n", + " df, \"hexagon\", geometry_type=\"Polygon\", properties=[\"count\", \"color\"]\n", + " )\n", + "\n", + "\n", + "m = leafmap.Map(\n", + " center=(-1.415727, 52.232395),\n", + " zoom=7,\n", + " pitch=40,\n", + " bearing=-27,\n", + ")\n", + "data = create_h3_grid()\n", + "m.add_geojson(\n", + " data,\n", + " layer_type=\"fill-extrusion\",\n", + " paint={\n", + " \"fill-extrusion-color\": [\"get\", \"color\"],\n", + " \"fill-extrusion-opacity\": 0.7,\n", + " \"fill-extrusion-height\": [\"*\", 100, [\"get\", \"count\"]],\n", + " },\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "61", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/DYWmj5y.png)" + ] + }, + { + "cell_type": "markdown", + "id": "62", + "metadata": {}, + "source": [ + "## Deck.GL Layer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(\n", + " style=\"positron\",\n", + " center=(-122.4, 37.74),\n", + " zoom=12,\n", + " pitch=40,\n", + ")\n", + "deck_grid_layer = {\n", + " \"@@type\": \"GridLayer\",\n", + " \"id\": \"GridLayer\",\n", + " \"data\": \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json\",\n", + " \"extruded\": True,\n", + " \"getPosition\": \"@@=COORDINATES\",\n", + " \"getColorWeight\": \"@@=SPACES\",\n", + " \"getElevationWeight\": \"@@=SPACES\",\n", + " \"elevationScale\": 4,\n", + " \"cellSize\": 200,\n", + " \"pickable\": True,\n", + "}\n", + "\n", + "m.add_deck_layers([deck_grid_layer], tooltip=\"Number of points: {{ count }}\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "64", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/xBVdT2u.png)" + ] + }, + { + "cell_type": "markdown", + "id": "65", + "metadata": {}, + "source": [ + "## Multiple Deck.GL Layers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66", + "metadata": {}, + "outputs": [], + "source": [ + "import requests" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67", + "metadata": {}, + "outputs": [], + "source": [ + "data = requests.get(\n", + " \"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson\"\n", + ").json()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(\n", + " style=\"positron\",\n", + " center=(0.45, 51.47),\n", + " zoom=4,\n", + " pitch=30,\n", + ")\n", + "deck_geojson_layer = {\n", + " \"@@type\": \"GeoJsonLayer\",\n", + " \"id\": \"airports\",\n", + " \"data\": data,\n", + " \"filled\": True,\n", + " \"pointRadiusMinPixels\": 2,\n", + " \"pointRadiusScale\": 2000,\n", + " \"getPointRadius\": \"@@=11 - properties.scalerank\",\n", + " \"getFillColor\": [200, 0, 80, 180],\n", + " \"autoHighlight\": True,\n", + " \"pickable\": True,\n", + "}\n", + "\n", + "deck_arc_layer = {\n", + " \"@@type\": \"ArcLayer\",\n", + " \"id\": \"arcs\",\n", + " \"data\": [\n", + " feature\n", + " for feature in data[\"features\"]\n", + " if feature[\"properties\"][\"scalerank\"] < 4\n", + " ],\n", + " \"getSourcePosition\": [-0.4531566, 51.4709959], # London\n", + " \"getTargetPosition\": \"@@=geometry.coordinates\",\n", + " \"getSourceColor\": [0, 128, 200],\n", + " \"getTargetColor\": [200, 0, 80],\n", + " \"getWidth\": 2,\n", + " \"pickable\": True,\n", + "}\n", + "\n", + "m.add_deck_layers(\n", + " [deck_geojson_layer, deck_arc_layer],\n", + " tooltip={\n", + " \"airports\": \"{{ &properties.name }}\",\n", + " \"arcs\": \"gps_code: {{ properties.gps_code }}\",\n", + " },\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "69", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/eFc4IbZ.png)" + ] + } + ], + "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.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/book/geospatial/raster_viz.ipynb b/_sources/book/geospatial/raster_viz.ipynb new file mode 100644 index 0000000..ad67bc8 --- /dev/null +++ b/_sources/book/geospatial/raster_viz.ipynb @@ -0,0 +1,475 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# Raster Data Visualization\n", + "\n", + "This notebook demonstrates how to visualize raster data using [leafmap](https://leafmap.org/). Leafmap can visualize raster data (e.g., Cloud Optimized GeoTIFF) stored in a local file or on the cloud (e.g., AWS S3). It can also visualize raster data stored in a [STAC](https://stacspec.org/) catalog.\n", + "\n", + "## Installation\n", + "\n", + "Uncomment the following line to install the required packages if needed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install \"leafmap[raster]\"" + ] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "## Import packages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3", + "metadata": {}, + "outputs": [], + "source": [ + "import leafmap" + ] + }, + { + "cell_type": "markdown", + "id": "4", + "metadata": {}, + "source": [ + "## COG\n", + "\n", + "A Cloud Optimized GeoTIFF (COG) is a regular GeoTIFF file, aimed at being hosted on a HTTP file server, with an internal organization that enables more efficient workflows on the cloud. It does this by leveraging the ability of clients issuing HTTP GET range requests to ask for just the parts of a file they need. More information about COG can be found at \n", + "\n", + "For this demo, we will use data from https://www.maxar.com/open-data/california-colorado-fires for mapping California and Colorado fires. Let's create an interactive map and add the COG to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.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": "markdown", + "id": "6", + "metadata": {}, + "source": [ + "You can add multiple COGs to the map. Let's add another COG to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7", + "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)\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "8", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/J9fLbYh.png)" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "Create a split map for comparing two COGs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.split_map(left_layer=url, right_layer=url2)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/FJa0Yta.png)" + ] + }, + { + "cell_type": "markdown", + "id": "12", + "metadata": {}, + "source": [ + "## Local Raster\n", + "\n", + "Leafmap can also visualize local GeoTIFF files. Let's download some sample data " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13", + "metadata": {}, + "outputs": [], + "source": [ + "dem_url = \"https://open.gishub.org/data/raster/srtm90.tif\"\n", + "leafmap.download_file(dem_url, unzip=False)" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, + "source": [ + "Visualize a single-band raster." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_raster(\"srtm90.tif\", cmap=\"terrain\", layer_name=\"DEM\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/7g9huvY.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17", + "metadata": {}, + "outputs": [], + "source": [ + "landsat_url = \"https://open.gishub.org/data/raster/cog.tif\"\n", + "leafmap.download_file(landsat_url)" + ] + }, + { + "cell_type": "markdown", + "id": "18", + "metadata": {}, + "source": [ + "Visualize a multi-band raster." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_raster(\"cog.tif\", bands=[4, 3, 2], layer_name=\"Landsat\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "20", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/euhkajs.png)" + ] + }, + { + "cell_type": "markdown", + "id": "21", + "metadata": {}, + "source": [ + "## STAC\n", + "\n", + "The SpatioTemporal Asset Catalog (STAC) specification provides a common language to describe a range of geospatial information so that it can more easily be indexed and discovered. A SpatioTemporal Asset is any file that represents information about the earth captured in a certain space and time. STAC aims to enable that next generation of geospatial search engines, while also supporting web best practices so geospatial information is more easily surfaced in traditional search engines. More information about STAC can be found at the [STAC website](https://stacspec.org). In this example, we will use a STAC item from the [SPOT Orthoimages of Canada](https://stacindex.org/catalogs/spot-orthoimages-canada-2005) available through the link below:" + ] + }, + { + "cell_type": "markdown", + "id": "22", + "metadata": {}, + "source": [ + "Create an interactive map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json\"\n", + "leafmap.stac_bands(url)" + ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "Add STAC layers to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.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": "26", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/IlqsJXK.png)" + ] + }, + { + "cell_type": "markdown", + "id": "27", + "metadata": {}, + "source": [ + "## Custom STAC Catalog" + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "Provide custom STAC API endpoints as a dictionary in the format of `{\"name\": \"url\"}`. The name will show up in the dropdown menu, while the url is the STAC API endpoint that will be used to search for items." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "catalogs = {\n", + " \"Element84 Earth Search\": \"https://earth-search.aws.element84.com/v1\",\n", + " \"Microsoft Planetary Computer\": \"https://planetarycomputer.microsoft.com/api/stac/v1\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40, -100], zoom=4)\n", + "m.set_catalog_source(catalogs)\n", + "m.add_stac_gui()\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "31", + "metadata": {}, + "source": [ + "Once the catalog panel is open, you can search for items from the custom STAC API endpoints. Simply draw a bounding box on the map or zoom to a location of interest. Click on the **Collections** button to retrieve the collections from the custom STAC API endpoints. Next, select a collection from the dropdown menu. Then, click on the **Items** button to retrieve the items from the selected collection. Finally, click on the **Display** button to add the selected item to the map." + ] + }, + { + "cell_type": "markdown", + "id": "32", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/M8IbRsM.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [ + "m.stac_gdf # The GeoDataFrame of the STAC search results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34", + "metadata": {}, + "outputs": [], + "source": [ + "m.stac_dict # The STAC search results as a dictionary" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", + "metadata": {}, + "outputs": [], + "source": [ + "m.stac_item # The selected STAC item of the search result" + ] + }, + { + "cell_type": "markdown", + "id": "36", + "metadata": {}, + "source": [ + "## AWS S3" + ] + }, + { + "cell_type": "markdown", + "id": "37", + "metadata": {}, + "source": [ + "To Be able to run this notebook you'll need to have AWS credential available as environment variables. Uncomment the following lines to set the environment variables." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38", + "metadata": {}, + "outputs": [], + "source": [ + "# os.environ[\"AWS_ACCESS_KEY_ID\"] = \"YOUR AWS ACCESS ID HERE\"\n", + "# os.environ[\"AWS_SECRET_ACCESS_KEY\"] = \"YOUR AWS ACCESS KEY HERE\"" + ] + }, + { + "cell_type": "markdown", + "id": "39", + "metadata": {}, + "source": [ + "In this example, we will use datasets from the [Maxar Open Data Program on AWS](https://registry.opendata.aws/maxar-open-data/)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40", + "metadata": {}, + "outputs": [], + "source": [ + "BUCKET = \"maxar-opendata\"\n", + "FOLDER = \"events/Kahramanmaras-turkey-earthquake-23/\"" + ] + }, + { + "cell_type": "markdown", + "id": "41", + "metadata": {}, + "source": [ + "List all the datasets in the bucket. Specify a file extension to filter the results if needed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42", + "metadata": {}, + "outputs": [], + "source": [ + "items = leafmap.s3_list_objects(BUCKET, FOLDER, ext=\".tif\")\n", + "items[:10]" + ] + }, + { + "cell_type": "markdown", + "id": "43", + "metadata": {}, + "source": [ + "Visualize raster datasets from the bucket." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_cog_layer(items[2], name=\"Maxar\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "45", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/NkTZ6Lj.png)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "geo", + "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/_sources/book/geospatial/samgeo.ipynb b/_sources/book/geospatial/samgeo.ipynb new file mode 100644 index 0000000..eafb264 --- /dev/null +++ b/_sources/book/geospatial/samgeo.ipynb @@ -0,0 +1,1112 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# SAMGeo\n", + "\n", + "## Install dependencies\n", + "\n", + "Uncomment and run the following cell to install the required dependencies." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install segment-geospatial groundingdino-py leafmap localtileserver" + ] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import leafmap\n", + "from samgeo import SamGeo\n", + "from samgeo.text_sam import LangSAM" + ] + }, + { + "cell_type": "markdown", + "id": "4", + "metadata": {}, + "source": [ + "## Download sample data\n", + "\n", + "### Create an interactive map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40.427495, -86.913638], zoom=18, height=700)\n", + "m.add_basemap(\"SATELLITE\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "6", + "metadata": {}, + "source": [ + "Pan and zoom the map to select the area of interest. Use the draw tools to draw a polygon or rectangle on the map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "if m.user_roi_bounds() is not None:\n", + " bbox = m.user_roi_bounds()\n", + "else:\n", + " bbox = [-86.9167, 40.4262, -86.9105, 40.4289]" + ] + }, + { + "cell_type": "markdown", + "id": "8", + "metadata": {}, + "source": [ + "### Download map tiles\n", + "\n", + "Download maps tiles and mosaic them into a single GeoTIFF file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "image = \"image.tif\"" + ] + }, + { + "cell_type": "markdown", + "id": "10", + "metadata": {}, + "source": [ + "Specify the basemap as the source." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "leafmap.map_tiles_to_geotiff(\n", + " output=image, bbox=bbox, zoom=18, source=\"Satellite\", overwrite=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "12", + "metadata": {}, + "source": [ + "You can also use your own image. Uncomment and run the following cell to use your own image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13", + "metadata": {}, + "outputs": [], + "source": [ + "# image = '/path/to/your/own/image.tif'" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, + "source": [ + "Display the downloaded image on the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m.layers[-1].visible = False # turn off the basemap\n", + "m.add_raster(image, layer_name=\"Image\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/YHwrpS2.png)" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "## Automatic mask generation\n", + "\n", + "### Initialize SAM class" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam = SamGeo(\n", + " model_type=\"vit_h\",\n", + " sam_kwargs=None,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "### Automatic mask generation\n", + "\n", + "Segment the image and save the results to a GeoTIFF file. Set `unique=True` to assign a unique ID to each object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.generate(image, output=\"masks.tif\", foreground=True, unique=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.show_masks(cmap=\"binary_r\")" + ] + }, + { + "cell_type": "markdown", + "id": "22", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/kWqLVuL.png)" + ] + }, + { + "cell_type": "markdown", + "id": "23", + "metadata": {}, + "source": [ + "Show the object annotations (objects with random color) on the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.show_anns(axis=\"off\", alpha=1, output=\"annotations.tif\")" + ] + }, + { + "cell_type": "markdown", + "id": "25", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/J6Ie0Zj.png)" + ] + }, + { + "cell_type": "markdown", + "id": "26", + "metadata": {}, + "source": [ + "Compare images with a slider." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "leafmap.image_comparison(\n", + " \"image.tif\",\n", + " \"annotations.tif\",\n", + " label1=\"Satellite Image\",\n", + " label2=\"Image Segmentation\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/cm4QyaR.png)" + ] + }, + { + "cell_type": "markdown", + "id": "29", + "metadata": {}, + "source": [ + "Add image to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m.add_raster(\"annotations.tif\", opacity=0.5, layer_name=\"Masks\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "31", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/Y6EaGVN.png)" + ] + }, + { + "cell_type": "markdown", + "id": "32", + "metadata": {}, + "source": [ + "Convert the object annotations to vector format, such as GeoPackage, Shapefile, or GeoJSON." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.raster_to_vector(\"masks.tif\", \"masks.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m.add_vector(\"masks.shp\", layer_name=\"Masks vector\")" + ] + }, + { + "cell_type": "markdown", + "id": "35", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/N0xVt9S.png)" + ] + }, + { + "cell_type": "markdown", + "id": "36", + "metadata": {}, + "source": [ + "### Automatic mask generation options\n", + "\n", + "There are several tunable parameters in automatic mask generation that control how densely points are sampled and what the thresholds are for removing low quality or duplicate masks. Additionally, generation can be automatically run on crops of the image to get improved performance on smaller objects, and post-processing can remove stray pixels and holes. Here is an example configuration that samples more masks:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam_kwargs = {\n", + " \"points_per_side\": 32,\n", + " \"pred_iou_thresh\": 0.86,\n", + " \"stability_score_thresh\": 0.92,\n", + " \"crop_n_layers\": 1,\n", + " \"crop_n_points_downscale_factor\": 2,\n", + " \"min_mask_region_area\": 100,\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam = SamGeo(\n", + " model_type=\"vit_h\",\n", + " sam_kwargs=sam_kwargs,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.generate(image, output=\"masks2.tif\", foreground=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.show_masks(cmap=\"binary_r\")" + ] + }, + { + "cell_type": "markdown", + "id": "41", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/S2LYen8.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.show_anns(axis=\"off\", opacity=1, output=\"annotations2.tif\")" + ] + }, + { + "cell_type": "markdown", + "id": "43", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/opEKsUu.png)" + ] + }, + { + "cell_type": "markdown", + "id": "44", + "metadata": {}, + "source": [ + "Compare images with a slider." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "leafmap.image_comparison(\n", + " image,\n", + " \"annotations.tif\",\n", + " label1=\"Image\",\n", + " label2=\"Image Segmentation\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "46", + "metadata": {}, + "source": [ + "## Use points as input prompts\n", + "\n", + "### Initialize SAM class" + ] + }, + { + "cell_type": "markdown", + "id": "47", + "metadata": {}, + "source": [ + "Set `automatic=False` to disable the `SamAutomaticMaskGenerator` and enable the `SamPredictor`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40.427495, -86.913638], zoom=18, height=700)\n", + "image = \"image.tif\"\n", + "m.add_raster(image, layer_name=\"Image\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam = SamGeo(\n", + " model_type=\"vit_h\",\n", + " automatic=False,\n", + " sam_kwargs=None,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "50", + "metadata": {}, + "source": [ + "Specify the image to segment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.set_image(image)" + ] + }, + { + "cell_type": "markdown", + "id": "52", + "metadata": {}, + "source": [ + "### Image segmentation with input points\n", + "\n", + "A single point can be used to segment an object. The point can be specified as a tuple of (x, y), such as (col, row) or (lon, lat). The points can also be specified as a file path to a vector dataset. For non (col, row) input points, specify the `point_crs` parameter, which will automatically transform the points to the image column and row coordinates.\n", + "\n", + "Try a single point input:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "point_coords = [[-86.913162, 40.427157]]\n", + "sam.predict(point_coords, point_labels=1, point_crs=\"EPSG:4326\", output=\"mask1.tif\")\n", + "m.add_raster(\"mask1.tif\", layer_name=\"Mask1\", nodata=0, cmap=\"Blues\", opacity=1)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "54", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/zUMLUsn.png)" + ] + }, + { + "cell_type": "markdown", + "id": "55", + "metadata": {}, + "source": [ + "Try multiple points input:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "point_coords = [\n", + " [-86.913162, 40.427157],\n", + " [-86.913425, 40.427157],\n", + " [-86.91343, 40.427721],\n", + " [-86.913012, 40.427741],\n", + "]\n", + "sam.predict(point_coords, point_labels=1, point_crs=\"EPSG:4326\", output=\"mask2.tif\")\n", + "m.add_raster(\"mask2.tif\", layer_name=\"Mask2\", nodata=0, cmap=\"Greens\", opacity=1)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "57", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/zUMLUsn.png)" + ] + }, + { + "cell_type": "markdown", + "id": "58", + "metadata": {}, + "source": [ + "### Interactive segmentation\n", + "\n", + "Display the interactive map and use the marker tool to draw points on the map. Then click on the `Segment` button to segment the objects. The results will be added to the map automatically. Click on the `Reset` button to clear the points and the results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m = sam.show_map()\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "60", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/3W7JGqP.png)" + ] + }, + { + "cell_type": "markdown", + "id": "61", + "metadata": {}, + "source": [ + "## Bounding box input prompts" + ] + }, + { + "cell_type": "markdown", + "id": "62", + "metadata": {}, + "source": [ + "### Create an interactive map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40.427495, -86.913638], zoom=18, height=700)\n", + "image = \"image.tif\"\n", + "m.add_raster(image, layer_name=\"Image\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam = SamGeo(\n", + " model_type=\"vit_h\",\n", + " automatic=False,\n", + " sam_kwargs=None,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "65", + "metadata": {}, + "source": [ + "Specify the image to segment. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.set_image(image)" + ] + }, + { + "cell_type": "markdown", + "id": "67", + "metadata": {}, + "source": [ + "### Create bounding boxes\n", + "\n", + "If no rectangles are drawn, the default bounding boxes will be used as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "if m.user_rois is not None:\n", + " boxes = m.user_rois\n", + "else:\n", + " boxes = [\n", + " [-86.913654, 40.426967, -86.912774, 40.427881],\n", + " [-86.914780, 40.426256, -86.913997, 40.426852],\n", + " [-86.913632, 40.426215, -86.912581, 40.426820],\n", + " ]" + ] + }, + { + "cell_type": "markdown", + "id": "69", + "metadata": {}, + "source": [ + "## Segment the image\n", + "\n", + "Use the `predict()` method to segment the image with specified bounding boxes. The `boxes` parameter accepts a list of bounding box coordinates in the format of [[left, bottom, right, top], [left, bottom, right, top], ...], a GeoJSON dictionary, or a file path to a GeoJSON file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.predict(boxes=boxes, point_crs=\"EPSG:4326\", output=\"mask.tif\", dtype=\"uint8\")" + ] + }, + { + "cell_type": "markdown", + "id": "71", + "metadata": {}, + "source": [ + "## Display the result\n", + "\n", + "Add the segmented image to the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m.add_raster(\"mask.tif\", cmap=\"viridis\", nodata=0, opacity=0.6, layer_name=\"Mask\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "73", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/9y31xUH.png)" + ] + }, + { + "cell_type": "markdown", + "id": "74", + "metadata": {}, + "source": [ + "## Text promots\n", + "\n", + "### Initialize LangSAM class\n", + "\n", + "The initialization of the LangSAM class might take a few minutes. The initialization downloads the model weights and sets up the model for inference." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40.427495, -86.913638], zoom=18, height=700)\n", + "image = \"image.tif\"\n", + "m.add_raster(image, layer_name=\"Image\")\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam = LangSAM()" + ] + }, + { + "cell_type": "markdown", + "id": "77", + "metadata": {}, + "source": [ + "### Specify text prompts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "text_prompt = \"tree\"" + ] + }, + { + "cell_type": "markdown", + "id": "79", + "metadata": {}, + "source": [ + "### Segment the image\n", + "\n", + "Part of the model prediction includes setting appropriate thresholds for object detection and text association with the detected objects. These threshold values range from 0 to 1 and are set while calling the predict method of the LangSAM class.\n", + "\n", + "`box_threshold`: This value is used for object detection in the image. A higher value makes the model more selective, identifying only the most confident object instances, leading to fewer overall detections. A lower value, conversely, makes the model more tolerant, leading to increased detections, including potentially less confident ones.\n", + "\n", + "`text_threshold`: This value is used to associate the detected objects with the provided text prompt. A higher value requires a stronger association between the object and the text prompt, leading to more precise but potentially fewer associations. A lower value allows for looser associations, which could increase the number of associations but also introduce less precise matches.\n", + "\n", + "Remember to test different threshold values on your specific data. The optimal threshold can vary depending on the quality and nature of your images, as well as the specificity of your text prompts. Make sure to choose a balance that suits your requirements, whether that's precision or recall." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.predict(image, text_prompt, box_threshold=0.24, text_threshold=0.24)" + ] + }, + { + "cell_type": "markdown", + "id": "81", + "metadata": {}, + "source": [ + "### Visualize the results\n", + "\n", + "Show the result with bounding boxes on the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.show_anns(\n", + " cmap=\"Greens\",\n", + " box_color=\"red\",\n", + " title=\"Automatic Segmentation of Trees\",\n", + " blend=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "83", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/qRcy16Z.png)" + ] + }, + { + "cell_type": "markdown", + "id": "84", + "metadata": {}, + "source": [ + "Show the result without bounding boxes on the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.show_anns(\n", + " cmap=\"Greens\",\n", + " add_boxes=False,\n", + " alpha=0.5,\n", + " title=\"Automatic Segmentation of Trees\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "86", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/TvqGByH.png)" + ] + }, + { + "cell_type": "markdown", + "id": "87", + "metadata": {}, + "source": [ + "Show the result as a grayscale image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.show_anns(\n", + " cmap=\"Greys_r\",\n", + " add_boxes=False,\n", + " alpha=1,\n", + " title=\"Automatic Segmentation of Trees\",\n", + " blend=False,\n", + " output=\"trees.tif\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "89", + "metadata": {}, + "source": [ + "Convert the result to a vector format." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.raster_to_vector(\"trees.tif\", \"trees.shp\")" + ] + }, + { + "cell_type": "markdown", + "id": "91", + "metadata": {}, + "source": [ + "Show the results on the interactive map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "m.add_raster(\"trees.tif\", layer_name=\"Trees\", palette=\"Greens\", opacity=0.5, nodata=0)\n", + "style = {\n", + " \"color\": \"#3388ff\",\n", + " \"weight\": 2,\n", + " \"fillColor\": \"#7c4185\",\n", + " \"fillOpacity\": 0.5,\n", + "}\n", + "m.add_vector(\"trees.shp\", layer_name=\"Vector\", style=style)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "93", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/WDQgECD.png)" + ] + }, + { + "cell_type": "markdown", + "id": "94", + "metadata": {}, + "source": [ + "### Interactive segmentation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "sam.show_map()" + ] + }, + { + "cell_type": "markdown", + "id": "96", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/Zn7Dwty.png)" + ] + } + ], + "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.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/book/geospatial/vector_viz.ipynb b/_sources/book/geospatial/vector_viz.ipynb new file mode 100644 index 0000000..116c6cb --- /dev/null +++ b/_sources/book/geospatial/vector_viz.ipynb @@ -0,0 +1,381 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# Vector Data Visualization\n", + "\n", + "## Installation\n", + "\n", + "Uncomment the following line to install [leafmap](https://leafmap.org) if needed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install \"leafmap[vector]\"" + ] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3", + "metadata": {}, + "outputs": [], + "source": [ + "import leafmap" + ] + }, + { + "cell_type": "markdown", + "id": "4", + "metadata": {}, + "source": [ + "## Visualize vector data\n", + "\n", + "You can visualize vector data using the `add_vector` function. It supports common vector data formats, including GeoJSON, Shapefile, GeoPackage, and any other formats supported by [geopandas](https://geopandas.org)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[0, 0], zoom=2)\n", + "data = \"https://open.gishub.org/data/vector/cables.geojson\"\n", + "m.add_vector(data, layer_name=\"Cable lines\", info_mode=\"on_hover\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "6", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/NIcnLWs.png)" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "You can style the vector with custom style callback functions. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[20, 0], zoom=2)\n", + "m.add_basemap(\"CartoDB.DarkMatter\")\n", + "data = \"https://open.gishub.org/data/vector/cables.geojson\"\n", + "callback = lambda feat: {\"color\": feat[\"properties\"][\"color\"], \"weight\": 1}\n", + "m.add_vector(data, layer_name=\"Cable lines\", style_callback=callback)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/mQnV53U.png)" + ] + }, + { + "cell_type": "markdown", + "id": "10", + "metadata": {}, + "source": [ + "## Choropleth map\n", + "\n", + "You can create a choropleth map using the `add_data` function. It supports GeoJSON, Shapefile, GeoPackage, and any other formats supported by [geopandas](https://geopandas.org). \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "data = \"https://raw.githubusercontent.com/opengeos/leafmap/master/docs/data/countries.geojson\"\n", + "m.add_data(\n", + " data, column=\"POP_EST\", scheme=\"Quantiles\", cmap=\"Blues\", legend_title=\"Population\"\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "12", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/4FV6f72.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_data(\n", + " data,\n", + " column=\"POP_EST\",\n", + " scheme=\"EqualInterval\",\n", + " cmap=\"Blues\",\n", + " legend_title=\"Population\",\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/KEY6zEj.png)" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "## GeoParquet\n", + "\n", + "Visualize GeoParquet data with leafmap and lonboard." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://open.gishub.org/data/duckdb/cities.parquet\"\n", + "gdf = leafmap.read_parquet(url, return_type=\"gdf\", src_crs=\"EPSG:4326\")\n", + "gdf.head()" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "Visualize point data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": {}, + "outputs": [], + "source": [ + "leafmap.view_vector(\n", + " gdf,\n", + " get_radius=20000,\n", + " get_fill_color=\"blue\",\n", + " zoom_to_layer=False,\n", + " map_args={\"center\": (40, -100), \"zoom\": 3, \"height\": 500},\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/BBsLjvx.png)" + ] + }, + { + "cell_type": "markdown", + "id": "20", + "metadata": {}, + "source": [ + "Visualizing polygon data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://data.source.coop/giswqs/nwi/wetlands/DC_Wetlands.parquet\"\n", + "gdf = leafmap.read_parquet(\n", + " url, return_type=\"gdf\", src_crs=\"EPSG:5070\", dst_crs=\"EPSG:4326\"\n", + ")\n", + "gdf.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22", + "metadata": {}, + "outputs": [], + "source": [ + "leafmap.view_vector(gdf, get_fill_color=[0, 0, 255, 128])" + ] + }, + { + "cell_type": "markdown", + "id": "23", + "metadata": {}, + "source": [ + "![vector](https://i.imgur.com/HRtpiVd.png)" + ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "![legend](https://i.imgur.com/fxzHHFN.png)\n", + "\n", + "## PMTiles\n", + "\n", + "[PMTiles](https://github.com/protomaps/PMTiles) is a single-file archive format for tiled data. A PMTiles archive can be hosted on a commodity storage platform such as S3, and enables low-cost, zero-maintenance map applications that are \"serverless\" - free of a custom tile backend or third party provider." + ] + }, + { + "cell_type": "markdown", + "id": "25", + "metadata": {}, + "source": [ + "## Remote PMTiles\n", + "\n", + "Leafmap can visualize PMTiles hosted locally or remotely." + ] + }, + { + "cell_type": "markdown", + "id": "26", + "metadata": {}, + "source": [ + "### Source Cooperative\n", + "\n", + "Visualize the [Google-Microsoft Open Buildings data](https://beta.source.coop/repositories/vida/google-microsoft-open-buildings/description) hosted on Source Cooperative.\n", + "\n", + "Check the metadata of the PMTiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://data.source.coop/vida/google-microsoft-open-buildings/pmtiles/go_ms_building_footprints.pmtiles\"\n", + "metadata = leafmap.pmtiles_metadata(url)\n", + "print(f\"layer names: {metadata['layer_names']}\")\n", + "print(f\"bounds: {metadata['bounds']}\")" + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "Visualize the PMTiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[20, 0], zoom=2)\n", + "m.add_basemap(\"CartoDB.DarkMatter\")\n", + "m.add_basemap(\"Esri.WorldImagery\", show=False)\n", + "\n", + "style = {\n", + " \"version\": 8,\n", + " \"sources\": {\n", + " \"example_source\": {\n", + " \"type\": \"vector\",\n", + " \"url\": \"pmtiles://\" + url,\n", + " \"attribution\": \"PMTiles\",\n", + " }\n", + " },\n", + " \"layers\": [\n", + " {\n", + " \"id\": \"buildings\",\n", + " \"source\": \"example_source\",\n", + " \"source-layer\": \"building_footprints\",\n", + " \"type\": \"fill\",\n", + " \"paint\": {\"fill-color\": \"#3388ff\", \"fill-opacity\": 0.5},\n", + " },\n", + " ],\n", + "}\n", + "\n", + "m.add_pmtiles(\n", + " url, name=\"Buildings\", style=style, overlay=True, show=True, zoom_to_layer=False\n", + ")\n", + "\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/kT6ng6k.png)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "geo", + "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/_sources/book/geospatial/whitebox.ipynb b/_sources/book/geospatial/whitebox.ipynb new file mode 100644 index 0000000..87c6984 --- /dev/null +++ b/_sources/book/geospatial/whitebox.ipynb @@ -0,0 +1,922 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# WhiteboxTools" + ] + }, + { + "cell_type": "markdown", + "id": "1", + "metadata": {}, + "source": [ + "## Installation\n", + "\n", + "Uncomment and run the following cell to install necessary packages for this notebook, including leafmap, geopandas, localtileserver, rio-cogeo, pynhd, py3dep." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install \"leafmap[raster]\" geopandas" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "## Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import leafmap" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "## Create interactive maps\n", + "\n", + "Specify the map center, zoom level, and height." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40, -100], zoom=4, height=\"600px\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "## Add basemaps\n", + "\n", + "Add OpenTopoMap, USGS 3DEP Elevation, and USGS Hydrography basemaps." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_basemap(\"OpenTopoMap\")\n", + "m.add_basemap(\"USGS 3DEP Elevation\")\n", + "m.add_basemap(\"USGS Hydrography\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "Add NLCD land cover map and legend." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"HYBRID\")\n", + "m.add_basemap(\"NLCD 2019 CONUS Land Cover\")\n", + "m.add_legend(builtin_legend=\"NLCD\", title=\"NLCD Land Cover Type\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "Add WMS layers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(center=[40, -100], zoom=4)\n", + "m.add_basemap(\"Esri.WorldImagery\")\n", + "url = \"https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2019_Land_Cover_L48/wms?\"\n", + "m.add_wms_layer(\n", + " url,\n", + " layers=\"NLCD_2019_Land_Cover_L48\",\n", + " name=\"NLCD 2019 CONUS Land Cover\",\n", + " format=\"image/png\",\n", + " transparent=True,\n", + ")\n", + "m.add_legend(builtin_legend=\"NLCD\", title=\"NLCD Land Cover Type\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "## Get watershed data\n", + "\n", + "Let's download watershed data for the Calapooia River basin in Oregon." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "gdf = leafmap.get_nhd_basins(feature_ids=23763529, fsource=\"comid\", simplified=False)" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "Plot the watershed boundary on the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_gdf(gdf, layer_name=\"Catchment\", info_mode=None)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "Save the watershed boundary to a GeoJSON or shapefile." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": {}, + "outputs": [], + "source": [ + "gdf.to_file(\"basin.geojson\", driver=\"GeoJSON\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19", + "metadata": {}, + "outputs": [], + "source": [ + "gdf.to_file(\"basin.shp\")" + ] + }, + { + "cell_type": "markdown", + "id": "20", + "metadata": {}, + "source": [ + "## Download DEM\n", + "\n", + "Download a digital elevation model (DEM) for the watershed from the USGS 3DEP Elevation service. Convert the DEM to a Cloud Optimized GeoTIFF (COG)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21", + "metadata": {}, + "outputs": [], + "source": [ + "leafmap.get_3dep_dem(\n", + " gdf, resolution=30, output=\"dem.tif\", dst_crs=\"EPSG:3857\", to_cog=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "22", + "metadata": {}, + "source": [ + "Display the DEM on the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_raster(\"dem.tif\", palette=\"terrain\", layer_name=\"DEM\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "## Get DEM metadata" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "metadata = leafmap.image_metadata(\"dem.tif\")\n", + "metadata" + ] + }, + { + "cell_type": "markdown", + "id": "26", + "metadata": {}, + "source": [ + "Get a summary statistics of the DEM." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27", + "metadata": {}, + "outputs": [], + "source": [ + "metadata[\"bands\"]" + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "## Add colorbar" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_colormap(cmap=\"terrain\", vmin=\"60\", vmax=1500, label=\"Elevation (m)\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "## Initialize WhiteboxTools\n", + "\n", + "Initialize the WhiteboxTools class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31", + "metadata": {}, + "outputs": [], + "source": [ + "wbt = leafmap.WhiteboxTools()" + ] + }, + { + "cell_type": "markdown", + "id": "32", + "metadata": {}, + "source": [ + "Check the WhiteboxTools version." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.version()" + ] + }, + { + "cell_type": "markdown", + "id": "34", + "metadata": {}, + "source": [ + "Display the WhiteboxTools interface." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", + "metadata": {}, + "outputs": [], + "source": [ + "leafmap.whiteboxgui()" + ] + }, + { + "cell_type": "markdown", + "id": "36", + "metadata": {}, + "source": [ + "## Set working directory" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.set_working_dir(os.getcwd())\n", + "wbt.verbose = False" + ] + }, + { + "cell_type": "markdown", + "id": "38", + "metadata": {}, + "source": [ + "## Smooth DEM\n", + "\n", + "All WhiteboxTools functions will return 0 if they are successful, and 1 if they are not." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.feature_preserving_smoothing(\"dem.tif\", \"smoothed.tif\", filter=9)" + ] + }, + { + "cell_type": "markdown", + "id": "40", + "metadata": {}, + "source": [ + "Display the smoothed DEM and watershed boundary on the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41", + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map()\n", + "m.add_raster(\"smoothed.tif\", palette=\"terrain\", layer_name=\"Smoothed DEM\")\n", + "m.add_geojson(\"basin.geojson\", layer_name=\"Watershed\", info_mode=None)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "42", + "metadata": {}, + "source": [ + "## Create hillshade" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.hillshade(\"smoothed.tif\", \"hillshade.tif\", azimuth=315, altitude=35)" + ] + }, + { + "cell_type": "markdown", + "id": "44", + "metadata": {}, + "source": [ + "Overlay the hillshade on the smoothed DEM with transparency." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_raster(\"hillshade.tif\", layer_name=\"Hillshade\")\n", + "m.layers[-1].opacity = 0.6" + ] + }, + { + "cell_type": "markdown", + "id": "46", + "metadata": {}, + "source": [ + "## Find no-flow cells\n", + "\n", + "Find cells with undefined flow, i.e. no valid flow direction, based on the D8 flow direction algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.find_no_flow_cells(\"smoothed.tif\", \"noflow.tif\")" + ] + }, + { + "cell_type": "markdown", + "id": "48", + "metadata": {}, + "source": [ + "Display the no-flow cells on the map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_raster(\"noflow.tif\", layer_name=\"No Flow Cells\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "50", + "metadata": {}, + "source": [ + "## Fill depressions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.fill_depressions(\"smoothed.tif\", \"filled.tif\")" + ] + }, + { + "cell_type": "markdown", + "id": "52", + "metadata": {}, + "source": [ + "Alternatively, you can use depression breaching to fill the depressions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.breach_depressions(\"smoothed.tif\", \"breached.tif\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.find_no_flow_cells(\"breached.tif\", \"noflow2.tif\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_raster(\"noflow2.tif\", layer_name=\"No Flow Cells after Breaching\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "56", + "metadata": {}, + "source": [ + "## Delineate flow direction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.d8_pointer(\"breached.tif\", \"flow_direction.tif\")" + ] + }, + { + "cell_type": "markdown", + "id": "58", + "metadata": {}, + "source": [ + "## Calculate flow accumulation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.d8_flow_accumulation(\"breached.tif\", \"flow_accum.tif\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_raster(\"flow_accum.tif\", layer_name=\"Flow Accumulation\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "61", + "metadata": {}, + "source": [ + "## Extract streams" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.extract_streams(\"flow_accum.tif\", \"streams.tif\", threshold=5000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_raster(\"streams.tif\", layer_name=\"Streams\")" + ] + }, + { + "cell_type": "markdown", + "id": "64", + "metadata": {}, + "source": [ + "## Calculate distance to outlet" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.distance_to_outlet(\n", + " \"flow_direction.tif\", streams=\"streams.tif\", output=\"distance_to_outlet.tif\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_raster(\"distance_to_outlet.tif\", layer_name=\"Distance to Outlet\")" + ] + }, + { + "cell_type": "markdown", + "id": "67", + "metadata": {}, + "source": [ + "## Vectorize streams" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.raster_streams_to_vector(\n", + " \"streams.tif\", d8_pntr=\"flow_direction.tif\", output=\"streams.shp\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "69", + "metadata": {}, + "source": [ + "The raster_streams_to_vector tool has a bug. The output vector file is missing the coordinate system. Use leafmap.vector_set_crs() to set the coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70", + "metadata": {}, + "outputs": [], + "source": [ + "leafmap.vector_set_crs(source=\"streams.shp\", output=\"streams.shp\", crs=\"EPSG:3857\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_shp(\n", + " \"streams.shp\", layer_name=\"Streams Vector\", style={\"color\": \"#ff0000\", \"weight\": 3}\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "72", + "metadata": {}, + "source": [ + "## Delineate basins" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.basins(\"flow_direction.tif\", \"basins.tif\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_raster(\"basins.tif\", layer_name=\"Basins\")" + ] + }, + { + "cell_type": "markdown", + "id": "75", + "metadata": {}, + "source": [ + "## Delineate the longest flow path" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.longest_flowpath(\n", + " dem=\"breached.tif\", basins=\"basins.tif\", output=\"longest_flowpath.shp\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "77", + "metadata": {}, + "source": [ + "Select only the longest flow path." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78", + "metadata": {}, + "outputs": [], + "source": [ + "leafmap.select_largest(\n", + " \"longest_flowpath.shp\", column=\"LENGTH\", output=\"longest_flowpath.shp\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_shp(\n", + " \"longest_flowpath.shp\",\n", + " layer_name=\"Longest Flowpath\",\n", + " style={\"color\": \"#ff0000\", \"weight\": 3},\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "80", + "metadata": {}, + "source": [ + "## Generate a pour point" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81", + "metadata": {}, + "outputs": [], + "source": [ + "if m.user_roi is not None:\n", + " m.save_draw_features(\"pour_point.shp\", crs=\"EPSG:3857\")\n", + "else:\n", + " coords = [-122.613559, 44.284383]\n", + " leafmap.coords_to_vector(coords, output=\"pour_point.shp\", crs=\"EPSG:3857\")" + ] + }, + { + "cell_type": "markdown", + "id": "82", + "metadata": {}, + "source": [ + "## Snap pour point to stream" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.snap_pour_points(\n", + " \"pour_point.shp\", \"flow_accum.tif\", \"pour_point_snapped.shp\", snap_dist=300\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_shp(\"pour_point_snapped.shp\", layer_name=\"Pour Point\")" + ] + }, + { + "cell_type": "markdown", + "id": "85", + "metadata": {}, + "source": [ + "## Delineate watershed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.watershed(\"flow_direction.tif\", \"pour_point_snapped.shp\", \"watershed.tif\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_raster(\"watershed.tif\", layer_name=\"Watershed\")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "88", + "metadata": {}, + "source": [ + "## Convert watershed raster to vector" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89", + "metadata": {}, + "outputs": [], + "source": [ + "wbt.raster_to_vector_polygons(\"watershed.tif\", \"watershed.shp\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90", + "metadata": {}, + "outputs": [], + "source": [ + "m.add_shp(\n", + " \"watershed.shp\",\n", + " layer_name=\"Watershed Vector\",\n", + " style={\"color\": \"#ffff00\", \"weight\": 3},\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/book/software/miniconda.ipynb b/_sources/book/software/miniconda.ipynb index bca53bc..2c43d3b 100644 --- a/_sources/book/software/miniconda.ipynb +++ b/_sources/book/software/miniconda.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "38a78f90", + "id": "0f7d3118", "metadata": {}, "source": [ "# Miniconda\n", diff --git a/_sources/book/software/overview.ipynb b/_sources/book/software/overview.ipynb index 92d9093..b3743a4 100644 --- a/_sources/book/software/overview.ipynb +++ b/_sources/book/software/overview.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "afebc73c", + "id": "14112298", "metadata": {}, "source": [ "# Overview\n", diff --git a/book/about/instructor.html b/book/about/instructor.html index 83a4b50..9ae3ef8 100644 --- a/book/about/instructor.html +++ b/book/about/instructor.html @@ -200,7 +200,15 @@

GeoPython

Labs

GeoPython

Labs

GeoPython

Labs