Earth Engine Tutorial #37: How to use Earth Engine with pydeck for 3D terrain visualization

Earth Engine Tutorial #37: How to use Earth Engine with pydeck for 3D terrain visualization


  • earthengine-api: a Python client library for calling the Google Earth Engine API.
  • pydeck: a WebGL-powered framework for visual exploratory data analysis of large datasets.
  • pydeck-earthengine-layers: a pydekc wrapper for Google Earth Engine. For documentation please visit this website.
  • Mapbox API key: you will need this add basemap tiles to pydeck.


  • conda create -n deck python
  • conda activate deck
  • conda install mamba -c conda-forge
  • mamba install earthengine-api pydeck pydeck-earthengine-layers -c conda-forge
  • jupyter nbextension install --sys-prefix --symlink --overwrite --py pydeck
  • jupyter nbextension enable --sys-prefix --py pydeck

This example is adopted from here. Credits to the developers of the pydeck-earthengine-layers package.



2D Visualization

import ee
import geemap
Map = geemap.Map()
image = ee.Image('USGS/NED').select('elevation')
    "min": 0, 
    "max": 4000,
    "palette": ['006633', 'E5FFCC', '662A00', 'D8D8D8', 'F5F5F5']
Map.addLayer(image, vis_params, 'NED')

3D Visualization

Import libraries

First, import required packages. Note that here we import the EarthEngineTerrainLayer instead of the EarthEngineLayer.

import ee
import pydeck as pdk
from pydeck_earthengine_layers import EarthEngineTerrainLayer

Authenticate with Earth Engine

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

except Exception as e:

Terrain Example

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.

It's important for the terrain source to have relatively high spatial resolution. In previous examples, we used 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 (30-meter resolution) as the Image source and the USGS's National Elevation Dataset (10-meter resolution, U.S. only) as the terrain source. SRTM30 is generally the best-resolution worldwide data source available.

# image = ee.Image('USGS/SRTMGL1_003')
image = ee.Image('USGS/NED').select('elevation')
terrain = ee.Image('USGS/NED').select('elevation')

Here vis_params consists of parameters that will be passed to the Earth Engine visParams argument. Any parameters that you could pass directly to Earth Engine in the code editor, you can also pass here to the EarthEngineLayer.

    "min": 0, 
    "max": 4000,
    "palette": ['006633', 'E5FFCC', '662A00', 'D8D8D8', 'F5F5F5']

Now we're ready to create the Pydeck layer. The EarthEngineLayer makes this simple. Just pass the Earth Engine object to the class.

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.

ee_layer = EarthEngineTerrainLayer(

Then just pass this layer to a pydeck.Deck instance, and call .show() to create a map:

view_state = pdk.ViewState(

r = pdk.Deck(

Did you find this article valuable?

Support Qiusheng Wu by becoming a sponsor. Any amount is appreciated!