reading in data:

library(readr)
chpt2_r_data <- read_csv("~/Downloads/chapter 2 /chpt2.r.data.csv", 
    col_types = cols(block = col_character(), 
        patch = col_character(), position = col_character(), 
         location = col_factor(),        # ← add this
        season = col_factor(),          # ← add this
        max.temp = col_number(), ros = col_number(), 
        rcd10 = col_number(), rcd20 = col_number(), 
        mortality1 = col_number(), mortality2 = col_number(), 
        mortality3 = col_number(), mortality10 = col_number(), 
        mortality20 = col_number(), mortality100 = col_number(), 
        mortality200 = col_number(), green.needles = col_number(), 
        tree.char = col_number(), tree.scorch = col_number(), 
        rcd1.avg = col_number(), rcd2.avg = col_number(), 
        rcd3.avg = col_number(), rcd4.avg = col_number(), 
        difn = col_number()))
## New names:
## • `` -> `...27`
## • `` -> `...28`
## • `` -> `...29`
## Warning: One or more parsing issues, call `problems()` on your data frame for details,
## e.g.:
##   dat <- vroom(...)
##   problems(dat)
chpt2_r_data <- chpt2_r_data[-(37:52), ]
chpt2_r_data <- chpt2_r_data[, !(names(chpt2_r_data) %in% c("...27", "...28", "...29"))]

Library:

library(glmmTMB)
library(DHARMa)
## This is DHARMa 0.4.7. For overview type '?DHARMa'. For recent changes, type news(package = 'DHARMa')
library(performance)
library(emmeans)
## Welcome to emmeans.
## Caution: You lose important information if you filter this package's results.
## See '? untidy'
library(multcomp)
## Loading required package: mvtnorm
## Loading required package: survival
## Loading required package: TH.data
## Loading required package: MASS
## 
## Attaching package: 'TH.data'
## The following object is masked from 'package:MASS':
## 
##     geyser
library(viridis)
## Loading required package: viridisLite
library(ggplot2)
library(car)
## Loading required package: carData

Model 1: growth of longleaf seedlings pre-fire

model1 <- glmmTMB(
  rcd10 ~ location + difn + (1 | patch) + (1 | block),
  data = chpt2_r_data,
   family = Gamma(link = "log")
)

summary(model1)
##  Family: Gamma  ( log )
## Formula:          rcd10 ~ location + difn + (1 | patch) + (1 | block)
## Data: chpt2_r_data
## 
##       AIC       BIC    logLik -2*log(L)  df.resid 
##      89.3     100.4     -37.7      75.3        29 
## 
## Random effects:
## 
## Conditional model:
##  Groups Name        Variance Std.Dev.
##  patch  (Intercept) 0.004362 0.06604 
##  block  (Intercept) 0.165233 0.40649 
## Number of obs: 36, groups:  patch, 12; block, 4
## 
## Dispersion estimate for Gamma family (sigma^2): 0.0834 
## 
## Conditional model:
##                 Estimate Std. Error z value Pr(>|z|)  
## (Intercept)     0.344923   0.377524   0.914   0.3609  
## locationedge    0.054709   0.118409   0.462   0.6441  
## locationoutside 0.255773   0.120000   2.131   0.0331 *
## difn            0.006028   0.004723   1.276   0.2019  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Anova(model1, type = "II")
## Analysis of Deviance Table (Type II Wald chisquare tests)
## 
## Response: rcd10
##           Chisq Df Pr(>Chisq)  
## location 5.0190  2    0.08131 .
## difn     1.6289  1    0.20186  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
emm_loc1 <- emmeans(model1, ~ location, type = "response")
pairs(emm_loc1, adjust = "holm")
##  contrast         ratio     SE  df null z.ratio p.value
##  inside / edge    0.947 0.1120 Inf    1  -0.462  0.6441
##  inside / outside 0.774 0.0929 Inf    1  -2.131  0.0992
##  edge / outside   0.818 0.0977 Inf    1  -1.682  0.1849
## 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log scale
emm_loc1
##  location response    SE  df asymp.LCL asymp.UCL
##  inside       2.07 0.458 Inf      1.34      3.19
##  edge         2.18 0.483 Inf      1.41      3.37
##  outside      2.67 0.591 Inf      1.73      4.12
## 
## Confidence level used: 0.95 
## Intervals are back-transformed from the log scale
cld(emm_loc1, adjust = "holm", Letters = letters)
##  location response    SE  df asymp.LCL asymp.UCL .group
##  inside       2.07 0.458 Inf      1.21      3.51  a    
##  edge         2.18 0.483 Inf      1.28      3.70  a    
##  outside      2.67 0.591 Inf      1.57      4.54  a    
## 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 3 estimates 
## Intervals are back-transformed from the log scale 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log scale 
## significance level used: alpha = 0.05 
## NOTE: If two or more means share the same grouping symbol,
##       then we cannot show them to be different.
##       But we also did not show them to be the same.
#sim_res1 <- simulateResiduals(model1)
#plot(sim_res1)
##testDispersion(sim_res1)
#testZeroInflation(sim_res1)
#testOutliers(sim_res1)
#check_model(model1)

