---
title: "CV by plot shape"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{CV by plot shape}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 6.5,
                      fig.height = 4.2, dpi = 120)
```

```{r setup}
library(trialSizing)
```

## The step before the models

`fit_lrp()`, `fit_qrp()` and `fit_mcm()` all start from the same thing: a table
of coefficients of variation, one row per planned plot size. `calc_cv_shapes()`
builds that table from the raw grid of basic experimental units (BEU) as the
trial was harvested, so the whole pipeline is grid in, CV table out, model fit.

## Theory

A uniformity trial is a grid of $L$ rows by $C$ columns of BEU. A rectangular
**plot shape** groups adjacent units into blocks of $X_L$ rows by $X_C$ columns,
and this is only possible when $X_L$ divides $L$ and $X_C$ divides $C$. Each
shape tiles the grid into

$$
n = \frac{L \, C}{X_L \, X_C}
$$

non-overlapping plots. For every shape the plot **totals** are formed, and their
mean, standard deviation and CV are computed:

$$
CV = 100 \times \frac{s}{\bar{y}}
$$

As plots get larger they average over more units, the totals vary
proportionally less, and the CV falls -- the decreasing curve every plot-size
method is built to read.

### Shapes are not interchangeable at equal area

A $1 \times 2$ shape and a $2 \times 1$ shape cover the same two basic units,
but along different directions of the field. Whenever fertility is not the same
in both directions their CVs differ, so both are reported and the CV table has
**repeated plot sizes** ($x = X_L X_C$) that are genuinely different rows. This
is the table-level counterpart of the directional autocorrelation that
[calc_paranaiba()] uses.

### Fewer plots, less information

A shape of area $X$ yields $n = LC/X$ plots, so a large plot size rests on few
plots and its CV is estimated with little information: the last rows of the
table are the least reliable. The `n` column is returned for exactly this
reason and is the natural weight for a weighted fit. Shapes leaving fewer than
`min_plots` plots are dropped, which by default removes only the whole grid
(a single plot, which has no variance).

## Data and basic use

```{r data}
grid1 <- as.matrix(uniformity_trial[uniformity_trial$trial == "T1",
                                    grep("^col", names(uniformity_trial))])
dim(grid1)
```

```{r fit}
tab <- calc_cv_shapes(grid1)
tab
```

The columns are `trial`, `X_L` and `X_C` (the shape in basic units), `x` (the
plot size $X_L X_C$), `n` (number of plots), `mean`, `sd` and `cv` (percent),
ordered by plot size.

### Same area, different orientation

The repeated plot sizes make the anisotropy visible directly:

```{r orientation}
tab[tab$x == 2, ]
```

Two shapes of 2 m², one running along the rows and one along the columns, with
different CVs. If they disagree strongly, a plot size chosen from one
orientation will not be the plot size chosen from the other.

### n falls as the plot grows

```{r counts}
unique(tab[, c("x", "n")])
```

The largest plots are supported by a handful of plots only, which is the case
for weighting the fit.

## Feeding the fitters

The returned columns are already named `x`, `cv` and `trial`, so the table goes
straight into the models with no reshaping:

```{r feed}
fit_lrp(tab, x = "x", cv = "cv", step = 0.05)
```

Passing `weights = TRUE` to the fitters uses the `n` column, giving the
well-estimated small plots more say than the sparse large ones.

## Several trials at once

A named list of grids produces one block of rows per trial, ready to fit one
model per trial with the `trial` argument:

```{r multi}
grids <- lapply(split(uniformity_trial, uniformity_trial$trial),
                function(d) as.matrix(d[, grep("^col", names(d))]))

tab3 <- calc_cv_shapes(grids)
table(tab3$trial)
```

```{r multi-fit}
fit_lrp(tab3, x = "x", cv = "cv", trial = "trial", step = 0.05)$summary
```

## Long-format data

When the measurements come out of a spreadsheet, the grid can be rebuilt from
row and column index columns rather than trusting the row order of the file:

```{r long}
long <- expand.grid(col = 1:12, row = 1:8)
long$mf <- as.vector(t(grid1))

head(calc_cv_shapes(long, value = "mf", row_id = "row", col_id = "col"), 4)
```

Missing cells are an error rather than a silent gap: every row/column
combination must be present.

## Where this fits

`calc_cv_shapes()` sits between checking the trial (`vignette("check_trial")`)
and fitting a model (`vignette("lrp")`, `vignette("qrp")`, `vignette("mcm")`).
The Paranaíba method (`vignette("paranaiba")`) skips it, working on the raw grid
directly, and `vignette("compare")` runs several methods on one trial at once,
building this table on the way when given a grid.

### References

Cargnelutti Filho, A. et al. (2025). Determinação do tamanho de parcela para
avaliar a massa de parte aérea de grão-de-bico. *Revista Vivências*, 21(43),
499-513.

Paranaíba, P. F., Ferreira, D. F. & Morais, A. R. (2009). Tamanho ótimo de
parcelas experimentais. *Revista Brasileira de Biometria*, 27(2), 255-268.
