16  Interactive maps

Author

Andres Patrignani

Published

March 16, 2024

Interactive maps provide a dynamic user experience, allowing for real-time zooming, panning, and exploration of geospatial data layers. In contrast, Matplotlib’s static figures, while useful for publication-quality visuals, lack the ability to explore data or to easily integrate multiple layers of information. Additionally, interactive maps can be easily integrated withing websites and are ideal for collaborative projects and public dissemination of geospatial research findings.

In this tutorial we will create an interactive map to explore different land covers across the state of Kansas. We will use the folium Python library, which is a wrapper around the popular Leaflet library implemented Javascript.

In this tutorial we will learn:

# Import modules
import ee
import folium
import numpy as np
from matplotlib import colors, colormaps

Define some helper functions

Let’s define some functions to avoid repeating the following code everytime we want to create a raster image or every time we want to specify a given colormap for our map.

def get_raster_map(ee_object, vis, name):
    """
    Function that retrieves raster map from GEE and applies some style.
    """
    if isinstance(ee_object, ee.Image):
        layer = folium.TileLayer(ee_object.getMapId(vis)['tile_fetcher'].url_format,
                           name=name,
                           overlay=True,
                           control=True,
                           attr='Map Data &copy; <a href="https://earthengine.google.com/">Google Earth Engine</a>')
        
    return layer



def get_vector_map(ee_object,vis,name):
    """
    Function that retrieves vector map from GEE and applies some style.
    """
    if isinstance(ee_object, ee.FeatureCollection):
        layer = folium.GeoJson(ee_object.getInfo(),
                               name=name,
                               style_function=lambda feature: {
                                   'fillColor': vis['face_color'],
                                   'color': vis['edge_color'],
                                   'weight': vis['line_width']})
    return layer
# Authenticate GEE (follow the link and copy-paste the token in the notebook)
#ee.Authenticate()

# Initialize the library.
ee.Initialize()

State land cover

# Read US states
US_states = ee.FeatureCollection("TIGER/2018/States")

# Select Kansas
region = US_states.filter(ee.Filter.inList('NAME',['Kansas']))
# Land use for 2021
land_use = ee.ImageCollection('USDA/NASS/CDL')\
             .filter(ee.Filter.date('2020-01-01', '2021-12-31')).first().clip(region)

# Select cropland layer
cropland = land_use.select('cropland')
# Get layer metadata
info = cropland.getInfo()

# Remove comment to print the entire information (output is long!)
# print(info)
print(info.keys())
dict_keys(['type', 'bands', 'id', 'version', 'properties'])
# Get land cover names, values, and colors from metadata

class_names = info['properties']['cropland_class_names']
class_values = info['properties']['cropland_class_values']
class_colors = info['properties']['cropland_class_palette']
# Create dictionary to easily access properties by land cover name
class_props = {}
for k,name in enumerate(class_names):
    class_props[name] = {'value':class_values[k], 'color':class_colors[k]}

# Print example
class_props['Corn']
{'value': 1, 'color': 'ffd300'}
# Create self masks for each land cover, so that only 
# the pixels for this land cover visible

corn = cropland.eq(class_props['Corn']['value']).selfMask()
sorghum = cropland.eq(class_props['Sorghum']['value']).selfMask()
soybeans = cropland.eq(class_props['Soybeans']['value']).selfMask()
wheat = cropland.eq(class_props['Winter Wheat']['value']).selfMask()
grassland = cropland.eq(class_props['Grassland/Pasture']['value']).selfMask()
Tip

Since we created a dictionary using the name of the land cover class as the key, in the previous cell you can use Tab-autocompletion.

# Initialize map centered at a specific location and zoom level
m = folium.Map(location=[38, -98], zoom_start=7)

get_raster_map(corn, {'palette':[class_props['Corn']['color']]}, 'Corn').add_to(m)
get_raster_map(sorghum, {'palette':[class_props['Sorghum']['color']]}, 'Sorghum').add_to(m)
get_raster_map(soybeans, {'palette':[class_props['Soybeans']['color']]}, 'Soybeans').add_to(m)
get_raster_map(wheat, {'palette':[class_props['Winter Wheat']['color']]}, 'Wheat').add_to(m)
get_raster_map(grassland, {'palette':[class_props['Grassland/Pasture']['color']]}, 'Grassland').add_to(m)

# Add vector layers
get_vector_map(region, vis={'face_color':'#00FFFF00',
                     'edge_color':'black',
                     'line_width':2}, name='State boundary').add_to(m)

get_vector_map(counties, vis={'face_color':'#00FFFF00',
                     'edge_color':'grey',
                     'line_width':1}, name='County boundary').add_to(m)


# Add a layer control panel to the map.
m.add_child(folium.LayerControl())

# Display the map.
display(m)
Make this Notebook Trusted to load map: File -> Trust Notebook