model 1 figure

# Estimated marginal means
emm_loc1 <- emmeans(model1, ~ location, type = "response")

# CLD (still created in case you need it elsewhere, but NOT plotted)
cld_loc1 <- cld(emm_loc1, adjust = "holm", Letters = letters)
cld_df1 <- as.data.frame(cld_loc1)
cld_df1$.group <- gsub(" ", "", cld_df1$.group)

# Colors
my_colors <- viridis(100, option = "D")[c(10, 40, 70, 90)]



# Plot
ggplot(cld_df1, aes(x = location, y = response, fill = location)) +
  geom_col() +
  geom_errorbar(aes(ymin = asymp.LCL, ymax = asymp.UCL), width = 0.2) +
  
  
  annotate("text",
         x = -Inf,
         y = Inf,
         label = "χ² = 5.019  df = 2  p = 0.0813",
         hjust = -0.1,
         vjust = 1.1,
         size = 5) +
  
  scale_fill_manual(values = my_colors) +
  labs(
    x = "Patch Location",
    y = "Change in RCD (mm)"
  ) +
  coord_cartesian(clip = "off") +
  theme_classic() +
  theme(
    legend.position = "none",
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 14),
    plot.margin = margin(10, 25, 10, 25)
  )

Model 2: mortality of longleaf seedlings pre-fire (binary)

chpt2_r_data$mort_bin <- ifelse(chpt2_r_data$mort.1 == "yes", 1, 0)

model2 <- glmmTMB(
  mort_bin ~ location + difn + (1 | patch) + (1 | block),
  data = chpt2_r_data,
   family = binomial(link = "logit")
)

summary(model2)
##  Family: binomial  ( logit )
## Formula:          mort_bin ~ location + difn + (1 | patch) + (1 | block)
## Data: chpt2_r_data
## 
##       AIC       BIC    logLik -2*log(L)  df.resid 
##      50.1      59.6     -19.1      38.1        30 
## 
## Random effects:
## 
## Conditional model:
##  Groups Name        Variance Std.Dev.
##  patch  (Intercept) 0.2021   0.4496  
##  block  (Intercept) 0.5298   0.7279  
## Number of obs: 36, groups:  patch, 12; block, 4
## 
## Conditional model:
##                 Estimate Std. Error z value Pr(>|z|)
## (Intercept)     -3.27692    3.04316  -1.077    0.282
## locationedge     1.06164    1.09437   0.970    0.332
## locationoutside  0.68888    1.12102   0.615    0.539
## difn             0.02420    0.04006   0.604    0.546
Anova(model2, type = "II")
## Analysis of Deviance Table (Type II Wald chisquare tests)
## 
## Response: mort_bin
##           Chisq Df Pr(>Chisq)
## location 0.9424  2     0.6243
## difn     0.3647  1     0.5459
emm_loc2 <- emmeans(model2, ~ location, type = "response")
pairs(emm_loc2, adjust = "holm")
##  contrast         odds.ratio    SE  df null z.ratio p.value
##  inside / edge         0.346 0.379 Inf    1  -0.970  0.9960
##  inside / outside      0.502 0.563 Inf    1  -0.615  1.0000
##  edge / outside        1.452 1.430 Inf    1   0.378  1.0000
## 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log odds ratio scale
emm_loc2
##  location  prob    SE  df asymp.LCL asymp.UCL
##  inside   0.148 0.135 Inf    0.0210     0.584
##  edge     0.334 0.190 Inf    0.0862     0.728
##  outside  0.257 0.169 Inf    0.0577     0.661
## 
## Confidence level used: 0.95 
## Intervals are back-transformed from the logit scale
cld(emm_loc2, adjust = "holm", Letters = letters)
##  location  prob    SE  df asymp.LCL asymp.UCL .group
##  inside   0.148 0.135 Inf    0.0133     0.691  a    
##  outside  0.257 0.169 Inf    0.0401     0.741  a    
##  edge     0.334 0.190 Inf    0.0612     0.795  a    
## 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 3 estimates 
## Intervals are back-transformed from the logit scale 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log odds ratio scale 
## significance level used: alpha = 0.05 
## NOTE: If two or more means share the same grouping symbol,
##       then we cannot show them to be different.
##       But we also did not show them to be the same.
#sim_res2 <- simulateResiduals(model2)
#plot(sim_res2)
#testDispersion(sim_res2)
#testZeroInflation(sim_res2)
#testOutliers(sim_res2)
#check_model(model2)

Model 2 figure

emm_loc2 <- emmeans(model2, ~ location, type = "response")
cld_loc2 <- cld(emm_loc2, adjust = "holm", Letters = letters)
cld_df2 <- as.data.frame(cld_loc2)
cld_df2$.group <- gsub(" ", "", cld_df2$.group)

cld_df2$prob <- cld_df2$prob * 100
cld_df2$asymp.LCL <- cld_df2$asymp.LCL * 100
cld_df2$asymp.UCL <- cld_df2$asymp.UCL * 100

