9. Creating Timelapses#

9.1. Introduction#

9.2. Technical requirements#

conda create -n gee python
conda activate gee
conda install -c conda-forge mamba
mamba install -c conda-forge geemap pygis
jupyter lab

Open in Colab

# pip install pygis
import ee
import geemap
geemap.ee_initialize()

9.3. The map function#

myList = ee.List.sequence(1, 10)
print(myList.getInfo())
def computeSquares(number):
    return ee.Number(number).pow(2)


squares = myList.map(computeSquares)
print(squares.getInfo())
squares = myList.map(lambda number: ee.Number(number).pow(2))
print(squares.getInfo())

9.4. Creating cloud-free composites#

Map = geemap.Map()
fc = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017').filter(
    ee.Filter.eq('country_na', 'Netherlands')
)

Map.addLayer(fc, {'color': 'ff000000'}, "Netherlands")
Map.centerObject(fc)
Map
years = ee.List.sequence(2013, 2021)
def yearly_image(year):

    start_date = ee.Date.fromYMD(year, 1, 1)
    end_date = start_date.advance(1, "year")

    collection = (
        ee.ImageCollection('LANDSAT/LC08/C01/T1')
        .filterDate(start_date, end_date)
        .filterBounds(fc)
    )

    image = ee.Algorithms.Landsat.simpleComposite(collection).clipToCollection(fc)

    return image
images = years.map(yearly_image)
vis_params = {'bands': ['B5', 'B4', 'B3'], 'max': 128}
for index in range(0, 9):
    image = ee.Image(images.get(index))
    layer_name = "Year " + str(index + 2013)
    Map.addLayer(image, vis_params, layer_name)

9.5. Creating timeseries#

collection = ee.ImageCollection("COPERNICUS/S2_HARMONIZED").filterMetadata(
    'CLOUDY_PIXEL_PERCENTAGE', 'less_than', 10
)
start_date = '2016-01-01'
end_date = '2022-12-31'
region = ee.Geometry.BBox(-122.5549, 37.6968, -122.3446, 37.8111)
images = geemap.create_timeseries(
    collection, start_date, end_date, region, frequency='year', reducer='median'
)
images.size().getInfo()
Map = geemap.Map()

vis_params = {"min": 0, "max": 4000, "bands": ["B8", "B4", "B3"]}
labels = [str(y) for y in range(2016, 2023)]

Map.addLayer(images, vis_params, "Sentinel-2", False)
Map.add_time_slider(images, vis_params, time_interval=2, labels=labels)
Map.centerObject(region)
Map

9.6. NAIP timelapse#

Map = geemap.Map(center=[40, -100], zoom=4)
Map
roi = Map.user_roi
if roi is None:
    roi = ee.Geometry.BBox(-99.1019, 47.1274, -99.0334, 47.1562)
    Map.addLayer(roi)
    Map.centerObject(roi)
collection = geemap.naip_timeseries(roi, start_year=2009, end_year=2022, RGBN=True)
years = geemap.image_dates(collection, date_format='YYYY').getInfo()
print(years)
size = len(years)
images = collection.toList(size)
for i in range(size):
    image = ee.Image(images.get(i))
    Map.addLayer(image, {'bands': ['N', 'R', 'G']}, years[i])
Map
timelapse = geemap.naip_timelapse(
    roi,
    out_gif="naip.gif",
    bands=['N', 'R', 'G'],
    frames_per_second=3,
    title='NAIP Timelapse',
)
geemap.show_image(timelapse)

9.7. Landsat timelapse#

Map = geemap.Map()
Map
roi = Map.user_roi
if roi is None:
    roi = ee.Geometry.BBox(-74.7222, -8.5867, -74.1596, -8.2824)
    Map.addLayer(roi)
    Map.centerObject(roi)
timelapse = geemap.landsat_timelapse(
    roi,
    out_gif='landsat.gif',
    start_year=1984,
    end_year=2022,
    start_date='01-01',
    end_date='12-31',
    bands=['SWIR1', 'NIR', 'Red'],
    frames_per_second=5,
    title='Landsat Timelapse',
    progress_bar_color='blue',
    mp4=True,
)
geemap.show_image(timelapse)

Map = geemap.Map()
roi = ee.Geometry.BBox(-115.5541, 35.8044, -113.9035, 36.5581)
Map.addLayer(roi)
Map.centerObject(roi)
Map
timelapse = geemap.landsat_timelapse(
    roi,
    out_gif='las_vegas.gif',
    start_year=1984,
    end_year=2022,
    bands=['NIR', 'Red', 'Green'],
    frames_per_second=5,
    title='Las Vegas, NV',
    font_color='blue',
)
geemap.show_image(timelapse)

Map = geemap.Map()
roi = ee.Geometry.BBox(113.8252, 22.1988, 114.0851, 22.3497)
Map.addLayer(roi)
Map.centerObject(roi)
Map
timelapse = geemap.landsat_timelapse(
    roi,
    out_gif='hong_kong.gif',
    start_year=1990,
    end_year=2022,
    start_date='01-01',
    end_date='12-31',
    bands=['SWIR1', 'NIR', 'Red'],
    frames_per_second=3,
    title='Hong Kong',
)
geemap.show_image(timelapse)

