library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.2.3
library(StanHeaders)
## Warning: package 'StanHeaders' was built under R version 4.2.3
library(rstan)
## Warning: package 'rstan' was built under R version 4.2.3
## 
## rstan version 2.26.21 (Stan version 2.26.1)
## For execution on a local, multicore CPU with excess RAM we recommend calling
## options(mc.cores = parallel::detectCores()).
## To avoid recompilation of unchanged Stan programs, we recommend calling
## rstan_options(auto_write = TRUE)
## For within-chain threading using `reduce_sum()` or `map_rect()` Stan functions,
## change `threads_per_chain` option:
## rstan_options(threads_per_chain = 1)
## Do not specify '-march=native' in 'LOCAL_CPPFLAGS' or a Makevars file
library(brms)
## Loading required package: Rcpp
## Loading 'brms' package (version 2.19.0). Useful instructions
## can be found by typing help('brms'). A more detailed introduction
## to the package is available through vignette('brms_overview').
## 
## Attaching package: 'brms'
## The following object is masked from 'package:rstan':
## 
##     loo
## The following object is masked from 'package:stats':
## 
##     ar
library(tidybayes)
## 
## Attaching package: 'tidybayes'
## The following objects are masked from 'package:brms':
## 
##     dstudent_t, pstudent_t, qstudent_t, rstudent_t
library(tidyr)
## 
## Attaching package: 'tidyr'
## The following object is masked from 'package:rstan':
## 
##     extract
library(bayestestR)
## 
## Attaching package: 'bayestestR'
## The following object is masked from 'package:tidybayes':
## 
##     hdi
library(bayesplot)
## This is bayesplot version 1.10.0
## - Online documentation and vignettes at mc-stan.org/bayesplot
## - bayesplot theme set to bayesplot::theme_default()
##    * Does _not_ affect other ggplot2 plots
##    * See ?bayesplot_theme_set for details on theme setting
## 
## Attaching package: 'bayesplot'
## The following object is masked from 'package:brms':
## 
##     rhat
library(cowplot)
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.2.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggpubr)
## 
## Attaching package: 'ggpubr'
## The following object is masked from 'package:cowplot':
## 
##     get_legend
library(kableExtra)
## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows
library(loo)
## Warning: package 'loo' was built under R version 4.2.3
## This is loo version 2.5.1
## - Online documentation and vignettes at mc-stan.org/loo
## - As of v2.0.0 loo defaults to 1 core but we recommend using as many as possible. Use the 'cores' argument or set options(mc.cores = NUM_CORES) for an entire session.
## - Windows 10 users: loo may be very slow if 'mc.cores' is set in your .Rprofile file (see https://github.com/stan-dev/loo/issues/94).
## 
## Attaching package: 'loo'
## The following object is masked from 'package:rstan':
## 
##     loo

#read in stable isotope data and scale/center

isodata <- read.csv("isotopedata.csv")
summary(isodata)
##      Lake                DOW               Site              Fd.13.C      
##  Length:23          Min.   : 1006200   Length:23          Min.   :-37.23  
##  Class :character   1st Qu.:21014500   Class :character   1st Qu.:-31.95  
##  Mode  :character   Median :49007900   Mode  :character   Median :-29.73  
##                     Mean   :40531987                      Mean   :-30.82  
##                     3rd Qu.:49012700                      3rd Qu.:-28.27  
##                     Max.   :86009000                      Max.   :-23.96  
##     Ed.13.C          Fd.15.N          Ed.15.N      
##  Min.   :-35.12   Min.   : 3.240   Min.   : 3.070  
##  1st Qu.:-29.95   1st Qu.: 3.940   1st Qu.: 4.105  
##  Median :-27.63   Median : 6.470   Median : 6.110  
##  Mean   :-29.13   Mean   : 7.089   Mean   : 6.916  
##  3rd Qu.:-27.36   3rd Qu.: 8.450   3rd Qu.: 8.255  
##  Max.   :-24.28   Max.   :14.440   Max.   :12.750

#adjust data by centering

#center data
isodata$Ed.13.Ccentered <- scale(isodata$Ed.13.C, center = T, scale = F)
isodata$Fd.13.Ccentered <- scale(isodata$Fd.13.C, center = T, scale = F)
isodata$Ed.15.Ncentered <- scale(isodata$Ed.15.N, center = T, scale = F)
isodata$Fd.15.Ncentered <- scale(isodata$Fd.15.N, center = T, scale = F)