my_colors <- viridis(100, option = "D")[c(10, 40, 70, 90)]  


ggplot(cld_df2, aes(x = location, y = prob, fill = location)) +
  
  geom_col(width = 0.6, color = "black") +
  
  geom_errorbar(
    aes(ymin = asymp.LCL, ymax = asymp.UCL),
    width = 0.2,
    linewidth = 1
  ) +
  
geom_text(
  aes(y = asymp.UCL + 5, label = .group),
  size = 6
) +
  
  scale_fill_manual(values = my_colors) +
  
  annotate("text",
         x = -Inf,
         y = Inf,
         label = "χ² = 0.942  df = 2  p = 0.6243",
         hjust = -0.1,
         vjust = 1.1,
         size = 5) +
  
  labs(
    x = "Patch Location",
    y = "Probability of Mortality (%)"
  ) +
  
  ylim(0, 100) +
  
  theme_classic() +
  theme(
    legend.position = "none",
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 14)
  )

Model 3: immediate post fire seedling mortality

chpt2_r_data$mortality2_beta <- pmin(pmax(chpt2_r_data$mortality2, 0.001), 0.999)


model3 <- glmmTMB(
  mortality2_beta ~ location + season + max.temp + ros + (1 | patch) + (1 | block),
  data = chpt2_r_data,
   family = beta_family(link = "logit")
)
## Warning in (function (start, objective, gradient = NULL, hessian = NULL, :
## NA/NaN function evaluation
## Warning in (function (start, objective, gradient = NULL, hessian = NULL, :
## NA/NaN function evaluation
summary(model3)
##  Family: beta  ( logit )
## Formula:          
## mortality2_beta ~ location + season + max.temp + ros + (1 | patch) +  
##     (1 | block)
## Data: chpt2_r_data
## 
##       AIC       BIC    logLik -2*log(L)  df.resid 
##     -34.4     -20.1      26.2     -52.4        27 
## 
## Random effects:
## 
## Conditional model:
##  Groups Name        Variance  Std.Dev. 
##  patch  (Intercept) 9.974e-01 9.987e-01
##  block  (Intercept) 6.269e-10 2.504e-05
## Number of obs: 36, groups:  patch, 12; block, 4
## 
## Dispersion parameter for beta family (): 10.1 
## 
## Conditional model:
##                  Estimate Std. Error z value Pr(>|z|)   
## (Intercept)      0.706166   0.853068   0.828  0.40779   
## locationedge    -0.732088   0.343723  -2.130  0.03318 * 
## locationoutside -0.859141   0.321892  -2.669  0.00761 **
## seasongrowing   -1.151780   0.680672  -1.692  0.09062 . 
## max.temp         0.002491   0.001147   2.172  0.02985 * 
## ros             -2.942300   2.333018  -1.261  0.20725   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Anova(model3, type = 2)
## Analysis of Deviance Table (Type II Wald chisquare tests)
## 
## Response: mortality2_beta
##           Chisq Df Pr(>Chisq)  
## location 7.7052  2    0.02122 *
## season   2.8633  1    0.09062 .
## max.temp 4.7179  1    0.02985 *
## ros      1.5905  1    0.20725  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
emm_loc3 <- emmeans(model3, ~ location, type = "response")
pairs(emm_loc3, adjust = "holm")
##  contrast         odds.ratio    SE  df null z.ratio p.value
##  inside / edge          2.08 0.715 Inf    1   2.130  0.0664
##  inside / outside       2.36 0.760 Inf    1   2.669  0.0228
##  edge / outside         1.14 0.355 Inf    1   0.407  0.6841
## 
## Results are averaged over the levels of: season 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log odds ratio scale
emm_loc3
##  location response     SE  df asymp.LCL asymp.UCL
##  inside      0.805 0.0613 Inf     0.657     0.898
##  edge        0.664 0.0860 Inf     0.482     0.808
##  outside     0.636 0.0866 Inf     0.456     0.784
## 
## Results are averaged over the levels of: season 
## Confidence level used: 0.95 
## Intervals are back-transformed from the logit scale
cld(emm_loc3, adjust = "holm", Letters = letters)
##  location response     SE  df asymp.LCL asymp.UCL .group
##  outside     0.636 0.0866 Inf     0.416     0.810  a    
##  edge        0.664 0.0860 Inf     0.440     0.833  ab   
##  inside      0.805 0.0613 Inf     0.618     0.913   b   
## 
## Results are averaged over the levels of: season 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 3 estimates 
## Intervals are back-transformed from the logit scale 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log odds ratio scale 
## significance level used: alpha = 0.05 
## NOTE: If two or more means share the same grouping symbol,
##       then we cannot show them to be different.
##       But we also did not show them to be the same.
#sim_res3 <- simulateResiduals(model3)
#plot(sim_res3)
#testDispersion(sim_res3)
#testZeroInflation(sim_res3)
#testOutliers(sim_res3)
#check_model(model3)

Model 3 figure- location

