In this tutorial, we demonstrate how to create interactive map layers from a RasterFrame of Landsat 8 imagery covering Orlando, Florida, USA. We show the three different methods available, which include:
to_map
, which creates a single map layer from a Tile column in a RasterFrame and returns an ipyleaflet map widget;to_map_layers
, which can create several, individually configurable map layers and returns an ipyleaflet map widget; andwrite_slippy
, which writes out a layer and (optionally) a standalone HTML page with a leaflet map embedded into it.
ipyleaflet is a geospatial Python library that enables users to create interactive maps in Jupyter Notebook. The first two methods demonstrated in this example (to_map
and to_map_layers
) create ipyleaflet.Map objects from a RasterFrame, which can be used in combination with other widgets in the ipyleaflet library.
Note: you can download the companion notebook for this example from the attachement provided at the end of this article.
Import Libraries
We will start by importing all of the Python libraries used in this example.
from earthai.init import * import earthai.chipping.strategy from earthai import RenderingMode from shapely.geometry import Polygon from shapely.geometry import Point import geopandas import ipyleaflet
Define a Region Covering Orlando, FL
We start by defining our region of interest - a rectangular region covering Orlando, FL. We use this region in the next step to extract imagery from the EarthAI Catalog. In the cell below we define a Shapely Polygon object, and load it into a GeoPandas DataFrame.
orlando_poly = Polygon([(-81.58825278434438, 28.695817228513512), \ (-81.20098471793813, 28.695817228513512), \ (-81.20098471793813, 28.244321125520017), \ (-81.58825278434438, 28.244321125520017), \ (-81.58825278434438, 28.695817228513512)]) orlando_gdf = geopandas.GeoDataFrame({"geometry":[orlando_poly], "crs":"EPSG:4326"})
Below, we use ipyleafet.Map
to create a simple interactive map displaying our region of interest over a basemap from OpenStreetMap.
m1 = ipyleaflet.Map(center=(28.4, -81.55), zoom=9) bounds_layer = ipyleaflet.GeoData(geo_dataframe=orlando_gdf, name='Orlando') m1.add_layer(bounds_layer) m1
Read Landsat 8 Imagery into a RasterFrame
We now query the EarthAI Catalog to find Landsat 8 imagery covering Orlando, FL. For simplicity, we choose a single scene acquired in March 2020, with less than 10% cloud cover.
l8_cat = earth_ondemand.read_catalog(orlando_gdf, start_datetime = '2020-03-01', end_datetime = '2020-03-15', max_cloud_cover = 10, collections = 'landsat8_l1tp')
We next join the returned catalog to the Orlando boundary, and use this boundary with spark.read.chip
to load in the Landsat 8 imagery. We choose to use the chip reader since our area of interest is much smaller than a full Landsat 8 scene, and this reduces the volume of data that we have to load in to the notebook environment. We use the FeatureAlignedGrid
chipping strategy, and read in the red, blue, green, near-infrared (NIR), and shortwave-infrared (SWIR, 1.6 micron) bands.
Note: the withColumn
method is used to rename the bands to their common names, and convert the cell types from uint16raw to uint16 so that NoData cells get rendered properly.
l8_cat = geopandas.sjoin(l8_cat, orlando_gdf, how='right').rename(columns={"geometry":"orlando_bounds"}) orlando_rf = spark.read.chip(l8_cat, catalog_col_names=['B4', 'B3', 'B2', 'B5', 'B6'], # red, green, blue, NIR, SWIR geometry_col_name='orlando_bounds', chipping_strategy=earthai.chipping.strategy.FeatureAlignedGrid(256), tile_dimensions=(256, 256)) \ .withColumn('red', rf_interpret_cell_type_as('B4', 'uint16')) \ .withColumn('green', rf_interpret_cell_type_as('B3', 'uint16')) \ .withColumn('blue', rf_interpret_cell_type_as('B2', 'uint16')) \ .withColumn('nir', rf_interpret_cell_type_as('B5', 'uint16')) \ .withColumn('swir', rf_interpret_cell_type_as('B6', 'uint16'))
Create a Single Map Layer: to_map
We can use the to_map
method to create a single map layer from a RasterFrame of Tiles. This layer can either be a single-band image, or a 3-band color composite. To see the full list of parameter options, run ?orlando_rf.to_map
in a notebook cell.
Single-Band Map Layer
We'll start by creating a single-band map layer of the Normalized Difference Built-up Index (NDBI), which is the normalized difference between the SWIR bands and NIR bands. We start by calculating NDBI and adding this column to orlando_rf:
orlando_rf = orlando_rf.withColumn("ndbi", rf_normalized_difference('swir', 'nir'))
In the call to to_map
, the first input parameter defines the label to give the map layer on output, which we set to NDBI
. For a single-band map layer, you can select any color ramp from this list of options shown below:
earthai.valid_color_ramps()
We set color_ramp = GreenToRedOrange
for the NDBI layer. We can also set rendering_mode = RenderingMode.UNIFORM
to help normalize the color contrast among tiles. Note that this option may be slow for large data sets as it requires an additional pass over the Tiles.
m2 = orlando_rf.select('ndbi').to_map("NDBI", color_ramp='GreenToRedOrange', rendering_mode=RenderingMode.UNIFORM) m2
The output m2 is an ipyleaflet.Map object, that can be used with any other interactive widgets in the ipyleaflet library. Note the control widget in the upper right corner: this allows you to toggle the NDBI layer on and off.
3-Band Color Composite Layer
to_map
can also be used to create a 3-band color composite. In this case, we need to select the three Tile columns to create the composite from, listed in order of how to render them: the first column maps to "R", the second to "G", and the third to "B".
Below we create a true color image using the red, green, and blue Tile columns.
m3 = orlando_rf.select('red','green','blue').to_map("TrueColor") m3
Create Multiple Map Layers: to_map_layers
We can use the to_map_layers
method to write several map layers at once. This method takes a list of Python dictionaries corresponding to each layer that you want to add and returns an ipyleaflet.Map object. Each item in the list will result in a single layer. The value in the columns key in the dictionary specifies which Tile columns to consider. You can type ?orlando_rf.to_map_layers
in a notebook cell to see the full descriptions of how to use this method.
NDBI and True Color Map Layers
Below, we create the same two layers as in the previous section: NDBI
and TrueColor
, but use to_map_layers
to put them on the same interactive map.
m4 = orlando_rf.to_map_layers([{"name": 'TrueColor', "columns": ['red', 'green', 'blue']}, {"name": 'NDBI', "columns": 'ndbi', "color_ramp": 'GreenToRedOrange', "rendering_mode": RenderingMode.UNIFORM}]) m4
Note the order of the map layer dictionaries supplied to to_map_layers
. The returned map widget will create the layers in this same order, such that the first one specified is on the bottom, and the last is on the top. You can use the control widget in the upper right corner to select/deselect which layers to show.
Overlay Polygons and Points
Since m4 is an ipyleaflet.Map object, we can use other tools in that library to add more layers. Below we define and add points corresponding to three theme parks that are part of the Walt Disney World Resort.
parks_point = [Point(-81.581212, 28.417663), # Magic Kingdom Point(-81.549404, 28.374694), # Epcot Point(-81.5582714, 28.3575294)] # Hollywood Studios parks_gdf = geopandas.GeoDataFrame({"geometry":parks_point, "crs":"EPSG:4326"}) parks_layer = ipyleaflet.GeoData(geo_dataframe=parks_gdf, name='Disney World Theme Parks') m4.add_layer(parks_layer) m4
We can also extract layers from other ipyleaflet.Map objects that have been created. Below we add the boundary for the Orlando, FL region by extracting the layer from m1:
m4.add_layer(m1.layers[-1]) m4
Write an HTML Page with an Embedded Leaflet Map
The write.slippy
method writes out a single map layer to a web map view. Run ?orlando_rf.write.slippy
in a notebook cell to view the full function details.
Write the HTML Page
This function requires an input file path to a local directory, where the map artefacts will be written to. Below, we write out the ndbi Tiles to a slippy map stored in the NDBI_slippy_map
directory. We set html=True
to generate a static HTML page.
orlando_rf.select('NDBI').write.slippy('NDBI_slippy_map', colorramp='GreenToRedOrange', render_mode=RenderingMode.UNIFORM, html=True)
To write out a 3-band color composite, simply select the three bands that you want to render, in order of "RGB":
orlando_rf.select('red', 'green', 'blue').write.slippy('TrueColor_slippy_map', html=True)
View the HTML Page
To download and view the HTML file, we have to first create a compressed tar
bundle to put the web map contents into a single file:
!tar -czf NDBI_slippy_map.tar.gz NDBI_slippy_map/
Now right click on the file "NDBI_slippy_map.tar.gz" in the folder viewer located in the left side bar, and select Download. Once the downloaded to your desktop, unzip the tar file and view the contents of the directory. Open the "index.html" file to view the slippy map in a web browser, as demonstrated below.
Comments
0 comments
Please sign in to leave a comment.