# library(mandala) # Install Mandala first (request download: https://listoagriculture.com/products)
library(lme4)
library(lmerTest)
library(dplyr)
library(ggplot2)Comparison: Mandala vs lme4
Field trial analysis vs general-purpose mixed models
Overview
This tutorial compares the mandala package with lme4, the most widely-used R package for mixed models. While both can fit linear mixed models, they serve different purposes.
Background
| Package | Primary Focus | Best For |
|---|---|---|
| lme4 | General-purpose | Any discipline |
| Mandala | Agricultural trials | Field experiments |
Loading Packages
Example 1: Basic RCBD
Data Setup
set.seed(321)
n_genotypes <- 12
n_blocks <- 5
rcbd_data <- expand.grid(
genotype = factor(paste0("G", sprintf("%02d", 1:n_genotypes))),
block = factor(paste0("B", 1:n_blocks))
)
rcbd_data$yield <- 4500 +
rnorm(n_genotypes, 0, 20)[as.numeric(rcbd_data$genotype)] +
rnorm(n_blocks, 0, 10)[as.numeric(rcbd_data$block)] +
rnorm(nrow(rcbd_data), 0, 15)
head(rcbd_data) genotype block yield
1 G01 B1 4542.286
2 G02 B1 4496.306
3 G03 B1 4503.019
4 G04 B1 4513.249
5 G05 B1 4497.798
6 G06 B1 4522.072
Syntax Comparison
Mandala:
mandala(
fixed = yield ~ genotype,
random = ~ block,
data = rcbd_data
)lme4:
lmer(
yield ~ genotype + (1|block),
data = rcbd_data
)lme4 Analysis
lme4_model <- lmer(
yield ~ genotype + (1|block),
data = rcbd_data,
REML = TRUE
)
summary(lme4_model)Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: yield ~ genotype + (1 | block)
Data: rcbd_data
REML criterion at convergence: 423
Scaled residuals:
Min 1Q Median 3Q Max
-1.9341 -0.7533 0.1652 0.6741 1.7233
Random effects:
Groups Name Variance Std.Dev.
block (Intercept) 125.5 11.20
Residual 221.6 14.89
Number of obs: 60, groups: block, 5
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 4529.901 8.333 19.684 543.637 < 2e-16 ***
genotypeG02 -47.166 9.415 44.000 -5.010 9.34e-06 ***
genotypeG03 -33.401 9.415 44.000 -3.548 0.000938 ***
genotypeG04 -19.832 9.415 44.000 -2.106 0.040913 *
genotypeG05 -28.048 9.415 44.000 -2.979 0.004693 **
genotypeG06 -16.668 9.415 44.000 -1.770 0.083595 .
genotypeG07 -13.595 9.415 44.000 -1.444 0.155835
genotypeG08 -24.406 9.415 44.000 -2.592 0.012896 *
genotypeG09 -17.345 9.415 44.000 -1.842 0.072182 .
genotypeG10 -43.653 9.415 44.000 -4.636 3.17e-05 ***
genotypeG11 -25.541 9.415 44.000 -2.713 0.009488 **
genotypeG12 -1.386 9.415 44.000 -0.147 0.883608
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) gntG02 gntG03 gntG04 gntG05 gntG06 gntG07 gntG08 gntG09
genotypeG02 -0.565
genotypeG03 -0.565 0.500
genotypeG04 -0.565 0.500 0.500
genotypeG05 -0.565 0.500 0.500 0.500
genotypeG06 -0.565 0.500 0.500 0.500 0.500
genotypeG07 -0.565 0.500 0.500 0.500 0.500 0.500
genotypeG08 -0.565 0.500 0.500 0.500 0.500 0.500 0.500
genotypeG09 -0.565 0.500 0.500 0.500 0.500 0.500 0.500 0.500
genotypeG10 -0.565 0.500 0.500 0.500 0.500 0.500 0.500 0.500 0.500
genotypeG11 -0.565 0.500 0.500 0.500 0.500 0.500 0.500 0.500 0.500
genotypeG12 -0.565 0.500 0.500 0.500 0.500 0.500 0.500 0.500 0.500
gntG10 gntG11
genotypeG02
genotypeG03
genotypeG04
genotypeG05
genotypeG06
genotypeG07
genotypeG08
genotypeG09
genotypeG10
genotypeG11 0.500
genotypeG12 0.500 0.500
# Variance components
as.data.frame(VarCorr(lme4_model)) grp var1 var2 vcov sdcor
1 block (Intercept) <NA> 125.5453 11.20470
2 Residual <NA> <NA> 221.6143 14.88671
Example 2: Nested Design
set.seed(654)
n_genotypes <- 30
n_complete <- 3
nested_data <- expand.grid(
genotype = factor(paste0("G", sprintf("%02d", 1:n_genotypes))),
complete_block = factor(1:n_complete)
)
nested_data$incomplete_block <- factor(
paste0(nested_data$complete_block, ".",
rep(1:5, length.out = nrow(nested_data)))
)
nested_data$yield <- 5500 +
rnorm(n_genotypes, 0, 30)[as.numeric(nested_data$genotype)] +
rnorm(n_complete, 0, 15)[as.numeric(nested_data$complete_block)] +
rnorm(nrow(nested_data), 0, 20)lme4_nested <- lmer(
yield ~ genotype + (1|complete_block) + (1|complete_block:incomplete_block),
data = nested_data,
REML = TRUE
)
as.data.frame(VarCorr(lme4_nested)) grp var1 var2 vcov sdcor
1 complete_block:incomplete_block (Intercept) <NA> 24.4848159 4.9482134
2 complete_block (Intercept) <NA> 0.7170808 0.8468062
3 Residual <NA> <NA> 301.0144193 17.3497671
Diagnostics
diag_data <- data.frame(
Fitted = fitted(lme4_model),
Residuals = residuals(lme4_model)
)
p1 <- ggplot(diag_data, aes(x = Fitted, y = Residuals)) +
geom_point(alpha = 0.6, color = "#5D4E6D") +
geom_hline(yintercept = 0, linetype = "dashed", color = "#9B5B5B") +
geom_smooth(se = FALSE, color = "#8B9A6D") +
theme_minimal() +
labs(title = "Residuals vs Fitted")
p2 <- ggplot(diag_data, aes(sample = Residuals)) +
stat_qq(color = "#5D4E6D") +
stat_qq_line(color = "#9B5B5B") +
theme_minimal() +
labs(title = "Normal Q-Q Plot")
gridExtra::grid.arrange(p1, p2, ncol = 2)
Key Differences
| Task | Mandala | lme4 |
|---|---|---|
| Random intercept | random = ~ block |
(1\|block) |
| Variance components | $varcomp |
VarCorr() |
| BLUPs | mandala_predict() |
ranef() |
| Heritability | Built-in | Manual |
| Spatial models | Built-in | Extensions needed |
When to Use Each
Use Mandala for:
- Agricultural field trials
- Spatial correlation modeling
- Quick heritability estimates
Use lme4 for:
- General mixed models
- Extensive diagnostics
- Large documentation/community
Session Information
sessionInfo()R version 4.5.2 (2025-10-31)
Platform: aarch64-apple-darwin20
Running under: macOS Tahoe 26.1
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: America/New_York
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] ggplot2_4.0.0 dplyr_1.1.4 lmerTest_3.1-3 lme4_1.1-37 Matrix_1.7-4
loaded via a namespace (and not attached):
[1] gtable_0.3.6 jsonlite_2.0.0 compiler_4.5.2
[4] tidyselect_1.2.1 Rcpp_1.1.0 gridExtra_2.3
[7] splines_4.5.2 scales_1.4.0 boot_1.3-32
[10] yaml_2.3.10 fastmap_1.2.0 lattice_0.22-7
[13] R6_2.6.1 labeling_0.4.3 generics_0.1.4
[16] knitr_1.50 rbibutils_2.3 htmlwidgets_1.6.4
[19] MASS_7.3-65 tibble_3.3.0 nloptr_2.2.1
[22] minqa_1.2.8 pillar_1.11.1 RColorBrewer_1.1-3
[25] rlang_1.1.6 xfun_0.54 S7_0.2.0
[28] cli_3.6.5 mgcv_1.9-3 withr_3.0.2
[31] magrittr_2.0.4 Rdpack_2.6.4 digest_0.6.37
[34] grid_4.5.2 lifecycle_1.0.4 nlme_3.1-168
[37] reformulas_0.4.2 vctrs_0.6.5 evaluate_1.0.5
[40] glue_1.8.0 numDeriv_2016.8-1.1 farver_2.1.2
[43] rmarkdown_2.30 pkgconfig_2.0.3 tools_4.5.2
[46] htmltools_0.5.8.1