#save values used to center fresh data
attrFC <- attributes(isodata$Fd.13.Ccentered)
attrFN <- attributes(isodata$Fd.15.Ncentered)

# plot(isodata$Ed.13.Ccentered, isodata$Fd.13.Ccentered)
# plot(isodata$Ed.13.C, isodata$Fd.13.C)

#run models in BRMS using scaled data #model output available as RDS file

# set.seed(1)
# brmCcentered <- brm(Fd.13.Ccentered ~ 0 + Ed.13.Ccentered + (1 + Ed.13.Ccentered|Lake), isodata, family = gaussian, iter = 100000)
# brmNcentered <- brm(Fd.15.Ncentered ~ 0 + Ed.15.Ncentered + (1 + Ed.15.Ncentered|Lake), isodata, family = gaussian, iter = 100000)

# read in model output
brmCcentered <- readRDS("carbon_model_centered.rds")
brmNcentered <- readRDS("nitrogen_model_centered.rds")

#summary(brmCcentered, waic = TRUE)
#summary(brmNcentered, waic = TRUE)

#model output
#summary of all carbon model parameters
brmCcentered %>%
  summarise_draws()   #90% slope CI: 0.94 - 1.38 (1.158)
## # A tibble: 17 × 10
##    variable          mean   median     sd    mad       q5     q95  rhat ess_bulk
##    <chr>            <num>    <num>  <num>  <num>    <num>   <num> <num>    <num>
##  1 b_Ed.13.Ccen…  1.16e+0  1.16e+0 0.137  0.104    0.940    1.38   1.00   15319.
##  2 sd_Lake__Int…  5.02e-1  4.00e-1 0.432  0.319    0.0443   1.32   1.00    8208.
##  3 sd_Lake__Ed.…  2.18e-1  1.55e-1 0.218  0.150    0.0133   0.652  1.00    3219.
##  4 cor_Lake__In…  3.23e-2  4.45e-2 0.583  0.754   -0.892    0.913  1.00   22841.
##  5 sigma          5.67e-1  5.54e-1 0.104  0.0965   0.422    0.757  1.00    5221.
##  6 r_Lake[Alexa… -8.18e-2 -2.47e-2 0.416  0.252   -0.808    0.505  1.00   11589.
##  7 r_Lake[Big.S… -6.85e-2 -1.54e-2 0.500  0.277   -0.915    0.624  1.00    6226.
##  8 r_Lake[Buffa… -3.34e-1 -2.86e-1 0.383  0.357   -0.999    0.151  1.00    3261.
##  9 r_Lake[Chipp… -8.43e-3 -3.59e-3 0.198  0.165   -0.341    0.318  1.00   66696.
## 10 r_Lake[Shami…  2.69e-1  2.19e-1 0.396  0.324   -0.234    0.926  1.00    8348.
## 11 r_Lake[Alexa…  2.87e-2  1.04e-2 0.149  0.0882  -0.189    0.294  1.00   14253.
## 12 r_Lake[Big.S… -2.84e-2 -1.30e-2 0.143  0.0885  -0.271    0.188  1.00    9025.
## 13 r_Lake[Buffa… -8.87e-2 -4.68e-2 0.236  0.135   -0.509    0.220  1.00    3355.
## 14 r_Lake[Chipp…  6.08e-3  1.30e-3 0.162  0.0946  -0.252    0.272  1.00   19413.
## 15 r_Lake[Shami…  9.00e-2  4.70e-2 0.213  0.122   -0.175    0.475  1.00    7859.
## 16 lprior        -4.45e+0 -4.43e+0 0.0938 0.0313  -4.60    -4.40   1.00    5707.
## 17 lp__          -4.08e+1 -4.05e+1 3.72   3.61   -47.4    -35.3    1.00    4098.
## # ℹ 1 more variable: ess_tail <num>
#summary of all nitrogen model parameters
brmNcentered %>%
  summarise_draws()   #90% slope CI: 0.89 - 1.28 (1.077)