emm_loc3 <- emmeans(model3, ~ location, type = "response")
cld_loc3 <- cld(emm_loc3, adjust = "holm", Letters = letters)
cld_df3 <- as.data.frame(cld_loc3)
cld_df3$.group <- gsub(" ", "", cld_df3$.group)

cld_df3$response <- cld_df3$response * 100
cld_df3$asymp.LCL <- cld_df3$asymp.LCL * 100
cld_df3$asymp.UCL <- cld_df3$asymp.UCL * 100


my_colors <- viridis(100, option = "D")[c(10, 40, 70, 90)]  

ggplot(cld_df3, aes(x = location, y = response, fill = location)) +
  
  geom_col(width = 0.65, color = "black") +
  
  geom_errorbar(
    aes(ymin = asymp.LCL, ymax = asymp.UCL),
    width = 0.2,
    linewidth = 0.8
  ) +
  
  geom_text(
    aes(y = asymp.UCL + 5, label = .group),
    size = 6
  ) +
  
  scale_fill_manual(values = my_colors) +
  
  labs(
    x = "Patch Location",
    y = "Probability of Mortality (%)"
  ) +
  
  ylim(0, 100) +
  
annotate("text",
         x = -Inf,
         y = Inf,
         label = "χ² = 7.705  df = 2  p = 0.0212",
         hjust = -0.1,
         vjust = 1.1,
         size = 4) +
  
  theme_classic() +
  theme(
    legend.position = "none",
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 14)
  )

model 3 figure- max temp

library(ggeffects)
library(ggplot2)
library(viridis)

# Predictions from beta regression model
pred3 <- ggpredict(model3, terms = "max.temp")
## You are calculating adjusted predictions on the population-level (i.e.
##   `type = "fixed"`) for a *generalized* linear mixed model.
##   This may produce biased estimates due to Jensen's inequality. Consider
##   setting `bias_correction = TRUE` to correct for this bias.
##   See also the documentation of the `bias_correction` argument.
pred_df <- as.data.frame(pred3)

pred_df$predicted <- pred_df$predicted * 100
pred_df$conf.low <- pred_df$conf.low * 100
pred_df$conf.high <- pred_df$conf.high * 100

ggplot(pred_df, aes(x = x, y = predicted)) +
  
  # Solid ribbon
  geom_ribbon(aes(ymin = conf.low,
                  ymax = conf.high),
              fill = "steelblue",
              alpha = 0.35,
              colour = NA) +
  
  # Solid line
  geom_line(color = "steelblue",
            linewidth = 1.3) +
  
  # Labels
  labs(
    x = "Maximum Temperature (°C)",
    y = "Predicted Seedling Mortality (%)"
  ) +
  
  annotate("text",
           x = max(pred_df$x),
           y = min(pred_df$predicted)-10,
           hjust = 1,
           vjust = 0,
           label = "χ² = 4.72\n df = 1\n p = 0.0298",
           size = 5) +
  
  theme_classic(base_size = 14) +
  theme(
    axis.title = element_text(face = "bold"),
    axis.text = element_text(color = "black")
  )

Model 5: severity (tree scorch), first order fire effect

###create the binary variable (1 for greater than or equal to 0.7 scorch, 0 for less than 0.7)
chpt2_r_data$tree.scorch_prop <- chpt2_r_data$tree.scorch / 100
chpt2_r_data$high_scorch <- ifelse(chpt2_r_data$tree.scorch_prop >= 0.7, 1, 0)

model5 <- glmmTMB(
  high_scorch ~ season + location + ros + max.temp + (1|patch) + (1|block),
  data = chpt2_r_data,
  family = binomial(link = "logit")
)

summary(model5)
##  Family: binomial  ( logit )
## Formula:          
## high_scorch ~ season + location + ros + max.temp + (1 | patch) +  
##     (1 | block)
## Data: chpt2_r_data
## 
##       AIC       BIC    logLik -2*log(L)  df.resid 
##      51.5      64.2     -17.8      35.5        28 
## 
## Random effects:
## 
## Conditional model:
##  Groups Name        Variance Std.Dev.
##  patch  (Intercept) 1.029    1.015   
##  block  (Intercept) 1.098    1.048   
## Number of obs: 36, groups:  patch, 12; block, 4
## 
## Conditional model:
##                  Estimate Std. Error z value Pr(>|z|)  
## (Intercept)     -0.376955   2.890840  -0.130   0.8963  
## seasongrowing    3.628621   2.168315   1.674   0.0942 .
## locationedge    -2.143485   1.434037  -1.495   0.1350  
## locationoutside -1.174080   1.248948  -0.940   0.3472  
## ros              8.003390   8.952915   0.894   0.3714  
## max.temp        -0.000185   0.004011  -0.046   0.9632  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
emm5 <- emmeans(model5, ~ location, type = "response")
pairs(emm5, adjust = "holm")
##  contrast         odds.ratio     SE  df null z.ratio p.value
##  inside / edge         8.529 12.200 Inf    1   1.495  0.4050
##  inside / outside      3.235  4.040 Inf    1   0.940  0.6944
##  edge / outside        0.379  0.461 Inf    1  -0.797  0.6944
## 
## Results are averaged over the levels of: season 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log odds ratio scale
cld(emm5, adjust = "holm", Letters = letters)
##  location  prob    SE  df asymp.LCL asymp.UCL .group
##  edge     0.380 0.290 Inf    0.0314     0.921  a    
##  outside  0.618 0.277 Inf    0.0885     0.964  a    
##  inside   0.840 0.167 Inf    0.2131     0.990  a    
## 
## Results are averaged over the levels of: season 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 3 estimates 
## Intervals are back-transformed from the logit scale 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log odds ratio scale 
## significance level used: alpha = 0.05 
## NOTE: If two or more means share the same grouping symbol,
##       then we cannot show them to be different.
##       But we also did not show them to be the same.
#sim_res5 <- simulateResiduals(model5)
#plot(sim_res5)
#testDispersion(sim_res5)
#testZeroInflation(sim_res5)
#testOutliers(sim_res5)
#check_model(model5)

