Code
setwd("..your working directory")
Set up a working directory and store the data files in that directory. Tell R that this is the directory you will be using, and read in your data:
setwd("..your working directory")
To do this laboratory you will need to install the following packages:
<- c("maptools", "rgdal", "raster", "neonUtilities", "rasterdiv",
packages "BiocManager", "tidyverse", "plyr", "reshape2")
# Package vector names
If you don’t want to install the packages one by one, you can use the next command.
# Install packages not yet installed
<- packages %in% rownames(installed.packages())
installed_packages
if (any(installed_packages == FALSE)) {
install.packages(packages[!installed_packages], dependencies = TRUE)
}
The package {rhdf5} is not available on CRAN, but it is located in “Bioconductor”.
When installing the package {rhdf5} R will ask you if you want to “Update all/some/none? [a/s/n]:” please in your console type n.
if ( ! ("rhdf5" %in% installed.packages())) {BiocManager::install("rhdf5")}
#BiocManager::install("rhdf5")
Call or load all packages
sapply(packages, require, character.only = TRUE)
library(rhdf5)
Double-check your working directory.
dir.create("Data")
dir.create("Data/NEON")
The first step is to prepare the information required to download the hyperspectral data from NEON-AOP. To do that we will first download the Terrestrial Observation System Sampling Locations dataset. You can download it from NEON Spatial Data & Maps, specifically under the Terrestrial Observation System Sampling Locations tab or by clicking HERE. Once you have downloaded the data, please store it within the folder NEON that is located within the folder Data
<- readOGR(dsn = "Data/NEON/All_NEON_TOS_Plots_v9",
NEON_plots layer = "All_NEON_TOS_Plot_Polygons_V9")
From the spatial distribution of the NEON sites/plots we loaded into R, we will select the NEON site Harvard Forest & Quabbin Watershed (HARV).
<- NEON_plots@data %>%
HARV_plots filter(siteID == "HARV" & plotType == "distributed" & subtype == "basePlot") %>%
arrange(plotID)
view(HARV_plots)
Now from the NEON site HARV we will select the plot number one (plotID = HARV_001) and extract the coordinates in UTM (Universal Transverse Mercator) system as spatial reference to download the hyperspectral data from the NEON-AOP.
<- HARV_plots$easting
east names(east) <- HARV_plots$plotID
<- HARV_plots$northing
north names(north) <- HARV_plots$plotID
east
north
<- c(east[1], north[1])
coords_HARV_001 coords_HARV_001
Now we have the UTM coordinates from the plot HARV_001 we can download the Hyperspectral Remote Sensing Data in HDF5 Format for that site.
byTileAOP(dpID = "DP3.30006.001", # NEON-AOP product
site = "HARV", # Site code
year = "2019", # Year
check.size = TRUE,
easting = coords_HARV_001[1], northing = coords_HARV_001[2], # Coordinates UTM
savepath = "Data/NEON", # Path
token = NA)
When you are downloading the Hyperspectral imagery {R} will ask you if you want to download the data please in your console type y.
We are now ready for start using hyperspectral data. Note that the downloaded data is in a HDF5 format, this format natively compresses data stored within it (i.e., makes it smaller) and supports data slicing, in other words, you can extract only the portions of the data that you need to work with rather than reading the entire dataset into ypur computer memory.
The downloaded hyperspectral data is stored within a folder DP3.30006.001 that in turn is stored within the folder scheme Data/Neon. Please pay attention to the full folder scheme. This scheme is composed of several folders with a file NEON_D01_HARV_DP3_725000_4700000_reflectance.h5 in HDF5 format. In order to load and work with this data you might need to specify the full path to that file.
<- "Data/NEON/DP3.30006.001/neon-aop-products/2019/FullSite/D01/2019_HARV_6/L3/Spectrometer/Reflectance/NEON_D01_HARV_DP3_725000_4700000_reflectance.h5" f
Note that you did not loaded all hyperspectral data into R but the path to the file, so using the path we can just call the metadata of the downloaded data.
When we are exploring the data structure in a HDF5 file, we really need to pay attention to the first two columns, these two columns is informing us about the location of the data (group) and the name of the data (name) stored into the file. For example the Map_info dataset is located in /HARV/Reflectance/Metadata/Coordinate_System and the Reflectance dataset under /HARV.
The wavelength dataset contains the middle wavelength values for each band in the dataset and the Reflectance dataset contains the image data, these two datasets are going to be used for both data processing and visualization.
View(h5ls(f, all = TRUE))
A band represents a group of wavelengths. For example, the wavelength values between 695 nm and 700 nm might be one band as captured by an imaging spectrometer. The imaging spectrometer collects reflected light energy in a pixel for light in that band. When we are working with a multispectral (e.g., Landsat, MODIS) or hyperspectral (e.g., NEON-AOP - NASA/JPL AVIRIS-NG) dataset, the band information is reported as the center wavelength value. This value represents the center point value of the wavelengths represented in that band. Thus in a band spanning 695-700 nm, the center would be 697.5 nm.
# Get information about the wavelengths of HARV plot 001
<- h5readAttributes(f, "/HARV/Reflectance/Metadata/Spectral_Data/Wavelength")
wlInfo
wlInfo
To read the wavelenghts of our hyperspectral image we just use the function {h5read}
<- h5read(f, "/HARV/Reflectance/Metadata/Spectral_Data/Wavelength")
WL
head(WL)
tail(WL)
To extract the full metadata of the hyperspectral image we use the function {h5readAttributes}. Please, read the content of the the metadata carefully.
<- h5readAttributes(f, "/HARV/Reflectance/Reflectance_Data")
reflInfo
reflInfo
For example, the center wavelength value associated with the band 34 is 549.0242
34] WL[
Importnatly, the {h5read} function reads data in the order: Bands, Cols, Rows. Let’s get these information from the reflectance metadata.
<- reflInfo$Dimensions[1]
nRows <- reflInfo$Dimensions[2]
nCols <- reflInfo$Dimensions[3]
nBands
nRows
nCols nBands
Now using the the information obtained from the reflectance metadata let’s extract the band 34. You can try other band if you prefere.
<- h5read(f, "/HARV/Reflectance/Reflectance_Data",
b34 index = list(34, 1:nCols, 1:nRows)) # get band 34
# what type of object is b34?
class(b34)
## [1] "array"
The returned object is an array, the arrays are matrices with more than 2 dimensions, i.e., are matrices stacked or piled in a single object.
# convert from array to matrix by selecting only the first band
<- b34[1,, ]
b34
# check it
class(b34)
Now we can plot the image of band 34.
image(b34)
The previous image is hard to visually interpret, let’s log the data and see what happens.
image(log(b34))
An image data in raster format will often contain a data ignore value and a scale factor. The data ignore value represents pixels where there are no data. Usually, no data values may be attributed to the sensor not collecting data in the area of the image or to processing results which yield null values.
From the reflectance metadata we can define the ignore value as -9999. Thus, let’s set all pixels with a value == -9999 to NA (no value).
# there is NO data value in our raster - let's define it
<- as.numeric(reflInfo$Data_Ignore_Value)
myNoDataValue
myNoDataValue
# set all values equal to -9999 to NA
== myNoDataValue] <- NA
b34[b34
# plot the image now
image(b34)
In order to get a raster file suitable for further analysis, we first need to define the Coordinate reference system (CRS) of the raster. Again, we obtain the necessary information form the HDF5 file.
# Extract the EPSG from the h5 dataset
<- h5read(f, "/HARV/Reflectance/Metadata/Coordinate_System/EPSG Code")
myEPSG
myEPSG
# convert the EPSG code to a CRS string
<- crs(paste0("+init=epsg:", myEPSG))
myCRS
myCRS
Define final raster with projection info.
<- raster(b34, crs = myCRS)
b34ras
# view the raster attributes
b34ras
Let’s take a look at the georeferenced raster. Take note of the coordinates on the x and y axis.
image(log(b34ras),
xlab = "UTM Easting",
ylab = "UTM Northing",
main = "Properly Oriented Raster")
Next we define the extents of our raster. The extents will be used to calculate the raster’s resolution. We get this information from the reflectance information obtained in a previous step.
# Grab the UTM coordinates of the spatial extent
<- reflInfo$Spatial_Extent_meters[1]
xMin <- reflInfo$Spatial_Extent_meters[2]
xMax <- reflInfo$Spatial_Extent_meters[3]
yMin <- reflInfo$Spatial_Extent_meters[4] yMax
Define the spatial extent of the raster image
# define the extent (left, right, top, bottom)
<- extent(xMin, xMax, yMin, yMax)
rasExt
# view the extent to make sure that it looks right
rasExt
Assign the spatial extent to the raster
extent(b34ras) <- rasExt
# look at raster attributes
b34ras
Visualize the raster file but now let’s change the colors by adjusting the zlims.
<- terrain.colors(25)
col
image(b34ras,
xlab = "UTM Easting",
ylab = "UTM Northing",
main = "Raster with Custom Colors",
col = col,
zlim = c(0, 1000))
We can now save the created raster.
# write out the raster as a geotiff
writeRaster(b34ras,
file = "Data/NEON/DP3.30006.001/HARV_plot_001_band_34.tif",
format = "GTiff",
overwrite = TRUE)
In the previous step we created a raster file of a single band, but each hyperspectral data from the NEON-AOP contains 426 bands. In this step we will construct a raster stack file, i.e., a raster with N bands, in other words, a raster of rasters. You can do it manually as we did for the band 34, but let’s take advantage of R and write a function that do the work for us. Please, take your time to read and understand the function.
# file: the hdf file
# band: the band you want to process
# noDataValue: values to be omitted
# extent: raster extent
# CRS: coordinates system
# returns: a matrix containing the reflectance data for the specific band
<- function(file, band, noDataValue, extent, CRS){
band2Raster # first, read in the raster
<- h5read(file, "/HARV/Reflectance/Reflectance_Data",
out index = list(band, NULL, NULL)) # path to the HDF5 file
# Convert from array to matrix
<- (out[1,, ]) # output
out # transpose data to fix flipped row and column order
# depending upon how your data are formatted you might not have to perform this
# step.
<- t(out)
out # assign data ignore values to NA
# note, you might chose to assign values of 15000 to NA
== myNoDataValue] <- NA
out[out
# turn the out object into a raster
<- raster(out, crs = CRS)
outr
# assign the extents to the raster
extent(outr) <- extent
# return the raster object
return(outr)
}
Now apply the function to create a RGB raster file, to do this, we will use the bands 58, 34 and 19, respectively.
# create a list of the bands we want in our stack
<- list(58, 34, 19)
rgb
# lapply tells R to apply the function to each element in the list
<- lapply(rgb, FUN = band2Raster, file = f,
rgb_harv noDataValue = myNoDataValue,
extent = rasExt,
CRS = myCRS)
# check out the properties or rgb_rast
# note that it displays properties of 3 rasters.
rgb_harv
Success!!! 🎉🎉🎉 we created a list of three rasters. Now in order to get the raster stack just apply the function stack() from the package {raster}.
# Create a raster stack from our list of rasters
<- stack(rgb_harv)
rgb_harv_stack
rgb_harv_stack
As a final step, let’s assign the names of the bands to the raster stack object.
# Create a list of band names
<- paste("Band_", unlist(rgb), sep = "")
bandNames
# set the rasterStack's names equal to the list of bandNames created above
names(rgb_harv_stack) <- bandNames
# check properties of the raster list - note the band names
rgb_harv_stack
# scale the data as specified in the reflInfo$Scale Factor
<- rgb_harv_stack/as.integer(reflInfo$Scale_Factor)
rgb_harv_stack
# plot one raster in the stack to make sure things look OK.
plot(rgb_harv_stack$Band_58, main = "Band 58")
And plot resulting RGB raster.
# create a 3 band RGB image
plotRGB(rgb_harv_stack,
r = 1, g = 2, b = 3,
stretch = "lin")
Cool, right?
As we did with the band 34, let’s save the RGB raster in a GeoTIFF format.
# write out final raster
writeRaster(rgb_harv_stack,
file = "Data/NEON/DP3.30006.001/HARV_plot_001_RGB.tif",
format = "GTiff",
overwrite = TRUE)
Now, we will calculate vegetation indices, specifically, we will calculate the Normalized Difference Vegetation Index (NDVI).
The \(NDVI\) is computed as the difference between near-infrared (\(NIR\)) and red (\(RED\)) reflectance divided by their sum.:
\[NDVI = \frac{NIR - R}{NIR + R}\]
To calculate the NDVI from the NEON-AOP hyperspectral data, first select the bands 58 (red) and 90 (NIR) and then create a raster stack as we did for the RGB raster.
# select bands to use in calculation (red, NIR)
<- c(58, 90) #bands c(58, 90) in full NEON hyperspectral dataset
ndvi_bands
# create raster list and then a stack using those two bands
<- lapply(ndvi_bands,
ndvi_harv FUN = band2Raster,
file = f,
noDataValue = myNoDataValue,
extent = rasExt,
CRS = myCRS)
<- stack(ndvi_harv)
ndvi_harv
# make the names pretty
<- paste("Band_", unlist(ndvi_bands), sep = "")
bandNDVINames names(ndvi_harv) <- bandNDVINames
# view the properties of the new raster stack
ndvi_harv
Write a function for NDVI calculation.
#calculate NDVI
<- function(ras) {
NDVI_func 2] - ras[, 1])/(ras[, 2] + ras[, 1])
(ras[, }
Apply the function and plot the result.
<- calc(ndvi_harv, fun = NDVI_func)
ndvi_calc
plot(ndvi_calc, main = "NDVI for the NEON HARV Field Site")
Now, play with breaks and colors to create a meaningful map add a color map with 4 colors.
<- rev(terrain.colors(4)) # use the 'rev()' function to put green as the highest NDVI value
myCol # add breaks to the colormap, including lowest and highest values (4 breaks = 3 segments)
<- c(0, .25, .5, .75, 1)
brk
# plot the image using breaks
plot(ndvi_calc, main = "NDVI for the NEON HARV Field Site", col = myCol, breaks = brk)
We can save the resulting NDVI raster.
writeRaster(ndvi_calc, file = "Data/NEON/DP3.30006.001/HARV_plot_001_NDVI.tif",
format = "GTiff", overwrite = TRUE)
Now we will extract all reflectance values for a selected pixel in the hyperspectral data from HARV and use this values to plot its spectral signatures. For practice purpose we will select a pixel at the position (100, 35), in other words, we are selecting the pixel at the row 100 and column 35. In addition to get the the reflectance for all bands we need to inform an empty space (as NULL).
# extract all bands from a single pixel
<- h5read(f, "/HARV/Reflectance/Reflectance_Data", index = list(NULL, 100, 35))
aPixel
class(aPixel)
# The line above generates a vector of reflectance values.
# Next, we reshape the data and turn them into a dataframe
<- adply(aPixel, c(1))
b
class(b)
# create clean data frame
<- b[2]
aPixeldf
# add wavelength data to matrix
$Wavelength <- WL
aPixeldf
head(aPixeldf)
Now select the scale factor from the reflectance object and scale the reflectance values for all bands.
<- reflInfo$Scale_Factor
scaleFact
# add scaled data column to the data frame
$scaled <- (aPixeldf$V1/as.vector(scaleFact))
aPixeldf
# make nice column names
names(aPixeldf) <- c('Reflectance', 'Wavelength', 'ScaledReflectance')
head(aPixeldf)
tail(aPixeldf)
As a last step let’s plot the scaled reflectance as a function of the wavelength.
%>%
aPixeldf ggplot(aes(x = Wavelength, y = ScaledReflectance)) +
geom_line() +
xlab("Wavelength (nm)") +
ylab("Reflectance")
In the previous step we selected and arbitrary pixel at (100, 35), however when we are working with real data we might need to have the spatial position of objects on the ground (e.g., GPS points).
We will use the exact geographical position of tree species in the HARV site. To do that, we will need to install two more packages that are not in CRAN but on GitHub. The packages are geoNEON and neonhs
First install and call the package geoNEON
# install the package {geoNEON}
::install_github('NEONScience/NEON-geolocation/geoNEON', dependencies = TRUE)
remotes
library(geoNEON)
Now download the data from woody plant vegetation from NEON.
# Download Woody plant vegetation structure from NEON #####
zipsByProduct(
dpID = "DP1.10098.001",
site = "HARV",
savepath = "Data/NEON",
check.size = FALSE
)
## Combine the files
stackByTable("Data/NEON/filesToStack10098", folder = TRUE)
The function {def.calc.geo.os} will refine the geolocation data associated with NEON data products.
# Calculate the more precise location for each NEON plot in the HARV site
<- "Data/NEON/filesToStack10098/stackedFiles/vst_mappingandtagging.csv" %>%
vegmap read_csv() %>%
mutate(year = substr(date, 1, 4)) %>%
filter(year == '2019') %>%
def.calc.geo.os("vst_mappingandtagging") # Calculate more precise geolocations for specific NEON data products
# Load individual tree coordinates
<- read_csv("Data/NEON/filesToStack10098/stackedFiles/vst_apparentindividual.csv")
vegind
# Combine the coordinates with three identification
<- right_join(vegind, vegmap,
veg by = c("individualID", "namedLocation", "domainID", "siteID", "plotID")) %>%
filter(!is.na(adjEasting), !is.na(adjNorthing), plantStatus == "Live")
Now select the individual trees available for the plot HARV_001 and transform it into a spatial object.
<- veg %>%
harv_01_trees select(adjNorthing, adjEasting, scientificName, plotID,
%>%
adjDecimalLatitude, adjDecimalLongitude) filter(plotID == "HARV_001")
<- SpatialPointsDataFrame(coords = harv_01_trees[, 2:1],
harv_01_trees_spt data = harv_01_trees,
proj4string = crs(ndvi_calc))
The plot HARV_001 is composed by four species and 38 individuals. You can verify that information.
unique(harv_01_trees$scientificName)
length(harv_01_trees$scientificName)
Plot the results
plot(ndvi_harv[[1]])
plot(harv_01_trees_spt, add = TRUE)
This is not over, now we will extract the spectral information for each of our trees in the plot HARV_001. For this we will use the R package {neonhs}
First install and call the package neonhs
::install_github('earthlab/neonhs')
remoteslibrary(neonhs)
Extract the spectra data associated with each tree species.
# Path to access the hyperspectral data
<- list.files(
hs_path_2019 path = "Data/NEON/DP3.30006.001/neon-aop-products/2019/",
pattern = "reflectance.h5",
recursive = TRUE, full.names = TRUE
)
# extract the spectra data
<- neonhs::hs_extract_pts(filename = hs_path_2019, # path to the h5 file
resHARV_001 pts = harv_01_trees_spt, # spatial points
bands = 1:426) # which bands
resHARV_001
The object with the spectral data is a SpatialPointsDataFrame we need to transform it into a data.frame to continue working with the spectra.
<- as.data.frame(resHARV_001) %>%
resHARV_001_df bind_rows() %>%
as_tibble() %>%
::select(!c("band418_2472nm", "band419_2477nm", "band420_2482nm", "band421_2487nm",
dplyr"band422_2492nm", "band423_2497nm", "band424_2502nm", "band425_2507nm",
"band426_2512nm", "adjEasting.1", "adjNorthing.1")) %>%
::select(plotID, scientificName, adjNorthing, adjEasting, adjDecimalLongitude, adjDecimalLatitude, everything())
dplyr
resHARV_001_df
Let’s perform a bit of cleaning…
<- resHARV_001_df %>%
resHARV_001_df_long ::select(!c(plotID, adjNorthing, adjEasting, adjDecimalLongitude, adjDecimalLatitude)) %>%
dplyr::melt(id.vars = "scientificName",
reshape2variable.name = "Wavelength",
value.name = "Reflectance")
<- resHARV_001_df_long %>%
resHARV_001_df_long mutate(Wavelength2 = Wavelength) %>%
separate(Wavelength2, into = c("bands", "wl"), sep = "_") %>%
mutate(WL = as.numeric(gsub("[nm]", "", wl))) %>%
mutate(scientificName = as.factor(scientificName))
Now let’s plot the results…
# Aux function for visualization
<- function() {
theme_nice theme_bw() + #base_family = "Noto Sans") +
theme(panel.grid.minor = element_blank(),
plot.background = element_rect(fill = "white", color = NA),
#plot.title = element_text(face = "bold"),
#strip.text = element_text(face = "bold"),
strip.background = element_rect(fill = "grey80", color = NA),
legend.title = element_text(face = "bold", size = 15),
legend.text = element_text(size = 12))
}
# plot the spectra by species
%>%
resHARV_001_df_long drop_na() %>%
#filter(scientificName == "Acer rubrum L.") %>%
ggplot() +
geom_line(aes(x = WL, y = Reflectance, color = scientificName)) +
scale_color_viridis_d(option = "A",
labels = c("Acer rubrum", "Betula lenta", "Pinus strobus", "Quercus rubra")) +
xlab("Wavelength (nm)") +
ylab("Reflectance") +
theme_nice()
Cool! we just made a plot with the spectral signatures for four species at HARV site, but there are some anomalies in the plot which difficult its interpretation. Those anomalies around 1400 nm and 1850 nm correspond to two major atmospheric absorption bands, i.e., regions in the spectra where gasses in the atmosphere (primarily carbon dioxide and water vapor) absorb radiation, and therefore, obscure the reflected radiation that the imaging spectrometer measures.
To eliminate those anomalies we first might need to select and eliminate those bands manually. Happily, the reflectance metadata contains the lower and upper bound of each of those atmospheric absorption bands. Let’s read those bands and plot rectangles where the reflectance measurements are obscured by atmospheric absorbtion.
# grab Reflectance metadata (which contains absorption band limits)
<- h5readAttributes(f, "/HARV/Reflectance" )
reflMetadata
<- reflMetadata$Band_Window_1_Nanometers
ab1 <- reflMetadata$Band_Window_2_Nanometers
ab2
ab1 ab2
Plot spectral signatures again with rectangles showing the absorption bands
%>%
resHARV_001_df_long drop_na() %>%
ggplot() +
geom_line(aes(x = WL, y = Reflectance, color = scientificName)) +
scale_color_viridis_d(option = "A",
labels = c("Acer rubrum", "Betula lenta", "Pinus strobus", "Quercus rubra")) +
geom_rect(mapping = aes(ymin = min(Reflectance),
ymax = max(Reflectance),
xmin = ab1[1], xmax = ab1[2]),
color = "darkgray", fill = "gray", alpha = 0.7) +
geom_rect(mapping = aes(ymin = min(Reflectance),
ymax = max(Reflectance),
xmin = ab2[1], xmax = ab2[2]),
color = "darkgray", fill = "gray", alpha = 0.7) +
xlab("Wavelength (nm)") +
ylab("Reflectance") +
theme_nice()
By inspecting the plot we can confirm that the sections of the spectra with anomalies are within the atmospheric absorption bands. Using the absorption band limits we can remove the sections with anomalies and plot masked spectral signatures for the four species.
# Duplicate the spectral signatures into a new data.frame
<- resHARV_001_df_long
resHARV_001_df_long_mask
# Mask out all values within each of the two atmospheric absorbtion bands
$WL >
resHARV_001_df_long_mask[resHARV_001_df_long_mask1] & resHARV_001_df_long_mask$WL < ab1[2], ]$Reflectance <- NA
ab1[
$WL >
resHARV_001_df_long_mask[resHARV_001_df_long_mask1] & resHARV_001_df_long_mask$WL < ab2[2], ]$Reflectance <- NA
ab2[
head(resHARV_001_df_long_mask)
Plot the masked spectral signatures
%>%
resHARV_001_df_long_mask ggplot() +
geom_line(aes(x = WL, y = Reflectance, color = scientificName)) +
scale_color_viridis_d(option = "A",
labels = c("Acer rubrum", "Betula lenta", "Pinus strobus", "Quercus rubra")) +
xlab("Wavelength (nm)") +
ylab("Reflectance") +
theme_nice()
It’s always good practice to close the H5 connection before moving on.
# close the H5 file
H5close()
Clean your R environment.
rm(list = ls())
As a final exercise we will estimate some diversity metrics directly from the results obtained in the previous steps. Specifically we will use the NDVI raster we created before.
<- raster("Data/NEON/DP3.30006.001/HARV_plot_001_NDVI.tif")
harv_ndvi
plot(harv_ndvi)
Now using the NDVI raster we will estimate the Shannon and Hill diversity metrics for each pixel. To do that we will use the package {rasterdiv} (Thouverai et al., 2021). Given the spatial extent and resolution of the NDVI raster file, this process will take some time (~2 minutes in Jesús’s computer) to finish.
The Shannon’s diversity index is one of the most common metrics used to estimate diversity from remote sensing data. This index is calculated as:
\[H = -\sum_{n=1}^{N} p_i ln_b(p_i) = 1\]
Where \(p_i\) is the proportional abundance of pixel \(i\) and \(b\) is the base of the logarithm. It is most popular to use natural logarithms, but some argue for base \(b = 2\). Shannon’s H is a dimensionless metric, in other words, it consider differences in the relative abundance among pixel values, but not their relative spectral distance, i.e. the distance among spectral values (Thouverai et al., 2021).
In this example we are using a parallel computation which allow to obtain results quickly, however if you have some issues running this part, please remove the argument np = 10 from the code below.
library(doParallel)
# Computes Shannon's diversity index (H') on different classes of numeric matrices using a moving window algorithm.
<- rasterdiv::Shannon(x = harv_ndvi, # NDVI raster
HARV_shannon window = 5, # window size
np = 10 # Number of cores, if this don't work for you, just remove this line of code
)
Plot the results for Shannon’s diversity.
plot(HARV_shannon)
The Hill’s generalized entropy diversity index is based on the effective number of species (or pixels) of \(H\alpha\), i.e., the number of species that would lead to the diversity \(H\) if the species are equally abundant (Cavender-Bares et al., 2020; Scheiner et al., 2017). An important component in the Hill’s diversity is the \(\alpha\) component, thus, different orders of \(\alpha\) result in different diversity measures; for example, \(\alpha = 0\) is simply species richness, \(\alpha = 1\) gives the exponential of Shannon’s entropy index, and \(\alpha = 2\) gives the inverse of Simpson’s concentration index (Cavender-Bares et al., 2020).
\[H_\alpha = (\sum_{n=1}^{N} p_i^{\alpha})^\frac{1}{1-\alpha}\]
Let’s compute the Hill’s diversity with an \(\alpha = 1\) and compare the results with the Shannon’s metric.
# Computes Hill's index of diversity (Hill numbers) on different classes of numeric matrices using a moving window algorithm.
<- rasterdiv::Hill(harv_ndvi,
HARV_hill alpha = 1,
window = 5,
np = 10, # Number of cores, if this don't work for you, just remove this line of code
rasterOut = TRUE)
Plot the results
plot(HARV_hill[[1]])
Explore the correlation between the two rasters
cor.test(values(HARV_shannon), values(HARV_hill[[1]]))
As indicated before, when \(\alpha = 1\) in the Hill’s calculation it will resemble the exponential of Shannon’s entropy index.
That’s it!
This was a very long lab, and it will take sometime to digest all the information. Thus the challenge for this lab is simple. Prepare a document with all the figures generated in this tutorial.