diff --git a/DESCRIPTION b/DESCRIPTION index 1507a707..f5c30e9b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: FSA Version: 0.10.9000 -Date: 2025-8-16 +Date: 2026-1-7 Title: Simple Fisheries Stock Assessment Methods Description: A variety of simple fish stock assessment methods. Authors@R: c( diff --git a/NEWS.md b/NEWS.md index e2c813e1..debb9252 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,14 @@ # FSA 0.10.9000 +* Updated the PSD and Relative Weight computation articles to reflect the changes to `psdVal()`, `psdAdd()`, `wsVal()`, and `wrAdd()`. * `chapmanRobson()`: Added catch for when n+T<1 and n+T<2. This addresses [#131](https://github.com/fishR-Core-Team/FSA/issues/131)). * `metaM()`: Added `method="HamelCope"` to address [#133](https://github.com/fishR-Core-Team/FSA/issues/133). A few minor edits to documentation. -* `PSDlit`: Added info for Flier and Longear Sunfish. -* `wSlit`: Added info for Flier and Longear Sunfish. This addresses [#122](https://github.com/fishR-Core-Team/FSA/issues/122)). +* `psdAdd()`: Addressed bugs as described in [#136](https://github.com/fishR-Core-Team/FSA/issues/136)) and [#137](https://github.com/fishR-Core-Team/FSA/issues/137). Added `thesaurus` functionality. Reworked examples in documentation. Reworked testing framework. Thanks to Dave Glover. +* `PSDlit`: Added info for Flier and Longear Sunfish to address [#122](https://github.com/fishR-Core-Team/FSA/issues/122)) and Northern Pikeminnow. Also updated information for Alabama Bass and Spotted Bass. Duplicated lines that combine `species` and `group` to partially address [#137](https://github.com/fishR-Core-Team/FSA/issues/137). +* `psdVal()`: Added `dat=` to allow more flexibility when called from `psdAdd()`. +* `PSDWRTest`: Added for testing PSD and relative weight functions. +* `wrAdd()`: Addressed bugs similar to those for `psdAdd()`. Added `thesaurus` functionality. Reworked examples in documentation. Reworked testing framework (especially expanded validation of results with hand-calculations). +* `wSlit`: Added info for Flier and Longear Sunfish to address [#122](https://github.com/fishR-Core-Team/FSA/issues/122)). Also updated information for Alabama Bass (further removed Spotted Bass (Alabama subspecies)), Spotted Bass, and Northern Pikeminnow (further removed Northern Squawfish (synonym of Northern Pikeminnow that is no longer used)). Duplicated lines that combine `species` and `group` to partially address [#137](https://github.com/fishR-Core-Team/FSA/issues/137). +* `wsVal()`: Added `dat=` to allow more flexibility when called from `wrAdd()`. # FSA 0.10.0 * Updated `test-coverage.yaml` and moved a `# nocov start` and `# nocov end` in `bootstrap.r` to address the errors with `test-coverage.yaml`. Addresses [#118](https://github.com/fishR-Core-Team/FSA/issues/118). diff --git a/R/PSDWRtest.R b/R/PSDWRtest.R new file mode 100644 index 00000000..fc2b00c0 --- /dev/null +++ b/R/PSDWRtest.R @@ -0,0 +1,44 @@ +#' @title Hypothetical weight-length data for testing PSD and relative weight functions +#' +#' @description Hypothetical weight-length and associated data. These data are useful for testing PSD and relative weight functions (e.g., \code{\link{psdAdd}} and \code{\link{wrAdd}}). +#' +#' @name PSDWRtest +#' +#' @docType data +#' +#' @format A data frame of many observations on the following 5 variables: +#' \describe{ +#' \item{species}{Species name} +#' \item{location}{Broad location of capture} +#' \item{len}{Length in mm} +#' \item{wt}{Weight in g} +#' \item{sex}{Sex as \code{F} for female, \code{M} for male, or \code{U} or \code{NA} for unknown or unrecorded} +#' } +#' +#' @section Topic(s): +#' \itemize{ +#' \item Size structure +#' \item Proportional size structure +#' \item Relative stock density +#' \item Proportional stock density +#' \item Relative weight +#' \item Standard weight +#' \item Condition +#' } +#' +#' @concept Size Structure +#' @concept PSD +#' @concept Condition +#' @concept Relative Weight +#' @concept Standard Weight +#' +#' @seealso \code{\link{psdAdd}}, \code{\link{psdCalc}}, and \code{\link{wrAdd}} +#' +#' @keywords datasets +#' +#' @examples +#' str(PSDWRtest) +#' peek(PSDWRtest,n=20) +#' unique(PSDWRtest$species) +#' +NULL diff --git a/R/PSDlit.R b/R/PSDlit.R index 6871db94..f6393258 100644 --- a/R/PSDlit.R +++ b/R/PSDlit.R @@ -1,6 +1,9 @@ #' @title Gabelhouse five-cell length categories for various species. #' #' @description Cutoffs for the Gabelhouse five-cell length categories for a variety of species. +#' +#' @details Entries for some species (e.g., \dQuote{Muskellunge} and \dQuote{Walleye}) have been duplicated for sub-groups to facilitate use with relative weight calculations. For example, entries for \dQuote{Muskellunge (overall)}, \dQuote{Muskellunge (female)}, and \dQuote{Muskellunge (male)} are duplicates of the entry for \dQuote{Muskellunge}; i.e., these entries in \code{PSDlit} are not necessarily just for those sub-groups but this allows for seamless similar computations of relative weights for these sub-groups. +#' #' #' @name PSDlit #' diff --git a/R/WSlit.R b/R/WSlit.R index d6e34ec6..e1d8e4ca 100644 --- a/R/WSlit.R +++ b/R/WSlit.R @@ -3,6 +3,8 @@ #' @description Parameters for all known standard weight equations. #' #' @details The minimum TL for the English units were derived by rounding the converted minimum TL for the metric units to what seemed like common units (inches, half inches, or quarter inches). +#' +#' Entries for \dQuote{Chinook Salmon (landlocked)} and \dQuote{Striped Bass (landlocked)} are the same as for \dQuote{Chinook Salmon} and \dQuote{Striped Bass} but were added to facilitate use with PSD calculations as Gabelhouse lengths are only published for the landlocked sub-group; i.e., these entries in \code{WSlit} are not necessarily just for landlocked populations. #' #' @name WSlit #' diff --git a/R/psdAdd.R b/R/psdAdd.R index 569d69e9..4010c326 100644 --- a/R/psdAdd.R +++ b/R/psdAdd.R @@ -6,6 +6,7 @@ #' @param species A character or factor vector that contains the species names. Ignored if \code{len} is a formula. #' @param group A named list that provides specific choices for \code{group} for species for which more than one set of Gabelhouse lengths exists in \code{\link{PSDlit}}. #' @param data A data.frame that minimally contains the length measurements and species names if \code{len} is a formula. +#' @param thesaurus A named list for providing alternative species names (the values in the list) that correspond to specific names in \code{PSDlit} (the names in the list). See details and examples. #' @param units A string that indicates the type of units used for the lengths. Choices are \code{mm} for millimeters (DEFAULT), \code{cm} for centimeters, and \code{in} for inches. #' @param use.names A logical that indicates whether the vector returned is numeric (\code{=FALSE}) or string (\code{=TRUE}; default) representations of the Gabelhouse lengths. See details. #' @param as.fact A logical that indicates that the new variable should be returned as a factor (\code{=TRUE}) or not (\code{=FALSE}). Defaults to same as \code{use.names} unless \code{addLens} is not \code{NULL}, in which case it will default to \code{FALSE}. See details. @@ -15,7 +16,9 @@ #' #' @details This computes a vector that contains the Gabelhouse lengths specific to each species for all individuals in an entire data frame. The vector can be appended to an existing data.frame to create a variable that contains the Gabelhouse lengths for each individual. The Gabelhouse length value will be \code{NA} for each individual for which Gabelhouse length definitions do not exist in \code{\link{PSDlit}}. Species names in the data.frame must be the same as those used in \code{\link{PSDlit}} (i.e., same spelling and capitalization; use \code{psdVal()} to see the list of species). #' -#' Some species have Gabelhouse lengths for sub-groups (e.g., \dQuote{lentic} vs \dQuote{lotic}). For these species, choose which sub-group to use with \code{group}. +#' The \code{thesaurus} argument may be used to relate alternate species names to the species names used in \code{PSDlit}. For example, you (or your data) may use \dQuote{Bluegill Sunfish}, but \dQuote{Bluegill} is used in \code{PSDlit}. The alternate species name can be used here if it is defined in a named vector (or list) given to \code{thesarus=}. The alternate species name is the value and the species name in \code{PSDlit} is the name in this vector/list - e.g., \code{c("Bluegill"="Bluegill Sunfish")}. See the examples for a demonstration. +#' +#' Some species have length categories separated by sub-group. For example, length categories exist for both lentic and lotic populations of Brown Trout. The length values for a sub-group may be obtained by either including the species name in \code{species} and the sub-group name in \code{group} or by using the combined species and sub-group name, with the sub-group name in parentheses, in \code{species}. Both methods are demonstrated in the examples. Note that an error is returned if a species has sub-groups but neither method is used to define the sub-group.#' #' #' Individuals shorter than \dQuote{stock} length will be listed as \code{substock} if \code{use.names=TRUE} or \code{0} if \code{use.names=FALSE}. #' @@ -42,63 +45,112 @@ #' @keywords manip #' #' @examples -#' #===== Create random data for three species -#' set.seed(345234534) -#' dbg <- data.frame(species=factor(rep(c("Bluegill"),30)), -#' tl=round(rnorm(30,130,50),0)) -#' dlb <- data.frame(species=factor(rep(c("Largemouth Bass"),30)), -#' tl=round(rnorm(30,350,60),0)) -#' dbt <- data.frame(species=factor(rep(c("Bluefin Tuna"),30)), -#' tl=round(rnorm(30,1900,300),0)) -#' df <- rbind(dbg,dlb,dbt) -#' -#' #===== Simple examples +#' #===== Simple examples -- 2 species, no groups, names as in PSDlit +#' #----- Isolate simple data from PSDWRtest +#' tmp <- subset(PSDWRtest, +#' species %in% c("Yellow Perch","Largemouth Bass"), +#' select=c("species","len")) +#' peek(tmp,n=6) +#' #' #----- Add variable using category names -- non-formula notation -#' df$PSD <- psdAdd(df$tl,df$species) -#' peek(df,n=6) +#' tmp$PSD <- psdAdd(tmp$len,tmp$species) +#' peek(tmp,n=6) #' #' #----- Add variable using category names -- formula notation -#' df$PSD1 <- psdAdd(tl~species,data=df) -#' peek(df,n=6) +#' tmp$PSD1 <- psdAdd(len~species,data=tmp) +#' peek(tmp,n=6) #' #' #----- Add variable using length values as names -#' # Also turned off messaging of fish not in PSDlit -#' df$PSD2 <- psdAdd(tl~species,data=df,use.names=FALSE,verbose=FALSE) -#' peek(df,n=6) +#' tmp$PSD2 <- psdAdd(len~species,data=tmp,use.names=FALSE) +#' peek(tmp,n=6) #' #' #----- Same as above but using dplyr #' if (require(dplyr)) { -#' df <- df %>% -#' mutate(PSD1A=psdAdd(tl,species,verbose=FALSE), -#' PSD2A=psdAdd(tl,species,use.names=FALSE,verbose=FALSE)) -#' peek(df,n=6) +#' tmp <- tmp %>% +#' mutate(PSD1A=psdAdd(len,species), +#' PSD2A=psdAdd(len,species,use.names=FALSE)) +#' peek(tmp,n=6) #' } #' -#' #===== Adding lengths besides the Gabelhouse lengths -#' #----- Add a "minimum length" for Bluegill -#' df$PSD3 <- psdAdd(tl~species,data=df,verbose=FALSE, -#' addLens=list("Bluegill"=c("minLen"=175))) -#' df$PSD3A <- psdAdd(tl~species,data=df,verbose=FALSE, -#' addLens=list("Bluegill"=175)) -#' df$PSD3B <- psdAdd(tl~species,data=df,verbose=FALSE, -#' addLens=list("Bluegill"=c("minLen"=175)),use.names=FALSE) -#' head(df,n=6) -#' -#' #----- Add add'l lengths and names for Bluegill and Largemouth Bass -#' df$psd4 <- psdAdd(tl~species,data=df,verbose=FALSE, -#' addLens=list("Bluegill"=175, -#' "Largemouth Bass"=c(254,356))) -#' peek(df,n=20) -#' -#' #===== Example for a species with sub-groups -#' dbt <- data.frame(species=factor(rep(c("Brown Trout"),30)), -#' tl=round(rnorm(30,230,50),0)) -#' dlt <- data.frame(species=factor(rep(c("Lake Trout"),30)), -#' tl=round(rnorm(30,550,60),0)) -#' df2 <- rbind(dbt,dlt) -#' -#' df2$psd <- psdAdd(tl~species,data=df2,group=list("Brown Trout"="lentic")) -#' peek(df2,n=6) +#' #===== Add lengths besides Gabelhouse lengths (start over with same simple data) +#' tmp <- subset(PSDWRtest, +#' species %in% c("Yellow Perch","Largemouth Bass"), +#' select=c("species","len")) +#' +#' #----- Add a "minimum length" for one species +#' tmp$PSD3 <- psdAdd(len~species,data=tmp, +#' addLens=list("Yellow Perch"=c("minLen"=225))) +#' tmp$PSD3A <- psdAdd(len~species,data=tmp, +#' addLens=list("Yellow Perch"=225)) +#' tmp$PSD3B <- psdAdd(len~species,data=tmp, +#' addLens=list("Yellow Perch"=c("minLen"=225)),use.names=FALSE) +#' head(tmp,n=6) +#' +#' #----- Add add'l lengths and names for multiple species +#' tmp$psd4 <- psdAdd(len~species,data=tmp, +#' addLens=list("Yellow Perch"=175, +#' "Largemouth Bass"=c(254,306))) +#' peek(tmp,n=20) +#' +#' #===== Handle additional species in PSDlit but named differently +#' #----- Isolate different species data from PSDWRtest +#' tmp <- subset(PSDWRtest, +#' species %in% c("Bluegill Sunfish","Lean Lake Trout"), +#' select=c("species","len")) +#' +#' #----- No "Bluegill Sunfish" in PSDlit, use thesaurus to note this is "Bluegill" +#' # Note: "Lean Lake Trout" not processed as not in PSDlit +#' tmp$psd5 <- psdAdd(len~species,data=tmp, +#' thesaurus=c("Bluegill"="Bluegill Sunfish")) +#' peek(tmp,n=6) +#' +#' #----- Process multiple species in PSDlit with different names +#' # Note: Can still use addLens=, but with original name +#' thes <- c("Bluegill"="Bluegill Sunfish","Lake Trout"="Lean Lake Trout") +#' tmp$psd6 <- psdAdd(len~species,data=tmp,thesaurus=thes) +#' tmp$psd7 <- psdAdd(len~species,data=tmp,thesaurus=thes, +#' addLens=list("Bluegill Sunfish"=c("minLen"=175))) +#' peek(tmp,n=20) +#' +#' #===== Example for a species with sub-groups but only one sub-group in data +#' #----- Isolate species data from PSDWRtest ... only Brook Trout has sub-group +#' tmp <- subset(PSDWRtest, +#' species %in% c("Yellow Perch","Brook Trout"), +#' select=c("species","len")) +#' +#' #----- This will err as Brook Trout has sub-groups in PSDlit (as message notes) +#' # tmp$psd8 <- psdAdd(len~species,data=tmp) +#' +#' #----- Can choose "overall" sub-group with group= +#' tmp$psd8 <- psdAdd(len~species,data=tmp, +#' group=list("Brook Trout"="overall")) +#' peek(tmp,n=10) +#' +#' #----- Or can create species name with sub-group name in parentheses +#' # Note: this is more useful in next examples +#' tmp$species2 <- ifelse(tmp$species=="Brook Trout","Brook Trout (overall)", +#' tmp$species) +#' tmp$psd8A <- psdAdd(len~species2,data=tmp) # note use of species2 +#' peek(tmp,n=10) +#' +#' #===== Example for species with more than one sub-group in data +#' #----- Isolate species data from PSDWRtest ... Brown Trout has two sub-groups +#' tmp <- subset(PSDWRtest, +#' species %in% c("Yellow Perch","Largemouth Bass","Brown Trout"), +#' select=c("species","len","location")) +#' peek(tmp,n=10) +#' +#' #----- Must create a species name variable with sub-groups in parentheses +#' # Note: there are likely many ways to do this specific to each use-case +#' tmp$species2 <- tmp$species +#' tmp$species2[tmp$species=="Brown Trout" & +#' tmp$location=="Trout Lake"] <- "Brown Trout (lotic)" +#' tmp$species2[tmp$species=="Brown Trout" & +#' tmp$location=="Brushy Creek"] <- "Brown Trout (lentic)" +#' peek(tmp,n=10) +#' +#' tmp$psd9 <- psdAdd(len~species2,data=tmp) +#' peek(tmp,n=10) #' #' @rdname psdAdd #' @export @@ -108,7 +160,8 @@ psdAdd <- function (len,...) { #' @rdname psdAdd #' @export -psdAdd.default <- function(len,species,group=NULL,units=c("mm","cm","in"), +psdAdd.default <- function(len,species,thesaurus=NULL, + group=NULL,units=c("mm","cm","in"), use.names=TRUE, as.fact=ifelse(is.null(addLens),use.names,FALSE), addLens=NULL,verbose=TRUE,...) { @@ -118,10 +171,10 @@ psdAdd.default <- function(len,species,group=NULL,units=c("mm","cm","in"), if (!inherits(species,c("character","factor"))) STOP("'species' must be character or factor.") ## Prepare the PSD literature values data frame - PSDlit <- FSA::PSDlit + PSDlit <- iPrepPSDlit(thesaurus) ## Find species that have known Gabelhouse lengths - # get list of species in data - specs <- unique(species) + # get list of species in data ... change from factor to character if necessary + specs <- as.character(unique(species)) GLHSspecs <- specs[specs %in% unique(PSDlit$species)] ## Create data.frames with species that are NA and w/o Gabelhouse lengths and ## one with Gabelhouse lengths. The loop below will then start with a @@ -130,7 +183,7 @@ psdAdd.default <- function(len,species,group=NULL,units=c("mm","cm","in"), # - rownumbers is needed to get back the original order # - PSD will eventually have the Gabelhouse length categories data <- data.frame(len,species,rownums=seq_along(len),PSD=rep(NA,length(len))) - # data.frame where species is NA and doesn't have Gabelhousee length + # data.frame where species is NA and doesn't have Gabelhouse length ndata <- data[is.na(data$species) | !data$species %in% GLHSspecs,] if (verbose & nrow(ndata)>0) MESSAGE("Species in the data with no Gabelhouse (PSD) lengths in `PSDlit`: ", @@ -138,7 +191,7 @@ psdAdd.default <- function(len,species,group=NULL,units=c("mm","cm","in"), # data.frame where species have Gabelhouse lengths ... make sure no NAs data <- data[data$species %in% GLHSspecs,] data <- data[!is.na(data$species),] - + ## Cycle through each species where PSD values are known, add PSD categories ## and append to data.frame that contained species w/o Gabelhouse lengths for (i in seq_along(GLHSspecs)) { @@ -150,10 +203,11 @@ psdAdd.default <- function(len,species,group=NULL,units=c("mm","cm","in"), else tmpAddLens <- NULL # get the Gabelhouse length categories if (!is.null(group)) { - if (GLHSspecs[i] %in% names(group)) group <- group[[GLHSspecs[i]]] - else group <- NULL - } - glhse <- psdVal(GLHSspecs[i],group=group,units=units,addLens=tmpAddLens) + if (GLHSspecs[i] %in% names(group)) tmp_group <- group[[GLHSspecs[i]]] + else tmp_group <- NULL + } else tmp_group <- NULL + glhse <- psdVal(GLHSspecs[i],group=tmp_group,units=units,addLens=tmpAddLens, + dat=PSDlit) # computes the Gabelhouse length categories and adds to the data frame if (all(is.na(tmpdf$len))) { if (verbose) message("All values in 'len' were missing for ",GLHSspecs[i]) @@ -176,7 +230,8 @@ psdAdd.default <- function(len,species,group=NULL,units=c("mm","cm","in"), #' @rdname psdAdd #' @export -psdAdd.formula <- function(len,data=NULL,group=NULL,units=c("mm","cm","in"), +psdAdd.formula <- function(len,data=NULL,thesaurus=NULL, + group=NULL,units=c("mm","cm","in"), use.names=TRUE, as.fact=ifelse(is.null(addLens),use.names,FALSE), addLens=NULL,verbose=TRUE,...) { @@ -196,6 +251,46 @@ psdAdd.formula <- function(len,data=NULL,group=NULL,units=c("mm","cm","in"), STOP("'len' must have one and only one factor variable (species)", " on right-hand-side.") ## Send to default method - psdAdd.default(tmp$mf[[tmp$Rpos]],tmp$mf[[tmp$EFactPos]],group,units, + psdAdd.default(tmp$mf[[tmp$Rpos]],tmp$mf[[tmp$EFactPos]],thesaurus,group,units, use.names,as.fact,addLens,verbose,...) } + + +# ============================================================================== +# Internal -- prepare PSDlit by loading it and replacing its default names with +# names in the thesaurus, if any +# ============================================================================== +iPrepPSDlit <- function(thesaurus) { + # Load PSDlit into dat in this function namespace + dat <- FSA::PSDlit + if (!is.null(thesaurus)) { + # Some sanity checks on thesaurus + if (!(is.vector(thesaurus) | is.list(thesaurus))) + STOP("'thesaurus' must be either a vector or list. ", + "Make sure it is not 'factor'ed.") + if (length(names(thesaurus))==0) + STOP("Values in 'thesaurus' must be named (with species names from 'PSDlit'.") + if (!is.character(thesaurus)) + STOP("Values in 'thesaurus' must be strings of species names.") + # thesaurus appears to be a named vector/list of strings ... start processing + # Alphabetize names in thesaurus to match PSDlit + thesaurus <- thesaurus[order(names(thesaurus))] + # Remove name from thesaurus if not in dat/PSDlit + thes.nokeep <- which(!names(thesaurus) %in% unique(dat$species)) + if (length(thes.nokeep)>0) { + MESSAGE("The following species names were in 'thesaurus' but do ", + "not have an entry in 'PSDlit' and will be ignored: ", + iStrCollapse(names(thesaurus)[thes.nokeep]),".") + thesaurus <- thesaurus[-thes.nokeep] + } + # Find dat/PSDlit species in kept thesaurus and change names to thesaurus names + if (length(thesaurus)>0) { + thes.pos <- which(dat$species %in% names(thesaurus)) + dat$species[thes.pos] <- unlist(thesaurus) + # Re-alphabetize dat/PSDlit + dat <- dat[order(dat$species),] + } + } + # Return dat/PSDlit + dat +} diff --git a/R/psdCalc.R b/R/psdCalc.R index a960fe22..18ee5674 100644 --- a/R/psdCalc.R +++ b/R/psdCalc.R @@ -48,51 +48,53 @@ #' @keywords hplot #' #' @examples -#' #===== Random length data for Yellow Perch (for example) to the nearest mm -#' set.seed(633437) -#' yepdf <- data.frame(yepmm=round(c(rnorm(100,mean=125,sd=15), -#' rnorm(50,mean=200,sd=25), -#' rnorm(20,mean=270,sd=40)),0), -#' species=rep("Yellow Perch",170)) -#' #' #===== Simple (typical) uses with just Gabelhouse lengths +#' tmp <- subset(PSDWRtest,species=="Yellow Perch",select=c("species","len")) +#' #' #----- All results -#' psdCalc(~yepmm,data=yepdf,species="Yellow Perch") +#' psdCalc(~len,data=tmp,species="Yellow Perch") #' #' #----- Just the traditional indices -#' psdCalc(~yepmm,data=yepdf,species="Yellow Perch",what="traditional") +#' psdCalc(~len,data=tmp,species="Yellow Perch",what="traditional") #' #' #----- Just the incremental indices -#' psdCalc(~yepmm,data=yepdf,species="Yellow Perch",what="incremental") +#' psdCalc(~len,data=tmp,species="Yellow Perch",what="incremental") #' #' #===== Add a custom length of interest (to the Gabelhouse lengths) -#' psdCalc(~yepmm,data=yepdf,species="Yellow Perch",addLens=150) +#' psdCalc(~len,data=tmp,species="Yellow Perch",addLens=150) #' #' #----- Additional lengths can be named -#' psdCalc(~yepmm,data=yepdf,species="Yellow Perch",addLens=c("minLen"=150)) -#' psdCalc(~yepmm,data=yepdf,species="Yellow Perch", +#' psdCalc(~len,data=tmp,species="Yellow Perch",addLens=c("minLen"=150)) +#' psdCalc(~len,data=tmp,species="Yellow Perch", #' addLens=c("minLen"=150,"maxslot"=275)) #' #' #----- Can return just those results that include the additional lengths -#' psdCalc(~yepmm,data=yepdf,species="Yellow Perch", +#' psdCalc(~len,data=tmp,species="Yellow Perch", #' addLens=c("minSlot"=150,"maxSlot"=275),justAdds=TRUE) -#' psdCalc(~yepmm,data=yepdf,species="Yellow Perch", +#' psdCalc(~len,data=tmp,species="Yellow Perch", #' addLens=c("minSlot"=150,"maxSlot"=275),justAdds=TRUE,what="traditional") #' #' #===== Can show intermediate values (num in category and in stock) -#' psdCalc(~yepmm,data=yepdf,species="Yellow Perch",showInterm=TRUE) +#' psdCalc(~len,data=tmp,species="Yellow Perch",showInterm=TRUE) +#' +#' #===== Some species require use of group +#' tmp <- subset(PSDWRtest,species=="Brown Trout" & location=="Trout Lake", +#' select=c("species","location","len")) +#' peek(tmp,n=6) #' -#' #===== Some species require use of group (e.g., treat these as if Brown Trout) -#' psdCalc(~yepmm,data=yepdf,species="Brown Trout",group="lotic") -#' psdCalc(~yepmm,data=yepdf,species="Brown Trout",group="lentic") +#' # will err because Brown Trout has sub-groups in PSDlit +#' # psdCalc(~len,data=tmp,species="Brown Trout") +#' psdCalc(~len,data=tmp,species="Brown Trout",group="lotic") +#' psdCalc(~len,data=tmp,species="Brown Trout (lotic)") #' #' #===== For species not in PSDlit ... don't include species and use addLens -#' # Note that these are same data as above, but treated as different species -#' psdCalc(~yepmm,data=yepdf,addLens=c("stock"=130,"quality"=200,"preferred"=250, -#' "memorable"=300,"trophy"=380)) +#' # Note these are same data as above, but treated as species not in PSDlit +#' psdCalc(~len,data=tmp,addLens=c("stock"=130,"quality"=200,"preferred"=250, +#' "memorable"=300,"trophy"=380)) #' #' @export psdCalc -psdCalc <- function(formula,data,species,group=NULL,units=c("mm","cm","in"), +psdCalc <- function(formula,data,species, + group=NULL,units=c("mm","cm","in"), method=c("multinomial","binomial"),conf.level=0.95, addLens=NULL,addNames=NULL,justAdds=FALSE, what=c("all","traditional","incremental","none"), @@ -105,8 +107,8 @@ psdCalc <- function(formula,data,species,group=NULL,units=c("mm","cm","in"), #----- Make sure species is not missing, or if it is that addLens have been given if (!missing(species)) { - brks <- psdVal(species,group,units=units,incl.zero=FALSE, - addLens=addLens,addNames=addNames) + brks <- psdVal(species,group=group,units=units, + incl.zero=FALSE,addLens=addLens,addNames=addNames) } else { # species is missing so must have an addLens if (is.null(addLens)) diff --git a/R/psdVal.R b/R/psdVal.R index 9ca7ea74..304e7a24 100644 --- a/R/psdVal.R +++ b/R/psdVal.R @@ -9,9 +9,12 @@ #' @param addLens A numeric vector that contains minimum length definitions for additional categories. See details. #' @param addNames A string vector that contains names for the additional length categories added with \code{addLens}. See details. #' @param showJustSource A logical that indicates whether just the literature source information should be returned (\code{TRUE}) or not. If \code{TRUE} this will NOT return any of the Gabelhouse length information. +#' @param dat Data.frame of Gabelhouse length categories for all species. Defaults to `PSDlit` and is generally not used by the user (this simplifies use of this function in \code{psdAdd}). #' #' @details Finds the Gabelhouse lengths from \code{data(PSDlit)} for the species given in \code{species}. The species name must be spelled exactly (including capitalization) as it appears in \code{data(PSDlit)}. Type \code{psdVal()} to see the list of species and how they are spelled. #' +#' Some species have length categories separated by sub-group. For example, length categories exist for both lentic and lotic populations of Brown Trout. The length values for a sub-group may be obtained by either including the species name in \code{species} and the sub-group name in \code{group} or by using the combined species and sub-group name, with the sub-group name in parentheses, in \code{species}. Both methods are demonstrated in the examples. Note that an error is returned if a species has sub-groups but neither method is used to define the sub-group.#' +#' #' A zero is included in the first position of the returned vector if \code{incl.zero=TRUE}. This is useful when computing PSD values with a data.frame that contains fish smaller than the stock length. #' #' Additional lengths may be added to the returned vector with \code{addLens}. Names for these lengths can be included as names in \code{addLens} or separately in \code{addNames}. If \code{addNames} is NULL and \code{addLens} is not named then the default category names will be the lengths from \code{addLens}. The \code{addLens} argument is useful for calculating PSD values that are different from the Gabelhouse lengths. @@ -47,10 +50,15 @@ #' psdVal("Bluegill",showJustSource=TRUE) #' #' #===== For species that have sub-groups +#' #----- using group= argument #' psdVal("Brown Trout",group="lentic") #' psdVal("Brown Trout",group="lotic") -#' psdVal("Palmetto Bass",group="revised") -#' psdVal("Palmetto Bass",group="original") +#' #----- group combined in species name, so no group= use +#' psdVal("Brown Trout (lentic)") +#' +#' #===== For species with revised values +#' psdVal("Palmetto Bass") +#' psdVal("Palmetto Bass (original)") #' #' #===== Adding user-defined categories #' #----- with lengths and names separately in addLens= and addNames= @@ -60,28 +68,29 @@ #' #----- with a named vector in addLens= #' psdVal("Bluegill",units="in",addLens=c("MinLen"=7)) #' psdVal("Bluegill",units="in",addLens=c("MinSlot"=7,"MaxSlot"=9)) -#' +#' #' @export psdVal psdVal <- function(species="List",group=NULL,units=c("mm","cm","in"), addLens=NULL,addNames=NULL, - incl.zero=TRUE,showJustSource=FALSE) { + incl.zero=TRUE,showJustSource=FALSE,dat=NULL) { units <- match.arg(units) - #====== Load PSDlit into this function's environment, do some checking, and - # return a data.frame with infor for just that species/group - PSDlit <- FSA::PSDlit - PSDlit <- iPSDGetSpecies(PSDlit,species,group) + + #====== If dat is null then load PSDlit into dat ... then do some checking, + # and return a data.frame with info for just that species/group + if (is.null(dat)) dat <- FSA::PSDlit + dat <- iPSDGetSpecies(dat,species,group) - #====== Prepare Result as longs as PSDlit was not returned as NULL - if (!is.null(PSDlit)) { + #====== Prepare Result as longs as dat was not returned as NULL + if (!is.null(dat)) { if (showJustSource) { ifelse(is.null(group),cols <- c(1,14),cols <- c(1,2,15)) - PSDlit[,cols] + dat[,cols] } else { #----- Identify columns based on units ifelse(units=="in",cols <- 3:8,cols <- 9:14) if (is.null(group)) cols <- cols-1 #----- get the length categories - PSDvec <- as.matrix(PSDlit[,cols])[1,] + PSDvec <- as.matrix(dat[,cols])[1,] names(PSDvec) <- gsub("\\..*","",names(PSDvec)) #----- remove zero category (substock) if asked if (!incl.zero) PSDvec <- PSDvec[!names(PSDvec)=="substock"] @@ -109,7 +118,6 @@ psdVal <- function(species="List",group=NULL,units=c("mm","cm","in"), } } - # ============================================================================== # Internal -- check species name against the 'dat' data.frame (usually PSDLit) # ============================================================================== diff --git a/R/wrAdd.R b/R/wrAdd.R index 22265c49..7f5a530e 100644 --- a/R/wrAdd.R +++ b/R/wrAdd.R @@ -6,6 +6,10 @@ #' #' The species names in \code{species} must match the spelling and capitalization of \code{species} in \code{\link{WSlit}}. Use \code{wsVal()} to see a list of all species for which standard weight equations exist in \code{\link{WSlit}} and, more importantly, how the species names are spelled and capitalized. #' +#' The \code{thesaurus} argument may be used to relate alternate species names to the species names used in \code{WSlit}. For example, you (or your data) may use \dQuote{Bluegill Sunfish}, but \dQuote{Bluegill} is used in \code{WSlit}. The alternate species name can be used here if it is defined in a named vector (or list) given to \code{thesarus=}. The alternate species name is the value and the species name in \code{PSDlit} is the name in this vector/list - e.g., \code{c("Bluegill"="Bluegill Sunfish")}. See the examples for a demonstration. +#' +#' Some species have length categories separated by sub-group. For example, length categories exist for both lentic and lotic populations of Brown Trout. The length values for a sub-group may be obtained by either including the species name in \code{species} and the sub-group name in \code{group} in \code{WsOpts} or by using the combined species and sub-group name, with the sub-group name in parentheses, in \code{species}. Both methods are demonstrated in the examples. Note that an error is returned if a species has sub-groups but neither method is used to define the sub-group. +#' #' Some (few) species have more than one equation listed in \code{\link{WSlit}} (for the specified units). In these instances the user must select one of the equations to use with \code{WsOpts}. \code{WsOpts} is a list of lists where the inside list contains one or more of \code{group}, \code{ref}, or \code{method} (see \code{\link{WSlit}}) required to specify a single equation for a particular species, which is the name of the inner list. See the examples for an illustration of how to use \code{WsOpts}. #' #' See examples and \href{https://fishr-core-team.github.io/FSA/articles/Computing_Relative_Weights.html}{this article} for a demonstration. @@ -14,6 +18,7 @@ #' @param len A numeric vector that contains length measurements. Not used if \code{wt} is a formula. #' @param spec A character or factor vector that contains the species names. Not used if \code{wt} is a formula. #' @param data A data.frame that minimally contains variables of the the observed lengths, observed weights, and the species names given in the \code{formula=}. +#' @param thesaurus A named list for providing alternative species names (the values in the list) that correspond to specific names in \code{PSDlit} (the names in the list). See details and examples. #' @param units A string that indicates whether the weight and length data in \code{formula} are in \code{"metric"} (DEFAULT; mm and g) or \code{"English"} (in and lbs) units. #' @param WsOpts A named list that provides specific choices for \code{group}, \code{ref}, or \code{method} for species for which more than one standard weight equation exists in \code{\link{WSlit}}. #' @param \dots Not used. @@ -31,51 +36,78 @@ #' @keywords manip #' #' @examples -#' #===== Create random data for three species -#' #----- just to control the randomization -#' set.seed(345234534) -#' dbt <- data.frame(species=factor(rep(c("Bluefin Tuna"),30)), -#' tl=round(rnorm(30,1900,300),0)) -#' dbt$wt <- round(4.5e-05*dbt$tl^2.8+rnorm(30,0,6000),1) -#' dbg <- data.frame(species=factor(rep(c("Bluegill"),30)), -#' tl=round(rnorm(30,130,50),0)) -#' dbg$wt <- round(4.23e-06*dbg$tl^3.316+rnorm(30,0,10),1) -#' dlb <- data.frame(species=factor(rep(c("Largemouth Bass"),30)), -#' tl=round(rnorm(30,350,60),0)) -#' dlb$wt <- round(2.96e-06*dlb$tl^3.273+rnorm(30,0,60),1) -#' df <- rbind(dbt,dbg,dlb) -#' str(df) -#' -#' #===== Add Wr variable -#' #----- using formula interface -#' df$Wr1 <- wrAdd(wt~tl+species,data=df) +#' #===== Simple example with 3 species, 2 in WSlit ... nothing unusual +#' tmp <- subset(PSDWRtest, +#' species %in% c("Yellow Perch","Iowa Darter","Largemouth Bass"), +#' select=c("species","len","wt")) +#' peek(tmp,n=10) #' +#' #----- Add Wr variable ... using formula interface +#' tmp$wr1 <- wrAdd(wt~len+species,data=tmp) #' #----- same but with non-formula interface -#' df$Wr2 <- wrAdd(df$wt,df$tl,df$species) -#' +#' tmp$wr2 <- wrAdd(tmp$wt,tmp$len,tmp$species) #' #----- same but using dplyr #' if (require(dplyr)) { -#' df <- df %>% -#' mutate(Wr3=wrAdd(wt,tl,species)) +#' tmp <- tmp %>% +#' mutate(wr3=wrAdd(wt,len,species)) #' } -#' #' #----- examine results -#' peek(df,n=10) -#' -#' #===== Example with only one species in the data.frame -#' bg <- droplevels(subset(df,species=="Bluegill")) -#' bg$Wr4 <- wrAdd(wt~tl+species,data=bg) -#' bg +#' peek(tmp,n=10) +#' +#' #===== Simple example with only one species in the data.frame +#' tmp <- subset(PSDWRtest,species %in% c("Yellow Perch"), +#' select=c("species","len","wt")) +#' tmp$wr <- wrAdd(wt~len+species,data=tmp) +#' peek(tmp,n=6) +#' +#' #===== Example of species with sub-groups but only 1 sub-group in data.frame +#' #----- Group not in species name so must specify group with WsOpts +#' tmp <- subset(PSDWRtest,species=="Brown Trout" & location=="Trout Lake", +#' select=c("species","len","wt")) +#' tmp$wr1 <- wrAdd(wt~len+species,data=tmp, +#' WsOpts=list("Brown Trout"=list("group"="lotic"))) +#' +#' #----- Group in species name so don't specify group with WsOpts +#' tmp$species2 <- "Brown Trout (lotic)" +#' tmp$wr2 <- wrAdd(wt~len+species2,data=tmp) # note use of species2 +#' +#' peek(tmp,n=6) +#' +#' #===== Example of species with sub-groups and 2 sub-groups in data.frame +#' tmp <- subset(PSDWRtest,species=="Brown Trout", +#' select=c("species","location","len","wt")) +#' #----- Must create "species" with sub-groups in name +#' #----- Many ways to do this, this is just one example for this case +#' tmp$species2 <- ifelse(tmp$location=="Trout Lake", +#' "Brown Trout (lotic)","Brown Trout (lentic)") +#' tmp$wr <- wrAdd(wt~len+species2,data=tmp) # note use of species2 +#' peek(tmp,n=6) #' -#' #===== Example with a species that has Ws eqns for multiple groups and a -#' # group needs to be specified with WsOpts -#' wae <- data.frame(species=factor(rep(c("Walleye"),30)), -#' tl=round(rnorm(30,500,200),0)) -#' wae$wt <- round(3.33e-06*wae$tl^3.16+rnorm(30,0,50),1) -#' # wae$Wr <- wrAdd(wt~tl+species,data=wae) # will err b/c multiple groups -#' wae$Wr <- wrAdd(wt~tl+species,data=wae, -#' WsOpts=list(Walleye=list(group="overall"))) -#' peek(wae,n=10) +#' #===== Example of a species name that needs the thesaurus +#' tmp <- subset(PSDWRtest,species %in% c("Yellow Perch","Bluegill Sunfish"), +#' select=c("species","len","wt")) +#' #----- Below will not add wr for "Bluegill Sunfish" as not in WsLit ("Bluegill" is) +#' tmp$wr1 <- wrAdd(wt~len+species,data=tmp) +#' #----- Use thesaurus to identify "Bluegill Sunfish" as "Blueill +#' tmp$wr2 <- wrAdd(wt~len+species,data=tmp,thesaurus=c("Bluegill"="Bluegill Sunfish")) +#' peek(tmp,n=10) +#' +#' #===== Example of species that has Ws eqns for multiple reference values +#' tmp <- subset(PSDWRtest,species=="Ruffe",select=c("species","len","wt")) +#' #----- Below will err as Ruffe has Ws eqns for multiple reference values +#' # tmp$wr <- wrAdd(wt~len+species,data=tmp) +#' #----- Must choose which eqn to use with WsOpts +#' tmp$wr <- wrAdd(wt~len+species,data=tmp, +#' WsOpts=list(Ruffe=list(ref=75))) +#' peek(tmp,n=6) +#' +#' #===== Example with two uses of WsOpts (and one species without) +#' tmp <- subset(PSDWRtest,species %in% c("Ruffe","Muskellunge","Iowa Darter"), +#' select=c("species","len","wt")) +#' tmp$wr <- wrAdd(wt~len+species,data=tmp, +#' WsOpts=list(Muskellunge=list(group="overall"), +#' Ruffe=list(ref=75))) +#' peek(tmp,n=10) #' #' @rdname wrAdd #' @export @@ -85,7 +117,7 @@ wrAdd <- function (wt,...) { #' @rdname wrAdd #' @export -wrAdd.default <- function(wt,len,spec, +wrAdd.default <- function(wt,len,spec,thesaurus=NULL, units=c("metric","English"),WsOpts=NULL,...) { ###### Internal Function #===== Print error if no options given, but they are needed @@ -94,7 +126,7 @@ wrAdd.default <- function(wt,len,spec, print(df[,c("species","group","ref","method")]) #----- Error message for next two possible problems STOP("More than one Ws equation exists for ",iStrCollapse(unique(df$species)), - ". Please use a named list in 'opts=' to select one ", + ". Please use a named list in 'WsOpts=' to select one ", "equation for ",iStrCollapse(unique(df$species))," by specifing 'group', ", "'ref', or 'method' as appropriate. See details in documentation ", "and above (for reference).") @@ -107,7 +139,7 @@ wrAdd.default <- function(wt,len,spec, #----- Reduce Wsdf to just for that species Wsdf <- droplevels(Wsdf[Wsdf$species==species,]) #----- If >1 Ws eqn for species/units, then need user to further define - # with opts, otherise one Ws eqn is returned + # with opts, otherwise one Ws eqn is returned if (nrow(Wsdf)>1) { # ..... Need opts for species but none given (at all) so STOP if (is.null(WsOpts)) iErrOpts(Wsdf) @@ -126,8 +158,8 @@ wrAdd.default <- function(wt,len,spec, Wsdf <- droplevels(Wsdf[Wsdf[[names(tmp)]]==tmp,]) if (nrow(Wsdf)==0) STOP("Use of '",crit_opts[i],"=",tmp[[1]],"' for ",iStrCollapse(species), - " did not return a standard weight equation. Please reconsider your use ", - "of 'WsOpts=' to restrict to only one equation for ", + " did not return a standard weight equation. Please reconsider your ", + "use of 'WsOpts=' to restrict to only one equation for ", iStrCollapse(species),".") else if (nrow(Wsdf)>1) { #..... send error if not reduced to only one Ws equation @@ -143,7 +175,6 @@ wrAdd.default <- function(wt,len,spec, #----- Return appropriate part of Wsdf (i.e., WSlit) Wsdf } - ###### END Internal Function ###### BEGIN Main Function @@ -156,7 +187,7 @@ wrAdd.default <- function(wt,len,spec, #===== Prepare the Ws literature values data frame #----- load WSlit data frame into this functions environment - WSlit <- FSA::WSlit + WSlit <- iPrepWSlit(thesaurus) #----- isolate only those data for which those units exist WSlit <- droplevels(WSlit[WSlit$units==units,]) @@ -166,8 +197,8 @@ wrAdd.default <- function(wt,len,spec, Wr=rep(NA,length(len))) #===== Initiate a blank new data frame with same columns as old data frame ndata <- data[-c(seq_len(nrow(data))),] - #===== get list of species in data - specs <- unique(spec) + #===== get list of species in data ... change from factor to character if necessary + specs <- as.character(unique(spec)) #===== cycle through each species where WS equations are known for (i in seq_along(specs)) { @@ -199,7 +230,7 @@ wrAdd.default <- function(wt,len,spec, #' @rdname wrAdd #' @export -wrAdd.formula <- function(wt,data,units=c("metric","English"),...) { +wrAdd.formula <- function(wt,data,thesaurus=NULL,units=c("metric","English"),...) { #===== Perform some checks on the formula tmp <- iHndlFormula(wt,data,expNumR=1,expNumE=2,expNumENums=1,expNumEFacts=1) if (tmp$vnum!=3) STOP("'wt' must have one variable on the left-hand-side ", @@ -215,5 +246,44 @@ wrAdd.formula <- function(wt,data,units=c("metric","English"),...) { #===== Call the wrAdd.default wrAdd.default(tmp$mf[,tmp$Rpos],tmp$mf[,tmp$ENumPos], - tmp$mf[,tmp$EFactPos],units,...) + tmp$mf[,tmp$EFactPos],thesaurus,units,...) } + +# ============================================================================== +# Internal -- prepare WSlit by loading it and replacing its default names with +# names in the thesaurus, if any +# ============================================================================== +iPrepWSlit <- function(thesaurus) { + # Load WSlit into dat in this function namespace + dat <- FSA::WSlit + if (!is.null(thesaurus)) { + # Some sanity checks on thesaurus + if (!(is.vector(thesaurus) | is.list(thesaurus))) + STOP("'thesaurus' must be either a vector or list. ", + "Make sure it is not 'factor'ed.") + if (length(names(thesaurus))==0) + STOP("Values in 'thesaurus' must be named (with species names from 'WSlit'.)") + if (!is.character(thesaurus)) + STOP("Values in 'thesaurus' must be strings of species names.") + # thesaurus appears to be a named vector/list of strings ... start processing + # Alphabetize names in thesaurus to match dat/WSlit + thesaurus <- thesaurus[order(names(thesaurus))] + # Remove name from thesaurus if not in dat/WSlit + thes.nokeep <- which(!names(thesaurus) %in% unique(dat$species)) + if (length(thes.nokeep)>0) { + MESSAGE("The following species names were in 'thesaurus' but do ", + "not have an entry in 'WSlit' and will be ignored: ", + iStrCollapse(names(thesaurus)[thes.nokeep]),".") + thesaurus <- thesaurus[-thes.nokeep] + } + # Find species in dat/PSDlit in kept thesaurus and change names to thesaurus names + if (length(thesaurus)>0) { + tmp <- match(dat$species,names(thesaurus)) + thes.pos <- which(!is.na(tmp)) + dat$species[thes.pos] <- unname(thesaurus[tmp[thes.pos]]) + } + } + # Return dat/WSlit + dat +} + diff --git a/R/wsVal.R b/R/wsVal.R index 87a8801b..dba9b5e2 100644 --- a/R/wsVal.R +++ b/R/wsVal.R @@ -10,6 +10,8 @@ #' #' Note from above that the coefficients are returned for the TRANSFORMED model. Thus, to obtain the standard weight (Ws), the returned coefficients are used to compute the common log of Ws which must then be raised to the power of 10 to compute the Ws. #' +#' Some species have length categories separated by sub-group. For example, length categories exist for both lentic and lotic populations of Brown Trout. The length values for a sub-group may be obtained by either including the species name in \code{species} and the sub-group name in \code{group} or by using the combined species and sub-group name, with the sub-group name in parentheses, in \code{species}. Both methods are demonstrated in the examples. Note that an error is returned if a species has sub-groups but neither method is used to define the sub-group. +#' #' See examples and \href{https://fishr-core-team.github.io/FSA/articles/Computing_Relative_Weights.html}{this article} for a demonstration. #' #' @param species A string that contains the species name for which to find Ws coefficients. See details. @@ -18,6 +20,7 @@ #' @param ref A numeric that indicates which percentile the equation should be returned for. Note that the vast majority of equations only exist for the \code{75}th percentile (DEFAULT). #' @param method A string that indicates which equation-derivation method should be used (one of \code{"RLP"}, \code{"EmP"}, or \code{"Other"}). Defaults to \code{NULL} which will result in the only method available being returned or an error asking the user to choose a method for equations for which more than one method is available (which is the case for very few species). #' @param simplify A logical that indicates whether the \sQuote{units}, \sQuote{ref}, \sQuote{measure}, \sQuote{method}, \sQuote{comments}, and \sQuote{source} fields should be included (\code{=FALSE}) or not (\code{=TRUE}; DEFAULT). See details. +#' @param dat Data.frame of Gabelhouse length categories for all species. Defaults to `WSlit` and is generally not used by the user (this simplifies use of this function in \code{wrAdd}). #' #' @return A one row data frame from \code{\link{WSlit}} that contains all known information about the standard weight equation for a given species, type of measurement units, and reference percentile if \code{simplify=FALSE}. If \code{simplify=TRUE} then only the species; minimum and maximum length for which the standard equation should be applied; and intercept, slope, and quadratic coefficients for the standard weight equation. Note that the maximum length and the quadratic coefficient will not be returned if they do not exist in \code{\link{WSlit}} for the species. #' @@ -37,90 +40,91 @@ #' #===== List all available Ws equations #' wsVal() #' -#' #===== Find equations for Bluegill, in different formats -#' wsVal("Bluegill") -#' wsVal("Bluegill",units="metric") -#' wsVal("Bluegill",units="English") -#' wsVal("Bluegill",units="English",simplify=TRUE) -#' -#' #===== Find equation for Cutthroat Trout, demonstrating use of group -#' wsVal("Cutthroat Trout",group="lotic") -#' wsVal("Cutthroat Trout",group="lentic") +#' #===== Find equations for Yellow Perch, in different formats +#' wsVal("Yellow Perch") +#' wsVal("Yellow Perch",units="metric") # same as default +#' wsVal("Yellow Perch",units="English") +#' wsVal("Yellow Perch",units="English",simplify=TRUE) #' #' #===== Find equation for Ruffe, demonstrating quadratic formula #' wsVal("Ruffe",units="metric",ref=75,simplify=TRUE) #' wsVal("Ruffe",units="metric",ref=50,simplify=TRUE) #' +#' #===== Find equation for Brown Trout, which has equations for sub-groups +#' #----- demonstrating use of group= argument +#' wsVal("Brown Trout",group="lotic") +#' wsVal("Brown Trout",group="lentic") +#' #----- demonstrating group combined in species name, so no group= arg +#' wsVal("Brown Trout (lotic)") +#' wsVal("Brown Trout (lentic)") +#' #' #===== Add Ws & Wr values to a data frame (for one species) ... also see wrAdd() -#' #----- Get Ws equation info -#' wsBG <- wsVal("Bluegill",units="metric") -#' wsBG +#' #----- Example data from PSDWRtest, simplify variables for this example +#' yepdf <- subset(PSDWRtest,species=="Yellow Perch",select=c("species","len","wt")) +#' str(yepdf) #' -#' #----- Get example data -#' data(BluegillLM,package="FSAdata") -#' str(BluegillLM) +#' #----- Get Ws equation info +#' ( wsYEP <- wsVal("Yellow Perch",units="metric") ) #' -#' #----- Add Ws (eqn is on log10-log10 scale ... so log10 len, 10^ result) -#' BluegillLM$ws <- 10^(wsBG[["int"]]+wsBG[["slope"]]*log10(BluegillLM$tl)) +#' #----- Add Ws (eqn is on log10-log10 scale ... so log10 length, 10^ result) +#' yepdf$ws <- 10^(wsYEP[["int"]]+wsYEP[["slope"]]*log10(yepdf$len)) #' #' #----- Change Ws for fish less than min.TL to NA -#' BluegillLM$ws[BluegillLM$tl% -#' mutate(ws=10^(wsBG[["int"]]+wsBG[["slope"]]*log10(tl)), -#' ws=ifelse(tl% filter(species=="Yellow Perch") %>% select(species,len,wt) %>% +#' mutate(ws=10^(wsYEP[["int"]]+wsYEP[["slope"]]*log10(len)), +#' ws=ifelse(len1) STOP("'species' must contain only one name.") - if (species=="List") iListSpecies(WSlit) + if (species=="List") iListSpecies(dat) else { #===== Make checks on species - #----- Species given, make sure in WSlit, then reduce data.frame to that species - if (!any(unique(WSlit$species)==species)) { + #----- Species given, make sure in dat/WSlit, then reduce data.frame to that species + if (!any(unique(dat$species)==species)) { tmp <- paste0("There is no Ws equation in 'WSlit' for ",iStrCollapse(species),".") - if (any(unique(WSlit$species)==capFirst(species))) + if (any(unique(dat$species)==capFirst(species))) STOP(tmp," However, there is an entry for ",iStrCollapse(capFirst(species)), " (note spelling, including capitalization).\n\n") else STOP(tmp," Type 'wsVal()' to see a list of available species.\n\n") - } else df <- droplevels(WSlit[WSlit$species==species,]) + } else df <- droplevels(dat[dat$species==species,]) #===== Determine if "group"s for that species and then handle if (any(!is.na(df$group))) { - #----- There are groups in WSlit, user did not supply group= so stop + #----- There are groups in dat/WSlit, user did not supply group= so stop if (is.null(group)) STOP(iStrCollapse(species)," has Ws equations for these sub-groups: ", iStrCollapse(unique(df$group)), ". Please use 'group=' to select the equation for one of these groups.\n\n") - #----- There are groups in WSlit, user supplied group=, is it good? + #----- There are groups in dat/WSlit, user supplied group=, is it good? if (!group %in% unique(df$group)) STOP("There is no ",iStrCollapse(group)," group for ",iStrCollapse(species), ". Please select from one of these groups: ", iStrCollapse(unique(df$group),last="or"),".\n\n") - #----- There are groups in WSlit, user supplied group= is good, reduce df + #----- There are groups in dat/WSlit, user supplied group= is good, reduce df df <- droplevels(df[df$group==group,]) } else { - #----- There are no groups in WSlit ... check if user supplied group= + #----- There are no groups in dat/WSlit ... check if user supplied group= if (!is.null(group)) WARN("There are no groups for ",iStrCollapse(species), "; thus, your 'group=' has been ignored.") #---- drop group variable from df @@ -129,7 +133,7 @@ wsVal <- function(species="List",group=NULL, #===== Checks on method tmp <- unique(df$method) - #----- If more than one method in WSlit but method NULL then force a choice + #----- If more than one method in dat/WSlit but method NULL then force a choice # otherwise (i.e., one method and method NULL) then continue with df if (is.null(method) & length(tmp)>1) STOP("Ws equations exist for both the RLP and EmP 'method's for ", @@ -151,7 +155,7 @@ wsVal <- function(species="List",group=NULL, #===== Make checks on ref (if OK reduce data frame to that ref) tmp <- unique(df$ref) - #----- If more than one ref in WSlit but ref is NULL then force a choice + #----- If more than one ref in dat/WSlit but ref is NULL then force a choice # otherwise (i.e., one ref and ref is NULL) then continue with df if (is.null(ref) & length(tmp)>1) STOP("Ws equations exist for more than one 'ref'erence value for ", @@ -183,4 +187,4 @@ wsVal <- function(species="List",group=NULL, df <- df[,names(df) %in% c("species",tmp,"int","slope","quad")] df } -} +} \ No newline at end of file diff --git a/data-raw/PSDlit.csv b/data-raw/PSDlit.csv index d6fe7abd..48794fe8 100644 --- a/data-raw/PSDlit.csv +++ b/data-raw/PSDlit.csv @@ -1,4 +1,5 @@ species,group,substock.in,stock.in,quality.in,preferred.in,memorable.in,trophy.in,substock.cm,stock.cm,quality.cm,preferred.cm,memorable.cm,trophy.cm,source +Alabama Bass,NA,0,7,11,14,17,20,0,18,28,35,43,51,Sammons et al. (2025) Arctic Grayling,NA,0,8,12,16,20,22,0,20,30,40,50,55,Hyatt (2000) Bighead Carp,NA,0,11.75,21.25,26.75,35,43.75,0,30,54,68,89,111,Phelps and Willis (2013) Bigmouth Buffalo,NA,0,11,18,24,30,37,0,28,46,61,76,94,Bister et al. (2000) @@ -10,16 +11,24 @@ Bluegill,NA,0,3,6,8,10,12,0,8,15,20,25,30,Gabelhouse (1984a) Brook Trout,overall,0,8,12,16,20,24,0,20,30,40,50,60,Hyatt (2000) Brook Trout,lentic,0,8,13,NA,NA,NA,0,20,33,NA,NA,NA,Anderson (1980) Brook Trout,lotic,0,5,8,NA,NA,NA,0,13,20,NA,NA,NA,Anderson (1980) +Brook Trout (overall),NA,0,8,12,16,20,24,0,20,30,40,50,60,Hyatt (2000) +Brook Trout (lentic),NA,0,8,13,NA,NA,NA,0,20,33,NA,NA,NA,Anderson (1980) +Brook Trout (lotic),NA,0,5,8,NA,NA,NA,0,13,20,NA,NA,NA,Anderson (1980) Brown Bullhead,NA,0,5,8,11,14,17,0,13,20,28,36,43,Bister et al. (2000) Brown Trout,lentic,0,8,12,16,20,24,0,20,30,40,50,60,Hyatt and Hubert (2001) Brown Trout,lotic,0,6,9,12,15,18,0,15,23,30,38,46,Milewski and Brown (1994) +Brown Trout (lentic),NA,0,8,12,16,20,24,0,20,30,40,50,60,Hyatt and Hubert (2001) +Brown Trout (lotic),NA,0,6,9,12,15,18,0,15,23,30,38,46,Milewski and Brown (1994) Bull Trout,NA,0,8,16,20,26,31,0,20,40,50,65,80,Hyatt (2000) Burbot,NA,0,8,15,21,26,32,0,20,38,53,67,82,Fisher et al. (1996) Chain Pickerel,NA,0,10,15,20,25,30,0,25,38,51,63,76,Gabelhouse (1984a) Channel Catfish,NA,0,11,16,24,28,36,0,28,41,61,71,91,Gabelhouse (1984a) Chinook Salmon,landlocked,0,11,18,24,30,37,0,28,46,61,76,94,Hill and Duffy (1993) +Chinook Salmon (landlocked),NA,0,11,18,24,30,37,0,28,46,61,76,94,Hill and Duffy (1993) Common Carp,NA,0,11,16,21,26,33,0,28,41,53,66,84,Gabelhouse (1984a) Cutthroat Trout,NA,0,8,14,18,24,30,0,20,35,45,60,75,Kruse and Hubert (1997) +Cutthroat Trout (lentic),NA,0,8,14,18,24,30,0,20,35,45,60,75,Kruse and Hubert (1997) +Cutthroat Trout (lotic),NA,0,8,14,18,24,30,0,20,35,45,60,75,Kruse and Hubert (1997) Flathead Catfish,NA,0,14,20,28,34,40,0,35,51,71,86,102,Quinn (1991) Flier,NA,0,3,5,6,7,9,0,8,13,15,18,23,Bonvechio et al (2025) Freshwater Drum,NA,0,8,12,15,20,25,0,20,30,38,51,63,Gabelhouse (1984a) @@ -35,14 +44,23 @@ Largemouth Bass,NA,0,8,12,15,20,25,0,20,30,38,51,63,Gabelhouse (1984a) Longear Sunfish,NA,0,2.5,4,5,7,8.25,0,6,10,13,17,21,Miller et al. (2025) Longnose Gar,NA,0,16,27,36,45,55,0,41,69,91,114,140,Bister et al. (2000) Muskellunge,NA,0,20,30,38,42,50,0,51,76,97,107,127,Gabelhouse (1984a) +Muskellunge (overall),NA,0,20,30,38,42,50,0,51,76,97,107,127,Gabelhouse (1984a) +Muskellunge (female),NA,0,20,30,38,42,50,0,51,76,97,107,127,Gabelhouse (1984a) +Muskellunge (male),NA,0,20,30,38,42,50,0,51,76,97,107,127,Gabelhouse (1984a) Northern Pike,NA,0,14,21,28,34,44,0,35,53,71,86,112,Gabelhouse (1984a) +Northern Pikeminnow,NA,0,7,10,14,16,20,0,17,26,35,41,51,Voss and Quist (2025) Northern Snakehead,NA,0,7.5,13,16.5,22,27.5,0,19,34,42,55,70,Kim et al. (2019) Paddlefish,NA,0,16,26,33,41,51,0,41,66,84,104,130,Brown and Murphy (1993) +Paddlefish (overall),NA,0,16,26,33,41,51,0,41,66,84,104,130,Brown and Murphy (1993) +Paddlefish (female),NA,0,16,26,33,41,51,0,41,66,84,104,130,Brown and Murphy (1993) +Paddlefish (male),NA,0,16,26,33,41,51,0,41,66,84,104,130,Brown and Murphy (1993) Pallid Sturgeon,NA,0,13,25,33,41,50,0,33,63,84,104,147,Shuman et al. (2006) -Palmetto Bass,revised,0,10,16,20,24,28,0,25,41,51,61,71,Dumont and Neely (2011) -Palmetto Bass,original,0,8,12,15,20,25,0,20,30,38,51,63,Gabelhouse (1984a) +Palmetto Bass,NA,0,10,16,20,24,28,0,25,41,51,61,71,Dumont and Neely (2011) +Palmetto Bass (original),NA,0,8,12,15,20,25,0,20,30,38,51,63,Gabelhouse (1984a) Pumpkinseed,NA,0,3,6,8,10,12,0,8,15,20,25,30,Gabelhouse (1984a) Rainbow Trout,NA,0,10,16,20,26,31,0,25,40,50,65,80,Simpkins and Hubert (1996) +Rainbow Trout (lentic),NA,0,10,16,20,26,31,0,25,40,50,65,80,Simpkins and Hubert (1996) +Rainbow Trout (lotic),NA,0,10,16,20,26,31,0,25,40,50,65,80,Simpkins and Hubert (1996) Redbreast Sunfish,NA,0,3,5,7,8,10,0,8,13,18,20,25,Bonvechio et al. (2023) Redear Sunfish,NA,0,4,7,9,11,13,0,10,18,23,28,33,Gabelhouse (1984a) River Carpsucker,NA,0,7,11,14,18,22,0,18,28,36,46,56,Bister et al. (2000) @@ -56,14 +74,18 @@ Silver Carp,NA,0,10,17.75,22,29,36.5,0,25,45,56,74,93,Phelps and Willis (2013) Smallmouth Bass,NA,0,7,11,14,17,20,0,18,28,35,43,51,Gabelhouse (1984a) Smallmouth Buffalo ,NA,0,11,18,24,30,37,0,28,46,61,76,94,Bister et al. (2000) Splake,NA,0,8,10,14,16,22,0,20,25,35,40,55,Hyatt (2000) -Spotted Bass,NA,0,7,11,14,17,20,0,18,28,35,43,51,Gabelhouse (1984a) +Spotted Bass,NA,0,5.5,9,12,14,17.25,0,15,23,30,35,44,Sammons et al. (2025) +Spotted Bass (original),NA,0,7,11,14,17,20,0,18,28,35,43,51,Gabelhouse (1984a) Spotted Gar,NA,0,12,19,25,31,39,0,30,48,64,79,99,Bister et al. (2000) Spotted Sunfish,NA,0,2,4,5,6,7,0,5,10,13,15,18,Bonvechio et al. (2023) Striped Bass,landlocked,0,12,20,30,35,45,0,30,51,76,89,114,Gabelhouse (1984a) +Striped Bass (landlocked),NA,0,12,20,30,35,45,0,30,51,76,89,114,Gabelhouse (1984a) Striped Bass X White Bass,NA,0,10,16,20,24,28,0,25,41,51,61,71,Dumont and Neely (2011) Suwannee Bass,NA,0,6,9.75,11.75,13.75,15.75,0,15,25,30,35,40,Bonvechio et al. (2010) Utah Chub,NA,0,4,8,10,12,15,0,10,20,25,30,38,Black et al. (2021) Walleye,NA,0,10,15,20,25,30,0,25,38,51,63,76,Gabelhouse (1984a) +Walleye (overall),NA,0,10,15,20,25,30,0,25,38,51,63,76,Gabelhouse (1984a) +Walleye (30-149 mm),NA,0,6,NA,NA,NA,NA,0,15,NA,NA,NA,NA,Gabelhouse (1984a) Warmouth,NA,0,3,6,8,10,12,0,8,15,20,25,30,Gabelhouse (1984a) White Bass,NA,0,6,9,12,15,18,0,15,23,30,38,46,Gabelhouse (1984a) White Catfish,NA,0,8,13,17,21,26,0,20,33,43,53,66,Bister et al. (2000) diff --git a/data-raw/WSlit.csv b/data-raw/WSlit.csv index 7ff65ce0..31eb5640 100644 --- a/data-raw/WSlit.csv +++ b/data-raw/WSlit.csv @@ -1,19 +1,27 @@ species,group,measure,units,ref,method,min.len,max.len,int,slope,quad,source,comment Aegean Chub,NA,TL,metric,75,EmP,70,220,-3.801,1.783,0.329,Giannetto et al. (2012),none African Sharptooth Catfish,NA,TL,metric,75,EmP,180,450,-3.668,1.885,0.2087,Emiroglu et al. (2018),only from Sakarya River Basin (Turkey) -Alabama Bass,NA,TL,metric,75,RLP,100,NA,-5.598,3.2904,NA,Dicenzo et al. (1995),min.len not made clear (assumed same as Spotted Bass); same as Spotted Bass (Alabama subspecies) +Alabama Bass,NA,TL,metric,75,EmP,150,550,-5.6189,3.284,NA,Sammons et al. (2025),RLP and EmP (quadratic) models not recommended +Alabama Bass,NA,TL,English,75,EmP,6,22,-3.5339,3.175,NA,Sammons et al. (2025),RLP and EmP (quadratic) models not recommended +Alabama Bass (original),NA,TL,metric,75,RLP,100,NA,-5.598,3.2904,NA,Dicenzo et al. (1995),HAS BEEN REVISED; min.len not made clear (assumed same as Spotted Bass) Ankara Nase,NA,TL,metric,75,EmP,70,240,-10.017,7.402,-0.971,Emiroglu et al. (2020),only from Turkey Arctic Grayling,NA,TL,metric,75,RLP,150,NA,-5.241,3.083,NA,Gilham et al. (2021),authors note that either RLP or EmP method may be used Arctic Grayling,NA,TL,metric,75,EmP,150,NA,-5.279,3.096,NA,Gilham et al. (2021),authors note that either RLP or EmP method may be used Bighead Carp,NA,TL,metric,50,RLP,160,NA,-4.65006,2.88934,NA,Lamer et al. (2019),none Bigmouth Buffalo,NA,TL,English,75,RLP,6,NA,-3.346,3.118,NA,Bister et al. (2000),none Bigmouth Buffalo,NA,TL,metric,75,RLP,150,NA,-5.069,3.118,NA,Bister et al. (2000),none -Bigmouth Sleepers,all,TL,metric,25,EmP,70,390,-6,3.631,-0.111,Cooney and Kwak (2010),none -Bigmouth Sleepers,all,TL,metric,50,EmP,70,390,-5.4,3.153,-0.011,Cooney and Kwak (2010),quadratic term not significant -Bigmouth Sleepers,all,TL,metric,75,EmP,70,390,-4.323,2.237,0.188,Cooney and Kwak (2010),none +Bigmouth Sleepers,overall,TL,metric,25,EmP,70,390,-6,3.631,-0.111,Cooney and Kwak (2010),none +Bigmouth Sleepers,overall,TL,metric,50,EmP,70,390,-5.4,3.153,-0.011,Cooney and Kwak (2010),quadratic term not significant +Bigmouth Sleepers,overall,TL,metric,75,EmP,70,390,-4.323,2.237,0.188,Cooney and Kwak (2010),none Bigmouth Sleepers,lotic,TL,metric,25,EmP,40,390,-6.083,3.708,-0.128,Cooney and Kwak (2010),none Bigmouth Sleepers,lotic,TL,metric,50,EmP,40,390,-5.574,3.302,-0.043,Cooney and Kwak (2010),quadratic term not significant Bigmouth Sleepers,lotic,TL,metric,75,EmP,40,390,-4.933,2.764,0.075,Cooney and Kwak (2010),quadratic term not significant +Bigmouth Sleepers (overall),NA,TL,metric,25,EmP,70,390,-6,3.631,-0.111,Cooney and Kwak (2010),none +Bigmouth Sleepers (overall),NA,TL,metric,50,EmP,70,390,-5.4,3.153,-0.011,Cooney and Kwak (2010),quadratic term not significant +Bigmouth Sleepers (overall),NA,TL,metric,75,EmP,70,390,-4.323,2.237,0.188,Cooney and Kwak (2010),none +Bigmouth Sleepers (lotic),NA,TL,metric,25,EmP,40,390,-6.083,3.708,-0.128,Cooney and Kwak (2010),none +Bigmouth Sleepers (lotic),NA,TL,metric,50,EmP,40,390,-5.574,3.302,-0.043,Cooney and Kwak (2010),quadratic term not significant +Bigmouth Sleepers (lotic),NA,TL,metric,75,EmP,40,390,-4.933,2.764,0.075,Cooney and Kwak (2010),quadratic term not significant Black Bullhead,NA,TL,English,75,RLP,5,NA,-3.297,3.085,NA,Bister et al. (2000),none Black Bullhead,NA,TL,metric,75,RLP,130,NA,-4.974,3.085,NA,Bister et al. (2000),none Black Crappie,NA,TL,English,75,RLP,4,NA,-3.576,3.345,NA,Neumann and Murphy (1991),none @@ -31,12 +39,23 @@ Brook Chub,NA,TL,metric,75,EmP,90,210,-7.75,5.75,-0.66,Giannetto et al. (2012),n Brook Trout,overall,TL,English,75,RLP,4.75,NA,-3.483,3.103,NA,Hyatt and Hubert (2001a),none Brook Trout,overall,TL,metric,75,RLP,120,NA,-5.186,3.103,NA,Hyatt and Hubert (2001a),none Brook Trout,Appalachia,TL,metric,75,EmP,80,226,-3.364,1.378,0.397,Harris et al. (2021),RLP and EmP (linear) models had length-related bias (thus not recommended) +Brook Trout (overall),NA,TL,English,75,RLP,4.75,NA,-3.483,3.103,NA,Hyatt and Hubert (2001a),none +Brook Trout (overall),NA,TL,metric,75,RLP,120,NA,-5.186,3.103,NA,Hyatt and Hubert (2001a),none +Brook Trout (lentic),NA,TL,English,75,RLP,4.75,NA,-3.483,3.103,NA,Hyatt and Hubert (2001a),"Same as Brook Trout, but added lentic/lotic for ease of use with PSDadd" +Brook Trout (lentic),NA,TL,metric,75,RLP,120,NA,-5.186,3.103,NA,Hyatt and Hubert (2001a),"Same as Brook Trout, but added lentic/lotic for ease of use with PSDadd" +Brook Trout (lotic),NA,TL,English,75,RLP,4.75,NA,-3.483,3.103,NA,Hyatt and Hubert (2001a),"Same as Brook Trout, but added lentic/lotic for ease of use with PSDadd" +Brook Trout (lotic),NA,TL,metric,75,RLP,120,NA,-5.186,3.103,NA,Hyatt and Hubert (2001a),"Same as Brook Trout, but added lentic/lotic for ease of use with PSDadd" +Brook Trout (Appalachia),NA,TL,metric,75,EmP,80,226,-3.364,1.378,0.397,Harris et al. (2021),RLP and EmP (linear) models had length-related bias (thus not recommended) Brown Bullhead,NA,TL,English,75,RLP,5,NA,-3.371,3.105,NA,Bister et al. (2000),none Brown Bullhead,NA,TL,metric,75,RLP,130,NA,-5.076,3.105,NA,Bister et al. (2000),none Brown Trout,lentic,TL,English,75,RLP,5.5,NA,-3.592,3.194,NA,Hyatt and Hubert (2001b),none Brown Trout,lentic,TL,metric,75,RLP,140,NA,-5.422,3.194,NA,Hyatt and Hubert (2001b),none Brown Trout,lotic,TL,English,75,RLP,5.5,NA,-3.366,2.96,NA,Milewski and Brown (1994),none Brown Trout,lotic,TL,metric,75,RLP,140,NA,-4.867,2.96,NA,Milewski and Brown (1994),none +Brown Trout (lentic),NA,TL,English,75,RLP,5.5,NA,-3.592,3.194,NA,Hyatt and Hubert (2001b),none +Brown Trout (lentic),NA,TL,metric,75,RLP,140,NA,-5.422,3.194,NA,Hyatt and Hubert (2001b),none +Brown Trout (lotic),NA,TL,English,75,RLP,5.5,NA,-3.366,2.96,NA,Milewski and Brown (1994),none +Brown Trout (lotic),NA,TL,metric,75,RLP,140,NA,-4.867,2.96,NA,Milewski and Brown (1994),none Bull Trout,NA,TL,English,75,RLP,4.75,NA,-3.608,3.115,NA,Hyatt and Hubert (2000),none Bull Trout,NA,TL,metric,75,RLP,120,NA,-5.327,3.115,NA,Hyatt and Hubert (2000),none Burbot,NA,TL,English,75,RLP,8,NA,-3.454,2.898,NA,Fisher et al. (1996),none @@ -48,6 +67,8 @@ Channel Catfish,NA,TL,English,75,RLP,2.75,NA,-3.829,3.294,NA,Brown et al. (1995) Channel Catfish,NA,TL,metric,75,RLP,70,NA,-5.8,3.294,NA,Brown et al. (1995),none Chinook Salmon,NA,TL,English,75,RLP,8,NA,-3.243,2.901,NA,Halseth et al. (1990),none Chinook Salmon,NA,TL,metric,75,RLP,200,NA,-4.661,2.901,NA,Halseth et al. (1990),none +Chinook Salmon (landlocked),NA,TL,English,75,RLP,8,NA,-3.243,2.901,NA,Halseth et al. (1990),Not clear just landlocked; added to simplify use with PSDlit +Chinook Salmon (landlocked),NA,TL,metric,75,RLP,200,NA,-4.661,2.901,NA,Halseth et al. (1990),Not clear just landlocked; added to simplify use with PSDlit Cisco,NA,TL,English,75,RLP,4,NA,-3.644,3.224,NA,Fisher and Fielder (1998),same as for Lake Herring Cisco,NA,TL,metric,75,RLP,100,NA,-5.517,3.224,NA,Fisher and Fielder (1998),same as for Lake Herring Common Carp,NA,TL,English,75,RLP,8,NA,-3.194,2.92,NA,Bister et al. (2000),none @@ -56,6 +77,10 @@ Cutthroat Trout,lentic,TL,English,75,RLP,5,NA,-3.514,3.086,NA,Kruse and Hubert ( Cutthroat Trout,lentic,TL,metric,75,RLP,130,NA,-5.192,3.086,NA,Kruse and Hubert (1997),none Cutthroat Trout,lotic,TL,English,75,RLP,5,NA,-3.492,3.099,NA,Kruse and Hubert (1997),none Cutthroat Trout,lotic,TL,metric,75,RLP,130,NA,-5.189,3.099,NA,Kruse and Hubert (1997),none +Cutthroat Trout (lentic),NA,TL,English,75,RLP,5,NA,-3.514,3.086,NA,Kruse and Hubert (1997),none +Cutthroat Trout (lentic),NA,TL,metric,75,RLP,130,NA,-5.192,3.086,NA,Kruse and Hubert (1997),none +Cutthroat Trout (lotic),NA,TL,English,75,RLP,5,NA,-3.492,3.099,NA,Kruse and Hubert (1997),none +Cutthroat Trout (lotic),NA,TL,metric,75,RLP,130,NA,-5.189,3.099,NA,Kruse and Hubert (1997),none European Chub,NA,TL,metric,75,EmP,70,470,-4.79,2.68,0.1,Giannetto et al. (2011),only from Italy (see Cavedano Chub) European Perch,NA,TL,metric,75,EmP,80,460,-3.1483,1.2663,0.4291,Giannetto et al. (2012),none Flannelmouth Sucker,NA,TL,English,75,RLP,4,NA,-3.527,3.068,NA,Didenko et al. (2004),none @@ -106,21 +131,32 @@ Muskellunge,male,TL,English,75,RLP,15,NA,-3.921,3.245,NA,Neumann and Willis (199 Muskellunge,male,TL,metric,75,RLP,380,NA,-5.823,3.245,NA,Neumann and Willis (1994),none Muskellunge,overall,TL,English,75,RLP,15,NA,-4.052,3.325,NA,Neumann and Willis (1994),none Muskellunge,overall,TL,metric,75,RLP,380,NA,-6.066,3.325,NA,Neumann and Willis (1994),none +Muskellunge (female),NA,TL,English,75,RLP,15,NA,-4.07,3.34,NA,Neumann and Willis (1994),none +Muskellunge (female),NA,TL,metric,75,RLP,380,NA,-6.105,3.34,NA,Neumann and Willis (1994),none +Muskellunge (male),NA,TL,English,75,RLP,15,NA,-3.921,3.245,NA,Neumann and Willis (1994),none +Muskellunge (male),NA,TL,metric,75,RLP,380,NA,-5.823,3.245,NA,Neumann and Willis (1994),none +Muskellunge (overall),NA,TL,English,75,RLP,15,NA,-4.052,3.325,NA,Neumann and Willis (1994),none +Muskellunge (overall),NA,TL,metric,75,RLP,380,NA,-6.066,3.325,NA,Neumann and Willis (1994),none Nile Tilapia,NA,TL,metric,75,EmP,80,280,-8.7951,6.751,-0.8479,Emiroglu et al. (2018),only from Sakarya River Basin (Turkey) Nipple-Lip Scraper,NA,TL,metric,75,EmP,70,360,-5.966,3.833,-0.181,Emiroglu et al. (2020),only from Turkey Northern Pike,NA,TL,English,75,RLP,4,NA,-3.745,3.096,NA,Anderson and Neumann (1996),none Northern Pike,NA,TL,metric,75,RLP,100,NA,-5.437,3.096,NA,Anderson and Neumann (1996),none -Northern Pikeminnow,NA,FL,English,75,RLP,10,NA,-3.328,2.986,NA,Parker et al. (1995),same as Northern Squawfish -Northern Pikeminnow,NA,FL,metric,75,RLP,250,NA,-4.886,2.986,NA,Parker et al. (1995),same as Northern Squawfish +Northern Pikeminnow,NA,FL,metric,50,EmP,90,580,-5.258,3.135,NA,Voss and Quist (2025),"Other methods and quartiles used, but this was only one that was length-unbiased" +Northern Pikeminnow (original),NA,FL,English,75,RLP,10,NA,-3.328,2.986,NA,Parker et al. (1995),HAS BEEN REVISED; Voss and Quist (2025) note that these equations are problematic and should not be used +Northern Pikeminnow (original),NA,FL,metric,75,RLP,250,NA,-4.886,2.986,NA,Parker et al. (1995),HAS BEEN REVISED; Voss and Quist (2025) note that these equations are problematic and should not be used Northern Snakehead,NA,TL,metric,75,RLP,200,NA,-5.142,3.0418,NA,Kim et al. (2019),from 4 populations -Northern Squawfish,NA,FL,English,75,RLP,10,NA,-3.328,2.986,NA,Parker et al. (1995),same as Northern Pikeminnow -Northern Squawfish,NA,FL,metric,75,RLP,250,NA,-4.886,2.986,NA,Parker et al. (1995),same as Northern Pikeminnow Paddlefish,female,BL,English,75,RLP,11,NA,-2.822,2.782,NA,Brown and Murphy (1993),none Paddlefish,female,BL,metric,75,RLP,280,NA,-4.073,2.782,NA,Brown and Murphy (1993),none Paddlefish,male,BL,English,75,RLP,11,NA,-3.063,2.91,NA,Brown and Murphy (1993),none Paddlefish,male,BL,metric,75,RLP,280,NA,-4.494,2.91,NA,Brown and Murphy (1993),none Paddlefish,overall,BL,English,75,RLP,11,NA,-3.34,3.092,NA,Brown and Murphy (1993),none Paddlefish,overall,BL,metric,75,RLP,280,NA,-5.027,3.092,NA,Brown and Murphy (1993),none +Paddlefish (female),NA,BL,English,75,RLP,11,NA,-2.822,2.782,NA,Brown and Murphy (1993),none +Paddlefish (female),NA,BL,metric,75,RLP,280,NA,-4.073,2.782,NA,Brown and Murphy (1993),none +Paddlefish (male),NA,BL,English,75,RLP,11,NA,-3.063,2.91,NA,Brown and Murphy (1993),none +Paddlefish (male),NA,BL,metric,75,RLP,280,NA,-4.494,2.91,NA,Brown and Murphy (1993),none +Paddlefish (overall),NA,BL,English,75,RLP,11,NA,-3.34,3.092,NA,Brown and Murphy (1993),none +Paddlefish (overall),NA,BL,metric,75,RLP,280,NA,-5.027,3.092,NA,Brown and Murphy (1993),none Palmetto Bass,NA,TL,English,75,RLP,4.5,NA,-3.448,3.139,NA,Brown and Murphy (1991b),same as Striped Bass x White Bass Palmetto Bass,NA,TL,metric,75,RLP,115,NA,-5.201,3.139,NA,Brown and Murphy (1991b),same as Striped Bass x White Bass Pejerrey,NA,TL,English,75,RLP,10,NA,-3.651,3.097,NA,Baigun and Anderson (1993),none @@ -132,6 +168,10 @@ Rainbow Trout,lentic,TL,English,75,RLP,4.75,NA,-3.354,2.99,NA,Simpkins and Huber Rainbow Trout,lentic,TL,metric,75,RLP,120,NA,-4.898,2.99,NA,Simpkins and Hubert (1996),none Rainbow Trout,lotic,TL,English,75,RLP,4.75,NA,-3.432,3.024,NA,Simpkins and Hubert (1996),none Rainbow Trout,lotic,TL,metric,75,RLP,120,NA,-5.023,3.024,NA,Simpkins and Hubert (1996),none +Rainbow Trout (lentic),NA,TL,English,75,RLP,4.75,NA,-3.354,2.99,NA,Simpkins and Hubert (1996),none +Rainbow Trout (lentic),NA,TL,metric,75,RLP,120,NA,-4.898,2.99,NA,Simpkins and Hubert (1996),none +Rainbow Trout (lotic),NA,TL,English,75,RLP,4.75,NA,-3.432,3.024,NA,Simpkins and Hubert (1996),none +Rainbow Trout (lotic),NA,TL,metric,75,RLP,120,NA,-5.023,3.024,NA,Simpkins and Hubert (1996),none Razorback Sucker,NA,TL,English,75,RLP,4.25,NA,-3.35,2.985,NA,Didenko et al. (2004),none Razorback Sucker,NA,TL,metric,75,RLP,110,NA,-4.886,2.985,NA,Didenko et al. (2004),none Redbreast Sunfish,NA,TL,English,75,EmP,3,11.75,-3.2727,3.1215,NA,Bonvechio et al. (2023),also used RLP and EmP-quadratic but did not recommend @@ -169,17 +209,20 @@ Smallmouth Bass,NA,TL,metric,75,RLP,150,NA,-5.329,3.2,NA,Kolander et al. (1993), Smallmouth Buffalo,NA,TL,English,75,RLP,8,NA,-3.448,3.208,NA,Bister et al. (2000),none Smallmouth Buffalo,NA,TL,metric,75,RLP,200,NA,-5.298,3.208,NA,Bister et al. (2000),none South European Roach,NA,TL,metric,75,EmP,60,200,-4.043,1.919,0.315,Giannetto et al. (2016),none -Spotted Bass,overall,TL,English,75,RLP,4,NA,-3.533,3.215,NA,Wiens et al. (1996),none -Spotted Bass,overall,TL,metric,75,RLP,100,NA,-5.392,3.215,NA,Wiens et al. (1996),none -Spotted Bass,Alabama subspecies,TL,metric,75,RLP,100,NA,-5.598,3.2904,NA,Dicenzo et al. (1995),min.len not made clear (assumed same as Spotted Bass); same as Alabama Bass +Spotted Bass,NA,TL,metric,75,EmP,150,490,-5.3467,3.197,NA,Sammons et al. (2025),also used RLP and EmP-quadratic but did not recommend +Spotted Bass,NA,TL,English,75,EmP,6,19.25,-3.3641,3.064,NA,Sammons et al. (2025),also used RLP and EmP-quadratic but did not recommend +Spotted Bass (original),NA,TL,English,75,RLP,4,NA,-3.533,3.215,NA,Wiens et al. (1996),HAS BEEN REVISED +Spotted Bass (original),NA,TL,metric,75,RLP,100,NA,-5.392,3.215,NA,Wiens et al. (1996),HAS BEEN REVISED Spotted Gar,NA,TL,English,75,RLP,10,NA,-4.388,3.431,NA,Bister et al. (2000),none Spotted Gar,NA,TL,metric,75,RLP,250,NA,-6.551,3.431,NA,Bister et al. (2000),none Spotted Sunfish,NA,TL,English,75,EmP,2.75,8,-3.3468,3.3343,NA,Bonvechio et al. (2023),also used RLP and EmP-quadratic but did not recommend Spotted Sunfish,NA,TL,metric,75,EmP,70,200,-5.3739,3.3343,NA,Bonvechio et al. (2023),also used RLP and EmP-quadratic but did not recommend Striped Bass,NA,TL,English,75,RLP,6,NA,-3.358,3.007,NA,Brown and Murphy (1991b),none Striped Bass,NA,TL,metric,75,RLP,150,NA,-4.924,3.007,NA,Brown and Murphy (1991b),none -Striped Bass X White Bass,NA,TL,English,75,RLP,4.5,NA,-3.448,3.139,NA,Brown and Murphy (1991b),same as Palmetto Bass and Striped Bass (Hybrid) -Striped Bass X White Bass,NA,TL,metric,75,RLP,115,NA,-5.201,3.139,NA,Brown and Murphy (1991b),same as Palmetto Bass and Striped Bass (Hybrid) +Striped Bass (landlocked),NA,TL,English,75,RLP,6,NA,-3.358,3.007,NA,Brown and Murphy (1991b),Not clear just landlocked; added to simplify use with PSDlit +Striped Bass (landlocked),NA,TL,metric,75,RLP,150,NA,-4.924,3.007,NA,Brown and Murphy (1991b),Not clear just landlocked; added to simplify use with PSDlit +Striped Bass X White Bass,NA,TL,English,75,RLP,4.5,NA,-3.448,3.139,NA,Brown and Murphy (1991b),same as Palmetto Bass +Striped Bass X White Bass,NA,TL,metric,75,RLP,115,NA,-5.201,3.139,NA,Brown and Murphy (1991b),same as Palmetto Bass Suwannee Bass,NA,TL,metric,75,EmP,110,NA,-0.106,-1.363,0.995,Bonvechio et al. (2010),none Tiger Muskellunge,NA,TL,English,75,RLP,9.5,NA,-4.095,3.337,NA,Rogers and Koupal (1997),none Tiger Muskellunge,NA,TL,metric,75,RLP,240,NA,-6.126,3.337,NA,Rogers and Koupal (1997),none @@ -189,6 +232,10 @@ Walleye,overall,TL,English,75,RLP,6,NA,-3.642,3.18,NA,Murphy et al. (1990),none Walleye,overall,TL,metric,75,RLP,150,NA,-5.453,3.18,NA,Murphy et al. (1990),none Walleye,30-149 mm,TL,English,75,RLP,1.25,6,-3.431,2.869,NA,Flammang et al. (1999),none Walleye,30-149 mm,TL,metric,75,RLP,30,149,-4.804,2.869,NA,Flammang et al. (1999),none +Walleye (overall),NA,TL,English,75,RLP,6,NA,-3.642,3.18,NA,Murphy et al. (1990),none +Walleye (overall),NA,TL,metric,75,RLP,150,NA,-5.453,3.18,NA,Murphy et al. (1990),none +Walleye (30-149 mm),NA,TL,English,75,RLP,1.25,6,-3.431,2.869,NA,Flammang et al. (1999),none +Walleye (30-149 mm),NA,TL,metric,75,RLP,30,149,-4.804,2.869,NA,Flammang et al. (1999),none Warmouth,NA,TL,English,75,RLP,3,NA,-3.284,3.241,NA,Bister et al. (2000),none Warmouth,NA,TL,metric,75,RLP,80,NA,-5.18,3.241,NA,Bister et al. (2000),none White Bass,NA,TL,English,75,RLP,4.5,NA,-3.394,3.081,NA,Brown and Murphy (1991b),none diff --git a/data-raw/aaa_Make_Fake_PSDWR_Data.R b/data-raw/aaa_Make_Fake_PSDWR_Data.R new file mode 100644 index 00000000..d31ce5da --- /dev/null +++ b/data-raw/aaa_Make_Fake_PSDWR_Data.R @@ -0,0 +1,136 @@ +## Creates weight-length data for a variety of species (some with sub-groups) to +## be used as examples in PSD and Wr calculations. Running the script will produce +## a data.frame called PSDWRtest that is distributed with FSA. +set.seed(633437) + +bgdf <- data.frame(species="Bluegill Sunfish", + location="Bass Lake", + len=round(c(rnorm(30,mean=100,sd=15), + rnorm(70,mean=150,sd=25), + rnorm(20,mean=200,sd=25)),0)) |> + dplyr::mutate(wt=10^(-5.37)*len^3.316, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.1),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=NA_character_) + +bktdf <- data.frame(species="Brook Trout", + location="Trout Lake", + len=round(c(rnorm(20,mean=175,sd=25), + rnorm(50,mean=255,sd=25), + rnorm(10,mean=310,sd=25)),0)) |> + dplyr::mutate(wt=10^(-5.18)*len^3.1, + wt=round(wt+rnorm(dplyr::n(),wt*0.10),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=sample(c("F","M"),dplyr::n(),replace=TRUE), + sex=NA_character_) + +brt1df <- data.frame(species="Brown Trout", + location="Trout Lake", + len=round(c(rnorm(20,mean=150,sd=20), + rnorm(50,mean=230,sd=25), + rnorm(10,mean=325,sd=25)),0)) |> + dplyr::mutate(wt=1.4e-05*len^2.96, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.1),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=sample(c("F","M"),dplyr::n(),replace=TRUE), + sex=NA_character_) + +brt2df <- data.frame(species="Brown Trout", + location="Brushy Creek", + len=round(c(rnorm(24,mean=200,sd=20), + rnorm(60,mean=325,sd=25), + rnorm(15,mean=450,sd=25)),0)) |> + dplyr::mutate(wt=3.65e-06*len^3.1, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.1),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=sample(c("F","M"),dplyr::n(),replace=TRUE)) + +iaddf <- FSAdata::InchLake2 |> + dplyr::filter(species=="Iowa Darter") |> + dplyr::mutate(species=="Iowa Darter", + location="Bass Lake", + sex=NA_character_, + len=round(length*25.4,0), + wt=NA) |> + dplyr::select(species,location,len,wt=weight,sex) + +lmbdf <- data.frame(species="Largemouth Bass", + location="Bass Lake", + len=round(c(rnorm(30,mean=200,sd=15), + rnorm(40,mean=300,sd=25), + rnorm(20,mean=350,sd=25)),0)) |> + dplyr::mutate(wt=10^(-5.5)*len^3.2, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.1),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=NA_character_) + +lktdf <- data.frame(species="Lean Lake Trout", + location="Trout Lake", + len=round(c(rnorm(10,mean=300,sd=40), + rnorm(60,mean=500,sd=50), + rnorm(30,mean=750,sd=50)),0)) |> + dplyr::mutate(wt=10^(-5.7)*len^3.246, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.1),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=sample(c("F","M"),dplyr::n(),replace=TRUE)) + +muedf <- data.frame(species="Muskellunge", + location="Long Lake", + len=round(c(rnorm(10,mean=600,sd=60), + rnorm(25,mean=800,sd=70), + rnorm(10,mean=1000,sd=60)),0)) |> + dplyr::mutate(wt=10^(-6.0)*len^3.32, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.1),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=sample(c("F","M","U"),dplyr::n(),c(0.4,0.4,0.2),replace=TRUE)) + +rufdf <- data.frame(species="Ruffe", + location="Round Lake", + len=round(c(rnorm(10,mean=70,sd=40), + rnorm(20,mean=120,sd=20), + rnorm(10,mean=160,sd=20)),0)) |> + dplyr::mutate(wt=3.03e-06*len^3.26, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.1),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=NA_character_) + +waedf1 <- data.frame(species="Walleye", + location="Bass Lake", + len=round(rnorm(50,mean=100,sd=25),0)) |> + dplyr::filter(len<150) |> + dplyr::mutate(wt=10^(-4.8)*len^2.87, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.05),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=NA_character_) + +waedf2 <- data.frame(species="Walleye", + location="Bass Lake", + len=round(c(rnorm(20,mean=250,sd=25), + rnorm(60,mean=425,sd=40), + rnorm(30,mean=600,sd=40)),0)) |> + dplyr::filter(len>=150) |> + dplyr::mutate(wt=10^(-5.45)*len^3.18, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.1),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=sample(c("F","M"),dplyr::n(),replace=TRUE), + sex=ifelse(len<300,NA,sex)) + +yepdf <- data.frame(species="Yellow Perch", + location="Bass Lake", + len=round(c(rnorm(100,mean=150,sd=25), + rnorm(50,mean=250,sd=25), + rnorm(20,mean=300,sd=25)),0)) |> + dplyr::mutate(wt=10^(-5.38)*len^3.23, + wt=round(wt+rnorm(dplyr::n(),0,wt*0.10),1), + wt=ifelse(wt<=0,min(wt[wt>0]),wt), + sex=sample(c("F","M"),dplyr::n(),replace=TRUE), + sex=ifelse(len<100,NA,sex)) + +## Combine +PSDWRtest <- rbind(bgdf,bktdf,brt1df,brt2df,iaddf,lmbdf,lktdf,muedf,rufdf,waedf1,waedf2,yepdf) + +## Add some (~5%) random NAs to wt +PSDWRtest$wt[sample(nrow(PSDWRtest),round(0.05*nrow(PSDWRtest),0))] <- NA_real_ + +## Write out to Rdata file +usethis::use_data(PSDWRtest,internal=FALSE,overwrite=TRUE) diff --git a/data/PSDWRtest.rda b/data/PSDWRtest.rda new file mode 100644 index 00000000..88275b78 Binary files /dev/null and b/data/PSDWRtest.rda differ diff --git a/data/PSDlit.rdata b/data/PSDlit.rdata index 0d121fa4..4ffaa7a2 100644 Binary files a/data/PSDlit.rdata and b/data/PSDlit.rdata differ diff --git a/data/WSlit.rdata b/data/WSlit.rdata index e6120c21..733a0e2e 100644 Binary files a/data/WSlit.rdata and b/data/WSlit.rdata differ diff --git a/inst/extdata/PSDWR_data4testthat.csv b/inst/extdata/PSDWR_data4testthat.csv new file mode 100644 index 00000000..90a46b46 --- /dev/null +++ b/inst/extdata/PSDWR_data4testthat.csv @@ -0,0 +1,291 @@ +species,location,sex,species2,len,wt,psd,ws,wr +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,66,5.1,substock,NA,NA +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,85,NA,stock,10.56703529,NA +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,97,16.6,stock,16.3732567,101.3848393 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,101,15.9,stock,18.72102725,84.93123687 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,102,18.3,stock,19.34274781,94.60910197 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,104,21.9,stock,20.62920792,106.1601593 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,108,21.5,stock,23.37938987,91.96133912 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,108,22.9,stock,23.37938987,97.94951934 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,108,27.2,stock,23.37938987,116.3417872 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,114,30.1,stock,27.97025895,107.6143058 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,124,38.5,stock,36.96462528,104.1536326 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,137,50.7,stock,51.44763325,98.5468073 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,143,61.8,stock,59.3054083,104.2063477 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,149,74,stock,67.96505396,108.8794839 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,151,81.1,quality,71.03748171,114.1650831 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,154,82.4,quality,75.82609843,108.6697083 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,154,NA,quality,75.82609843,NA +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,155,75.1,quality,77.47113365,96.9393327 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,156,72.5,quality,79.14093341,91.60872494 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,156,81.7,quality,79.14093341,103.2335562 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,163,95.9,quality,91.54067199,104.7621761 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,165,93.6,quality,95.31840335,98.19719667 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,165,104.5,quality,95.31840335,109.632554 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,179,NA,quality,124.87073,NA +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,184,151.5,quality,136.8156888,110.7329148 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,186,161.1,quality,141.8093685,113.6032137 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,191,138.3,quality,154.8483727,89.31317622 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,207,216.2,preferred,202.1890658,106.9296202 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,209,213.7,preferred,208.7397143,102.3763018 +Bluegill Sunfish,Bass Lake,NA,Bluegill Sunfish,239,346.6,preferred,325.6622653,106.4292787 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),135,27.8,stock,26.5720881,104.6210591 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),147,38.3,stock,34.60873215,110.6657124 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),164,51.9,stock,48.60270721,106.7841752 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),166,56.1,stock,50.4655949,111.1648443 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),172,62.3,stock,56.34362316,110.571519 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),204,NA,quality,95.67146175,NA +Brook Trout,Trout Lake,NA,Brook Trout (lotic),206,108.2,quality,98.61204945,109.7228996 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),208,110.7,quality,101.6132936,108.9424386 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),229,150.6,quality,136.9523541,109.9652511 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),241,174.7,quality,160.4718588,108.8664401 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),245,185.5,quality,168.8816097,109.8402605 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),246,187.6,quality,171.0297407,109.6885251 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),249,193.9,quality,177.5851204,109.1870758 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),261,225.1,quality,205.5111996,109.5317435 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),271,253.4,quality,230.9424185,109.7243207 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),276,268.2,quality,244.4223311,109.7281082 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),279,276.8,quality,252.7608707,109.5106213 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),285,296,quality,270.0123326,109.6246224 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),291,316.4,quality,288.0447373,109.8440482 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),336,492.3,quality,450.0189248,109.3953994 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),339,505.1,quality,462.6042981,109.1861883 +Brook Trout,Trout Lake,NA,Brook Trout (lotic),340,512.6,quality,466.8518451,109.7992876 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),161,25.5,substock,42.32547572,60.24740317 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),172,27.8,substock,52.27305224,53.18227807 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),203,53.9,stock,88.74468355,60.73603268 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),206,54.4,stock,93.00191728,58.49341776 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),209,54,stock,97.39737179,55.4429745 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),215,67.3,stock,106.612577,63.1257605 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),225,78.1,stock,123.2738509,63.35487976 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),258,111.1,stock,190.8593062,58.21041803 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),286,158.6,stock,265.2363909,59.79571636 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),295,176.6,stock,292.8272703,60.30859074 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),297,NA,stock,299.2155082,NA +Brown Trout,Brushy Creek,F,Brown Trout (lentic),298,187.4,stock,302.4452356,61.96163072 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),299,174.8,stock,305.6988293,57.18046105 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),308,203,quality,336.0709615,60.40390967 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),314,182.6,quality,357.4318887,51.08665617 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),316,261.1,quality,364.754402,71.58241231 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),318,204.4,quality,372.1793056,54.919765 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),324,202.4,quality,395.0761042,51.23063578 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),326,253,quality,402.9183201,62.79188296 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),333,232.2,quality,431.2080718,53.84871369 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),338,233.3,quality,452.2305951,51.58872542 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),339,223,quality,456.5179265,48.848027 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),348,NA,quality,496.3683768,NA +Brown Trout,Brushy Creek,M,Brown Trout (lentic),423,575.7,preferred,925.829753,62.18205865 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),442,720.1,preferred,1065.316683,67.59492377 +Brown Trout,Brushy Creek,M,Brown Trout (lentic),447,642,preferred,1104.287685,58.13702433 +Brown Trout,Brushy Creek,F,Brown Trout (lentic),455,754.1,preferred,1168.660596,64.52686117 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),128,25,substock,NA,NA +Brown Trout,Trout Lake,NA,Brown Trout (lotic),134,29.9,substock,NA,NA +Brown Trout,Trout Lake,NA,Brown Trout (lotic),138,32.7,substock,NA,NA +Brown Trout,Trout Lake,NA,Brown Trout (lotic),143,40.9,substock,32.56826858,125.5823591 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),208,117.3,stock,98.73416814,118.8038571 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),220,116,stock,116.5657964,99.51461198 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),230,122.9,quality,132.9579758,92.43522193 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),232,144.8,quality,136.4094429,106.151009 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),245,164.4,quality,160.299294,102.558156 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),249,171.8,quality,168.1705976,102.158167 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),254,181.5,quality,178.3642456,101.7580622 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),264,NA,quality,199.9620698,NA +Brown Trout,Trout Lake,NA,Brown Trout (lotic),281,257.4,quality,240.5308062,107.0133194 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),333,461.3,preferred,397.5895226,116.0241842 +Brown Trout,Trout Lake,NA,Brown Trout (lotic),374,583,preferred,560.6604774,103.984501 +Iowa Darter,Bass Lake,NA,Iowa Darter,43,0.3,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,43,0.6,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,46,NA,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,46,NA,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,46,NA,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,48,0.7,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,48,0.8,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,48,NA,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,51,0.6,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,51,0.8,NA,NA,NA +Iowa Darter,Bass Lake,NA,Iowa Darter,56,0.9,NA,NA,NA +Largemouth Bass,Bass Lake,NA,Largemouth Bass,188,55.4,substock,82.28461484,67.32728847 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,191,64.6,substock,86.66070365,74.54359044 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,196,61.4,substock,94.30921318,65.10498596 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,196,69.8,substock,94.30921318,74.011857 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,200,77.5,stock,100.7560599,76.91845046 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,202,85,stock,104.0914437,81.65896922 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,204,78.1,stock,107.5027411,72.64931034 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,208,76.6,stock,114.5569112,66.86632799 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,226,103.8,stock,150.3131311,69.05584314 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,273,172.3,stock,278.9718251,61.7625095 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,284,201.8,stock,317.4760198,63.56385597 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,285,218.3,stock,321.1494827,67.97457625 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,286,246.7,stock,324.8523602,75.94219105 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,287,228.3,stock,328.5847837,69.47978462 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,288,246.4,stock,332.3468849,74.1394041 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,292,206.4,stock,347.6947017,59.36242312 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,294,242.9,stock,355.550106,68.31667208 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,294,248.3,stock,355.550106,69.83544536 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,295,271.7,stock,359.5236451,75.57221999 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,296,236.6,stock,363.5279189,65.08440966 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,301,259.4,quality,384.014957,67.54945224 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,306,311.9,quality,405.2903179,76.95718013 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,312,259.9,quality,431.8848663,60.17807528 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,319,379.9,quality,464.4157135,81.80171105 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,330,NA,quality,518.914881,NA +Largemouth Bass,Bass Lake,NA,Largemouth Bass,333,349.3,quality,534.5150973,65.34894932 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,333,395,quality,534.5150973,73.8987546 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,335,390.6,quality,545.094316,71.65732398 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,341,483.2,quality,577.7036114,83.64150587 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,347,472.4,quality,611.6435087,77.23453176 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,362,467.6,quality,702.5110364,66.56123189 +Largemouth Bass,Bass Lake,NA,Largemouth Bass,396,726.3,preferred,942.4457136,77.0654468 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,276,197.8,substock,NA,NA +Lean Lake Trout,Trout Lake,F,Lean Lake Trout,312,276,stock,260.0314108,106.1410232 +Lean Lake Trout,Trout Lake,F,Lean Lake Trout,458,895.7,stock,904.0018965,99.08165054 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,471,913.1,stock,989.9787318,92.2343047 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,473,1106.5,stock,1003.689227,110.2432875 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,478,1075.6,stock,1038.53934,103.5685369 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,511,1157.3,quality,1289.835251,89.72463727 +Lean Lake Trout,Trout Lake,F,Lean Lake Trout,524,1240.2,quality,1399.424128,88.62216786 +Lean Lake Trout,Trout Lake,F,Lean Lake Trout,525,1156.5,quality,1408.111673,82.13126997 +Lean Lake Trout,Trout Lake,F,Lean Lake Trout,529,1480,quality,1443.235196,102.5473883 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,558,1539.7,quality,1716.226524,89.71426429 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,564,1526.6,quality,1776.85493,85.91584909 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,580,1877.7,quality,1945.751021,96.50258329 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,595,1937.8,quality,2113.888474,91.66992601 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,601,1973,quality,2183.868762,90.3442567 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,680,3403.4,preferred,3260.79826,104.3732156 +Lean Lake Trout,Trout Lake,F,Lean Lake Trout,709,3488.7,preferred,3734.200901,93.42561079 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,724,4312.4,preferred,3996.790513,107.8965732 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,736,3830.4,preferred,4215.852282,90.85707335 +Lean Lake Trout,Trout Lake,F,Lean Lake Trout,737,3990.9,preferred,4234.473951,94.24783447 +Lean Lake Trout,Trout Lake,F,Lean Lake Trout,752,5291.2,preferred,4520.673175,117.0445152 +Lean Lake Trout,Trout Lake,F,Lean Lake Trout,781,5994,preferred,5111.463406,117.2658302 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,785,4678.7,preferred,5196.930463,90.02814322 +Lean Lake Trout,Trout Lake,M,Lean Lake Trout,829,6924,memorable,6203.374581,111.6166678 +Muskellunge,Long Lake,F,Muskellunge (female),542,1167.2,stock,1063.059608,109.796289 +Muskellunge,Long Lake,F,Muskellunge (female),593,1460.1,stock,1435.498278,101.7138106 +Muskellunge,Long Lake,F,Muskellunge (female),766,2768.2,quality,3375.391019,82.01123911 +Muskellunge,Long Lake,F,Muskellunge (female),1090,11590.9,memorable,10964.89565,105.7091683 +Muskellunge,Long Lake,M,Muskellunge (male),572,1355.6,stock,1332.754365,101.714167 +Muskellunge,Long Lake,M,Muskellunge (male),604,1669.3,stock,1590.248028,104.9710467 +Muskellunge,Long Lake,M,Muskellunge (male),680,2756.5,stock,2336.099959,117.9958071 +Muskellunge,Long Lake,M,Muskellunge (male),716,2761.9,stock,2761.803384,100.0034983 +Muskellunge,Long Lake,M,Muskellunge (male),786,3576.5,quality,3738.059087,95.67799537 +Muskellunge,Long Lake,M,Muskellunge (male),947,8109.2,quality,6843.144046,118.5010858 +Muskellunge,Long Lake,M,Muskellunge (male),965,8692.1,quality,7274.298726,119.4905561 +Muskellunge,Long Lake,M,Muskellunge (male),978,8879.3,preferred,7597.130451,116.8770243 +Muskellunge,Long Lake,M,Muskellunge (male),1045,11109.7,preferred,9419.597863,117.9424022 +Muskellunge,Long Lake,U,Muskellunge (overall),683,2723.2,stock,2282.700005,119.2973231 +Muskellunge,Long Lake,U,Muskellunge (overall),856,6312.3,quality,4835.877239,130.5306088 +Muskellunge,Long Lake,U,Muskellunge (overall),940,8965.1,quality,6601.613786,135.8016432 +Muskellunge,Long Lake,U,Muskellunge (overall),1097,11376.4,memorable,11032.8328,103.1140434 +Ruffe,Round Lake,NA,Ruffe,19,0.1,substock,NA,NA +Ruffe,Round Lake,NA,Ruffe,26,0.1,substock,NA,NA +Ruffe,Round Lake,NA,Ruffe,95,9.4,quality,10.55732536,89.03770301 +Ruffe,Round Lake,NA,Ruffe,105,11.7,quality,14.32531794,81.67357997 +Ruffe,Round Lake,NA,Ruffe,106,11.7,quality,14.74948502,79.32480343 +Ruffe,Round Lake,NA,Ruffe,114,17.5,quality,18.48152114,94.68917557 +Ruffe,Round Lake,NA,Ruffe,118,20.6,quality,20.58697,100.0632924 +Ruffe,Round Lake,NA,Ruffe,137,25.2,preferred,33.08087874,76.17693652 +Ruffe,Round Lake,NA,Ruffe,143,31.7,memorable,37.98916046,83.44485537 +Ruffe,Round Lake,NA,Ruffe,151,40.6,memorable,45.34913131,89.52762452 +Ruffe,Round Lake,NA,Ruffe,152,36.1,memorable,46.33839166,77.90516396 +Ruffe,Round Lake,NA,Ruffe,175,56.4,trophy,73.85609555,76.36471923 +Ruffe,Round Lake,NA,Ruffe,189,89.3,trophy,95.69305504,93.31920688 +Ruffe,Round Lake,NA,Ruffe,196,102.5,trophy,108.2707524,94.67007266 +Walleye,Bass Lake,NA,Walleye (30-149 mm),75,3.5,substock,3.763143371,93.00735197 +Walleye,Bass Lake,NA,Walleye (30-149 mm),75,3.6,substock,3.763143371,95.66470489 +Walleye,Bass Lake,NA,Walleye (30-149 mm),75,3.8,substock,3.763143371,100.9794107 +Walleye,Bass Lake,NA,Walleye (30-149 mm),82,5.1,substock,4.861070755,104.9151567 +Walleye,Bass Lake,NA,Walleye (30-149 mm),84,4.8,substock,5.209034954,92.14758668 +Walleye,Bass Lake,NA,Walleye (30-149 mm),84,5,substock,5.209034954,95.98706946 +Walleye,Bass Lake,NA,Walleye (30-149 mm),85,NA,substock,5.388934412,NA +Walleye,Bass Lake,NA,Walleye (30-149 mm),86,5.2,substock,5.572833357,93.30980611 +Walleye,Bass Lake,NA,Walleye (30-149 mm),93,7.2,substock,6.97553592,103.2178758 +Walleye,Bass Lake,NA,Walleye (30-149 mm),96,7,substock,7.640753123,91.61400568 +Walleye,Bass Lake,NA,Walleye (30-149 mm),96,9,substock,7.640753123,117.7894359 +Walleye,Bass Lake,NA,Walleye (30-149 mm),108,10.9,substock,10.71254735,101.749842 +Walleye,Bass Lake,NA,Walleye (30-149 mm),110,12,substock,11.29160335,106.2736587 +Walleye,Bass Lake,NA,Walleye (30-149 mm),121,15.9,substock,14.84264251,107.123782 +Walleye,Bass Lake,NA,Walleye (30-149 mm),123,15.4,substock,15.55742675,98.98809264 +Walleye,Bass Lake,NA,Walleye (30-149 mm),127,16.8,substock,17.05347447,98.5136491 +Walleye,Bass Lake,NA,Walleye (30-149 mm),132,19.1,substock,19.05138742,100.2551656 +Walleye,Bass Lake,NA,Walleye (overall),228,117,substock,110.9769573,105.4272912 +Walleye,Bass Lake,NA,Walleye (overall),258,145.7,stock,164.4184936,88.61533565 +Walleye,Bass Lake,NA,Walleye (overall),261,190.8,stock,170.575563,111.8565852 +Walleye,Bass Lake,NA,Walleye (overall),266,194.2,stock,181.1855691,107.182929 +Walleye,Bass Lake,NA,Walleye (overall),268,218.4,stock,185.553284,117.7020397 +Walleye,Bass Lake,F,Walleye (overall),347,431.3,stock,421.9371158,102.2190236 +Walleye,Bass Lake,M,Walleye (overall),348,448.6,stock,425.8160194,105.3506631 +Walleye,Bass Lake,F,Walleye (overall),381,540.6,quality,567.9909587,95.17757135 +Walleye,Bass Lake,F,Walleye (overall),385,519.6,quality,587.1717057,88.49200242 +Walleye,Bass Lake,M,Walleye (overall),390,527.9,quality,611.7661602,86.29114102 +Walleye,Bass Lake,M,Walleye (overall),392,667.9,quality,621.7985331,107.4142129 +Walleye,Bass Lake,M,Walleye (overall),401,752.5,quality,668.3425401,112.5919652 +Walleye,Bass Lake,M,Walleye (overall),402,698.2,quality,673.657034,103.6432435 +Walleye,Bass Lake,M,Walleye (overall),411,729.4,quality,722.7980855,100.913383 +Walleye,Bass Lake,M,Walleye (overall),418,698.4,quality,762.6768708,91.57220137 +Walleye,Bass Lake,M,Walleye (overall),419,582.7,quality,768.4941981,75.82360433 +Walleye,Bass Lake,M,Walleye (overall),428,787.8,quality,822.2259617,95.81307775 +Walleye,Bass Lake,M,Walleye (overall),431,962.6,quality,840.6935571,114.5006991 +Walleye,Bass Lake,F,Walleye (overall),432,841.7,quality,846.9120554,99.38458128 +Walleye,Bass Lake,M,Walleye (overall),434,794.6,quality,859.4435168,92.45517413 +Walleye,Bass Lake,M,Walleye (overall),449,851.3,quality,957.5101016,88.90767822 +Walleye,Bass Lake,F,Walleye (overall),454,848.7,quality,991.830849,85.56902629 +Walleye,Bass Lake,F,Walleye (overall),470,1293.1,quality,1107.315013,116.7779705 +Walleye,Bass Lake,M,Walleye (overall),490,1313,quality,1264.222556,103.8582957 +Walleye,Bass Lake,M,Walleye (overall),515,1586.3,preferred,1480.97248,107.1120511 +Walleye,Bass Lake,F,Walleye (overall),549,1603.9,preferred,1814.847157,88.37658831 +Walleye,Bass Lake,F,Walleye (overall),560,1762.5,preferred,1933.027025,91.17823894 +Walleye,Bass Lake,F,Walleye (overall),564,1827.9,preferred,1977.277164,92.4453098 +Walleye,Bass Lake,M,Walleye (overall),571,2390.1,preferred,2056.377409,116.2286645 +Walleye,Bass Lake,M,Walleye (overall),572,1878.4,preferred,2067.851616,90.83823935 +Walleye,Bass Lake,M,Walleye (overall),603,2330.6,preferred,2445.733051,95.29249313 +Walleye,Bass Lake,F,Walleye (overall),653,3286.3,memorable,3150.822343,104.2997555 +Yellow Perch,Bass Lake,F,Yellow Perch,105,12.5,substock,13.88166105,90.04686078 +Yellow Perch,Bass Lake,F,Yellow Perch,120,17.8,substock,21.36758424,83.3037549 +Yellow Perch,Bass Lake,F,Yellow Perch,122,23.4,substock,22.53939492,103.8182262 +Yellow Perch,Bass Lake,F,Yellow Perch,128,27.8,substock,26.32014042,105.6225368 +Yellow Perch,Bass Lake,F,Yellow Perch,131,30.6,stock,28.3652284,107.8785602 +Yellow Perch,Bass Lake,F,Yellow Perch,133,26.9,stock,29.78796263,90.30493403 +Yellow Perch,Bass Lake,F,Yellow Perch,136,34,stock,32.01331692,106.205802 +Yellow Perch,Bass Lake,F,Yellow Perch,138,32.3,stock,33.55903384,96.24830128 +Yellow Perch,Bass Lake,M,Yellow Perch,146,42.8,stock,40.25869789,106.31243 +Yellow Perch,Bass Lake,F,Yellow Perch,150,40.2,stock,43.931372,91.50636133 +Yellow Perch,Bass Lake,F,Yellow Perch,150,44.8,stock,43.931372,101.9772385 +Yellow Perch,Bass Lake,F,Yellow Perch,151,NA,stock,44.88441196,NA +Yellow Perch,Bass Lake,M,Yellow Perch,154,44.9,stock,47.82906911,93.87596464 +Yellow Perch,Bass Lake,F,Yellow Perch,154,49.5,stock,47.82906911,103.4935468 +Yellow Perch,Bass Lake,M,Yellow Perch,158,NA,stock,51.95919224,NA +Yellow Perch,Bass Lake,F,Yellow Perch,162,50.4,stock,56.3291888,89.47403837 +Yellow Perch,Bass Lake,F,Yellow Perch,174,71.8,stock,70.95354063,101.1929769 +Yellow Perch,Bass Lake,F,Yellow Perch,189,90,stock,92.67692754,97.1115491 +Yellow Perch,Bass Lake,F,Yellow Perch,196,104.9,stock,104.2286495,100.6441132 +Yellow Perch,Bass Lake,F,Yellow Perch,197,88.7,stock,105.9560868,83.7139259 +Yellow Perch,Bass Lake,M,Yellow Perch,206,117.7,quality,122.402735,96.15798212 +Yellow Perch,Bass Lake,F,Yellow Perch,225,176.3,quality,162.7606942,108.3185353 +Yellow Perch,Bass Lake,F,Yellow Perch,240,215.9,quality,200.4851966,107.6887489 +Yellow Perch,Bass Lake,M,Yellow Perch,244,248.8,quality,211.4799208,117.6471029 +Yellow Perch,Bass Lake,M,Yellow Perch,248,226.5,quality,222.8840184,101.6223602 +Yellow Perch,Bass Lake,M,Yellow Perch,249,228.7,quality,225.7999758,101.2843332 +Yellow Perch,Bass Lake,M,Yellow Perch,252,242.2,preferred,234.7057594,103.1930365 +Yellow Perch,Bass Lake,F,Yellow Perch,257,285,preferred,250.0828951,113.9622124 +Yellow Perch,Bass Lake,F,Yellow Perch,260,269.5,preferred,259.6354047,103.799403 +Yellow Perch,Bass Lake,M,Yellow Perch,261,289.6,preferred,262.8747294,110.1665423 +Yellow Perch,Bass Lake,F,Yellow Perch,262,286.5,preferred,266.1418497,107.6493608 +Yellow Perch,Bass Lake,M,Yellow Perch,264,305,preferred,272.7600013,111.8199144 +Yellow Perch,Bass Lake,F,Yellow Perch,265,272.7,preferred,276.111295,98.76452176 +Yellow Perch,Bass Lake,F,Yellow Perch,266,271.4,preferred,279.4909091,97.1051262 +Yellow Perch,Bass Lake,F,Yellow Perch,266,297.9,preferred,279.4909091,106.586651 +Yellow Perch,Bass Lake,F,Yellow Perch,274,321.8,preferred,307.5631625,104.628915 +Yellow Perch,Bass Lake,M,Yellow Perch,277,283.4,preferred,318.5735053,88.95906135 +Yellow Perch,Bass Lake,F,Yellow Perch,278,315.6,preferred,322.3032545,97.92020268 +Yellow Perch,Bass Lake,M,Yellow Perch,279,373,preferred,326.0630424,114.395056 +Yellow Perch,Bass Lake,M,Yellow Perch,280,346.9,preferred,329.8530022,105.168059 +Yellow Perch,Bass Lake,F,Yellow Perch,281,348.1,preferred,333.6732668,104.3236107 +Yellow Perch,Bass Lake,F,Yellow Perch,284,348.7,preferred,345.3172219,100.9796146 +Yellow Perch,Bass Lake,M,Yellow Perch,288,419,preferred,361.2748551,115.9781795 +Yellow Perch,Bass Lake,F,Yellow Perch,291,422.6,preferred,373.5720318,113.1241003 +Yellow Perch,Bass Lake,M,Yellow Perch,299,411.3,preferred,407.7725042,100.8650646 +Yellow Perch,Bass Lake,F,Yellow Perch,306,360.8,memorable,439.4203924,82.10816027 +Yellow Perch,Bass Lake,M,Yellow Perch,312,455.9,memorable,467.8636867,97.44291189 +Yellow Perch,Bass Lake,F,Yellow Perch,313,507.2,memorable,472.7246079,107.2929125 +Yellow Perch,Bass Lake,M,Yellow Perch,347,675.2,memorable,659.5750265,102.3689456 diff --git a/inst/extdata/PSDWR_data4testthat.xlsx b/inst/extdata/PSDWR_data4testthat.xlsx new file mode 100644 index 00000000..2a16ef80 Binary files /dev/null and b/inst/extdata/PSDWR_data4testthat.xlsx differ diff --git a/man/PSDWRtest.Rd b/man/PSDWRtest.Rd new file mode 100644 index 00000000..0a0b3b3d --- /dev/null +++ b/man/PSDWRtest.Rd @@ -0,0 +1,47 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/PSDWRtest.R +\docType{data} +\name{PSDWRtest} +\alias{PSDWRtest} +\title{Hypothetical weight-length data for testing PSD and relative weight functions} +\format{ +A data frame of many observations on the following 5 variables: + \describe{ + \item{species}{Species name} + \item{location}{Broad location of capture} + \item{len}{Length in mm} + \item{wt}{Weight in g} + \item{sex}{Sex as \code{F} for female, \code{M} for male, or \code{U} or \code{NA} for unknown or unrecorded} + } +} +\description{ +Hypothetical weight-length and associated data. These data are useful for testing PSD and relative weight functions (e.g., \code{\link{psdAdd}} and \code{\link{wrAdd}}). +} +\section{Topic(s)}{ + + \itemize{ + \item Size structure + \item Proportional size structure + \item Relative stock density + \item Proportional stock density + \item Relative weight + \item Standard weight + \item Condition + } +} + +\examples{ +str(PSDWRtest) +peek(PSDWRtest,n=20) +unique(PSDWRtest$species) + +} +\seealso{ +\code{\link{psdAdd}}, \code{\link{psdCalc}}, and \code{\link{wrAdd}} +} +\concept{Condition} +\concept{PSD} +\concept{Relative Weight} +\concept{Size Structure} +\concept{Standard Weight} +\keyword{datasets} diff --git a/man/PSDlit.Rd b/man/PSDlit.Rd index c42afe34..e74e3dbc 100644 --- a/man/PSDlit.Rd +++ b/man/PSDlit.Rd @@ -30,6 +30,9 @@ Original summary table from Dr. Michael Hansen, University of Wisconsin-Stevens \description{ Cutoffs for the Gabelhouse five-cell length categories for a variety of species. } +\details{ +Entries for some species (e.g., \dQuote{Muskellunge} and \dQuote{Walleye}) have been duplicated for sub-groups to facilitate use with relative weight calculations. For example, entries for \dQuote{Muskellunge (overall)}, \dQuote{Muskellunge (female)}, and \dQuote{Muskellunge (male)} are duplicates of the entry for \dQuote{Muskellunge}; i.e., these entries in \code{PSDlit} are not necessarily just for those sub-groups but this allows for seamless similar computations of relative weights for these sub-groups. +} \section{Topic(s)}{ \itemize{ diff --git a/man/WSlit.Rd b/man/WSlit.Rd index e9fe6e02..970d52e4 100644 --- a/man/WSlit.Rd +++ b/man/WSlit.Rd @@ -30,6 +30,8 @@ Parameters for all known standard weight equations. } \details{ The minimum TL for the English units were derived by rounding the converted minimum TL for the metric units to what seemed like common units (inches, half inches, or quarter inches). + +Entries for \dQuote{Chinook Salmon (landlocked)} and \dQuote{Striped Bass (landlocked)} are the same as for \dQuote{Chinook Salmon} and \dQuote{Striped Bass} but were added to facilitate use with PSD calculations as Gabelhouse lengths are only published for the landlocked sub-group; i.e., these entries in \code{WSlit} are not necessarily just for landlocked populations. } \section{Topic(s)}{ diff --git a/man/psdAdd.Rd b/man/psdAdd.Rd index 4026a71e..a8679890 100644 --- a/man/psdAdd.Rd +++ b/man/psdAdd.Rd @@ -11,6 +11,7 @@ psdAdd(len, ...) \method{psdAdd}{default}( len, species, + thesaurus = NULL, group = NULL, units = c("mm", "cm", "in"), use.names = TRUE, @@ -23,6 +24,7 @@ psdAdd(len, ...) \method{psdAdd}{formula}( len, data = NULL, + thesaurus = NULL, group = NULL, units = c("mm", "cm", "in"), use.names = TRUE, @@ -39,6 +41,8 @@ psdAdd(len, ...) \item{species}{A character or factor vector that contains the species names. Ignored if \code{len} is a formula.} +\item{thesaurus}{A named list for providing alternative species names (the values in the list) that correspond to specific names in \code{PSDlit} (the names in the list). See details and examples.} + \item{group}{A named list that provides specific choices for \code{group} for species for which more than one set of Gabelhouse lengths exists in \code{\link{PSDlit}}.} \item{units}{A string that indicates the type of units used for the lengths. Choices are \code{mm} for millimeters (DEFAULT), \code{cm} for centimeters, and \code{in} for inches.} @@ -62,7 +66,9 @@ Creates a vector of the Gabelhouse lengths specific to a species for all individ \details{ This computes a vector that contains the Gabelhouse lengths specific to each species for all individuals in an entire data frame. The vector can be appended to an existing data.frame to create a variable that contains the Gabelhouse lengths for each individual. The Gabelhouse length value will be \code{NA} for each individual for which Gabelhouse length definitions do not exist in \code{\link{PSDlit}}. Species names in the data.frame must be the same as those used in \code{\link{PSDlit}} (i.e., same spelling and capitalization; use \code{psdVal()} to see the list of species). -Some species have Gabelhouse lengths for sub-groups (e.g., \dQuote{lentic} vs \dQuote{lotic}). For these species, choose which sub-group to use with \code{group}. +The \code{thesaurus} argument may be used to relate alternate species names to the species names used in \code{PSDlit}. For example, you (or your data) may use \dQuote{Bluegill Sunfish}, but \dQuote{Bluegill} is used in \code{PSDlit}. The alternate species name can be used here if it is defined in a named vector (or list) given to \code{thesarus=}. The alternate species name is the value and the species name in \code{PSDlit} is the name in this vector/list - e.g., \code{c("Bluegill"="Bluegill Sunfish")}. See the examples for a demonstration. + +Some species have length categories separated by sub-group. For example, length categories exist for both lentic and lotic populations of Brown Trout. The length values for a sub-group may be obtained by either including the species name in \code{species} and the sub-group name in \code{group} or by using the combined species and sub-group name, with the sub-group name in parentheses, in \code{species}. Both methods are demonstrated in the examples. Note that an error is returned if a species has sub-groups but neither method is used to define the sub-group.#' Individuals shorter than \dQuote{stock} length will be listed as \code{substock} if \code{use.names=TRUE} or \code{0} if \code{use.names=FALSE}. @@ -75,63 +81,112 @@ See examples and \href{https://fishr-core-team.github.io/FSA/articles/Computing_ } \examples{ -#===== Create random data for three species -set.seed(345234534) -dbg <- data.frame(species=factor(rep(c("Bluegill"),30)), - tl=round(rnorm(30,130,50),0)) -dlb <- data.frame(species=factor(rep(c("Largemouth Bass"),30)), - tl=round(rnorm(30,350,60),0)) -dbt <- data.frame(species=factor(rep(c("Bluefin Tuna"),30)), - tl=round(rnorm(30,1900,300),0)) -df <- rbind(dbg,dlb,dbt) - -#===== Simple examples +#===== Simple examples -- 2 species, no groups, names as in PSDlit +#----- Isolate simple data from PSDWRtest +tmp <- subset(PSDWRtest, + species \%in\% c("Yellow Perch","Largemouth Bass"), + select=c("species","len")) +peek(tmp,n=6) + #----- Add variable using category names -- non-formula notation -df$PSD <- psdAdd(df$tl,df$species) -peek(df,n=6) +tmp$PSD <- psdAdd(tmp$len,tmp$species) +peek(tmp,n=6) #----- Add variable using category names -- formula notation -df$PSD1 <- psdAdd(tl~species,data=df) -peek(df,n=6) +tmp$PSD1 <- psdAdd(len~species,data=tmp) +peek(tmp,n=6) #----- Add variable using length values as names -# Also turned off messaging of fish not in PSDlit -df$PSD2 <- psdAdd(tl~species,data=df,use.names=FALSE,verbose=FALSE) -peek(df,n=6) +tmp$PSD2 <- psdAdd(len~species,data=tmp,use.names=FALSE) +peek(tmp,n=6) #----- Same as above but using dplyr if (require(dplyr)) { - df <- df \%>\% - mutate(PSD1A=psdAdd(tl,species,verbose=FALSE), - PSD2A=psdAdd(tl,species,use.names=FALSE,verbose=FALSE)) - peek(df,n=6) + tmp <- tmp \%>\% + mutate(PSD1A=psdAdd(len,species), + PSD2A=psdAdd(len,species,use.names=FALSE)) + peek(tmp,n=6) } -#===== Adding lengths besides the Gabelhouse lengths -#----- Add a "minimum length" for Bluegill -df$PSD3 <- psdAdd(tl~species,data=df,verbose=FALSE, - addLens=list("Bluegill"=c("minLen"=175))) -df$PSD3A <- psdAdd(tl~species,data=df,verbose=FALSE, - addLens=list("Bluegill"=175)) -df$PSD3B <- psdAdd(tl~species,data=df,verbose=FALSE, - addLens=list("Bluegill"=c("minLen"=175)),use.names=FALSE) -head(df,n=6) - -#----- Add add'l lengths and names for Bluegill and Largemouth Bass -df$psd4 <- psdAdd(tl~species,data=df,verbose=FALSE, - addLens=list("Bluegill"=175, - "Largemouth Bass"=c(254,356))) -peek(df,n=20) - -#===== Example for a species with sub-groups -dbt <- data.frame(species=factor(rep(c("Brown Trout"),30)), - tl=round(rnorm(30,230,50),0)) -dlt <- data.frame(species=factor(rep(c("Lake Trout"),30)), - tl=round(rnorm(30,550,60),0)) -df2 <- rbind(dbt,dlt) - -df2$psd <- psdAdd(tl~species,data=df2,group=list("Brown Trout"="lentic")) -peek(df2,n=6) +#===== Add lengths besides Gabelhouse lengths (start over with same simple data) +tmp <- subset(PSDWRtest, + species \%in\% c("Yellow Perch","Largemouth Bass"), + select=c("species","len")) + +#----- Add a "minimum length" for one species +tmp$PSD3 <- psdAdd(len~species,data=tmp, + addLens=list("Yellow Perch"=c("minLen"=225))) +tmp$PSD3A <- psdAdd(len~species,data=tmp, + addLens=list("Yellow Perch"=225)) +tmp$PSD3B <- psdAdd(len~species,data=tmp, + addLens=list("Yellow Perch"=c("minLen"=225)),use.names=FALSE) +head(tmp,n=6) + +#----- Add add'l lengths and names for multiple species +tmp$psd4 <- psdAdd(len~species,data=tmp, + addLens=list("Yellow Perch"=175, + "Largemouth Bass"=c(254,306))) +peek(tmp,n=20) + +#===== Handle additional species in PSDlit but named differently +#----- Isolate different species data from PSDWRtest +tmp <- subset(PSDWRtest, + species \%in\% c("Bluegill Sunfish","Lean Lake Trout"), + select=c("species","len")) + +#----- No "Bluegill Sunfish" in PSDlit, use thesaurus to note this is "Bluegill" +# Note: "Lean Lake Trout" not processed as not in PSDlit +tmp$psd5 <- psdAdd(len~species,data=tmp, + thesaurus=c("Bluegill"="Bluegill Sunfish")) +peek(tmp,n=6) + +#----- Process multiple species in PSDlit with different names +# Note: Can still use addLens=, but with original name +thes <- c("Bluegill"="Bluegill Sunfish","Lake Trout"="Lean Lake Trout") +tmp$psd6 <- psdAdd(len~species,data=tmp,thesaurus=thes) +tmp$psd7 <- psdAdd(len~species,data=tmp,thesaurus=thes, + addLens=list("Bluegill Sunfish"=c("minLen"=175))) +peek(tmp,n=20) + +#===== Example for a species with sub-groups but only one sub-group in data +#----- Isolate species data from PSDWRtest ... only Brook Trout has sub-group +tmp <- subset(PSDWRtest, + species \%in\% c("Yellow Perch","Brook Trout"), + select=c("species","len")) + +#----- This will err as Brook Trout has sub-groups in PSDlit (as message notes) +# tmp$psd8 <- psdAdd(len~species,data=tmp) + +#----- Can choose "overall" sub-group with group= +tmp$psd8 <- psdAdd(len~species,data=tmp, + group=list("Brook Trout"="overall")) +peek(tmp,n=10) + +#----- Or can create species name with sub-group name in parentheses +# Note: this is more useful in next examples +tmp$species2 <- ifelse(tmp$species=="Brook Trout","Brook Trout (overall)", + tmp$species) +tmp$psd8A <- psdAdd(len~species2,data=tmp) # note use of species2 +peek(tmp,n=10) + +#===== Example for species with more than one sub-group in data +#----- Isolate species data from PSDWRtest ... Brown Trout has two sub-groups +tmp <- subset(PSDWRtest, + species \%in\% c("Yellow Perch","Largemouth Bass","Brown Trout"), + select=c("species","len","location")) +peek(tmp,n=10) + +#----- Must create a species name variable with sub-groups in parentheses +# Note: there are likely many ways to do this specific to each use-case +tmp$species2 <- tmp$species +tmp$species2[tmp$species=="Brown Trout" & + tmp$location=="Trout Lake"] <- "Brown Trout (lotic)" +tmp$species2[tmp$species=="Brown Trout" & + tmp$location=="Brushy Creek"] <- "Brown Trout (lentic)" +peek(tmp,n=10) + +tmp$psd9 <- psdAdd(len~species2,data=tmp) +peek(tmp,n=10) } \references{ diff --git a/man/psdCalc.Rd b/man/psdCalc.Rd index 6c1d4fd9..21416f8f 100644 --- a/man/psdCalc.Rd +++ b/man/psdCalc.Rd @@ -74,48 +74,49 @@ See examples and \href{https://fishr-core-team.github.io/FSA/articles/Computing_ } \examples{ -#===== Random length data for Yellow Perch (for example) to the nearest mm -set.seed(633437) -yepdf <- data.frame(yepmm=round(c(rnorm(100,mean=125,sd=15), - rnorm(50,mean=200,sd=25), - rnorm(20,mean=270,sd=40)),0), - species=rep("Yellow Perch",170)) - #===== Simple (typical) uses with just Gabelhouse lengths +tmp <- subset(PSDWRtest,species=="Yellow Perch",select=c("species","len")) + #----- All results -psdCalc(~yepmm,data=yepdf,species="Yellow Perch") +psdCalc(~len,data=tmp,species="Yellow Perch") #----- Just the traditional indices -psdCalc(~yepmm,data=yepdf,species="Yellow Perch",what="traditional") +psdCalc(~len,data=tmp,species="Yellow Perch",what="traditional") #----- Just the incremental indices -psdCalc(~yepmm,data=yepdf,species="Yellow Perch",what="incremental") +psdCalc(~len,data=tmp,species="Yellow Perch",what="incremental") #===== Add a custom length of interest (to the Gabelhouse lengths) -psdCalc(~yepmm,data=yepdf,species="Yellow Perch",addLens=150) +psdCalc(~len,data=tmp,species="Yellow Perch",addLens=150) #----- Additional lengths can be named -psdCalc(~yepmm,data=yepdf,species="Yellow Perch",addLens=c("minLen"=150)) -psdCalc(~yepmm,data=yepdf,species="Yellow Perch", +psdCalc(~len,data=tmp,species="Yellow Perch",addLens=c("minLen"=150)) +psdCalc(~len,data=tmp,species="Yellow Perch", addLens=c("minLen"=150,"maxslot"=275)) #----- Can return just those results that include the additional lengths -psdCalc(~yepmm,data=yepdf,species="Yellow Perch", +psdCalc(~len,data=tmp,species="Yellow Perch", addLens=c("minSlot"=150,"maxSlot"=275),justAdds=TRUE) -psdCalc(~yepmm,data=yepdf,species="Yellow Perch", +psdCalc(~len,data=tmp,species="Yellow Perch", addLens=c("minSlot"=150,"maxSlot"=275),justAdds=TRUE,what="traditional") #===== Can show intermediate values (num in category and in stock) -psdCalc(~yepmm,data=yepdf,species="Yellow Perch",showInterm=TRUE) +psdCalc(~len,data=tmp,species="Yellow Perch",showInterm=TRUE) + +#===== Some species require use of group +tmp <- subset(PSDWRtest,species=="Brown Trout" & location=="Trout Lake", + select=c("species","location","len")) +peek(tmp,n=6) -#===== Some species require use of group (e.g., treat these as if Brown Trout) -psdCalc(~yepmm,data=yepdf,species="Brown Trout",group="lotic") -psdCalc(~yepmm,data=yepdf,species="Brown Trout",group="lentic") +# will err because Brown Trout has sub-groups in PSDlit +# psdCalc(~len,data=tmp,species="Brown Trout") +psdCalc(~len,data=tmp,species="Brown Trout",group="lotic") +psdCalc(~len,data=tmp,species="Brown Trout (lotic)") #===== For species not in PSDlit ... don't include species and use addLens -# Note that these are same data as above, but treated as different species -psdCalc(~yepmm,data=yepdf,addLens=c("stock"=130,"quality"=200,"preferred"=250, - "memorable"=300,"trophy"=380)) +# Note these are same data as above, but treated as species not in PSDlit +psdCalc(~len,data=tmp,addLens=c("stock"=130,"quality"=200,"preferred"=250, + "memorable"=300,"trophy"=380)) } \references{ diff --git a/man/psdVal.Rd b/man/psdVal.Rd index 1ef6452a..dd6fad11 100644 --- a/man/psdVal.Rd +++ b/man/psdVal.Rd @@ -11,7 +11,8 @@ psdVal( addLens = NULL, addNames = NULL, incl.zero = TRUE, - showJustSource = FALSE + showJustSource = FALSE, + dat = NULL ) } \arguments{ @@ -28,6 +29,8 @@ psdVal( \item{incl.zero}{A logical that indicates if a zero is included in the first position of the returned vector (DEFAULT) or not. This position will be named \dQuote{substock}. See details.} \item{showJustSource}{A logical that indicates whether just the literature source information should be returned (\code{TRUE}) or not. If \code{TRUE} this will NOT return any of the Gabelhouse length information.} + +\item{dat}{Data.frame of Gabelhouse length categories for all species. Defaults to `PSDlit` and is generally not used by the user (this simplifies use of this function in \code{psdAdd}).} } \value{ A vector of minimum values for length categories for the chosen species. @@ -38,6 +41,8 @@ Returns a vector with the five Gabelhouse lengths for a chosen species. \details{ Finds the Gabelhouse lengths from \code{data(PSDlit)} for the species given in \code{species}. The species name must be spelled exactly (including capitalization) as it appears in \code{data(PSDlit)}. Type \code{psdVal()} to see the list of species and how they are spelled. +Some species have length categories separated by sub-group. For example, length categories exist for both lentic and lotic populations of Brown Trout. The length values for a sub-group may be obtained by either including the species name in \code{species} and the sub-group name in \code{group} or by using the combined species and sub-group name, with the sub-group name in parentheses, in \code{species}. Both methods are demonstrated in the examples. Note that an error is returned if a species has sub-groups but neither method is used to define the sub-group.#' + A zero is included in the first position of the returned vector if \code{incl.zero=TRUE}. This is useful when computing PSD values with a data.frame that contains fish smaller than the stock length. Additional lengths may be added to the returned vector with \code{addLens}. Names for these lengths can be included as names in \code{addLens} or separately in \code{addNames}. If \code{addNames} is NULL and \code{addLens} is not named then the default category names will be the lengths from \code{addLens}. The \code{addLens} argument is useful for calculating PSD values that are different from the Gabelhouse lengths. @@ -59,10 +64,15 @@ psdVal("Bluegill",units="in",incl.zero=FALSE) psdVal("Bluegill",showJustSource=TRUE) #===== For species that have sub-groups +#----- using group= argument psdVal("Brown Trout",group="lentic") psdVal("Brown Trout",group="lotic") -psdVal("Palmetto Bass",group="revised") -psdVal("Palmetto Bass",group="original") +#----- group combined in species name, so no group= use +psdVal("Brown Trout (lentic)") + +#===== For species with revised values +psdVal("Palmetto Bass") +psdVal("Palmetto Bass (original)") #===== Adding user-defined categories #----- with lengths and names separately in addLens= and addNames= diff --git a/man/wrAdd.Rd b/man/wrAdd.Rd index 1eb0dbba..df416899 100644 --- a/man/wrAdd.Rd +++ b/man/wrAdd.Rd @@ -8,9 +8,17 @@ \usage{ wrAdd(wt, ...) -\method{wrAdd}{default}(wt, len, spec, units = c("metric", "English"), WsOpts = NULL, ...) - -\method{wrAdd}{formula}(wt, data, units = c("metric", "English"), ...) +\method{wrAdd}{default}( + wt, + len, + spec, + thesaurus = NULL, + units = c("metric", "English"), + WsOpts = NULL, + ... +) + +\method{wrAdd}{formula}(wt, data, thesaurus = NULL, units = c("metric", "English"), ...) } \arguments{ \item{wt}{A numeric vector that contains weight measurements or a formula of the form \code{wt~len+spec} where \dQuote{wt} generically represents the weight variable, \dQuote{len} generically represents the length variable, and \dQuote{spec} generically represents the species variable. Note that this formula can only contain three variables and they must be in the order of weight first, length second, species third.} @@ -21,6 +29,8 @@ wrAdd(wt, ...) \item{spec}{A character or factor vector that contains the species names. Not used if \code{wt} is a formula.} +\item{thesaurus}{A named list for providing alternative species names (the values in the list) that correspond to specific names in \code{PSDlit} (the names in the list). See details and examples.} + \item{units}{A string that indicates whether the weight and length data in \code{formula} are in \code{"metric"} (DEFAULT; mm and g) or \code{"English"} (in and lbs) units.} \item{WsOpts}{A named list that provides specific choices for \code{group}, \code{ref}, or \code{method} for species for which more than one standard weight equation exists in \code{\link{WSlit}}.} @@ -38,6 +48,10 @@ This computes a vector that contains the relative weight specific to each specie The species names in \code{species} must match the spelling and capitalization of \code{species} in \code{\link{WSlit}}. Use \code{wsVal()} to see a list of all species for which standard weight equations exist in \code{\link{WSlit}} and, more importantly, how the species names are spelled and capitalized. +The \code{thesaurus} argument may be used to relate alternate species names to the species names used in \code{WSlit}. For example, you (or your data) may use \dQuote{Bluegill Sunfish}, but \dQuote{Bluegill} is used in \code{WSlit}. The alternate species name can be used here if it is defined in a named vector (or list) given to \code{thesarus=}. The alternate species name is the value and the species name in \code{PSDlit} is the name in this vector/list - e.g., \code{c("Bluegill"="Bluegill Sunfish")}. See the examples for a demonstration. + +Some species have length categories separated by sub-group. For example, length categories exist for both lentic and lotic populations of Brown Trout. The length values for a sub-group may be obtained by either including the species name in \code{species} and the sub-group name in \code{group} in \code{WsOpts} or by using the combined species and sub-group name, with the sub-group name in parentheses, in \code{species}. Both methods are demonstrated in the examples. Note that an error is returned if a species has sub-groups but neither method is used to define the sub-group. + Some (few) species have more than one equation listed in \code{\link{WSlit}} (for the specified units). In these instances the user must select one of the equations to use with \code{WsOpts}. \code{WsOpts} is a list of lists where the inside list contains one or more of \code{group}, \code{ref}, or \code{method} (see \code{\link{WSlit}}) required to specify a single equation for a particular species, which is the name of the inner list. See the examples for an illustration of how to use \code{WsOpts}. See examples and \href{https://fishr-core-team.github.io/FSA/articles/Computing_Relative_Weights.html}{this article} for a demonstration. @@ -47,51 +61,78 @@ See examples and \href{https://fishr-core-team.github.io/FSA/articles/Computing_ } \examples{ -#===== Create random data for three species -#----- just to control the randomization -set.seed(345234534) -dbt <- data.frame(species=factor(rep(c("Bluefin Tuna"),30)), - tl=round(rnorm(30,1900,300),0)) -dbt$wt <- round(4.5e-05*dbt$tl^2.8+rnorm(30,0,6000),1) -dbg <- data.frame(species=factor(rep(c("Bluegill"),30)), - tl=round(rnorm(30,130,50),0)) -dbg$wt <- round(4.23e-06*dbg$tl^3.316+rnorm(30,0,10),1) -dlb <- data.frame(species=factor(rep(c("Largemouth Bass"),30)), - tl=round(rnorm(30,350,60),0)) -dlb$wt <- round(2.96e-06*dlb$tl^3.273+rnorm(30,0,60),1) -df <- rbind(dbt,dbg,dlb) -str(df) - -#===== Add Wr variable -#----- using formula interface -df$Wr1 <- wrAdd(wt~tl+species,data=df) - +#===== Simple example with 3 species, 2 in WSlit ... nothing unusual +tmp <- subset(PSDWRtest, + species \%in\% c("Yellow Perch","Iowa Darter","Largemouth Bass"), + select=c("species","len","wt")) +peek(tmp,n=10) + +#----- Add Wr variable ... using formula interface +tmp$wr1 <- wrAdd(wt~len+species,data=tmp) #----- same but with non-formula interface -df$Wr2 <- wrAdd(df$wt,df$tl,df$species) - +tmp$wr2 <- wrAdd(tmp$wt,tmp$len,tmp$species) #----- same but using dplyr if (require(dplyr)) { - df <- df \%>\% - mutate(Wr3=wrAdd(wt,tl,species)) + tmp <- tmp \%>\% + mutate(wr3=wrAdd(wt,len,species)) } - #----- examine results -peek(df,n=10) - -#===== Example with only one species in the data.frame -bg <- droplevels(subset(df,species=="Bluegill")) -bg$Wr4 <- wrAdd(wt~tl+species,data=bg) -bg - -#===== Example with a species that has Ws eqns for multiple groups and a -# group needs to be specified with WsOpts -wae <- data.frame(species=factor(rep(c("Walleye"),30)), - tl=round(rnorm(30,500,200),0)) -wae$wt <- round(3.33e-06*wae$tl^3.16+rnorm(30,0,50),1) -# wae$Wr <- wrAdd(wt~tl+species,data=wae) # will err b/c multiple groups -wae$Wr <- wrAdd(wt~tl+species,data=wae, - WsOpts=list(Walleye=list(group="overall"))) -peek(wae,n=10) +peek(tmp,n=10) + +#===== Simple example with only one species in the data.frame +tmp <- subset(PSDWRtest,species \%in\% c("Yellow Perch"), + select=c("species","len","wt")) +tmp$wr <- wrAdd(wt~len+species,data=tmp) +peek(tmp,n=6) + +#===== Example of species with sub-groups but only 1 sub-group in data.frame +#----- Group not in species name so must specify group with WsOpts +tmp <- subset(PSDWRtest,species=="Brown Trout" & location=="Trout Lake", + select=c("species","len","wt")) +tmp$wr1 <- wrAdd(wt~len+species,data=tmp, + WsOpts=list("Brown Trout"=list("group"="lotic"))) + +#----- Group in species name so don't specify group with WsOpts +tmp$species2 <- "Brown Trout (lotic)" +tmp$wr2 <- wrAdd(wt~len+species2,data=tmp) # note use of species2 + +peek(tmp,n=6) + +#===== Example of species with sub-groups and 2 sub-groups in data.frame +tmp <- subset(PSDWRtest,species=="Brown Trout", + select=c("species","location","len","wt")) +#----- Must create "species" with sub-groups in name +#----- Many ways to do this, this is just one example for this case +tmp$species2 <- ifelse(tmp$location=="Trout Lake", + "Brown Trout (lotic)","Brown Trout (lentic)") +tmp$wr <- wrAdd(wt~len+species2,data=tmp) # note use of species2 +peek(tmp,n=6) + +#===== Example of a species name that needs the thesaurus +tmp <- subset(PSDWRtest,species \%in\% c("Yellow Perch","Bluegill Sunfish"), + select=c("species","len","wt")) +#----- Below will not add wr for "Bluegill Sunfish" as not in WsLit ("Bluegill" is) +tmp$wr1 <- wrAdd(wt~len+species,data=tmp) +#----- Use thesaurus to identify "Bluegill Sunfish" as "Blueill +tmp$wr2 <- wrAdd(wt~len+species,data=tmp,thesaurus=c("Bluegill"="Bluegill Sunfish")) +peek(tmp,n=10) + +#===== Example of species that has Ws eqns for multiple reference values +tmp <- subset(PSDWRtest,species=="Ruffe",select=c("species","len","wt")) +#----- Below will err as Ruffe has Ws eqns for multiple reference values +# tmp$wr <- wrAdd(wt~len+species,data=tmp) +#----- Must choose which eqn to use with WsOpts +tmp$wr <- wrAdd(wt~len+species,data=tmp, + WsOpts=list(Ruffe=list(ref=75))) +peek(tmp,n=6) + +#===== Example with two uses of WsOpts (and one species without) +tmp <- subset(PSDWRtest,species \%in\% c("Ruffe","Muskellunge","Iowa Darter"), + select=c("species","len","wt")) +tmp$wr <- wrAdd(wt~len+species,data=tmp, + WsOpts=list(Muskellunge=list(group="overall"), + Ruffe=list(ref=75))) +peek(tmp,n=10) } \references{ diff --git a/man/wsVal.Rd b/man/wsVal.Rd index 7b3db782..70fd1966 100644 --- a/man/wsVal.Rd +++ b/man/wsVal.Rd @@ -10,7 +10,8 @@ wsVal( units = c("metric", "English"), ref = NULL, method = NULL, - simplify = FALSE + simplify = FALSE, + dat = NULL ) } \arguments{ @@ -25,6 +26,8 @@ wsVal( \item{method}{A string that indicates which equation-derivation method should be used (one of \code{"RLP"}, \code{"EmP"}, or \code{"Other"}). Defaults to \code{NULL} which will result in the only method available being returned or an error asking the user to choose a method for equations for which more than one method is available (which is the case for very few species).} \item{simplify}{A logical that indicates whether the \sQuote{units}, \sQuote{ref}, \sQuote{measure}, \sQuote{method}, \sQuote{comments}, and \sQuote{source} fields should be included (\code{=FALSE}) or not (\code{=TRUE}; DEFAULT). See details.} + +\item{dat}{Data.frame of Gabelhouse length categories for all species. Defaults to `WSlit` and is generally not used by the user (this simplifies use of this function in \code{wrAdd}).} } \value{ A one row data frame from \code{\link{WSlit}} that contains all known information about the standard weight equation for a given species, type of measurement units, and reference percentile if \code{simplify=FALSE}. If \code{simplify=TRUE} then only the species; minimum and maximum length for which the standard equation should be applied; and intercept, slope, and quadratic coefficients for the standard weight equation. Note that the maximum length and the quadratic coefficient will not be returned if they do not exist in \code{\link{WSlit}} for the species. @@ -43,6 +46,8 @@ See \code{\link{WSlit}} for more information about the meaning of each value ret Note from above that the coefficients are returned for the TRANSFORMED model. Thus, to obtain the standard weight (Ws), the returned coefficients are used to compute the common log of Ws which must then be raised to the power of 10 to compute the Ws. +Some species have length categories separated by sub-group. For example, length categories exist for both lentic and lotic populations of Brown Trout. The length values for a sub-group may be obtained by either including the species name in \code{species} and the sub-group name in \code{group} or by using the combined species and sub-group name, with the sub-group name in parentheses, in \code{species}. Both methods are demonstrated in the examples. Note that an error is returned if a species has sub-groups but neither method is used to define the sub-group. + See examples and \href{https://fishr-core-team.github.io/FSA/articles/Computing_Relative_Weights.html}{this article} for a demonstration. } \section{IFAR Chapter}{ @@ -53,49 +58,51 @@ See examples and \href{https://fishr-core-team.github.io/FSA/articles/Computing_ #===== List all available Ws equations wsVal() -#===== Find equations for Bluegill, in different formats -wsVal("Bluegill") -wsVal("Bluegill",units="metric") -wsVal("Bluegill",units="English") -wsVal("Bluegill",units="English",simplify=TRUE) - -#===== Find equation for Cutthroat Trout, demonstrating use of group -wsVal("Cutthroat Trout",group="lotic") -wsVal("Cutthroat Trout",group="lentic") +#===== Find equations for Yellow Perch, in different formats +wsVal("Yellow Perch") +wsVal("Yellow Perch",units="metric") # same as default +wsVal("Yellow Perch",units="English") +wsVal("Yellow Perch",units="English",simplify=TRUE) #===== Find equation for Ruffe, demonstrating quadratic formula wsVal("Ruffe",units="metric",ref=75,simplify=TRUE) wsVal("Ruffe",units="metric",ref=50,simplify=TRUE) +#===== Find equation for Brown Trout, which has equations for sub-groups +#----- demonstrating use of group= argument +wsVal("Brown Trout",group="lotic") +wsVal("Brown Trout",group="lentic") +#----- demonstrating group combined in species name, so no group= arg +wsVal("Brown Trout (lotic)") +wsVal("Brown Trout (lentic)") + #===== Add Ws & Wr values to a data frame (for one species) ... also see wrAdd() -#----- Get Ws equation info -wsBG <- wsVal("Bluegill",units="metric") -wsBG +#----- Example data from PSDWRtest, simplify variables for this example +yepdf <- subset(PSDWRtest,species=="Yellow Perch",select=c("species","len","wt")) +str(yepdf) -#----- Get example data -data(BluegillLM,package="FSAdata") -str(BluegillLM) +#----- Get Ws equation info +( wsYEP <- wsVal("Yellow Perch",units="metric") ) -#----- Add Ws (eqn is on log10-log10 scale ... so log10 len, 10^ result) -BluegillLM$ws <- 10^(wsBG[["int"]]+wsBG[["slope"]]*log10(BluegillLM$tl)) +#----- Add Ws (eqn is on log10-log10 scale ... so log10 length, 10^ result) +yepdf$ws <- 10^(wsYEP[["int"]]+wsYEP[["slope"]]*log10(yepdf$len)) #----- Change Ws for fish less than min.TL to NA -BluegillLM$ws[BluegillLM$tl\% - mutate(ws=10^(wsBG[["int"]]+wsBG[["slope"]]*log10(tl)), - ws=ifelse(tl\% filter(species=="Yellow Perch") \%>\% select(species,len,wt) \%>\% + mutate(ws=10^(wsYEP[["int"]]+wsYEP[["slope"]]*log10(len)), + ws=ifelse(len% + expect_message("Species in the data with no Gabelhouse") %>% + expect_error("\"Brown Trout\" has Gabelhouse categories for these") + tmp <- psdAdd(len~species,data=df,group=list("Brown Trout"="lotic")) %>% + expect_message("Species in the data with no Gabelhouse") + tmp <- psdAdd(len~species,data=df,group=list("Brown Trout"="lotic"), + thesaurus=c("bluegill"="Bluegill Sunfish")) %>% + expect_message("The following species names were in \'thesaurus\'") %>% + expect_message("Species in the data with no Gabelhouse") + psdAdd(len~species,data=df,group=list("Brown Trout"="lotic"), + thesaurus=c("Bluegill Sunfish")) %>% + expect_error("Values in \'thesaurus\' must be named") + psdAdd(len~species,data=df,group=list("Brown Trout"="lotic"), + thesaurus=c("Bluegill"=7)) %>% + expect_error("Values in \'thesaurus\' must be strings") + psdAdd(len~species,data=df,group=list("Brown Trout"="lotic"), + thesaurus=c("Bluegill"=factor("Bluegill Sunfish"))) %>% + expect_error("\'thesaurus\' must be either a vector or list") + tmp <- psdAdd(len~species,data=df,group=list("Brown Trout"="lotic"), + thesaurus=c("Bluegill"="Bluegill Sunfish")) %>% + expect_message("Species in the data with no Gabelhouse") %>% + expect_no_error() + #===== bad units + expect_error(psdAdd(len~species,df,units="inches"), + "should be one of") + expect_error(psdAdd(df$len,df$species,units="inches"), + "should be one of") + #===== One species had all missing lengths + tmp <- subset(PSDWRtest,species=="Yellow Perch",select=c("species","len")) + tmp$len <- NA_real_ + expect_message(psdAdd(len~species,tmp), + "All values in \'len\' were missing for Yellow Perch") }) test_that("psdCalc() messages",{ - ## species name does not exist in PSDlit - expect_error(psdCalc(~tl,data=df,species="Slimy Sculpin"), + #===== Get some data for one species + df <- subset(PSDWRtest,species=="Yellow Perch",select=c("species","len")) + #===== get Gabelhouse lengths for Yellow Perch + ghl <- psdVal("Yellow Perch") + + #===== species name does not exist in PSDlit + expect_error(psdCalc(~len,data=df,species="Slimy Sculpin"), "There are no Gablehouse lengths in 'PSDlit'") - expect_error(psdCalc(~tl,data=df,species="Yellow perch"), + expect_error(psdCalc(~len,data=df,species="Yellow perch"), "There are no Gablehouse lengths in 'PSDlit'") - ## needed and bad group= - expect_error(psdCalc(~tl,data=df,species="Brown Trout"), + + #===== needed and bad group= + expect_error(psdCalc(~len,data=df,species="Brown Trout"), "\"Brown Trout\" has Gabelhouse categories for these") - expect_error(psdCalc(~tl,data=df,species="Brown Trout",group="Derek"), + expect_error(psdCalc(~len,data=df,species="Brown Trout",group="Derek"), "There is no \"Derek\" group for \"Brown Trout\"") - expect_no_failure(psdCalc(~tl,data=df,species="Brown Trout",group="lotic")) %>% - suppressWarnings() + expect_error(psdCalc(~len,data=df,species="Brown Trout (Lotic)"), + "There are no Gablehouse lengths in 'PSDlit'") + psdCalc(~len,data=df,species="Brown Trout",group="lotic") %>% + expect_warning("some CI coverage may be lower") %>% + expect_no_failure() - ## get Gabelhouse lengths for Yellow Perch - ghl <- psdVal("Yellow Perch") - ## restrict data.frame to no fish - tmp <- subset(df,tl=quality fish - tmp <- subset(df,tl% - expect_warning("No fish in larger than 'stock' categories") %>% - suppressWarnings() - - ## bad formulae - expect_error(psdCalc(tl,data=df,species="Yellow Perch"), - "not found") - expect_error(psdCalc(tl~species,data=df,species="Yellow Perch"), + "\'data\' does not contain any rows") + #----- restrict data.frame to sub-stock-length fish + tmp <- subset(df,len=quality fish + tmp <- subset(df,len% + expect_warning("\'ptbl\' not a table of proportions") %>% + expect_error("\'x\' must be whole numbers") + expect_warning(psdCI(c(1,0,0,0),c(5,3,2,10),20), + "\'ptbl\' not a table of proportions") + expect_warning(psdCI(c(1,0,0,0),c(5,4,3,3),300), + "\'ptbl\' not a table of proportions") + #----- looks like proportions, but doesn't sum to 1 + expect_error(psdCI(c(1,0,0,0),c(0.5,0.3,0.1,0.08),20), + "\'ptbl\' does not sum to 1") + expect_error(psdCI(c(1,0,0,0),c(0.5,0.3,0.2,0.08),20), + "\'ptbl\' does not sum to 1") + #----- small n for table using multinomial distribution + expect_warning(psdCI(c(0,0,0,1),c(0.5,0.3,0.1,0.1),20,method="multinomial"), + "CI coverage may be lower than") + + #===== problems with indicator vector + ipsd <- c(0.130,0.491,0.253,0.123) + n <- 445 + + #----- all zeros + expect_error(psdCI(c(0,0,0,0),ipsd,n), + "\'indvec\' cannot be all zeros") + #----- all ones + expect_error(psdCI(c(1,1,1,1),ipsd,n), + "\'indvec\' cannot be all ones") + #----- wrong length of indvec + expect_error(psdCI(c(1,0,0),ipsd,n), + "Length of \'ptbl\' and \'indvec\' must be the same") + expect_error(psdCI(c(1,0,0,0,0),ipsd,n), + "Length of \'ptbl\' and \'indvec\' must be the same") + + #===== bad args in conf.level + expect_error(psdCI(c(0,0,1,1),ipsd,n=n,conf.level=0), + "\'conf.level\' must be between 0 and 1") + expect_error(psdCI(c(0,0,1,1),ipsd,n=n,conf.level=1), + "\'conf.level\' must be between 0 and 1") + expect_error(psdCI(c(0,0,1,1),ipsd,n=n,conf.level="R"), + "\'conf.level\' must be numeric") +}) + test_that("psdPlot() messages",{ - ## get Gabelhouse lengths for Yellow Perch + #===== Get some data for one species + df <- subset(PSDWRtest,species=="Yellow Perch",select=c("species","len")) + #===== get Gabelhouse lengths for Yellow Perch ghl <- psdVal("Yellow Perch") - - ## restrict data.frame to no fish - tmp <- subset(df,tl=quality fish - tmp <- subset(df,tl=130)) - tmp <- suppressWarnings(psdCalc(~tl,data=df1,species="Yellow Perch")) + + #===== All values, but df only has values greater than stock values + df1 <- droplevels(subset(df,len>=130)) + tmp <- suppressWarnings(psdCalc(~len,data=df1,species="Yellow Perch")) expect_equal(class(tmp),c("matrix","array")) expect_equal(mode(tmp),"numeric") - expect_equal(nrow(tmp),8) + expect_equal(nrow(tmp),7) expect_equal(ncol(tmp),3) - expect_equal(rownames(tmp),c("PSD-Q","PSD-P","PSD-M","PSD-T","PSD S-Q", - "PSD Q-P","PSD P-M","PSD M-T")) + expect_equal(rownames(tmp),c("PSD-Q","PSD-P","PSD-M", + "PSD S-Q","PSD Q-P","PSD P-M","PSD M-T")) expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) - ## All values, but df only has values greater than quality values - df1 <- droplevels(subset(df,tl>=200)) - tmp <- suppressWarnings(psdCalc(~tl,data=df1,species="Yellow Perch")) + + #===== All values, but df only has values greater than quality values + df1 <- droplevels(subset(df,len>=200)) + tmp <- suppressWarnings(psdCalc(~len,data=df1,species="Yellow Perch")) expect_equal(class(tmp),c("matrix","array")) expect_equal(mode(tmp),"numeric") - expect_equal(nrow(tmp),7) + expect_equal(nrow(tmp),6) expect_equal(ncol(tmp),3) - expect_equal(rownames(tmp),c("PSD-Q","PSD-P","PSD-M","PSD-T", + expect_equal(rownames(tmp),c("PSD-Q","PSD-P","PSD-M", "PSD Q-P","PSD P-M","PSD M-T")) expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) - ## All values, but df only has values greater than memorable value - df1 <- droplevels(subset(df,tl>=300)) - tmp <- suppressWarnings(psdCalc(~tl,data=df1,species="Yellow Perch")) + + #===== All values, but df only has values greater than memorable value + df1 <- droplevels(subset(df,len>=300)) + tmp <- suppressWarnings(psdCalc(~len,data=df1,species="Yellow Perch")) expect_equal(class(tmp),c("matrix","array")) expect_equal(mode(tmp),"numeric") - expect_equal(nrow(tmp),5) + expect_equal(nrow(tmp),4) expect_equal(ncol(tmp),3) - expect_equal(rownames(tmp),c("PSD-Q","PSD-P","PSD-M","PSD-T","PSD M-T")) + expect_equal(rownames(tmp),c("PSD-Q","PSD-P","PSD-M","PSD M-T")) expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) - ## Pretend like no species is given - tmp <- suppressWarnings(psdCalc(~tl,data=df, + #===== Pretend like no species is given + tmp <- suppressWarnings(psdCalc(~len,data=df, addLens=c("stock"=130,"quality"=200,"preferred"=250, "memorable"=300,"trophy"=380))) expect_equal(class(tmp),c("matrix","array")) expect_equal(mode(tmp),"numeric") - expect_equal(nrow(tmp),8) + expect_equal(nrow(tmp),7) expect_equal(ncol(tmp),3) - expect_equal(rownames(tmp),c("PSD-Q","PSD-P","PSD-M","PSD-T","PSD S-Q", - "PSD Q-P","PSD P-M","PSD M-T")) + expect_equal(rownames(tmp),c("PSD-Q","PSD-P","PSD-M", + "PSD S-Q","PSD Q-P","PSD P-M","PSD M-T")) expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) - tmp <- suppressWarnings(psdCalc(~tl,data=df, + tmp <- suppressWarnings(psdCalc(~len,data=df, addLens=c("stock"=130,"name1"=200,"name2"=250))) expect_equal(class(tmp),c("matrix","array")) expect_equal(mode(tmp),"numeric") @@ -490,7 +476,7 @@ test_that("psdCalc() returns",{ expect_equal(rownames(tmp),c("PSD-name1","PSD-name2","PSD S-name1","PSD name1-name2")) expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) - tmp <- suppressWarnings(psdCalc(~tl,data=df, + tmp <- suppressWarnings(psdCalc(~len,data=df, addLens=c("stock"=130,"name1"=200))) expect_equal(class(tmp),c("matrix","array")) expect_equal(mode(tmp),"numeric") @@ -500,26 +486,80 @@ test_that("psdCalc() returns",{ expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) }) -test_that("psdAdd() returns",{ - tmp <- df - tmp$PSD <- suppressMessages(psdAdd(tl~species,data=tmp)) - expect_equal(ncol(tmp),4) - expect_true(is.factor(tmp$PSD)) - tmp$PSD <- suppressMessages(psdAdd(tl~species,data=tmp,use.names=FALSE)) - expect_equal(ncol(tmp),4) - expect_true(is.numeric(tmp$PSD)) -}) +test_that("psdCI() returns",{ + #===== Make an incremental proportions table + n <- 997 + ipsd <- c(130,491,253,123)/n + + #===== single binomial + tmp <- psdCI(c(0,0,1,1),ipsd,n=n) + expect_equal(class(tmp),c("matrix","array")) + expect_equal(mode(tmp),"numeric") + expect_equal(nrow(tmp),1) + expect_equal(ncol(tmp),3) + expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) + + tmp <- psdCI(c(1,0,0,0),ipsd,n=n,label="PSD S-Q") + expect_equal(class(tmp),c("matrix","array")) + expect_equal(mode(tmp),"numeric") + expect_equal(nrow(tmp),1) + expect_equal(ncol(tmp),3) + expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) + expect_equal(rownames(tmp),"PSD S-Q") + + #===== single multinomial + tmp <- psdCI(c(0,0,1,1),ipsd,n=n,method="multinomial") + expect_equal(class(tmp),c("matrix","array")) + expect_equal(mode(tmp),"numeric") + expect_equal(nrow(tmp),1) + expect_equal(ncol(tmp),3) + expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) + + tmp <- psdCI(c(1,0,0,0),ipsd,n=n,method="multinomial",label="PSD S-Q") + expect_equal(class(tmp),c("matrix","array")) + expect_equal(mode(tmp),"numeric") + expect_equal(nrow(tmp),1) + expect_equal(ncol(tmp),3) + expect_equal(colnames(tmp),c("Estimate","95% LCI","95% UCI")) + expect_equal(rownames(tmp),"PSD S-Q") + + #===== Adjustment for not proportions + ipsd <- c(130,491,253,123) + n <- sum(ipsd) + ipsd2 <- ipsd/n + + tmp <- suppressWarnings(psdCI(c(0,0,1,1),ipsd,n=n)) + tmp2 <- psdCI(c(0,0,1,1),ipsd2,n=n) + expect_equal(tmp,tmp2) + + tmp <- suppressWarnings(psdCI(c(0,0,1,1),ipsd,n=n,method="multinomial")) + tmp2 <- psdCI(c(0,0,1,1),ipsd2,n=n,method="multinomial") + expect_equal(tmp,tmp2) + + ## Adjustment for a PSD of 0 or 1 + ipsd <- c(1,0,0,0) + n <- 455 + tmp <- psdCI(c(1,1,0,0),ipsd,n=n) + expect_equal(tmp,matrix(c(100,NA,NA),nrow=1),ignore_attr=TRUE) + + ipsd <- c(0,0,0,1) + n <- 455 + tmp <- psdCI(c(1,1,0,0),ipsd,n=n) + expect_equal(tmp,matrix(c(0,NA,NA),nrow=1),ignore_attr=TRUE) +}) ## Validate Results ---- test_that("Does psdAdd() create correct Gabelhouse categories?",{ - suppressMessages(df2$gcatn <- psdAdd(tl~species,data=df2)) - expect_equal(df2$gcatn,df2$GCATN) + #!!!!! df2 has hand-calculated results for psd variable + suppressMessages(df2$psd2 <- psdAdd(len~species2,data=df2, + thesaurus=thes)) + expect_equal(df2$psd,df2$psd2) }) test_that("Does psdAdd() properly handle NA in species?",{ - ## Makes sure NAs are in proper position and by extension correct number - # Just NAs for species only one other species + #!!!!! Makes sure NAs are in proper position and by extension correct number + #===== Just NAs for species only one other species testdf <- data.frame(TL=c(400,90,250,130,50), Spp=c("White Crappie",NA,"White Crappie", "White Crappie","White Crappie")) @@ -527,7 +567,7 @@ test_that("Does psdAdd() properly handle NA in species?",{ expect_equal(which(is.na(testdf$TL) | is.na(testdf$Spp)), which(is.na(gcat))) - # Just NAs for species only multiple other species + #===== Just NAs for species only multiple other species testdf <- data.frame(TL=c(400,90,250,130,50), Spp=c("White Crappie",NA,"White Crappie", "White Crappie","Black Crappie")) @@ -535,7 +575,7 @@ test_that("Does psdAdd() properly handle NA in species?",{ expect_equal(which(is.na(testdf$TL) | is.na(testdf$Spp)), which(is.na(gcat))) - # Just NAs for species, but with a species w/o Gabelhouse lengths + #===== Just NAs for species, but with a species w/o Gabelhouse lengths testdf <- data.frame(TL=c(400,90,250,NA,50), Spp=c("White Crappie",NA,"badSpp", "White Crappie","Black Crappie")) @@ -543,139 +583,118 @@ test_that("Does psdAdd() properly handle NA in species?",{ expect_equal(which(is.na(testdf$TL) | is.na(testdf$Spp) | testdf$Spp=="badSpp"), which(is.na(gcat))) - # NAs for length and species + #===== NAs for length and species testdf <- data.frame(TL=c(400,90,250,NA,50), Spp=c("White Crappie",NA,"White Crappie", "White Crappie","Black Crappie")) suppressMessages(gcat <- psdAdd(TL~Spp,data=testdf,drop.levels=TRUE)) expect_equal(which(is.na(testdf$TL) | is.na(testdf$Spp)), which(is.na(gcat))) - }) test_that("Does psdCalc() compute correct PSD values?",{ - suppressWarnings(bgres <- psdCalc(~tl,data=df2bg,species="Bluegill")) - expect_equal(bgres[,"Estimate"],c(80,60,40,20,20,20,20,20),ignore_attr=TRUE) - suppressWarnings(lmbres <- psdCalc(~tl,data=df2lmb,species="Largemouth Bass")) - expect_equal(lmbres[,"Estimate"],c(60,30,10,40,30,20,10),ignore_attr=TRUE) - ## pretend like no species is given (but using bluegill results) - suppressWarnings(bgres <- psdCalc(~tl,data=df2bg, - addLens=c("stock"=80,"quality"=150, - "preferred"=200,"memorable"=250, - "trophy"=300))) - expect_equal(bgres[,"Estimate"],c(80,60,40,20,20,20,20,20),ignore_attr=TRUE) + #===== Bluegill and Bass examples + suppressWarnings(res <- psdCalc(~len,data=subset(df2,species=="Bluegill Sunfish"), + species="Bluegill")) + expect_equal(res[,"Estimate"],c(55,10,45,45,10),ignore_attr=TRUE) + suppressWarnings(res <- psdCalc(~len,data=subset(df2,species=="Largemouth Bass"), + species="Largemouth Bass")) + expect_equal(res[,"Estimate"],c(43,4,57,39,4),ignore_attr=TRUE) + + #===== pretend like no species is given (but using bluegill results) + suppressWarnings(res <- psdCalc(~len,data=subset(df2,species=="Bluegill Sunfish"), + species="Bluegill", + addLens=c("stock"=80,"quality"=150, + "preferred"=200,"memorable"=250, + "trophy"=300))) + expect_equal(res[,"Estimate"],c(55,10,45,45,10),ignore_attr=TRUE) }) #test_that("Does psdCalc() work with a tibble?",{ -# tmp <- tibble::as_tibble(df2bg) -# suppressWarnings(bgres <- psdCalc(~tl,data=df2bg,species="Bluegill")) -# suppressWarnings(bgres2 <- psdCalc(~tl,data=tmp,species="Bluegill")) -# expect_equal(bgres,bgres2) +# #!!!!! Commented out so as not to have to include tibble in package depends +# tmp1 <- subset(df2,species=="Bluegill Sunfish") +# tmp2 <- tibble::as_tibble(tmp1) +# suppressWarnings(res1 <- psdCalc(~len,data=tmp1,species="Bluegill")) +# suppressWarnings(res2 <- psdCalc(~len,data=tmp2,species="Bluegill")) +# expect_equal(res,res2) #}) -test_that("Does psdCI results match Brenden et al. (2008) results",{ - ## proportions table from Brenden et al. (2008) - ipsd <- c(0.130,0.491,0.253,0.123) - n <- 445 - - ## results from Brendent et al. (2008) ... Table 2 - bpsd <- cbind(c(13,49,25,12,87,38), - c(9,42,20,8,82,31), - c(17,56,31,17,91,44)) - colnames(bpsd) <- c("Estimate","95% LCI","95% UCI") - rownames(bpsd) <- c("PSD S-Q","PSD Q-P","PSD P-M","PSD M-T","PSD","PSD-P") - - ## psdCI calculations - imat <- matrix(c(1,0,0,0, - 0,1,0,0, - 0,0,1,0, - 0,0,0,1, - 0,1,1,1, - 0,0,1,1),nrow=6,byrow=TRUE) - rownames(imat) <- rownames(bpsd) - mcis <- t(apply(imat,MARGIN=1,FUN=psdCI,ptbl=ipsd,n=n,method="multinomial")) - colnames(mcis) <- c("Estimate","95% LCI","95% UCI") - diff <- mcis-bpsd - # Brenden's results were rounded, thus all should be within 0.5 - expect_true(all(abs(diff)<=0.5)) -}) - -test_that("Does psdCI results match Brenden et al. (2008) results",{ - ## Setup sample with known PSD values +test_that("Does psdCalc() results match Brenden et al. (2008) results",{ + #===== Setup sample with known PSD values brks <- psdVal("Yellow Perch") freq <- c(110,75,50,35,20,10) - df3 <- data.frame(tl=rep(brks,freq)+sample(1:45,300,replace=TRUE), + tmp <- data.frame(tl=rep(brks,freq)+sample(1:45,300,replace=TRUE), species=factor(rep("Yellow Perch",300))) - ## Get known PSD values + + #===== Get known PSD values psdXYs <- prop.table(freq[-1])*100 psdXs <- rcumsum(psdXYs)[-1] psdXYs <- psdXYs[-length(psdXYs)] - ## Get psdCalc results + + #----- Get psdCalc results suppressWarnings( - resXY <- psdCalc(~tl,data=df3,species="Yellow Perch",what="incremental", + resXY <- psdCalc(~tl,data=tmp,species="Yellow Perch",what="incremental", digits=getOption("digits"))) suppressWarnings( - resX <- psdCalc(~tl,data=df3,species="Yellow Perch",what="traditional", + resX <- psdCalc(~tl,data=tmp,species="Yellow Perch",what="traditional", digits=getOption("digits"))) - ## Are lengths what you would expect + + #----- Are lengths what you would expect expect_equal(nrow(resXY),4) expect_equal(nrow(resX),4) - ## Are values the same + #----- Are values the same diffs <- round(resXY[,"Estimate"]-psdXYs,7) expect_equal(diffs,rep(0,length(diffs)),ignore_attr=TRUE) diffs <- round(resX[,"Estimate"]-psdXs,7) expect_equal(diffs,rep(0,length(diffs)),ignore_attr=TRUE) - ## Do things still work if all sub-stock fish are removed - tmp <- droplevels(subset(df3,tl>=brks["stock"])) + #===== Do things still work if all sub-stock fish are removed + tmp1 <- droplevels(subset(tmp,tl>=brks["stock"])) suppressWarnings( - resXY <- psdCalc(~tl,data=tmp,species="Yellow Perch",what="incremental", + resXY <- psdCalc(~tl,data=tmp1,species="Yellow Perch",what="incremental", digits=getOption("digits"))) suppressWarnings( - resX <- psdCalc(~tl,data=tmp,species="Yellow Perch",what="traditional", + resX <- psdCalc(~tl,data=tmp1,species="Yellow Perch",what="traditional", digits=getOption("digits"))) expect_equal(nrow(resXY),4) expect_equal(nrow(resX),4) - ## Are values the same diffs <- round(resXY[,"Estimate"]-psdXYs,7) expect_equal(diffs,rep(0,length(diffs)),ignore_attr=TRUE) diffs <- round(resX[,"Estimate"]-psdXs,7) expect_equal(diffs,rep(0,length(diffs)),ignore_attr=TRUE) - ## Do things still work if all sub-stock and stock fish are removed + #===== Do things still work if all sub-stock and stock fish are removed psdXYs <- prop.table(freq[-c(1:2)])*100 psdXs <- rcumsum(psdXYs)[-1] psdXYs <- psdXYs[-length(psdXYs)] - tmp <- droplevels(subset(df3,tl>=brks["quality"])) + tmp1 <- droplevels(subset(tmp,tl>=brks["quality"])) suppressWarnings( - resXY <- psdCalc(~tl,data=tmp,species="Yellow Perch",what="incremental", + resXY <- psdCalc(~tl,data=tmp1,species="Yellow Perch",what="incremental", digits=getOption("digits"))) suppressWarnings( - resX <- psdCalc(~tl,data=tmp,species="Yellow Perch",what="traditional", + resX <- psdCalc(~tl,data=tmp1,species="Yellow Perch",what="traditional", digits=getOption("digits"))) expect_equal(nrow(resXY),3) # no S-Q row expect_equal(nrow(resX),4) # all should be there - ## Are values the same diffs <- round(resXY[,"Estimate"]-psdXYs,7) expect_equal(diffs,rep(0,length(diffs)),ignore_attr=TRUE) diffs <- round(resX[-1,"Estimate"]-psdXs,7) expect_equal(diffs,rep(0,length(diffs)),ignore_attr=TRUE) - ## Do things still work if all trophy fish are removed + #===== Do things still work if all trophy fish are removed psdXYs <- prop.table(freq[-c(1,length(freq))])*100 psdXs <- rcumsum(psdXYs)[-1] - tmp <- droplevels(subset(df3,tl% - expect_output("Walleye") - expect_error(wrAdd(wt~tl+species,wae, + #===== need to use WsOpts + expect_error(wrAdd(wt~len+species,df2), + "More than one Ws equation exists for \"Ruffe\"") %>% + expect_output("Ruffe") + expect_error(wrAdd(wt~len+species,df2, WsOpts=list(Bluegill=list(group="overall"))), + "More than one Ws equation exists for \"Ruffe\"") %>% + expect_output("Ruffe") + expect_error(wrAdd(wt~len+species,df2, + WsOpts=list(Ruffe=list(ref=50))), "More than one Ws equation exists for \"Walleye\"") %>% expect_output("Walleye") - expect_error(wrAdd(wt~tl+species,wae, - WsOpts=list(Walleye=list(ref=50))), + expect_error(wrAdd(wt~len+species,df2, + WsOpts=list(Ruffe=list(ref=50), + Walleye=list(ref=50))), "Use of 'ref=50' for \"Walleye\" did not return") - expect_error(wrAdd(wt~tl+species,wae, - WsOpts=list(Walleye=list(junk=50))), + expect_error(wrAdd(wt~len+species,df2, + WsOpts=list(Ruffe=list(junk=50))), "'junk' in 'WsOpts=' must be one of") + expect_no_error(wrAdd(wt~len+species,data=df2, + WsOpts=list(Walleye=list(group="overall"), + Ruffe=list(ref=75)))) + + #===== bad thesaurus + expect_error(wrAdd(wt~len+species,df2,thesaurus=c("Bluegill"), + WsOpts=list(Walleye=list(group="overall"), + Ruffe=list(ref=75))), + "Values in \'thesaurus\' must be named") + expect_error(wrAdd(wt~len+species,df2,thesaurus=c("Bluegill"=7), + WsOpts=list(Walleye=list(group="overall"), + Ruffe=list(ref=75))), + "Values in \'thesaurus\' must be strings of species names") + expect_error(wrAdd(wt~len+species,df2,thesaurus=factor(c("Bluegill"="Bluegill Sunfish")), + WsOpts=list(Walleye=list(group="overall"), + Ruffe=list(ref=75))), + "\'thesaurus\' must be either a vector or list") + tmp <- wrAdd(wt~len+species,df2,thesaurus=c("bluegill"="Bluegill Sunfish"), + WsOpts=list(Walleye=list(group="overall"), + Ruffe=list(ref=75))) %>% + expect_message("The following species names were in \'thesaurus\' but do not") }) ## Test Output Types ---- test_that("wsVal() results",{ - ## Do Bluegill results match ... example with no group or quad + #===== Do Bluegill results match ... example with no group or quad bg1 <- wsVal("Bluegill") bg2 <- WSlit[WSlit$species=="Bluegill" & WSlit$units=="metric",] bg2 <- bg2[,!names(bg2) %in% c("group","max.len","quad","comment")] @@ -116,7 +141,7 @@ test_that("wsVal() results",{ bg2 <- WSlit[WSlit$species=="Bluegill" & WSlit$units=="English",] bg2 <- bg2[,names(bg2) %in% c("species","min.len","int","slope")] expect_equal(bg1,bg2,ignore_attr=TRUE) - ## Do Ruffe results match ... example with quad + #===== Do Ruffe results match ... example with quad ruf1 <- wsVal("Ruffe",ref=75) ruf2 <- WSlit[WSlit$species=="Ruffe" & WSlit$units=="metric" & WSlit$ref=="75",] ruf2 <- ruf2[!names(ruf2) %in% c("group","comment")] @@ -125,7 +150,7 @@ test_that("wsVal() results",{ ruf2 <- WSlit[WSlit$species=="Ruffe" & WSlit$units=="metric" & WSlit$ref=="75",] ruf2 <- ruf2[,names(ruf2) %in% c("species","min.len","max.len","int","slope","quad")] expect_equal(ruf1,ruf2,ignore_attr=TRUE) - ## Do Walleye results match ... example with a sub-group + #===== Do Walleye results match ... example with a sub-group wae1 <- wsVal("Walleye",group="overall") wae2 <- WSlit[WSlit$species=="Walleye" & WSlit$group=="overall" & WSlit$units=="metric",] wae2 <- wae2[,!names(wae2) %in% c("max.len","quad","comment")] @@ -138,19 +163,38 @@ test_that("wsVal() results",{ wae2 <- WSlit[WSlit$species=="Walleye" & WSlit$group=="overall" & WSlit$units=="metric",] wae2 <- wae2[,names(wae2) %in% c("species","min.len","int","slope")] expect_equal(wae1,wae2,ignore_attr=TRUE) + #===== Do Walleye results match ... example with a sub-group in the species name + wae1 <- wsVal("Walleye (overall)") + wae2 <- WSlit[WSlit$species=="Walleye (overall)" & WSlit$units=="metric",] + wae2 <- wae2[,!names(wae2) %in% c("group","max.len","quad","comment")] + expect_equal(wae1,wae2,ignore_attr=TRUE) + wae1 <- wsVal("Walleye (overall)",units="English") + wae2 <- WSlit[WSlit$species=="Walleye (overall)" & WSlit$units=="English",] + wae2 <- wae2[,!names(wae2) %in% c("group","max.len","quad","comment")] + expect_equal(wae1,wae2,ignore_attr=TRUE) + wae1 <- wsVal("Walleye (overall)",simplify=TRUE) + wae2 <- WSlit[WSlit$species=="Walleye (overall)" & WSlit$units=="metric",] + wae2 <- wae2[,names(wae2) %in% c("species","min.len","int","slope")] + expect_equal(wae1,wae2,ignore_attr=TRUE) - ## + #===== Check list output expect_message(capture.output(wsVal("List")),"must be one of following") expect_output(suppressMessages(wsVal("List"))) }) ## Validate Results ---- -test_that("wrAdd() matches values computed in Excel.",{ +test_that("wrAdd() matches values computed 'by hand' in Excel.",{ # Read in external CSV file - ftmp <- system.file("extdata","PSDWR_testdata.csv",package="FSA") - df <- read.csv(ftmp) - - df$wr <- wrAdd(wt~tl+species,data=df) - expect_equal(df$wr,df$WR) + ftmp <- system.file("extdata","PSDWR_data4testthat.csv",package="FSA") + tmp <- read.csv(ftmp) + # Create a thesaurus for a couple of species + thes <- c("Bluegill"="Bluegill Sunfish", + "Lake Trout"="Lean Lake Trout") + # Add wr variable as calculated in FSA + tmp$wr2 <- wrAdd(wt~len+species2,data=tmp, + thesaurus=thes, + WsOpts=list(Ruffe=list(ref=75))) + # Compare + expect_equal(tmp$wr,tmp$wr2) }) diff --git a/vignettes/articles/Computing_PSDs.qmd b/vignettes/articles/Computing_PSDs.qmd index b814153a..32474855 100644 --- a/vignettes/articles/Computing_PSDs.qmd +++ b/vignettes/articles/Computing_PSDs.qmd @@ -25,11 +25,11 @@ The following packages are used herein. Note that the `FSA` functions described #| results: hide #| message: false library(FSA) -library(dplyr) # mutate, select, group_by, summarize +library(dplyr) # mutate, select, filter, case_when ``` -# Creating PSD-Related Length Categories +# Looking-Up PSD-Related Lengths ## Gabelhouse Length Categories Five-cell Gabelhouse (GH) length categories have been deveoped for a number of freshwater game fish in the United States, as well as several non-game fish in the United States and some other fish from outside of the United States. These values have been collated into the `PSDlit` data.frame^[Specifics [here](https://fishr-core-team.github.io/FSA/reference/PSDlit.html).] distributed with `FSA` and are most easily accessed with `psdVal()`. For example, the GH length categories for Bluegill are retrieved below. @@ -37,14 +37,14 @@ Five-cell Gabelhouse (GH) length categories have been deveoped for a number of f psdVal("Bluegill") ``` -The default is to return lengths in millimeters; however, they can be returned in centimeters or inches with `units=` +The default is to return lengths in millimeters; however, they can be returned in centimeters or inches with `units=`.^[A few species do not have define English unit lengths.] ```{r} psdVal("Bluegill",units="cm") psdVal("Bluegill",units="in") ``` -By default, a sixth cell is included that is labeled as "substock" and will always have the value of 0. This can be useful for data that includes individuals shorter than the stock length. Use `incl.zero=FALSE` to exclude this category. +By default, a sixth cell is included that is labeled as "substock" and will always have the value of 0. This can be useful for some analyses with data that includes individuals shorter than the stock length. Use `incl.zero=FALSE` to exclude this category. ```{r} psdVal("Bluegill",incl.zero=FALSE) @@ -71,12 +71,36 @@ A small number of species have separate length designations for sub-groups of th psdVal("Brown Trout") ``` -Then try again with `group=` as suggested to select a specific group. +Then try again with `group=` to select a specific group as suggested. ```{r} psdVal("Brown Trout",group="lotic") ``` +These same species and sub-group combinations can also be accessed by combining the species name and lower-case sub-group name (in parenthesis) into the first argument (and then not using `group=`). + +```{r} +psdVal("Brown Trout (lotic)") +``` + +Thus, species with sub-group designations can be identified by scanning the list of names returned by `psdVal()` for parentheses. This has some limitations as there are a few species that appear to have a sub-group but the name with parentheses is only used here (in `PSDlit`) to facilitate use when calculating PSD and relative weight metrics^[As described in [this vignette](https://fishr-core-team.github.io/FSA/articles/Computing_Relative_Weights.html).] with the same data.frame. Muskellunge is an example of this where there is only one set of GH length categories but they are repeated for separate sub-groups because separate standard weight equations exist for these sub-groups. + +```{r} +psdVal("Muskellunge") +psdVal("Muskellunge (overall)") +psdVal("Muskellunge (female)") +psdVal("Muskellunge (male)") +``` + +There are also a few species where an original definition of GH length categories has been revised in the literature. The original and revised definitions are available in `PSDlit` with the revised definitions accessed by using just the species name and the original definitions accessed by appending "(original)" to the species name. + +```{r} +psdVal("Spotted Bass") # revised definitions +psdVal("Spotted Bass (original)") +``` + +We strongly urge you to have a good understanding of the GH length categories for your species' of interest and make sure that `psdVal()` is returning the values that you expect (i.e., correct species, sub-group (if appropriate), units, etc.). + ## Additional Length Categories There may be times when you desire length categories in addition to the GH lengths. For example, suppose that the minimum length limit for Largemouth Bass is 254 mm. This length can be included as one of the categories by including a vector with the length (or lengths) to `addLens=`. If the item in the vector is named (second example below) then the value will also be named in the returned result. @@ -91,12 +115,12 @@ Multiple additional lengths can be included. psdVal("Largemouth Bass",addLens=c("minSlot"=254,"maxSlot"=356)) ``` -# Adding Length Category Variable for One Species +# Add Length Categories for One Species ## "Manual" Additions -Suppose that we want to add another variable with the GH length categories to the data.frame of lengths (along with capture location) for Yellow Perch from Saginaw Bay, MI in `YPerchSB1` (distributed with the `FSAdata` package). Note here that lengths are in **centimeters**. +Suppose that we want to add a variable with the GH length categories to the data.frame of lengths (along with capture location) for Yellow Perch from Saginaw Bay, MI in `YPerchSB1` (distributed with the `FSAdata` package). Note here that lengths are in **centimeters**. ```{r} -data(YPerchSB1,package="FSAdata") +data(YPerchSB1,package="FSAdata") # retrieve the data.frame peek(YPerchSB1,n=10) ``` @@ -122,55 +146,158 @@ YPerchSB1 <- YPerchSB1 |> peek(YPerchSB1,n=10) ``` -A frequency table can then be used to find the number of individuals in each category. +## Use the `psdAdd()` Convenience Function +`psdAdd()` can be used to add a length categorization variable to a data.frame for **all** species in the data.frame for which the GH length categories exists.^[Here, however, it is being applied to a data.frame with only one species.] The main argument to `psdAdd()` is a formula of the form `length~species`, where `length` is the name of the observed length variable and `species` is the name of the species variable. In these data there is no variable that identified the species, likely because the data contains only one species. Thus, before `psdAdd()` can be used in this example, a new variable with the species name was added.^[`YperchSB1` was loaded again to start without the modifications performed previously.] + +```{r} +data(YPerchSB1,package="FSAdata") +YPerchSB1 <- YPerchSB1 |> + mutate(spec="Yellow Perch", + ghcats1=psdAdd(tl~spec,units="cm")) +peek(YPerchSB1,n=10) +``` + +`psdAdd()` requires that the species variable have the species names in the spelling and capitalization used by `PSDlit`. So, for example, suppose that the `YPerchSB1` species names used the abbreviation `yep` rather than `Yellow Perch`.^[Note that `YPerchSB1` is loaded again to start over and the new abbreviation is added for this example.] A named list or vector can be given to `thesaurus=` that defines how the original species names (i.e., the items to the right of the `=` in the vector) relate to the species names required by `PSDlit` (i.e., the names to the left of the `=` in the vector). `psdAdd()` will match the two names appropriately while creating the GH length categories. ```{r} -xtabs(~ghcats2,data=YPerchSB1) +data(YPerchSB1,package="FSAdata") +YPerchSB1 <- YPerchSB1 |> + mutate(spec="yep", + ghcats1=psdAdd(tl~spec,units="cm",thesaurus=c("Yellow Perch"="yep"))) +peek(YPerchSB1,n=10) ``` -The reverse cumulative sum of these values, with the substock fish removed, divided by the stock-length sum times 100 are the PSD-X values. +# Add Length Categories for Multiple Species +The real value of `psdAdd()` is that it can be used to efficiently add length categories for multiple species in a single data.frame. This is illustrated below for a variety of scenarios. + +## "Good" Names and No Groups +`InchLake2` distributed with `FSAdata` contains lengths for several species captured from Inch Lake. These data provide a simple example for using `psdAdd()` because all species names are spelled and capitalized as required (i.e., same as in `PSDlit1) and none of the species have sub-groups.^[See the next section for how to deal with these issues.] Note that lengths are in **inches** here. ```{r} -( tmp <- rcumsum(xtabs(~ghcats2,data=YPerchSB1))[-1] ) -round(tmp/tmp["stock"]*100,1) +data("InchLake2",package="FSAdata") # retrieve the data.frame +peek(InchLake2,n=10) ``` -So, for example, `r round(tmp/tmp["stock"]*100,1)[["quality"]]`\% of fish that reach stock-size also reached quality-size (i.e., "PSD-Q"). +`psdAdd()` can be used as described previously (i.e., with a formula of the form `length~species` and `units=`) to add GH length categories for all species in the data.frame for which GH length categories exist in `PSDlit`. A message will be issued identifying the species in the data.frame for which GH length categories do not exist. The new variable will show `` for those species. -## Use the `psdAdd()` Convenience Function -`psdAdd()` can be used to add a length categorization variable to a data.frame for **all** species in the data.frame for which the GH length categories exists. The main argument to `psdAdd()` is a formula of the form `length~species`, where `length` is the observed length variable and `species` is the name of the species variable. Again, the species must be spelled (and capitalized) as in `PSDlit`. In these data there is no variable that identified the species, likely because the data contains only one species. Thus, for this example, before `psdAdd()` can be used, a new variable with the species name must be added. +```{r} +InchLake2 <- InchLake2 |> + mutate(ghcats1=psdAdd(length~species,units="in")) +peek(InchLake2,n=10) +``` + +Additional non-GH length categories can be used with `psdAdd()` through `addLens()` similar to what was described for `psdVal()`. However, a named list must be given to `addLens()` that has named vectors for each species for the additional lengths to be added. An example for this is given in [the documentation](https://fishr-core-team.github.io/FSA/reference/psdAdd.html) for `psdAdd()`. + +## "Bad" Names and No Groups +Now consider the `Herman` data.frame (distributed with the `FSAdata` package) that has the lengths (cm) of four species -- Walleye, Yellow Perch, Black Crappie, and Black Bullhead -- from Lake Herman, SD. These four species do not have sub-groups defined in `PSDlit`. However, observing the data below^[And [the documentation](https://fishr-core-team.github.io/FSAdata/reference/Herman.html).] shows that the species variable (`spec`) contains codes for the species names rather than the names required by `PSDlit`. + +```{r} +data(Herman,package="FSAdata") # retrieve the data.frame +peek(Herman,n=10) +``` + +One way to deal with the issue of "bad" species names is to use a named list or vector that defines how the names from `PSDlit` should be matched to the names in the data.frame. As before, the species names in `PSDlit` are the names in the vector (i.e., before the `=`) and the species names in the data.frame are the items in the vector (i.e., after the `=`). + +```{r} +thes <- c("Walleye"="wae","Yellow Perch"="yep", + "Black Crappie"="bkc","Black Bullhead"="bbh") +``` + +This list/vector is then given to `thesaurus=` in `psdAdd()` which will perform the name matching while creating the GH length categories. + +```{r} +Herman <- Herman |> + mutate(ghcats1=psdAdd(tl~spec,units="cm",thesaurus=thes)) +peek(Herman,n=10) +``` + +`thesaurus=` can be used even if only some of the species names are non-"standard." Additionally, the named list/vector in `thesaurus=` can contain names that don't exist in the original data.frame. Thus, a global thesaurus containing all species that *could* be encountered could be created, for example as an agency-wide definition, and used with a variety of specific data.frames. + +## "Bad" Names and Groups +The use of `psdAdd()` can become complicated for data.frames with species names other than what `PSDlit` expects and species for which GH lengths exist for sub-groups, especially if more than one sub-group is in the data. The hypothetical data set `PSDWRtest` distributed with `FSA` can be used to illustrate how to handle these "issues". + +```{r} +peek(PSDWRtest,n=20) +``` + +`psdAdd()` will produce some informative error messages, but it is best that you have a full understanding of the issues that may arise with your data by carefully examining your data and understanding the GH length categories for the species in your data. The "issues" that need to be addressed with the `PSDWRtest` data are as follows: + + - "Bluegill Sunfish" was used rather than "Bluegill". + - "Lean Lake Trout" was used rather than "Lake Trout". + - Brook Trout were sampled from a lotic ("Trout Lake") system, for which there are sub-groups for GH length categories. + - Brown Trout were sampled from a lotic ("Trout Lake") and lentic ("Brush Creek") system, for which there are sub-groups for GH length categories. + +The easiest way to deal with all of these "issues" is to create a new "species" variable (i.e., `species2` below) that appends the specific groups in parentheses to the species name. There are a variety of ways to do this and which way (is best or works) may depend on the specifics of the situation. Here, `case_when()` from `dplyr` is used with a series of statements that begin with a "condition" to the left of the `~` and a new species "name" for that condition to the right of the `~`. The `.default=species` at the end will put the name from `species` into `species2` for all situations where none of the conditions above it are met (e.g., if `species` is "Yellow Perch" then `species2` will be "Yellow Perch"). ```{r} +PSDWRtest <- PSDWRtest |> + mutate(species2=case_when( + species=="Bluegill Sunfish" ~ "Bluegill", + species=="Lean Lake Trout" ~ "Lake Trout", + species=="Brown Trout" & location=="Trout Lake" ~ "Brown Trout (lotic)", + species=="Brown Trout" & location=="Brushy Creek" ~ "Brown Trout (lentic)", + species=="Brook Trout" & location=="Trout Lake" ~ "Brook Trout (lotic)", + .default=species + )) +peek(PSDWRtest,n=20) +``` + +The GH length categories are added to this data.frame with `psdAdd()`, specifically noting the use of the new `species2` variable. + +```{r} +PSDWRtest$psd <- psdAdd(len~species2,data=PSDWRtest) +peek(PSDWRtest,n=20) +``` + +Handling these types of "issues" in conjunction with computing relative weights is illustrated in [this companion vignette](https://fishr-core-team.github.io/FSA/articles/Computing_PSDs_and_RelativeWeights.html). + + + +# Computing PSD Summaries +## For One Species from Length Category Variable +PSD summaries for a single species from the GH length category variable will be illustrated with the `YPerchSB1` data.frame created above. + +```{r} +data(YPerchSB1,package="FSAdata") YPerchSB1 <- YPerchSB1 |> mutate(species="Yellow Perch", - ghcats3=psdAdd(tl~species,units="cm")) + ghcats1=psdAdd(tl~species,units="cm")) peek(YPerchSB1,n=10) ``` -The PSD-X metrics can then be computed as before. +A frequency table is used to find the number of individuals in each category. The substock-sized fish are immediately dropped (if they are present). ```{r} -( tmp <- rcumsum(xtabs(~ghcats3,data=YPerchSB1))[-1] ) -round(tmp/tmp["stock"]*100,1) +( tmp <- xtabs(~ghcats1,data=YPerchSB1) ) +( tmp <- tmp[-1] ) ``` -# Using `psdCalc()` to Compute All PSD-X and PSD-X-Y Values for One Species -All of that (in the previous sections) is a bit tedious and, more importantly, does not compute confidence intervals for the values.^[See `psdCI()` for how to compute confidence intervals from the raw data.] `psdCalc()` provides a convenient interface for computing all of the PSD metrics, with confidence intervals, for a data.frame with one species. Before illustrating `psdCalc()`, I returned to the original `YPerchSB1` data.frame without the changes made in the previous sections. +The PSD X-Y (i.e., incremental PSD) values are computed by dividing each value in the frequency table that excludes the sub-stock fish by the sum of that frequency table multiplied by 100, which is easily accomplished with `prop.table()`. ```{r} -#| echo: false -data(YPerchSB1,package="FSAdata") +( tmp <- prop.table(tmp)*100 ) ``` + +Thus, for example, `r round(tmp[["stock"]])`\% of fish that reached stock-size were between stock- and quality-sized (i.e,. "PSD S-Q"). + +The PSD-X (i.e., traditional PSD) values are computed by the reverse cumulative sum (i.e., accumulating from right-to-left) on the `prop.table()` results (and dropping the results for the stock-sized fish which will always be 100). + ```{r} -peek(YPerchSB1,n=6) +( tmp <- rcumsum(tmp)[-1] ) ``` + +So, for example, `r round(tmp[["quality"]],1)`\% of fish that reach stock-size also reached quality-size (i.e., "PSD-Q"). + +## Using `psdCalc()` for One Species +The calculations in the previous section are a bit tedious and, more importantly, do not compute confidence intervals for the values.^[See `psdCI()` for how to compute confidence intervals from the raw data.] `psdCalc()` provides a convenient interface for computing all of the PSD metrics, with confidence intervals, for a data.frame with **one** species. + ```{r} #| echo: false #| results: hide ypres <- psdCalc(~tl,data=YPerchSB1,species="Yellow Perch",units="cm") ``` -`psdCalc()` takes a formula of the form `~length` as the first argument with the appropriate data.frame in `data=`. As with `psdVal()`, `psdCalc()` requires the correctly spelled (and capitalized) species name in `species=` and units in `units=`.^[Again, `units=` defaults to `mm`.] +`psdCalc()` takes a formula of the form `~length` as the first argument with the appropriate data.frame in `data=`. As with `psdVal()`, `psdCalc()` requires the correctly spelled (and capitalized) species name in `species=` and units in `units=`.^[Again, `units=` defaults to `mm`.] Note in the use below that the GH length category variable is not needed (thus, the calculations below do **not** need to follow `psdAdd()`). ```{r} psdCalc(~tl,data=YPerchSB1,species="Yellow Perch",units="cm") @@ -182,17 +309,13 @@ By default, PSD metrics that are 0 are dropped from the results. They can be inc psdCalc(~tl,data=YPerchSB1,species="Yellow Perch",units="cm",drop0Est=FALSE) ``` -The PSD-X (in contrast to PSD X-Y) values are referred to here as "traditional" PSD metrics as they show the percent of stock-sized fish that were also X-sized. For example, PSD-P is the percent of stock-sized fish that also reach preferred-size. In this example, `r ypres["PSD-P","Estimate"]`\% (95%CI: `r ypres["PSD-P","95% LCI"]`\%-`r ypres["PSD-P","95% UCI"]`\%) of stock-sized fish attained preferred size. - -Just the "traditional" metrics may be returned by including `what="traditional"`. +The PSD-X (in contrast to PSD X-Y) values are referred to here as "traditional" PSD metrics as they show the percent of stock-sized fish that were also X-sized. For example, PSD-P is the percent of stock-sized fish that also reached preferred-size. In this example, `r ypres["PSD-P","Estimate"]`\% (95%CI: `r ypres["PSD-P","95% LCI"]`\%-`r ypres["PSD-P","95% UCI"]`\%) of stock-sized fish attained preferred size. Just the "traditional" metrics may be returned by including `what="traditional"`. ```{r} psdCalc(~tl,data=YPerchSB1,species="Yellow Perch",units="cm",what="traditional") ``` -The PSD X-Y values are referred to here as "incremental" PSD metrics as they show the percent of stock-sized fish that were between X- and Y-sized. For example, PSD Q-P is the percent of stock-sized fish that reached quality-size but had not reach preferred-size. In this example, `r ypres["PSD Q-P","Estimate"]`\% (95%CI: `r ypres["PSD Q-P","95% LCI"]`\%-`r ypres["PSD Q-P","95% UCI"]`\%) of stock-sized fish attained quality but not preferred size. - -Just the "incremental" metrics may be returned by including `what="incremental"`. +The PSD X-Y values are referred to here as "incremental" PSD metrics as they show the percent of stock-sized fish that were between X- and Y-sized. For example, PSD Q-P is the percent of stock-sized fish that reached quality-size but had not reach preferred-size. In this example, `r ypres["PSD Q-P","Estimate"]`\% (95%CI: `r ypres["PSD Q-P","95% LCI"]`\%-`r ypres["PSD Q-P","95% UCI"]`\%) of stock-sized fish attained quality but not preferred size. Just the "incremental" metrics may be returned by including `what="incremental"`. ```{r} psdCalc(~tl,data=YPerchSB1,species="Yellow Perch",units="cm",what="incremental") @@ -214,42 +337,17 @@ psdCalc(~tl,data=YPerchSB1,species="Yellow Perch",units="cm", addLens=c("minSlot"=17.5,"maxSlot"=27.5)) ``` -## Using `psdPlot()` to Visualize the PSD Metrics -`psdPlot()` can be used to produce a histogram of lengths with different colors for substock- and stock-size fish, vertical lines depicting the GH length categories, and the "traditional" PSD metrics shown. The basic arguments to `psdPlot()` are the same as those to `psdCalc()`. - -```{r} -#| fig-width: 5 -#| fig-height: 4.5 -psdPlot(~tl,data=YPerchSB1,species="Yellow Perch",units="cm") -``` - -There may be times where the length category lines don't fall on the breaks for the histogram bars. You may be able to ameliorate this issue by changing the width of the breaks with `w=` or where the breaks start with `startcat=`.^[While this was not an issue with these data, this code shows how to make narrower bar widths with `w=`.] - -```{r} -#| fig-width: 5 -#| fig-height: 4.5 -psdPlot(~tl,data=YPerchSB1,species="Yellow Perch",units="cm",w=0.5) -``` - -This plot is meant to be illustrative and not of "publication-quality." However, some aspects of the plot can be modified to make some changes in appearance. See `?psdPlot` for documentation of these other arguments. - -# Adding a Length Category Variable for All Species -The real value of `psdAdd()` is that it can be used to efficiently add length categories for multiple species in a single data.frame. For example, `InchLake2` distributed with `FSAdata` contains lengths for several species captured from Inch Lake. Note that lengths are in **inches** here. +## For Multiple Species from Length Category Variable +PSD-X and PSD X-Y summaries for multiple species requires more work as will be demonstrated below with the `InchLake2` data.frame from previous. Note here that `psdAdd()` is used to add the GH length categories in `ghcats1`. ```{r} data("InchLake2",package="FSAdata") -peek(InchLake2,n=10) -``` - -`psdAdd()` can be used as described previously (i.e., with a formula of the form `length~species` and `units=`) to add GH length categories for all species in the data.frame for which GH length categories exist in `PSDlit`. Note that a message will be issued identifying the species in the data.frame for which GH length categories do not exist. The new variable will be `NA` for these species. - -```{r} InchLake2 <- InchLake2 |> mutate(ghcats1=psdAdd(length~species,units="in")) peek(InchLake2,n=10) ``` -Summaries by species requires some work. First, remove all substock-sized individuals. +First, remove all substock-sized individuals. ```{r} Inch_mod <- InchLake2 |> @@ -257,23 +355,21 @@ Inch_mod <- InchLake2 |> droplevels() ``` -Incremental PSD metrics (i.e, PSD X-Y) are quickly computed with `xtabs()` and `prop.table()`. +Incremental PSD metrics (i.e, PSD X-Y) are then computed with `xtabs()` and `prop.table()`, similar to before except that `margin=1` must be used in `prop.table()` so that the proportions are computed from the row totals. ```{r} -freq <- xtabs(~species+ghcats1,data=Inch_mod) +( freq <- xtabs(~species+ghcats1,data=Inch_mod) ) iPSDs <- prop.table(freq,margin=1)*100 round(iPSDs,1) ``` -Traditional PSD metrics (i.e., PSD-X) can be found by `apply()`ing `rcumsum()`^[This finds reverse cumulative sums; i.e., sums from end-to-start, rather than start-to-end.] to each row (i.e., `MARGIN=1`) of the PSD X-Y values. The result from `apply()` will be oriented opposite of what is desired (i.e., species a columns rather than rows), so it should be `t()`ransposed. +Traditional PSD metrics (i.e., PSD-X) are found by `apply()`ing `rcumsum()`^[This finds reverse cumulative sums; i.e., sums from end-to-start, rather than start-to-end.] to each row (i.e., `MARGIN=1`) of the PSD X-Y values. The result from `apply()` will be oriented opposite of what is desired (i.e., species in columns rather than rows), so it should be transposed with `t()`. ```{r} tPSDs <- t(apply(iPSDs,MARGIN=1,FUN=rcumsum)) round(tPSDs,1) ``` -Additional non-GH length categories can be used with `psdAdd()` through `addLens()` similar to what was described for `psdVal()` and `psdCalc()`. However, a named list must be given to `addLens()` that as named vectors for each species for what an additional length is added. An example for this is given in the documentation for `psdAdd()`. - The use of `psdAdd()` is fairly efficient if interest is only in the point PSD-X or PSD X-Y values. If one needs confidence intervals for these values then it is probably best to use `psdCalc()` on separate data.frames for each species. This is demonstrated below for Yellow Perch and Bluegill from the Inch Lake data. ```{r} @@ -281,9 +377,26 @@ InchYP <- InchLake2 |> filter(species=="Yellow Perch") psdCalc(~length,data=InchYP,species="Yellow Perch",units="in") ``` - ```{r} InchBG <- InchLake2 |> filter(species=="Bluegill") psdCalc(~length,data=InchBG,species="Bluegill",units="in") ``` +## Using `psdPlot()` to Visualize the PSD Metrics +`psdPlot()` can be used to produce a histogram of lengths with different colors for substock- and stock-size fish, vertical lines depicting the GH length categories, and the "traditional" PSD metrics shown. The basic arguments to `psdPlot()` are the same as those to `psdCalc()`. + +```{r} +#| fig-width: 5 +#| fig-height: 4.5 +psdPlot(~tl,data=YPerchSB1,species="Yellow Perch",units="cm") +``` + +There may be times where the length category lines don't fall on the breaks for the histogram bars. You may be able to ameliorate this issue by changing the width of the breaks with `w=` or where the breaks start with `startcat=`.^[While this was not an issue with these data, this code shows how to make narrower bar widths with `w=`.] + +```{r} +#| fig-width: 5 +#| fig-height: 4.5 +psdPlot(~tl,data=YPerchSB1,species="Yellow Perch",units="cm",w=0.5) +``` + +This plot is meant to be illustrative and not of "publication-quality." However, some aspects of the plot can be modified to make some changes in appearance. See `?psdPlot` for documentation of these other arguments. diff --git a/vignettes/articles/Computing_PSDs_and_RelativeWeights.qmd b/vignettes/articles/Computing_PSDs_and_RelativeWeights.qmd new file mode 100644 index 00000000..cadf39be --- /dev/null +++ b/vignettes/articles/Computing_PSDs_and_RelativeWeights.qmd @@ -0,0 +1,87 @@ +--- +title: "Computing PSD and Relative Weight Metrics in FSA" +author: "Derek H. Ogle" +date: "`r Sys.Date()`" +format: + html: + toc: true + toc-depth: 2 + reference-location: margin + fig-cap-location: bottom + tbl-cap-location: top +knitr: + opts_chunk: + collapse: true + comment: '#>' +--- + +# Introduction +Other vignettes introduced using `FSA` to compute [proportional size distribution (PSD)](https://fishr-core-team.github.io/FSA/articles/Computing_PSDs.html) and [relative weight (i.e., condition)](https://fishr-core-team.github.io/FSA/articles/Computing_Relative_Weights.html) metrics. Both of those vignettes mentioned some peculiarities in their methodology related to when PSDs and relative weights were computed concurrently on the same data that contained some "issues." These peculiarities and issues are explained further and how to handle them are illustrated here. I urge you to explore those other vignettes before continuing here. + +The following packages are used herein. Note that the `FSA` functions described here were modified after version 0.9.6 and are thus **specific to FSA >v0.9.6**. + +```{r} +#| label: setup +#| results: hide +#| message: false +library(FSA) +library(dplyr) # mutate, select, filter, case_when +``` + +# Data +The hypothetical `PSDWRtest` data.frame distributed with `FSA` was created to purposely provide data for a variety of species that were realistic but created some issues for the `psdAdd()` and `wrAdd()` functions described in the other vignettes. + +```{r} +peek(PSDWRtest,n=20) +``` + +Ultimately it is best that you have a full understanding of the issues that may arise with your data by carefully examining your data and understanding the Gabelhouse (GH) length categories and relative weight equations for the species in your data. There are several "issues" that need to be addressed with the `PSDWRtest` data. + +First, Bluegill and Lake Trout exist in `PSDlit` and `WSlit` but appear as "Bluegill Sunfish" and "Lean Lake Trout" in `PSDWRtest`. + +Second, Brook Trout were sampled from a lotic ("Trout Lake") system and Brown Trout were sampled from a lotic ("Trout Lake") and a lentic ("Brush Creek") system. There are separate GH length categories and standard weight equations for these sub-groups for each species. + +Third, Muskellunge and Walleye provide a challenge because standard weight equations differ among sub-groups for each of these species, but the GH length categories do not differ among sub-groups. Walleye use separate standard weight equations depending on whether the individual's total length is less than 150 mm or not. Muskellunge have a sex-specific standard weight equation for when sex is known, but an overall equation for when sex is unknown. As will be seen, a new species variable will be created that incorporates the subgroup name into the "species name" for calculating standard weights (as was illustrated in [this vignette](https://fishr-core-team.github.io/FSA/articles/Computing_Relative_Weights.html)). Because the GH length categories don't differ by sub-group for either of these species, these new names are not needed when finding the GH length categories. However, for simplicity (as illustrated further below), these GH length categories have been duplicated for the sub-groups of each species and labelled with the combined species and sub-group name. This is illustrated below for muskellunge. + +```{r} +wsVal("Muskellunge (overall)") # different from next two +wsVal("Muskellunge (female)") +wsVal("Muskellunge (male)") +psdVal("Muskellunge (overall)") # exact same as next two +psdVal("Muskellunge (female)") +psdVal("Muskellunge (male)") +``` + +Fourth, Ruffe for which the reference quantile of the standard weight equation must be specified. + +# Adding GH Length Category and Wr Variables +The easiest way to deal with all of these "issues" except for the one related to Ruffe is to create a new "species" variable (i.e., `species2` below) that appends the specific sub-groups in parentheses to the species name. There are a variety of ways to do this and which way (is best or works) may depend on the specifics of the situation. Here, we use `case_when()` from `dplyr` with a series of statements that begin with a "condition" to the left of the `~` and new species "name" for that condition to the right of the `~`. The `.default=species` at the end puts the name from `species` into `species2` for all situations where none of the conditions above it are met (e.g., if `species` is "Yellow Perch" then `species2` will be "Yellow Perch"). + +```{r} +PSDWRtest <- PSDWRtest |> + mutate(species2=case_when( + species=="Bluegill Sunfish" ~ "Bluegill", + species=="Lean Lake Trout" ~ "Lake Trout", + species=="Brown Trout" & location=="Trout Lake" ~ "Brown Trout (lotic)", + species=="Brown Trout" & location=="Brushy Creek" ~ "Brown Trout (lentic)", + species=="Brook Trout" & location=="Trout Lake" ~ "Brook Trout (lotic)", + species=="Muskellunge" & sex=="M" ~ "Muskellunge (male)", + species=="Muskellunge" & sex=="F" ~ "Muskellunge (female)", + species=="Muskellunge" & sex=="U" ~ "Muskellunge (overall)", + species=="Muskellunge" & is.na(sex) ~ "Muskellunge (overall)", + species=="Walleye" & len>=150 ~ "Walleye (overall)", + species=="Walleye" & len<150 ~ "Walleye (30-149 mm)", + .default=species + )) +peek(PSDWRtest,n=20) +``` + +The GH length categories and relative weights for each fish (for species with standard weight equations) is added to this data.drame with `psdAdd()` and `wrAdd()` as described in the other vignettes, specifically noting the use of the "new" species variable `species2`. Further note the use of `wsOpts=` to define which reference quantile to use for the Ruffe standard weight equation. + +```{r} +PSDWRtest$psd <- psdAdd(len~species2,data=PSDWRtest) +PSDWRtest$wr <- wrAdd(wt~len+species2,data=PSDWRtest, + WsOpts=list(Ruffe=list(ref=75))) +peek(PSDWRtest,n=20) +``` + diff --git a/vignettes/articles/Computing_Relative_Weights.qmd b/vignettes/articles/Computing_Relative_Weights.qmd index 430a5abf..d91f603a 100644 --- a/vignettes/articles/Computing_Relative_Weights.qmd +++ b/vignettes/articles/Computing_Relative_Weights.qmd @@ -29,11 +29,11 @@ The following packages are used herein. Note that the `FSA` functions described #| results: hide #| message: false library(FSA) -library(dplyr) # mutate, select, group_by, summarize +library(dplyr) # mutate, select, group_by, summarize, case_when ``` -# Standard Weight Equations +# Looking Up Standard Weight Equations Equations for computing the standard weight (i.e., $Ws_i$) from an individual fish's observed length (i.e., $L_i$) have been derived for a number of freshwater game fish in the United States, as well as several non-game fish in the United States and some other fish from outside of the United States. The specifics of these equations have been collated into the `WSlit` data.frame^[Specifics [here](https://fishr-core-team.github.io/FSA/reference/WSlit.html).] distributed with `FSA` and are most easily accessed with `wsVal()`. For example, the specifics of the standard weight equation for Bluegill are retrieved below. ```{r} @@ -42,13 +42,13 @@ wsVal("Bluegill") The results returned from `wsVal()` are: -- `species`: species of fish asked for. If left blank then a list of all species for which a standard weight equation exists in `WSlit` will be shown. +- `species`: species of fish asked for. - `group`: the sub-group for the species. Some species have separate standard weight equations for sub-groups (e.g,. `male` or `female`, or `lentic` and `lotic`). If `group` does not appear in the output then there is no sub-group for that species (as illustrated here). The sub-group can be chosen with `group=` in `wsVal()` as demonstrated later.^[Leave `group=` at the default `NULL` for species without sub-group equations.] -- `measure`: the length measure used (will generally be `TL` for total length, but could be `FL` for fork length, `BL` for body length, or `CL` for caudal length depending on the species). -- `units`: the units for which the equation was developed. The default is `metric` which has length in mm and weight in grams. However, `English` can also be used which has lengths in inches and weight in pounds. These are the only two "units" for which the equation can be returned; thus, if you recorded lengths and weights in different units you will need to adjust your data accordingly (or adjust the standard weights computed from the equations (see below) accordingly). -- `ref`: the quantile used when developing the standard weight equation. The 75th percentile is used for most species, but some species have alternatives (50th or 25th percentile). Alternatives for a species can be chosen with `ref=` in `wsVal()`.^[For species with only one possible `ref`, then `ref=` should be left at the default `NULL`.] -- `method`: the method used to develop the standard weight equation. This will usually be `RLP` (regression-line-percentile) or `EmP` (empirical percentile) but is `Other` only for Bluegill, as shown here. Some (very few) species have equations for both methods. In these instances, you will need to choose which to use with `method=` in `wsVal()`.^[For species where only one method is available then leave `method=` at the default `NULL`.] -- `min.TL`: the minimum length for which the standard weight equation is appropriate.^[The postfix after the period will be replaced with the `measure` type ( (here `TL` but for some species `FL`, `BL`, or `CL`)).] +- `measure`: the length measure used (will generally be `TL` for total length, but depending on the species could be `FL` for fork length, `BL` for body length, or `CL` for caudal length). +- `units`: the units for which the equation was developed. The default is `metric` which has length in mm and weight in grams. However, `English` can also be used which has lengths in inches and weight in pounds.^[A few species have an equation for only one set of units.] These are the only two "units" for which the equation can be returned; thus, if you recorded lengths and weights in different units you will need to adjust your data accordingly (or adjust the standard weights computed from the equations (see below) accordingly). +- `ref`: the quantile used when developing the standard weight equation. The 75th percentile is used for most species, but some species have alternatives (50th or 25th percentile).^[Alternatives for a species can be chosen with `ref=` in `wsVal()`. For species with only one possible `ref`, then `ref=` should be left at the default `NULL`.] +- `method`: the method used to develop the standard weight equation. This will usually be `RLP` (regression-line-percentile) or `EmP` (empirical percentile) but is `Other` only for Bluegill, as shown here. Some (very few) species have equations for both methods.^[For species with multiple `method`s, you will need to choose which to use with `method=` in `wsVal()`. For species where only one method is available then leave `method=` at the default `NULL`.] +- `min.TL`: the minimum length for which the standard weight equation is appropriate.^[The postfix after the period will be replaced with the `measure` type (here `TL` but for some species `FL`, `BL`, or `CL`).] - `max.TL`: the maximum length for which the standard weight equation is appropriate. Maximum lengths have not been specified for all species and, thus, may not appear in all outputs (e.g., for Bluegill here). - `int`: the intercept, **on the common logarithm (i.e., log10) scale**, for the standard weight equation. - `slope`: the slope, **on the log10 scale**, for the standard weight equation. @@ -68,7 +68,7 @@ Blue Sucker is an example where some of the "optional" values are returned (e.g. wsVal("Blue Sucker",units="English") ``` -Use of `wsVal()` requires spelling (and capitalizing) the name as it appears in `WSlit`. One can see all species names available in `WSlit` with `wsVal()` without any arguments. +Use of `wsVal()` requires spelling (and capitalizing) the species name as it appears in `WSlit`. One can see all species names available in `WSlit` with `wsVal()` without any arguments. ```{r} wsVal() @@ -82,7 +82,7 @@ wsVal("Blue sucker") wsVal("Blue suckr") ``` -It is also not always obvious whether a species has equations for sub-groups or not.^[But see @tbl-species_issues.] One way to deal with this is to just ask for the equation for your species of interest without using `group=`. If sub-groups exist then you will get an error message asking you to choose which sub-group to use. +It is also not always obvious whether a species has equations for sub-groups or not. One way to deal with this is to just ask for the equation for your species of interest without using `group=`. If sub-groups exist then you will get an error message asking you to choose which sub-group to use. ```{r} #| error: true @@ -95,7 +95,13 @@ Then try again by choosing the sub-group with `group=`. wsVal("Brown Trout",group="lentic") ``` -The same general process can be used for species that have equations developed from multiple methods. +These same species and sub-group combinations can be also accessed by combining the species name and sub-group name (in parenthesis) into the first argument (and then not using `group=`). + +```{r} +wsVal("Brown Trout (lotic)") +``` + +The same general process can be used for species that have equations developed from multiple methods; though, only the sub-group identifiers can be combined (with parentheses) in the species name and used in the first argument. ```{r} #| error: true @@ -111,41 +117,33 @@ wsVal("Ruffe") wsVal("Ruffe",ref=50) ``` -## Cautions -@tbl-species_issues shows species for which multiple standard weight equations exist in `WSlit` such that the specific one must be chosen by using `group=`, `method=`, or `ref=` in `wsVal()`. +There are two species (Chinook Salmon and Striped Bass) that appear to have sub-groups (i.e., "landlocked") but only that one specific sub-group appears in `WSlit`. The standard weight literature for these species did not identify the equation as only being for "landlocked" populations. However, these entries were added to facilitate use when calculating proportional size distribution (PSD) metrics,^[See [this vignette](https://fishr-core-team.github.io/FSA/articles/Computing_PSDs.html).] which were defined just for "landlocked" populations, and relative weight metrics with the same data.frame.^[As illustrated in [this companion vignette](https://fishr-core-team.github.io/FSA/articles/Computing_PSDs_and_RelativeWeights.html).] The standard weight equations for these species can be accessed by either just the species name or the species name with the group in parentheses. However, note that they are the exact same information. +```{r} +wsVal("Striped Bass") +wsVal("Striped Bass (landlocked)") +``` -| Species | Cause of Multiple Equations | -|:-----|:--------------------| -| Arctic Grayling | Multiple `method`s exist | -| Bigmouth Sleepers | Sub-`group`s exist; multiple `ref`erence values | -| Brook Trout | Sub-`group`s exist | -| Brown Trout | Sub-`group`s exist | -| Cutthroat Trout | Sub-`group`s exist | -| Mountain Mullet | Multiple `ref`erence values | -| Muskellunge | Sub-`group`s exist | -| Paddlefish | Sub-`group`s exist | -| Rainbow Trout | Sub-`group`s exist | -| River Goby | Multiple `ref`erence values | -| Ruffe | Multiple `ref`erence values | -| Sardine | Multiple `ref`erence values | -| Spotted Bass | Sub-`group`s exist | -| Walleye | Sub-`group`s exist | +There are also a few species where an original standard weight equation has been revised in the literature. The original and revised equations are available in `WSlit` with the revised equations accessed by just using the species name and the original equations accessed by appending "(original)" to the species name. -: Species for which the user will have to select among multiple standard weight equations by using `group=`, `method=`, or `ref=` in `wsVal()`. {#tbl-species_issues} +```{r} +wsVal("Spotted Bass") # revised definitions +wsVal("Spotted Bass (original)") +``` +We strongly urge you to have a good understanding of the standard weight literature for your species' of interest and make sure that `wsVal()` is returning the values that you expect. # Calculate Individual Relative Weight -## Example with Linear Equation -The specifics of the standard weight equation returned by `wsVal()` can be used to compute the standard weight for a fish given its observed length. As an example, suppose that the relative weight of a Largemouth Bass with an observed length and weight of 350 mm and 650 g is desired. +## For Typical Linear Equation +The specifics of the standard weight equation returned by `wsVal()` can be used to compute the standard weight for a fish given its observed length. As an example, suppose that the relative weight of a Largemouth Bass with an observed length of 350 mm and weight of 650 g is desired. Begin by assigning the specifics of the standard weight equation for Largemouth Bass returned by `wsVal()` to an object (e.g., `wsLMB` here). ```{r} -wsLMB <- wsVal("Largemouth Bass") +( wsLMB <- wsVal("Largemouth Bass") ) ``` -The intercept and slope for the standard weight equation on the **log10-log10** scale can be extracted from this object. +The intercept and slope for the standard weight equation on the **log10-log10** scale can be extracted from this object.^[The double-brackets (i.e., `[[]]`) are used to remove the name (e.g., `int`) from the returned value.] ```{r} wsLMB[["int"]] @@ -158,16 +156,16 @@ The standard weight is then computed from these results and the **log10-transfor ( ex1 <- 10^(wsLMB[["int"]]+wsLMB[["slope"]]*log10(350)) ) ``` -This calculation suggests that standard weight for a 250 mm Largemouth Bass is `r formatC(ex1,format="f",digits=1)` g. With this and @eq-Wri, the relative weight for this individual can be computed (recalling that the observed weight was 650 g). +This calculation suggests that the standard weight for a 350 mm Largemouth Bass is `r formatC(ex1,format="f",digits=1)` g. With this and @eq-Wri, the relative weight for this individual is computed (recalling that the observed weight was 650 g). ```{r} 100*650/ex1 ``` -This indicates that the individual is heavier than a standard fish of the same length as this values is greater than 100. +This indicates that the individual is (slightly) heavier than a "standard fish" of the same length as this values is greater than 100. -## Example with Quadratic Equation -A similar process can be followed for species where the standard weight equation includes a quadratic term. The only "trick" here is to include the quadratic term multiplied by the **square** of the log10-transformed observed length when computing the standard weight. This calculation is illustrated below with a 500 mm and 1010 g Blue Sucker. +## For Quadratic Equation +A similar process can be followed for a species where the standard weight equation includes a quadratic term. The only "trick" here is to include the quadratic term multiplied by the **square** of the log10-transformed observed length when computing the standard weight. This calculation is illustrated below with a 500 mm and 1010 g Blue Sucker. ```{r} ( wsBS <- wsVal("Blue Sucker",simplify=TRUE) ) @@ -186,24 +184,21 @@ A few things to consider when calculating relative weights for individuals. # Calculate Relative Weights for All of One Species It is not common to compute the standard and relative weights for a single individual as was done in the previous section. Rather, it is more useful to calculate these values for all individuals in a sample, and then summarize those values for an overall assessment of the condition of those individuals. -Consider the `CiscoTL` data.frame distributed with the `FSAdata` package that contains the lengths (mm) and weights (g) of Cisco (*Coregonus artedii*) sampled from Trout Lake, WI, USA over a 25 year period. +Consider the `CiscoTL` data.frame distributed with the `FSAdata` package that contains the lengths (mm) and weights (g) of Cisco (*Coregonus artedii*) sampled from Trout Lake, WI, USA over a 25 year period. Note that there are many missing weights in this data.frame. ```{r} -data("CiscoTL",package="FSAdata") -str(CiscoTL) +data("CiscoTL",package="FSAdata") # retrieve the data.frame peek(CiscoTL,n=10) ``` -Note that there are lots of missing weights in this data.frame. - ## "Manual" Calculations -The relative weight calculation begins by finding the specifics of the standard weight equation for Cisco. +The relative weight calculation begins by finding the specifics of the standard weight equation for Cisco and assigning them to an object (here, `wsC`). ```{r} ( wsC <- wsVal("Cisco") ) ``` -Two new variables -- `Ws` for standard weight and `Wr` for relative weight -- are added to the data.frame in three steps below. First, `Ws` is calculated using the coefficients from the standard weight equation and the log-transformed length variable as shown above (but within `mutate()` from `dplyr`). Second, if the observed length is less than the minimum length for which the standard weight equation should be applied, then the previously calculated `Ws` is replaced with an `NA` (for missing value). Finally, the relative weight is computed from the observed weight and standard weight variables using @eq-Wri. +Two new variables -- `Ws` for standard weight and `Wr` for relative weight -- are added to the data.frame in three steps below. First, `Ws` is calculated using the coefficients from the standard weight equation and the log-transformed length variable as shown above (but within `mutate()` from `dplyr`). Second, if the observed length is less than the minimum length for which the standard weight equation should be applied, then the previously calculated `Ws` is replaced with an `NA` (for missing value).^[These two steps could have been combined by replacing `Ws` with the calculation in `ifelse()`.] Finally, the relative weight is computed from the observed weight and standard weight variables using @eq-Wri. ```{r} CiscoTL <- CiscoTL |> @@ -213,38 +208,30 @@ CiscoTL <- CiscoTL |> peek(CiscoTL,n=10) ``` -As an illustration, the mean and standard deviation of relative weights are computed below (along with `validn` which is the number of non-`NA` (i.e., non-missing) relative weights).^[More interesting summaries and plots may be constructed with these data. This is just an example of summarizing relative weights for a sample.] These results suggest that this population of Cisco is substantially "skinnier" (i.e., under-weight) than the standard for the species (because the mean relative weight is substantially less than 100). - -```{r} -CiscoTL |> - summarize(validn=sum(!is.na(Wr)), - mnWr=mean(Wr,na.rm=TRUE), - sdWr=sd(Wr,na.rm=TRUE)) -``` - ## Using the `WrAdd()` Convenience Function -`wrAdd()` can be used to add a relative weight variable to a data.frame for **all** species in the data.frame for which a standard weight equation exists. The main argument to `wrAdd()` is a formula of the form `weight~length+species` where `weight` is the observed weight variable, `length` is the observed length variable, and `species` is the name of the species variable. One constraint here is that the species must be spelled (and capitalized) as in `WSlit`. In these data for Cisco, the species name is in `spname` but the species is all capital letters as "CISCO", rather than the required "Cisco". `capFirst()`^[From `FSA`.] may be used to convert a word to a form where just the first letter is capitalized, and is used below.^[Note that the `CiscoTL` data.frame was re-read so that the additions in the previous section were removed.] +`wrAdd()` can be used to add a relative weight variable to a data.frame for **all** species in the data.frame for which a standard weight equation exists.^[Though its use is illustrated here on a data.frame with only one species. See the next sections for an example with more species.] The main argument to `wrAdd()` is a formula of the form `weight~length+species` where `weight` is the name of the observed weight variable, `length` is the name of the observed length variable, and `species` is the name of the species variable. One constraint here is that the species names in the `species` variable must be spelled (and capitalized) exactly as in `WSlit`. In these data, the species name is in `spname` but is in all capital letters as "CISCO", rather than the required "Cisco". `capFirst()`^[From `FSA`.] may be used to convert a word to a form where just the first letter is capitalized, and is used below.^[Note that the `CiscoTL` data.frame was re-read so that the additions in the previous section were removed.] ```{r} -#| echo: false data("CiscoTL",package="FSAdata") -``` -```{r} CiscoTL <- CiscoTL |> mutate(Wr=wrAdd(weight~length+capFirst(spname))) peek(CiscoTL,n=10) ``` -`wrAdd()` deals with species that have more than one standard weight equation^[As illustrated previuosly.] with `WsOpts=`. For example, consider adding a relative weight variable to the `RuffeSLRH92` data.frame distributed with `FSAdata`. +A more general approach to deal with species that are spelled differently than expected in `WSlit` is to provide a named list or vector that defines how the original species names (i.e., the items in the vector to the right of the `=`) relate to the species names required by `WSlit` (i.e., the names in the vector to the left of the `=`) to `thesaurus=`. `wrAdd()` will match the two names appropriately while creating the relative weight variable. ```{r} -data("RuffeSLRH92",package="FSAdata") -str(RuffeSLRH92) +CiscoTL <- CiscoTL |> + mutate(Wr2=wrAdd(weight~length+spname,thesaurus=c("Cisco"="CISCO"))) +peek(CiscoTL,n=10) ``` -Note that there is no species variable, which is needed by `wrAdd()`.^[Note that `wrAdd()` is more convenient for data.frames with multiple species as will be illustrated in the next section.] Additionally, for simplicity of presentation, I removed several other variables that are not needed for this example. +`thesaurus=` can be used even if only some of the species names are non-"standard." Additionally, the named list/vector in `thesaurus=` can contain names that don't exist in the original data.frame. Thus, a global thesaurus containing all species that *could* be encountered could be created, for example as an agency-wide definition, and used with a variety of specific data.frames. + +`wrAdd()` handles species that have more than one standard weight equation^[As described previously.] with `WsOpts=`. For example, consider adding a relative weight variable to the `RuffeSLRH92` data.frame distributed with `FSAdata`. Note that there is no species variable, which is needed by `wrAdd()`, so one was added with `mutate()`.^[Note that `wrAdd()` is more convenient for data.frames with multiple species as will be illustrated in the next section.] Additionally, for simplicity of presentation, I removed several other variables (with `select()`) that are not needed for this example. ```{r} +data("RuffeSLRH92",package="FSAdata") # retrieve the data.frame RuffeSLRH92 <- RuffeSLRH92 |> mutate(species="Ruffe") |> select(species,length,weight,sex) @@ -268,29 +255,116 @@ peek(RuffeSLRH92,n=10) ``` # Calculate Relative Weights for All of Multiple Species -The real value of `wrAdd()` is that it can be used to efficiently add a relative weight variable for multiple species in a single data.frame. For example, `InchLake2` distributed with `FSAdata` contains lengths and weights for several species captured from Inch Lake. +The real value of `wrAdd()` is that it can be used to efficiently add a relative weight variable for multiple species in a single data.frame. This is illustrated below for a variety of scenarios. + +## "Good" Names and No Groups +`InchLake2` distributed with `FSAdata` contains lengths and weights for several species captured from Inch Lake. These data provide a simple example for using `wrAdd()` because all species names are spelled as required and none of the species have sub-groups.^[See the next section for how to deal with these issues.] ```{r} -data("InchLake2",package="FSAdata") +data("InchLake2",package="FSAdata") # retrieve the data.frame peek(InchLake2,n=10) ``` -One oddity of these data is that length was recorded in inches, whereas weight was recorded in grams. The standard weight equations either use inches and pounds or millimeters and grams. In this case, I converted the inches to mm first, and then added the relative weight variable with `wrAdd()` as before. +A complication here is that length and weight are in "mixed" units; i.e., inches for length and grams for weight. One or the other must be converted to the same unit type. Below length is converted to mm before `wrAdd()` is used to add a relative weight variable. ```{r} InchLake2 <- InchLake2 |> - mutate(lenmm=length*25.4, - Wr=wrAdd(weight~lenmm+species)) + mutate(length=length*25.4, + Wr=wrAdd(weight~length+species)) +peek(InchLake2,n=10) +``` + +Note that species without known standard weight equations in `WSlit` (e.g., Bluntnose Minnow) will have `NA` for the relative weight variable, as will individuals with lengths outside the range of lengths for which the standard weight equation should be applied. + +## "Bad" Names and No Groups +Now consider the `BGHRfish` data.frame (distributed with the `FSAdata` package) that has the lengths (mm) and weights (g) of three species -- Smallmouth Bass, Largemouth Bass, and Bluegill -- from Big Hill Reservoir, KS. These three species do not have sub-groups defined in `WSlit`, but upon observing the data below^[And [the documentation](https://fishr-core-team.github.io/FSAdata/reference/Herman.html).] it is seen that the species variable (`specCode`) contains codes for the species names rather than the names required by `PSDlit`. + +```{r} +data(BGHRfish,package="FSAdata") # retrieve the data.frame +peek(BGHRfish,n=10) +``` + +One way to deal with the issue of "bad" species names is to use a named list or vector that defines how the names from `WSlit` should be matched to the names in the data.frame. For this purpose, the species names in `WSlit` are the names in the vector (i.e., before the `=`) and the species names in the data.frame are the items in the vector (i.e., after the `=`).^[The numeric species codes are in parentheses as `specCode` will be converted to a string before using `wrAdd()`.] + +```{r} +thes <- c("Smallmouth Bass"="116","Largemouth Bass"="118","Bluegill"="122") +``` + +This list/vector is then given to `thesaurus=` in `wrAdd()` which will perform the name matching while creating the GH length categories. However, one complicating factor with these data is that `wrAdd()` expects a string in `species` (and, thus, `thesaurus=`) rather than a numeric like `specCode`. Thus, `specCode` is converted to a character below before using `wrAdd()`. + +```{r} +BGHRfish <- BGHRfish |> + mutate(specCode=as.character(specCode), + Wr=wrAdd(weight~length+specCode,thesaurus=thes)) +peek(BGHRfish,n=10) +``` + +## "Bad" Names, Groups, and Multiple Equations +The use of `wrAdd()` can become complicated for data.frames with species names other than what `WSlit` expects, with species for which standard weight equations exist for sub-groups, especially if more than one sub-group is in the data, and for species with multiple standard weight equations. The hypothetical data set `PSDWRtest` distributed with `FSA` can be used to illustrate how to handle these "issues". + +```{r} +peek(PSDWRtest,n=20) +``` + +`wrAdd()` will produce some informative error messages, but it is best that you have a full understanding of the issues that may arise with your data by carefully examining your data and understanding the standard weight (and Gabelhouse length categories) for the species in your data. The "issues" that need to be addressed with the `PSDWRtest` data are as follows: + + - "Bluegill Sunfish" was used rather than "Bluegill". + - "Lean Lake Trout" was used rather than "Lake Trout". + - Brook Trout sampled from a lotic ("Trout Lake") system, for which there are standard weight equations for sub-groups. + - Brown Trout sampled from a lotic ("Trout Lake") and lentic ("Brush Creek") system, for which there are standard weight equations for sub-groups. + - Muskellunge for which sex is known for some and not for others, and there is a desire to use the sex-specific standard weight equation when sex is known (and use the overall equation when it is not). + - Walleye of sizes for which separate standard weight equations may be used. + - Ruffe for which the reference quantile of the standard weight equation must be specified. + +The easiest way to deal with most of these "issues" is to create a new "species" variable (i.e., `species2` below) that appends the specific groups in parentheses to the species name. There are a variety of ways to do this and which way (is best or works) may depend on the specifics of the situation. Here, we primarily use `case_when()` from `dplyr` with a series of statements that begin with a "condition" to the left of the `~` and new species "name" for that condition to the right of the `~`. The `.default=species` at the end puts the name from `species` into `species2` for all situations where none of the conditions above it are met (e.g., if `species` is "Yellow Perch" then `species2` will be "Yellow Perch"). + +```{r} +PSDWRtest <- PSDWRtest |> + mutate(species2=case_when( + species=="Bluegill Sunfish" ~ "Bluegill", + species=="Lean Lake Trout" ~ "Lake Trout", + species=="Brown Trout" & location=="Trout Lake" ~ "Brown Trout (lotic)", + species=="Brown Trout" & location=="Brushy Creek" ~ "Brown Trout (lentic)", + species=="Brook Trout" & location=="Trout Lake" ~ "Brook Trout (lotic)", + species=="Muskellunge" & sex=="M" ~ "Muskellunge (male)", + species=="Muskellunge" & sex=="F" ~ "Muskellunge (female)", + species=="Muskellunge" & sex=="U" ~ "Muskellunge (overall)", + species=="Muskellunge" & is.na(sex) ~ "Muskellunge (overall)", + species=="Walleye" & len>=150 ~ "Walleye (overall)", + species=="Walleye" & len<150 ~ "Walleye (30-149 mm)", + .default=species + )) +peek(PSDWRtest,n=20) +``` + +The relative weights for each fish (for species with standard weight equations) is added to this data.drame with `wrAdd()` as described above, noting the use of the "new" species variable `species2`. Further note the use of `wsOpts=` to define which reference quantile to use for the Ruffe standard weight equation. + +```{r} +PSDWRtest$wr <- wrAdd(wt~len+species2,data=PSDWRtest, + WsOpts=list(Ruffe=list(ref=75))) +peek(PSDWRtest,n=20) ``` -The mean and sd of relative weight by species is shown below. It is important to carefully examine these results because a species could have no mean relative weight calculated because there is no standard weight equation for that species (in `WSlit`) or because the species name is not spelled as expected (in `WSlit`). The four species with no mean relative weight below all do, indeed, not have a known standard weight equation. + +# Summarizing Relative Weights +## Single Species +As an illustration, the mean and standard deviation of relative weights for Cisco (in `CiscoTL` from above) are computed below (along with `validn` which is the number of non-`NA` (i.e., non-missing) relative weights).^[More interesting summaries and plots may be constructed with these data. This is just an example of summarizing relative weights for a sample.] These results suggest that this population of Cisco is substantially "skinnier" (i.e., under-weight) than the standard for the species (because the mean relative weight is substantially less than 100). ```{r} -InchLake2 |> - group_by(species) |> +CiscoTL |> summarize(validn=sum(!is.na(Wr)), mnWr=mean(Wr,na.rm=TRUE), - sdWr=sd(Wr,na.rm=TRUE)) |> - as.data.frame() + sdWr=sd(Wr,na.rm=TRUE)) ``` +## Multiple Species +The mean and sd of relative weight for all species in `PSDWRtest` from above is shown below. It is important to carefully examine these results because a species could have no mean relative weight calculated because there is no standard weight equation for that species (in `WSlit`) or because the species name is not spelled as expected (in `WSlit`). The only species below with no mean relative weight (i.e., Iowa Darter) does, indeed, not have a known standard weight equation. + +```{r} +PSDWRtest |> + group_by(species,location) |> + summarize(validn=sum(!is.na(wr)), + mnWr=mean(wr,na.rm=TRUE), + sdWr=sd(wr,na.rm=TRUE)) |> + as.data.frame() +```