# rm(list=ls())
setwd("~/Documents/PhD Thesis/Heritability meta-analysis")
library(readxl)
library(tidyverse); theme_set(theme_light())
library(metafor)
library(patchwork)
source('Functions/useful_functions.R')
source('Functions/mlm.variance.distribution.R')
# Load processed data:
load("Data/heritability_estimates_processed.RData")
# data.full <- data.full %>% filter(!(study == "Zhang et al.")) # duplicate estimate!
data <- data.full %>%
filter(trait != "gamete contribution") %>%
mutate(trait = fct_drop(trait))
dat_s <- data %>%
filter(!(trait %in% c("photochemistry", "immune response"))) %>%
mutate(trait = factor(trait))
dat_sh <- data %>%
filter(!(trait %in% c("photochemistry", "nutrient content", "immune response"))) %>%
mutate(trait = factor(trait))
dat_shg <- data %>%
filter(trait %in% c("symbiont community", "survival", "nutrient content", "growth", "bleaching")) %>%
filter(!(growth.form %in% c("columnar", "encrusting"))) %>%
mutate(trait = factor(trait), growth.form = factor(growth.form))
dat_tm <- data %>%
filter(!is.na(temp.diff)) %>%
filter(!(trait %in% c("symbiont community", "morphology", "gene expression"))) %>%
mutate(trait = factor(trait),
temp.manip = temp.manip.plus.others,
temp.s = sqrt(temp.diff))
dat_tm_nz <- dat_tm %>% filter(temp.diff >0) %>%
mutate(trait = factor(trait),
stage = factor(stage),
h2 = factor(h2),
growth.form = factor(growth.form))
# Specify final main model
final.model.A <- rma(yi=val.log ~ trait*stage + h2,
vi=sv.log, data=dat_s, method="REML", test="knha")When defining the base model architecture that includes all data (save for one estimate on the heritability of gamete compatibility), the optimal and most parsimonious explanatory variable was the trait type. In order of increasing relative heritability (not accounting for differences in heritability type):
In sub-analyses using smaller data subsets, life stage, heritability type, and growth form came out important, whereas temperature manipulation (binary yes/no), temperature differential (°C above normal/ambient/control temperature), and symbiont type (symbiotic or asymbiotic) were not.
An overall model of trait type, and a sub-analysis model of trait type x life stage + heritability type was preferred through model selection. No other models were found.
Narrow-sense heritability is reported for 10 studies, broad-sense for 10 studies, including one study reporting broad-sense and narrow-sense estimates (Carlon et al. 2011).
table.plot("h2", "study", data.full) # only Carlon et al. study with multiple h2 valuessummarise.coverage("trait", "study", data.full)Most studies (12/19) report on a single trait type and not multiple trait types. Three studies report on two trait types (Meyer et al. 2009; Manzello et al. 2019; Kenkel et al. 2015), two studies report on three trait types (Csázár et al. 2010; Quigley et al. 2020), and Zhang et al. (2019) and Wright et al. (2019) report on four and six trait types, respectively.
Both immune response and gamete contribution trait types have only a single study contributing to their estimates. In the case of the latter, gamete contribution has only one estimate, limiting any inferences using models.
table.plot("trait", "species", data.full)
data.full %>% group_by(species) %>% tally %>% arrange(-n)
summarise.coverage("species", "study", data.full)$YMost heritability estimates are from Acropora millepora (48 estimates; 5 separate studies), A. spathulata (12; 1), Porites astreoides (9; 2), Fabia fragum (6; 1), Orbicella faveolata (4; 3), and A. cervicornis (3; 2).
Most diversity of species/studies are covered by trait types such as growth, survival, bleaching, and symbiont community.
Following the process of mixed model selection outlined by Zuur et al. (Mixed Effects Modelling Book, 2009, pp. 121-122) and Diggle et al. (2002), we:
We have 4 main factors that cover the complete dataset:
trait type (9 levels, including survival, growth, bleaching, etc.)
heritability type (broad- or narrow-sense)
coral life stage (larval, juvenile, adult)
coral growth form (3 main types: corymbose, branching, massive; also encrusting and columnar)
Thus, our beyond optimal model is one that includes the main effects of all 4 factors (additive model). As seen later on, we cannot examine interactions, given factor combinations being missing For example, heritability estimates for narrow-sense heritability exist only for 6/9 trait types, so no interaction between trait type x heritability type can be properly examined without removing the 3 trait types with only broad-sense heritability estimates.
summarise.coverage("trait", "h2", data)$X # 9 broad, 6 narrowNext, we fit different random effect structures, including nested (3-level) models that include either study ID or species ID as an upper level, with estimate ID nested within (sampling variance acts as the 3rd, most basal level in a meta-model). We also fit similar models with one or both of study/species ID and estimate ID fixed at zero, as well as a ‘null’ random effects model, where all random effects are fit at zero (essentially a fixed effects model).
m.study.nested <- rma.mv(yi=val.log ~ trait + h2 + growth.form + stage,
V=sv.log, random = ~1|study/est.id,
data=data, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.spp.nested <- rma.mv(yi=val.log ~ trait + h2 + growth.form + stage,
V=sv.log, random = ~1|species/est.id,
data=data, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.only.est <- rma.mv(yi=val.log ~ trait + h2 + growth.form + stage,
V=sv.log, random = ~1|study/est.id,
data=data, method="REML", tdist=T,
sigma2 = c(0, NA)) # same as random = ~1|est.id
m.only.study <- rma.mv(yi=val.log ~ trait + h2 + growth.form + stage,
V=sv.log, random = ~1|study/est.id,
data=data, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|study
m.only.spp <- rma.mv(yi=val.log ~ trait + h2 + growth.form + stage,
V=sv.log, random = ~1|species/est.id,
data=data, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|species
m.no.reff <- rma.mv(yi=val.log ~ trait + h2 + growth.form + stage,
V=sv.log, random = ~1|study/est.id,
data=data, method="REML", tdist=T,
sigma2 = c(0, 0)) # no random effects
TableS1 <- myAIC(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff) %>%
mutate(model = fct_recode(model,
"Estimate ID nested in study ID" = "m.study.nested",
"Estimate ID nested in species" = "m.spp.nested",
"Study ID only" = "m.only.study",
"Species only" = "m.only.spp",
"Estimate ID only" = "m.only.est",
"No random effect" = "m.no.reff"))
write.csv(TableS1, file="Suppl Tables//TableS1.csv", row.names=F)
TableS1| model | df | AICc | ΔAICc |
|---|---|---|---|
| Estimate ID nested in study ID | 15 | 112.2116 | 0.00000 |
| Estimate ID only | 15 | 118.1781 | 5.96650 |
| Estimate ID nested in species | 15 | 121.5713 | 9.35972 |
| Study ID only | 15 | 190.3282 | 78.11664 |
| Species only | 15 | 311.9348 | 199.72324 |
| No random effect | 15 | 353.5841 | 241.37256 |
Here, we see that the model with estimate ID nested within study ID is preferred (random=~1|study/est.id, sigma2 = c(NA,NA)), since it has the lowest relative AICc value.
Thus, we continue on with this random effects structure when deciding our fixed effects structure.
Next, we select the optimal by comparing model AICc values of all possible fixed-effect models for factors that exist for the complete dataset:
trait type (t; 9 levels: survival, growth, gene expression, etc.)
heritability type (h; 2 levels: \(h^2\) or \(H^2\))
coral growth form (g; 4 levels: branching, massive/columnar, corymbose, or encrusting)
coral life stage (s; 3 levels: larval, juvenile, adult)
We also have a factor of symbiont type (symbiotic or asymbiotic), however, there are only 4 estimates with asymbiotic individuals, and these all involve coral larvae from broadcast-spawners. Thus, there are too few estimates and too little coverage to compare at this stage. Similarly, temperature was not manipulated for a few of the studies, and thus is not assessed here either.
We fit all combinations of additive factors possible, excluding any interactions at this point, as the data are not complete for a number of factor combinations. We display only the top 10 models by AICc (given it is different in all models to AIC, our N sample size is too small for the k model parameters being estimated!).
Again, because the data are not complete for interactions at this stage, we examine only additive models with the various factors.
dat <- data %>% mutate(t = trait, h = h2, g = growth.form, s = stage)
mod_names <- ls(pattern = "m.fixed.")
do.call("rm", as.list(mod_names))
# One-ways with less and less other terms:
m.fixed.1way.t.h.g.s <- rma.mv(yi=val.log ~ t + h + g + s,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.t.h.g <- rma.mv(yi=val.log ~ t + h + g,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.t.h.s <- rma.mv(yi=val.log ~ t + h + s,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.t.g.s <- rma.mv(yi=val.log ~ t + g + s,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.h.g.s <- rma.mv(yi=val.log ~ h + g + s,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.t.h <- rma.mv(yi=val.log ~ t + h,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.t.g <- rma.mv(yi=val.log ~ t + g,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.t.s <- rma.mv(yi=val.log ~ t + s,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.h.g <- rma.mv(yi=val.log ~ h + g,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.h.s <- rma.mv(yi=val.log ~ h + s,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.g.s <- rma.mv(yi=val.log ~ g + s,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.t <- rma.mv(yi=val.log ~ t,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.h <- rma.mv(yi=val.log ~ h,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.g <- rma.mv(yi=val.log ~ g,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.s <- rma.mv(yi=val.log ~ s,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
m.fixed.1way.null <- rma.mv(yi=val.log ~ 1,
random = ~1|study/est.id, V=sv.log,
data=dat, method="ML", tdist=T)
mod_names <- ls(pattern = "m.fixed")
param_list=c("t", "h", "g", "s")
table1 <- do.call(myAIC, as.list(c(mod_names, getmodel=T,
param.list = list(param_list))))
# table1$rel.importance
AICt <- table1$AICtable %>% filter(model == "m.fixed.1way.t") %>% pull(4) %>% round(2)
AICth <- table1$AICtable %>% filter(model == "m.fixed.1way.t.h") %>% pull(4) %>% round(2)
AICts <- table1$AICtable %>% filter(model == "m.fixed.1way.t.s") %>% pull(4) %>% round(2)
AICths <- table1$AICtable %>% filter(model == "m.fixed.1way.t.h.s") %>% pull(4) %>% round(2)
# head(table1$AICtable)
TableS2 <- head(table1$AICtable) %>%
mutate(model = fct_recode(model,
"trait" = "m.fixed.1way.t",
"trait + heritability type" = "m.fixed.1way.t.h",
"trait + life stage" = "m.fixed.1way.t.s",
"trait + heritability type + life stage" = "m.fixed.1way.t.h.s",
"trait + growth form + life stage" = "m.fixed.1way.t.g.s",
"trait + growth form" = "m.fixed.1way.t.g"))
write.csv(TableS2, file="Suppl Tables/TableS2.csv", row.names=F)
TableS2| model | df | AICc | ΔAICc |
|---|---|---|---|
| trait | 8 | 100.7705 | 0.0000000 |
| trait + heritability type | 9 | 101.1370 | 0.3664769 |
| trait + life stage | 10 | 101.8590 | 1.0884955 |
| trait + heritability type + life stage | 11 | 103.3778 | 2.6072277 |
| trait + growth form | 12 | 109.0199 | 8.2493425 |
| m.fixed.1way.t.h.g | 13 | 109.3342 | 8.5636276 |
The model with the lowest AICc is one with only trait type as a fixed effect, followed closely (within ΔAICc < 2) by a model of trait + life stage (ΔAICc = 1.09), and trait + heritability type (ΔAICc = 0.37), and finally, trait + heritability + stage (ΔAICc = 2.61). and finally a few models including life stage, heritability, and trait type. However, clearly, there are data limitations present that limit the number of model parameters possible. Thus, we accept trait type by itself as the core model for the complete dataset.
rbind(
data.frame(
Model = rep(paste0("~ trait (ΔAICc=", AICt,")")),
Parameter = names(coef(m.fixed.1way.t)),
Estimate = coef(m.fixed.1way.t),
SE = m.fixed.1way.t$se),
data.frame(
Model = rep(paste0("~ trait + life stage (ΔAICc=", AICts,")")),
Parameter = names(coef(m.fixed.1way.t.s)),
Estimate = coef(m.fixed.1way.t.s),
SE = m.fixed.1way.t.s$se),
data.frame(
Model = rep(paste0("~ trait + h2 (ΔAICc=", AICth,")")),
Parameter = names(coef(m.fixed.1way.t.h)),
Estimate = coef(m.fixed.1way.t.h),
SE = m.fixed.1way.t.h$se),
data.frame(
Model = rep(paste0("~ trait + h2 + life stage (ΔAICc=", AICths,")")),
Parameter = names(coef(m.fixed.1way.t.h.s)),
Estimate = coef(m.fixed.1way.t.h.s),
SE = m.fixed.1way.t.h.s$se)) %>%
mutate(Parameter = factor(Parameter),
Parameter = fct_relevel(Parameter, "intrcpt")) %>%
ggplot(aes(x=Estimate, y=Parameter, color=Model)) +
geom_vline(xintercept=0, linetype="dashed") +
geom_pointrange(aes(xmin = Estimate - SE, xmax = Estimate + SE), position = position_dodge(width=0.3)) +
labs(x="Parameter estimate (log[X+0.2] scale) ± SE") +
theme(legend.position="top", legend.direction="vertical")The plot shows relatively similar coefficient estimates and uncertainty in the top 4 models. However, we go with the best model of only trait type as a predictor.
Due to the small effect size of life stage in the trait + life stage model, and the nearly identical AICc value (difference of 0.15), we fit our final model using trait type only as:
\[ logit(h^2 + 0.2) \sim N(\mu, \sigma^2) \\ \mu = trait_k \, + \, \epsilon_{i} \]
where \(\sigma^2\) are the estimated amount of heterogeneity in the studies/estimates, calculated using an inverse variance weighting method via package metafor that accounts for uncertainty in each estimate, and \(\epsilon\) is the residual error for each estimate.
# Using subset data
final.model <- rma.mv(yi=val.log ~ trait,
V=sv.log, random = ~1|study/est.id,
data=data, method="REML", tdist=T)
final.model
Multivariate Meta-Analysis Model (k = 94; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.0933 0.3055 18 no study
sigma^2.2 0.0566 0.2379 94 no study/est.id
Test for Residual Heterogeneity:
QE(df = 85) = 477.5080, p-val < .0001
Test of Moderators (coefficients 2:9):
F(df1 = 8, df2 = 85) = 6.5312, p-val < .0001
Model Results:
estimate se tval pval ci.lb ci.ub
intrcpt -1.1454 0.2175 -5.2667 <.0001 -1.5779 -0.7130
traitphotochemistry 0.3631 0.1832 1.9818 0.0507 -0.0012 0.7273
traitgrowth 0.3884 0.2140 1.8149 0.0731 -0.0371 0.8139
traitnutrient content 0.5335 0.2375 2.2466 0.0273 0.0614 1.0056
traitbleaching 0.5690 0.2438 2.3340 0.0220 0.0843 1.0537
traitsymbiont community 0.6742 0.3090 2.1818 0.0319 0.0598 1.2886
traitmorphology 0.7919 0.3083 2.5683 0.0120 0.1789 1.4050
traitimmune response 0.9435 0.2532 3.7265 0.0003 0.4401 1.4468
traitsurvival 1.1345 0.2199 5.1598 <.0001 0.6973 1.5716
intrcpt ***
traitphotochemistry .
traitgrowth .
traitnutrient content *
traitbleaching *
traitsymbiont community *
traitmorphology *
traitimmune response ***
traitsurvival ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
save(final.model, file="Models/final.model.Rdata")
x <- mlm.variance.distribution(final.model, suppress.plot=F)Lastly, we check the final model diagnostics, such as examining the funnel plot for asymmetry indicating publishing bias, in addition to simulating data based on the final model to examine if it loosely resembles the data observed.
x <- resid(final.model)
hist(x) # looks approx. normal!## Model checks:
par(mfrow=c(2,1))
funnel(final.model)
funnel(final.model, yaxis="vinv")par(mfrow=c(1,1))
ranktest(final.model) # p = 0.72
Rank Correlation Test for Funnel Plot Asymmetry
Kendall's tau = -0.0252, p = 0.7194
Visually, the funnel plot appears to be slightly asymmetric in favour of studies reporting lower heritabilities, but a rank correlation test for funnel plot asymmetry was not statistically significant (Kendall’s \(\tau = = -0.025\), \(P = 0.72\)), indicating no apparent publication bias.
fsn(yi=val.log, vi=sv.log, data=data, type="Rosenberg") # N=1287 to get no significance (but assumes fixed effects)
Fail-safe N Calculation Using the Rosenberg Approach
Average Effect Size: -0.0875
Observed Significance Level: <.0001
Target Significance Level: 0.05
Fail-safe N: 1285
# Number of studies x5 + 10:
length(unique(data$study))*5 + 10[1] 100
cdist <- cooks.distance(final.model, reestimate=FALSE)
cdist.i <- which(cdist >2)
plot(cdist)
points(cdist.i, cdist[cdist.i], col="red", pch=16)data[cdist.i,] %>% select(study, species, val, trait) %>%
cbind(., cooks = round(cdist[cdist.i], 2))| study | species | val | trait | cooks | |
|---|---|---|---|---|---|
| 16 | Wright et al. 2019 | Acropora millepora | 0.92 | immune response | 5.2 |
update(final.model, .~., data[-cdist.i,])
Multivariate Meta-Analysis Model (k = 94; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.0933 0.3055 18 no study
sigma^2.2 0.0566 0.2379 94 no study/est.id
Test for Residual Heterogeneity:
QE(df = 85) = 477.5080, p-val < .0001
Test of Moderators (coefficients 2:9):
F(df1 = 8, df2 = 85) = 6.5312, p-val < .0001
Model Results:
estimate se tval pval ci.lb ci.ub
intrcpt -1.1454 0.2175 -5.2667 <.0001 -1.5779 -0.7130
traitphotochemistry 0.3631 0.1832 1.9818 0.0507 -0.0012 0.7273
traitgrowth 0.3884 0.2140 1.8149 0.0731 -0.0371 0.8139
traitnutrient content 0.5335 0.2375 2.2466 0.0273 0.0614 1.0056
traitbleaching 0.5690 0.2438 2.3340 0.0220 0.0843 1.0537
traitsymbiont community 0.6742 0.3090 2.1818 0.0319 0.0598 1.2886
traitmorphology 0.7919 0.3083 2.5683 0.0120 0.1789 1.4050
traitimmune response 0.9435 0.2532 3.7265 0.0003 0.4401 1.4468
traitsurvival 1.1345 0.2199 5.1598 <.0001 0.6973 1.5716
intrcpt ***
traitphotochemistry .
traitgrowth .
traitnutrient content *
traitbleaching *
traitsymbiont community *
traitmorphology *
traitimmune response ***
traitsurvival ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
The main influential point is one for immune response, which drives the average estimate for immune response much higher than other values for immune response. Note that all the values for the immune response trait come from the same study (Wright et al. 2019), and so the values are already to be interpreted cautiously.
plot(fitted(final.model), rstandard(final.model)$z)
abline(h=0, lty=2)plot(residuals(final.model, type="pearson"))
abline(h=0, lty=2)# Simulate new data given the parameter values of the data and same variance structure, plot on real data to see if it is similar
xsim <- simulate(final.model, 100) %>%
mutate(true.val = data$val.log,
weighting = 1/data$sv.log) %>%
pivot_longer(cols=-c(true.val, weighting)) %>%
select(name, true.val, sim.val = value, weighting)
xsim %>%
ggplot(aes(x=true.val, y=sim.val)) +
geom_point(aes(col=weighting), alpha=0.05) +
geom_abline(slope=1, intercept=0, linetype="dashed") +
scale_colour_viridis_c() +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
scale_y_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1))# More accuracy in the middle, definitely!
# reruns model, based around the same variance/covariance structures but with simulated data.
xsim %>%
ggplot(aes(y=weighting)) +
geom_point(aes(x=sim.val), col="red", size=2, alpha=0.05) +
geom_point(data= filter(xsim, name == "sim_1"),
aes(x=true.val),
col="blue", size=2, alpha=0.9) +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
labs(x="Heritability estimate", y=expression("Weighting (1/SE"^2*")"))# Seems that the model is in general simulating the true data ok!
# Main problem is that values are simulating beyond the bounds of possible heritability.Note that the data was previously not complete enough to examine interactions between explanatory variables properly. For example, some factors such as heritability type and life stage have only a single level represented within some trait types, and some traits involve entirely one level of another factor, e.g., all estimates for nutrient content, immune response, and photochemistry come from single studies, and thus all have only one of the two heritability types within, thus precluding direct comparisons within these trait types.
Thus, to better compare interactions, we conduct separate analyses on subsetted data.
To guide our analysis further, we determine which additional factors can be examined in combination with trait type, and compare the sample sizes of each comparison to determine the order of the sub-analyses.
p1 <- data %>% table.plot("stage", "trait", .) # singular for photochemistry, immune response
p_stage <- table.plot("stage", "trait", dat_s)
p2 <- data %>% table.plot("h2", "trait", .) # singular for photochemistry, nutrient content, immune response
p_h2 <- table.plot("h2", "trait", dat_sh)
p3 <- data %>% table.plot("growth.form", "trait", .) # singular for traits: photochemistry, immune response, morphology, immune response, gene expression; singular for columnar and encrusting growth forms
p_growthform <- table.plot("growth.form", "trait", dat_shg)
p4 <- data %>% filter(!is.na(temp.diff)) %>%
table.plot("temp.manip.plus.others", "trait", .) # singular for traits: photochemistry, immune response, morphology, immune response, gene expression; singular for columnar and encrusting growth forms
p_tempmanip <- table.plot("temp.manip.plus.others", "trait", dat_tm)
require(patchwork)
(p1 | p2) / (p3 | p4)We see there there are a number of rows/columns with less than 2 levels (i.e. ‘singular’ terms), which make it impossible to estimate interaction terms for these factor combinations, due to the singularity. Thus, we subset these rows/columns and plot the remaining data to examine the sample sizes and factor levels remaining.
require(patchwork)
(p_stage | p_h2) / (p_growthform | p_tempmanip)Both life stage and heritability type use similar levels, and thus can be combined for the smaller sample size of heritability type. Life stage thus must be examined first, then heritability type and life stage can be examined together for the smaller data subset. Growth form also uses an even more narrow range of studies, and thus we can examine it after looking at the latter two.
Finally, temperature manipulation results in a few different trait types being removed (e.g., morphology, symbiont community), and the addition of photochemistry, and the data within each trait type are also dissimilar due to some studies being observational and thust being removed. Thus, this analysis must be done on its own, and factors re-added on a case-by-case basis.
dat_s %>% table.plot("stage", "trait", .)# exclude photochemistry, immune responseUsing the smaller data subset, we can now examine possible interactions between trait type and life stage, and include additive terms for other predictors.
The beyond-optimal model in this case is a full analysis of trait type x life stage: \[ logit(h^2) \sim N(\mu, \tau^2) \\ \mu = trait \times stage + h^2type + growth\,form + \epsilon_{i} \]
m.study.nested <- rma.mv(yi=val.log ~ trait * stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_s, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.spp.nested <- rma.mv(yi=val.log ~ trait * stage + h2 + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_s, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.only.est <- rma.mv(yi=val.log ~ trait * stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_s, method="REML", tdist=T,
sigma2 = c(0, NA)) # same as random = ~1|est.id
m.only.study <- rma.mv(yi=val.log ~ trait * stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_s, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|study
m.only.spp <- rma.mv(yi=val.log ~ trait * stage + h2 + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_s, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|species
m.no.reff <- rma.mv(yi=val.log ~ trait * stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_s, method="REML", tdist=T,
sigma2 = c(0, 0)) # no random effects
TableS3 <- myAIC(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff) %>%
mutate(model = fct_recode(model,
"Estimate ID nested in study ID" = "m.study.nested",
"Estimate ID nested in species" = "m.spp.nested",
"Study ID only" = "m.only.study",
"Species only" = "m.only.spp",
"Estimate ID only" = "m.only.est",
"No random effect" = "m.no.reff"))
write.csv(TableS3, file="Suppl Tables/TableS3.csv", row.names=F)
TableS3| model | df | AICc | ΔAICc |
|---|---|---|---|
| Estimate ID only | 22 | 127.7203 | 0.000000 |
| Study ID only | 22 | 130.9134 | 3.193072 |
| Estimate ID nested in study ID | 22 | 133.9795 | 6.259191 |
| Estimate ID nested in species | 22 | 135.5664 | 7.846154 |
| No random effect | 22 | 141.7589 | 14.038646 |
| Species only | 22 | 148.0740 | 20.353683 |
rm(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff)A random effects structure of estimate ID-only is preferred (i.e. to treat estimate IDs as sample sizes of same units). Next preferred is ΔAICc = 1.34.
mod_names <- ls(pattern = "m.fixed.")
do.call("rm", as.list(mod_names))
m.fixed.txs.h.g <- rma.mv(yi=val.log ~ trait*stage + h2 + growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.t.s.h.g <- rma.mv(yi=val.log ~ trait + stage + h2 + growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.txs.h <- rma.mv(yi=val.log ~ trait*stage + h2,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.txs.g <- rma.mv(yi=val.log ~ trait*stage + growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.txs <- rma.mv(yi=val.log ~ trait*stage,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.t.s.g <- rma.mv(yi=val.log ~ trait + stage + growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.t.s.h <- rma.mv(yi=val.log ~ trait + stage + h2,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.t.h.g <- rma.mv(yi=val.log ~ trait + h2 + growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.s.h.g <- rma.mv(yi=val.log ~ stage + h2 + growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.t.s <- rma.mv(yi=val.log ~ trait + stage,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.t.h <- rma.mv(yi=val.log ~ trait + h2,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.t.g <- rma.mv(yi=val.log ~ trait + growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.s.h <- rma.mv(yi=val.log ~ stage + h2,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.s.g <- rma.mv(yi=val.log ~ stage + growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.h.g <- rma.mv(yi=val.log ~ h2 + growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.t <- rma.mv(yi=val.log ~ trait,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.s <- rma.mv(yi=val.log ~ stage,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.h <- rma.mv(yi=val.log ~ h2,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.g <- rma.mv(yi=val.log ~ growth.form,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
m.fixed.null <- rma.mv(yi=val.log ~ 1,
random = ~1|study/est.id, V=sv.log,
data=dat_s, method="ML", tdist=T, sigma2 = c(0, NA))
mod_names <- ls(pattern = "m.fixed.")
TableS4 <- head(do.call("myAIC", as.list(c(mod_names, getmodel=T)))) %>%
mutate(model = fct_recode(model,
"trait x life stage + heritability type" = "m.fixed.txs.h",
"trait x life stage" = "m.fixed.txs",
"trait x life stage + growth form" = "m.fixed.txs.g",
"trait x life stage + heritability type + growth form" = "m.fixed.txs.h.g",
"trait + life stage + growth form" = "m.fixed.t.s.g",
"trait + heritability type + growth form" = "m.fixed.t.h.g"))
write.csv(TableS4, file="Suppl Tables/TableS4.csv", row.names=F)
TableS4| model | df | AICc | ΔAICc |
|---|---|---|---|
| trait x life stage + heritability type | 18 | 80.14774 | 0.000000 |
| trait x life stage | 17 | 82.18116 | 2.033424 |
| trait x life stage + growth form | 21 | 88.98944 | 8.841700 |
| trait x life stage + heritability type + growth form | 22 | 90.13248 | 9.984738 |
| trait + life stage + growth form | 12 | 91.85181 | 11.704067 |
| trait + heritability type + growth form | 11 | 92.39415 | 12.246413 |
# trait x life stage preferred!
# Double-check with rma fits (knha method is slightly different from rma.mv with t-distributed CIs):
# m.fixed.txs.h <- rma(yi=val.log ~ trait*stage + h2,
# vi=sv.log, data=dat_s, method="ML", test="knha")
# m.fixed.txs.g <- rma(yi=val.log ~ trait*stage + growth.form,
# vi=sv.log, data=dat_s, method="ML", test="knha")
# m.fixed.txs <- rma(yi=val.log ~ trait*stage,
# vi=sv.log, data=dat_s, method="ML", test="knha")
# myAIC(m.fixed.txs.h, m.fixed.txs.g, m.fixed.txs)
# model of trait x life stage + heritability type is still preferred!The trait x life stage + heritability fixed effect structure is optimal. The next closest model drops the effect of heritability type, and is over 2 ΔAICc away (ΔAICc = 2.6).
final.model.A <- rma(yi=val.log ~ trait*stage + h2, vi=sv.log,
data=dat_s, method="REML", test="knha")
final.model.A
Mixed-Effects Model (k = 74; tau^2 estimator: REML)
tau^2 (estimated amount of residual heterogeneity): 0.0382 (SE = 0.0173)
tau (square root of estimated tau^2 value): 0.1953
I^2 (residual heterogeneity / unaccounted variability): 46.98%
H^2 (unaccounted variability / sampling variability): 1.89
R^2 (amount of heterogeneity accounted for): 78.27%
Test for Residual Heterogeneity:
QE(df = 55) = 96.0189, p-val = 0.0005
Test of Moderators (coefficients 2:19):
F(df1 = 18, df2 = 55) = 7.8780, p-val < .0001
Model Results:
estimate se tval pval
intrcpt -0.2731 0.5329 -0.5126 0.6103
traitgrowth 0.4395 0.1690 2.6012 0.0119
traitnutrient content 0.0561 0.5609 0.1001 0.9206
traitbleaching -0.3175 0.5803 -0.5470 0.5866
traitsymbiont community 0.1795 0.5609 0.3200 0.7501
traitmorphology 0.1718 0.5757 0.2984 0.7665
traitsurvival 0.2574 0.5368 0.4794 0.6335
stagejuvenile 0.1620 0.1729 0.9374 0.3526
stageadult -0.6607 0.5544 -1.1917 0.2385
h2narrow -0.2716 0.1195 -2.2720 0.0270
traitgrowth:stagejuvenile -1.4359 0.5894 -2.4364 0.0181
traitbleaching:stagejuvenile -0.6695 0.3533 -1.8951 0.0633
traitsymbiont community:stagejuvenile -0.5102 0.6872 -0.7424 0.4610
traitmorphology:stagejuvenile -0.4727 0.3466 -1.3640 0.1781
traitnutrient content:stageadult -0.1588 0.5932 -0.2678 0.7899
traitbleaching:stageadult 1.1584 0.6216 1.8636 0.0677
traitsymbiont community:stageadult 0.6817 0.6128 1.1125 0.2708
traitmorphology:stageadult 0.3645 0.6503 0.5605 0.5774
traitsurvival:stageadult 0.3266 0.5682 0.5748 0.5678
ci.lb ci.ub
intrcpt -1.3410 0.7947
traitgrowth 0.1009 0.7781 *
traitnutrient content -1.0679 1.1802
traitbleaching -1.4805 0.8456
traitsymbiont community -0.9446 1.3036
traitmorphology -0.9819 1.3255
traitsurvival -0.8184 1.3331
stagejuvenile -0.1844 0.5084
stageadult -1.7718 0.4504
h2narrow -0.5112 -0.0320 *
traitgrowth:stagejuvenile -2.6170 -0.2548 *
traitbleaching:stagejuvenile -1.3776 0.0385 .
traitsymbiont community:stagejuvenile -1.8873 0.8670
traitmorphology:stagejuvenile -1.1672 0.2218
traitnutrient content:stageadult -1.3476 1.0299
traitbleaching:stageadult -0.0873 2.4042 .
traitsymbiont community:stageadult -0.5463 1.9098
traitmorphology:stageadult -0.9388 1.6678
traitsurvival:stageadult -0.8121 1.4653
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
save(final.model.A, file="Models/final.model.A.Rdata")
final.model.A$I[1] 46.97796
final.model.A$k - final.model.A$p # df for parameter tests[1] 55
Estimate ID-only, so all residual heterogeneity is: \(I^2\) = 46.10%, N = 74
x <- resid(final.model.A)
hist(x) # looks approx. normal, except for one strong outlier at -1.5par(mfrow=c(2,1))
funnel(final.model.A)
update(final.model.A, .~., data=dat_s[x!=0,]) %>%
funnel(., yaxis="vinv")par(mfrow=c(1,1))fsn(yi=val.log, vi=sv.log, data=dat_s, type="Rosenberg") # N=513 to get no significance (but assumes fixed effects)
Fail-safe N Calculation Using the Rosenberg Approach
Average Effect Size: -0.0770
Observed Significance Level: <.0001
Target Significance Level: 0.05
Fail-safe N: 505
# Number of studies x5 + 10:
length(unique(dat_s$study))*5 + 10[1] 100
cdist <- cooks.distance(final.model.A, reestimate=FALSE)
plot(cdist)
cdist.i <- which(cdist >2)
points(cdist.i, cdist[cdist.i], col="red", pch=16)data[cdist.i,] %>% select(study, species, val, trait, stage, h2) %>%
cbind(., cooks = round(cdist[cdist.i], 2))| study | species | val | trait | stage | h2 | cooks | |
|---|---|---|---|---|---|---|---|
| 3 | Quigley et al. 2020 | Acropora spathulata | 0.93 | survival | juvenile | narrow | 2.87 |
| 19 | Wright et al. 2019 | Acropora millepora | 0.16 | immune response | adult | broad | 3.94 |
| 27 | Manzello et al. 2019 | Orbicella faveolata | 0.73 | symbiont community | adult | broad | 3.87 |
update(final.model.A, .~., data=dat_s[-cdist.i,]) # effect of juv:growth n.s.
Mixed-Effects Model (k = 71; tau^2 estimator: REML)
tau^2 (estimated amount of residual heterogeneity): 0.0312 (SE = 0.0167)
tau (square root of estimated tau^2 value): 0.1767
I^2 (residual heterogeneity / unaccounted variability): 37.71%
H^2 (unaccounted variability / sampling variability): 1.61
R^2 (amount of heterogeneity accounted for): 80.78%
Test for Residual Heterogeneity:
QE(df = 52) = 77.6553, p-val = 0.0121
Test of Moderators (coefficients 2:19):
F(df1 = 18, df2 = 52) = 7.7445, p-val < .0001
Model Results:
estimate se tval pval
intrcpt -0.1933 0.5276 -0.3664 0.7156
traitgrowth 0.4393 0.1631 2.6927 0.0095
traitnutrient content -0.0240 0.5527 -0.0433 0.9656
traitbleaching -0.3937 0.5722 -0.6882 0.4944
traitsymbiont community 0.1831 0.5498 0.3331 0.7404
traitmorphology 0.0920 0.5650 0.1628 0.8713
traitsurvival 0.2231 0.5279 0.4227 0.6743
stagejuvenile -0.0201 0.1883 -0.1066 0.9155
stageadult -0.7347 0.5481 -1.3405 0.1859
h2narrow -0.3514 0.1316 -2.6704 0.0101
traitgrowth:stagejuvenile -1.2874 0.5805 -2.2179 0.0310
traitbleaching:stagejuvenile -0.4081 0.3714 -1.0989 0.2769
traitsymbiont community:stagejuvenile -0.3317 0.6814 -0.4868 0.6285
traitmorphology:stagejuvenile -0.6400 0.4486 -1.4267 0.1596
traitnutrient content:stageadult -0.0860 0.5831 -0.1476 0.8833
traitbleaching:stageadult 1.0240 0.6382 1.6045 0.1147
traitsymbiont community:stageadult 0.6723 0.5960 1.1279 0.2645
traitmorphology:stageadult 0.4698 0.6392 0.7349 0.4657
traitsurvival:stageadult 0.3567 0.5575 0.6397 0.5251
ci.lb ci.ub
intrcpt -1.2520 0.8654
traitgrowth 0.1119 0.7667 **
traitnutrient content -1.1330 1.0851
traitbleaching -1.5419 0.7544
traitsymbiont community -0.9201 1.2864
traitmorphology -1.0417 1.2257
traitsurvival -0.8362 1.2825
stagejuvenile -0.3979 0.3578
stageadult -1.8345 0.3651
h2narrow -0.6155 -0.0874 *
traitgrowth:stagejuvenile -2.4522 -0.1226 *
traitbleaching:stagejuvenile -1.1533 0.3371
traitsymbiont community:stagejuvenile -1.6991 1.0357
traitmorphology:stagejuvenile -1.5402 0.2601
traitnutrient content:stageadult -1.2561 1.0840
traitbleaching:stageadult -0.2566 2.3046
traitsymbiont community:stageadult -0.5237 1.8683
traitmorphology:stageadult -0.8130 1.7525
traitsurvival:stageadult -0.7621 1.4754
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
update(final.model.A, .~., data=dat_s[-cdist.i[1],]) # immune : temp interaction remains
Mixed-Effects Model (k = 73; tau^2 estimator: REML)
tau^2 (estimated amount of residual heterogeneity): 0.0367 (SE = 0.0175)
tau (square root of estimated tau^2 value): 0.1916
I^2 (residual heterogeneity / unaccounted variability): 42.32%
H^2 (unaccounted variability / sampling variability): 1.73
R^2 (amount of heterogeneity accounted for): 78.12%
Test for Residual Heterogeneity:
QE(df = 54) = 88.0509, p-val = 0.0023
Test of Moderators (coefficients 2:19):
F(df1 = 18, df2 = 54) = 7.7700, p-val < .0001
Model Results:
estimate se tval pval
intrcpt -0.1934 0.5267 -0.3673 0.7149
traitgrowth 0.4394 0.1659 2.6495 0.0106
traitnutrient content -0.0236 0.5537 -0.0426 0.9662
traitbleaching -0.3965 0.5729 -0.6920 0.4919
traitsymbiont community 0.1802 0.5522 0.3264 0.7454
traitmorphology 0.0921 0.5678 0.1622 0.8718
traitsurvival 0.2155 0.5291 0.4073 0.6854
stagejuvenile -0.0252 0.1976 -0.1273 0.8992
stageadult -0.7392 0.5477 -1.3496 0.1828
h2narrow -0.3513 0.1251 -2.8084 0.0069
traitgrowth:stagejuvenile -1.2859 0.5855 -2.1963 0.0324
traitbleaching:stagejuvenile -0.4027 0.3763 -1.0702 0.2893
traitsymbiont community:stagejuvenile -0.3237 0.6845 -0.4729 0.6382
traitmorphology:stagejuvenile -0.2267 0.3643 -0.6224 0.5363
traitnutrient content:stageadult -0.0805 0.5852 -0.1376 0.8911
traitbleaching:stageadult 1.2575 0.6138 2.0488 0.0454
traitsymbiont community:stageadult 0.6799 0.6024 1.1287 0.2640
traitmorphology:stageadult 0.4721 0.6421 0.7352 0.4654
traitsurvival:stageadult 0.3676 0.5598 0.6567 0.5142
ci.lb ci.ub
intrcpt -1.2493 0.8625
traitgrowth 0.1069 0.7720 *
traitnutrient content -1.1338 1.0866
traitbleaching -1.5451 0.7522
traitsymbiont community -0.9269 1.2873
traitmorphology -1.0464 1.2305
traitsurvival -0.8453 1.2763
stagejuvenile -0.4214 0.3711
stageadult -1.8374 0.3589
h2narrow -0.6021 -0.1005 **
traitgrowth:stagejuvenile -2.4598 -0.1121 *
traitbleaching:stagejuvenile -1.1572 0.3518
traitsymbiont community:stagejuvenile -1.6961 1.0487
traitmorphology:stagejuvenile -0.9571 0.5036
traitnutrient content:stageadult -1.2538 1.0928
traitbleaching:stageadult 0.0269 2.4880 *
traitsymbiont community:stageadult -0.5278 1.8875
traitmorphology:stageadult -0.8153 1.7595
traitsurvival:stageadult -0.7547 1.4899
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
update(final.model.A, .~., data=dat_s[-cdist.i[2],]) # no interaction after removal!
Mixed-Effects Model (k = 73; tau^2 estimator: REML)
tau^2 (estimated amount of residual heterogeneity): 0.0385 (SE = 0.0175)
tau (square root of estimated tau^2 value): 0.1963
I^2 (residual heterogeneity / unaccounted variability): 47.24%
H^2 (unaccounted variability / sampling variability): 1.90
R^2 (amount of heterogeneity accounted for): 78.55%
Test for Residual Heterogeneity:
QE(df = 54) = 95.1290, p-val = 0.0005
Test of Moderators (coefficients 2:19):
F(df1 = 18, df2 = 54) = 8.0025, p-val < .0001
Model Results:
estimate se tval pval
intrcpt -0.2318 0.5313 -0.4363 0.6644
traitgrowth 0.4396 0.1683 2.6122 0.0116
traitnutrient content 0.0148 0.5593 0.0265 0.9789
traitbleaching -0.3590 0.5786 -0.6205 0.5376
traitsymbiont community 0.1793 0.5581 0.3213 0.7492
traitmorphology 0.1305 0.5741 0.2272 0.8211
traitsurvival 0.2342 0.5345 0.4382 0.6630
stagejuvenile 0.1664 0.1725 0.9641 0.3393
stageadult -0.7023 0.5527 -1.2706 0.2093
h2narrow -0.3129 0.1241 -2.5219 0.0147
traitgrowth:stagejuvenile -1.4603 0.5869 -2.4881 0.0160
traitbleaching:stagejuvenile -0.6325 0.3534 -1.7896 0.0791
traitsymbiont community:stagejuvenile -0.5143 0.6838 -0.7521 0.4552
traitmorphology:stagejuvenile -0.8264 0.4563 -1.8112 0.0757
traitnutrient content:stageadult -0.1171 0.5914 -0.1981 0.8437
traitbleaching:stageadult 1.2096 0.6202 1.9503 0.0563
traitsymbiont community:stageadult 0.6822 0.6100 1.1183 0.2684
traitmorphology:stageadult 0.4207 0.6491 0.6482 0.5196
traitsurvival:stageadult 0.3500 0.5657 0.6186 0.5388
ci.lb ci.ub
intrcpt -1.2970 0.8334
traitgrowth 0.1022 0.7769 *
traitnutrient content -1.1064 1.1361
traitbleaching -1.5189 0.8010
traitsymbiont community -0.9397 1.2983
traitmorphology -1.0205 1.2814
traitsurvival -0.8373 1.3057
stagejuvenile -0.1796 0.5123
stageadult -1.8105 0.4059
h2narrow -0.5617 -0.0642 *
traitgrowth:stagejuvenile -2.6371 -0.2836 *
traitbleaching:stagejuvenile -1.3411 0.0761 .
traitsymbiont community:stagejuvenile -1.8852 0.8566
traitmorphology:stagejuvenile -1.7413 0.0884 .
traitnutrient content:stageadult -1.3028 1.0685
traitbleaching:stageadult -0.0338 2.4531 .
traitsymbiont community:stageadult -0.5408 1.9053
traitmorphology:stageadult -0.8806 1.7220
traitsurvival:stageadult -0.7843 1.4842
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
plot(fitted(final.model.A), rstandard(final.model.A)$z)
abline(h=0, lty=2)plot(residuals(final.model.A, type="pearson"))
abline(h=0, lty=2)# Not amazing, not terrible
# Simulate new data given the parameter values of the data and same variance structure, plot on real data to see if it is similar
xsim <- simulate(final.model.A, 100) %>%
mutate(true.val = dat_s$val.log,
weighting = 1/dat_s$sv.log) %>%
pivot_longer(cols=-c(true.val, weighting)) %>%
select(name, true.val, sim.val = value, weighting)
xsim %>%
ggplot(aes(x=true.val, y=sim.val)) +
geom_point(aes(col=weighting), alpha=0.05) +
geom_abline(slope=1, intercept=0, linetype="dashed") +
scale_colour_viridis_c() +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
scale_y_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1))# reruns model, based around the same variance/covariance structures but with simulated data.
xsim %>%
ggplot(aes(y=weighting)) +
geom_point(aes(x=sim.val), col="red", size=2, alpha=0.05) +
geom_point(data= filter(xsim, name == "sim_1"),
aes(x=true.val),
col="blue", size=2, alpha=0.9) +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
labs(x="Heritability estimate", y=expression("Weighting (1/SE"^2*")"))# Seems that the model is in general simulating the true data ok!
# Main problem is that values are simulating beyond the bounds of possible heritability.Main result: trait type x heritability type interaction supported. Most of the interaction is likely driven by the gene expression trait level, where one estimate of narrow-sense h2 is higher than all broad-sense estimates of H2.
dat_sh %>% table.plot("h2", "trait", .) # subset allows examination of h2 x trait typedat_sh %>% table.plot("stage", "trait", .) # can also look at life stage interaction too!dat_sh %>% table.plot("stage", "h2", .)dat_sh %>% table.plot("stage", "growth.form", .) # some bad levels for growth form!The data subset allows for the examination of h2 x trait type interaction, as well as the trait x life stage interaction seen previously!
The beyond-optimal model in this case is a full analysis of trait type x heritability type + trait type x life stage, plus additive effects: \[ logit(h^2) \sim N(\mu, \tau^2) \\ \mu = trait \times stage + trait \times h^2type + growth\,form + \epsilon_{i} \]
m.study.nested <- rma.mv(yi=val.log ~ trait * h2 + trait * stage + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_sh, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.spp.nested <- rma.mv(yi=val.log ~ trait * h2 + trait * stage + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_sh, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.only.est <- rma.mv(yi=val.log ~ trait * h2 + trait * stage + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_sh, method="REML", tdist=T,
sigma2 = c(0, NA)) # same as random = ~1|est.id
m.only.study <- rma.mv(yi=val.log ~ trait * h2 + trait * stage + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_sh, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|study
m.only.spp <- rma.mv(yi=val.log ~ trait * h2 + trait * stage + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_sh, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|species
m.no.reff <- rma.mv(yi=val.log ~ trait * h2 + trait * stage + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_sh, method="REML", tdist=T,
sigma2 = c(0, 0)) # no random effects
TableS5 <- myAIC(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff) %>%
mutate(model = fct_recode(model,
"Estimate ID nested in study ID" = "m.study.nested",
"Estimate ID nested in species" = "m.spp.nested",
"Study ID only" = "m.only.study",
"Species only" = "m.only.spp",
"Estimate ID only" = "m.only.est",
"No random effect" = "m.no.reff"))
write.csv(TableS5, file="Suppl Tables/TableS5.csv", row.names=F)
TableS5| model | df | AICc | ΔAICc |
|---|---|---|---|
| Study ID only | 23 | 161.1380 | 0.0000000 |
| Estimate ID only | 23 | 161.1796 | 0.0416663 |
| No random effect | 23 | 168.1204 | 6.9824555 |
| Estimate ID nested in study ID | 23 | 172.7948 | 11.6568354 |
| Estimate ID nested in species | 23 | 174.4590 | 13.3210780 |
| Species only | 23 | 178.7043 | 17.5662968 |
rm(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff)The optimal model is using study ID-only, however the second-most preferred model uses estimate ID only, and ΔAICc = 0.27, so close call either way. Let’s continue with study ID.
mod_names <- ls(pattern = "m.fixed.")
do.call("rm", as.list(mod_names))
m.fixed.txh.txs.g <- rma.mv(yi=val.log ~ trait*h2 + trait*stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txh.txs <- rma.mv(yi=val.log ~ trait*h2 + trait*stage,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txh.s.g <- rma.mv(yi=val.log ~ trait*h2 + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txh.s <- rma.mv(yi=val.log ~ trait*h2 + stage,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txh.g <- rma.mv(yi=val.log ~ trait*h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txh <- rma.mv(yi=val.log ~ trait*h2,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txs.h.g <- rma.mv(yi=val.log ~ trait*stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txs.h <- rma.mv(yi=val.log ~ trait*stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txs.g <- rma.mv(yi=val.log ~ trait*stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txs <- rma.mv(yi=val.log ~ trait*stage,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.s.h.g <- rma.mv(yi=val.log ~ trait + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.s.h <- rma.mv(yi=val.log ~ trait + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.s.g <- rma.mv(yi=val.log ~ trait + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.h.g <- rma.mv(yi=val.log ~ trait + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.s.h.g <- rma.mv(yi=val.log ~ stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.s <- rma.mv(yi=val.log ~ trait + stage,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.h <- rma.mv(yi=val.log ~ trait + h2,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.g <- rma.mv(yi=val.log ~ trait + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.s.h <- rma.mv(yi=val.log ~ stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.s.g <- rma.mv(yi=val.log ~ stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.h.g <- rma.mv(yi=val.log ~ h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t <- rma.mv(yi=val.log ~ trait,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.s <- rma.mv(yi=val.log ~ stage,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.h <- rma.mv(yi=val.log ~ h2,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.g <- rma.mv(yi=val.log ~ growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.null <- rma.mv(yi=val.log ~ 1,
V=sv.log, random = ~1|study/est.id, data=dat_sh,
method="ML", tdist=T, sigma2 = c(NA, 0))
mod_names <- ls(pattern = "m.fixed.")
TableS6 <- head(do.call("myAIC", as.list(c(mod_names, getmodel=T)))) %>%
mutate(model = fct_recode(model,
"trait x life stage" = "m.fixed.txs",
"trait x life stage + heritability type" = "m.fixed.txs.h",
"trait x life stage + trait x heritability type" = "m.fixed.txh.txs",
"trait x heritability type + life stage" = "m.fixed.txh.s",
"trait + heritability type" = "m.fixed.txh",
"trait x life stage + growth form" = "m.fixed.txs.g"))
write.csv(TableS6, file="Suppl Tables/TableS6.csv", row.names=F)
TableS6| model | df | AICc | ΔAICc |
|---|---|---|---|
| trait x life stage | 15 | 78.15443 | 0.000000 |
| trait x life stage + heritability type | 16 | 80.83149 | 2.677067 |
| trait x life stage + trait x heritability type | 19 | 84.42971 | 6.275287 |
| trait + heritability type | 11 | 87.69613 | 9.541702 |
| trait x heritability type + life stage | 13 | 89.18243 | 11.028005 |
| trait x life stage + growth form | 19 | 91.08915 | 12.934727 |
A model of trait type x life stage only is preferred! The next closest model is one with trait type x life stage + heritability type (ΔAICc = 2.15).
final.model.B <- rma.mv(yi=val.log ~ trait*stage,
V=sv.log, random = ~1|study/est.id,
data=dat_sh, method="REML", tdist=T, sigma2 = c(NA, 0))
rma(yi=val.log ~ trait*stage,
vi=sv.log, random = ~1|study,
data=dat_sh, method="REML", test="knha")
Mixed-Effects Model (k = 67; tau^2 estimator: REML)
tau^2 (estimated amount of residual heterogeneity): 0.0506 (SE = 0.0214)
tau (square root of estimated tau^2 value): 0.2249
I^2 (residual heterogeneity / unaccounted variability): 59.08%
H^2 (unaccounted variability / sampling variability): 2.44
R^2 (amount of heterogeneity accounted for): 71.18%
Test for Residual Heterogeneity:
QE(df = 51) = 98.0787, p-val < .0001
Test of Moderators (coefficients 2:16):
F(df1 = 15, df2 = 51) = 6.3854, p-val < .0001
Model Results:
estimate se tval pval
intrcpt -0.5447 0.5338 -1.0205 0.3123
traitgrowth 0.4409 0.1788 2.4665 0.0170
traitbleaching -0.0513 0.5871 -0.0874 0.9307
traitsymbiont community 0.1741 0.5801 0.3001 0.7653
traitmorphology 0.4434 0.5869 0.7554 0.4535
traitsurvival 0.3882 0.5499 0.7060 0.4834
stagejuvenile 0.1248 0.1932 0.6457 0.5214
stageadult -0.3981 0.5575 -0.7140 0.4785
traitgrowth:stagejuvenile -1.2857 0.6089 -2.1115 0.0396
traitbleaching:stagejuvenile -0.9029 0.3637 -2.4826 0.0164
traitsymbiont community:stagejuvenile -0.4675 0.7096 -0.6588 0.5130
traitmorphology:stagejuvenile -0.6348 0.3765 -1.6864 0.0978
traitbleaching:stageadult 0.8123 0.6270 1.2954 0.2010
traitsymbiont community:stageadult 0.6961 0.6417 1.0848 0.2831
traitmorphology:stageadult -0.0036 0.6569 -0.0056 0.9956
traitsurvival:stageadult 0.2024 0.5845 0.3463 0.7305
ci.lb ci.ub
intrcpt -1.6164 0.5269
traitgrowth 0.0820 0.7998 *
traitbleaching -1.2299 1.1273
traitsymbiont community -0.9906 1.3387
traitmorphology -0.7350 1.6217
traitsurvival -0.7158 1.4923
stagejuvenile -0.2632 0.5127
stageadult -1.5173 0.7212
traitgrowth:stagejuvenile -2.5081 -0.0633 *
traitbleaching:stagejuvenile -1.6330 -0.1727 *
traitsymbiont community:stagejuvenile -1.8920 0.9570
traitmorphology:stagejuvenile -1.3906 0.1209 .
traitbleaching:stageadult -0.4466 2.0711
traitsymbiont community:stageadult -0.5922 1.9844
traitmorphology:stageadult -1.3224 1.3151
traitsurvival:stageadult -0.9711 1.3760
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# final.model.B
save(final.model.B, file="Models/final.model.B.Rdata")
mlm.variance.distribution(final.model.B)| % of total variance | I2 | |
|---|---|---|
| Level 1 | 25.04703 | — |
| Level 2 | 0.00000 | 0 |
| Level 3 | 74.95297 | 74.95 |
final.model.B$k - final.model.B$p[1] 51
Without the effect of heritability type, juvenile bleaching also is a significant interaction term!
x <- resid(final.model.B)
hist(x) # looks approx. normal, except for one strong outlier at -1.5par(mfrow=c(2,1))
funnel(final.model.B)
funnel(final.model.B, yaxis = "vinv")par(mfrow=c(1,1))
dat_sh[x < -1,] %>% select(study, species, trait, stage, h2, val)| study | species | trait | stage | h2 | val | |
|---|---|---|---|---|---|---|
| 15 | Quigley et al. 2020 | Acropora spathulata | survival | juvenile | narrow | 0.00038 |
# update(final.model.B, .~., data=dat_sh[x > -1,]) %>%
# funnel() # Funnel looks good once that one point is removed!fsn(yi=val.log, vi=sv.log, data=dat_sh, type="Rosenberg") # N=513 to get no significance (but assumes fixed effects)
Fail-safe N Calculation Using the Rosenberg Approach
Average Effect Size: -0.0477
Observed Significance Level: 0.0009
Target Significance Level: 0.05
Fail-safe N: 127
# Number of studies x5 + 10:
length(unique(dat_sh$study))*5 + 10[1] 100
cdist <- cooks.distance(final.model.B, reestimate=FALSE)
plot(cdist)
cdist.i <- which(cdist >2)
points(cdist.i, cdist[cdist.i], col="red", pch=16)dat_sh[cdist.i,] %>% select(study, trait, stage, h2, val) %>% mutate(cdist = cdist[cdist.i])| study | trait | stage | h2 | val | cdist |
|---|---|---|---|---|---|
| Kenkel et al. 2015 | survival | juvenile | broad | 0.9400000 | 8.992638 |
| Quigley et al. 2020 | survival | juvenile | narrow | 0.9300000 | 13.235339 |
| Manzello et al. 2019 | bleaching | adult | broad | 0.9300000 | 60.246805 |
| Zhang et al. 2019 | bleaching | larvae | broad | 0.4511525 | 2.069310 |
| Quigley et al. 2020 | bleaching | juvenile | narrow | 0.1500000 | 2.488141 |
| Császár et al. 2010 | growth | adult | broad | 0.5900000 | 6.604630 |
update(final.model.B, .~., data=dat_sh[-cdist.i[1],])
Multivariate Meta-Analysis Model (k = 66; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.0726 0.2694 18 no study
sigma^2.2 0.0000 0.0000 66 yes study/est.id
Test for Residual Heterogeneity:
QE(df = 50) = 97.6866, p-val < .0001
Test of Moderators (coefficients 2:16):
F(df1 = 15, df2 = 50) = 13.7493, p-val < .0001
Model Results:
estimate se tval pval
intrcpt -0.4900 0.5603 -0.8744 0.3861
traitgrowth 0.5823 0.1601 3.6365 0.0007
traitbleaching 0.0216 0.6175 0.0350 0.9722
traitsymbiont community 0.1121 0.6178 0.1814 0.8568
traitmorphology 0.4845 0.5986 0.8093 0.4222
traitsurvival 0.3098 0.5696 0.5439 0.5890
stagejuvenile 0.5172 0.2683 1.9274 0.0596
stageadult -0.5949 0.5961 -0.9980 0.3231
traitgrowth:stagejuvenile -1.8358 0.6121 -2.9992 0.0042
traitbleaching:stagejuvenile -1.1454 0.3094 -3.7023 0.0005
traitsymbiont community:stagejuvenile -0.9659 0.7138 -1.3533 0.1821
traitmorphology:stagejuvenile -1.0902 0.4303 -2.5337 0.0145
traitbleaching:stageadult 0.8833 0.6623 1.3336 0.1884
traitsymbiont community:stageadult 0.6005 0.6652 0.9027 0.3710
traitmorphology:stageadult 0.1383 0.7203 0.1920 0.8485
traitsurvival:stageadult 0.7554 0.6052 1.2482 0.2178
ci.lb ci.ub
intrcpt -1.6154 0.6355
traitgrowth 0.2607 0.9039 ***
traitbleaching -1.2187 1.2619
traitsymbiont community -1.1288 1.3529
traitmorphology -0.7179 1.6869
traitsurvival -0.8343 1.4539
stagejuvenile -0.0218 1.0561 .
stageadult -1.7923 0.6025
traitgrowth:stagejuvenile -3.0653 -0.6064 **
traitbleaching:stagejuvenile -1.7668 -0.5240 ***
traitsymbiont community:stagejuvenile -2.3996 0.4677
traitmorphology:stagejuvenile -1.9545 -0.2260 *
traitbleaching:stageadult -0.4470 2.2135
traitsymbiont community:stageadult -0.7356 1.9366
traitmorphology:stageadult -1.3085 1.5850
traitsurvival:stageadult -0.4602 1.9710
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# dat_sh %>% table.plot("stage", "trait", .) Plot the coefficients with different model datasets:
dat_sh.out1 <- update(final.model.B, .~., data=dat_sh[-cdist.i[1],])
dat_sh.out2 <- update(final.model.B, .~., data=dat_sh[-cdist.i[2],])
dat_sh.out3 <- update(final.model.B, .~., data=dat_sh[-cdist.i[3],])
dat_sh.out4 <- update(final.model.B, .~., data=dat_sh[-cdist.i[4],])
dat_sh.out5 <- update(final.model.B, .~., data=dat_sh[-cdist.i[5],])
dat_sh.out.all <- update(final.model.B, .~., data=dat_sh[-cdist.i[c(1,2,3,5)],])
rbind(
data.frame(
Model = rep(" Original model fit"),
Parameter = names(coef(final.model.B)),
Estimate = coef(final.model.B),
SE = final.model.B$se),
data.frame(
Model = rep(paste0(" without Kenkel et al. 2015 - juvenile survival\nCook's dist = ",round(cdist[cdist.i[1]],1))),
Parameter = names(coef(dat_sh.out1)),
Estimate = coef(dat_sh.out1),
SE = dat_sh.out1$se),
data.frame(
Model = rep(paste0(" without Quigley et al. 2020 - juvenile survival\nCook's dist = ",round(cdist[cdist.i[2]],1))),
Parameter = names(coef(dat_sh.out2)),
Estimate = coef(dat_sh.out2),
SE = dat_sh.out2$se),
data.frame(
Model = rep(paste0(" without Manzello et al. 2019 - adult bleaching\nCook's dist = ",round(cdist[cdist.i[3]],1))),
Parameter = names(coef(dat_sh.out3)),
Estimate = coef(dat_sh.out3),
SE = dat_sh.out3$se),
data.frame(
Model = rep(paste0(" without Quigley et al. 2020 - juvenile bleaching\nCook's dist = ",round(cdist[cdist.i[4]],1))),
Parameter = names(coef(dat_sh.out4)),
Estimate = coef(dat_sh.out4),
SE = dat_sh.out4$se),
data.frame(
Model = rep(paste0(" without Császár et al. 2010 - adult growth\nCook's dist = ",round(cdist[cdist.i[5]],1))),
Parameter = names(coef(dat_sh.out5)),
Estimate = coef(dat_sh.out5),
SE = dat_sh.out5$se),
data.frame(
Model = rep(paste0("without estimates with Cook's distance > 5")),
Parameter = names(coef(dat_sh.out.all)),
Estimate = coef(dat_sh.out.all),
SE = dat_sh.out.all$se)) %>%
mutate(Parameter = factor(Parameter),
Parameter = fct_relevel(Parameter, "intrcpt")) %>%
ggplot(aes(x=Estimate, y=Parameter, color=Model)) +
geom_vline(xintercept=0, linetype="dashed") +
geom_pointrange(aes(xmin = Estimate - SE, xmax = Estimate + SE), position = position_dodge(width=0.3)) +
labs(x="Parameter estimate (log[X+0.2] scale) ± SE") +
theme(legend.position="top", legend.direction="vertical")plot(fitted(final.model.B), rstandard(final.model.B)$z)
abline(h=0, lty=2)plot(residuals(final.model.B, type="pearson"))
abline(h=0, lty=2)# Not amazing, not terrible
# Simulate new data given the parameter values of the data and same variance structure, plot on real data to see if it is similar
xsim <- simulate(final.model.B, 100) %>%
mutate(true.val = dat_sh$val.log,
weighting = 1/dat_sh$sv.log) %>%
pivot_longer(cols=-c(true.val, weighting)) %>%
select(name, true.val, sim.val = value, weighting)
xsim %>%
ggplot(aes(x=true.val, y=sim.val)) +
geom_point(aes(col=weighting), alpha=0.05) +
geom_abline(slope=1, intercept=0, linetype="dashed") +
scale_colour_viridis_c() +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
scale_y_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1))# reruns model, based around the same variance/covariance structures but with simulated data.
xsim %>%
ggplot(aes(y=weighting)) +
geom_point(aes(x=sim.val), col="red", size=2, alpha=0.05) +
geom_point(data= filter(xsim, name == "sim_1"),
aes(x=true.val),
col="blue", size=2, alpha=0.9) +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
labs(x="Heritability estimate", y=expression("Weighting (1/SE"^2*")"))# Seems that the model is in general simulating the true data ok!
# Main problem is that values are simulating beyond the bounds of possible heritability.For this analysis, note that there are only three estimates for encrusting species (Montipora capitata, Montipora flabellate, Montipora patula) and only a single estimate for columnar coral (Porites evermanni). Thus, we initially lumped these species into an ‘Other’ category, but quickly found that they lacked most of the trait and life stage combinations in order to be included in any analysis.
dat_shg %>% table.plot("growth.form", "trait", .)dat_shg %>% table.plot("stage", "trait", .) # can also look at life stage interaction toodat_shg %>% table.plot("stage", "h2", .)dat_shg %>% table.plot("h2", "growth.form", .)The beyond-optimal model in this case is a full analysis of trait type x growth form + trait type x life stage, plus additive effects: \[ logit(h^2) \sim N(\mu, \tau^2) \\ \mu = trait \times growth\,form + trait \times stage + h^2type + \epsilon_{i} \]
# growth form without h2:
m.study.nested <- rma.mv(yi=val.log ~ trait * growth.form + trait * stage + h2,
V=sv.log, random = ~1|study/est.id,
data=dat_shg, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.spp.nested <- rma.mv(yi=val.log ~ trait * growth.form + trait * stage + h2,
V=sv.log, random = ~1|species/est.id,
data=dat_shg, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.only.est <- rma.mv(yi=val.log ~ trait * growth.form + trait * stage + h2,
V=sv.log, random = ~1|study/est.id,
data=dat_shg, method="REML", tdist=T,
sigma2 = c(0, NA)) # same as random = ~1|est.id
m.only.study <- rma.mv(yi=val.log ~ trait * growth.form + trait * stage + h2,
V=sv.log, random = ~1|study/est.id,
data=dat_shg, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|study
m.only.spp <- rma.mv(yi=val.log ~ trait * growth.form + trait * stage + h2,
V=sv.log, random = ~1|species/est.id,
data=dat_shg, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|species
m.no.reff <- rma.mv(yi=val.log ~ trait * growth.form + trait * stage + h2,
V=sv.log, random = ~1|study/est.id,
data=dat_shg, method="REML", tdist=T,
sigma2 = c(0, 0)) # no random effects
TableS7 <- myAIC(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff) %>%
mutate(model = fct_recode(model,
"Estimate ID nested in study ID" = "m.study.nested",
"Estimate ID nested in species" = "m.spp.nested",
"Study ID only" = "m.only.study",
"Species only" = "m.only.spp",
"Estimate ID only" = "m.only.est",
"No random effect" = "m.no.reff"))
write.csv(TableS7, file="Suppl Tables/TableS7.csv", row.names=F)
TableS7| model | df | AICc | ΔAICc |
|---|---|---|---|
| Study ID only | 18 | 120.6457 | 0.0000000 |
| Estimate ID only | 18 | 121.1527 | 0.5070027 |
| No random effect | 18 | 122.5166 | 1.8708784 |
| Estimate ID nested in study ID | 18 | 132.7621 | 12.1163709 |
| Species only | 18 | 133.0640 | 12.4182707 |
| Estimate ID nested in species | 18 | 134.2297 | 13.5839257 |
rm(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff)Study ID only is preferred, estimate ID is close to optimal as well (ΔAIC=0.5), and null effects structure may also be preferred (ΔAIC=1.9). Continuing with study ID as the random effect…
mod_names <- ls(pattern = "m.fixed.")
do.call("rm", as.list(mod_names))
m.fixed.txg.txs.h <- rma.mv(yi=val.log ~ trait*growth.form + trait*stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txg.txs <- rma.mv(yi=val.log ~ trait*growth.form + trait*stage,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txg.s.h <- rma.mv(yi=val.log ~ trait*growth.form + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txg.s <- rma.mv(yi=val.log ~ trait*growth.form + stage,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txg.h <- rma.mv(yi=val.log ~ trait*growth.form + h2,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txg <- rma.mv(yi=val.log ~ trait*growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txs.h.g <- rma.mv(yi=val.log ~ trait*stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txs.h <- rma.mv(yi=val.log ~ trait*stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txs.g <- rma.mv(yi=val.log ~ trait*stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.txs <- rma.mv(yi=val.log ~ trait*stage,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.s.h.g <- rma.mv(yi=val.log ~ trait + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.s.h <- rma.mv(yi=val.log ~ trait + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.s.g <- rma.mv(yi=val.log ~ trait + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.h.g <- rma.mv(yi=val.log ~ trait + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.s.h.g <- rma.mv(yi=val.log ~ stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.s <- rma.mv(yi=val.log ~ trait + stage,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.h <- rma.mv(yi=val.log ~ trait + h2,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t.g <- rma.mv(yi=val.log ~ trait + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.s.h <- rma.mv(yi=val.log ~ stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.s.g <- rma.mv(yi=val.log ~ stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.h.g <- rma.mv(yi=val.log ~ h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.t <- rma.mv(yi=val.log ~ trait,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.s <- rma.mv(yi=val.log ~ stage,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.h <- rma.mv(yi=val.log ~ h2,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.g <- rma.mv(yi=val.log ~ growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
m.fixed.null <- rma.mv(yi=val.log ~ 1,
V=sv.log, random = ~1|study/est.id, data=dat_shg,
method="ML", tdist=T, sigma2 = c(NA, 0))
mod_names <- ls(pattern = "m.fixed.")
TableS8 <- head(do.call("myAIC", as.list(c(mod_names, getmodel=T)))) %>%
mutate(model = fct_recode(model,
"trait x life stage" = "m.fixed.txs",
"trait x life stage + heritability type" = "m.fixed.txs.h",
"trait x life stage + trait x growth form + heritability type" = "m.fixed.txg.txs.h",
"trait x life stage + trait x growth form" = "m.fixed.txg.txs",
"trait x life stage + growth form" = "m.fixed.txs.g",
"trait x life stage + heritability type + growth form" = "m.fixed.txs.h.g"))
write.csv(TableS8, file="Suppl Tables/TableS8.csv", row.names=F)
TableS8| model | df | AICc | ΔAICc |
|---|---|---|---|
| trait x life stage | 12 | 57.98042 | 0.000000 |
| trait x life stage + heritability type | 13 | 60.54629 | 2.565869 |
| trait x life stage + growth form | 14 | 64.92559 | 6.945171 |
| trait x life stage + trait x growth form + heritability type | 18 | 64.99195 | 7.011524 |
| trait x life stage + trait x growth form | 17 | 65.29626 | 7.315839 |
| trait x life stage + heritability type + growth form | 15 | 67.87557 | 9.895152 |
final.model.C <- rma.mv(yi=val.log ~ trait*stage,
V=sv.log, random = ~1|study/est.id,
data=dat_shg, method="REML", tdist=T, sigma2 = c(NA, 0))
final.model.C
Multivariate Meta-Analysis Model (k = 54; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.0529 0.2299 17 no study
sigma^2.2 0.0000 0.0000 54 yes study/est.id
Test for Residual Heterogeneity:
QE(df = 41) = 93.9742, p-val < .0001
Test of Moderators (coefficients 2:13):
F(df1 = 12, df2 = 41) = 23.6844, p-val < .0001
Model Results:
estimate se tval pval
intrcpt -0.6172 0.1912 -3.2273 0.0025
traitnutrient content 0.4909 0.2465 1.9919 0.0531
traitbleaching 0.1467 0.2912 0.5039 0.6170
traitsymbiont community 0.2457 0.3067 0.8011 0.4277
traitsurvival 0.4578 0.1300 3.5205 0.0011
stagejuvenile -0.5560 0.2683 -2.0725 0.0445
stageadult 0.1402 0.1997 0.7022 0.4865
traitbleaching:stagejuvenile -0.2689 0.3408 -0.7891 0.4346
traitsymbiont community:stagejuvenile 0.1181 0.7130 0.1656 0.8693
traitsurvival:stagejuvenile 0.8090 0.1631 4.9600 <.0001
traitnutrient content:stageadult -0.7353 0.2389 -3.0780 0.0037
traitbleaching:stageadult 0.1797 0.3139 0.5725 0.5701
traitsymbiont community:stageadult -0.1109 0.3336 -0.3325 0.7412
ci.lb ci.ub
intrcpt -1.0034 -0.2310 **
traitnutrient content -0.0068 0.9887 .
traitbleaching -0.4413 0.7347
traitsymbiont community -0.3736 0.8650
traitsurvival 0.1952 0.7204 **
stagejuvenile -1.0977 -0.0142 *
stageadult -0.2630 0.5434
traitbleaching:stagejuvenile -0.9572 0.4193
traitsymbiont community:stagejuvenile -1.3218 1.5580
traitsurvival:stagejuvenile 0.4796 1.1384 ***
traitnutrient content:stageadult -1.2177 -0.2528 **
traitbleaching:stageadult -0.4542 0.8136
traitsymbiont community:stageadult -0.7847 0.5628
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
save(final.model.C, file="Models/final.model.C.Rdata")
mlm.variance.distribution(final.model.C)| % of total variance | I2 | |
|---|---|---|
| Level 1 | 20.66957 | — |
| Level 2 | 0.00000 | 0 |
| Level 3 | 79.33043 | 79.33 |
final.model.C$k - final.model.C$p[1] 41
A final fixed effect structure of ~trait type x life stage + heritability type (for estimate-ID only random effect) or ~trait type x life stage (for study-ID only random effect).
x <- resid(final.model.C)
hist(x) # looks approx. normal, except for one strong outlier at -1.5par(mfrow=c(2,1))
funnel(final.model.C)
funnel(final.model.C, yaxis = "vinv")par(mfrow=c(1,1))
dat_shg[x < -1,] %>% select(study, species, trait, stage, h2, val)| study | species | trait | stage | h2 | val | |
|---|---|---|---|---|---|---|
| 15 | Quigley et al. 2020 | Acropora spathulata | survival | juvenile | narrow | 0.00038 |
update(final.model.C, .~., data=dat_shg[x > -1,]) %>%
funnel()Funnel looks good once that one category with n=1 is removed!
fsn(yi=val.log, vi=sv.log, data=dat_shg, type="Rosenberg") # N=513 to get no significance (but assumes fixed effects)
Fail-safe N Calculation Using the Rosenberg Approach
Average Effect Size: -0.0512
Observed Significance Level: 0.0004
Target Significance Level: 0.05
Fail-safe N: 122
# Number of studies x5 + 10:
length(unique(dat_shg$study))*5 + 10[1] 95
cdist <- cooks.distance(final.model.C, reestimate=FALSE)
plot(cdist)
cdist.i <- which(cdist >2)
points(cdist.i, cdist[cdist.i], col="red", pch=16)dat_shg[cdist.i,] %>% select(study, trait, stage, h2, val) %>% mutate(cdist = cdist[cdist.i])| study | trait | stage | h2 | val | cdist |
|---|---|---|---|---|---|
| Kenkel et al. 2015 | survival | juvenile | broad | 0.9400000 | 9.213022 |
| Quigley et al. 2020 | survival | juvenile | narrow | 0.9300000 | 13.513205 |
| Manzello et al. 2019 | bleaching | adult | broad | 0.9300000 | 58.185574 |
| Zhang et al. 2019 | bleaching | larvae | broad | 0.4511525 | 2.085304 |
| Quigley et al. 2020 | bleaching | juvenile | narrow | 0.1500000 | 2.487176 |
update(final.model.C, .~., data=dat_shg[-cdist.i[3],])
Multivariate Meta-Analysis Model (k = 53; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.0393 0.1983 17 no study
sigma^2.2 0.0000 0.0000 53 yes study/est.id
Test for Residual Heterogeneity:
QE(df = 40) = 80.6448, p-val = 0.0001
Test of Moderators (coefficients 2:13):
F(df1 = 12, df2 = 40) = 23.0564, p-val < .0001
Model Results:
estimate se tval pval
intrcpt -0.5565 0.1800 -3.0911 0.0036
traitnutrient content 0.4251 0.2385 1.7826 0.0822
traitbleaching 0.0809 0.2844 0.2844 0.7776
traitsymbiont community 0.1907 0.2877 0.6629 0.5112
traitsurvival 0.4162 0.1280 3.2522 0.0023
stagejuvenile -0.6165 0.2471 -2.4954 0.0168
stageadult 0.0554 0.1862 0.2974 0.7677
traitbleaching:stagejuvenile -0.2038 0.3350 -0.6084 0.5464
traitsymbiont community:stagejuvenile 0.1884 0.7046 0.2674 0.7906
traitsurvival:stagejuvenile 0.8508 0.1615 5.2696 <.0001
traitnutrient content:stageadult -0.7129 0.2317 -3.0766 0.0038
traitbleaching:stageadult 0.0633 0.3210 0.1973 0.8446
traitsymbiont community:stageadult 0.2378 0.3573 0.6657 0.5094
ci.lb ci.ub
intrcpt -0.9204 -0.1926 **
traitnutrient content -0.0569 0.9071 .
traitbleaching -0.4940 0.6557
traitsymbiont community -0.3908 0.7722
traitsurvival 0.1575 0.6748 **
stagejuvenile -1.1158 -0.1172 *
stageadult -0.3209 0.4317
traitbleaching:stagejuvenile -0.8810 0.4733
traitsymbiont community:stagejuvenile -1.2357 1.6125
traitsurvival:stagejuvenile 0.5245 1.1771 ***
traitnutrient content:stageadult -1.1812 -0.2446 **
traitbleaching:stageadult -0.5854 0.7121
traitsymbiont community:stageadult -0.4843 0.9599
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Plot the coefficients with different model datasets:
dat_shg.out1 <- update(final.model.C, .~., data=dat_shg[-cdist.i[1],])
dat_shg.out2 <- update(final.model.C, .~., data=dat_shg[-cdist.i[2],])
dat_shg.out3 <- update(final.model.C, .~., data=dat_shg[-cdist.i[3],])
dat_shg.out4 <- update(final.model.C, .~., data=dat_shg[-cdist.i[4],])
dat_shg.out5 <- update(final.model.C, .~., data=dat_shg[-cdist.i[5],])
dat_shg.out.all <- update(final.model.C, .~., data=dat_shg[-cdist.i[c(1,2,3,5)],])
rbind(
data.frame(
Model = rep(" Original model fit"),
Parameter = names(coef(final.model.C)),
Estimate = coef(final.model.C),
SE = final.model.C$se),
data.frame(
Model = rep(paste0(" without Kenkel et al. 2015 - juvenile survival\nCook's dist = ",round(cdist[cdist.i[1]],1))),
Parameter = names(coef(dat_shg.out1)),
Estimate = coef(dat_shg.out1),
SE = dat_shg.out1$se),
data.frame(
Model = rep(paste0(" without Quigley et al. 2020 - juvenile survival\nCook's dist = ",round(cdist[cdist.i[2]],1))),
Parameter = names(coef(dat_shg.out2)),
Estimate = coef(dat_shg.out2),
SE = dat_shg.out2$se),
data.frame(
Model = rep(paste0(" without Manzello et al. 2019 - adult bleaching\nCook's dist = ",round(cdist[cdist.i[3]],1))),
Parameter = names(coef(dat_shg.out3)),
Estimate = coef(dat_shg.out3),
SE = dat_shg.out3$se),
data.frame(
Model = rep(paste0(" without Quigley et al. 2020 - juvenile bleaching\nCook's dist = ",round(cdist[cdist.i[4]],1))),
Parameter = names(coef(dat_shg.out4)),
Estimate = coef(dat_shg.out4),
SE = dat_shg.out4$se),
data.frame(
Model = rep(paste0(" without Császár et al. 2010 - adult growth\nCook's dist = ",round(cdist[cdist.i[5]],1))),
Parameter = names(coef(dat_shg.out5)),
Estimate = coef(dat_shg.out5),
SE = dat_shg.out5$se),
data.frame(
Model = rep(paste0("without estimates with Cook's distance > 5")),
Parameter = names(coef(dat_shg.out.all)),
Estimate = coef(dat_shg.out.all),
SE = dat_shg.out.all$se)) %>%
mutate(Parameter = factor(Parameter),
Parameter = fct_relevel(Parameter, "intrcpt")) %>%
ggplot(aes(x=Estimate, y=Parameter, color=Model)) +
geom_vline(xintercept=0, linetype="dashed") +
geom_pointrange(aes(xmin = Estimate - SE, xmax = Estimate + SE), position = position_dodge(width=0.3)) +
labs(x="Parameter estimate (log[X+0.2] scale) ± SE") +
theme(legend.position="top", legend.direction="vertical")plot(fitted(final.model.C), rstandard(final.model.C)$z)
abline(h=0, lty=2)plot(residuals(final.model.C, type="pearson"))
abline(h=0, lty=2)# Not amazing, not terrible
# Simulate new data given the parameter values of the data and same variance structure, plot on real data to see if it is similar
xsim <- simulate(final.model.C, 100) %>%
mutate(true.val = dat_shg$val.log,
weighting = 1/dat_shg$sv.log) %>%
pivot_longer(cols=-c(true.val, weighting)) %>%
select(name, true.val, sim.val = value, weighting)
xsim %>%
ggplot(aes(x=true.val, y=sim.val)) +
geom_point(aes(col=weighting), alpha=0.05) +
geom_abline(slope=1, intercept=0, linetype="dashed") +
scale_colour_viridis_c() +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
scale_y_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1))# reruns model, based around the same variance/covariance structures but with simulated data.
xsim %>%
ggplot(aes(y=weighting)) +
geom_point(aes(x=sim.val), col="red", size=2, alpha=0.05) +
geom_point(data= filter(xsim, name == "sim_1"),
aes(x=true.val),
col="blue", size=2, alpha=0.9) +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
labs(x="Heritability estimate", y=expression("Weighting (1/SE"^2*")"))Seems that the model is in general simulating the true data ok. Main problem is that values are simulating beyond the bounds of possible heritability.
dat_tm %>% pull(temp.diff) %>% hist() # some high values, use a sqrt-transform to make more normally distributed!dat_tm %>% pull(temp.diff) %>% sqrt() %>% hist() # better!dat_tm %>% table.plot("stage", "trait", .) # no other interactions possible!dat_tm %>% table.plot("h2", "trait", .) # no other interactions possible!dat_tm %>% table.plot("growth.form", "trait", .) # no other interactionsLife stage, heritability type, and growth form are all signular for the photochemistry and immune response categories (all entirely overlapping for these trait types) ### Step 1: Define beyond optimal model
Beyond optimal is simply trait x temp differential: this sub-analysis. \[ logit(h^2) \sim N(\mu, \tau^2) \\ \mu = trait_k \times sqrt(temp\;diff) + stage + h^2type + growth\;form \, + \, \epsilon_{i} \]
m.study.nested <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.spp.nested <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.only.est <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(0, NA)) # same as random = ~1|est.id
m.only.study <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|study
m.only.spp <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|species
m.no.reff <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(0, 0)) # no random effects
TableS9 <- myAIC(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff) %>%
mutate(model = fct_recode(model,
"Estimate ID nested in study ID" = "m.study.nested",
"Estimate ID nested in species" = "m.spp.nested",
"Study ID only" = "m.only.study",
"Species only" = "m.only.spp",
"Estimate ID only" = "m.only.est",
"No random effect" = "m.no.reff"))
write.csv(TableS9, file="Suppl Tables/TableS9.csv", row.names=F)
TableS9| model | df | AICc | ΔAICc |
|---|---|---|---|
| Estimate ID nested in study ID | 18 | 106.2510 | 0.000000 |
| Estimate ID only | 18 | 109.9066 | 3.655575 |
| Estimate ID nested in species | 18 | 115.7686 | 9.517644 |
| Study ID only | 18 | 122.1959 | 15.944893 |
| No random effect | 18 | 212.4151 | 106.164141 |
| Species only | 18 | 212.4499 | 106.198954 |
rm(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff)The nested estimate ID within study ID random effects structure is preferred. The next closest is estimate ID-only, with ΔAICc = 3.69.
mod_names <- ls(pattern = "m.fixed.")
do.call("rm", as.list(mod_names))
m.fixed.txm.s.h.g <-
rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.s.h <-
rma.mv(yi=val.log ~ trait*temp.s + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.s.g <-
rma.mv(yi=val.log ~ trait*temp.s + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.h.g <-
rma.mv(yi=val.log ~ trait*temp.s + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.s <-
rma.mv(yi=val.log ~ trait*temp.s + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.h <-
rma.mv(yi=val.log ~ trait*temp.s + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.g <-
rma.mv(yi=val.log ~ trait*temp.s + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm <-
rma.mv(yi=val.log ~ trait*temp.s,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.s.h.g <-
rma.mv(yi=val.log ~ trait + temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.s.h <-
rma.mv(yi=val.log ~ trait + temp.s + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.s.g <-
rma.mv(yi=val.log ~ trait + temp.s + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.h.g <-
rma.mv(yi=val.log ~ trait + temp.s + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.s.h.g <-
rma.mv(yi=val.log ~ trait + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.s.h.g <-
rma.mv(yi=val.log ~ temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.s <-
rma.mv(yi=val.log ~ trait + temp.s + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.h <-
rma.mv(yi=val.log ~ trait + temp.s + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.g <-
rma.mv(yi=val.log ~ trait + temp.s + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.s.h <-
rma.mv(yi=val.log ~ trait + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.s.g <-
rma.mv(yi=val.log ~ trait + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.h.g <-
rma.mv(yi=val.log ~ trait + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.s.h <-
rma.mv(yi=val.log ~ temp.s + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.s.g <-
rma.mv(yi=val.log ~ temp.s + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.h.g <-
rma.mv(yi=val.log ~ temp.s + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.s.h.g <-
rma.mv(yi=val.log ~ stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m <-
rma.mv(yi=val.log ~ trait + temp.s,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.s <-
rma.mv(yi=val.log ~ trait + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.h <-
rma.mv(yi=val.log ~ trait + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.g <-
rma.mv(yi=val.log ~ trait + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.s <-
rma.mv(yi=val.log ~ temp.s + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.h <-
rma.mv(yi=val.log ~ temp.s + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.g <-
rma.mv(yi=val.log ~ temp.s + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.s.h <-
rma.mv(yi=val.log ~ stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.s.g <-
rma.mv(yi=val.log ~ stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.h.g <-
rma.mv(yi=val.log ~ h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t <-
rma.mv(yi=val.log ~ trait,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m <-
rma.mv(yi=val.log ~ temp.s,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.s <-
rma.mv(yi=val.log ~ stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.h <-
rma.mv(yi=val.log ~ h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.g <-
rma.mv(yi=val.log ~ growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.null <-
rma.mv(yi=val.log ~ 1,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
mod_names <- ls(pattern = "m.fixed.")
TableS10 <- head(do.call("myAIC", as.list(c(mod_names, getmodel=T)))) %>%
mutate(model = fct_recode(model,
"trait + heritability type" = "m.fixed.t.h",
"trait" = "m.fixed.t",
"trait x temp diff" = "m.fixed.txm",
"trait + heritability type + temp diff" = "m.fixed.t.m.h",
"trait + temp diff" = "m.fixed.t.m",
"trait x temp diff + heritability type" = "m.fixed.txm.h"))
write.csv(TableS10, file="Suppl Tables/TableS10.csv", row.names=F)
TableS10| model | df | AICc | ΔAICc |
|---|---|---|---|
| trait + heritability type | 6 | 69.37282 | 0.0000000 |
| trait | 5 | 69.86893 | 0.4961053 |
| trait x temp diff | 11 | 71.25972 | 1.8869012 |
| trait + heritability type + temp diff | 7 | 71.68958 | 2.3167581 |
| trait + temp diff | 6 | 72.36935 | 2.9965266 |
| trait x temp diff + heritability type | 12 | 72.51076 | 3.1379393 |
final.model.Di <- rma.mv(yi=val.log ~ trait + h2,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T, sigma2 = c(NA, NA))
final.model.Di
Multivariate Meta-Analysis Model (k = 70; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.0722 0.2688 12 no study
sigma^2.2 0.0616 0.2482 70 no study/est.id
Test for Residual Heterogeneity:
QE(df = 63) = 343.8923, p-val < .0001
Test of Moderators (coefficients 2:7):
F(df1 = 6, df2 = 63) = 8.0903, p-val < .0001
Model Results:
estimate se tval pval ci.lb ci.ub
intrcpt -0.7526 0.1600 -4.7042 <.0001 -1.0723 -0.4329 ***
traitgrowth 0.0484 0.1488 0.3253 0.7460 -0.2490 0.3458
traitnutrient content 0.1898 0.1764 1.0760 0.2860 -0.1627 0.5422
traitbleaching 0.1699 0.2035 0.8350 0.4069 -0.2367 0.5765
traitimmune response 0.5845 0.1969 2.9681 0.0042 0.1910 0.9780 **
traitsurvival 0.8209 0.1564 5.2501 <.0001 0.5084 1.1334 ***
h2narrow -0.3904 0.2275 -1.7159 0.0911 -0.8451 0.0643 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
save(final.model.Di, file="Models/final.model.Di.Rdata")
mlm.variance.distribution(final.model.Di)| % of total variance | I2 | |
|---|---|---|
| Level 1 | 10.62483 | — |
| Level 2 | 41.13839 | 41.14 |
| Level 3 | 48.23679 | 48.24 |
final.model.Di$k - final.model.Di$p[1] 63
# Temp x trait type model:
tempxtrait.model <- rma.mv(yi=val.log ~ trait * temp.s,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T, sigma2 = c(NA, NA))
tempxtrait.model
Multivariate Meta-Analysis Model (k = 70; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.0992 0.3149 12 no study
sigma^2.2 0.0405 0.2013 70 no study/est.id
Test for Residual Heterogeneity:
QE(df = 58) = 257.6998, p-val < .0001
Test of Moderators (coefficients 2:12):
F(df1 = 11, df2 = 58) = 7.2539, p-val < .0001
Model Results:
estimate se tval pval ci.lb
intrcpt -0.8284 0.2222 -3.7288 0.0004 -1.2731
traitgrowth 0.0443 0.2268 0.1954 0.8457 -0.4097
traitnutrient content 0.1502 0.2405 0.6245 0.5347 -0.3313
traitbleaching 0.4375 0.2995 1.4608 0.1495 -0.1620
traitimmune response 0.1466 0.2649 0.5533 0.5822 -0.3837
traitsurvival 0.8591 0.2187 3.9288 0.0002 0.4214
temp.s -0.0079 0.1345 -0.0585 0.9535 -0.2771
traitgrowth:temp.s -0.0151 0.1586 -0.0951 0.9246 -0.3326
traitnutrient content:temp.s 0.0526 0.1717 0.3062 0.7606 -0.2911
traitbleaching:temp.s -0.2549 0.1976 -1.2902 0.2021 -0.6505
traitimmune response:temp.s 0.5337 0.2023 2.6382 0.0107 0.1288
traitsurvival:temp.s -0.0296 0.1519 -0.1952 0.8459 -0.3336
ci.ub
intrcpt -0.3837 ***
traitgrowth 0.4983
traitnutrient content 0.6317
traitbleaching 1.0371
traitimmune response 0.6768
traitsurvival 1.2969 ***
temp.s 0.2613
traitgrowth:temp.s 0.3024
traitnutrient content:temp.s 0.3962
traitbleaching:temp.s 0.1406
traitimmune response:temp.s 0.9387 *
traitsurvival:temp.s 0.2743
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# save(tempxtrait.model, file="Models/final.model.Di.Rdata")
mlm.variance.distribution(tempxtrait.model)| % of total variance | I2 | |
|---|---|---|
| Level 1 | 10.22495 | — |
| Level 2 | 26.04400 | 26.04 |
| Level 3 | 63.73104 | 63.73 |
tempxtrait.model$k - tempxtrait.model$p[1] 58
x <- resid(tempxtrait.model)
hist(x) # looks approx. normal, except for one strong outlier at -1.5par(mfrow=c(2,1))
funnel(tempxtrait.model)
update(tempxtrait.model, .~., data=dat_tm[x!=0,]) %>%
funnel(., yaxis="vinv")par(mfrow=c(1,1))fsn(yi=val.log, vi=sv.log, data=dat_tm, type="Rosenberg") # N=1669 to get no significance (but assumes fixed effects)
Fail-safe N Calculation Using the Rosenberg Approach
Average Effect Size: -0.1361
Observed Significance Level: <.0001
Target Significance Level: 0.05
Fail-safe N: 1669
# Number of studies x5 + 10:
length(unique(dat_tm$study))*5 + 10 # 1669 >> 70[1] 70
cdist <- cooks.distance(tempxtrait.model, reestimate=FALSE)
plot(cdist)
cdist.i <- which(cdist >2)
points(cdist.i, cdist[cdist.i], col="red", pch=16)data[cdist.i,] %>% select(study, species, val, trait, stage, h2) %>%
cbind(., cooks = round(cdist[cdist.i], 2))| study | species | val | trait | stage | h2 | cooks | |
|---|---|---|---|---|---|---|---|
| 3 | Quigley et al. 2020 | Acropora spathulata | 0.93 | survival | juvenile | narrow | 2.67 |
| 16 | Wright et al. 2019 | Acropora millepora | 0.92 | immune response | adult | broad | 7.64 |
update(tempxtrait.model, .~., data=dat_tm[-cdist.i,]) # effect of juv:growth n.s.
Multivariate Meta-Analysis Model (k = 68; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.1472 0.3836 12 no study
sigma^2.2 0.0089 0.0942 68 no study/est.id
Test for Residual Heterogeneity:
QE(df = 56) = 247.6234, p-val < .0001
Test of Moderators (coefficients 2:12):
F(df1 = 11, df2 = 56) = 7.9160, p-val < .0001
Model Results:
estimate se tval pval ci.lb
intrcpt -0.8029 0.1882 -4.2673 <.0001 -1.1799
traitgrowth 0.0827 0.1717 0.4816 0.6319 -0.2613
traitnutrient content 0.1550 0.1755 0.8834 0.3808 -0.1965
traitbleaching 0.4262 0.2343 1.8190 0.0743 -0.0432
traitimmune response 0.1522 0.1972 0.7721 0.4433 -0.2428
traitsurvival 0.8945 0.1580 5.6622 <.0001 0.5780
temp.s -0.0349 0.0989 -0.3532 0.7252 -0.2332
traitgrowth:temp.s 0.0204 0.1188 0.1714 0.8645 -0.2176
traitnutrient content:temp.s 0.0607 0.1285 0.4724 0.6385 -0.1968
traitbleaching:temp.s -0.1523 0.1586 -0.9606 0.3409 -0.4700
traitimmune response:temp.s 0.2668 0.2114 1.2622 0.2121 -0.1567
traitsurvival:temp.s -0.0822 0.1171 -0.7022 0.4855 -0.3168
ci.ub
intrcpt -0.4260 ***
traitgrowth 0.4267
traitnutrient content 0.5066
traitbleaching 0.8956 .
traitimmune response 0.5473
traitsurvival 1.2109 ***
temp.s 0.1633
traitgrowth:temp.s 0.2583
traitnutrient content:temp.s 0.3182
traitbleaching:temp.s 0.1653
traitimmune response:temp.s 0.6903
traitsurvival:temp.s 0.1523
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
update(tempxtrait.model, .~., data=dat_tm[-cdist.i[1],]) # no real difference
Multivariate Meta-Analysis Model (k = 69; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.1437 0.3790 12 no study
sigma^2.2 0.0134 0.1156 69 no study/est.id
Test for Residual Heterogeneity:
QE(df = 57) = 254.1203, p-val < .0001
Test of Moderators (coefficients 2:12):
F(df1 = 11, df2 = 57) = 11.2090, p-val < .0001
Model Results:
estimate se tval pval ci.lb
intrcpt -0.8102 0.1944 -4.1675 0.0001 -1.1996
traitgrowth 0.0859 0.1812 0.4740 0.6373 -0.2769
traitnutrient content 0.1535 0.1862 0.8247 0.4130 -0.2192
traitbleaching 0.4308 0.2448 1.7603 0.0837 -0.0593
traitimmune response 0.1509 0.2081 0.7250 0.4714 -0.2659
traitsurvival 0.8820 0.1683 5.2414 <.0001 0.5450
temp.s -0.0273 0.1052 -0.2599 0.7958 -0.2379
traitgrowth:temp.s 0.0148 0.1257 0.1180 0.9065 -0.2369
traitnutrient content:temp.s 0.0568 0.1359 0.4179 0.6776 -0.2153
traitbleaching:temp.s -0.1600 0.1651 -0.9691 0.3366 -0.4906
traitimmune response:temp.s 0.6038 0.1527 3.9550 0.0002 0.2981
traitsurvival:temp.s -0.0827 0.1234 -0.6702 0.5054 -0.3299
ci.ub
intrcpt -0.4209 ***
traitgrowth 0.4487
traitnutrient content 0.5263
traitbleaching 0.9210 .
traitimmune response 0.5677
traitsurvival 1.2190 ***
temp.s 0.1832
traitgrowth:temp.s 0.2666
traitnutrient content:temp.s 0.3289
traitbleaching:temp.s 0.1706
traitimmune response:temp.s 0.9096 ***
traitsurvival:temp.s 0.1644
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
update(tempxtrait.model, .~., data=dat_tm[-cdist.i[2],]) # no real difference
Multivariate Meta-Analysis Model (k = 69; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.0994 0.3153 12 no study
sigma^2.2 0.0371 0.1926 69 no study/est.id
Test for Residual Heterogeneity:
QE(df = 57) = 251.2029, p-val < .0001
Test of Moderators (coefficients 2:12):
F(df1 = 11, df2 = 57) = 6.1569, p-val < .0001
Model Results:
estimate se tval pval ci.lb
intrcpt -0.8252 0.2178 -3.7895 0.0004 -1.2612
traitgrowth 0.0415 0.2215 0.1872 0.8521 -0.4021
traitnutrient content 0.1507 0.2344 0.6432 0.5227 -0.3186
traitbleaching 0.4355 0.2932 1.4854 0.1430 -0.1516
traitimmune response 0.1471 0.2584 0.5693 0.5714 -0.3704
traitsurvival 0.8631 0.2130 4.0518 0.0002 0.4365
temp.s -0.0115 0.1312 -0.0877 0.9304 -0.2742
traitgrowth:temp.s -0.0113 0.1549 -0.0730 0.9421 -0.3216
traitnutrient content:temp.s 0.0548 0.1676 0.3271 0.7448 -0.2809
traitbleaching:temp.s -0.2545 0.1937 -1.3137 0.1942 -0.6424
traitimmune response:temp.s 0.2434 0.2573 0.9459 0.3482 -0.2719
traitsurvival:temp.s -0.0270 0.1484 -0.1822 0.8560 -0.3242
ci.ub
intrcpt -0.3891 ***
traitgrowth 0.4850
traitnutrient content 0.6201
traitbleaching 1.0226
traitimmune response 0.6646
traitsurvival 1.2896 ***
temp.s 0.2512
traitgrowth:temp.s 0.2989
traitnutrient content:temp.s 0.3905
traitbleaching:temp.s 0.1334
traitimmune response:temp.s 0.7587
traitsurvival:temp.s 0.2701
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
plot(fitted(tempxtrait.model), rstandard(tempxtrait.model)$z)
abline(h=0, lty=2)plot(residuals(tempxtrait.model, type="pearson"))
abline(h=0, lty=2)# Not amazing, not terrible
# Simulate new data given the parameter values of the data and same variance structure, plot on real data to see if it is similar
xsim <- simulate(tempxtrait.model, 100) %>%
mutate(true.val = dat_tm$val.log,
weighting = 1/dat_tm$sv.log) %>%
pivot_longer(cols=-c(true.val, weighting)) %>%
select(name, true.val, sim.val = value, weighting)
xsim %>%
ggplot(aes(x=true.val, y=sim.val)) +
geom_point(aes(col=weighting), alpha=0.05) +
geom_abline(slope=1, intercept=0, linetype="dashed") +
scale_colour_viridis_c() +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
scale_y_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1))# reruns model, based around the same variance/covariance structures but with simulated data.
xsim %>%
ggplot(aes(y=weighting)) +
geom_point(aes(x=sim.val), col="red", size=2, alpha=0.05) +
geom_point(data= filter(xsim, name == "sim_1"),
aes(x=true.val),
col="blue", size=2, alpha=0.9) +
scale_x_continuous(
breaks=log( c(0,0.10,0.25,0.5,0.75,1)+0.2),
labels = c(0,0.10,0.25,0.5,0.75,1)) +
labs(x="Heritability estimate", y=expression("Weighting (1/SE"^2*")"))dat_tm %>% table.plot("temp.manip", "trait", .)dat_tm %>% table.plot("temp.manip", "stage", .) # life stage x temp.manip possibledat_tm %>% table.plot("temp.manip", "h2", .) # h2 x temp.manipdat_tm %>% table.plot("temp.manip", "growth.form", .) # not possible for encrusting, columnar, remove!dat_tm %>% table.plot("stage", "trait", .) # no other interactions possible!dat_tm %>% table.plot("h2", "trait", .) # no other interactions possible!dat_tm %>% table.plot("growth.form", "trait", .) # no other interactions# Life stage, heritability type, and growth form are all signular for the photochemistry and immune response categories (all entirely overlapping for these trait types)Beyond optimal is simply trait x temp manipulation or temp magnitude for this sub-analysis. \[ logit(h^2) \sim N(\mu, \tau^2) \\ \mu = trait_k \times temp\;manip + stage + h^2type + growth\;form \, + \, \epsilon_{i} \]
## Compare random effects (fixed effects included)
m.study.nested <- rma.mv(yi=val.log ~ trait*temp.manip + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.spp.nested <- rma.mv(yi=val.log ~ trait*temp.manip + stage + h2 + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.only.est <- rma.mv(yi=val.log ~ trait*temp.manip + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(0, NA)) # same as random = ~1|est.id
m.only.study <- rma.mv(yi=val.log ~ trait*temp.manip + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|study
m.only.spp <- rma.mv(yi=val.log ~ trait*temp.manip + stage + h2 + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|species
m.no.reff <- rma.mv(yi=val.log ~ trait*temp.manip + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T,
sigma2 = c(0, 0)) # no random effects
TableS11 <- myAIC(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff) %>%
mutate(model = fct_recode(model,
"Estimate ID nested in study ID" = "m.study.nested",
"Estimate ID nested in species" = "m.spp.nested",
"Study ID only" = "m.only.study",
"Species only" = "m.only.spp",
"Estimate ID only" = "m.only.est",
"No random effect" = "m.no.reff"))
write.csv(TableS11, file="Suppl Tables/TableS11.csv", row.names=F)
TableS11| model | df | AICc | ΔAICc |
|---|---|---|---|
| Estimate ID nested in study ID | 18 | 106.3283 | 0.000000 |
| Estimate ID only | 18 | 107.9884 | 1.660187 |
| Estimate ID nested in species | 18 | 113.8505 | 7.522256 |
| Study ID only | 18 | 120.0003 | 13.672022 |
| Species only | 18 | 178.0667 | 71.738476 |
| No random effect | 18 | 181.4887 | 75.160427 |
rm(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff)The nested estimate ID within study ID random effects structure is preferred. The next closest is estimate ID-only, with ΔAICc = 1.66.
mod_names <- ls(pattern = "m.fixed.")
do.call("rm", as.list(mod_names))
m.fixed.txm.s.h.g <-
rma.mv(yi=val.log ~ trait*temp.manip + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.s.h <-
rma.mv(yi=val.log ~ trait*temp.manip + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.s.g <-
rma.mv(yi=val.log ~ trait*temp.manip + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.h.g <-
rma.mv(yi=val.log ~ trait*temp.manip + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.s <-
rma.mv(yi=val.log ~ trait*temp.manip + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.h <-
rma.mv(yi=val.log ~ trait*temp.manip + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm.g <-
rma.mv(yi=val.log ~ trait*temp.manip + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.txm <-
rma.mv(yi=val.log ~ trait*temp.manip,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.s.h.g <-
rma.mv(yi=val.log ~ trait + temp.manip + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.s.h <-
rma.mv(yi=val.log ~ trait + temp.manip + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.s.g <-
rma.mv(yi=val.log ~ trait + temp.manip + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.h.g <-
rma.mv(yi=val.log ~ trait + temp.manip + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.s.h.g <-
rma.mv(yi=val.log ~ trait + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.s.h.g <-
rma.mv(yi=val.log ~ temp.manip + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.s <-
rma.mv(yi=val.log ~ trait + temp.manip + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.h <-
rma.mv(yi=val.log ~ trait + temp.manip + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m.g <-
rma.mv(yi=val.log ~ trait + temp.manip + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.s.h <-
rma.mv(yi=val.log ~ trait + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.s.g <-
rma.mv(yi=val.log ~ trait + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.h.g <-
rma.mv(yi=val.log ~ trait + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.s.h <-
rma.mv(yi=val.log ~ temp.manip + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.s.g <-
rma.mv(yi=val.log ~ temp.manip + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.h.g <-
rma.mv(yi=val.log ~ temp.manip + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.s.h.g <-
rma.mv(yi=val.log ~ stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.m <-
rma.mv(yi=val.log ~ trait + temp.manip,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.s <-
rma.mv(yi=val.log ~ trait + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.h <-
rma.mv(yi=val.log ~ trait + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t.g <-
rma.mv(yi=val.log ~ trait + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.s <-
rma.mv(yi=val.log ~ temp.manip + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.h <-
rma.mv(yi=val.log ~ temp.manip + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m.g <-
rma.mv(yi=val.log ~ temp.manip + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.s.h <-
rma.mv(yi=val.log ~ stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.s.g <-
rma.mv(yi=val.log ~ stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.h.g <-
rma.mv(yi=val.log ~ h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.t <-
rma.mv(yi=val.log ~ trait,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.m <-
rma.mv(yi=val.log ~ temp.manip,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.s <-
rma.mv(yi=val.log ~ stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.h <-
rma.mv(yi=val.log ~ h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.g <-
rma.mv(yi=val.log ~ growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
m.fixed.null <-
rma.mv(yi=val.log ~ 1,
V=sv.log, random = ~1|study/est.id, data=dat_tm, method="ML",
tdist=T, sigma = c(NA, NA))
mod_names <- ls(pattern = "m.fixed.")
TableS12 <- head(do.call("myAIC", as.list(c(mod_names, getmodel=T)))) %>%
mutate(model = fct_recode(model,
"trait + heritability type" = "m.fixed.t.h",
"trait" = "m.fixed.t",
"trait + heritability type + temp manip" = "m.fixed.t.m.h",
"trait + temp manip" = "m.fixed.t.m",
"trait x temp manip" = "m.fixed.txm",
"trait + life stage" = "m.fixed.t.s"))
write.csv(TableS12, file="Suppl Tables/TableS12.csv", row.names=F)
TableS12| model | df | AICc | ΔAICc |
|---|---|---|---|
| trait + heritability type | 6 | 69.37282 | 0.0000000 |
| trait | 5 | 69.86893 | 0.4961053 |
| trait + heritability type + temp manip | 7 | 70.17968 | 0.8068565 |
| trait + temp manip | 6 | 71.22687 | 1.8540525 |
| trait x temp manip | 11 | 71.67283 | 2.3000087 |
| trait + life stage | 7 | 72.57154 | 3.1987165 |
A model of trait type + heritability type is preferred, though a model of trait (ΔAIC=0.5) and trait x temperature difference (ΔAIC=1.9) are also close.
final.model.Dii <- rma.mv(yi=val.log ~ trait + h2,
V=sv.log, random = ~1|study/est.id,
data=dat_tm, method="REML", tdist=T, sigma2 = c(NA, NA))
final.model.Dii
Multivariate Meta-Analysis Model (k = 70; method: REML)
Variance Components:
estim sqrt nlvls fixed factor
sigma^2.1 0.0722 0.2688 12 no study
sigma^2.2 0.0616 0.2482 70 no study/est.id
Test for Residual Heterogeneity:
QE(df = 63) = 343.8923, p-val < .0001
Test of Moderators (coefficients 2:7):
F(df1 = 6, df2 = 63) = 8.0903, p-val < .0001
Model Results:
estimate se tval pval ci.lb ci.ub
intrcpt -0.7526 0.1600 -4.7042 <.0001 -1.0723 -0.4329 ***
traitgrowth 0.0484 0.1488 0.3253 0.7460 -0.2490 0.3458
traitnutrient content 0.1898 0.1764 1.0760 0.2860 -0.1627 0.5422
traitbleaching 0.1699 0.2035 0.8350 0.4069 -0.2367 0.5765
traitimmune response 0.5845 0.1969 2.9681 0.0042 0.1910 0.9780 **
traitsurvival 0.8209 0.1564 5.2501 <.0001 0.5084 1.1334 ***
h2narrow -0.3904 0.2275 -1.7159 0.0911 -0.8451 0.0643 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
save(final.model.Dii, file="Models/final.model.Dii.Rdata")
mlm.variance.distribution(final.model.Dii)| % of total variance | I2 | |
|---|---|---|
| Level 1 | 10.62483 | — |
| Level 2 | 41.13839 | 41.14 |
| Level 3 | 48.23679 | 48.24 |
final.model.Dii$k - final.model.Dii$p[1] 63
dat_tm_nz <- dat_tm %>% filter(temp.diff >0) %>%
mutate(trait = factor(trait),
stage = factor(stage),
h2 = factor(h2),
growth.form = factor(growth.form))
dat_tm_nz %>% pull(temp.diff) %>% hist() # some high values, use a sqrt-transform to make more normally distributed!dat_tm_nz %>% pull(temp.diff) %>% sqrt() %>% hist() # better!dat_tm_nz %>% table.plot("stage", "trait", .) # no other interactions possible!dat_tm_nz %>% table.plot("h2", "trait", .) # no other interactions possible!dat_tm_nz %>% table.plot("growth.form", "trait", .) # no other interactions# Life stage, heritability type, and growth form are all singular for the photochemistry and immune response categories (all entirely overlapping for these trait types)Beyond optimal is simply trait x temp differential: this sub-analysis. \[ logit(h^2) \sim N(\mu, \tau^2) \\ \mu = trait_k \times sqrt(temp\;diff) + stage + h^2type + growth\;form \, + \, \epsilon_{i} \]
m.study.nested <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm_nz, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.spp.nested <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_tm_nz, method="REML", tdist=T,
sigma2 = c(NA, NA))
m.only.est <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm_nz, method="REML", tdist=T,
sigma2 = c(0, NA)) # same as random = ~1|est.id
m.only.study <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm_nz, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|study
m.only.spp <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|species/est.id,
data=dat_tm_nz, method="REML", tdist=T,
sigma2 = c(NA, 0)) # same as random = ~1|species
m.no.reff <- rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id,
data=dat_tm_nz, method="REML", tdist=T,
sigma2 = c(0, 0)) # no random effects
TableS13 <- myAIC(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff) %>%
mutate(model = fct_recode(model,
"Estimate ID nested in study ID" = "m.study.nested",
"Estimate ID nested in species" = "m.spp.nested",
"Study ID only" = "m.only.study",
"Species only" = "m.only.spp",
"Estimate ID only" = "m.only.est",
"No random effect" = "m.no.reff"))
write.csv(TableS13, file="Suppl Tables/TableS13.csv", row.names=F)
TableS13| model | df | AICc | ΔAICc |
|---|---|---|---|
| Estimate ID only | 15 | 120.4662 | 0.00000 |
| Study ID only | 15 | 131.1002 | 10.63401 |
| Estimate ID nested in study ID | 15 | 134.9756 | 14.50947 |
| Estimate ID nested in species | 15 | 137.2662 | 16.80000 |
| No random effect | 15 | 146.0231 | 25.55699 |
| Species only | 15 | 150.1833 | 29.71717 |
rm(m.study.nested, m.spp.nested, m.only.est, m.only.study, m.only.spp, m.no.reff)The estimate ID-only random effects structure is preferred. The next closest is estimate ID-only, with ΔAICc = 10.6.
mod_names <- ls(pattern = "m.fixed.")
do.call("rm", as.list(mod_names))
m.fixed.txm.s.h.g <-
rma.mv(yi=val.log ~ trait*temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.txm.s.h <-
rma.mv(yi=val.log ~ trait*temp.s + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.txm.s.g <-
rma.mv(yi=val.log ~ trait*temp.s + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.txm.h.g <-
rma.mv(yi=val.log ~ trait*temp.s + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.txm.s <-
rma.mv(yi=val.log ~ trait*temp.s + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.txm.h <-
rma.mv(yi=val.log ~ trait*temp.s + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.txm.g <-
rma.mv(yi=val.log ~ trait*temp.s + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.txm <-
rma.mv(yi=val.log ~ trait*temp.s,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.m.s.h.g <-
rma.mv(yi=val.log ~ trait + temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.m.s.h <-
rma.mv(yi=val.log ~ trait + temp.s + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.m.s.g <-
rma.mv(yi=val.log ~ trait + temp.s + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.m.h.g <-
rma.mv(yi=val.log ~ trait + temp.s + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.s.h.g <-
rma.mv(yi=val.log ~ trait + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.m.s.h.g <-
rma.mv(yi=val.log ~ temp.s + stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.m.s <-
rma.mv(yi=val.log ~ trait + temp.s + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.m.h <-
rma.mv(yi=val.log ~ trait + temp.s + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.m.g <-
rma.mv(yi=val.log ~ trait + temp.s + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.s.h <-
rma.mv(yi=val.log ~ trait + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.s.g <-
rma.mv(yi=val.log ~ trait + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.h.g <-
rma.mv(yi=val.log ~ trait + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.m.s.h <-
rma.mv(yi=val.log ~ temp.s + stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.m.s.g <-
rma.mv(yi=val.log ~ temp.s + stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.m.h.g <-
rma.mv(yi=val.log ~ temp.s + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.s.h.g <-
rma.mv(yi=val.log ~ stage + h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.m <-
rma.mv(yi=val.log ~ trait + temp.s,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.s <-
rma.mv(yi=val.log ~ trait + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.h <-
rma.mv(yi=val.log ~ trait + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t.g <-
rma.mv(yi=val.log ~ trait + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.m.s <-
rma.mv(yi=val.log ~ temp.s + stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.m.h <-
rma.mv(yi=val.log ~ temp.s + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.m.g <-
rma.mv(yi=val.log ~ temp.s + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.s.h <-
rma.mv(yi=val.log ~ stage + h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.s.g <-
rma.mv(yi=val.log ~ stage + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.h.g <-
rma.mv(yi=val.log ~ h2 + growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.t <-
rma.mv(yi=val.log ~ trait,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.m <-
rma.mv(yi=val.log ~ temp.s,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.s <-
rma.mv(yi=val.log ~ stage,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.h <-
rma.mv(yi=val.log ~ h2,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.g <-
rma.mv(yi=val.log ~ growth.form,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
m.fixed.null <-
rma.mv(yi=val.log ~ 1,
V=sv.log, random = ~1|study/est.id, data=dat_tm_nz, method="ML",
tdist=T, sigma =c(0, NA))
mod_names <- ls(pattern = "m.fixed.")
TableS14 <- head(do.call("myAIC", as.list(c(mod_names, getmodel=T)))) %>%
mutate(model = fct_recode(model,
"trait + life stage" = "m.fixed.t.s",
"life stage" = "m.fixed.s",
"trait + temp diff + life stage" = "m.fixed.t.m.s",
"life stage + heritability type" = "m.fixed.s.h",
"life stage + temp diff" = "m.fixed.m.s",
"trait + life stage + heritability type" = "m.fixed.t.s.h"))
write.csv(TableS14, file="Suppl Tables/TableS14.csv", row.names=F)
TableS14| model | df | AICc | ΔAICc |
|---|---|---|---|
| trait + life stage | 7 | 56.82920 | 0.0000000 |
| life stage | 2 | 57.13176 | 0.3025557 |
| trait + temp diff + life stage | 8 | 57.39062 | 0.5614156 |
| life stage + heritability type | 3 | 59.35959 | 2.5303886 |
| life stage + temp diff | 3 | 59.66963 | 2.8404316 |
| trait + life stage + heritability type | 8 | 60.19922 | 3.3700163 |
final.model.Diii <- rma(yi=val.log ~ trait + stage, vi=sv.log,
data=dat_tm_nz, method="REML", test="knha")
final.model.Diii
Mixed-Effects Model (k = 44; tau^2 estimator: REML)
tau^2 (estimated amount of residual heterogeneity): 0.1017 (SE = 0.0350)
tau (square root of estimated tau^2 value): 0.3189
I^2 (residual heterogeneity / unaccounted variability): 75.32%
H^2 (unaccounted variability / sampling variability): 4.05
R^2 (amount of heterogeneity accounted for): 44.14%
Test for Residual Heterogeneity:
QE(df = 36) = 168.0695, p-val < .0001
Test of Moderators (coefficients 2:8):
F(df1 = 7, df2 = 36) = 4.6735, p-val = 0.0008
Model Results:
estimate se tval pval ci.lb ci.ub
intrcpt -0.3474 0.2144 -1.6206 0.1138 -0.7821 0.0874
traitgrowth -0.0745 0.2086 -0.3574 0.7229 -0.4975 0.3484
traitnutrient content -0.1846 0.2086 -0.8848 0.3821 -0.6077 0.2385
traitbleaching -0.2138 0.2411 -0.8869 0.3810 -0.7027 0.2751
traitimmune response 0.4615 0.2687 1.7176 0.0945 -0.0834 1.0065 .
traitsurvival 0.3768 0.1924 1.9587 0.0579 -0.0133 0.7670 .
stagejuvenile -0.6982 0.2096 -3.3317 0.0020 -1.1233 -0.2732 **
stageadult -0.2565 0.1908 -1.3441 0.1873 -0.6435 0.1305
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
save(final.model.Diii, file="Models/final.model.Diii.Rdata")
final.model.Diii$I[1] 75.32359
final.model.Diii$k - final.model.Diii$p[1] 36
R session info:
sessionInfo()R version 4.0.2 (2020-06-22)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.4
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
locale:
[1] en_CA.UTF-8/en_CA.UTF-8/en_CA.UTF-8/C/en_CA.UTF-8/en_CA.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] patchwork_1.0.1 metafor_2.4-0 Matrix_1.2-18 forcats_0.5.0
[5] stringr_1.4.0 dplyr_1.0.2 purrr_0.3.4 readr_1.3.1
[9] tidyr_1.1.2 tibble_3.0.3 ggplot2_3.3.3 tidyverse_1.3.0
[13] readxl_1.3.1
loaded via a namespace (and not attached):
[1] tidyselect_1.1.0 xfun_0.17 haven_2.3.1 lattice_0.20-41
[5] colorspace_1.4-1 vctrs_0.3.4 generics_0.0.2 viridisLite_0.3.0
[9] htmltools_0.5.0 yaml_2.2.1 blob_1.2.1 rlang_0.4.7
[13] pillar_1.4.6 glue_1.4.2 withr_2.2.0 DBI_1.1.0
[17] dbplyr_1.4.4 modelr_0.1.8 lifecycle_0.2.0 munsell_0.5.0
[21] gtable_0.3.0 cellranger_1.1.0 rvest_0.3.6 evaluate_0.14
[25] labeling_0.3 knitr_1.29 fansi_0.4.1 highr_0.8
[29] broom_0.7.0 Rcpp_1.0.5 scales_1.1.1 backports_1.1.10
[33] jsonlite_1.7.1 farver_2.0.3 fs_1.5.0 hms_0.5.3
[37] digest_0.6.25 stringi_1.5.3 grid_4.0.2 cli_2.0.2
[41] tools_4.0.2 magrittr_1.5 crayon_1.3.4 pkgconfig_2.0.3
[45] ellipsis_0.3.1 xml2_1.3.2 reprex_0.3.0 lubridate_1.7.9
[49] assertthat_0.2.1 rmarkdown_2.5 httr_1.4.2 rstudioapi_0.11
[53] R6_2.4.1 nlme_3.1-149 compiler_4.0.2