model 5 figure

chpt2_r_data$tree.scorch_prop <- chpt2_r_data$tree.scorch / 100
chpt2_r_data$high_scorch <- ifelse(chpt2_r_data$tree.scorch_prop >= 0.7, 1, 0)

emm5 <- emmeans(model5, ~ location, type = "response")
cld5 <- cld(emm5, adjust = "holm", Letters = letters)
cld_df5 <- as.data.frame(cld5)
cld_df5$.group <- gsub(" ", "", cld_df5$.group)

cld_df5$prob <- cld_df5$prob * 100
cld_df5$asymp.LCL <- cld_df5$asymp.LCL * 100
cld_df5$asymp.UCL <- cld_df5$asymp.UCL * 100

my_colors <- viridis(100, option = "D")[c(10, 40, 70, 90)]  

ggplot(cld_df5, aes(x = location, y = prob, fill = location)) +
  
  geom_col(width = 0.65, color = "black") +
  
  geom_errorbar(
    aes(ymin = asymp.LCL, ymax = asymp.UCL),
    width = 0.2,
    linewidth = 0.8
  ) +
  
  geom_text(
    aes(y = asymp.UCL + 5, label = .group),
    size = 6
  ) +
  
  scale_fill_manual(values = my_colors) +
  
  labs(
    x = "Patch Location",
    y = "Probability of High Tree Scorch (≥70%)"
  ) +
  
  coord_cartesian(ylim = c(0, 100)) +
  
  theme_classic() +
  theme(
    legend.position = "none",
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 14)
  )

Model 6: impacts on severity (char height), first order fire effect

model6 <- glmmTMB(
  tree.char ~ season + location + ros + max.temp + (1 | patch ) + (1 | block),
  data = chpt2_r_data,
  family = Gamma(link = "log")
)
## Warning in (function (start, objective, gradient = NULL, hessian = NULL, :
## NA/NaN function evaluation
summary(model6)
##  Family: Gamma  ( log )
## Formula:          
## tree.char ~ season + location + ros + max.temp + (1 | patch) +      (1 | block)
## Data: chpt2_r_data
## 
##       AIC       BIC    logLik -2*log(L)  df.resid 
##      97.8     112.0     -39.9      79.8        27 
## 
## Random effects:
## 
## Conditional model:
##  Groups Name        Variance  Std.Dev. 
##  patch  (Intercept) 1.413e-01 3.759e-01
##  block  (Intercept) 1.930e-10 1.389e-05
## Number of obs: 36, groups:  patch, 12; block, 4
## 
## Dispersion estimate for Gamma family (sigma^2): 0.169 
## 
## Conditional model:
##                   Estimate Std. Error z value Pr(>|z|)   
## (Intercept)     -0.3142579  0.4572089  -0.687  0.49187   
## seasongrowing   -0.6508829  0.2861865  -2.274  0.02295 * 
## locationedge    -0.0506114  0.1872238  -0.270  0.78691   
## locationoutside -0.0698913  0.1744770  -0.401  0.68873   
## ros             -0.6598510  1.3904424  -0.475  0.63510   
## max.temp         0.0018213  0.0006712   2.713  0.00666 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Anova(model6, type = 2)
## Analysis of Deviance Table (Type II Wald chisquare tests)
## 
## Response: tree.char
##           Chisq Df Pr(>Chisq)   
## season   5.1726  1    0.02295 * 
## location 0.1663  2    0.92023   
## ros      0.2252  1    0.63510   
## max.temp 7.3625  1    0.00666 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
emm6 <- emmeans(model6, ~ location, type = "response")
pairs(emm6, adjust = "holm")
##  contrast         ratio    SE  df null z.ratio p.value
##  inside / edge     1.05 0.197 Inf    1   0.270  1.0000
##  inside / outside  1.07 0.187 Inf    1   0.401  1.0000
##  edge / outside    1.02 0.183 Inf    1   0.108  1.0000
## 
## Results are averaged over the levels of: season 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log scale
cld(emm6, adjust = "holm", Letters = letters)
##  location response    SE  df asymp.LCL asymp.UCL .group
##  outside      1.34 0.227 Inf     0.890      2.01  a    
##  edge         1.36 0.243 Inf     0.889      2.09  a    
##  inside       1.43 0.245 Inf     0.951      2.16  a    
## 
## Results are averaged over the levels of: season 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 3 estimates 
## Intervals are back-transformed from the log scale 
## P value adjustment: holm method for 3 tests 
## Tests are performed on the log scale 
## significance level used: alpha = 0.05 
## NOTE: If two or more means share the same grouping symbol,
##       then we cannot show them to be different.
##       But we also did not show them to be the same.
#sim_res6 <- simulateResiduals(model6)
#plot(sim_res6)
#testDispersion(sim_res6)
#testZeroInflation(sim_res6)
#testOutliers(sim_res6)
#check_model(model6)

