Skip to content

Instantly share code, notes, and snippets.

@jslefche
Last active October 23, 2019 15:55
Show Gist options
  • Save jslefche/c480eeb2ad67ca7c9a46 to your computer and use it in GitHub Desktop.
Save jslefche/c480eeb2ad67ca7c9a46 to your computer and use it in GitHub Desktop.
Edgar Equations

Edgar Equations for Estimating Invertebrate Biomass from Size Structured Abundances

Generates estimates of ash-free dry weight from size-fractionated abundances of epifaunal invertebrates.

From:

Edgar, Graham J. "The use of the size structure of benthic macrofaunal communities to estimate faunal biomass
and secondary production." Journal of Experimental Marine Biology and Ecology 137.3 (1990): 195-214.

Example

set.seed(1)

example.data = cbind.data.frame(
  data.frame(
    sample = 1:40,
    temperature = runif(40, 20, 30),
    group = sample(c("Crustacean", "Mollusc", "Polychaete", "Caprellid"), 40, replace = TRUE)
    ), 
  matrix(rpois(40*9, 10), ncol = 9, dimnames = list(NULL, c(8, 5.6, 4, 2.8, 2, 1.4, 1, 0.71, 0.5)))
)
  
# Default settings
edgarMethod(example.data, group.colname = "group") 

# Remove sieve size < 1 mm from dataset
edgarMethod(example.data[, -(11:12)], "group")

# Use min.size argument instead of subsetting
edgarMethod(example.data, "group", min.size = 1)
#' `edgarMethod` an R function for calculating the ash-free dry weight of epifaunal invertebrate samples
#' Author: Jon Lefcheck
#' Last updated: 31 August 2017
#' @param x = a sample-by-sieve size abundance matrix,
#' @param group.colname = the name of the column containing the taxonomic classification (i.e., "Crustacean", "Mollusc", etc.)
#' @param min.size = the minimum sieve size to consider and return, default is the length of the dataset
#' @return a `data.frame` containing the original abundances, dry weight (mg), and production (mg d-1) if temperature is provided
edgarMethod = function(x, group.colname = "group", min.size = NULL) {
x <- as.data.frame(x)
x[, group.colname] <- as.character(x[, group.colname])
# If groups are not capitalized, capitalize them
capitalize <- function(y) {
x <- as.character(y)
paste0(toupper(substr(y, 1, 1)), tolower(substring(y, 2)))
}
x[, group.colname] <- apply(x[group.colname], 1, capitalize)
# Stop function if none the groups appear
if(!all(unique(x[, group.colname]) %in% c("Crustacean", "Mollusc", "Polychaete", "Caprellid")))
warning(
paste0(" Unknown groups: ",
paste0(unique(x[, group.colname])[!unique(x[, group.colname]) %in% c("Crustacean", "Mollusc", "Polychaete", "Caprellid")], collapse = ", "),
"\n Re-specify only as: Crustacean, Mollusc, Polychaete, or Caprellid"),
call. = FALSE
)
# Determine sieve size classes
sieves <- c(8, 5.6, 4, 2.8, 2, 1.4, 1, 0.71, 0.5)
if(!is.null(min.size)) if(!all(min.size %in% sieves)) stop("Minimum size must be: 8, 5.6, 4, 2.8, 2, 1.4, 1, 0.71, 0.5")
# Identify columns for sieve sizes
sieve.colnums <- which(colnames(x) %in% colnames(x)[grepl(paste0(sieves, collapse = "|"), colnames(x))])
# Order column index based on sieve size
sieve.order <- as.numeric(
unlist(
regmatches(colnames(x)[sieve.colnums],
gregexpr("[[:digit:]]+\\.*[[:digit:]]*", colnames(x)[sieve.colnums]))
)
)
names(sieve.order) <- sieve.colnums
sieve.colnums <- as.numeric(names(sieve.order)[order(sieve.order, decreasing = TRUE)])
# If min.size != 0.5, reduce to minimum size
if(!is.null(min.size)) {
if(!min.size %in% sieves) stop(paste0("Argument 'min.size = ", min.size, "' is not a recognized sieve size!"))
sieve.grepl <- sieve.colnums[1:which(sieves == min.size)]
message(paste0("Only computing abundance and biomass for sieve sizes >=", min.size, " mm!"))
} else
sieve.grepl <- sieve.colnums
# Convert NA abundances to 0
x[, sieve.grepl][is.na(x[, sieve.grepl])] <- 0
# Create vector of multipliers representing estimated biomass for a single individual in each size class
multiples <-
outer(x[, group.colname] == "Crustacean", c(36.1267, 14.6591, 5.8067, 2.3001, 0.9111, 0.3609, 0.143, 0.0577, 0.0229)[1:length(sieve.grepl)]) +
outer(x[, group.colname] == "Mollusc", c(45.8608, 18.0764, 6.9501, 2.6722, 1.0274, 0.395, 0.1519, 0.0596, 0.0229)[1:length(sieve.grepl)]) +
outer(x[, group.colname] == "Polychaete", c(27.3382, 11.78, 4.9632, 2.0911, 0.881, 0.3712, 0.1564, 0.0671, 0.0283)[1:length(sieve.grepl)]) +
outer(x[, group.colname] == "Platyhelminth", c(40.2429, 16.5011, 6.607, 2.6454, 1.0592, 0.4241, 0.1698, 0.0693, 0.0277)[1:length(sieve.grepl)]) +
outer(x[, group.colname] == "Caprellid", c(4.3076, 2.2675, 1.1733, 0.6071, 0.3142, 0.1626, 0.0841, 0.0441, 0.0228)[1:length(sieve.grepl)])
# Add additional columns for estimated biomass in each sieve size class
if(length(sieve.colnums) == length(sieve.grepl))
x <- cbind(x, (x[, sieve.grepl] * multiples)) else
x <- cbind(x[, -(sieve.colnums[!sieve.colnums %in% sieve.grepl])], x[, sieve.grepl] * multiples)
# Append names
colnames(x)[sieve.grepl] <- paste(colnames(x)[sieve.grepl], "_abund", sep = "")
colnames(x)[(ncol(x) - length(sieve.grepl) + 1):ncol(x)] <-
paste(colnames(x)[(ncol(x) - length(sieve.grepl) + 1):ncol(x)], "_biomass", sep = "")
# Obtain total abundance
x$total.abund <- rowSums(x[, grepl("_abund", colnames(x))], na.rm = TRUE)
# Obtain total biomass in mg
x$total.biomass <- rowSums(x[, grepl("_biomass", colnames(x))], na.rm = TRUE)
# If there is a column for temperature, obtain secondary production in mg AFDM day-1
temp.colnum <- ifelse(any(grepl("temp|Temp|T\\.|t\\.", colnames(x))), which(grepl("temp|Temp|T\\.|t\\.", colnames(x))), NA)
if(!is.na(temp.colnum))
x$total.secondprod.mg.d <-
(0.0049 * ((x$total.biomass * 1000) ^ 0.80) *
(x[, temp.colnum] ^ 0.89)
)
# Return dataframe
return(x)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment