Nothing
#' Correlation between Traits and Axes
#'
#' Compute relationship between all traits and all axes of the functional
#' space. For continuous trait a linear model is computed and r2 and p-value
#' are returned. For other types of traits, a Kruskal-Wallis test is computed
#' and eta2 statistics is returned.
#' Option allows to plot trait-axis relationships with scatterplot and boxplot
#' for continuous and non-continuous traits, respectively.
#'
#' @param sp_tr a data frame containing species as rows and traits as columns.
#'
#' @param sp_faxes_coord a matrix of species coordinates in a multidimensional
#' functional space. Species coordinates have been retrieved
#' thanks to \code{\link{tr.cont.fspace}} or \code{\link{quality.fspaces}}.
#'
#' @param tr_nm a vector gathering the names of traits (as in `sp_tr`) to
#' consider. If `NULL` all traits are considered.
#'
#' @param faxes_nm a vector gathering the names of PCoA axes (as in
#' `sp_faxes_coord`) to consider.
#'
#' @param plot a logical value indicating whether plot illustrating relations
#' between trait and axes should be drawn. **You can only plot relationships
#' for up to 10 traits and/or 10 axes**.
#'
#' @param name_file the file name (without extension) to save the plot as a 300
#' dpi JPEG file. Default is `NULL` which means plot is only displayed. If
#' `plot = FALSE` this argument is ignored.
#'
#' @param color_signif an R color name or an hexadecimal code referring to
#' the color of points when relationships between the trait and the axis is
#' significant. Default is `darkblue`.
#'
#' @param color_non_signif an R color name or an hexadecimal code referring to
#' the
#' color of points when relationships between the trait and the axis are not
#' significant. Default is `gray80`.
#'
#' @param stop_if_NA a logical value to stop or not the process if the
#' `sp_tr` data frame contains NA. Functional measures are sensitive to
#' missing traits. For further explanations, see the Note section.
#' Default is `TRUE`.
#'
#' @return 1 data frame with for each combination of trait and axis (rows), the
#' name of the test performed, and the corresponding statistics and p-value.
#' If `plot = TRUE` a multi-panel figure with traits as columns and axes as
#' rows is also plotted. When relationships between trait and axis is
#' significant the points are colored, else they remain grayish.
#'
#' @author Nicolas Loiseau and Sebastien Villeger
#'
#' @export
#' @importFrom stats summary.lm
#'
#' @examples
#' # Load Species x Traits Data
#' data("fruits_traits", package = "mFD")
#'
#' # Load Traits categories dataframe
#' data("fruits_traits_cat", package = "mFD")
#'
#' # Compute Functional Distance
#' sp_dist_fruits <- mFD::funct.dist(sp_tr = fruits_traits,
#' tr_cat = fruits_traits_cat,
#' metric = "gower",
#' scale_euclid = "scale_center",
#' ordinal_var = "classic",
#' weight_type = "equal",
#' stop_if_NA = TRUE)
#'
#' # Compute Functional Spaces Quality (to retrieve species coordinates)
#' fspaces_quality_fruits <- mFD::quality.fspaces(
#' sp_dist = sp_dist_fruits,
#' maxdim_pcoa = 10,
#' deviation_weighting = "absolute",
#' fdist_scaling = FALSE,
#' fdendro = "average")
#'
#' # Retrieve Species Coordinates
#' sp_faxes_coord_fruits <- fspaces_quality_fruits$details_fspaces$sp_pc_coord
#'
#' # Compute Correlation between Traits and Functional Axes
#' mFD::traits.faxes.cor(
#' sp_tr = fruits_traits,
#' sp_faxes_coord = sp_faxes_coord_fruits,
#' tr_nm = NULL,
#' faxes_nm = NULL,
#' name_file = NULL,
#' color_signif = "darkblue",
#' color_non_signif = "gray80")
traits.faxes.cor <- function(sp_tr, sp_faxes_coord, tr_nm = NULL,
faxes_nm = NULL, plot = FALSE, name_file = NULL,
color_signif = "darkblue",
color_non_signif = "gray80",
stop_if_NA = TRUE) {
## Check inputs ----
if (missing(sp_tr)) {
stop("Argument 'sp_tr' is mandatory.")
}
if (missing(sp_faxes_coord)) {
stop("Argument 'sp_faxes_coord' is mandatory.")
}
check.sp.tr(sp_tr, stop_if_NA = stop_if_NA)
check.sp.faxes.coord(sp_faxes_coord)
if (!identical(sort(rownames(sp_tr)), sort(rownames(sp_faxes_coord)))) {
stop("Species names mismatch between 'sp_tr' and 'sp_faxes_coord'.")
}
# If not provided, getting 'tr_nm' and 'faxes_nm' else checking
if (is.null(tr_nm)) {
tr_nm <- names(sp_tr)
} else {
if (any(!(tr_nm %in% names(sp_tr)))) {
stop("Trait names should be as in 'sp_tr'.")
}
}
if (is.null(faxes_nm)){
faxes_nm <- colnames(sp_faxes_coord)
} else {
if (any(!(faxes_nm %in% colnames(sp_faxes_coord)))) {
stop("Axes names should be as in 'sp_tr'.")
}
}
# If needed, checking number of plots to draw
if (plot) {
if (length(faxes_nm) > 10) {
stop("Number of axes to plot should be < 11.")
}
if (length(tr_nm) > 10) {
stop("Number of traits to plot should be < 11.")
}
}
## Preparing ----
# combinations trait*axes:
res <- as.data.frame(matrix(NA, length(tr_nm) * length(faxes_nm), 6 ,
dimnames = list(NULL, c("trait", "axis", "test",
"stat", "value",
"p.value"))))
# flag for moving down combinations of traits and axes:
flag <- 0
# loop on traits and axes ####
for (i in tr_nm) {
for (j in faxes_nm) {
# moving through combinations of traits and axes:
flag <- flag + 1
# data:
trait <- NULL
axis <- NULL
data_ij <- data.frame("trait" = sp_tr[ , i],
"axis" = sp_faxes_coord[ , j])
# if trait is continuous Linear Model ----
if (is.numeric(data_ij$trait)) {
# test
test_ij <- "Linear Model"
lm_ij <- summary(stats::lm(trait ~ axis, data = data_ij))
res[flag, c("trait", "axis", "test", "stat")] <- c(i, j, test_ij, "r2")
res[flag, c("value", "p.value")] <- c(round(lm_ij$r.squared, 3),
round(lm_ij$coefficients[2, 4],
4))
} else {
# if trait is not continuous Kruskal Wallis test ----
test_ij <- "Kruskal-Wallis"
kw_ij <- stats::kruskal.test(axis ~ trait, data = data_ij)
kw_ij_eta2 <- rstatix::kruskal_effsize(data = data_ij, axis ~ trait)
res[flag, c("trait", "axis", "test", "stat")] <- c(i, j, test_ij,
"eta2")
res[flag, c("value", "p.value")] <- c(round(kw_ij_eta2$effsize, 3),
round(kw_ij$p.value, 4))
}
# plotting if needed ----
if (plot) {
# X axis has trait names only for last Faxes (bottom row)
x_lab_ij <- NULL
if (j == faxes_nm[length(faxes_nm)]) {
x_lab_ij <- i
}
# Y axis will have Faxes names only for first trait (left column)
y_lab_ij <- NULL
if (i == tr_nm[1]) {
y_lab_ij <- j
}
# Main color according to significance of relationship:
if (res[flag, "p.value"] < 0.05) {
col_cor <- color_signif
} else {
col_cor <- color_non_signif
}
# Empty plot
gg_ij <- ggplot2::ggplot(data_ij, ggplot2::aes(trait, axis)) +
ggplot2::xlab(x_lab_ij) +
ggplot2::ylab(y_lab_ij) +
ggplot2::theme_bw()
# if continuous trait, adding points:
if (res[flag, "stat"] == "r2") {
gg_ij <- gg_ij + ggplot2::geom_point(size = 2, col = col_cor)
} else {
# if ordinal or categorical trait violin plot + jittered points:
gg_ij <- gg_ij + ggplot2::geom_boxplot(colour = col_cor) +
ggplot2::geom_jitter(colour = col_cor, width = 0.3, size = 1.5)
}
# if not first panel merging down with previous one(s):
if (j == faxes_nm[1]) {
col_j <- gg_ij
} else {
col_j <- col_j / gg_ij
}
} # end of if plot
} # end of j
# merging plots if needed:
if (plot) {
# if not first trait, merging with other side by side:
if (i == tr_nm[1]) {
tr_faxes_plot <- col_j
} else {
tr_faxes_plot <- tr_faxes_plot | col_j
}
} # end of if plot
} # end of i
## Function Return ----
if (!plot) {
return("tr_faxes_stat" = res) # default
} else {
# if plot to be returned:
# adding title and legend to plot:
tr_faxes_plot <- tr_faxes_plot +
patchwork::plot_annotation(
title = "Relation between traits and PCoA axes",
caption = "Made with mFD package")
# displaying or saving:
if (is.null(name_file)){
# table with statistics and plot:
return(list("tr_faxes_stat" = res, "tr_faxes_plot" = tr_faxes_plot))
} else {
# saving plot as a 300dpi jepg file:
ggplot2::ggsave(filename = paste0(name_file, ".jpeg"),
plot = tr_faxes_plot,
device = "jpeg",
width = length(tr_nm) * 3,
height = length(faxes_nm) * 2.33,
units = "in",
dpi = 300)
# and returning table with statistics
return("tr_faxes_stat" = res)
} # end of if jpeg
} # end of if plot
} # end of function
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.