# Import modules
import ee
import json
import requests
import matplotlib.pyplot as plt
from matplotlib import colors
import xarray as xr
import pandas as pd
10 Band computations
Active and passive remote sensors onboard orbitting satellites usually collect multiple spectral bands. The combination of several of these bands can often be used to characterize land surface features, like vegetation, water bodies, and wildfires.
In this example we will use the red and near infrared bands from Sentinel 2 satellite of the European Space Agency to compute the normalized difference vegetation index at 10-meter spatial resolution for a production field in Argentina.
# Authenticate
#ee.Authenticate()
# Initialize API
ee.Initialize()
# Import boundary for area of interest (aoi)
with open('../datasets/field_bnd_carmen.geojson') as file:
= json.load(file)
aoi_json
# Define the ee.Geometry
= ee.Geometry(aoi_json['features'][0]['geometry'])
aoi
# Create mask for field
= ee.Image.constant(1).clip(aoi).mask() mask
# Define start and end dates
# Summer for southern hemisphere, matching the soybean growing season
= '2023-01-10'
start_date = '2023-01-30' end_date
# Load Sentinel-2 image collection
= ee.ImageCollection('COPERNICUS/S2') \
S2 \
.filterDate(start_date, end_date) \
.filterBounds(aoi) filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20)) \
.'B8', 'B4']) # B8 is NIR, B4 is Red .select([
# Print the following line to explore the selected images
#S2.getInfo()['features']
def calculate_ndvi(image):
"""
Function to calculate NDVI for a single image.
"""
= image.normalizedDifference(['B8', 'B4']).rename('NDVI')
ndvi return image.addBands(ndvi)
# Apply the NDVI function to each image in the collection
= S2.map(calculate_ndvi) ndvi_collection
# Apply the function to add mean NDVI as a property
= ndvi_collection.reduce(ee.Reducer.mean())
ndvi_mean
# Mask ndvi image
= ndvi_mean.mask(mask) ndvi_mean
# Inspect resulting image (note the the new band is "NDVI_mean"
'NDVI_mean').getInfo() ndvi_mean.select(
{'type': 'Image',
'bands': [{'id': 'NDVI_mean',
'data_type': {'type': 'PixelType',
'precision': 'float',
'min': -1,
'max': 1},
'crs': 'EPSG:4326',
'crs_transform': [1, 0, 0, 0, 1, 0]}]}
# Get url link for image
= ndvi_mean.getDownloadUrl({'region': aoi,'scale':10,
image_url 'bands':['NDVI_mean'],
'crs': 'EPSG:4326',
'format': 'GEO_TIFF'})
# Request data using URL and save data as a new GeoTiff file
= requests.get(image_url)
response
# Save geotiff image to local drive
= '../outputs/field_carmen_ndvi.tif'
filename with open(filename, 'wb') as f:
f.write(response.content)
# Read saved geotiff image from local drive
= xr.open_dataarray(filename).squeeze() ndvi_raster
= pd.DataFrame(aoi_json['features'][0]['geometry']['coordinates'][0])
df = ['lon','lat']
df.columns 3) df.head(
lon | lat | |
---|---|---|
0 | -61.792900 | -33.750588 |
1 | -61.790372 | -33.753893 |
2 | -61.784847 | -33.750976 |
# Create colormap
= ['#FEFEFE','#CE7E45', '#DF923D', '#F1B555', '#FCD163', '#99B718', '#74A901',
hex_palette '#66A000', '#529400', '#3E8601', '#207401', '#056201', '#004C00', '#023B01',
'#012E01', '#011D01', '#011301']
# Use the built-in ListedColormap function to do the conversion
= colors.ListedColormap(hex_palette) rgb_cmap
# Create figure
=(8,4), cmap=rgb_cmap, add_colorbar=True,
ndvi_raster.plot.imshow(figsize={'label':'NDVI'})
cbar_kwargs
'lon'], df['lat'],'-k')
plt.plot(df['Field NDVI')
plt.title('Longitude')
plt.xlabel('Latitude')
plt.ylabel(
plt.tight_layout() plt.show()
We can also get the NDVI values and corresponding coordinates to create a contour plot to delineate areas of higher and lower vegetation values.
# Give arrays a shorter name
= ndvi_raster.coords['x']
X = ndvi_raster.coords['y']
Y = ndvi_raster.values
Z
plt.figure()'lon'], df['lat'],'-k', linewidth=2)
plt.plot(df[=8, linewidths=0.5, colors='k')
plt.contour(X, Y, Z, levels=8, cmap='Spectral')
plt.contourf(X, Y, Z, levels='NDVI')
plt.colorbar(label=15)
plt.xticks(rotation plt.show()