9.8. Sentinel-1 timelapse#

Map = geemap.Map()
Map
roi = Map.user_roi
if roi is None:
    roi = ee.Geometry.BBox(117.1132, 3.5227, 117.2214, 3.5843)
    Map.addLayer(roi)
    Map.centerObject(roi)
timelapse = geemap.sentinel1_timelapse(
    roi,
    out_gif='sentinel1.gif',
    start_year=2019,
    end_year=2019,
    start_date='04-01',
    end_date='08-01',
    frequency='day',
    vis_params={"min": -30, "max": 0},
    palette="Greys",
    frames_per_second=3,
    title='Sentinel-1 Timelapse',
    add_colorbar=True,
    colorbar_bg_color='gray',
)
geemap.show_image(timelapse)

9.9. Sentinel-2 timelapse#

Map = geemap.Map()
Map
roi = Map.user_roi
if roi is None:
    roi = ee.Geometry.BBox(-74.7222, -8.5867, -74.1596, -8.2824)
    Map.addLayer(roi)
    Map.centerObject(roi)
timelapse = geemap.sentinel2_timelapse(
    roi,
    out_gif='sentinel2.gif',
    start_year=2016,
    end_year=2021,
    start_date='01-01',
    end_date='12-31',
    frequency='year',
    bands=['SWIR1', 'NIR', 'Red'],
    frames_per_second=3,
    title='Sentinel-2 Timelapse',
)
geemap.show_image(timelapse)

9.10. MODIS timelapse#

9.10.1. MODIS NDVI#

Map = geemap.Map()
Map
roi = Map.user_roi
if roi is None:
    roi = ee.Geometry.BBox(-18.6983, -36.1630, 52.2293, 38.1446)
    Map.addLayer(roi)
    Map.centerObject(roi)
timelapse = geemap.modis_ndvi_timelapse(
    roi,
    out_gif='ndvi.gif',
    data='Terra',
    band='NDVI',
    start_date='2000-01-01',
    end_date='2021-12-31',
    frames_per_second=3,
    title='MODIS NDVI Timelapse',
    overlay_data='countries',
)
geemap.show_image(timelapse)

9.10.2. MODIS temperature#

Map = geemap.Map()
Map
roi = Map.user_roi
if roi is None:
    roi = ee.Geometry.BBox(-171.21, -57.13, 177.53, 79.99)
    Map.addLayer(roi)
    Map.centerObject(roi)
timelapse = geemap.modis_ocean_color_timelapse(
    satellite='Aqua',
    start_date='2018-01-01',
    end_date='2020-12-31',
    roi=roi,
    frequency='month',
    out_gif='temperature.gif',
    overlay_data='continents',
    overlay_color='yellow',
    overlay_opacity=0.5,
)
geemap.show_image(timelapse)

9.11. GOES timelapse#

Map = geemap.Map()
Map
roi = Map.user_roi
if roi is None:
    roi = ee.Geometry.BBox(167.1898, -28.5757, 202.6258, -12.4411)
    Map.addLayer(roi)
    Map.centerObject(roi)
start_date = "2022-01-15T03:00:00"
end_date = "2022-01-15T07:00:00"
data = "GOES-17"
scan = "full_disk"
timelapse = geemap.goes_timelapse(
    roi, "goes.gif", start_date, end_date, data, scan, framesPerSecond=5
)
geemap.show_image(timelapse)

roi = ee.Geometry.BBox(-159.5954, 24.5178, -114.2438, 60.4088)
start_date = "2021-10-24T14:00:00"
end_date = "2021-10-25T01:00:00"
data = "GOES-17"
scan = "full_disk"
timelapse = geemap.goes_timelapse(
    roi, "hurricane.gif", start_date, end_date, data, scan, framesPerSecond=5
)
geemap.show_image(timelapse)

Map = geemap.Map()
roi = ee.Geometry.BBox(-121.0034, 36.8488, -117.9052, 39.0490)
Map.addLayer(roi)
Map.centerObject(roi)
Map
start_date = "2020-09-05T15:00:00"
end_date = "2020-09-06T02:00:00"
data = "GOES-17"
scan = "full_disk"
timelapse = geemap.goes_fire_timelapse(
    roi, "fire.gif", start_date, end_date, data, scan, framesPerSecond=5
)
geemap.show_image(timelapse)

9.12. Fading effects#

in_gif = "https://i.imgur.com/ZWSZC5z.gif"
geemap.show_image(in_gif)
out_gif = "gif_fading.gif"
geemap.gif_fading(in_gif, out_gif, verbose=False)
geemap.show_image(out_gif)

roi = ee.Geometry.BBox(-69.3154, -22.8371, -69.1900, -22.7614)
timelapse = geemap.landsat_timelapse(
    roi,
    out_gif='mines.gif',
    start_year=2004,
    end_year=2010,
    frames_per_second=1,
    title='Copper mines, Chile',
    fading=True,
)
geemap.show_image(timelapse)

