The influence of species richness and climate and environmental conditions on diversification rates may change over time, for instance, due to inherent uncaptured changes of the system affecting the dynamic of the species assemblage (Silvestro & Schnitzler 2018). Such confounding effects were incorporated by time‑stratifying the analysis of covariate influence on speciation and extinction rates. We estimate the temporal heterogeneity of speciation and extinction rates in endemic species from three random samples of speciation and extinction times drawn from each of the 100 BDS analyses.
# Load required packages
library(coda)
library(foreach)
library(doParallel)
# Auxiliary functions
source("AuxiliaryFunctions/extractAgesFromMcmcLog.R")
Due to computational limits we will only extract 2 random sets out of the speciation and extinction times inferred by each of the 2 BDS analyses.
#
set.seed(23) # Reproducibility
BDS <- 1:2 # Number of BDS analyses
RanSamp <- 2 # Random samples of speciation and extinction times
for(i in BDS){
McmcLog <- read.table(paste0("Results/BDS/pyrate_mcmc_logs/TrimBounded_",
BDS[i], "_GBD1-1_mcmc.log"),
header = TRUE, sep = "\t")
extractAgesFromMcmcLog(McmcLog, N = RanSamp,
Out = paste0("Results/BD/Fix_", BDS[i], "_"))
}
We analysed the times of origination and extinction using a reversible jump (rj) MCMC (Silvestro et al. 2019) analysis. Marginal speciation and extinction rates were obtained from 2,000,000 rj-MCMC iterations with sampling every 2,500 iterations after discarding the first 50,000 iterations as burn-in.
runPyRateShift <- function(Fix, i){
system( paste("python2 PyRate/PyRate.py",
paste0("-d Results/BD/", Fix[i], ".txt"),
"-n 500001", # Generations to run
"-s 2500", # Sampling frequency
"-b 50000", # Burn-in
"-p 500000", # Print frequency
"-A 4",
"-edgeShift 13.65 0",
"-log_marginal_rates 0",
paste0("-wd Results/BD")))
}
Fix <- paste(paste0("Fix_", BDS), rep(1:RanSamp, each = length(BDS)), sep = "_")
Fix <- sort(Fix)
# Run on 2 cores in parallel
Ncores <- 2
registerDoParallel(Ncores)
PyRate <- foreach(iter = 1:4, .inorder = FALSE) %dopar% runPyRateShift(Fix, iter)
stopImplicitCluster()
Check effective sampling sizes
McmcLogFiles <- list.files("Results/BD/pyrate_mcmc_logs", pattern = "rj_mcmc.log")
McmcLogs <- vector(mode = "list", length(McmcLogFiles))
for(i in 1:length(McmcLogFiles)){
McmcLogs[[i]] <- read.table(paste0("Results/BD/pyrate_mcmc_logs/", McmcLogFiles[i]),
header = TRUE, sep = "\t")
}
lapply( McmcLogs, function(x) apply(x, 2, function(y) round(effectiveSize(as.mcmc(y)))))
## [[1]]
## it posterior prior BD_lik k_birth k_death
## 0 181 57 181 116 67
## RJ_hp root_age death_age tot_length
## 181 0 0 0
##
## [[2]]
## it posterior prior BD_lik k_birth k_death
## 0 181 97 181 137 40
## RJ_hp root_age death_age tot_length
## 181 0 0 0
##
## [[3]]
## it posterior prior BD_lik k_birth k_death
## 0 93 108 82 113 114
## RJ_hp root_age death_age tot_length
## 181 0 0 0
##
## [[4]]
## it posterior prior BD_lik k_birth k_death
## 0 181 114 124 181 86
## RJ_hp root_age death_age tot_length
## 181 0 0 0
Summarize from the posterior distribution the number of shifts in speciation and extinction rates and their ages.
SpRj <- list.files("Results/BD/pyrate_mcmc_logs/", pattern = "sp_rates")
ExRj <- list.files("Results/BD/pyrate_mcmc_logs/", pattern = "ex_rates")
EdgeShift <- 13.65
TimeSeq <- seq(EdgeShift, 0, by = -0.05)
SpTmp <- read.table(paste0("Results/BD/pyrate_mcmc_logs/", SpRj[1]),
sep = "\t", fill = NA, col.names = paste0("V", 1:20))
Nrow <- nrow(SpTmp)
ExThroughTime <- SpThroughTime <- matrix(NA_real_,
ncol = length(TimeSeq),
nrow = length(SpRj)*Nrow)
ExShifts <- SpShifts <- matrix(NA_real_, ncol = 8, nrow = length(SpRj) * Nrow)
Counter <- 1
for(i in 1:length(SpRj)){
# Give a high number of col.names because each line may differ in length
SpTmp <- read.table(paste0("Results/BD/pyrate_mcmc_logs/", SpRj[i]),
sep = "\t", fill = NA, col.names = paste0("V", 1:20))
ExTmp <- read.table(paste0("Results/BD/pyrate_mcmc_logs/", ExRj[i]),
sep = "\t", fill = NA, col.names = paste0("V", 1:20))
for(y in 1:nrow(SpTmp)){
# Speciation
Sp1Tmp <- unlist( SpTmp[y, ] )
# Rarely there is a shift inferred earlier then 13.65
if (all(Sp1Tmp <= EdgeShift, na.rm = TRUE)){
# Which element is > 136 (i.e., the constrained edgeShift)
W136 <- which(Sp1Tmp >= EdgeShift)
ShiftTimesTmp <- na.omit(Sp1Tmp[W136:length(Sp1Tmp)])
# Get the rates for each time step:
SpThroughTime[Counter, ] <- approx(x = c(ShiftTimesTmp, 0), y = Sp1Tmp[1:(W136-1)],
xout = TimeSeq, method = "constant")$y
SpShifts[Counter, 1:length(ShiftTimesTmp)] <- ShiftTimesTmp
}
# Extinction
Ex1Tmp <- unlist( ExTmp[y, ] )
if (all(Ex1Tmp <= EdgeShift, na.rm = TRUE)){
# Which element is > 136 (i.e., the constrained edgeShift)
W136 <- which(Ex1Tmp >= EdgeShift)
ShiftTimesTmp <- na.omit(Ex1Tmp[W136:length(Ex1Tmp)])
# Get the rates for each time step:
ExThroughTime[Counter, ] <- approx(x = c(ShiftTimesTmp, 0), y = Ex1Tmp[1:(W136-1)],
xout = TimeSeq, method = "constant")$y
ExShifts[Counter, 1:length(ShiftTimesTmp)] <- ShiftTimesTmp
}
Counter <- Counter + 1
}
}
# Omit the fixed edge shift of 13.65 million years
SpThroughTime <- SpThroughTime[, -1]
ExThroughTime <- ExThroughTime[, -1]
SpShifts <- SpShifts[, -1]
ExShifts <- ExShifts[, -1]
# Omit all rows with occasional NAs
Keep <- 1:(Counter-1) # Easier
SpThroughTime <- SpThroughTime[Keep, ]
ExThroughTime <- ExThroughTime[Keep, ]
SpShifts <- SpShifts[Keep, ]
ExShifts <- ExShifts[Keep, ]
# Rescale rates from 13.6 million years to 1.36
SpThroughTime <- SpThroughTime * 10
ExThroughTime <- ExThroughTime * 10
NetDivThroughTime <- SpThroughTime - ExThroughTime
SpShifts <- SpShifts / 10
ExShifts <- ExShifts / 10
# Fequency of shifts found across all birth-death analyses
PerSpShift <- apply(SpShifts, 2, function(x) sum(!is.na(x)) / length(x))
PerExShift <- apply(ExShifts, 2, function(x) sum(!is.na(x)) / length(x))
#
MedSpShift <- apply(SpShifts, 2, median, na.rm = TRUE)
MedExShift <- apply(ExShifts, 2, median, na.rm = TRUE)
ExShiftsHpd <- SpShiftsHpd <- matrix(NA_real_, nrow = 2, ncol = ncol(SpShifts))
for(i in 1:ncol(SpShifts)){
TmpShift <- na.omit(SpShifts[, i])
if(length(TmpShift) > 1){
SpShiftsHpd[, i] <- HPDinterval(coda:::mcmc(TmpShift))
}
TmpShift <- na.omit(ExShifts[, i])
if(length(TmpShift) > 1){
ExShiftsHpd[, i] <- HPDinterval(coda:::mcmc(TmpShift))
}
}
SummarySpShift <- rbind(PerSpShift, MedSpShift, SpShiftsHpd)
SummarySpShift <- SummarySpShift[, SummarySpShift[1, ] != 0]
rownames(SummarySpShift) <- c("Frequency", "Age", "LwrHPD", "UprHPD")
colnames(SummarySpShift) <- paste("Shift", 1:ncol(SummarySpShift))
SummarySpShift
## Shift 1 Shift 2 Shift 3 Shift 4
## Frequency 1.000000 0.9889503 0.1077348 0.004143646
## Age 1.242096 1.0304314 0.6242546 0.612175085
## LwrHPD 1.194638 0.5455362 0.1591756 0.578141248
## UprHPD 1.264968 1.1704639 1.1509796 0.793681392
SummaryExShift <- rbind(PerExShift, MedExShift, ExShiftsHpd)
SummaryExShift <- SummaryExShift[, SummaryExShift[1, ] != 0]
rownames(SummaryExShift) <- c("Frequency", "Age", "LwrHPD", "UprHPD")
colnames(SummaryExShift) <- paste("Shift", 1:ncol(SummaryExShift))
SummaryExShift
## Shift 1 Shift 2
## Frequency 0.788674 0.0704419890
## Age 1.174994 0.0086376024
## LwrHPD 1.018517 0.0006749044
## UprHPD 1.264901 1.1041635518
Plot speciation and extinction rates (including shifts) through time.
Prob <- seq(0.95, 0.05, by = -0.05)
NetDivThroughTimeHPD <- ExThroughTimeHPD <- SpThroughTimeHPD <- vector(mode = "list", length(Prob))
for(i in 1:length(Prob)){
SpThroughTimeHPD[[i]] <- apply(SpThroughTime, 2,
function(x) HPDinterval(coda:::mcmc(x), prob = Prob[i]))
ExThroughTimeHPD[[i]] <- apply(ExThroughTime, 2,
function(x) HPDinterval(coda:::mcmc(x), prob = Prob[i]))
NetDivThroughTimeHPD[[i]] <- apply(NetDivThroughTime, 2,
function(x) HPDinterval(coda:::mcmc(x), prob = Prob[i]))
}
# Means
SpThroughTimeMean <- apply(SpThroughTime, 2, median)
ExThroughTimeMean <- apply(ExThroughTime, 2, median)
TimeSeq <- TimeSeq[-1]
par(las = 1, mar = c(5.1, 4.5, 0.1, 0.8))
plot(1, 1, type = "n",
xlim = c(14, 0), ylim = c(0, max(unlist(SpThroughTimeHPD))),
xaxs = "i", xaxt = "n",
xlab = "Age (Myr ago)",
ylab = expression(paste("Speciation rate (events ", lineage^{-1}, " ", Myr^{-1}, ")")))
axis(side = 1, at = seq(14, 0, by = -2), labels = seq(14, 0, by = -2)/10)
abline(v = SummarySpShift[2, SummarySpShift[1, ] > 0.75]*10, lty = 2, col = "dodgerblue")
for(i in 1:length(Prob)){
polygon(c(TimeSeq, rev(TimeSeq)),
c(SpThroughTimeHPD[[i]][1, ], rev(SpThroughTimeHPD[[i]][2, ])),
col = adjustcolor("dodgerblue", alpha = 1/length(Prob)), border = NA)
}
lines(TimeSeq, SpThroughTimeMean, col = "dodgerblue")
par(las = 1, mar = c(5.1, 4.5, 0.1, 0.8))
plot(1, 1, type = "n",
xlim = c(14, 0), ylim = c(0, max(unlist(ExThroughTimeHPD))),
xaxs = "i", xaxt = "n",
xlab = "Age (Myr ago)",
ylab = expression(paste("Extinction rate (events ", lineage^{-1}, " ", Myr^{-1}, ")")))
axis(side = 1, at = seq(14, 0, by = -2), labels = seq(14, 0, by = -2)/10)
abline(v = SummaryExShift[2, SummaryExShift[1, ] > 0.75]*10, lty = 2, col = "red")
for(i in 1:length(Prob)){
polygon(c(TimeSeq, rev(TimeSeq)),
c(ExThroughTimeHPD[[i]][1, ], rev(ExThroughTimeHPD[[i]][2, ])),
col = adjustcolor("red", alpha = 1/length(Prob)), border = NA)
}
lines(TimeSeq, ExThroughTimeMean, col = "red")
Sys.time()
## [1] "2020-01-03 22:45:44 CET"
sessionInfo()
## R version 3.6.2 (2019-12-12)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 16.04.6 LTS
##
## Matrix products: default
## BLAS: /usr/lib/libblas/libblas.so.3.6.0
## LAPACK: /usr/lib/lapack/liblapack.so.3.6.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=de_DE.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=de_DE.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=de_DE.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=de_DE.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] parallel stats graphics grDevices utils datasets methods
## [8] base
##
## other attached packages:
## [1] doParallel_1.0.15 iterators_1.0.12 foreach_1.4.7 coda_0.19-3
## [5] knitr_1.25
##
## loaded via a namespace (and not attached):
## [1] Rcpp_1.0.2 codetools_0.2-16 lattice_0.20-38 digest_0.6.21
## [5] grid_3.6.2 magrittr_1.5 evaluate_0.14 rlang_0.4.0
## [9] stringi_1.4.3 rmarkdown_1.15 tools_3.6.2 stringr_1.4.0
## [13] xfun_0.10 yaml_2.2.0 compiler_3.6.2 htmltools_0.4.0