Model 6 figure

library(ggeffects)
library(ggplot2)
library(viridis)

# Generate predictions (holding other vars at typical values)
pred6 <- ggpredict(model6, terms = "max.temp")

# Convert to dataframe (ggeffects already is, but keeps things explicit)
pred_df <- as.data.frame(pred6)

# Plot
ggplot(pred_df, aes(x = x, y = predicted)) +
  
  # Confidence ribbon
  geom_ribbon(aes(ymin = conf.low, ymax = conf.high),
              fill = viridis(1, option = "D"),
              alpha = 0.25) +
  
  # Prediction line
  geom_line(color = viridis(1, option = "D"),
            linewidth = 1.3) +
  
  # Labels
  labs(
    x = "Maximum Temperature (°C)",
    y = "Predicted Tree Char Height (m)"
  ) +
  
  # Annotation (replace with real values later)
  annotate("text",
           x = min(pred_df$x),
           y = max(pred_df$predicted),
           hjust = 0,
           vjust = 1,
           label = "χ² = 7.36\n df = 1\n p = 0.0067",
           size = 5) +
  
  # Theme
  theme_classic(base_size = 14) +
  theme(
    axis.title = element_text(face = "bold"),
    axis.text = element_text(color = "black")
  )

model 6, season and char

library(emmeans)
library(ggplot2)
library(viridis)
library(multcomp)

# Estimated marginal means for season
emm_season6 <- emmeans(model6, ~ season, type = "response")

cld_season6 <- cld(emm_season6, adjust = "holm", Letters = letters)
cld_df6 <- as.data.frame(cld_season6)

cld_df6$.group <- gsub(" ", "", cld_df6$.group)

# No scaling needed (Gamma model → continuous response)
cld_df6$response <- cld_df6$response
cld_df6$asymp.LCL <- cld_df6$asymp.LCL
cld_df6$asymp.UCL <- cld_df6$asymp.UCL

my_colors <- viridis(100, option = "D")[c(25,60)]  

# Plot
ggplot(cld_df6, aes(x = season, y = response, fill = season)) +
  
  geom_col(width = 0.65, color = "black") +
  
  geom_errorbar(
    aes(ymin = asymp.LCL, ymax = asymp.UCL),
    width = 0.2,
    linewidth = 0.8
  ) +
  
  geom_text(
    aes(y = asymp.UCL + 0.05 * max(asymp.UCL), label = .group),
    size = 6
  ) +
  
  scale_fill_manual(values = my_colors) +
  
  labs(
    x = "Season",
    y = "Tree Char Height (m)"
  ) +
  
  annotate("text",
           x = -Inf,
           y = Inf,
           label = "χ² = 5.173, df = 1, p = 0.0229",
           hjust = -1.5,
           vjust = 1.1,
           size = 5) +
  
  theme_classic() +
  theme(
    legend.position = "none",
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 14)
  )

combines first order fire effects figures

Model 7: impacts on delayed planted seedling mortality: 2nd order fire effect

model7 <- glmmTMB(
  mortality3 ~ location * season + difn + ros + max.temp,
  data = chpt2_r_data,
  family = ordbeta(link = "logit")
)


