library("ggplot2")
library("GGally")
library("Hmisc")
library("readr")
library("dplyr")
library("networkD3")
library("tidyr")
library('tibble')
library('pals')
library("rstatix")
library("cowplot")
library("ggrepel")
sessionInfo()
## R version 4.5.0 (2025-04-11 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=English_United Kingdom.utf8 
## [2] LC_CTYPE=English_United Kingdom.utf8   
## [3] LC_MONETARY=English_United Kingdom.utf8
## [4] LC_NUMERIC=C                           
## [5] LC_TIME=English_United Kingdom.utf8    
## 
## time zone: Europe/Berlin
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] ggrepel_0.9.6   cowplot_1.2.0   rstatix_1.1.0   pals_1.10      
##  [5] tibble_3.3.1    tidyr_1.3.2     networkD3_0.4.1 dplyr_1.2.1    
##  [9] readr_2.1.6     Hmisc_5.2-6     GGally_2.4.0    ggplot2_4.0.2  
## 
## loaded via a namespace (and not attached):
##  [1] gtable_0.3.6        xfun_0.61           bslib_0.10.0       
##  [4] htmlwidgets_1.6.4   tzdb_0.5.0          vctrs_0.7.3        
##  [7] tools_4.5.0         generics_0.1.4      cluster_2.1.8.2    
## [10] pkgconfig_2.0.3     data.table_1.18.2.1 checkmate_2.3.4    
## [13] RColorBrewer_1.1-3  S7_0.2.1            lifecycle_1.0.5    
## [16] compiler_4.5.0      farver_2.1.2        stringr_1.6.0      
## [19] data.tree_1.2.0     mapproj_1.2.12      carData_3.0-6      
## [22] htmltools_0.5.8.1   maps_3.4.3          sass_0.4.10        
## [25] yaml_2.3.10         htmlTable_2.4.3     Formula_1.2-5      
## [28] pillar_1.11.1       car_3.1-5           jquerylib_0.1.4    
## [31] cachem_1.1.0        abind_1.4-8         rpart_4.1.24       
## [34] ggstats_0.12.0      tidyselect_1.2.1    digest_0.6.37      
## [37] stringi_1.8.7       purrr_1.2.1         fastmap_1.2.0      
## [40] grid_4.5.0          colorspace_2.1-2    cli_3.6.5          
## [43] magrittr_2.0.3      base64enc_0.1-6     dichromat_2.0-0.1  
## [46] broom_1.0.12        foreign_0.8-91      withr_3.0.2        
## [49] scales_1.4.0        backports_1.5.0     rmarkdown_2.30     
## [52] igraph_2.2.2        otel_0.2.0          nnet_7.3-20        
## [55] gridExtra_2.3       hms_1.1.4           evaluate_1.0.5     
## [58] knitr_1.51          rlang_1.2.0         Rcpp_1.1.0         
## [61] glue_1.8.0          rstudioapi_0.18.0   jsonlite_2.0.0     
## [64] R6_2.6.1

Correlation matrix (Tree growth)

sample_info_no_R <-read.table("Alaska_info_no_R.txt", row.names=1, header=T, check.names=F)

df_correlation <- sample_info_no_R[, c("BAI_10y", "detBAI_10y", "rcsBAI_10y", "Age", "DBH", "Height", "pH", "Site")]
df_correlation <- na.omit(df_correlation)

# Compute correlations + p-values
cor_results <- rcorr(as.matrix(df_correlation[, 1:7])) # column 9 (Site) is used for point colours
cor_matrix <- cor_results$r
p_matrix <- cor_results$P

site_colors <- c(Alaska_Range = "#EE7733", Brooks_Range = "#009988", Interior = "#5E4FA2")

lower_fun_sig <- function(data, mapping, ...) {
  ggplot(data = data, mapping = mapping) +
    geom_point(aes(color = Site), alpha = 0.7, size = 1.5) +
    scale_color_manual(values = site_colors,
                       labels = c("Alaska Range", "Brooks Range", "Interior Alaska")) +
    geom_smooth(method = "lm", se = FALSE, color = "darkred", size = 0.7)}

