GEE Tutorial #39 - How to create Landsat timelapse animations without coding
This tutorial shows you how to create timelapse animations of Landsat imagery and normalized difference indices (e.g., NDVI, NDWI) using Earth Engine and geemap.
Steps to create a Landsat timelapse:
- Pan and zoom to your area of interest, or click the globe icon at the upper left corner to search for a location.
- Use the drawing tool to draw a rectangle anywhere on the map.
- Adjust the parameters (e.g., start year, end year, title) if needed.
- Click the
Create timelapse
button to create a timelapse. - Once the timelapse has been added to the map, click the hyperlink at the end if you want to download the GIF.
Web Apps: gishub.org/timelapse, gishub.org/gee-ngrok
Notebook: github.com/giswqs/geemap/blob/master/exampl..
Demo:
YouTube:
Source Code:
import os
import ee
import geemap
import ipywidgets as widgets
Map = geemap.Map()
Map.add_basemap('HYBRID')
Map
style = {'description_width': 'initial'}
title = widgets.Text(
description='Title:',
value='Landsat Timelapse',
width=200,
style=style
)
bands = widgets.Dropdown(
description='Select RGB Combo:',
options=['Red/Green/Blue', 'NIR/Red/Green', 'SWIR2/SWIR1/NIR', 'NIR/SWIR1/Red','SWIR2/NIR/Red',
'SWIR2/SWIR1/Red', 'SWIR1/NIR/Blue', 'NIR/SWIR1/Blue', 'SWIR2/NIR/Green', 'SWIR1/NIR/Red'],
value='NIR/Red/Green',
style=style
)
hbox1 = widgets.HBox([title, bands])
hbox1
speed = widgets.IntSlider(
description=' Frames per second:',
tooltip='Frames per second:',
value=10,
min=1,
max = 30,
style=style
)
cloud = widgets.Checkbox(
value=True,
description='Apply fmask (remove clouds, shadows, snow)',
style=style
)
hbox2 = widgets.HBox([speed, cloud])
hbox2
start_year = widgets.IntSlider(description='Start Year:', value=1984, min=1984, max=2020, style=style)
end_year = widgets.IntSlider(description='End Year:', value=2020, min=1984, max=2020, style=style)
start_month = widgets.IntSlider(description='Start Month:', value=5, min=1, max=12, style=style)
end_month = widgets.IntSlider(description='End Month:', value=10, min=1, max=12, style=style)
hbox3 = widgets.HBox([start_year, end_year, start_month, end_month])
hbox3
font_size = widgets.IntSlider(description='Font size:', value=30, min=10, max=50, style=style)
font_color = widgets.ColorPicker(
concise=False,
description='Font color:',
value='white',
style=style
)
progress_bar_color = widgets.ColorPicker(
concise=False,
description='Progress bar color:',
value='blue',
style=style
)
hbox4 = widgets.HBox([font_size, font_color, progress_bar_color])
hbox4
# Normalized Satellite Indices: https://www.usna.edu/Users/oceano/pguth/md_help/html/norm_sat.htm
nd_options = ['Vegetation Index (NDVI)',
'Water Index (NDWI)',
'Modified Water Index (MNDWI)',
'Snow Index (NDSI)',
'Soil Index (NDSI)',
'Burn Ratio (NBR)',
'Customized']
nd_indices = widgets.Dropdown(options=nd_options, value=None, description='Normalized Difference Index:', style=style)
first_band = widgets.Dropdown(
description='1st band:',
options=['Blue', 'Green','Red','NIR', 'SWIR1', 'SWIR2'],
value=None,
style=style
)
second_band = widgets.Dropdown(
description='2nd band:',
options=['Blue', 'Green','Red','NIR', 'SWIR1', 'SWIR2'],
value=None,
style=style
)
nd_threshold = widgets.FloatSlider(
value=0,
min=-1,
max=1,
step=0.01,
description='Threshold:',
orientation='horizontal',
)
nd_color = widgets.ColorPicker(
concise=False,
description='Color:',
value='blue',
style=style
)
def nd_index_change(change):
if nd_indices.value == 'Vegetation Index (NDVI)':
first_band.value = 'NIR'
second_band.value = 'Red'
elif nd_indices.value == 'Water Index (NDWI)':
first_band.value = 'NIR'
second_band.value = 'SWIR1'
elif nd_indices.value == 'Modified Water Index (MNDWI)':
first_band.value = 'Green'
second_band.value = 'SWIR1'
elif nd_indices.value == 'Snow Index (NDSI)':
first_band.value = 'Green'
second_band.value = 'SWIR1'
elif nd_indices.value == 'Soil Index (NDSI)':
first_band.value = 'SWIR1'
second_band.value = 'NIR'
elif nd_indices.value == 'Burn Ratio (NBR)':
first_band.value = 'NIR'
second_band.value = 'SWIR2'
elif nd_indices.value == 'Customized':
first_band.value = None
second_band.value = None
nd_indices.observe(nd_index_change, names='value')
hbox5 = widgets.HBox([nd_indices, first_band, second_band, nd_threshold, nd_color])
hbox5
create_gif = widgets.Button(
description='Create timelapse',
button_style='primary',
tooltip='Click to create timelapse',
style=style
)
download_gif = widgets.Button(
description='Download GIF',
button_style='primary',
tooltip='Click to download timelapse',
disabled=False,
style=style
)
output = widgets.Output()
hbox5 = widgets.HBox([create_gif])
hbox5
def submit_clicked(b):
with output:
output.clear_output()
if start_year.value > end_year.value:
print('The end year must be great than the start year.')
return
if start_month.value > end_month.value:
print('The end month must be great than the start month.')
return
if start_year.value == end_year.value:
add_progress_bar = False
else:
add_progress_bar = True
start_date = str(start_month.value).zfill(2) + '-01'
end_date = str(end_month.value).zfill(2) + '-30'
print('Computing...')
nd_bands = None
if (first_band.value is not None) and (second_band.value is not None):
nd_bands = [first_band.value, second_band.value]
Map.add_landsat_ts_gif(roi=Map.user_roi, label=title.value, start_year=start_year.value,
end_year=end_year.value, start_date=start_date, end_date=end_date,
bands=bands.value.split('/'), font_color=font_color.value,
frames_per_second=speed.value, font_size=font_size.value,
add_progress_bar= add_progress_bar, progress_bar_color=progress_bar_color.value,
download=True, apply_fmask=cloud.value, nd_bands=nd_bands,
nd_threshold=nd_threshold.value, nd_palette=['black', nd_color.value])
create_gif.on_click(submit_clicked)
output