## # A tibble: 17 × 10
##    variable          mean   median     sd    mad       q5     q95  rhat ess_bulk
##    <chr>            <num>    <num>  <num>  <num>    <num>   <num> <num>    <num>
##  1 b_Ed.15.Ncen…  1.08e+0  1.08e+0 0.117  0.0825  8.95e-1   1.28   1.00    1011.
##  2 sd_Lake__Int…  3.85e-1  2.66e-1 0.435  0.244   2.43e-2   1.10   1.00    1391.
##  3 sd_Lake__Ed.…  1.78e-1  1.05e-1 0.245  0.103   9.06e-3   0.592  1.00     724.
##  4 cor_Lake__In…  5.29e-2  6.68e-2 0.582  0.754  -8.89e-1   0.922  1.00   20212.
##  5 sigma          5.55e-1  5.42e-1 0.0970 0.0889  4.22e-1   0.732  1.00   33324.
##  6 r_Lake[Alexa… -1.35e-1 -7.17e-2 0.411  0.210  -8.03e-1   0.330  1.00    1057.
##  7 r_Lake[Big.S…  1.09e-1  6.24e-2 0.224  0.163  -1.93e-1   0.528  1.00    4499.
##  8 r_Lake[Buffa…  6.02e-3  3.93e-3 0.458  0.187  -5.79e-1   0.638  1.01     504.
##  9 r_Lake[Chipp… -1.28e-1 -9.13e-2 0.199  0.165  -4.93e-1   0.143  1.00   16821.
## 10 r_Lake[Shami…  3.09e-2  1.88e-2 0.367  0.186  -5.30e-1   0.592  1.00    1006.
## 11 r_Lake[Alexa…  4.48e-2  2.07e-2 0.171  0.0814 -1.74e-1   0.332  1.00     916.
## 12 r_Lake[Big.S… -1.34e-2 -3.91e-3 0.139  0.0735 -2.46e-1   0.197  1.00    1556.
## 13 r_Lake[Buffa…  1.87e-2  1.12e-2 0.130  0.0636 -1.47e-1   0.221  1.00     930.
## 14 r_Lake[Chipp… -5.14e-2 -1.55e-2 0.158  0.0777 -3.60e-1   0.140  1.00    1039.
## 15 r_Lake[Shami… -3.64e-2 -1.21e-2 0.156  0.0691 -2.60e-1   0.152  1.00    1004.
## 16 lprior        -5.50e+0 -5.48e+0 0.0618 0.0106 -5.56e+0  -5.47   1.00     951.
## 17 lp__          -4.21e+1 -4.19e+1 3.66   3.59   -4.85e+1 -36.6    1.00    1244.
## # ℹ 1 more variable: ess_tail <num>
# plot model output
#plot(brmCcentered)
#plot(brmNcentered)

#graph fixed effects

Cfe_only <- tibble(Ed.13.Ccentered = seq(min(isodata$Ed.13.Ccentered), max(isodata$Ed.13.Ccentered), length.out=500)) %>%
  add_fitted_draws(brmCcentered, re_formula = NA, scale = "response", n = 500)
## Warning: `fitted_draws` and `add_fitted_draws` are deprecated as their names were confusing.
## - Use [add_]epred_draws() to get the expectation of the posterior predictive.
## - Use [add_]linpred_draws() to get the distribution of the linear predictor.
## - For example, you used [add_]fitted_draws(..., scale = "response"), which
##   means you most likely want [add_]epred_draws(...).
## NOTE: When updating to the new functions, note that the `model` parameter is now
##   named `object` and the `n` parameter is now named `ndraws`.
Cfe_only_mean <- Cfe_only %>% 
  group_by(Ed.13.Ccentered) %>%
  summarise(.value = mean(.value))

Cfixed <- ggplot(Cfe_only, aes(x = Ed.13.Ccentered, y = .value)) +
  stat_interval(alpha = 0.05) +
  guides(color = FALSE) +
  geom_line(data = Cfe_only_mean, color = "red", lwd = 1) +
  geom_point(data = isodata, mapping = aes(x = Ed.13.Ccentered, y = Fd.13.Ccentered, shape = Lake), color = "black", size = 3.5, stroke = .7) +
  scale_shape_manual(labels = c("Alexander", "Big Sandy", "Buffalo", "Chippewa", "Shamineau"),
                    values = c(2,8,7,21,3)) +
  geom_abline(slope = 1, intercept = 0, lty = 2, lwd = 1) +
  labs(x = expression(paste("EtOH ", delta^{13}, " C (\u2030)")), y = expression(paste("Fresh ", delta^{13}, " C (\u2030)"))) +
  theme_linedraw() + 
  theme(axis.title=element_text(size=16,face="bold"))
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
Nfe_only <- tibble(Ed.15.Ncentered = seq(min(isodata$Ed.15.Ncentered), max(isodata$Ed.15.Ncentered), length.out=500)) %>%
  add_fitted_draws(brmNcentered, re_formula = NA, scale = "response", n = 500)
## Warning: `fitted_draws` and `add_fitted_draws` are deprecated as their names were confusing.
## - Use [add_]epred_draws() to get the expectation of the posterior predictive.
## - Use [add_]linpred_draws() to get the distribution of the linear predictor.
## - For example, you used [add_]fitted_draws(..., scale = "response"), which
##   means you most likely want [add_]epred_draws(...).
## NOTE: When updating to the new functions, note that the `model` parameter is now
##   named `object` and the `n` parameter is now named `ndraws`.
Nfe_only_mean <- Nfe_only %>% 
  group_by(Ed.15.Ncentered) %>%
  summarise(.value = mean(.value))

Nfixed <- ggplot(Nfe_only, aes(x = Ed.15.Ncentered, y = .value)) +
  stat_interval(alpha = 0.05) +
  guides(color = FALSE) +
  geom_line(data = Nfe_only_mean, color = "red", lwd = 1) +
  geom_point(data = isodata, mapping = aes(x = Ed.15.Ncentered, y = Fd.15.Ncentered, shape = Lake), color = "black", size = 3.5, stroke = .7) +
  scale_shape_manual(labels = c("Alexander", "Big Sandy", "Buffalo", "Chippewa", "Shamineau"),
                    values = c(2,8,7,21,3)) +
  geom_abline(slope = 1, intercept = 0, lty = 2, lwd = 1) +
  labs(x = expression(paste("EtOH ", delta^{15}, " N (\u2030)")), y = expression(paste("Fresh ", delta^{15}, " N (\u2030)"))) +
  theme_linedraw() + 
  theme(axis.title=element_text(size=16,face="bold"))

CNfixed <- ggarrange(Cfixed, Nfixed,
                     nrow = 1, ncol = 2,
                     common.legend = TRUE, legend = "bottom")
CNfixed

#check group-level slope/intercept effects

# find region of practical equivalence
# rope(brmCcentered) #0.38
# rope(brmNcentered) #0.36

Cslope <- brmCcentered %>%
  spread_draws(r_Lake[Lake,Ed.13.Ccentered]) %>%
  ggplot(aes(y = Lake, x = r_Lake, fill = stat(abs(x)  < .38))) +
  stat_halfeye() +
  geom_vline(xintercept = c(-.38, .38), linetype = "dashed") +
  scale_fill_manual(values = c("gray80", "skyblue")) +
  xlab("Carbon Random Slope Offset") + 
  theme_linedraw()+
  theme(legend.position = "none") +
  scale_x_continuous(limits = c(-1.5,1.5)) 

Nslope <- brmNcentered %>%
  spread_draws(r_Lake[Lake,Ed.15.Ncentered]) %>%
  ggplot(aes(y = Lake, x = r_Lake, fill = stat(abs(x)  < .36))) +
  stat_halfeye() +
  geom_vline(xintercept = c(-.36, .36), linetype = "dashed") +
  scale_fill_manual(values = c("gray80", "skyblue")) +
  xlab("Nitrogen Random Slope Offset") +
  theme_linedraw()+
  theme(legend.position = "none") +
  scale_x_continuous(limits = c(-1.5,1.5)) 

Cintercept <- brmCcentered %>%
  spread_draws(r_Lake[Lake,Intercept]) %>%
  ggplot(aes(y = Lake, x = r_Lake, fill = stat(abs(x)  < .38))) +
  stat_halfeye() +
  geom_vline(xintercept = c(-.38, .38), linetype = "dashed") +
  scale_fill_manual(values = c("gray80", "skyblue")) +
  xlab("Carbon Random Intercept Offset") +
  theme_linedraw()+
  theme(legend.position = "none") +
  scale_x_continuous(limits = c(-1.5,1.5)) 

Nintercept <- brmNcentered %>%
  spread_draws(r_Lake[Lake,Intercept]) %>%
  ggplot(aes(y = Lake, x = r_Lake, fill = stat(abs(x)  < .36))) +
  stat_halfeye() +
  geom_vline(xintercept = c(-.36, .36), linetype = "dashed") +
  scale_fill_manual(values = c("gray80", "skyblue")) +
  xlab("Nitrogen Random Intercept Offset") +
  theme_linedraw()+
  theme(legend.position = "none") +
  scale_x_continuous(limits = c(-1.5,1.5)) 

CNoffsets <- plot_grid(Cslope, 
                   Nslope + theme(axis.text.y = element_blank(),
                                    axis.ticks.y = element_blank(),
                                    axis.title.y = element_blank()),
                   Cintercept,
                   Nintercept + theme(axis.text.y = element_blank(),
                                    axis.ticks.y = element_blank(),
                                    axis.title.y = element_blank()),
                   nrow = 2,
                   labels = NA)
## Warning: `stat(abs(x) < 0.38)` was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(abs(x) < 0.38)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Removed 10264 rows containing missing values (`stat_slabinterval()`).
## Warning: Removed 9591 rows containing missing values (`stat_slabinterval()`).
## Warning: Removed 10264 rows containing missing values (`stat_slabinterval()`).
## Warning: Removed 9591 rows containing missing values (`stat_slabinterval()`).
CNoffsets
## Warning: Removed 1 rows containing missing values (`geom_text()`).

#hypothesis testing

#R-squared values
bayes_R2(brmCcentered) #0.980
##     Estimate   Est.Error      Q2.5     Q97.5
## R2 0.9795584 0.004056344 0.9693175 0.9843029
bayes_R2(brmNcentered) #0.979
##     Estimate   Est.Error      Q2.5     Q97.5
## R2 0.9785942 0.003518459 0.9696729 0.9827415
#set up hypothesis test based on fixed effect output
#fixef(brmCcentered)
#fixef(brmNcentered)

hypothesis(brmCcentered, "Ed.13.Ccentered > 1") #91% chance slope is greater than 1 
## Hypothesis Tests for class b:
##                 Hypothesis Estimate Est.Error CI.Lower CI.Upper Evid.Ratio
## 1 (Ed.13.Ccentered)... > 0     0.16      0.14    -0.06     0.38       9.77
##   Post.Prob Star
## 1      0.91     
## ---
## 'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
## '*': For one-sided hypotheses, the posterior probability exceeds 95%;
## for two-sided hypotheses, the value tested against lies outside the 95%-CI.
## Posterior probabilities of point hypotheses assume equal prior probabilities.
hypothesis(brmNcentered, "Ed.15.Ncentered > 1") #81% chance slope is greater than 1 
## Hypothesis Tests for class b:
##                 Hypothesis Estimate Est.Error CI.Lower CI.Upper Evid.Ratio
## 1 (Ed.15.Ncentered)... > 0     0.08      0.12    -0.11     0.28       4.14
##   Post.Prob Star
## 1      0.81     
## ---
## 'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
## '*': For one-sided hypotheses, the posterior probability exceeds 95%;
## for two-sided hypotheses, the value tested against lies outside the 95%-CI.
## Posterior probabilities of point hypotheses assume equal prior probabilities.

##test model accuracy #K-fold cross validation test for carbon

#kfoldC <- kfold(brmCcentered, K = 5, folds = 'grouped', group = "Lake", save_fits = TRUE)
#kfoldN <- kfold(brmNcentered, K = 5, folds = 'grouped', group = "Lake", save_fits = TRUE)

#read in k-fold cross validation results
kfoldC <- readRDS("kfoldcarboncentered.rds")
kfoldN <- readRDS("kfoldnitrogencentered.rds")

#define loss functions
rmse <- function(y, yrep) {
  yrep_mean <- colMeans(yrep)
  sqrt(mean((y - yrep_mean)^2))
}

rmspe <- function(y, yrep) {
  yrep_mean <- colMeans(yrep)
  sqrt(mean((y - yrep_mean)/y)^2)
}

#predict responses and evaluate loss
#carbon
kfpC <- kfold_predict(kfoldC)
rmse(y = kfpC$y, yrep = kfpC$yrep) #0.701
## [1] 0.7027048
rmspe(y = kfpC$y, yrep = kfpC$yrep) #2.94%
## [1] 2.940255
#nitrogen
kfpN <- kfold_predict(kfoldN)
rmse(y = kfpN$y, yrep = kfpN$yrep) #0.59
## [1] 0.5900601
rmspe(y = kfpN$y, yrep = kfpN$yrep) #6.01%
## [1] 6.024614