9.13. Adding animated text#

9.13.1. Add animated text to an existing GIF#

in_gif = os.path.abspath('../data/animation.gif')
out_dir = os.path.join(os.path.expanduser('~'), 'Downloads')
out_gif = os.path.join(out_dir, 'output.gif')
if not os.path.exists(out_dir):
    os.makedirs(out_dir)
geemap.show_image(in_gif)

9.13.1.1. Add animated text to GIF#

geemap.add_text_to_gif(
    in_gif,
    out_gif,
    xy=('5%', '5%'),
    text_sequence=1984,
    font_size=30,
    font_color='#0000ff',
    duration=100,
)
geemap.show_image(out_gif)

9.13.1.2. Add place name#

geemap.add_text_to_gif(
    out_gif, out_gif, xy=('30%', '85%'), text_sequence="Las Vegas", font_color='black'
)
geemap.show_image(out_gif)

9.13.1.3. Change font type#

geemap.system_fonts()
geemap.add_text_to_gif(
    in_gif,
    out_gif,
    xy=('5%', '5%'),
    text_sequence=1984,
    font_size=30,
    font_color='#0000ff',
    duration=100,
)
geemap.add_text_to_gif(
    out_gif,
    out_gif,
    xy=('30%', '85%'),
    text_sequence="Las Vegas",
    font_type="timesbd.ttf",
    font_size=30,
    font_color='black',
)
geemap.show_image(out_gif)

9.13.2. Create GIF from Earth Engine data#

9.13.2.1. Prepare for an ImageCollection#

import ee
import geemap

ee.Initialize()

# Define an area of interest geometry with a global non-polar extent.
aoi = ee.Geometry.Polygon(
    [[[-179.0, 78.0], [-179.0, -58.0], [179.0, -58.0], [179.0, 78.0]]], None, False
)

# Import hourly predicted temperature image collection for northern winter
# solstice. Note that predictions extend for 384 hours; limit the collection
# to the first 24 hours.
tempCol = (
    ee.ImageCollection('NOAA/GFS0P25')
    .filterDate('2018-12-22', '2018-12-23')
    .limit(24)
    .select('temperature_2m_above_ground')
)

# Define arguments for animation function parameters.
videoArgs = {
    'dimensions': 768,
    'region': aoi,
    'framesPerSecond': 10,
    'crs': 'EPSG:3857',
    'min': -40.0,
    'max': 35.0,
    'palette': ['blue', 'purple', 'cyan', 'green', 'yellow', 'red'],
}

9.13.2.2. Save the GIF to local drive#

saved_gif = os.path.join(os.path.expanduser('~'), 'Downloads/temperature.gif')
geemap.download_ee_video(tempCol, videoArgs, saved_gif)
geemap.show_image(saved_gif)

9.13.2.3. Generate an hourly text sequence#

text = [str(n).zfill(2) + ":00" for n in range(0, 24)]
print(text)

9.13.2.4. Add text to GIF#

out_gif = os.path.join(os.path.expanduser('~'), 'Downloads/output2.gif')
geemap.add_text_to_gif(
    saved_gif,
    out_gif,
    xy=('3%', '5%'),
    text_sequence=text,
    font_size=30,
    font_color='#ffffff',
)
geemap.add_text_to_gif(
    out_gif,
    out_gif,
    xy=('32%', '92%'),
    text_sequence='NOAA GFS Hourly Temperature',
    font_color='white',
)
geemap.show_image(out_gif)

9.13.3. Adding colorbar to an image#

import geemap
import os
# geemap.update_package()

9.13.3.1. Download a GIF#

from geemap import *
url = 'https://i.imgur.com/MSde1om.gif'
download_file(url, 'temp.gif')
in_gif = os.path.join(out_dir, 'temp.gif')
show_image(in_gif)

9.13.3.2. Get image URLs#

noaa_logo = 'https://bit.ly/3ahJoMq'
ee_logo = 'https://i.imgur.com/Qbvacvm.jpg'

9.13.3.3. Set output GIF path#

out_gif = os.path.join(out_dir, 'output.gif')

9.13.3.4. Add images to GIF#

add_image_to_gif(
    in_gif, out_gif, in_image=noaa_logo, xy=('2%', '80%'), image_size=(80, 80)
)
add_image_to_gif(
    out_gif, out_gif, in_image=ee_logo, xy=('13%', '79%'), image_size=(85, 85)
)

9.13.3.5. Display output GIF#

show_image(out_gif)

9.13.3.6. Create a colorbar#

width = 250
height = 30
palette = ['blue', 'purple', 'cyan', 'green', 'yellow', 'red']
labels = [-40, 35]
colorbar = create_colorbar(
    width=width,
    height=height,
    palette=palette,
    vertical=False,
    add_labels=True,
    font_size=20,
    labels=labels,
)
show_image(colorbar)

9.13.3.7. Add colorbar to GIF#

add_image_to_gif(
    out_gif, out_gif, in_image=colorbar, xy=('69%', '89%'), image_size=(250, 250)
)
show_image(out_gif)

9.14. Summary#

9.15. References#