# Import modules
import ee
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pprint import pprint
# Modules required for example 4
import folium
import clipboard # !pip install clipboard
5 Time series at a point
# Trigger the authentication flow.
#ee.Authenticate()
# Initialize the library.
ee.Initialize()
# Define function to create dataframe from GEE data
def array_to_df(arr):
"""Function to convert list into dataframe"""
= pd.DataFrame(arr[1:])
df = arr[0]
df.columns 'time'] = pd.to_datetime(df['time'], unit='ms')
df[return df
Example 1: Tallgrass prairie vegetation index
Retrive and plot the enhanced vegetation index (EVI) for a point under grassland vegetation at the Konza Prairie
Product: MODIS
# Get collection for Modis 16-day
= ee.ImageCollection('MODIS/MCD43A4_006_EVI').filterDate('2021-01-01','2021-12-31')
MCD43A4 = MCD43A4.select('EVI') EVI
# Run this line to explore dataset details (output is long!)
pprint(EVI.getInfo())
# Define point of interest
= ee.Geometry.Point([-96.556316, 39.084535]) konza_point
# Get data for region
= EVI.getRegion(konza_point, scale=1).getInfo() konza_evi
# Run this line to inspect retrieved data (output is long!)
pprint(konza_evi)
# Convert array into dataframe
= array_to_df(konza_evi)
df_konza
# Save dataframe as a .CSV file
# df.to_csv('modis_evi.csv', index=False)
# Create figure to visualize time series
=(6,4))
plt.figure(figsize'EVI Konza 2021')
plt.title('time'], df_konza['EVI'], linestyle='-',
plt.plot(df_konza[=1, marker='o', color='green')
linewidth'Date')
plt.xlabel('EVI')
plt.ylabel(#plt.savefig('evi_figure.png', dpi=300)
plt.show()
Example 2: Drought index
Drought can be represented by a variety of indices, including soil moisture, potential atmopsheric demand, days without measurable precipitation, and indices that combine one or more of these variables. The Evaporative Demand Drought Index (EDDI) is inteded to represent the potential for drought (rather than the actual occurrence of drought).
In this exercise we will compare drought conditions for eastern and western Kansas during 2021 and 2022.
Product: GRIDMET DROUGHT
# Define locations
= ee.Geometry.Point([-95.317201, 38.588548]) # Near Ottawa, KS
eastern_ks = ee.Geometry.Point([-101.721117, 38.517258]) # Near Tribune, KS western_ks
# Load EDDI product
= ee.ImageCollection("GRIDMET/DROUGHT").filterDate('2021-01-01','2022-12-31')
gridmet_drought = gridmet_drought.select('eddi14d') eddi
# Get eddie for points
= eddi.getRegion(eastern_ks, scale=1).getInfo()
eastern_eddi = eddi.getRegion(western_ks, scale=1).getInfo() western_eddi
# Explore output
0:3] eastern_eddi[
[['id', 'longitude', 'latitude', 'time', 'eddi14d'],
['20210105',
-95.31720298383848,
38.588547875926515,
1609826400000,
-0.029999999329447746],
['20210110',
-95.31720298383848,
38.588547875926515,
1610258400000,
-1.0099999904632568]]
# Create dataframe for each point
= array_to_df(eastern_eddi)
df_eastern = array_to_df(western_eddi)
df_western
# Display a few rows
df_eastern.head()
# Save data to a comma-separated value file
# df.to_csv('eddi_14_day.csv', index=False)
id | longitude | latitude | time | eddi14d | |
---|---|---|---|---|---|
0 | 20210105 | -95.317203 | 38.588548 | 2021-01-05 06:00:00 | -0.03 |
1 | 20210110 | -95.317203 | 38.588548 | 2021-01-10 06:00:00 | -1.01 |
2 | 20210115 | -95.317203 | 38.588548 | 2021-01-15 06:00:00 | -0.03 |
3 | 20210120 | -95.317203 | 38.588548 | 2021-01-20 06:00:00 | 0.39 |
4 | 20210125 | -95.317203 | 38.588548 | 2021-01-25 06:00:00 | 0.39 |
# Create figure to compare EDDI for both points
=(6,4))
plt.figure(figsize'EDDI Kansas 2021-2022')
plt.title('time'], df_eastern['eddi14d'], linestyle='-', color='navy', label='Eastern KS')
plt.plot(df_eastern['time'], df_western['eddi14d'], linestyle='-', color='tomato', label='Western KS')
plt.plot(df_western[
plt.legend()'14-day EDDI', size=14)
plt.ylabel( plt.show()
# Compute difference. If negative, that means that drought potential is greater in
# western Kansas
=(6,4))
plt.figure(figsize'EDDI Difference eastern-western Kansas')
plt.title('time'], df_eastern['eddi14d']-df_western['eddi14d'], linestyle='-', color='navy')
plt.plot(df_eastern[0, linestyle='--', color='k')
plt.axhline('14-day EDDI', size=14)
plt.ylabel( plt.show()
Example 3: Irrigated vs rainfed corn vegetation index
# Define points
= {'latitude': [38.7640, 38.7628, 38.7787, 38.7642, 38.7162, 38.7783],
data 'longitude':[-101.8946, -101.8069, -101.6937, -101.9922, -101.8284, -101.9919],
'irrigated':[True, True, True, False, False, False]}
= pd.DataFrame(data)
df df.head()
latitude | longitude | irrigated | |
---|---|---|---|
0 | 38.7640 | -101.8946 | True |
1 | 38.7628 | -101.8069 | True |
2 | 38.7787 | -101.6937 | True |
3 | 38.7642 | -101.9922 | False |
4 | 38.7162 | -101.8284 | False |
# Get product
= ee.ImageCollection("MODIS/061/MOD13Q1").filterDate(ee.Date("2022-04-01"),ee.Date("2022-11-15")) MOD13Q1
Since in this particular exercise we have multiple locations, one simple solution is to iterate over each point and request the time series of NDVI.
# Iterate over each point and retrieve NDVI
={}
ndvi
for k, row in df.iterrows():
= ee.Geometry.Point(row['longitude'], row['latitude'])
point = MOD13Q1.select('NDVI').getRegion(point, 0.01).getInfo()
result = np.transpose(result)
result_in_colums f"field_{k+1}"] = result_in_colums[4][1:]
ndvi[= result_in_colums[0][1:]
dates
# Create Dataframe with the NDVI data for each field
= pd.DataFrame(ndvi,dtype=float)
df_ndvi
# Add dates as index
= pd.to_datetime(dates, format='%Y_%m_%d')
df_ndvi.index
# Apply conversion factor
= df_ndvi*0.0001
df_ndvi
df_ndvi.head()
field_1 | field_2 | field_3 | field_4 | field_5 | field_6 | |
---|---|---|---|---|---|---|
2022-04-07 | 0.1933 | 0.2024 | 0.2222 | 0.2934 | 0.2032 | 0.2007 |
2022-04-23 | 0.2118 | 0.2178 | 0.1972 | 0.2785 | 0.2104 | 0.2107 |
2022-05-09 | 0.1824 | 0.2039 | 0.2220 | 0.2328 | 0.1959 | 0.1827 |
2022-05-25 | 0.2440 | 0.2056 | 0.2632 | 0.2115 | 0.1943 | 0.1902 |
2022-06-10 | 0.3325 | 0.2236 | 0.2235 | 0.2186 | 0.2033 | 0.2054 |
=(6,4))
df_ndvi.plot(figsize'NDVI Irrigated vs Rainfed Corn in Kansas')
plt.title('Date')
plt.xlabel('NDVI')
plt.ylabel( plt.show()
Example 4: Interactive selection
In this example we will leverage the interactive functionality of the Folium library and the computer’s clipboard to get geographic coordinates with a mouse click and then retrieve time series of a vegetation index using GEE.
# Define function to create raster map
# Declare a function (blueprint)
def create_raster(ee_object, vis_params, name):
"""Function that creates a folium raster layer"""
= folium.raster_layers.TileLayer(ee_object.getMapId(vis_params)['tile_fetcher'].url_format,
raster =name,
name=True,
overlay=True,
control='Map Data © <a href="https://earthengine.google.com/">Google Earth Engine</a>')
attrreturn raster
# US Counties dataset
= ee.FeatureCollection("TIGER/2018/Counties")
US_counties
# Select county of interest
= '20'
state_FIP = 'Thomas'
county_name = US_counties.filter(ee.Filter.eq('STATEFP','20').And(ee.Filter.eq('NAME','Thomas')).And(ee.Filter.eq('GEOID','20193')))
county = county.getInfo() county_meta
### Select cropland datalayer ###
= '2018-01-01'
start_date = '2018-12-31'
end_date = ee.ImageCollection('USDA/NASS/CDL').filter(ee.Filter.date(start_date,end_date)).first()
CDL = CDL.select('cropland')
cropland
# Clip cropland layer to selected county
= cropland.clip(county)
county_cropland
### Select vegetation index (vi) ###
= 'EVI' # or 'NDVI'
band
# Define start and end of time series for vegetation index
= '2017-10-15'
start_date_vi = '2018-06-15'
end_date_vi
# Request dataset and band
= ee.ImageCollection('MODIS/MCD43A4_006_EVI').filterDate(start_date_vi,end_date_vi)
MCD43A4 = MCD43A4.select('EVI') vi
# Get county boundaries
= float(county_meta['features'][0]['properties']['INTPTLAT'])
location_lat = float(county_meta['features'][0]['properties']['INTPTLON'])
location_lon
# Visualize county boundaries
= folium.Map(location=[location_lat, location_lon], zoom_start=10)
m
# Add click event to paste coordinates into the clipboard
=False))
m.add_child(folium.ClickForLatLng(alert
m.add_child(folium.LatLngPopup())
# Create raster using function defined earlier and add map
'cropland').add_to(m)
create_raster(county_cropland, {},
folium.GeoJson(county.getInfo(),='County boundary',
name=lambda feature: {
style_function'fillColor': 'None',
'color': 'black',
'weight': 2,
'dashArray': '5, 5'
}).add_to(m)
# Add some controls
folium.LayerControl().add_to(m)
# Display map
m
= eval(clipboard.paste())
lat, lon print(lat, lon)
# Define selected coordinates as point geometry
= ee.Geometry.Point([lon, lat])
field_point
= EVI.getRegion(field_point, scale=1).getInfo()
point_evi = array_to_df(point_evi)
df_point
if 'df' not in locals():
= df_point
df else:
= pd.concat([df, df_point])
df
= df.groupby(by='time', as_index=False)['EVI'].median()
evi_mean 'smoothed'] = evi_mean['EVI'].rolling(window=15, min_periods=1, center=True).mean()
evi_mean[
# Create figure
=(8,4))
plt.figure(figsize'time'], evi_mean['smoothed'], color='tomato', linewidth=2)
plt.plot(evi_mean[for lat in df['latitude'].unique():
= df['latitude'] == lat
idx 'time'], df.loc[idx,'EVI'], linestyle='-', linewidth=1, color='gray')
plt.plot(df.loc[idx,
plt.show()
39.402244 -100.990448