#apply correction to ethanol values and rescale

#save model slopes
Ccentered <- as.data.frame(fixef(brmCcentered))
Ncentered <- as.data.frame(fixef(brmNcentered))

#create new centered fresh values by multiplying by slopes and add to initial dataframe
isodata$newfreshcenteredC <- (isodata$Ed.13.Ccentered * Ccentered[1,1])
isodata$newfreshcenteredN <- (isodata$Ed.15.Ncentered * Ncentered[1,1])

#rescale new fresh values by adding mean fresh values
isodata$returnfreshC <- isodata$newfreshcenteredC + attrFC$'scaled:center' 
isodata$returnfreshN <- isodata$newfreshcenteredN + attrFN$'scaled:center'

#values used to uncenter
mean(isodata$Fd.13.C) #-30.819
## [1] -30.81913
mean(isodata$Fd.15.N) #7.089
## [1] 7.088696

#testing that model fit is more accurate than no change (1:1 line)

#create fitted values on 1:1 line
checkC <- lm(returnfreshC ~ 0 + offset(1 * Ed.13.C), data = isodata)
checkN <- lm(returnfreshN ~ 0 + offset(1 * Ed.15.N), data = isodata)


#plots of original values(black), corrected values based on brms model(blue), and data fit on 1:1 line(red)
# carbon
plot(isodata$Ed.13.C, isodata$Fd.13.C, pch = 19)
abline(coef = c(0,1))
points(isodata$Ed.13.C, checkC$fitted.values, col = "red", pch = 19)
points(isodata$Ed.13.C, isodata$returnfreshC, col = "blue", pch = 19)
legend(x = -35.5, y = -24,legend = c("observed data", "1:1 fit", "model corrected data"), fill = c("black", "red", "blue"))

# nitrogen
plot(isodata$Ed.15.N, isodata$Fd.15.N, pch = 19)
abline(coef = c(0,1))
points(isodata$Ed.15.N, checkN$fitted.values, col = "red", pch = 19)
points(isodata$Ed.15.N, isodata$returnfreshN, col = "blue", pch = 19)
legend(x = 3, y = 14,legend = c("observed data", "1:1 fit", "model corrected data"), fill = c("black", "red", "blue"))

#RMSE for observed fresh values vs. 1:1 line
sqrt(sum((isodata$Fd.13.C - checkC$fitted.values)^2)/nrow(isodata)) #1.86 carbon
## [1] 1.856626
sqrt(sum((isodata$Fd.15.N - checkN$fitted.values)^2)/nrow(isodata)) #0.61 nitrogen
## [1] 0.614205
#RMSE for observed fresh values vs. model fit: model fit is more accurate
sqrt(sum((isodata$Fd.13.C - isodata$returnfreshC)^2)/nrow(isodata)) #0.61 carbon
## [1] 0.6060523
sqrt(sum((isodata$Fd.15.N - isodata$returnfreshN)^2)/nrow(isodata)) #0.53 nitrogen
## [1] 0.5267476

#marginal predictive check using LOO probability integral transform

#Carbon

#run leave-one-out cross validation
looC <- loo(brmCcentered, save_psis = TRUE)
## Warning: Found 2 observations with a pareto_k > 0.7 in model 'brmCcentered'. It
## is recommended to set 'moment_match = TRUE' in order to perform moment matching
## for problematic observations.
plot(looC) # diagnostic plot

yrepC <- posterior_predict(brmCcentered, na.rm = TRUE) # model output
psisC <- looC$psis_object 
lwC <- weights(psisC, na.rm = TRUE) # normalized log weights
yC <- isodata$Fd.13.Ccentered[,1] # observed fresh zooplankton values

#plot results
loo_C <- suppressWarnings(ppc_loo_intervals(yC, yrepC, psis_object = psisC))
loo_C

# Most confident between ~-26 to -39 for C13, transformed to uncentered values
4 + attrFC$'scaled:center' # -26.819
## [1] -26.81913
-8 + attrFC$'scaled:center' # -38.819
## [1] -38.81913
#RMSE value for carbon (k-fold CV RMSE more representative of data, grouped by lake)
rmse(y = yC, yrep = yrepC) #.470
## [1] 0.4700717
rmspe(y = yC, yrep = yrepC) #2.314%
## [1] 2.306374
#Nitrogen

#run leave-one-out cross validation
looN <- loo(brmNcentered, save_psis = TRUE)
plot(looN)

