Nothing
########################################################################
# strata methods definitions.
#
# Zhian Kamvar, March 2015
# kamvarz@science.oregonstate.edu
########################################################################
#==============================================================================#
#==============================================================================#
# Workhorse functions for strata methods. These avoids needless copying and
# pasting of code to dispatch the methods to two unrelated classes
# (genind and genlight).
#==============================================================================#
#==============================================================================#
.getStrata <- function(x, formula = NULL, combine = TRUE, call = match.call()){
if (is.null(x@strata)) return(NULL)
if (is.null(formula)) return(x@strata)
vars <- all.vars(formula)
if (any(!vars %in% names(x@strata))){
stop(.strata_incompatible_warning(vars, x@strata), call. = FALSE)
}
if (combine){
strata <- .make_strata(formula, x@strata)
} else {
strata <- x@strata[all.vars(formula)]
}
invisible(return(strata))
}
.setStrata <- function(x, value, call = match.call()){
if (is.null(value)){
x@strata <- value
return(x)
}
if (!inherits(value, "data.frame")){
callval <- as.character(call["value"])
stop(paste(callval, "is not a data frame"), call. = FALSE)
}
if (nrow(value) != nInd(x)){
stop("Number of rows in data frame not equal to number of individuals in object.", call. = FALSE)
}
value <- data.frame(lapply(value, function(f) factor(f, unique(f))))
x@strata <- value
return(x)
}
.nameStrata <- function(x, value, call = match.call()){
if (missing(value)){
return(names(x@strata))
}
if (is.null(x@strata)){
warning("Cannot name an empty strata", call. = FALSE)
return(x)
}
if (is.language(value)){
value <- all.vars(value)
}
if (!is.vector(value) | length(value) != length(x@strata)){
stop(paste("nameStrata needs a vector argument of length", length(x@strata)), call. = FALSE)
}
names(x@strata) <- value
return(x)
}
.splitStrata <- function(x, value, sep = "_", call = match.call()){
if (is.null(x@strata)){
warning("Cannot split empty strata", call. = FALSE)
return(x)
}
if (is.language(value)){
# valterms <- attr(terms(value), "term.labels")
# valterms <- valterms[length(valterms)]
# valterms <- gsub(":", sep, valterms)
value <- all.vars(value)
} else {
stop("Value must be a formula.", call. = FALSE)
}
if (length(value) < 1){
stop("Value must have more than one level.", call. = FALSE)
}
strata <- x@strata
if (length(strata) > 1){
warning("Strata must be length 1. Taking the first column.", call. = FALSE)
strata <- strata[1]
}
seps <- gregexpr(sep, strata[[1]])
sepmatch <- vapply(seps, function(val) all(as.integer(val) > 0), logical(1))
seps <- vapply(seps, length, numeric(1))
all_seps_match <- all(sepmatch)
given_seps <- length(value) - 1
if (!all_seps_match | all(seps != given_seps)){
seps <- ifelse(all_seps_match, seps[1], 0) + 1
msg1 <- paste("\n Data has", seps, ifelse(seps == 1, "level", "levels"),
"of strata with the separator", sep, ".")
msg2 <- paste("Here is the fist column of the data:", strata[1, ])
stop(paste(msg1, "\n ", msg2), call. = FALSE)
}
x@strata <- colsplit(as.character(strata[[1]]), pattern = sep, value)
x@strata <- data.frame(lapply(x@strata, function(f) factor(f, levels = unique(f))))
# names(strata) <- value
# x@strata <- strata
return(x)
}
.addStrata <- function(x, value, name = "NEW", call = match.call()){
if (is.null(x@strata)){
strata <- data.frame(vector(mode = "character", length = nInd(x)))
wasNULL <- TRUE
} else {
strata <- x@strata
wasNULL <- FALSE
}
if ((is.vector(value) | is.factor(value)) & length(value) == nrow(strata)){
value <- factor(value, levels = unique(value))
NEW <- data.frame(value)
names(NEW) <- name
strata <- cbind(strata, NEW)
} else if (is.data.frame(value) && nrow(value) == nrow(strata)){
value <- data.frame(lapply(value, function(f) factor(f, unique(f))))
strata <- cbind(strata, value)
} else if (is.data.frame(value)){
callval <- as.character(call["value"])
msg <- .not_enough_rows_warning(callval, nrow(value), nrow(strata))
stop(msg, call. = FALSE)
} else {
stop("value must be a vector or data frame.", call. = FALSE)
}
if (wasNULL){
strata <- strata[-1, , drop = FALSE]
}
x@strata <- strata
return(x)
}
.setPop <- function(x, formula = NULL, call = match.call()){
if (is.null(x@strata)){
warning("Cannot set the population from an empty strata", call. = FALSE)
return(x)
}
if (is.null(formula) | !is.language(formula)){
callform <- as.character(call["formula"])
stop(paste(callform, "must be a valid formula object."), call. = FALSE)
}
vars <- all.vars(formula)
if (!all(vars %in% names(x@strata))){
stop(.strata_incompatible_warning(vars, x@strata), call. = FALSE)
}
pop(x) <- .make_strata(formula, x@strata)[[length(vars)]]
return(x)
}
#==============================================================================#
#==============================================================================#
# Formal methods definitions and documentation.
#==============================================================================#
#==============================================================================#
#==============================================================================#
#' Access and manipulate the population strata for genind or genlight objects.
#'
#' The following methods allow the user to quickly change the strata of a genind
#' or genlight object.
#'
#' @export
#' @rdname strata-methods
#' @aliases strata,genind-method strata,genlight-method
#' @param x a genind or genlight object
#' @param formula a nested formula indicating the order of the population
#' strata.
#' @param combine if \code{TRUE} (default), the levels will be combined according to the
#' formula argument. If it is \code{FALSE}, the levels will not be combined.
#' @param value a data frame OR vector OR formula (see details).
#' @docType methods
#'
#' @details \subsection{Function Specifics}{ \itemize{ \item \strong{strata()} -
#' Use this function to view or define population stratification of a
#' \linkS4class{genind} or \linkS4class{genlight} object. \item
#' \strong{nameStrata()} - View or rename the different levels of strata.
#' \item \strong{splitStrata()} - Split strata that are combined with a common
#' separator. This function should only be used once during a workflow.
#' \itemize{ \item \emph{Rationale:} It is often difficult to import files
#' with several levels of strata as most data formats do not allow unlimited
#' population levels. This is circumvented by collapsing all population strata
#' into a single population factor with a common separator for each
#' observation. } \item \strong{addStrata()} - Add levels to your population
#' strata. This is ideal for adding groups defined by
#' \code{\link{find.clusters}}. You can input a data frame or a vector, but if
#' you put in a vector, you have the option to name it. }}
#'
#' \subsection{Argument Specifics}{
#'
#' These functions allow the user to seamlessly carry all possible population
#' stratification with their \linkS4class{genind} or \linkS4class{genlight}
#' object. Note that there are two ways of performing all methods: \itemize{
#' \item modifying: \code{strata(myData) <- myStrata} \item preserving:
#' \code{myNewData <- strata(myData, value = myStrata)} } They essentially do
#' the same thing except that the modifying assignment method (the one with
#' the "\code{<-}") will modify the object in place whereas the non-assignment
#' method will preserve the original object (unless you overwrite it). Due to
#' convention, everything right of the assignment is termed \code{value}. To
#' avoid confusion, here is a guide to the argument \strong{\code{value}} for
#' each function: \itemize{ \item \strong{strata()} \code{value = }a
#' \code{\link{data.frame}} that defines the strata for each individual in the
#' rows. \item \strong{nameStrata()} \code{value = }a \code{\link{vector}} or
#' a \code{\link{formula}} that will define the names. \item
#' \strong{splitStrata()} \code{value = }a \code{\link{formula}} argument with
#' the same number of levels as the strata you wish to split. \item
#' \strong{addStrata()} \code{value = }a \code{\link{vector}} or
#' \code{\link{data.frame}} with the same length as the number of individuals
#' in your data. }}
#'
#' \subsection{Details on Formulas}{
#'
#' The preferred use of these functions is with a \code{\link{formula}}
#' object. Specifically, a hierarchical formula argument is used to assign the
#' levels of the strata. An example of a hierarchical formula would
#' be:\tabular{r}{ \code{~Country/City/Neighborhood}} This convention was
#' chosen as it becomes easier to type and makes intuitive sense when defining
#' a \code{\link{hierarchy}}. Note: it is important to use hiearchical
#' formulas when specifying hierarchies as other types of formulas (eg.
#' \code{~Country*City*Neighborhood}) will give incorrect results.}
#'
#' @seealso \code{\link{setPop}} \code{\link{genind}}
#' \code{\link{as.genind}}
#'
#' @author Zhian N. Kamvar
#' @examples
#' # let's look at the microbov data set:
#' data(microbov)
#' microbov
#'
#' # We see that we have three vectors of different names in the 'other' slot.
#' # ?microbov
#' # These are Country, Breed, and Species
#' names(other(microbov))
#'
#' # Let's set the strata
#' strata(microbov) <- data.frame(other(microbov))
#' microbov
#'
#' # And change the names so we know what they are
#' nameStrata(microbov) <- ~Country/Breed/Species
#'
#' \dontrun{
#' # let's see what the strata looks like by Species and Breed:
#' head(strata(microbov, ~Breed/Species))
#'
#' # If we didn't want the last column combined with the first, we can set
#' # combine = FALSE
#' head(strata(microbov, ~Breed/Species, combine = FALSE))
#'
#' #### USING splitStrata ####
#'
#' # For the sake of example, we'll imagine that we have imported our data set
#' # with all of the stratifications combined.
#' setPop(microbov) <- ~Country/Breed/Species
#' strata(microbov) <- NULL
#'
#' # This is what our data would look like after import.
#' microbov
#'
#' # To set our strata here, we need to use the functions strata and splitStrata
#' strata(microbov) <- data.frame(x = pop(microbov))
#' microbov # shows us that we have "one" level of stratification
#' head(strata(microbov)) # all strata are separated by "_"
#'
#' splitStrata(microbov) <- ~Country/Breed/Species
#' microbov # Now we have all of our strata named and split
#' head(strata(microbov)) # all strata are appropriately named and split.
#' }
#==============================================================================#
strata <- function(x, formula = NULL, combine = TRUE, value){
standardGeneric("strata")
}
#' @export
setGeneric("strata")
setMethod(
f = "strata",
signature(x = "genind"),
definition = function(x, formula = NULL, combine = TRUE, value){
theCall <- match.call()
if (missing(value)){
.getStrata(x, formula = formula, combine = combine, theCall)
} else {
.setStrata(x, value, theCall)
}
})
setMethod(
f = "strata",
signature(x = "genlight"),
definition = function(x, formula = NULL, combine = TRUE, value){
theCall <- match.call()
if (missing(value)){
.getStrata(x, formula = formula, combine = combine, theCall)
} else {
.setStrata(x, value, theCall)
}
})
#==============================================================================#
#' @export
#' @rdname strata-methods
#' @aliases strata<-,genind-method strata<-,genlight-method
#' @docType methods
#==============================================================================#
"strata<-" <- function(x, value){
standardGeneric("strata<-")
}
#' @export
setGeneric("strata<-")
setMethod(
f = "strata<-",
signature(x = "genind"),
definition = function(x, value){
theCall <- match.call()
return(.setStrata(x, value, theCall))
})
setMethod(
f = "strata<-",
signature(x = "genlight"),
definition = function(x, value){
theCall <- match.call()
return(.setStrata(x, value, theCall))
})
#==============================================================================#
#' @export
#' @rdname strata-methods
#' @aliases nameStrata,genind-method nameStrata,genlight-method
#' @docType methods
#==============================================================================#
nameStrata <- function(x, value){
standardGeneric("nameStrata")
}
#' @export
setGeneric("nameStrata")
setMethod(
f = "nameStrata",
signature(x = "genind"),
definition = function(x, value){
.nameStrata(x, value)
})
setMethod(
f = "nameStrata",
signature(x = "genlight"),
definition = function(x, value){
.nameStrata(x, value)
})
#==============================================================================#
#' @export
#' @rdname strata-methods
#' @aliases nameStrata<-,genind-method nameStrata<-,genlight-method
#' @docType methods
#==============================================================================#
"nameStrata<-" <- function(x, value){
standardGeneric("nameStrata<-")
}
#' @export
setGeneric("nameStrata<-")
setMethod(
f = "nameStrata<-",
signature(x = "genind"),
definition = function(x, value){
return(nameStrata(x, value))
})
setMethod(
f = "nameStrata<-",
signature(x = "genlight"),
definition = function(x, value){
return(nameStrata(x, value))
})
#==============================================================================#
#' @export
#' @rdname strata-methods
#' @aliases splitStrata,genind-method splitStrata,genlight-method
#' @docType methods
#' @param sep a \code{character} indicating the character used to separate
#' hierarchical levels. This defaults to "_".
#' @importFrom reshape2 colsplit
#==============================================================================#
splitStrata <- function(x, value, sep = "_"){
standardGeneric("splitStrata")
}
#' @export
setGeneric("splitStrata")
setMethod(
f = "splitStrata",
signature(x = "genind"),
definition = function(x, value, sep = "_"){
.splitStrata(x, value, sep = sep)
})
setMethod(
f = "splitStrata",
signature(x = "genlight"),
definition = function(x, value, sep = "_"){
.splitStrata(x, value, sep = sep)
})
#==============================================================================#
#' @export
#' @rdname strata-methods
#' @aliases splitStrata<-,genind-method splitStrata<-,genlight-method
#' @docType methods
#==============================================================================#
"splitStrata<-" <- function(x, sep = "_", value){
standardGeneric("splitStrata<-")
}
#' @export
setGeneric("splitStrata<-")
setMethod(
f = "splitStrata<-",
signature(x = "genind"),
definition = function(x, sep = "_", value){
return(splitStrata(x, value, sep))
})
setMethod(
f = "splitStrata<-",
signature(x = "genlight"),
definition = function(x, sep = "_", value){
return(splitStrata(x, value, sep))
})
#==============================================================================#
#' @export
#' @rdname strata-methods
#' @aliases addStrata,genind-method addStrata,genlight-method
#' @param name an optional name argument for use with addStrata if supplying
#' a vector. Defaults to "NEW".
#' @docType methods
#==============================================================================#
addStrata <- function(x, value, name = "NEW"){
standardGeneric("addStrata")
}
#' @export
setGeneric("addStrata")
setMethod(
f = "addStrata",
signature(x = "genind"),
definition = function(x, value, name = "NEW"){
theCall <- match.call()
.addStrata(x, value, name = name, theCall)
})
setMethod(
f = "addStrata",
signature(x = "genlight"),
definition = function(x, value, name = "NEW"){
theCall <- match.call()
.addStrata(x, value, name = name, theCall)
})
#==============================================================================#
#' @export
#' @rdname strata-methods
#' @aliases addStrata<-,genind-method addStrata<-,genlight-method
#' @docType methods
#==============================================================================#
"addStrata<-" <- function(x, name = "NEW", value){
standardGeneric("addStrata<-")
}
#' @export
setGeneric("addStrata<-")
setMethod(
f = "addStrata<-",
signature(x = "genind"),
definition = function(x, name = "NEW", value){
theCall <- match.call()
return(.addStrata(x, value, name = name, theCall))
})
setMethod(
f = "addStrata<-",
signature(x = "genlight"),
definition = function(x, name = "NEW", value){
theCall <- match.call()
return(.addStrata(x, value, name = name, theCall))
})
#==============================================================================#
#' Manipulate the population factor of genind objects.
#'
#' The following methods allow the user to quickly change the population of a
#' genind object.
#'
#' @export
#' @rdname population-methods
#' @param x a genind or genlight object
#' @param formula a nested formula indicating the order of the population
#' strata.
#' @param value same as formula
#' @aliases setPop,genind-method setPop,genlight-method
#' @docType methods
#' @author Zhian N. Kamvar
#' @examples
#'
#' data(microbov)
#'
#' strata(microbov) <- data.frame(other(microbov))
#'
#' # Currently set on just
#' head(pop(microbov))
#'
#' # setting the strata to both Pop and Subpop
#' setPop(microbov) <- ~coun/breed
#' head(pop(microbov))
#'
#' \dontrun{
#'
#' # Can be used to create objects as well.
#' microbov.old <- setPop(microbov, ~spe)
#' head(pop(microbov.old))
#' }
#==============================================================================#
setPop <- function(x, formula = NULL) standardGeneric("setPop")
#' @export
setGeneric("setPop")
setMethod(
f = "setPop",
signature(x = "genind"),
definition = function(x, formula = NULL){
.setPop(x, formula = formula)
})
setMethod(
f = "setPop",
signature(x = "genlight"),
definition = function(x, formula = NULL){
.setPop(x, formula = formula)
})
#==============================================================================#
#' @export
#' @rdname population-methods
#' @aliases setPop<-,genind-method setPop<-,genlight-method
#' @docType methods
#==============================================================================#
"setPop<-" <- function(x, value) standardGeneric("setPop<-")
#' @export
setGeneric("setPop<-")
setMethod(
f = "setPop<-",
signature(x = "genind"),
definition = function(x, value){
return(setPop(x, value))
})
setMethod(
f = "setPop<-",
signature(x = "genlight"),
definition = function(x, value){
return(setPop(x, value))
})
#==============================================================================#
#==============================================================================#
# internal functions utilized
#==============================================================================#
#==============================================================================#
#==============================================================================#
# A function for creating a population strata using a formula and data frame
#
# hier = a nested formula such as ~ A/B/C where C is nested within B, which is
# nested within A.
#
# df = a data frame containing columns corresponding to the variables in hier.
#
# example:
# df <- data.frame(list(a = letters, b = LETTERS, c = 1:26))
# newdf <- .make_strata(~ a/b/c, df)
# df[names(newdf)] <- newdf # Add new columns.
#
# Public functions utilizing this function:
#
# # setPop, strata
#
# Internal functions utilizing this function:
# # none
#==============================================================================#
.make_strata <- function(strata, df, expand_label = FALSE){
newlevs <- attr(terms(strata), "term.labels")
levs <- all.vars(strata)
if (length(levs) > 1){
newlevs <- gsub(":", "_", newlevs)
}
if (!all(levs %in% names(df))){
stop(.strata_incompatible_warning(levs, df), call. = FALSE)
}
newdf <- df[levs[1]]
if (!expand_label){
newlevs <- levs
}
lapply(1:length(levs), function(x) newdf[[newlevs[x]]] <<- as.factor(.pop_combiner(df, levs[1:x])))
return(newdf)
}
#==============================================================================#
# This will be used to join heirarchical population vectors for the purposes of
# maintaining strata.
# Public functions utilizing this function:
# #
#
# Internal functions utilizing this function:
# # .make_strata
#==============================================================================#
.pop_combiner <- function(df, strata=c(1), sep="_"){
if(!is.list(df)){
warning("df must be a data frame or a list", call. = FALSE)
return(df)
}
else{
if(length(strata)==1){
return(df[[strata]])
}
else{
comb <- vector(length=length(df[[strata[1]]]))
comb <- df[[strata[1]]]
lapply(strata[-1], function(x) comb <<- paste(comb, df[[x]], sep=sep))
return(comb)
}
}
}
#==============================================================================#
# A function that will quit the function if a level in the strata is not
# present in the given data frame.
#
# Public functions utilizing this function:
# # setPop strata poppr.amova
#
# Internal functions utilizing this function:
# # .make_strata make_ade_df
#==============================================================================#
.strata_incompatible_warning <- function(levs, df){
msg <- paste("One or more levels in the given strata is not present",
"in the data frame.\n", paste(rep("-", 78), collapse = ""),
"\nstrata:\t", paste(levs, collapse = ", "), "\nData:\t",
paste(names(df), collapse = ", "))
return(msg)
}
#==============================================================================#
# A function that will send a message if the number of rows in a data frame does
# not match what is expected.
#
# Public functions utilizing this function:
# # addStrata
#
# Internal functions utilizing this function:
# # .addStrata
#==============================================================================#
.not_enough_rows_warning <- function(dfname, dfrow, nind){
msg <- paste("The data frame or vector does not have enough rows\n",
paste(rep("-", 78), collapse = ""),
"\n", dfname, ":\t", dfrow, "\nData :\t", nind)
return(msg)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.