{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\"Open\n", "\n", "Uncomment the following line to install [geemap](https://geemap.org) if needed." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# !pip install geemap" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# How to use Earth Engine with pydeck for 3D terrain visualization\n", "Pydeck + Earth Engine: Terrain Visualization\n", "\n", "**Requirements**\n", "\n", "- [earthengine-api](https://github.com/google/earthengine-api): a Python client library for calling the Google Earth Engine API.\n", "- [pydeck](https://pydeck.gl/index.html): a WebGL-powered framework for visual exploratory data analysis of large datasets.\n", "- [pydeck-earthengine-layers](https://github.com/UnfoldedInc/earthengine-layers/tree/master/py): a pydekc wrapper for Google Earth Engine. For documentation please visit this [website](https://earthengine-layers.com/).\n", "- [Mapbox API key](https://pydeck.gl/installation.html#getting-a-mapbox-api-key): you will need this add basemap tiles to pydeck.\n", "\n", "**Installation**\n", "\n", "- conda create -n deck python\n", "- conda activate deck\n", "- conda install mamba -c conda-forge\n", "- mamba install earthengine-api pydeck pydeck-earthengine-layers -c conda-forge\n", "- jupyter nbextension install --sys-prefix --symlink --overwrite --py pydeck\n", "- jupyter nbextension enable --sys-prefix --py pydeck" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This example is adopted from [here](https://github.com/UnfoldedInc/earthengine-layers/blob/master/py/examples/terrain.ipynb). Credits to the developers of the [pydeck-earthengine-layers](https://github.com/UnfoldedInc/earthengine-layers) package." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2D Visualization" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import ee\n", "import geemap" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Map = geemap.Map()\n", "Map" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "image = ee.Image('USGS/NED').select('elevation')\n", "vis_params = {\n", " \"min\": 0,\n", " \"max\": 4000,\n", " \"palette\": ['006633', 'E5FFCC', '662A00', 'D8D8D8', 'F5F5F5'],\n", "}\n", "Map.addLayer(image, vis_params, 'NED')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3D Visualization\n", "\n", "### Import libraries" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, import required packages. Note that here we import the `EarthEngineTerrainLayer` instead of the `EarthEngineLayer`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import ee\n", "import pydeck as pdk\n", "from pydeck_earthengine_layers import EarthEngineTerrainLayer" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Authenticate with Earth Engine\n", "\n", "Using Earth Engine requires authentication. If you don't have a Google account approved for use with Earth Engine, you'll need to request access. For more information and to sign up, go to https://signup.earthengine.google.com/." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "try:\n", " ee.Initialize()\n", "except Exception as e:\n", " ee.Authenticate()\n", " ee.Initialize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Terrain Example\n", "\n", "In contrast to the `EarthEngineLayer`, where you need to supply _one_ Earth Engine object to render, with the `EarthEngineTerrainLayer` you must supply **two** Earth Engine objects. The first is used to render the image in the same way as the `EarthEngineLayer`; the second supplies elevation values used to extrude terrain in 3D. Hence the former can be any `Image` object; the latter must be an `Image` object whose values represents terrain heights.\n", "\n", "It's important for the terrain source to have relatively high spatial resolution. In previous examples, we used [SRTM90][srtm90] as an elevation source, but that only has a resolution of 90 meters. When used as an elevation source, it looks very blocky/pixelated at high zoom levels. In this example we'll use [SRTM30][srtm30] (30-meter resolution) as the `Image` source and the [USGS's National Elevation Dataset][ned] (10-meter resolution, U.S. only) as the terrain source. SRTM30 is generally the best-resolution worldwide data source available.\n", "\n", "[srtm90]: https://developers.google.com/earth-engine/datasets/catalog/CGIAR_SRTM90_V4\n", "[srtm30]: https://developers.google.com/earth-engine/datasets/catalog/USGS_SRTMGL1_003\n", "[ned]: https://developers.google.com/earth-engine/datasets/catalog/USGS_NED" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# image = ee.Image('USGS/SRTMGL1_003')\n", "image = ee.Image('USGS/NED').select('elevation')\n", "terrain = ee.Image('USGS/NED').select('elevation')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here `vis_params` consists of parameters that will be passed to the Earth Engine [`visParams` argument][visparams]. Any parameters that you could pass directly to Earth Engine in the code editor, you can also pass here to the `EarthEngineLayer`.\n", "\n", "[visparams]: https://developers.google.com/earth-engine/image_visualization" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vis_params = {\n", " \"min\": 0,\n", " \"max\": 4000,\n", " \"palette\": ['006633', 'E5FFCC', '662A00', 'D8D8D8', 'F5F5F5'],\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we're ready to create the Pydeck layer. The `EarthEngineLayer` makes this simple. Just pass the Earth Engine object to the class." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Including the `id` argument isn't necessary when you only have one pydeck layer, but it is necessary to distinguish multiple layers, so it's good to get into the habit of including an `id` parameter." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ee_layer = EarthEngineTerrainLayer(image, terrain, vis_params, id=\"EETerrainLayer\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then just pass this layer to a `pydeck.Deck` instance, and call `.show()` to create a map:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "view_state = pdk.ViewState(\n", " latitude=36.15, longitude=-111.96, zoom=10.5, bearing=-66.16, pitch=60\n", ")\n", "\n", "r = pdk.Deck(layers=[ee_layer], initial_view_state=view_state)\n", "\n", "r.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 5 }