---
title: "Pooled analysis of multi-environment trials with CANE"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Pooled analysis of multi-environment trials with CANE}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 7)
options(width = 95)
```

```{r}
library(CANE)
```

## The problem

A single experiment at one site in one season answers a narrow question. Crop
improvement and agronomy therefore repeat the same experiment across locations,
seasons or years, and the quantity of interest becomes the
treatment-by-environment interaction: do treatments rank consistently, or does
the best treatment depend on where and when it is grown?

Pooling such a series is not simply a matter of fitting one larger model. The
classical workflow has four prerequisites, and each is easy to get wrong:

1. each environment must first be analysed on its own, with every effect tested
   against the error term that the design assigns to it;
2. the error variances of the environments must be compared, because
   heterogeneous errors invalidate the pooled F-tests;
3. if they are heterogeneous, the data must be rescaled before pooling; and
4. the pooled treatment means must be separated using the correct error
   stratum, and interpreted in the light of the interaction.

`CANE` performs all four in one design-specific function call.

## The five functions

```{r}
data.frame(
  Design = c("Completely randomised", "Randomised block", "Latin square",
             "Split plot", "Strip plot"),
  Function = c("PooledCRD()", "PooledRBD()", "PooledLSD()", "PooledSPD()",
               "PooledStPD()"),
  `Error strata` = c(1, 1, 1, 2, 3),
  `Design arguments` = c("-", "Replication", "Row, Column",
                         "Replication, MainPlot, SubPlot",
                         "Replication, RowFactor, ColumnFactor"),
  check.names = FALSE)
```

All five share the same interface: `data`, `Response`, `Location`, the
design-specific factors, `alpha`, `Mult_Comp_Test`, and optionally `transform`
and `env_effect`. There is no omnibus function that handles every design; the
user chooses the function matching the design that was actually conducted.

## A worked randomised block series

The `sugarcane` dataset holds commercial cane sugar yield (t/ha) of 18
genotypes grown in a randomised block design with two replications at two
locations over three crop cycles, giving six environments.

```{r}
data(sugarcane)
str(sugarcane)
with(sugarcane, table(env, rep))
```

```{r}
fit <- PooledRBD(sugarcane, Response = "ccsy", Location = "env",
                 Treatment = "gen", Replication = "rep",
                 alpha = 0.05, Mult_Comp_Test = 1)
```

### Step 1: the environments on their own

```{r}
fit$Individual_ANOVA[["SGA-IP"]]
```

The error mean squares of the six environments are what the next step compares:

```{r}
fit$Environment_Key
```

### Step 2: are the error variances homogeneous?

```{r}
fit$Bartlett_Test
fit$Levene_Test
```

The largest error mean square is more than a hundred times the smallest, so the
error variances are clearly heterogeneous. Bartlett's test is sensitive to
non-normality, which is why `CANE` reports the median-centred Brown-Forsythe
form of Levene's test beside it, and the environment-wise Shapiro-Wilk tests as
well:

```{r}
fit$Normality_Test
```

Both tests agree here, so the decision to rescale is secure. When they
disagree, prefer Levene, and use `transform = "always"` or
`transform = "never"` to take the decision yourself rather than leaving it to a
threshold.

### Step 3: the transformation

```{r}
fit$Transformation$applied
cat(fit$Transformation$reason)
```

Aitken's transformation divides each observation by the square root of the
error mean square of **its own** environment. That yields a useful
self-check: after the transformation each environment contributes an error sum
of squares equal to its own error degrees of freedom, so the pooled error mean
square must come out at exactly 1.

```{r}
cat(fit$Transformation$diagnostic$note)
```

### Step 4: the pooled analysis

```{r}
fit$Pooled_ANOVA
```

The `Error` column names the mean square used as the denominator of each
F-test. In a randomised block series the environment main effect is tested
against the replication-within-environment mean square, because replications
are the units within which environments are compared; the treatment effect and
the interaction are tested against the pooled error.

Note the caveat attached to the environment main effect on a transformed
scale: each environment has been divided by its own error standard deviation,
so that term is no longer expressed in t/ha and is not interpretable as a
yield difference. Interpretation belongs to the treatment and interaction
terms.

### Step 5: separating the treatment means

```{r}
fit$Treatments_Comparison
```

Because the analysis was carried out on the transformed scale, the means in
the `Mean` column and the grouping letters both refer to that scale. The
arithmetic means on the original scale are given alongside, for reporting in
t/ha. They are not an inverse transformation: no single multiplier inverts
Aitken's rescaling, because each environment was divided by a different
constant.

### The interaction matters

```{r}
fit$GEI_Note
```

The interaction is significant, so the pooled ranking conceals genotypes that
excel in some environments and not others. The environment-wise comparisons
are already in the object:

```{r}
fit$Location_wise[["TCSM-IP"]]$groups[1:5, ]
```

## Designs with more than one error stratum

A split plot design has two error terms and a strip plot design three. This is
where the choice of denominator is not a detail: the main plot effect of a
split plot tested against the subplot error is simply the wrong test.

```{r}
data(spd_example)
sp <- PooledSPD(spd_example, "Yield", "Location", "Replication", "MainPlot",
                "SubPlot", 0.05, 1)
