Skip to content

Factorial ANOVA

When an experiment crosses two factors, genotype by treatment, the interesting number is not either main effect. It is the interaction. Does the treatment do the same thing in the knockout as in the wild type, or does the genotype change how the drug acts? A grouped box plot shows the cells, and a factorial ANOVA puts a p-value on that question.

This page draws the grouped box and reports a Type II ANOVA: the two main effects and their interaction. R uses rstatix, Python uses statsmodels. Both run in the pinned pubplot container and agree on all three p-values.

twoway_response.csv crosses two genotypes (ko, wt) with three treatments (vehicle, low, high), roughly eight replicates per cell, one continuous response. The design has a built-in interaction: the treatments separate cleanly in the knockout and collapse in the wild type.

Dodge the treatment within each genotype so the cells sit side by side. The subtitle carries the ANOVA. Type II sums of squares are the right default when the design is close to balanced and you want each effect adjusted for the others.

library(ggplot2)
library(rstatix)
df$genotype <- factor(df$genotype)
df$treatment <- factor(df$treatment)
# Type II ANOVA: two main effects and their interaction.
at <- as.data.frame(anova_test(df, response ~ genotype * treatment, type = 2))
sig <- at[at$p < 0.05, ]
sub <- paste(sprintf("%s: P = %.2g", gsub(":", " × ", sig$Effect), sig$p),
collapse = "\n")
ggplot(df, aes(genotype, response, fill = treatment)) +
geom_boxplot(position = position_dodge(0.8), width = 0.7,
outlier.shape = NA, alpha = 0.9) +
geom_point(position = position_jitterdodge(jitter.width = 0.15, dodge.width = 0.8),
size = 1.3, alpha = 0.7, shape = 21, stroke = 0.3) +
scale_fill_manual(values = c("#3B6DB3", "#C1432B", "#2E8B57")) +
labs(x = "Genotype", y = "Response (a.u.)", fill = "Treatment", subtitle = sub) +
theme_classic(base_size = 13) +
theme(plot.subtitle = element_text(hjust = 0.5, size = 9.5, colour = "grey30"))

Grouped box of response by genotype and treatment, Type II ANOVA subtitle (R)

Both engines return the same three p-values: genotype 2.9e-10, treatment 2.2e-7, and the interaction 2.3e-10. The interaction is real, and the plot shows why. In the knockout the three treatments fan out; in the wild type they nearly overlap. A single main-effect bar chart would have hidden that.

  • Put the interaction on the figure, not just the main effects. It is the term a factorial design exists to test.
  • Dodge, do not stack or facet, for two factors. Side-by-side boxes let the eye compare cells within a genotype directly.
  • Keep one legend, placed outside the plotting area, so it never sits on a data point.
  • Hold the treatment colors identical to the two-group and multi-group pages, so a reader moving through the section is not relearning the palette.

For three factors, add the third as a facet row rather than a fourth color. The runnable scripts and fixture are in the companion code repo under guides/figures/factorial-anova/.