This tutorial illustrates how to build and post-process a spatial HMSC model including traits and species ‘phylogeny’. The focus is set on modeling trait-environment relationships but we will also explore some other species and community based outputs.
library(Hmsc)
library(tidyverse)
library(viridis)
library(vioplot)
library(abind)
library(RColorBrewer)
library(ape)
library(corrplot)
If you get an error message, check that the R packages and their dependencies are installed correctly. If not, use the command to install all listed packages: install.packages(c("Hmsc", "tidyverse", "viridis","vioplot","abind","RColorBrewer, "ape", "corrplot"))
.
The example data set is available as the Rdata file NEAtl_FishTraitEnv.Rdata
, available for download here.
Make sure the file NEAtl_FishTraitEnv.Rdata
is in your working directory, then load it in R.
load("NEAtl_FishTraitEnv.Rdata")
The Rdata file contains four objects:
abu
containing the abundance of taxa in grid cellsenv
containing the environmental condition per grid celltrait
containing the trait information per taxacoo
the coordinates of each grid celltaxo
taxonomic relationship of species (taxonomic/phylogenetic tree)Importantly, the rows in abu
correspond to the same grid cell than the rows in env
, and the column in abu
correspond to the same taxa than the rows in trait
.
all(row.names(abu)==row.names(env))
## [1] TRUE
all(colnames(abu)==row.names(trait))
## [1] TRUE
dim(trait)
## [1] 148 7
names(trait)
## [1] "Trophic.level" "K" "Lmax"
## [4] "Lifespan" "Age.maturity" "Fecundity_log"
## [7] "Offspring.size_log"
The trait
table contains 7 traits (i.e variable, in column) characterizing 148 taxa (in rows). The 7 traits broadly represent the life history and ecology of fish in terms of their feeding, growth, survival and reproduction. These are:
Trait values for fecundity and offspring size were log-transformed to reduce the influence of outliers.
For further analysis in HMSC, convert trait names to one one word per column in case traits consist of multiple words
trait<-trait %>%
dplyr::rename_all(make.names)
head(trait)
## Trophic.level K Lmax Lifespan Age.maturity
## Agonus cataphractus 3.43 0.47 21 1.0 3.0
## Alosa alosa 2.95 0.32 65 10.0 3.5
## Alosa fallax 4.03 0.33 43 25.0 2.5
## Amblyraja hyperborea 4.31 0.15 89 24.0 11.0
## Amblyraja radiata 4.20 0.15 69 16.0 11.0
## Ammodytes 3.15 0.55 23 7.7 3.2
## Fecundity_log Offspring.size_log
## Agonus cataphractus 7.843849 0.6931472
## Alosa alosa 12.652360 0.0000000
## Alosa fallax 11.875831 0.0000000
## Amblyraja hyperborea 3.401197 4.6298628
## Amblyraja radiata 2.833213 4.0073332
## Ammodytes 9.429476 -0.0618754
dim(env)
## [1] 169 7
names(env)
## [1] "Depth" "SBT" "SBS" "Chl" "SBT_sea" "Chl_sea" "Fishing"
The env
table contains 7 environmental variables (in column) characterizing 169 grid cells (in rows). The environmental variables measure hydrography, habitat, food availability and anthropogenic pressures, which are known to affect the distribution of fish species. These are:
We build a phylo object from the taxonomic relationships provided in taxo
First make sure the taxonomic units are factors
str(taxo) #listed as chr
## 'data.frame': 148 obs. of 6 variables:
## $ phylum : chr "Chordata" "Chordata" "Chordata" "Chordata" ...
## $ class : chr "Actinopterygii" "Actinopterygii" "Actinopterygii" "Elasmobranchii" ...
## $ order : chr "Scorpaeniformes" "Clupeiformes" "Clupeiformes" "Rajiformes" ...
## $ family : chr "Agonidae" "Clupeidae" "Clupeidae" "Rajidae" ...
## $ genus : chr "Agonus" "Alosa" "Alosa" "Amblyraja" ...
## $ species: chr "Agonus cataphractus" "Alosa alosa" "Alosa fallax" "Amblyraja hyperborea" ...
taxo <- as.data.frame(lapply(taxo, as.factor)) # make factors
str(taxo) # now they are!
## 'data.frame': 148 obs. of 6 variables:
## $ phylum : Factor w/ 1 level "Chordata": 1 1 1 1 1 1 1 1 1 1 ...
## $ class : Factor w/ 4 levels "Actinopterygii",..: 1 1 1 2 2 1 1 1 1 1 ...
## $ order : Factor w/ 20 levels "Anguilliformes",..: 16 6 6 15 15 12 12 12 12 12 ...
## $ family : Factor w/ 54 levels "Agonidae","Ammodytidae",..: 1 12 12 38 38 2 3 3 3 48 ...
## $ genus : Factor w/ 105 levels "Agonus","Alosa",..: 1 2 2 3 3 4 5 5 5 6 ...
## $ species: Factor w/ 148 levels "Agonus cataphractus",..: 1 2 3 4 5 6 7 8 9 10 ...
# build the tree
tree<-as.phylo(~class/order/family/genus/species, data=taxo, collapse = FALSE)
## Warning in as.phylo.formula(~class/order/family/genus/species, data = taxo, :
## NAs introduced by coercion
tree$edge.length<-rep(1,length(tree$edge))
# It's important to check if the tip lables of tree correspond to the names in abu
if(all(sort(tree$tip.label) == sort(colnames(abu)))){
print("species names in tree and abu match")
} else{
print("species names in tree and abu do not match")
} #there is some problem which we can already see from the NA message before.
## Warning in sort(tree$tip.label) == sort(colnames(abu)): longer object length is
## not a multiple of shorter object length
## [1] "species names in tree and abu do not match"
# Looks like we have some NA in genus, so what we do now is take the species information for all NA at genus level to fill the NA correctly.
taxo2<-taxo%>%
mutate(genus = coalesce(genus,species))
# Build tree again with new taxo2
tree<-as.phylo(~class/order/family/genus/species, data=taxo2, collapse = FALSE) # no NA message
tree$edge.length<-rep(1,length(tree$edge))
# Check lable correspondence
if(all(sort(tree$tip.label) == sort(colnames(abu)))){
print("species names in tree and abu match")
} else{
print("species names in tree and abu do not match")
} # All good now!
## [1] "species names in tree and abu match"
#Have a look at the tree
str(tree)
## List of 5
## $ edge : int [1:334, 1:2] 149 150 151 152 153 152 154 151 155 156 ...
## $ Nnode : int 187
## $ node.label : chr [1:187] "" "Actinopterygii" "Scorpaeniformes" "Agonidae" ...
## $ tip.label : chr [1:148] "Agonus cataphractus" "Leptagonus decagonus" "Artediellus atlanticus" "Icelus bicornis" ...
## $ edge.length: num [1:668] 1 1 1 1 1 1 1 1 1 1 ...
## - attr(*, "class")= chr "phylo"
## - attr(*, "order")= chr "cladewise"
plot(tree, cex=0.5)
XFormula = as.formula(paste("~",paste(colnames(env), collapse="+")))
XFormula
## ~Depth + SBT + SBS + Chl + SBT_sea + Chl_sea + Fishing
You can also specify second order polynomial response terms for your regression model. Then HMSC fits both, the liner term and the quadratic term as covariates. Here, this is exemplified for SBT, SBS and Chl, where one could ecologically assume bell shaped responses. For reasons of simplicity, we continue with the above defined regression model.
XFormula = ~ Depth + poly(SBT, degree = 2, raw= TRUE) + poly(SBT, degree = 2, raw= TRUE) + poly(SBS, degree = 2, raw= TRUE) + poly(Chl, degree = 2, raw= TRUE) + SBT_sea + Chl_sea + Fishing
TrFormula = as.formula(paste("~",paste(colnames(trait), collapse="+")))
TrFormula
## ~Trophic.level + K + Lmax + Lifespan + Age.maturity + Fecundity_log +
## Offspring.size_log
studyDesign = data.frame(grid.cell = as.factor(rownames(coo))) # "sample" level is defined as grid.cell
rL = HmscRandomLevel(sData = coo) # here the random effect is defined to be spatially explicit based on the coordinates of the grid cell
rL = setPriors(rL,nfMin=1,nfMax=2) # here we set the number of latent variable factors. In this example they are low for computational reasons
# Have a look at the random effect
rL
## Hmsc random level object with 169 units. Spatial dimensionality is 2 and number of covariates is 0.
head(rL$s)
## Longitude Latitude
## 1554 -28.75 66.25
## 1577 -26.25 63.75
## 1578 -26.25 66.25
## 1601 -23.75 63.75
## 1602 -23.75 66.25
## 1625 -21.25 63.75
test.run = TRUE # TEST RUN TAKES ABOUT 2 MIN ON MY COMPUTER
if (test.run){
# with this option, the model runs fast but results are not reliable
thin = 1 # interval of iterations per samples
samples = 10 # number of samples taken per chain
transient = ceiling(0.5*samples*thin) # burn-in, i.e. number of first iterations which will be cut off
nChains = 2 # number of independent MCMC chains
} else {
# with this option, the model evaluates slow but it reproduces the results shown in this tutorial
thin = 100 # interval of iterations per samples
samples = 250 # number of samples taken per chain
transient = ceiling(0.5*samples*thin) # burn-in, i.e. number of first iterations which will be cut off
nChains = 4 # number of independent MCMC chains
}
m = Hmsc(Y= abu, XData = env, XFormula = XFormula, TrFormula = TrFormula, TrData = trait, phyloTree = tree, studyDesign = studyDesign, ranLevels = list("grid.cell"= rL), distr = "normal")
m = sampleMcmc(m, thin = thin, samples = samples, transient = transient, nChains = nChains)
# You can also run chains in parallel by adding 'nParallel = nChains' in the sampleMCMC() function, but you won't see the progress of the run until it finished.
filename = paste("NorthAtlantic","_thin_", as.character(thin),"_samples_", as.character(samples),"_chains_", as.character(nChains), ".Rdata",sep = "")
save(m,file=filename)
You can now either continue with the post-processing of the model with your fitted test run, or maybe better, load the previously fitted model which used a higher thinning, more samples and chains, hence, included more iterations for better convergence of the MCMC chains.
load("NorthAtlantic_rL_tree_thin_10_samples_250_chains_4.Rdata")
# convert model to coda object
mpost = convertToCodaObject(m)
You can visually check the MCMC convergence and mixing for beta (species-environment) and gamma (trait-environment) parameters
Since we have 7 environmental covariates and 148 species we get 1036 specific mixing plots for the beta parameters … not too convenient to go through.
plot(mpost$Beta)
Rather have a look at summarized diagnostics
# check effective sample size
# should ideally be close to your drawn samples, here, 4 (chains) * 250 (samples) = 1000 samples)
summary(effectiveSize(mpost$Beta))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 786.3 973.5 1000.0 1039.7 1073.1 3009.1
# check the distribution of the effective sample size (ess) and the Gelman-Rubin potential scale reduction factor (psrf), the latter should be ideally (very) close to 1, if not, chains did not properly converge and need more iterations.
# These should be checked for all parameters of interest, i.e. beta and gamma
# Provided model looks quite okay already but could be better.
par(mfrow=c(1,3))
# Beta parameters (species-environment)
hist(effectiveSize(mpost$Beta), main="ess(beta)")
hist(gelman.diag(mpost$Beta, multivariate = FALSE)$psrf, main="psrf(beta)")
vioplot(gelman.diag(mpost$Beta,multivariate = FALSE)$psrf,main="psrf(beta)")
# Gamma parameters (trait-environment)
hist(effectiveSize(mpost$Gamma), main="ess(gamma)")
hist(gelman.diag(mpost$Gamma, multivariate = FALSE)$psrf, main="psrf(gamma)")
vioplot(gelman.diag(mpost$Gamma,multivariate = FALSE)$psrf,main="psrf(gamma)")
# compute predicted species abundance matrix/ posterior samples
predY=computePredictedValues(m)
For our model type (abundance, normal distribution) MF provides two metrics, calculated for all individual species.
Root Mean Square Error ($RMSE) is the standard deviation of the residuals (prediction errors). Residuals are a measure of how far from the regression line data points are; RMSE is a measure of how spread out these residuals are. In other words, it tells you how concentrated the data is around the line of best fit.
R\(^{2}\) ($R2): your “usual” measure of explained variation. Here prvided species specifically as result of the regression model (XFormula), with included enviornmental covariates
MF = evaluateModelFit(hM = m, predY = predY)
MF
## $RMSE
## [1] 0.0241029358 0.0014314489 0.0073169183 0.0187911408 0.0885159012
## [6] 0.0346446105 0.0136305201 0.0943027509 0.0360033458 0.0208712288
## [11] 0.0154651006 0.1461136596 0.1203870472 0.0408219267 0.0515242462
## [16] 0.1210255635 0.0055227474 0.0005995548 0.0128888613 0.2045381038
## [21] 0.0579907823 0.0367240697 0.0543206618 0.0523487887 0.0018713588
## [26] 0.0433405301 0.0615989253 0.0079690515 0.0177833047 0.0849765722
## [31] 0.0060515463 0.0011669438 0.1376531756 0.0258356317 0.0392692258
## [36] 0.0162264416 0.0014285170 0.0304224151 0.0137556508 0.0134335595
## [41] 0.0086522366 0.0373137086 0.0269322690 0.0591678346 0.0319173319
## [46] 0.0637858504 0.0186484259 0.0894529194 0.1557369308 0.1736746185
## [51] 0.0166861096 0.0037573490 0.0933817135 0.0470956150 0.0798659479
## [56] 0.0521142782 0.0052529823 0.0070319185 0.1078269908 0.1851185561
## [61] 0.0080399183 0.0027945350 0.0321503914 0.0729486076 0.0010771206
## [66] 0.0015120361 0.0068494672 0.0894043068 0.1055254614 0.0739688439
## [71] 0.0971860282 0.0018487378 0.0032043031 0.0232099973 0.1300051939
## [76] 0.0113907181 0.0892338450 0.0425038936 0.0304542148 0.0363220015
## [81] 0.0790463131 0.0033406344 0.0035364000 0.0410142846 0.0282597170
## [86] 0.0653487791 0.0696642229 0.0198900945 0.0620962660 0.0385681678
## [91] 0.0160730309 0.0289539578 0.0165150585 0.1855458666 0.0340455503
## [96] 0.2751537032 0.1429938941 0.1637984239 0.0696600465 0.2129265801
## [101] 0.0929376991 0.0361639325 0.0448428580 0.0274158349 0.0298960751
## [106] 0.0259057176 0.0392662996 0.0219753868 0.0354233989 0.0022716614
## [111] 0.0003792495 0.0030218258 0.0041627969 0.0608144431 0.0444505572
## [116] 0.0768815680 0.0095162587 0.1055773264 0.0035414957 0.0281635514
## [121] 0.0263790250 0.0130644601 0.0014693578 0.1418579748 0.0368109862
## [126] 0.0763812344 0.0054467997 0.0151676489 0.0103469626 0.0912308275
## [131] 0.0101719696 0.3477377602 0.0160081278 0.0495907360 0.1163158962
## [136] 0.0169024463 0.0347735323 0.0356100947 0.1023453991 0.0090917374
## [141] 0.0832952640 0.1899526158 0.0255823513 0.3298954455 0.0362762143
## [146] 0.1280924593 0.0010536769 0.0229889704
##
## $R2
## [1] 0.48334800 0.21134569 0.26939255 0.49018658 0.37220233 0.30125187
## [7] 0.35742836 0.21470593 0.23726842 0.10341809 0.28461468 0.40550609
## [13] 0.54343096 0.36378860 0.28327302 0.51454944 0.17075013 0.09448774
## [19] 0.14183871 0.53572196 0.30319968 0.45354565 0.66146518 0.43327172
## [25] 0.34344043 0.37855572 0.70240299 0.40640819 0.42261932 0.35717771
## [31] 0.36822101 0.19487403 0.80322460 0.24793953 0.45209886 0.05802683
## [37] 0.28380160 0.37262344 0.55688773 0.29448202 0.28956787 0.34404460
## [43] 0.34351027 0.39777003 0.31827264 0.27473236 0.12880359 0.83042682
## [49] 0.32802159 0.68048040 0.10038272 0.32936502 0.54997327 0.10285840
## [55] 0.41673962 0.43296509 0.09756813 0.19446871 0.41832397 0.67546889
## [61] 0.44414168 0.38859948 0.40332475 0.21799855 0.34886891 0.29572280
## [67] 0.05778352 0.44492038 0.43538088 0.55718027 0.59974749 0.08081121
## [73] 0.11308655 0.57573746 0.80031489 0.23978694 0.22967848 0.07085071
## [79] 0.48016469 0.51944714 0.24126949 0.05348689 0.04748534 0.24422022
## [85] 0.34328053 0.18463908 0.20770095 0.26799344 0.29196864 0.27014509
## [91] 0.14385522 0.28130739 0.14911916 0.53910893 0.18958411 0.44271186
## [97] 0.83163447 0.60234361 0.44140420 0.57077242 0.61137988 0.05872545
## [103] 0.38538305 0.38681484 0.55980961 0.39099866 0.22710801 0.52688414
## [109] 0.56314817 0.21602132 0.02156530 0.27497435 0.10001841 0.53105487
## [115] 0.63789700 0.81485566 0.19083529 0.47385487 0.40923046 0.52483313
## [121] 0.51025962 0.12886184 0.09380564 0.64007033 0.52590710 0.76114005
## [127] 0.60816816 0.43082696 0.17797052 0.76162523 0.31433613 0.40154301
## [133] 0.60903099 0.52615478 0.81181975 0.46821117 0.04339615 0.33103648
## [139] 0.84848783 0.15524245 0.27244413 0.30134776 0.28207730 0.42933768
## [145] 0.62776174 0.75578451 0.29152432 0.76118208
mean(MF$R2)
## [1] 0.3793841
#Here, we take the mean of posterior samples for further processing
predY = apply(abind(predY,along=3),c(1,2), mean)
# Plot species specific R2 in relation to prevalence
plot(colSums(((m$Y>0)*1)/m$ny), MF$R2,main=paste("Mean R2 = ", round(mean(MF$R2),2),".", sep=""), xlab = "Prevalence")
par(mfrow=c(1,1))
# Specify groups of how the variation should be partitioned You can also combine groups
group=c(1,2,3,4,5,6,7)
# Specify group names m$covNames[-1] gives the included covariate names excluding the intercept
groupnames = m$covNames[-1]
#compte species specific variance partitioning
VP = computeVariancePartitioning(hM = m, group = group, groupnames = groupnames)
plotVariancePartitioning(m, VP, viridis(8))
# Shown are all species with 90% posterior support for having positive (red) or negative(blue) responses to environmental covariates
beta = getPostEstimate(m, "Beta")
plotBeta(m, beta, supportLevel=.9, spNamesNumbers = c(FALSE, FALSE), covNamesNumbers = c(TRUE, FALSE), plotTree = T)
## [1] 0.3 1.0 0.0 1.0
gamma = getPostEstimate(m, "Gamma")
plotGamma(m, gamma, supportLevel=.8)
# modify support level to highlight stronger or weaker posterior support for positive/ negative relationship
We can ask about the influence of traits on species abundances, i.e. how much do traits explain out of the variation in species abundances
VP$R2T$Y
## [1] 0.01933062
# The traits explain only 1.93% of variation in species abundances
Let us then ask how much the traits explain out of the variation among the species in their responses to environmental covariates.
VP$R2T$Beta
## (Intercept) Depth SBT SBS Chl SBT_sea
## 0.011770572 0.010954368 0.024170906 0.011867357 0.007802353 0.023027623
## Chl_sea Fishing
## 0.008830540 0.026924321
barplot(VP$R2T$Beta[-1])
#The traits explain also not much of the variation in the species niches, with traits explaining most out of the variation in species responses to SBT, SBT_sea and fishing with ca. 2.5% each
Now let’s see how the predicted trait-environment responses are over the realized environmental gradient. Here we exemplified for all CWM trait responses as well as species richness with SBT as focal variable.
# Construct environmental Gradient based on fitted model, specify your focal variable.
Gradient = constructGradient(m, focalVariable="SBT", ngrid = 25)
# make predictions based on fitted model
predYgradient = predict(m,XData=Gradient$XDataNew, ranLevels = Gradient$rLNew, studyDesign = Gradient$studyDesignNew, expected = TRUE)
par(mfrow=c(2,4))
# measure = T implies trait relationship to focal variable, index = 2 implies second trait of trait matrix (1 is the intercept).
# traits ~ SBT
plotGradient(m, Gradient, pred=predYgradient, measure="T", index = 2, showData =F)
## [1] 0.999
plotGradient(m, Gradient, pred=predYgradient, measure="T", index = 3, showData =F)
## [1] 0.422
plotGradient(m, Gradient, pred=predYgradient, measure="T", index = 4, showData =F)
## [1] 0.021
plotGradient(m, Gradient, pred=predYgradient, measure="T", index = 5, showData =F)
## [1] 0.977
plotGradient(m, Gradient, pred=predYgradient, measure="T", index = 6, showData =F)
## [1] 0.003
plotGradient(m, Gradient, pred=predYgradient, measure="T", index = 7, showData =F)
## [1] 0.984
plotGradient(m, Gradient, pred=predYgradient, measure="T", index = 8, showData =F)
## [1] 0.045
# Species ~ SBT // If you specify measure = Y, this is the species response, with index being the number of species in the abu matrix
plotGradient(m, Gradient, pred=predYgradient, measure="Y", index = 50, showData =F) #here examplified for species 50, cod
## [1] 0
# Note that the scale of all relationships is very small for the traits
S=rowSums(predY)
#predicted CWM
predT = (predY%*%m$Tr)/matrix(rep(S,m$nt),ncol=m$nt)
#make data frame for plotting
data<-data.frame(predT, coo)
colpal<-rev(brewer.pal(11,"RdYlBu")) # Color palette for the map
funPlot<-function(Var){
colnames(data)[which(colnames(data)==Var)]<-"Var"
ggplot(data, aes(x= Longitude, y= Latitude, fill= Var))+
geom_tile(data=data,aes(x=Longitude,y=Latitude,fill= Var)) + #
scale_fill_gradientn(name = Var, colours=colpal, na.value = 'white')+
borders(fill="gray44",colour="black") +
coord_quickmap(xlim=c(range(data$Longitude)),ylim=c(range(data$Latitude)))+
labs(x = "Lon",y="Lat")+
theme(legend.position = c(0.93,0.8))+
theme(legend.title = element_text(size = 8),legend.text = element_text(size = 7))+
guides(shape = guide_legend(override.aes = list(size = 0.2)))+
theme(panel.background = element_rect(fill=alpha('light blue', 0.4), colour = 'black'))
}
# list all output
Metrics<-colnames(data)
Metrics
## [1] "X.Intercept." "Trophic.level" "K"
## [4] "Lmax" "Lifespan" "Age.maturity"
## [7] "Fecundity_log" "Offspring.size_log" "Longitude"
## [10] "Latitude"
#We plot the CWM of Trophic level, which is the 2nd variable
funPlot(Var=Metrics[2])# Plot CWM traits and diversity metrics
Here we illustrate the residual association plot among species at the level of grid cell. Pairs of species illustrated by red and blue show positive and negative associations, respectively, with statistical support of at least 95% posterior probability
par(mfrow=c(1,1))
OmegaCor = computeAssociations(m)
supportLevel = 0.9
for (r in 1:m$nr){
plotOrder = corrMatOrder(OmegaCor[[r]]$mean,order="AOE")
toPlot = ((OmegaCor[[r]]$support>supportLevel) + (OmegaCor[[r]]$support<(1-supportLevel))>0)*OmegaCor[[r]]$mean
par(xpd=T)
colnames(toPlot)=rownames(toPlot)=gsub("_"," ",x=colnames(toPlot))
corrplot(toPlot[plotOrder,plotOrder], method = "color", col=colorRampPalette(c("blue","white","red"))(200), title=paste("random effect level:",m$rLNames[r]),type="full",tl.col="black",tl.cex=.4, mar=c(0,0,6,0))
}
We build a presence-absence model with the same structure and specifications as above. For this we need to change the link function to “probit” and transform the abundance data to presence-absence.
m = Hmsc(Y= 1*(abu>0), XData = env, XFormula = XFormula, TrFormula = TrFormula, TrData = trait, phyloTree = tree, studyDesign = studyDesign, ranLevels = list("grid.cell"= rL), distr = "probit")
Next we fit the model as above.
m = sampleMcmc(m, thin = thin, samples = samples, transient = transient, nChains = nChains)
# compute predicted species occurrence matrix from posterior samples
predY=computePredictedValues(m)
#evaluate model fit
MF = evaluateModelFit(hM = m, predY = predY)
MF
## $RMSE
## [1] 0.2043474 0.2112074 0.2452425 0.3058084 0.2307849 0.3485816 0.2276085
## [8] 0.2664577 0.2199623 0.2859988 0.3718063 0.2314359 0.2754418 0.1829732
## [15] 0.1117695 0.2274460 0.3024150 0.2876661 0.2177659 0.1902863 0.2194968
## [22] 0.1349278 0.1103794 0.2041797 0.2620985 0.2736369 0.1643216 0.2375135
## [29] 0.1119734 0.2920832 0.2595443 0.2685171 0.2100611 0.2605150 0.1702702
## [36] 0.2864073 0.2233830 0.2460489 0.2368907 0.3380119 0.2811300 0.1741510
## [43] 0.2302583 0.1583545 0.3596973 0.3233873 0.2793448 0.1780917 0.2581432
## [50] 0.1778816 0.3800001 0.2473961 0.2974098 0.3329670 0.2583362 0.1822965
## [57] 0.2383175 0.2752547 0.2543954 0.1325111 0.2346596 0.2164220 0.2649561
## [64] 0.2766946 0.2061530 0.2200791 0.2679550 0.2447704 0.2416894 0.2825703
## [71] 0.2272519 0.2339338 0.2523387 0.2338831 0.2363901 0.2265008 0.2880394
## [78] 0.4123583 0.1896096 0.1966470 0.2626998 0.2666296 0.2586606 0.2789196
## [85] 0.2918235 0.2798699 0.2651267 0.2742749 0.2031151 0.3345763 0.2587659
## [92] 0.2986930 0.1827315 0.1912792 0.3201268 0.2072077 0.1754651 0.2724417
## [99] 0.1722335 0.2541437 0.1881461 0.3214160 0.2202247 0.2494580 0.1653224
## [106] 0.2242608 0.4324346 0.3492411 0.1767657 0.1827091 0.2555083 0.1501612
## [113] 0.2802601 0.2442998 0.2532104 0.1988362 0.2845569 0.2122642 0.1762328
## [120] 0.2956183 0.2106699 0.2638517 0.2324514 0.1995834 0.1204574 0.2286059
## [127] 0.2095511 0.1784304 0.3070114 0.1350802 0.2580376 0.1770515 0.1826851
## [134] 0.1120672 0.2027442 0.2687508 0.2148657 0.2503981 0.1339848 0.2621735
## [141] 0.2830376 0.1895614 0.3055313 0.2290751 0.1843219 0.1699762 0.1875599
## [148] 0.1318489
##
## $AUC
## [1] 0.9855643 0.9624724 0.9633987 0.9401018 0.9840217 0.9079710 0.9842262
## [8] 0.9699015 0.9860160 0.9416462 0.8536232 0.9803783 0.9648426 0.9913511
## [15] 0.9993197 0.9839074 0.9366899 0.9105373 0.9691120 0.9915179 0.9869702
## [22] 0.9991810 0.9995610 0.9887574 0.9500000 0.9657612 0.9956083 0.9660929
## [29] 0.9995069 0.9525307 0.9328774 0.9221477 0.9834152 0.9571846 0.9961240
## [36] 0.8968391 0.9702204 0.9788173 0.9666145 0.9097479 0.8992921 0.9935255
## [43] 0.9841737 0.9951691 0.8976731 0.9272183 0.9244217 0.9934118 0.9739423
## [50] 0.9833244 0.8706525 0.9604863 0.9457594 0.8872093 0.9726661 0.9931694
## [57] 0.9431579 0.9530572 0.9688073 0.9938424 0.9805855 0.9769444 0.9610909
## [64] 0.9583708 0.9785965 0.9750000 0.8649381 0.9726284 0.9745617 0.9630641
## [71] 0.9817876 0.9462074 0.9462677 0.9734889 0.9827781 0.9710145 0.9422637
## [78] 0.8084746 0.9918699 0.9899972 0.9689755 0.8980868 0.9395109 0.9593364
## [85] 0.9534017 0.9631505 0.9650231 0.9564004 0.9895050 0.9092437 0.9419540
## [92] 0.9231283 0.9819820 0.9925750 0.9374825 0.9801309 0.9980023 0.9580339
## [99] 0.9948552 0.9629630 0.9934063 0.9193548 0.9879518 0.9520115 0.9906602
## [106] 0.9781037 0.7862349 0.8730909 0.9885591 0.9870175 0.9049123 0.9940351
## [113] 0.9564086 0.9739007 0.9535058 0.9933989 0.9544283 0.9871302 0.9915849
## [120] 0.9528139 0.9863910 0.9673950 0.9697222 0.9904735 0.9980481 0.9819668
## [127] 0.9832578 0.9911957 0.8299320 0.9980267 0.9277193 0.9933977 0.9918699
## [134] 0.9996321 0.9803818 0.9662080 0.9747546 0.9577001 0.9987267 0.9445939
## [141] 0.9611814 0.9883629 0.9358844 0.9757394 0.9911406 0.9953623 0.9863946
## [148] 0.9986133
##
## $TjurR2
## [1] 0.7427867 0.5028891 0.6037010 0.5659250 0.7146765 0.4921621 0.7239853
## [8] 0.6830180 0.7644368 0.4751269 0.3286146 0.7256685 0.6468773 0.7029917
## [15] 0.9102108 0.7762363 0.5322472 0.3527813 0.5125437 0.8061841 0.7468028
## [22] 0.8424068 0.9176976 0.7976506 0.4868334 0.6797622 0.8408287 0.5283133
## [29] 0.9065774 0.6091045 0.4922892 0.2966961 0.7104487 0.5441139 0.7764817
## [36] 0.2830684 0.5236197 0.7016190 0.5466084 0.4316732 0.2211566 0.7832787
## [43] 0.7467659 0.8592530 0.4630760 0.4678506 0.3745661 0.8305136 0.6802259
## [50] 0.7137340 0.3866086 0.5422406 0.5495501 0.3555109 0.7061227 0.8377863
## [57] 0.3834153 0.5243009 0.6821491 0.8312885 0.7089314 0.5623340 0.6227560
## [64] 0.6342641 0.4902411 0.5707337 0.1859354 0.6272984 0.7235269 0.6703727
## [71] 0.7690837 0.3332472 0.3438651 0.6991626 0.7277365 0.6099776 0.5149654
## [78] 0.2461256 0.7689551 0.8120902 0.6694316 0.2250497 0.3389160 0.5869128
## [85] 0.5851379 0.6569832 0.6748573 0.5967688 0.7729210 0.4519119 0.3835149
## [92] 0.3970930 0.6253413 0.8150964 0.5616674 0.6696742 0.8185810 0.6731251
## [99] 0.7843435 0.5449114 0.8212888 0.4441025 0.7667406 0.4430943 0.8329886
## [106] 0.6785970 0.2419629 0.3396439 0.6627763 0.5878529 0.2922326 0.7134422
## [113] 0.5882655 0.7219765 0.6214107 0.7786137 0.5839923 0.7677816 0.7288576
## [120] 0.6008543 0.7557928 0.6130714 0.4826802 0.8047514 0.8983628 0.7785269
## [127] 0.7583392 0.7767699 0.1580521 0.8901874 0.3212448 0.7939858 0.8096178
## [134] 0.7636307 0.7542837 0.6548449 0.6414627 0.5224251 0.8941671 0.4636315
## [141] 0.6572211 0.7452532 0.5236303 0.7085883 0.7859511 0.8475944 0.6198922
## [148] 0.8928947
mean(MF$AUC)
## [1] 0.9613633
mean(MF$TjurR2)
## [1] 0.6226501
#Here, we take the mean of posterior samples for further processing
predY = apply(abind(predY,along=3),c(1,2), mean)
# Plot species specific R2 in relation to prevalence
plot(colSums(((m$Y>0)*1)/m$ny), MF$AUC,main=paste("Mean AUC = ", round(mean(MF$AUC),2),".", sep=""), xlab = "Prevalence")
Let’s jump straight to the model outputs we examined earlier (NOTE: this model did not converge as well and would need to run it longer for more reliable results)
par(mfrow=c(1,1))
# Specify groups of how the variation should be partitioned You can also combine groups
group=c(1,2,3,4,5,6,7)
# Specify group names m$covNames[-1] gives the included covariate names excluding the intercept
groupnames = m$covNames[-1]
#compte species specific variance partitioning
VP = computeVariancePartitioning(hM = m, group = group, groupnames = groupnames)
plotVariancePartitioning(m, VP, viridis(8))
Note that e.g. SBT seems to contribute more to the explained variation for the occurrences of species (17.4%) compared to the abundances (computed above 10.8%)
# Shown are all species with 90% posterior support for having positive (red) or negative(blue) responses to environmental covariates
beta = getPostEstimate(m, "Beta")
plotBeta(m, beta, supportLevel=.9, spNamesNumbers = c(FALSE, FALSE), covNamesNumbers = c(TRUE, FALSE), plotTree = T)
## [1] 0.3 1.0 0.0 1.0
Also, responses of species to covariates structuring their presence or absence differ to those structuring abundances. See e.g. clear change of species response patterns in Chl and fishing (now positive) compared to the more negative responses for abundances calculated above.
gamma = getPostEstimate(m, "Gamma")
plotGamma(m, gamma, supportLevel=.9)
VP$R2T$Beta
## (Intercept) Depth SBT SBS Chl SBT_sea
## 0.08335066 0.10070599 0.12260729 0.06524582 0.13810405 0.20474257
## Chl_sea Fishing
## 0.12547593 0.11947270
VP$R2T$Y
## [1] 0.1431769
Here we also see more relationships with high statistical support of traits and environment. However, the patterns we saw earlier, i.e. positive relationships between SBT and Lifespan and Fecundity, are also found here.
We also discover that traits contribute substantially more to the variation of species occurrences than to species abundances (14.3% vs. ~2%).
Locking at VP\(R2T\)Beta we see that traits explain 20% of the variation among the species in their responses SBT_sea
# Construct environmental Gradient based on fitted model, specify your focal variable.
Gradient = constructGradient(m, focalVariable="SBT", ngrid = 25)
# make predictions based on fitted model
predYgradient = predict(m,XData=Gradient$XDataNew, ranLevels = Gradient$rLNew, studyDesign = Gradient$studyDesignNew, expected = TRUE)
par(mfrow=c(2,4))
# measure = T implies trait relationship to focal variable, index = 2 implies second trait of trait matrix (1 is the intercept).
# traits ~ SBT
plotGradient(m, Gradient, pred=predYgradient, measure="T",
index = 2, showData =F, showPosteriorSupport=F)
## [1] 0.994
plotGradient(m, Gradient, pred=predYgradient, measure="T",
index = 3, showData =F, showPosteriorSupport=F)
## [1] 0.539
plotGradient(m, Gradient, pred=predYgradient, measure="T",
index = 4, showData =F, showPosteriorSupport=F)
## [1] 0.712
plotGradient(m, Gradient, pred=predYgradient, measure="T",
index = 5, showData =F, showPosteriorSupport=F)
## [1] 0.979
plotGradient(m, Gradient, pred=predYgradient, measure="T",
index = 6, showData =F, showPosteriorSupport=F)
## [1] 0.001
plotGradient(m, Gradient, pred=predYgradient, measure="T",
index = 7, showData =F, showPosteriorSupport=F)
## [1] 0.971
plotGradient(m, Gradient, pred=predYgradient, measure="T",
index = 8, showData =F, showPosteriorSupport=F)
## [1] 0.923
#in a presence absence probit model, measure S provides the response of species richness against your chosen covariate
plotGradient(m, Gradient, pred=predYgradient, measure="S",
index = 1, showData =F, showPosteriorSupport=F)
## [1] 0.998