sp$Pooled_ANOVA
```

Mean separation follows the same logic. Main plot means are compared with the
main plot error, subplot means with the subplot error:

```{r}
sp$Treatments_Comparison$MainPlot$statistics
sp$Treatments_Comparison$SubPlot$statistics
```

The strip plot design returns three sets of comparisons, one per stratum:

```{r}
data(stpd_example)
st <- PooledStPD(stpd_example, "Yield", "Location", "Replication", "RowFactor",
                 "ColumnFactor", 0.05, 1)
st$Pooled_ANOVA
names(st$Treatments_Comparison)
```

## Choosing a multiple comparison procedure

`Mult_Comp_Test = 1` gives Tukey's HSD, which controls the family-wise error
rate over all pairwise comparisons and is the sensible default when all
pairwise differences are of interest. `2` gives Duncan's multiple range test,
whose graduated protection levels buy power at the cost of weaker error
control. `3` gives Fisher's LSD, which makes no adjustment at all; with
\eqn{t} means it conducts \eqn{t(t-1)/2} independent tests at level
\eqn{\alpha}, so the chance of at least one false declaration grows quickly.
`CANE` warns when LSD is requested for more than three treatments. Reserve it
for a small number of comparisons planned before the data were seen.

## Fixed or random environments

By default environments are treated as fixed, which is appropriate when they
are a specific set of target sites or seasons. If the environments are better
regarded as a sample from a wider population to which the conclusion should
generalise, the treatment main effect should be tested against the
treatment-by-environment interaction:

```{r}
fr <- PooledRBD(sugarcane, "ccsy", "env", "gen", "rep", 0.05, 1,
                env_effect = "random")
r <- fr$Pooled_ANOVA
r[r$Source %in% c("Treatment", "Treatment x Env"), ]
```

The pooled comparison of means then uses the same mean square, so the grouping
letters and the F-test rest on the same denominator:

```{r}
fr$Treatments_Comparison$parameters[, c("test", "error_stratum", "scale")]
```

## What CANE is not for

`CANE` implements the fixed-effects pooled analysis of a *balanced* series of
experiments. It is deliberately narrow. For

* unbalanced series, or treatment sets that only partly overlap between
  environments, use a mixed-model package such as **nlme** or **lme4**, which
  handle missing cells properly;
* augmented designs, in which a few checks are replicated and the test entries
  are not, use **augmentedRCBD** (archived on CRAN in April 2026 for an
  administrative reason; it remains installable from its own repository);
* the single-trial stage of a mixed-model pipeline, use **statgenSTA**;
* explicit modelling of heterogeneous variances or of a spatial covariance
  structure, use **nlme**, **lme4**, **sommer** or **asreml**;
* multiplicative decomposition of the interaction and stability analysis
  (AMMI, GGE biplots, Shukla's variance, Eberhart-Russell regression), use
  **metan** or **ammistability**;
* best linear unbiased prediction of genotype effects for selection, use a
  mixed-model package.

The pooled ANOVA is the first step of a multi-environment analysis, not the
last one. Its value is that it tests the main effects and the interaction
exactly and transparently, which tells you whether the more elaborate analyses
are worth running.
