Two-Way MANOVA
The blueprint for Factorial Multivariate Discovery. This model audits the synergistic interaction between two categorical factors across a vector of multiple continuous outcomes.
What is it?
Two-Way MANOVA (Multivariate Analysis of Variance) evaluates the effects of two categorical factors on multiple continuous dependent variables simultaneously.
When to use it
- 2 Factors: Categorical independent groupings.
- 2+ Outcomes: Continuous, correlated dependent variables.
- Bivariate Protection: Prevents Family-wise Type I error inflation.
Core Idea
Instead of separate univariate ANOVAs, MANOVA creates a linear combination of outcomes to construct a multi-dimensional comparison. This is visualized as confidence ellipses:
By examining outcomes in 2D space, MANOVA detects differences that univariate tests might miss because it considers group covariance.
Hypotheses
How it works
Constructs Hypothesis (H) and Error (E) matrices instead of simple Sum of Squares. Computes multivariate tests like Wilk's Lambda.
Assumptions
Important Note
Box's M test is highly sensitive. If it is significant (p<0.001), Homogeneity of Covariance is violated. Pivot to Pillai's Trace as a robust test statistic.
Quick Example
Two-Way MANOVA Live Laboratory
Vary factor shifts and covariance correlation to watch confidence ellipses tilt and drift.
| Multivariate Test | Value | F-Approx | df | p-value |
|---|---|---|---|---|
| Wilk's Lambda (Λ) | 0.850 | 3.53 | 2, 26 | 0.0118 |
Hypotheses
Pragmatic null and alternative hypotheses defined in mathematical notation.
H₀: All group mean vectors are equal across the combination of DVs (no main effects or interactions exist when considering all DVs jointly)
Hₐ: At least one group's mean vector differs on the combined DVs (at least one main effect or interaction exists)
MANOVA tests simultaneous group differences across multiple DVs, accounting for correlations among outcomes. Tests 3 omnibus effects: Main effect A, Main effect B, and A×B interaction. If significant, follow with univariate ANOVAs or discriminant analysis to identify which DVs drive effects. MANOVA has greater power than separate ANOVAs when DVs are moderately correlated (r = .3-.7).
Assumptions
The core mathematical criteria needed to ensure that statistical testing remains unbiased and valid.
Diagnostics
Checking residual plots and indices to examine model deviations and ensure standard error integrity.
- Box's M test for homogeneity of covariance matrices (use α = .001)
- Bartlett's test of sphericity for DV correlations
- Mahalanobis distances to detect multivariate outliers (D² > χ²_critical)
- Correlation matrix among DVs (check for multicollinearity and adequate correlation)
- Descriptive statistics (M, SD) for all DVs across all IV combinations
- Mardia's or Royston's multivariate normality test
- Q-Q plots for each DV by group
- Scatterplot matrix for all DV pairs, colored by groups
- Cell sizes and balance check (n per cell)
- Univariate ANOVA follow-ups for significant MANOVA effects
- Discriminant function analysis to identify DV combinations driving effects
- Effect sizes (partial η², Pillai-Bartlett trace, Roy's largest root)
Applied Minds
Review concrete study examples, data layout guidelines, and copy executable syntax scripts.
Psychotherapy Type on Mental Health Outcomes (Anxiety + Depression)
Research question: Does psychotherapy type (CBT, ACT, Psychodynamic) and treatment duration (Short-term [8 weeks], Long-term [16 weeks]) affect mental health outcomes? Design: 2×3 factorial design with n=25 per cell (150 total). Two DVs: (1) Beck Anxiety Inventory (BAI, 0-63), (2) Beck Depression Inventory-II (BDI-II, 0-63). DVs moderately correlated (r ≈ .5). Hypothesis: CBT superior to other therapies; longer duration enhances all therapies.
# Two-way MANOVA: Therapy × Duration on Anxiety + Depression
# Factorial design with 2 correlated DVs
# Load packages
library(tidyverse) # Data manipulation
library(car) # For MANOVA (Anova function)
library(heplots) # For HE plots and effect sizes
library(mvnormtest) # For multivariate normality tests
library(biotools) # For Box's M test
library(MASS) # For LDA (discriminant analysis)
# Set seed
set.seed(2025)
# Simulate realistic data
n_per_cell <- 25
therapy_levels <- c("CBT", "ACT", "Psychodynamic")
duration_levels <- c("Short", "Long")
data <- expand.grid(
therapy = rep(therapy_levels, each = n_per_cell),
duration = rep(duration_levels, each = n_per_cell * 3 / 2)
) %>%
slice(rep(1:n(), length.out = 150)) %>%
mutate(
# Base scores (post-treatment, lower = better)
therapy_effect_anx = case_when(
therapy == "CBT" ~ -12,
therapy == "ACT" ~ -8,
therapy == "Psychodynamic" ~ -5
),
therapy_effect_dep = case_when(
therapy == "CBT" ~ -14,
therapy == "ACT" ~ -9,
therapy == "Psychodynamic" ~ -6
),
duration_effect = ifelse(duration == "Long", -5, 0),
# Generate correlated DVs (r ≈ .5)
base_anx = 35 + therapy_effect_anx + duration_effect,
base_dep = 32 + therapy_effect_dep + duration_effect,
# Add correlated error
error_shared = rnorm(n(), 0, 3),
error_anx = rnorm(n(), 0, 4),
error_dep = rnorm(n(), 0, 4),
anxiety = base_anx + error_shared + error_anx,
depression = base_dep + error_shared + error_dep
) %>%
mutate(
anxiety = pmin(pmax(anxiety, 0), 63),
depression = pmin(pmax(depression, 0), 63)
) %>%
select(therapy, duration, anxiety, depression)
cat("=== Data Structure ===", "\n")
cat("Design: 2 (Duration) × 3 (Therapy) factorial\n")
cat("Total n:", nrow(data), "\n")
cat("Cells:", length(unique(data$therapy)) * length(unique(data$duration)), "\n\n")
# === STEP 1: Check Assumptions ===
# 1. Check correlations among DVs
cat("=== DV Correlation ===", "\n")
cor_matrix <- cor(data[, c("anxiety", "depression")])
print(cor_matrix)
cat("\nIdeal for MANOVA: .3 < r < .7 (here r ≈", round(cor_matrix[1,2], 2), ")\n\n")
# 2. Bartlett's test of sphericity (DVs correlated?)
cat("=== Bartlett's Test of Sphericity ===", "\n")
bartlett_test <- cortest.bartlett(cor_matrix, n = nrow(data))
print(bartlett_test)
cat(ifelse(bartlett_test$p.value < .05, "✓ DVs sufficiently correlated", "X DVs not correlated"), "\n\n")
# 3. Check cell sizes
cat("=== Cell Sizes ===", "\n")
print(table(data$therapy, data$duration))
cat("\n")
# 4. Descriptive statistics
cat("=== Descriptive Statistics ===", "\n")
desc_stats <- data %>%
group_by(therapy, duration) %>%
summarise(
n = n(),
M_anx = mean(anxiety), SD_anx = sd(anxiety),
M_dep = mean(depression), SD_dep = sd(depression),
.groups = "drop"
)
print(desc_stats, n=6)
# 5. Box's M test (homogeneity of covariance matrices)
cat("\n=== Box's M Test ===", "\n")
data$group <- interaction(data$therapy, data$duration)
boxm_result <- boxM(data[, c("anxiety", "depression")], data$group)
print(boxm_result)
cat("\nInterpretation: Use α = .001 (Box's M is sensitive). p > .001 = equal covariances\n")
cat(ifelse(boxm_result$p.value > .001, "✓ Covariances equal", "⚠ Covariances unequal - use Pillai's Trace"), "\n\n")
# 6. Multivariate outliers (Mahalanobis distance)
cat("=== Multivariate Outliers ===", "\n")
center <- colMeans(data[, c("anxiety", "depression")])
cov_matrix <- cov(data[, c("anxiety", "depression")])
mahal_dist <- mahalanobis(data[, c("anxiety", "depression")], center, cov_matrix)
chi_crit <- qchisq(0.999, df = 2) # 2 DVs
outliers <- sum(mahal_dist > chi_crit)
cat("Outliers(D² > χ²_{.999, 2} =", round(chi_crit, 2), "):", outliers, "\n")
cat(ifelse(outliers == 0, "✓ No multivariate outliers", "⚠ Outliers detected"), "\n\n")
# 7. Multivariate normality (Mardia's test - requires mvnormtest or MVN)
cat("=== Multivariate Normality ===", "\n")
cat("Check univariate normality per DV(necessary but not sufficient)\n")
shapiro_anx <- by(data$anxiety, data$group, shapiro.test)
shapiro_dep <- by(data$depression, data$group, shapiro.test)
cat("Anxiety: all groups p >", min(sapply(shapiro_anx, function(x) x$p.value)), "\n")
cat("Depression: all groups p >", min(sapply(shapiro_dep, function(x) x$p.value)), "\n\n")
# === STEP 2: Run Two-way MANOVA ===
cat("=== Two-way MANOVA ===", "\n")
# Create MANOVA model
manova_model <- manova(cbind(anxiety, depression) ~ therapy * duration, data = data)
# Summary with Pillai's Trace (most robust)
cat("\n--- Pillai's Trace(most robust to violations) ---\n")
print(summary(manova_model, test = "Pillai"))
# Summary with Wilks' Lambda (most common)
cat("\n--- Wilks' Lambda(most common, assumes homogeneity) ---\n")
print(summary(manova_model, test = "Wilks"))
# Use car::Anova for Type II/III SS and effect sizes
cat("\n--- Type II MANOVA(car::Anova) ---\n")
manova_car <- Anova(lm(cbind(anxiety, depression) ~ therapy * duration, data = data),
type = 2, test.statistic = "Pillai")
print(manova_car)
# === STEP 3: Effect Sizes ===
cat("\n=== Effect Sizes ===", "\n")
# Compute partial eta squared
eta_sq <- etasq(manova_model, test = "Pillai")
print(eta_sq)
cat("\nInterpretation: .01 = small, .06 = medium, .14 = large(Cohen, 1988)\n\n")
# === STEP 4: Follow-up Univariate ANOVAs ===
cat("=== Follow-up Univariate ANOVAs(if MANOVA significant) ===", "\n")
cat("\n--- Anxiety(BAI) ---\n")
anova_anx <- aov(anxiety ~ therapy * duration, data = data)
print(summary(anova_anx))
cat("\n--- Depression(BDI-II) ---\n")
anova_dep <- aov(depression ~ therapy * duration, data = data)
print(summary(anova_dep))
cat("\nNote: Apply Bonferroni correction: α = .05/2 = .025 for 2 DVs\n\n")
# === STEP 5: Post-hoc Tests ===
if(manova_car$`Pr(>F)`[1] < .05) { # If therapy main effect significant
cat("=== Post-hoc: Therapy Main Effect ===", "\n")
# Pairwise comparisons for anxiety
cat("\n--- Anxiety ---\n")
pairwise_anx <- pairwise.t.test(data$anxiety, data$therapy, p.adjust.method = "bonferroni")
print(pairwise_anx)
# Pairwise comparisons for depression
cat("\n--- Depression ---\n")
pairwise_dep <- pairwise.t.test(data$depression, data$therapy, p.adjust.method = "bonferroni")
print(pairwise_dep)
}
# === STEP 6: Visualizations ===
cat("\n=== Visualizations ===", "\n")
# Interaction plot for anxiety
p1 <- ggplot(data, aes(x = therapy, y = anxiety, color = duration, group = duration)) +
stat_summary(fun = mean, geom = "point", size = 3) +
stat_summary(fun = mean, geom = "line", linewidth = 1) +
stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.2) +
labs(title = "Therapy × Duration on Anxiety(BAI)",
y = "Anxiety Score(lower = better)", x = "Therapy Type") +
theme_bw()
print(p1)
# Interaction plot for depression
p2 <- ggplot(data, aes(x = therapy, y = depression, color = duration, group = duration)) +
stat_summary(fun = mean, geom = "point", size = 3) +
stat_summary(fun = mean, geom = "line", linewidth = 1) +
stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.2) +
labs(title = "Therapy × Duration on Depression(BDI-II)",
y = "Depression Score(lower = better)", x = "Therapy Type") +
theme_bw()
print(p2)
# Bivariate plot showing groups in multivariate space
p3 <- ggplot(data, aes(x = anxiety, y = depression, color = therapy, shape = duration)) +
geom_point(alpha = 0.6, size = 2) +
stat_ellipse(aes(group = interaction(therapy, duration)), level = 0.68) +
labs(title = "Multivariate Space: Anxiety × Depression",
x = "Anxiety(BAI)", y = "Depression(BDI-II)") +
theme_bw()
print(p3)
# === STEP 7: Discriminant Function Analysis (optional) ===
cat("\n=== Discriminant Function Analysis ===", "\n")
cat("Identifies linear combinations of DVs that best separate groups\n\n")
lda_model <- lda(group ~ anxiety + depression, data = data)
cat("Standardized discriminant coefficients:\n")
print(lda_model$scaling)
# === APA-Style Reporting ===
cat("\n=== APA-Style Report ===", "\n")
cat("
A two-way MANOVA was conducted to examine the effects of psychotherapy type
(CBT, ACT, Psychodynamic) and treatment duration(short-term, long-term) on
mental health outcomes(anxiety and depression). The DVs were moderately
correlated(r = .52), supporting MANOVA's use. Box's M test indicated equal
covariance matrices across groups(p = .08), and no multivariate outliers were
detected(all D² < 13.8).
Using Pillai's Trace(robust to assumption violations), results revealed a
significant main effect of therapy type, V = 0.32, F(4, 288) = 13.45, p < .001,
partial η² = .16 (large effect), and a significant main effect of duration,
V = 0.18, F(2, 143) = 15.67, p < .001, partial η² = .18 (large effect). The
Therapy × Duration interaction was not significant, V = 0.03, F(4, 288) = 1.12,
p = .35.
Follow-up univariate ANOVAs(α = .025 with Bonferroni correction) revealed:
• Therapy effect on anxiety: F(2, 144) = 18.34, p < .001, η² = .20
• Therapy effect on depression: F(2, 144) = 22.56, p < .001, η² = .24
• Duration effect on anxiety: F(1, 144) = 31.23, p < .001, η² = .18
• Duration effect on depression: F(1, 144) = 28.91, p < .001, η² = .17
Post-hoc comparisons(Bonferroni-adjusted) indicated CBT was superior to both
ACT(anxiety: p < .001, d = 0.89; depression: p < .001, d = 1.02) and
Psychodynamic therapy(anxiety: p < .001, d = 1.45; depression: p < .001,
d = 1.67). ACT also outperformed Psychodynamic therapy on both outcomes
(both p < .01). Long-term treatment yielded better outcomes than short-term
across all therapies.
Findings support CBT as the most effective therapy for comorbid anxiety and
depression, with dose-response effects favoring longer treatment duration.
")
cat("\n=== Key Statistics to Report ===", "\n")
cat("• Pillai's Trace(or Wilks' Λ) for each effect\n")
cat("• F-statistic with df1 and df2\n")
cat("• p-values and effect sizes(partial η² or V)\n")
cat("• Box's M test result\n")
cat("• DV correlations\n")
cat("• Follow-up univariate ANOVAs with Bonferroni correction\n")
cat("• Post-hoc pairwise comparisons with adjusted p-values\n")
cat("• Descriptive statistics(M, SD) for all DV × IV combinations\n")Significant main effects for therapy type (Pillai's V = 0.32, F[4,288] = 13.45, p < .001, η²_p = .16) and duration (V = 0.18, F[2,143] = 15.67, p < .001, η²_p = .18). CBT outperformed ACT and Psychodynamic therapy on both anxiety (F[2,144] = 18.34, p < .001) and depression (F[2,144] = 22.56, p < .001). Long-term treatment was superior to short-term (both p < .001). No Therapy × Duration interaction (p = .35), suggesting duration benefits generalize across therapies. Findings support CBT as gold standard with dose-response effects.
Alternatives
Structured fallback pathways for choosing alternative tests when normality or slopes requirements fail.
- Pillai's Trace — Mandatory omnibus choice if Box's M is significant.
- Separate Welch ANOVAs — Execute group strikes on individual outcomes with Bonferroni protection.
- PCA Pre-Reduction — Collapse the outcome vector into orthogonal components before the factorial strike.
- Structural Equation Modeling (SEM) — Model the outcomes as a latent construct if theory supports a shared cause.
- Regularized MANOVA — Apply shrinkage to the covariance matrix to prevent model collapse in sparse grids.
Post-hoc
Group mean comparisons and correction controls (e.g. Tukey HSD, Bonferroni) to protect against Family-Wise Error Rates.
Post-hoc pairwise tests defined for this model.
No specific guidelines provided.
Effect Size
Understanding effect sizes (e.g., Cohen's d, Partial Eta-Squared) and clinical impact benchmarks.
Most robust to violations. Range [0, 1]. V = .01 (small), .06 (medium), .14 (large). Preferred when assumptions violated
Most commonly reported. Range [0, 1], smaller = larger effect. Λ = .99 (small), .94 (medium), .86 (large). Equivalent to likelihood ratio test
Proportion of variance in DV set explained by IV. Same thresholds as Cohen's benchmarks: .01 (small), .06 (medium), .14 (large)
Most powerful when effect is on single dimension, but liberal (inflates Type I error). Use only when theoretically justified
0.2
0.5
0.8
Sample Size
Guidelines for minimum sample requirements and power analysis parameters.
n per cell must exceed number of DVs (absolute minimum). Recommended: n ≥ 20 per cell for 2-3 DVs
| Effect Size | Parameters | Required n |
|---|---|---|
| Small Effect | α=.05, power=.80 | n ≈ 200 per group |
| Medium Effect | α=.05, power=.80 | n ≈ 35 per group |
| Large Effect | α=.05, power=.80 | n ≈ 15 per group |
Reporting
How to compile statistical results into publication prose matching APA and journal style guides.
A two-way MANOVA was conducted to examine the effects of IV1 and IV2 on list DVs. The number DVs were describe correlation: moderately/highly correlated, r = .XX to .YY, supporting the use of MANOVA. Preliminary assumption testing revealed state Box's M result, outlier status, normality. Using Pillai's Trace/Wilks' Lambda (robust to assumption violations), results revealed describe significance of main effects and interaction with V or Λ, F(df1, df2) = X.XX, p = .XXX, partial η² = .XX, and interpretation of effect size. Follow-up univariate ANOVAs (α = .05/k with Bonferroni correction) indicated describe which DVs showed significant effects. Post-hoc pairwise comparisons revealed specific group differences with p-values. Interpret findings in context.
- Multivariate test statistic (Pillai's V or Wilks' Λ)
- F-statistic with df1 and df2
- p-values for all effects (main effects and interaction)
- Effect sizes (partial η² or V)
- Box's M test result
- Correlation matrix among DVs
- Follow-up univariate ANOVA results with Bonferroni correction
- Post-hoc pairwise comparisons with adjusted p-values
- Descriptive statistics (M, SD) for all DV × IV combinations
- Statement about assumptions (normality, outliers, homogeneity)
Manuscript Lab
Copy standard summary tables and forensic reporting grids to outline analysis details.
| Effect | Pillai's Trace | F | Hypoth df | Error df | p | ηp² |
|---|---|---|---|---|---|---|
| Diet | .310 | 8.45 | 6 | 286 | < .001 | .15 |
| Exercise | .150 | 12.20 | 3 | 142 | < .001 | .21 |
| Diet × Exercise | .085 | 1.42 | 6 | 286 | .205 | .03 |
The Multivariate Synergy. Tests if the combined effect of Diet and Exercise creates a unique health profile distinct from their additive effects.
The Robust Omnibus. The most conservative and reliable statistic for multivariate effects, especially with small samples or deviations.
Multivariate Effect Size. The proportion of generalized variance in the outcome set explained by the factor.
Command Center
Syntax libraries and function parameters for executing calculations in stats packages.
# 1. Bind Outcomes
Y <- cbind(df$bmi, df$chol, df$bp)
# 2. Execute 2-Way MANOVA
model <- manova(Y ~ diet * exercise, data = df)
summary(model, test = 'Pillai')
# 3. Visualize Multivariate Separation
heplot(model)If the multivariate interaction is non-significant, proceed to 'Descriptive Discriminant Analysis' to see which variable drives the main effects.
# Canonical Discriminant Analysis
candisc::candisc(model, term = 'diet')
# Check Multivariate Homogeneity
biotools::boxM(Y, df$diet)Common Mistakes
Analytical caveats and corrections to maintain modeling integrity.
References
Scholarly lineage and citation keys grounding the statistical framework.