# Import modules
import ee
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import xarray as xr
import requests
import json
8 Reduce collection to time series
In geospatial analysis, collections of images are typically aggregated into images, but it is also possible to aggregate image collections in the form of a time series to visualize meaningful trends or patterns over a given area and time range.
This tutorial will guide you through the process of synthesizing each image in a collection of images into a single average value representing the entire region of interest, thus, creating a time series that reflects the mean value for a region over time.
Example 1: Mean vegetation dynamics for entire watershed
In this exercise we will reduce an image collection into a time series of average values of Enhanced Vegetation Index (EVI) for the region of interest over the specified date range.
# Trigger the authentication flow.
#ee.Authenticate()
# Initialize the library.
ee.Initialize()
# Read US watersheds using hydrologic unit codes (HUC)
= ee.FeatureCollection("USGS/WBD/2017/HUC12")
watersheds = watersheds.filter(ee.Filter.eq('huc12', '102701010204')).first().geometry()
mcdowell_creek = mcdowell_creek.getInfo() mcdowell_creek_geom
# Get collection for Terra Vegetation Indices 16-Day Global 500m
= '2021-01-01'
start_date = '2022-12-31'
end_date = ee.ImageCollection('MODIS/006/MOD13A1') \
collection \
.filterDate(start_date, end_date) 'EVI') .select(
The enxt step is to create a function that will be applied to each image of the ImageCollection. The function will aggregate all the pixels in the region of interest into a single average value. Since each image represent a day, the resulting average value will be associated with the date of the image, so that then we can create a time series.
# Function to apply reduceRegion to each image and extract the areal average EVI.
def compute_mean_evi(image):
= image.reduceRegion(
mean_evi =ee.Reducer.mean(),
reducer=mcdowell_creek,
geometry=500,
scale=1e9
maxPixels
)
# Get the date of the image.
= image.date().format('YYYY-MM-dd')
date
# Return a Feature with properties for mean EVI and date.
#return ee.Feature(None, {'meanEVI': mean_evi.get('EVI'), 'date': date})
return ee.Feature(None, {'EVI_avg': mean_evi.get('EVI'), 'date': date})
# Map the function over the collection.
= collection.map(compute_mean_evi) # This is a feature collection evi_means
# Convert the resulting Feature Collection to a list of dictionaries.
= ee.Reducer.toList(2)
reducer = ['date','EVI_avg']
selector = evi_means.reduceColumns(reducer, selector).values().getInfo() evi_data_list
# Convert the list of data to a pandas DataFrame for easy handling and visualization.
= pd.DataFrame(np.squeeze(evi_data_list), columns=['date','EVI_avg']).dropna()
df
# Apply factor to EVI
'EVI_avg'] = df['EVI_avg'].astype(float) * 0.0001
df[
# Convert dates to datetime format
'date'] = pd.to_datetime(df['date'])
df[
# Display a few rows
3) df.head(
date | EVI_avg | |
---|---|---|
0 | 2021-01-01 | 0.197894 |
1 | 2021-01-17 | 0.173088 |
2 | 2021-02-02 | 0.170202 |
# Create figure
=(8,3))
plt.figure(figsize'Kings Creek watershed 2022')
plt.title('date'], df['EVI_avg'])
plt.plot(df['Enhanced Vegetation Index')
plt.ylabel( plt.show()
Example 2: Mean ground water anomaly for entire aquifer
The Gravity Recovery and Climate Experiment (GRACE) mission utilizes a pair of satellites in tandem orbit to measure small variations in Earth’s gravitational pull. These variations are caused by changes in mass distribution, including water moving through the Earth’s system. As water accumulates or depletes in an area, such as in an aquifer, it alters the region’s gravitational attraction, which GRACE detects.
The application of GRACE data has been crucial in monitoring the Ogallala Aquifer, one of the largest aquifers in the world, stretching across eight states in the United States. Over-reliance on this aquifer for agricultural irrigation, municipal, and industrial water has led to substantial depletion in water levels. By capturing the changes in gravitational pull over the Ogallala region, GRACE has provided researchers and policymakers with essential data on the aquifer’s depletion rates.
# Read boundary of Ogalla Aquifer
with open('../datasets/ogallala_aquifer_bnd.geojson') as file:
= json.load(file)
roi_json
# Define the ee.Geometry
= ee.Geometry(roi_json['features'][0]['geometry'])
roi
# Create mask
= ee.Image.constant(1).clip(roi).mask() mask
# Get GRACE equivalent water thickeness anomaly
= ee.ImageCollection('NASA/GRACE/MASS_GRIDS/LAND') \
grace '2002-04-01', '2017-01-07') \
.filterDate(\
.filterBounds(roi) 'lwe_thickness_csr') .select(
# Create function to apply the reduceRegion() method to each image
def compute_mean_water(image):
= image.reduceRegion(
mean_water =ee.Reducer.mean(),
reducer=roi,
geometry=100_000,
scale=1e9
maxPixels
)
# Get the date of the image.
= image.date().format('YYYY-MM-dd')
date
# Return a Feature with properties for mean water thickness and date.
return ee.Feature(None, {'water_thickness_avg':mean_water.get('lwe_thickness_csr'),
'date': date})
# Apply the created function to each image in the collection
# This operation results in a FeatureCollection
= grace.map(compute_mean_water) mean_water_thickness
# Convert the resulting Feature Collection to a list of dictionaries.
= ee.Reducer.toList(2)
reducer = ['date','water_thickness_avg']
selector = mean_water_thickness.reduceColumns(reducer, selector).getInfo() data_list
# Convert the list of data to a pandas DataFrame for easy handling and visualization.
= pd.DataFrame(np.squeeze(data_list['list']),
df =['date','water_thickness_avg']).dropna()
columns
# Convert dates to datetime format
'date'] = pd.to_datetime(df['date'])
df[
'water_thickness_avg'] = df['water_thickness_avg'].astype(float)
df[
# Display a few rows
3) df.head(
date | water_thickness_avg | |
---|---|---|
0 | 2002-04-01 | 7.638767 |
1 | 2002-05-01 | 7.061499 |
2 | 2002-08-01 | -2.686608 |
# Create figure
=(8,3))
plt.figure(figsize'Ogallala aquifer')
plt.title('date'], df['water_thickness_avg'])
plt.plot(df['Equivalent Water Thickness Anomaly')
plt.ylabel( plt.show()