ggpairs(df_correlation, columns = 1:7,
        lower = list(continuous = lower_fun_sig),
        upper = list(continuous = wrap("cor", size = 4)),
        diag = list(continuous = wrap("densityDiag", alpha = 0.5, fill = "lightblue")),
        legend = c(2, 1),
        progress = FALSE) +
theme_bw() + theme(panel.grid = element_blank(),
        strip.background = element_rect(fill = "lightgray"),
        axis.text = element_text(size = 8),
        legend.position = "bottom")
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'

Differences between Plots

palette <- c("#EE7733","#CC6677", "#009988","#337538","#33BBEE", "#5E4FA2")

pH <- ggplot(sample_info_no_R, aes(x = Plot, y = pH, fill = Plot)) + geom_violin(trim = FALSE) +geom_point(size = 2, color = "gray10", alpha = 0.3,
             position = position_jitter(width = 0.1)) + scale_fill_manual(values = palette) + ylab("Soil pH") + theme_minimal() + theme(legend.position = "none")
Age_plot <- ggplot(sample_info_no_R, aes(x = Plot, y = Age, fill = Plot)) + geom_violin(trim = FALSE) +geom_point(size = 2, color = "gray10", alpha = 0.3,
             position = position_jitter(width = 0.1)) + scale_fill_manual(values = palette) + ylab("Tree age, years") + theme_minimal() + theme(legend.position = "none")
DBH_plot <- ggplot(sample_info_no_R, aes(x = Plot, y = DBH, fill = Plot)) + geom_violin(trim = FALSE) +geom_point(size = 2, color = "gray10", alpha = 0.3,
             position = position_jitter(width = 0.1)) + scale_fill_manual(values = palette) + ylab("DBH, cm") + theme_minimal() + theme(legend.position = "none")
Height_plot <- ggplot(sample_info_no_R, aes(x = Plot, y = Height, fill = Plot)) + geom_violin(trim = FALSE) +geom_point(size = 2, color = "gray10", alpha = 0.3, 
              position = position_jitter(width = 0.1)) + scale_fill_manual(values = palette) + ylab("Tree height, m") + theme_minimal() + theme(legend.position = "none")