yrepN <- posterior_predict(brmNcentered, na.rm = TRUE)
psisN <- looN$psis_object
lwN <- weights(psisN, na.rm = TRUE) # normalized log weights
yN <- isodata$Fd.15.Ncentered[,1] # this would be fresh zooplankton values for you

#plot results
loo_N <- suppressWarnings(ppc_loo_intervals(yN, yrepN, psis_object = psisN))
loo_N

# Most confident between ~2 to 15 for N15
7.5 + attrFN$'scaled:center' # 14.587
## [1] 14.5887
-5 + attrFN$'scaled:center' # 2.089
## [1] 2.088696
#RMSE value for nitrogen (k-fold CV RMSE more representative of data, grouped by lake)
rmse(y = yN, yrep = yrepN) #.469
## [1] 0.4687541
rmspe(y = yN, yrep = yrepN) # 4.994%
## [1] 4.988865
#plot combined results
loo_check <- plot_grid(loo_C + theme(legend.position="none"), loo_N + theme(legend.position="none"), align = 'h', labels = c("C13", "N15"), label_x = .05, ncol = 2, rel_widths = c(1,1))

legend <- get_legend(loo_C)

loo_check <- plot_grid(loo_check, legend, ncol = 2, rel_widths = c(1,.1))
loo_check

#table of model output and covergence
posterior <- as.data.frame(matrix(NA, nrow = 2, ncol = 5))

posterior[1,] <- diagnostic_posterior(brmCcentered)
posterior[2,] <- diagnostic_posterior(brmNcentered)
posterior[,5] <- c(0.980, 0.979)
posterior[,1] <- c("Carbon", "Nitrogen")
colnames(posterior) <- c("Slope Parameter", "R-hat", "ESS", "MCSE", "R^2")

output <- as.data.frame(matrix(NA, nrow = 2, ncol = 4))

output[1,] <- fixef(brmCcentered)
output[2,] <- fixef(brmNcentered)
output$slope <- c("Carbon", "Nitrogen")
colnames(output) <- c("Estimate", "Est.Error", "Q2.5", "Q97.5", "Slope Parameter")
col_order <- c("Slope Parameter", "Estimate", "Est.Error", "Q2.5", "Q97.5")
output <- output[,col_order]

combined <- bind_cols(output, posterior[,-1])
write.table(combined, file = "combinedtable.txt", sep = ',')

combined %>%
  kbl(caption = "Model Output", digits = 3)  %>%
  kable_classic(full_width = F, html_font = "Cambria")
Model Output
Slope Parameter Estimate Est.Error Q2.5 Q97.5 R-hat ESS MCSE R^2
Carbon 1.158 0.137 0.866 1.441 1.000 10381.910 0.001 0.980
Nitrogen 1.077 0.117 0.833 1.359 1.005 378.018 0.006 0.979
combine
## function (...) 
## {
##     lifecycle::deprecate_warn("1.0.0", "combine()", "vctrs::vec_c()", 
##         always = TRUE)
##     args <- list2(...)
##     if (length(args) == 1 && is.list(args[[1]])) {
##         args <- args[[1]]
##     }
##     args <- keep(args, function(.x) !is.null(.x))
##     names(args) <- NULL
##     if (length(args) == 0) {
##         logical()
##     }
##     else {
##         vec_c(!!!args)
##     }
## }
## <bytecode: 0x000001db667a5918>
## <environment: namespace:dplyr>
#hypothesis test table
hyptest <- as.data.frame(matrix(NA, nrow = 2, ncol = 7))

hyptest[1,] <- c("C13 Slope > 1", 0.16, 0.14, -0.06, 0.38, 9.77, 0.91)
hyptest[2,] <- c("N15 Slope > 1", 0.08, 0.12, -0.11, 0.28, 4.14, 0.81)
colnames(hyptest) <- c("Test", "Estimate", "Est.Error", "LCI", "UCI", "Evid. Ratio", "Probability")

write.table(hyptest, file = "hyptesttable.txt", sep = ',')

hyptest <- hyptest %>%
  kbl(caption = "Hypothesis Test Results", digits = 3)  %>%
  kable_classic(full_width = F, html_font = "Cambria")