summary(model7)
##  Family: ordbeta  ( logit )
## Formula:          mortality3 ~ location * season + difn + ros + max.temp
## Data: chpt2_r_data
## 
##       AIC       BIC    logLik -2*log(L)  df.resid 
##      58.3      75.5     -17.2      34.3        19 
## 
## 
## Dispersion parameter for ordbeta family (): 10.1 
## 
## Conditional model:
##                                Estimate Std. Error z value Pr(>|z|)  
## (Intercept)                    2.315449   2.639746   0.877   0.3804  
## locationedge                   0.821250   0.795584   1.032   0.3020  
## locationoutside                0.019961   0.832481   0.024   0.9809  
## seasongrowing                 -0.177888   0.887174  -0.200   0.8411  
## difn                          -0.022757   0.027428  -0.830   0.4067  
## ros                            1.733842   2.618028   0.662   0.5078  
## max.temp                      -0.003492   0.002680  -1.303   0.1926  
## locationedge:seasongrowing    -2.751582   1.358321  -2.026   0.0428 *
## locationoutside:seasongrowing -0.115826   1.035156  -0.112   0.9109  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Anova(model7, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
## 
## Response: mortality3
##                  Chisq Df Pr(>Chisq)  
## (Intercept)     0.7694  1     0.3804  
## location        2.2292  2     0.3281  
## season          0.0402  1     0.8411  
## difn            0.6884  1     0.4067  
## ros             0.4386  1     0.5078  
## max.temp        1.6978  1     0.1926  
## location:season 4.9973  2     0.0822 .
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
emm7 <- emmeans(model7, ~ season * location, type = "response")
pairs(emm7, adjust = "FDR")
##  contrast                          odds.ratio     SE  df null z.ratio p.value
##  dormant inside / growing inside        1.195  1.060 Inf    1   0.201  0.9677
##  dormant inside / dormant edge          0.440  0.350 Inf    1  -1.032  0.5033
##  dormant inside / growing edge          8.234 12.500 Inf    1   1.392  0.3343
##  dormant inside / dormant outside       0.980  0.816 Inf    1  -0.024  0.9809
##  dormant inside / growing outside       1.315  1.210 Inf    1   0.298  0.9677
##  growing inside / dormant edge          0.368  0.268 Inf    1  -1.373  0.3343
##  growing inside / growing edge          6.892  9.160 Inf    1   1.453  0.3343
##  growing inside / dormant outside       0.820  0.599 Inf    1  -0.271  0.9677
##  growing inside / growing outside       1.101  0.867 Inf    1   0.122  0.9677
##  dormant edge / growing edge           18.718 22.800 Inf    1   2.405  0.2423
##  dormant edge / dormant outside         2.228  1.330 Inf    1   1.346  0.3343
##  dormant edge / growing outside         2.989  1.960 Inf    1   1.671  0.3343
##  growing edge / dormant outside         0.119  0.133 Inf    1  -1.904  0.3343
##  growing edge / growing outside         0.160  0.167 Inf    1  -1.754  0.3343
##  dormant outside / growing outside      1.341  0.792 Inf    1   0.497  0.9285
## 
## P value adjustment: fdr method for 15 tests 
## Tests are performed on the log odds ratio scale
cld(emm7, adjust = "FDR", Letters = letters)
##  season  location response     SE  df asymp.LCL asymp.UCL .group
##  growing edge        0.044 0.0486 Inf   0.00217     0.493  a    
##  growing outside     0.224 0.0864 Inf   0.07191     0.517  a    
##  growing inside      0.241 0.1160 Inf   0.05643     0.627  a    
##  dormant inside      0.275 0.1450 Inf   0.05273     0.720  a    
##  dormant outside     0.279 0.0864 Inf   0.11058     0.546  a    
##  dormant edge        0.463 0.1200 Inf   0.19462     0.754  a    
## 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 6 estimates 
## Intervals are back-transformed from the logit scale 
## P value adjustment: fdr method for 15 tests 
## Tests are performed on the log odds ratio scale 
## significance level used: alpha = 0.05 
## NOTE: If two or more means share the same grouping symbol,
##       then we cannot show them to be different.
##       But we also did not show them to be the same.
#sim_res7 <- simulateResiduals(model7)
#plot(sim_res7)
#testDispersion(sim_res7)
#testZeroInflation(sim_res7)
#testOutliers(sim_res7)
#check_model(model7)

model 7 fig

library(ggeffects)
library(ggplot2)
library(viridis)
library(grid)  # for unit()

# ----------------------------
# Predictions
# ----------------------------
pred7 <- ggpredict(model7, terms = c("location", "season"))
pred_df <- as.data.frame(pred7)

# percent scale
pred_df$predicted <- pred_df$predicted * 100
pred_df$conf.low <- pred_df$conf.low * 100
pred_df$conf.high <- pred_df$conf.high * 100

pred_df$season <- pred_df$group

# ----------------------------
# VIRIDIS (EXPLICIT CONTROL)
# ----------------------------
base_cols <- viridis(10, option = "D")

loc_levels <- sort(unique(pred_df$x))

# pick specific viridis positions
cols <- c(
  inside  = base_cols[3],
  edge    = base_cols[6],
  outside = base_cols[9]
)

# ensure names match your factor levels
cols <- cols[loc_levels]

# ----------------------------
# CHI-SQUARE TEXT (dormant only)
# ----------------------------
chi_df <- data.frame(
  season = "growing",
  x = 1.55,  # centered between 3 bars (adjust if needed)
  y = max(pred_df$predicted) * 1.45,
  label = "χ² = 4.997, df = 2, p = 0.0822"
)