plot_grid(pH, Age_plot, DBH_plot, Height_plot, labels = c("Soil pH", "Tree age", "Tree DBH", "Tree height" ), ncol = 2)
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_ydensity()`).
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 2 rows containing non-finite outside the scale range
## (`stat_ydensity()`).
## Warning: Removed 2 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 2 rows containing non-finite outside the scale range
## (`stat_ydensity()`).
## Warning: Removed 2 rows containing missing values or values outside the scale range
## (`geom_point()`).

Soil pH in BF (map)

BF_pH <- subset(sample_info_no_R, Plot == "BF" & !is.na(pH))
BF_pH$Sample <- rownames(BF_pH)

ggplot(BF_pH, aes(x = Longitude, y = Latitude)) +
  geom_point(aes(fill = pH), shape = 21, size = 4, color = "gray20") +
  geom_text_repel(aes(label = paste0(Sample, "\npH ", pH)), size = 2.8, point.size = 4, max.overlaps = Inf, lineheight = 0.9) +
  scale_fill_viridis_c(name = "Soil pH") +
  coord_quickmap() +
  theme_bw()

Statistical tests

shapiro.test(sample_info_no_R$pH) # data are not normally distributed
## 
##  Shapiro-Wilk normality test
## 
## data:  sample_info_no_R$pH
## W = 0.90744, p-value = 1.111e-06
bartlett.test(pH ~ Plot, data = sample_info_no_R) # variance is not equal
## 
##  Bartlett test of homogeneity of variances
## 
## data:  pH by Plot
## Bartlett's K-squared = 70.137, df = 5, p-value = 9.597e-14
dunn_test(sample_info_no_R , pH ~ Habitat) #not significant 
## # A tibble: 1 × 9
##   .y.   group1 group2      n1    n2 statistic     p p.adj p.adj.signif
## * <chr> <chr>  <chr>    <int> <int>     <dbl> <dbl> <dbl> <chr>       
## 1 pH    forest treeline    59    52     0.287 0.774 0.774 ns
dunn_test(sample_info_no_R , pH ~ Plot, p.adjust.method = "bonferroni") 
## # A tibble: 15 × 9
##    .y.   group1 group2    n1    n2 statistic        p    p.adj p.adj.signif
##  * <chr> <chr>  <chr>  <int> <int>     <dbl>    <dbl>    <dbl> <chr>       
##  1 pH    AF     AT        19    21   -1.47   1.41e- 1 1   e+ 0 ns          
##  2 pH    AF     BF        19    21    3.56   3.71e- 4 5.56e- 3 **          
##  3 pH    AF     BT        19    20    6.66   2.78e-11 4.17e-10 ****        
##  4 pH    AF     IF        19    19    3.93   8.53e- 5 1.28e- 3 **          
##  5 pH    AF     IT        19    11    2.92   3.48e- 3 5.22e- 2 ns          
##  6 pH    AT     BF        21    21    5.16   2.43e- 7 3.64e- 6 ****        
##  7 pH    AT     BT        21    20    8.32   8.89e-17 1.33e-15 ****        
##  8 pH    AT     IF        21    19    5.50   3.83e- 8 5.75e- 7 ****        
##  9 pH    AT     IT        21    11    4.23   2.37e- 5 3.55e- 4 ***         
## 10 pH    BF     BT        21    20    3.22   1.29e- 3 1.93e- 2 *           
## 11 pH    BF     IF        21    19    0.466  6.41e- 1 1   e+ 0 ns          
## 12 pH    BF     IT        21    11   -0.0544 9.57e- 1 1   e+ 0 ns          
## 13 pH    BT     IF        20    19   -2.68   7.39e- 3 1.11e- 1 ns          
## 14 pH    BT     IT        20    11   -2.73   6.28e- 3 9.42e- 2 ns          
## 15 pH    IF     IT        19    11   -0.443  6.58e- 1 1   e+ 0 ns
dunn_test(sample_info_no_R , pH ~ Site, p.adjust.method = "bonferroni") 
## # A tibble: 3 × 9
##   .y.   group1       group2    n1    n2 statistic        p    p.adj p.adj.signif
## * <chr> <chr>        <chr>  <int> <int>     <dbl>    <dbl>    <dbl> <chr>       
## 1 pH    Alaska_Range Brook…    40    41      8.38 5.25e-17 1.58e-16 ****        
## 2 pH    Alaska_Range Inter…    40    30      6.04 1.57e- 9 4.72e- 9 ****        
## 3 pH    Brooks_Range Inter…    41    30     -1.68 9.22e- 2 2.77e- 1 ns
shapiro.test(sample_info_no_R$Age) # data are not normally distributed
## 
##  Shapiro-Wilk normality test
## 
## data:  sample_info_no_R$Age
## W = 0.92442, p-value = 1.209e-05
bartlett.test(Age ~ Habitat, data = sample_info_no_R) # variance is equal
## 
##  Bartlett test of homogeneity of variances
## 
## data:  Age by Habitat
## Bartlett's K-squared = 1.0282, df = 1, p-value = 0.3106
kruskal_test(sample_info_no_R , Age ~ Habitat) #significant
## # A tibble: 1 × 6
##   .y.       n statistic    df       p method        
## * <chr> <int>     <dbl> <int>   <dbl> <chr>         
## 1 Age     108      8.43     1 0.00369 Kruskal-Wallis
shapiro.test(sample_info_no_R$Age) # data are not normally distributed
## 
##  Shapiro-Wilk normality test
## 
## data:  sample_info_no_R$Age
## W = 0.92442, p-value = 1.209e-05
bartlett.test(Age ~ Plot, data = sample_info_no_R) # variance is not equal
## 
##  Bartlett test of homogeneity of variances
## 
## data:  Age by Plot
## Bartlett's K-squared = 54.315, df = 5, p-value = 1.805e-10
res.kruskal <-kruskal_test(sample_info_no_R , Age ~ Plot)
res.kruskal #significant
## # A tibble: 1 × 6
##   .y.       n statistic    df        p method        
## * <chr> <int>     <dbl> <int>    <dbl> <chr>         
## 1 Age     108      22.4     5 0.000440 Kruskal-Wallis
dunn_test(sample_info_no_R , Age ~ Plot, p.adjust.method = "bonferroni") 
## # A tibble: 15 × 9
##    .y.   group1 group2    n1    n2 statistic        p   p.adj p.adj.signif
##  * <chr> <chr>  <chr>  <int> <int>     <dbl>    <dbl>   <dbl> <chr>       
##  1 Age   AF     AT        19    18   -3.50   0.000465 0.00697 **          
##  2 Age   AF     BF        19    21   -1.43   0.154    1       ns          
##  3 Age   AF     BT        19    20   -2.82   0.00479  0.0718  ns          
##  4 Age   AF     IF        19    19   -3.52   0.000432 0.00648 **          
##  5 Age   AF     IT        19    11   -3.50   0.000459 0.00688 **          
##  6 Age   AT     BF        18    21    2.18   0.0294   0.441   ns          
##  7 Age   AT     BT        18    20    0.762  0.446    1       ns          
##  8 Age   AT     IF        18    19    0.0282 0.977    1       ns          
##  9 Age   AT     IT        18    11   -0.460  0.645    1       ns          
## 10 Age   BF     BT        21    20   -1.45   0.148    1       ns          
## 11 Age   BF     IF        21    19   -2.18   0.0292   0.439   ns          
## 12 Age   BF     IT        21    11   -2.35   0.0186   0.279   ns          
## 13 Age   BT     IF        20    19   -0.744  0.457    1       ns          
## 14 Age   BT     IT        20    11   -1.13   0.259    1       ns          
## 15 Age   IF     IT        19    11   -0.490  0.624    1       ns

DBH vs Habitat/Plot

shapiro.test(sample_info_no_R$DBH) # data are not normally distributed
## 
##  Shapiro-Wilk normality test
## 
## data:  sample_info_no_R$DBH
## W = 0.92854, p-value = 1.919e-05
bartlett.test(DBH ~ Habitat, data = sample_info_no_R) # variance is not equal
## 
##  Bartlett test of homogeneity of variances
## 
## data:  DBH by Habitat
## Bartlett's K-squared = 5.1545, df = 1, p-value = 0.02319
dunn_test(sample_info_no_R , DBH ~ Habitat) # not significant
## # A tibble: 1 × 9
##   .y.   group1 group2      n1    n2 statistic     p p.adj p.adj.signif
## * <chr> <chr>  <chr>    <int> <int>     <dbl> <dbl> <dbl> <chr>       
## 1 DBH   forest treeline    59    50     -1.51 0.131 0.131 ns
shapiro.test(sample_info_no_R$DBH) # data are not normally distributed
## 
##  Shapiro-Wilk normality test
## 
## data:  sample_info_no_R$DBH
## W = 0.92854, p-value = 1.919e-05
bartlett.test(DBH ~ Plot, data = sample_info_no_R) # variance is not equal
## 
##  Bartlett test of homogeneity of variances
## 
## data:  DBH by Plot
## Bartlett's K-squared = 23.109, df = 5, p-value = 0.0003217
res.kruskal <-kruskal_test(sample_info_no_R , DBH ~ Plot)
res.kruskal #significant
## # A tibble: 1 × 6
##   .y.       n statistic    df         p method        
## * <chr> <int>     <dbl> <int>     <dbl> <chr>         
## 1 DBH     109      30.0     5 0.0000149 Kruskal-Wallis
dunn_test(sample_info_no_R , DBH ~ Plot, p.adjust.method = "bonferroni") 
## # A tibble: 15 × 9
##    .y.   group1 group2    n1    n2 statistic         p    p.adj p.adj.signif
##  * <chr> <chr>  <chr>  <int> <int>     <dbl>     <dbl>    <dbl> <chr>       
##  1 DBH   AF     AT        19    19    -4.37  0.0000126 0.000188 ***         
##  2 DBH   AF     BF        19    21    -2.26  0.0238    0.358    ns          
##  3 DBH   AF     BT        19    20    -2.72  0.00657   0.0985   ns          
##  4 DBH   AF     IF        19    19    -2.78  0.00536   0.0805   ns          
##  5 DBH   AF     IT        19    11     0.616 0.538     1        ns          
##  6 DBH   AT     BF        19    21     2.22  0.0267    0.401    ns          
##  7 DBH   AT     BT        19    20     1.71  0.0881    1        ns          
##  8 DBH   AT     IF        19    19     1.58  0.113     1        ns          
##  9 DBH   AT     IT        19    11     4.36  0.0000133 0.000199 ***         
## 10 DBH   BF     BT        21    20    -0.497 0.619     1        ns          
## 11 DBH   BF     IF        21    19    -0.593 0.553     1        ns          
## 12 DBH   BF     IT        21    11     2.55  0.0108    0.162    ns          
## 13 DBH   BT     IF        20    19    -0.102 0.919     1        ns          
## 14 DBH   BT     IT        20    11     2.94  0.00327   0.0491   *           
## 15 DBH   IF     IT        19    11     3.00  0.00270   0.0405   *

Height vs Habitat/Plot

shapiro.test(sample_info_no_R$Height) # data are not normally distributed
## 
##  Shapiro-Wilk normality test
## 
## data:  sample_info_no_R$Height
## W = 0.94182, p-value = 0.0001269
bartlett.test(Height ~ Habitat, data = sample_info_no_R) # variance is equal
## 
##  Bartlett test of homogeneity of variances
## 
## data:  Height by Habitat
## Bartlett's K-squared = 2.6759, df = 1, p-value = 0.1019
dunn_test(sample_info_no_R , Height ~ Habitat) # significant
## # A tibble: 1 × 9
##   .y.    group1 group2      n1    n2 statistic         p     p.adj p.adj.signif
## * <chr>  <chr>  <chr>    <int> <int>     <dbl>     <dbl>     <dbl> <chr>       
## 1 Height forest treeline    59    50     -4.08 0.0000455 0.0000455 ****
shapiro.test(sample_info_no_R$Height) # data are not normally distributed
## 
##  Shapiro-Wilk normality test
## 
## data:  sample_info_no_R$Height
## W = 0.94182, p-value = 0.0001269
bartlett.test(Height ~ Plot, data = sample_info_no_R) # variance is not equal
## 
##  Bartlett test of homogeneity of variances
## 
## data:  Height by Plot
## Bartlett's K-squared = 35.151, df = 5, p-value = 1.404e-06
res.kruskal <-kruskal_test(sample_info_no_R , Height ~ Plot)
res.kruskal #significant
## # A tibble: 1 × 6
##   .y.        n statistic    df             p method        
## * <chr>  <int>     <dbl> <int>         <dbl> <chr>         
## 1 Height   109      47.6     5 0.00000000424 Kruskal-Wallis
dunn_test(sample_info_no_R , Height ~ Plot, p.adjust.method = "bonferroni") 
## # A tibble: 15 × 9
##    .y.    group1 group2    n1    n2 statistic           p     p.adj p.adj.signif
##  * <chr>  <chr>  <chr>  <int> <int>     <dbl>       <dbl>     <dbl> <chr>       
##  1 Height AF     AT        19    19    -4.74  0.00000217    3.25e-5 ****        
##  2 Height AF     BF        19    21    -1.52  0.129         1   e+0 ns          
##  3 Height AF     BT        19    20    -3.37  0.000739      1.11e-2 *           
##  4 Height AF     IF        19    19     0.272 0.786         1   e+0 ns          
##  5 Height AF     IT        19    11     1.08  0.280         1   e+0 ns          
##  6 Height AT     BF        19    21     3.34  0.000845      1.27e-2 *           
##  7 Height AT     BT        19    20     1.42  0.155         1   e+0 ns          
##  8 Height AT     IF        19    19     5.01  0.000000546   8.19e-6 ****        
##  9 Height AT     IT        19    11     5.14  0.000000277   4.16e-6 ****        
## 10 Height BF     BT        21    20    -1.92  0.0545        8.17e-1 ns          
## 11 Height BF     IF        21    19     1.80  0.0726        1   e+0 ns          
## 12 Height BF     IT        21    11     2.39  0.0168        2.52e-1 ns          
## 13 Height BT     IF        20    19     3.65  0.000262      3.93e-3 **          
## 14 Height BT     IT        20    11     3.97  0.0000714     1.07e-3 **          
## 15 Height IF     IT        19    11     0.848 0.396         1   e+0 ns