hyptest
Hypothesis Test Results
Test Estimate Est.Error LCI UCI Evid. Ratio Probability
C13 Slope > 1 0.16 0.14 -0.06 0.38 9.77 0.91
N15 Slope > 1 0.08 0.12 -0.11 0.28 4.14 0.81
sessionInfo()
## R version 4.2.2 (2022-10-31 ucrt)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19045)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=English_United States.utf8 
## [2] LC_CTYPE=English_United States.utf8   
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.utf8    
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] loo_2.5.1           kableExtra_1.3.4    ggpubr_0.6.0       
##  [4] dplyr_1.1.1         cowplot_1.1.1       bayesplot_1.10.0   
##  [7] bayestestR_0.13.0   tidyr_1.3.0         tidybayes_3.0.3    
## [10] brms_2.19.0         Rcpp_1.0.10         rstan_2.26.21      
## [13] StanHeaders_2.26.21 ggplot2_3.4.2      
## 
## loaded via a namespace (and not attached):
##   [1] colorspace_2.1-0     ggsignif_0.6.4       ellipsis_0.3.2      
##   [4] markdown_1.5         base64enc_0.1-3      rstudioapi_0.14     
##   [7] farver_2.1.1         svUnit_1.0.6         DT_0.27             
##  [10] lubridate_1.9.2      fansi_1.0.4          mvtnorm_1.1-3       
##  [13] xml2_1.3.3           bridgesampling_1.1-2 codetools_0.2-18    
##  [16] cachem_1.0.7         knitr_1.42           shinythemes_1.2.0   
##  [19] jsonlite_1.8.4       broom_1.0.3          ggdist_3.2.1        
##  [22] shiny_1.7.4          httr_1.4.5           compiler_4.2.2      
##  [25] backports_1.4.1      Matrix_1.5-1         fastmap_1.1.1       
##  [28] cli_3.6.1            later_1.3.0          htmltools_0.5.5     
##  [31] prettyunits_1.1.1    tools_4.2.2          igraph_1.4.1        
##  [34] coda_0.19-4          gtable_0.3.3         glue_1.6.2          
##  [37] reshape2_1.4.4       posterior_1.4.1      V8_4.2.2            
##  [40] carData_3.0-5        jquerylib_0.1.4      vctrs_0.6.1         
##  [43] svglite_2.1.1        nlme_3.1-160         crosstalk_1.2.0     
##  [46] insight_0.19.0       tensorA_0.36.2       xfun_0.38           
##  [49] stringr_1.5.0        ps_1.7.3             rvest_1.0.3         
##  [52] timechange_0.2.0     mime_0.12            miniUI_0.1.1.1      
##  [55] lifecycle_1.0.3      gtools_3.9.4         rstatix_0.7.2       
##  [58] zoo_1.8-11           scales_1.2.1         colourpicker_1.2.0  
##  [61] promises_1.2.0.1     Brobdingnag_1.2-9    parallel_4.2.2      
##  [64] inline_0.3.19        shinystan_2.6.0      yaml_2.3.7          
##  [67] curl_5.0.0           gridExtra_2.3        sass_0.4.5          
##  [70] stringi_1.7.12       highr_0.10           dygraphs_1.1.1.6    
##  [73] checkmate_2.1.0      pkgbuild_1.4.0       systemfonts_1.0.4   
##  [76] rlang_1.1.0          pkgconfig_2.0.3      matrixStats_0.63.0  
##  [79] distributional_0.3.2 evaluate_0.20        lattice_0.20-45     
##  [82] purrr_1.0.1          labeling_0.4.2       rstantools_2.3.0    
##  [85] htmlwidgets_1.6.2    processx_3.8.0       tidyselect_1.2.0    
##  [88] plyr_1.8.8           magrittr_2.0.3       R6_2.5.1            
##  [91] generics_0.1.3       pillar_1.9.0         withr_2.5.0         
##  [94] xts_0.13.0           datawizard_0.6.5     abind_1.4-5         
##  [97] tibble_3.2.1         crayon_1.5.2         car_3.1-1           
## [100] arrayhelpers_1.1-0   utf8_1.2.3           rmarkdown_2.21      
## [103] grid_4.2.2           callr_3.7.3          threejs_0.3.3       
## [106] webshot_0.5.4        digest_0.6.31        xtable_1.8-4        
## [109] httpuv_1.6.9         RcppParallel_5.1.7   stats4_4.2.2        
## [112] munsell_0.5.0        viridisLite_0.4.1    bslib_0.4.2         
## [115] shinyjs_2.1.0