# ----------------------------
# PLOT
# ----------------------------
ggplot(pred_df,
       aes(x = x,
           y = predicted,
           fill = x)) +
  
  # bars
  geom_col(width = 0.7, color = "black") +
  
  # error bars
  geom_errorbar(aes(ymin = conf.low,
                    ymax = conf.high),
                width = 0.2,
                linewidth = 0.8) +
  
  # chi-square annotation (ONLY dormant facet)
  geom_text(
    data = chi_df,
    aes(x = x, y = y, label = label),
    inherit.aes = FALSE,
    size = 4,
    fontface = "italic"
  ) +
  
  # facets
  facet_wrap(
    ~season,
    nrow = 1,
    labeller = labeller(season = c(
      growing = "Growing",
      dormant = "Dormant"
    ))
  ) +
  
  # viridis manual colors
  scale_fill_manual(values = cols) +
  
  labs(
    x = "Location",
    y = "Predicted Mortality (%)"
  ) +
  
  theme_classic(base_size = 14) +
  
  theme(
    legend.position = "none",
    
    panel.spacing = unit(1.5, "lines"),
    panel.border = element_rect(color = "black", fill = NA),
    
    strip.background = element_rect(color = "black", fill = "white"),
    strip.text = element_text(size = 14, face = "bold"),
    
    axis.title.y = element_text(size = 14),
    axis.text.x = element_text(size = 12)
  )

model 9: planted seedling growth post fire, 2nd order fire effect

model9_data <- chpt2_r_data[!is.na(chpt2_r_data$rcd20), ]
model9_data$rcd20_ig <- model9_data$rcd20 + 1e-6

model9 <- glmmTMB(
  rcd20_ig ~ location + max.temp + ros + tree.scorch + tree.char +
    difn + green.needles + season + (1 | patch) + (1 | block),
  data = model9_data,
  family = gaussian(link = "log"),
  control = glmmTMBControl(optimizer = optim, optArgs = list(method = "BFGS")
))

summary(model9)
##  Family: gaussian  ( log )
## Formula:          
## rcd20_ig ~ location + max.temp + ros + tree.scorch + tree.char +  
##     difn + green.needles + season + (1 | patch) + (1 | block)
## Data: model9_data
## 
##       AIC       BIC    logLik -2*log(L)  df.resid 
##     149.3     167.1     -61.6     123.3        16 
## 
## Random effects:
## 
## Conditional model:
##  Groups   Name        Variance Std.Dev.
##  patch    (Intercept) 0.1422   0.377   
##  block    (Intercept) 1.1316   1.064   
##  Residual             1.7531   1.324   
## Number of obs: 29, groups:  patch, 12; block, 4
## 
## Dispersion estimate for gaussian family (sigma^2): 1.75 
## 
## Conditional model:
##                   Estimate Std. Error z value Pr(>|z|)   
## (Intercept)     -1.1432882  1.2428518  -0.920  0.35763   
## locationedge     0.0279611  0.2126652   0.132  0.89540   
## locationoutside -0.0265196  0.2078471  -0.128  0.89847   
## max.temp         0.0018267  0.0006062   3.013  0.00258 **
## ros             -1.4837444  0.9358266  -1.585  0.11285   
## tree.scorch     -0.0001214  0.0081062  -0.015  0.98805   
## tree.char        0.1510273  0.1039283   1.453  0.14617   
## difn             0.0041250  0.0117000   0.353  0.72441   
## green.needles    0.0024901  0.0217064   0.115  0.90867   
## seasongrowing    0.8096581  1.3640937   0.594  0.55281   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Anova(model9, type = "II")
## Analysis of Deviance Table (Type II Wald chisquare tests)
## 
## Response: rcd20_ig
##                Chisq Df Pr(>Chisq)   
## location      0.0629  2   0.969034   
## max.temp      9.0799  1   0.002584 **
## ros           2.5138  1   0.112855   
## tree.scorch   0.0002  1   0.988047   
## tree.char     2.1118  1   0.146172   
## difn          0.1243  1   0.724414   
## green.needles 0.0132  1   0.908669   
## season        0.3523  1   0.552813   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#emm9 <- emmeans(model9, ~ location, type = "response")
#pairs(emm9, adjust = "FDR")
#cld(emm9, adjust = "FDR", Letters = letters)

#sim_res9 <- simulateResiduals(model9)
#plot(sim_res9)
#testDispersion(sim_res9)
#testZeroInflation(sim_res9)
#testOutliers(sim_res9)
#check_model(model9)

model 9 figure

library(viridis)

# Predictions from model9
pred9 <- ggpredict(model9, terms = "max.temp")
pred_df <- as.data.frame(pred9)

# Pick a nice mid-range viridis color
col <- viridis(5, option = "D")[3]

ggplot(pred_df, aes(x = x, y = predicted)) +
  
  # Solid ribbon (CI)
  geom_ribbon(aes(ymin = conf.low,
                  ymax = conf.high),
              fill = col,
              alpha = 0.35,
              colour = NA) +
  
  # Solid line
  geom_line(color = col,
            linewidth = 1.3) +
  
  # Labels
  labs(
    x = "Maximum Temperature (°C)",
    y = "Predicted Change Root Collar Diameter (mm)"
  ) +
  
  annotate("text",
           x = min(pred_df$x),
           y = max(pred_df$predicted),
           hjust = 0,
           vjust = -3,
           label = "χ² = 9.079 \n df = 1 \n p = 0.0026",
           size = 5) +
  
  theme_classic(base_size = 12) +
  theme(
    axis.title = element_text(face = "bold"),
    axis.text.x = element_text(color = "black", size = 14),
    axis.text.y = element_text(color = "black", size = 12)
  )

combined 7 and 9 figure