ANOVA
Structure
(lm() +
car::Anova()) |
Model and sums of squares |
A single fit, lm(Y ~ L + L:Block + A + B + A:B + L:A + L:B + L:A:B + L:Block:A), with sums of squares from car::Anova(type = "II"). Block enters only through L:Block, so blocks are nested within Location. The ANOVA is run on the Aitken-transformed values for any character that failed Bartlett's test |
| Pooled Error (a) — main-plot stratum |
Row 9, the L:Block:A term, giving df = Locations × (Blocks − 1) × (Main-plot levels − 1). Tests Main plot (A), Location × Block and Location × Main plot |
| Pooled Error (b) — sub-plot stratum |
Row 10, the Residuals, giving df = Locations × Main-plot levels × (Blocks − 1) × (Sub-plot levels − 1). Tests the Location main effect, Sub plot (B), Main × Sub, Location × Sub, Location × Main × Sub, and Pooled Error (a) itself (F = MSEa / MSEb) |
| Where Location is tested |
Note the asymmetry. The Location main effect is tested against Pooled Error (b), while Location × Main plot and Location × Block are tested against Pooled Error (a). The Location post-hoc comparison likewise uses Error (b). This is how the source is written, and it must be reproduced to get the same p-values |
| Reported sources |
10 rows, shown in the Individual ANOVA tab in this order: Location, Main plot, Location × Main plot, Location × Block, Pooled Error (a), Sub plot, Location × Sub plot, Main plot × Sub plot, Location × Main plot × Sub plot, Pooled Error (b) |
Homogeneity
& Pooling
(bartlett.test()) |
Test performed |
Run per character. Within each Location, aov(Y ~ Block + FactorA + Block:FactorA + FactorB + FactorA:FactorB) is fitted. Its residuals from every Location are joined into one vector, labelled by Location, and passed to bartlett.test(residuals, group_labels). A single test is performed. Because Block:FactorA absorbs the whole-plot error, the residuals being compared are the sub-plot errors |
| Minimum data requirement |
A Location contributes only if it has ≥ 2 levels each of Block, FactorA and FactorB. Fewer than 2 valid Locations ⇒ the chi-square and p-value are reported as NA and no transformation is applied |
| Trigger for Aitken transformation |
Hardcoded at p ≤ 0.05, independent of the user's significance level α |
| Aitken transformation applied |
Within each Location, every observation of the affected character is divided by sqrt(MSE) for that Location, where MSE = sum(resid(m)^2) / df.residual(m) from the model above. The per-Location MSE values are printed beneath the Bartlett table. One consequence is that Pooled Error (b) of a transformed character is close to 1 |
User
Transformation
(optional) |
Default |
Off. Enabled by the transformation checkbox; variables are then assigned to the log, square-root or arcsine pickers |
| Log |
log10(x) when all values > 0; otherwise the column is shifted first: log10(x - min(x) + 1) |
| Square root |
sqrt(x) when all values > 0; sqrt(x + 0.5) when any value equals 0; refused with a warning if any value is negative |
| Arcsine |
asin(sqrt(x)), requiring proportions in [0, 1]; exact 0 and 1 are first replaced by 1/(4n) and 1 - 1/(4n), where n is the number of rows. Refused entirely if any value falls outside [0, 1] |
Multiple
Comparison
(agricolae) |
Procedure |
selectInput(choices = c("LSD","TUKEY","DMRT"), selected = "LSD") ⇒ LSD is the shipped default |
| Significance level α |
Choices are 0.05 and 0.01. The selected = argument is set to a value not in the choice list, so the control falls back to its first entry: the effective default is 0.05 |
| Error term passed to each test |
Supplied explicitly per effect: DFerror / MSerror of Pooled Error (a) for Main plot and Location × Main plot; Pooled Error (b) for Location, Sub plot, Main × Sub, Location × Sub and Location × Main × Sub |
| DMRT implementation |
duncan_test(), a copy of agricolae::duncan.test() shipped in duncan_test.R. The only change is in how the studentized range is found: when qtukey() returns NaN (many treatments), the value is solved with uniroot() instead, and ranks that still cannot be found are dropped. Where qtukey() succeeds the output is identical to duncan.test() |
| Critical difference reported |
One value per effect from the statistics component: column 6 for LSD, column 5 for Tukey's HSD. For DMRT, the critical ranges from $duncan are reported in separate tables |
| CD suppression & unrounded CD |
CD is shown only when the effect's F-test p ≤ the selected α; otherwise -. The letters are decided at full precision, and the unrounded CD is kept separately (rcbd_CD*_exact) for the reference note beside the rounded value |
| Letter order |
The $groups letters are re-indexed by the row names of the matching means table ([rownames(rcbd_result_mean*), ]), which is ordered by gtools::mixedsort(). Letters therefore follow the means table row for row |
Dispersion
Statistics |
SE(m), SE(d) |
sqrt(MSerror / r) and sqrt(2 * MSerror / r), where MSerror is statistics[1, 1] of the corresponding agricolae call and r is the replication of its first mean |
| CV (%) |
statistics[1, 4] of the corresponding agricolae call |
Summary
Stats tab |
Per group |
For each character, grouped separately by Main plot, Sub plot and Location, on the uploaded (untransformed) values: Mean, SD, SE = SD / √n, Min, Max, CV = SD / Mean × 100, moments::skewness(), moments::kurtosis() (not excess kurtosis) |
Precision &
Presentation |
Decimal places |
numericInput("rcbd_digit", value = 2, min = 1, max = 4) ⇒ 2 decimal places |
| Table font |
selected = "cambria"; affects table rendering only, not computation |
Principal
Component
Analysis
(prcomp()) |
Input matrix |
Character means per Location × Main × Sub combination, row-ordered by gtools::mixedorder(), computed on demand from the uploaded values (after any user transformation, but not Aitken-scaled). Requires at least two response variables (req(ncol(rcbd_df) > 9) on data carrying 8 structural columns) |
| Scaling |
prcomp(center = TRUE, scale = TRUE) ⇒ correlation-matrix PCA via SVD, so no trait dominates PC1 merely through its unit of measurement |
| Sign convention |
Both $x and $rotation are multiplied by −1 after fitting. This is a presentation choice (PC signs are arbitrary), but it must be reproduced to match the app's loadings and index scores |
| Index scores |
Index 1 = PC1 scores; Index 2 = PC2 scores, each reported raw and rescaled to [0, 1] with scales::rescale(). The index plots mark a combination as Selected against a cutoff, default 0.75 (choices 0.50, 0.75, 0.80, 0.90, 0.95) |
Plots &
Normality |
Interaction plots |
Means from phia::interactionMeans() on lm(response ~ FactorA + FactorB + Location + FactorA:FactorB + FactorA:Location + FactorB:Location + FactorA:FactorB:Location) |
| Normality (Q-Q panel) |
Residuals of lm(y ~ L + L:Block + A + L:A + L:Block:A + B + L:B + L:Block:B + A:B + L:A:B); note this model also carries L:Block:B, unlike the ANOVA model. Optional annotations: Shapiro-Wilk (3 ≤ n ≤ 5000), Anderson-Darling (nortest::ad.test(), n ≥ 7), Kolmogorov-Smirnov against a fitted normal (n ≥ 2); each needs non-zero variance |