I’m currently using the agricolae package in R to generate randomized complete block designs (RCBD) with six treatments and four replicates. While the randomization works as expected, I’ve noticed that sometimes the same treatment appears adjacent to itself across blocks (e.g., the same treatment in neighboring plots). In our field trials, the company prefers to avoid such situations due to potential neighborhood effects (e.g., drift, root interference).
My questions are: Is it possible to prevent this adjacency directly within agricolae, by imposing spatial constraints in the design?
If not, would the best approach be to loop over randomizations until a spatially acceptable layout is found?
Are there any other packages or strategies you would recommend that allow more control over treatment layout, while still being compatible with agricolae?
Below is a minimal working example showing how I generate the design and plot it. Any suggestions on how to add spatial constraints would be greatly appreciated!
# Install agricolae and agricolaeplotr if needed
install.packages("agricolae")
install.packages("agricolaeplotr")
library(tidyverse)
library(agricolae)
library(agricolaeplotr) # for plot_rcbd()
# Define treatment names
fertilizers <- c("Growth2000",
"Starter50",
"WellGrown",
"MaxDev",
"SuperBoost",
"NatFertilizer")
# Generate a randomized complete block design (RCBD)
RCBD <- design.rcbd(trt = treatments,
r = 4,
seed = 2025)
# Plot the field layout
plot_rcbd(design = RCBD,
factor_name = "fertilizers", # Column containing the treatment levels
treatment_label = "fertilizers", # Display treatment names in the plot
width = 2, # Width of each plot (in meters)
height = 1) # Height of each block (in meters)
This plot shows an example of what I’d like to avoid: the Growth2000 treatment appears in adjacent plots in blocks 3 and 4, first column.
Thank you in advance for your feedback and any ideas you might have to control for treatment adjacency in the field layout.
Best regards.
I had a quick look at the agricolae
package but didn't see any design that did what you wanted, so I modified the design.rcbd
function so that it checks for the previous assignment and resamples until the plots are all different. I made only six modifications (shown by lines with #).
design.rcbd2 <- function(trt, r, serie = 2, seed = 0, kinds = "Super-Duper",
first = TRUE, continue = FALSE, randomization = TRUE) {
number <- 10
if (serie > 0)
number <- 10^serie
ntr <- length(trt)
if (seed == 0) {
genera <- runif(1)
seed <- .Random.seed[3]
}
set.seed(seed, kinds)
parameters <- list(design = "rcbd", trt = trt, r = r, serie = serie,
seed = seed, kinds = kinds, randomization)
# mtr <- trt
mtr <- vector(mode="list", length=r) ### Modify above line
if (randomization)
# mtr <- sample(trt, ntr, replace = FALSE)
mtr[[1]] <- sample(trt, ntr, replace = FALSE) ### Modify
block <- c(rep(1, ntr))
for (y in 2:r) {
block <- c(block, rep(y, ntr))
mtr[[y]] <- sample(trt, ntr, replace = FALSE) ### Insert
while(any(mtr[[y]]==mtr[[y-1]])) { # Insert
if (randomization)
# mtr <- c(mtr, sample(trt, ntr, replace = FALSE))
mtr[[y]] <- sample(trt, ntr, replace = FALSE) ### Modify above line
}
}
mtr <- unlist(mtr) # Insert
plots <- block * number + (1:ntr)
book <- data.frame(plots, block = as.factor(block), trt = as.factor(mtr))
names(book)[3] <- c(paste(deparse(substitute(trt))))
names(book)[3] <- c(paste(deparse(substitute(trt))))
if (continue) {
start0 <- 10^serie
if (serie == 0)
start0 <- 0
book$plots <- start0 + 1:nrow(book)
}
outdesign <- list(parameters = parameters, sketch = matrix(book[, 3], byrow = TRUE, ncol = ntr), book = book)
return(outdesign)
}
Test it:
RCBD2 <- design.rcbd2(trt = fertilizers,
r = 4,
randomization=TRUE,
seed = 2025)
plot_rcbd(design = RCBD2,
factor_name = "fertilizers", # Column containing the treatment levels
treatment_label = "fertilizers", # Display treatment names in the plot
width = 2, # Width of each plot (in meters)
height = 1) # Height of each block (in meters)