## ========================================================================== ## Supplementary Code S1 ## Mulch-Mediated Enhancement of Physiological Performance and Macronutrient ## Status in Mandarin (Citrus reticulata Blanco) Cultivation Under Semi-Arid ## Vertisol Conditions ## Saini, Bhatnagar, Singh, Chhipa & Sharma ## ## Reproduces the linear mixed-effects model (LMM) analysis reported in the ## manuscript (Tables 1-13): treatment x month/time comparisons for soil and ## plant physiological parameters, RCBD with 9 treatments x 3 replications. ## ## Input data: Supplementary_Data_S1_Raw_Data.xlsx, sheet "Raw_Data_Long" ## columns: Parameter, Treatment, Time_Point, Replication, Value ## ========================================================================== ## ---- 0. Packages --------------------------------------------------------- required <- c("readxl", "dplyr", "tidyr", "nlme", "emmeans", "multcomp", "multcompView", "effectsize") to_install <- required[!required %in% installed.packages()[, "Package"]] if (length(to_install)) install.packages(to_install, repos = "https://cloud.r-project.org") library(readxl) library(dplyr) library(tidyr) library(nlme) library(emmeans) library(multcomp) library(multcompView) library(effectsize) ## ---- 1. Load data ---------------------------------------------------- data_path <- "Supplementary_Data_S1_Raw_Data.xlsx" raw <- read_excel(data_path, sheet = "Raw_Data_Long") ## ---- Data quality checks -------------------------------------------- cat("\n=============================\n") cat("DATA QUALITY CHECKS\n") cat("=============================\n") print(summary(raw)) cat("\nMissing values:\n") print(colSums(is.na(raw))) cat("\nObservations per parameter:\n") print(table(raw$Parameter)) raw <- raw %>% mutate( Treatment = factor(Treatment, levels = paste0("T", 0:8)), Tree = interaction(Treatment, Replication, drop = TRUE), Block = factor(Replication) ) ## Two families of parameters: ## A) repeated-measures across 5 sampling months (RWC, chlorophyll, proline, ## Leaf_N, Leaf_P, Leaf_K, Stomatal_conductance, Photosynthetic_rate) ## B) initial vs final only (WHC, Bacteria, Fungi) months_5 <- c("June", "August", "October", "December", "February") ## ---- 2. Generic LMM fitting function (Treatment x Time, AR(1), Tree|Block) ---- fit_lmm <- function(param_name, time_levels) { d <- raw %>% filter(Parameter == param_name) %>% mutate(Time = factor(Time_Point, levels = time_levels)) %>% arrange(Treatment, Tree, Time) model <- lme( Value ~ Treatment * Time, random = ~1 | Block/Tree, correlation = corAR1(form = ~ as.numeric(Time) | Block/Tree), data = d, na.action = na.omit, control = lmeControl(opt = "optim", maxIter = 200, msMaxIter = 200) ) cat("\n================", param_name, "================\n") ## ANOVA print(anova(model)) ## Estimated marginal means emm <- emmeans(model, ~ Treatment | Time) ## Tukey groupings (explicit namespace for long-term reproducibility, ## since which package exports cld() for emmGrid objects has changed ## across versions of emmeans/multcomp/multcompView) tuk <- multcomp::cld( emm, Letters = letters, adjust = "tukey" ) print(tuk) ## Overall treatment means emm_overall <- emmeans(model, ~ Treatment) ## Bias-corrected standardized effect sizes (Hedges' g) ## Estimated from the model-based marginal means and expressed ## as treatment-versus-control (T0) contrasts. eff_all <- eff_size( emm_overall, sigma = sigma(model), edf = df.residual(model) ) ## Hedges' g, treatment (T1-T8) versus control (T0) contr <- contrast( eff_all, method = "trt.vs.ctrl", ref = 1 ) cat("\nHedges' g (treatment versus control)\n") print(contr) ## ------------------------------- ## Model diagnostics (written to a per-parameter PDF only; nothing is ## drawn to the active device, to avoid producing every plot twice) ## ## NOTE: nlme's plot.lme() returns a lattice/trellis object, not a base ## R plot. Trellis objects only render when explicitly print()-ed; unlike ## base graphics, a bare `plot(model)` call inside a function body builds ## the trellis object and discards it without drawing anything. print() ## is therefore required here (this does not produce a stray console ## "NULL" the way wrapping a base-graphics plot() call would, since ## print.trellis() returns invisibly). ## ------------------------------- cat("\nModel diagnostics\n") res_norm <- residuals(model, type = "normalized") dir.create("Diagnostics", showWarnings = FALSE) pdf(file.path( "Diagnostics", paste0(gsub("[^A-Za-z0-9]", "_", param_name), "_diagnostics.pdf") )) print(plot(model)) qqnorm(res_norm, main = paste("Normal Q-Q:", param_name)) qqline(res_norm) dev.off() cat("\nShapiro-Wilk normality test (alpha = 0.05)\n") print(shapiro.test(res_norm)) list( model = model, emmeans_by_time = tuk, overall_emmeans = emm_overall, contrasts = contr, effect_sizes = contr ) } ## ---- 3. Fit the eight repeated-measures parameters (Tables 2-9) ---------- results_repeated <- list() for (p in c("RWC (%)", "Chlorophyll (mg g-1 FW)", "Proline (umol g-1 FW)", "Leaf_N (% dry matter)", "Leaf_P (% dry matter)", "Leaf_K (% dry matter)", "Stomatal_conductance (mmol m-2 s-1)", "Photosynthetic_rate (umol CO2 m-2 s-1)")) { results_repeated[[p]] <- fit_lmm(p, months_5) } ## ---- 4. Fit the initial-vs-final parameters (Tables 1, 12, 13) ----------- init_final <- c("Initial", "Final") results_if <- list() for (p in c("WHC (%)", "Bacteria (x1e6 CFU g-1 dry soil)", "Fungi (x1e4 CFU g-1 dry soil)")) { results_if[[p]] <- fit_lmm(p, init_final) } ## ---- 5. Pairwise contrasts vs control (Hedges' g reported in manuscript) -- ## Each parameter's treatment-versus-control (T0) Hedges' g was already ## computed inside fit_lmm() and stored in $contrasts (== $effect_sizes). ## Print them all together here for a consolidated view. for (nm in c(names(results_repeated), names(results_if))) { res <- if (nm %in% names(results_repeated)) results_repeated[[nm]] else results_if[[nm]] cat("\n---- Hedges' g, treatment versus control (T0):", nm, "----\n") print(res$contrasts) } ## ---- 6. Export tidy summary tables ---------------------------------------- dir.create("LMM_outputs", showWarnings = FALSE) for (nm in names(results_repeated)) { write.csv(as.data.frame(results_repeated[[nm]]$emmeans_by_time), file = file.path("LMM_outputs", paste0(gsub("[^A-Za-z0-9]", "_", nm), "_by_time.csv")), row.names = FALSE) write.csv(as.data.frame(results_repeated[[nm]]$effect_sizes), file = file.path("LMM_outputs", paste0(gsub("[^A-Za-z0-9]", "_", nm), "_hedges_g.csv")), row.names = FALSE) } for (nm in names(results_if)) { write.csv(as.data.frame(results_if[[nm]]$emmeans_by_time), file = file.path("LMM_outputs", paste0(gsub("[^A-Za-z0-9]", "_", nm), "_initial_final.csv")), row.names = FALSE) write.csv(as.data.frame(results_if[[nm]]$effect_sizes), file = file.path("LMM_outputs", paste0(gsub("[^A-Za-z0-9]", "_", nm), "_hedges_g.csv")), row.names = FALSE) } cat("\nAll LMM outputs written to ./LMM_outputs/\n") cat("\nR version used for this run:", R.version.string, "\n") cat("Session info:\n") print(sessionInfo()) ## ========================================================================== ## Notes for reproducibility (see manuscript Statistical Analysis section): ## - Fixed effects: Treatment (9 levels), Time/Month, Treatment x Time ## - Random effect: Tree nested within Block (=replication) ## - Correlation: first-order autoregressive AR(1) within tree across time ## - Post-hoc: Tukey-adjusted estimated marginal means using ## multcomp::cld() (explicit namespace; multcompView is loaded ## to supply the underlying letter-generation algorithm). ## - Effect sizes: bias-corrected Hedges' g calculated only for ## treatment-versus-control comparisons (T0) ## - Model assumptions evaluated using normalized-residual plots, ## normal Q-Q plots and Shapiro-Wilk tests ## - The exact R version used for each execution is reported automatically ## above, together with sessionInfo() (packages nlme and emmeans; see ## manuscript Materials & Methods -> Statistical analysis for the ## version used to generate the results reported in the manuscript). ## ==========================================================================