Using Google Earth Engine to render satellite layers on a map
Satellite imagery tells useful stories that can’t be told from the ground—such as providing information about weather and climate, geography and human settlement. This information can be vital for managing global supply chains, predicting and mitigating extreme weather events, and monitoring the environmental impacts of human development. Harnessing this information and moulding it in a way that shows the story you are trying to tell, can be a powerful tool in any geospatial application it is applied to.
However, in order to tell powerful stories using satellite imagery, first you need to know what information is available to you, how to access it and render the information on a map. These layers do not magically appear on your map, but here I will give you a step-by-step overview of how to render your satellite layers on a map using Google Earth Engine.
How do you get started?
Firstly, you need to decide which datasets you need for your map that will supplement the story you want to communicate. The great news is that Google Earth Engine has an easily accessible dataset catalog for users.
There is a large range of datasets to choose from, each with accompanying documentation on how to use it. The collection is compartmentalised in a way that groups similar datasets—for example, all climate related datasets are listed together here.
In the examples I am providing in this blog, we will be using these datasets inside of the Earth Engine Code Editor. The Earth Engine Code Editor is where you can write and compile special Javascript code in the browser. To do this, you will need to submit a form to Google with an accompanying Google account to access the code editor. It’s free and you can sign up here.
How do you use these datasets?
Once you’re in the editor, you can create a new script. You can do this by clicking ‘new’ under the scripts tab on the left, selecting ‘file’, and giving the script a name.
Optionally, you can create a repository or folder to better organise your script hierarchy. It’s important that by this stage, you have chosen the data you’d like to use on your map. For this example, I am using the ERA5 dataset to display global temperature data.
Now we can start writing our script!
The code you can see in the example above is using bits and pieces of the code snippets provided under the ERA5 dataset documentation. The three parts in the example outline the simplest implementation of a script you might have.
Part one:
To begin with, we initialise the image collection. An image collection is essentially an ordered set of images that can be loaded onto a map. ‘ECMWF/ERA5/DAILY’ is the route we’ll parse into the ee.ImageCollection function to pull in the ERA5 dataset. To get the air temperature data, we’ll select it using ‘mean_2m_air_temperature’. Finally, we’ll filter it to only display the days of July 2019.
Part two:
Here, we set up the visualisation parameters. This will determine how the layer will look on the map. In this case, we only need three variables. The palette defines an array of hexadecimal values (which represents colour) to visualise the dataset. The minimum and maximum values determine the spread of the range of colours that we define in the palette.
Part three:
Finally, we can add the layer to the map using Map.addLayer. Here we parse the image collection (it is filtered one more time to get a single day’s data), the visualisation parameters and a title.
We then hit ‘run’ and should see the results below.
Multiband layers and geometry clipping
But what if we want to see a layer clipped to a specific area on the map? Or if we wanted to visualise data over more than one visual band?
I’m going to use the case of visualising NDVI (Normalised Difference Vegetation Index). NDVI essentially measures greenery on the Earth; some use cases include predicting agricultural yield, identifying fire hazard areas and documenting areas in drought. You can read more about NDVI here.
NDVI is described as follows, where NIR = Near infrared red reflectance, and RED = red reflectance:
NDVI = (NIR-RED) / (NIR+RED)
If you want to visualise NDVI, then you’ll need to use two bands—the near infrared band and infrared band.
To get surface reflectance, you can use the Sentinel 2 dataset. Under the bands tab, we can see all the bands that are available to use. Take note of the B4 (red) and B8 (near infrared) bands – we’ll be needing these later.
Now, let’s make a new script from scratch. I’ll make a geometry that displays the NDVI layer over the US state of Wyoming (a nice simple rectangle). To begin with, I’ll draw a polygon on the map which we’ll use in the script. You can do this by selecting the draw tools on the map and drawing a shape. The polygon created can automatically be referenced in the script after the drawing is complete.
Now we can use the geometry in the script. It will appear in the ‘Imports’ section of your script editor.
Most of this script’s functionality is shared with the ERA5 example, but there are a couple of extra things going on:
Part one:
Like I mentioned earlier, the geometry created will appear in the imports section here. If there are multiple polygons it will help us to differentiate them by renaming each one, which you can do from here.
Part two:
The image collection, after being filtered, is mapped using the normalizedDifference function, and the two bands we wanted to use are put into an array: B4 (red) and B8 (near infrared). After the mapping is completed, we want to get the maximum value for each region, and then finally we clip it to the geometry that was drawn.
The output is as follows (with an opacity value of 0.8).
Can I use this in my own apps?
Yes! Almost every aspect of the code in Earth Engine code editor can be closely copied over into Javascript (or any language that builds on Javascript). Here is a code snippet in TypeScript using the Angular framework that has the exact same functionality:
Most of the code above is the same with some changes here and there, I’ll explain them here for you.
Firstly, all vars are changed to const—this is a convention of Typescript.
The main difference is that we wrap the function inside of a promise, which allows us to run the function asynchronously and not freeze the application when we want to load in the layer. The promise type is EarthEngineMapResponse, which is a self-defined interface that defines the map (with an ID and coordinates) that we want the function to return.
Finally, instead of map.AddLayer we use image.getMap, with the format defined above.
Instead of returning the map to Earth Engine’s map, we extract it using this function. The promise simply ensures that this function gets executed completely before the next operation.
How does this work though? Are all the satellite datasets required to be pulled into an application?
That would be too resource intensive—instead, the data is sent to be executed on Earth Engine’s server. Any function that has ‘ee’ before it is doing this. Sometimes, you’ll want to get this raw data back, which you can extract using the getInfo function after an ee operation.
Are you interested in satellite data and imagery?
The two datasets I used in this blog barely scratch the surface of the kinds of data that can be used within your applications. Last year, the team at EO Data Science catalogue added a bunch of new datasets that were previously inaccessible in GEE, to the GEE Data Catalogue.
If you want to learn more or need assistance with an Earth Engine integration solution like this, our Software Engineering team would love to chat. You can get in touch with us here!
Related Articles
Here are more related articles you may be interested in.