Analyze the effect of two independent factors and their interaction.
0.01 (1%)
0.05 (5%)
0.10 (10%)
2
3
4
Enter numerical data separated by commas, spaces, or new lines.
Factor B (Level 1)
Factor B (Level 2)
Factor A (Level 1)
Factor A (Level 2)
ANOVA Summary Table
Source of Variation
Sum of Squares (SS)
Degrees of Freedom (df)
Mean Square (MS)
F-Statistic
P-Value
Understanding the Two-Way ANOVA Calculator
This 2-Way ANOVA (Analysis of Variance) calculator is designed for statistical analysis of a 2×2 factorial design. It helps researchers and students determine if there is a statistically significant difference between the means of two independent factors (Factor A and Factor B) and if there is an interaction effect between them.
What is Two-Way ANOVA?
A Two-Way ANOVA is an extension of the One-Way ANOVA that examines the influence of two different categorical independent variables on one continuous dependent variable. The "2-way" aspect calculates three distinct effects:
Main Effect of Factor A: Does the first factor (rows) significantly affect the outcome?
Main Effect of Factor B: Does the second factor (columns) significantly affect the outcome?
Interaction Effect (A × B): Does the effect of one factor depend on the level of the other factor?
How to Use This Calculator
Select Significance Level (α): Choose your alpha (usually 0.05), which sets the threshold for statistical significance.
Enter Data: Input your raw data points into the four quadrants corresponding to the combinations of Factor A and Factor B levels. Separate numbers using commas, spaces, or new lines.
Requirement: For the most accurate standard calculation, this tool assumes a balanced design, meaning the number of replicates (data points) in each cell should be equal.
Interpreting the Results
The output table displays the standard ANOVA components:
SS (Sum of Squares): Represents the total variation attributed to each source.
df (Degrees of Freedom): Calculated based on the number of levels and total sample size.
MS (Mean Square): The SS divided by the df. This represents the variance estimates.
F-Statistic: The ratio of the factor MS to the Error MS. A higher F-value indicates a stronger effect.
P-Value: The probability that the observed results occurred by chance. If P < α, the effect is statistically significant.
Formulae Used
The calculations follow the standard partitioning of variance:
The F-statistic is calculated as F = MSSource / MSError.
// Utility: Gamma function for P-value calculation (Lanczos approximation)
var logGamma = function(z) {
var c = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];
var x = z;
var y = z;
var tmp = x + 5.5;
tmp -= (x + 0.5) * Math.log(tmp);
var ser = 1.000000000190015;
for (var j = 0; j < 6; j++) ser += c[j] / ++y;
return -tmp + Math.log(2.5066282746310005 * ser / x);
};
// Utility: Regularized Incomplete Beta Function (for F-distribution CDF)
var betainc = function(x, a, b) {
var bt = (x === 0 || x === 1) ? 0 : Math.exp(logGamma(a + b) – logGamma(a) – logGamma(b) + a * Math.log(x) + b * Math.log(1 – x));
if (x < (a + 1) / (a + b + 2)) {
return bt * betacf(x, a, b) / a;
} else {
return 1 – bt * betacf(1 – x, b, a) / b;
}
};
// Utility: Continued Fraction for Beta
var betacf = function(x, a, b) {
var fpmin = 1e-30;
var m2 = 0;
var aa = 0;
var del = 0;
var h = 1 – a * (a + b) * x / (a + 1);
if (Math.abs(h) < fpmin) h = fpmin;
var c = 1 / fpmin;
var d = 1 / h;
h = d;
var qab = a + b;
var qap = a + 1;
var qam = a – 1;
for (var m = 1; m <= 100; m++) {
m2 = 2 * m;
aa = m * (b – m) * x / ((qam + m2) * (a + m2));
d = 1 + aa * d;
if (Math.abs(d) < fpmin) d = fpmin;
c = 1 + aa / c;
if (Math.abs(c) < fpmin) c = fpmin;
d = 1 / d;
h *= d * c;
aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
d = 1 + aa * d;
if (Math.abs(d) < fpmin) d = fpmin;
c = 1 + aa / c;
if (Math.abs(c) < fpmin) c = fpmin;
d = 1 / d;
del = d * c;
h *= del;
if (Math.abs(del – 1.0) < 3e-7) break;
}
return h;
};
// Utility: Calculate P-value from F, df1, df2
var calculatePValue = function(f, df1, df2) {
if (f <= 0) return 1.0;
var x = df2 / (df2 + df1 * f);
return betainc(x, df2 / 2, df1 / 2);
};
// Main Calculator Logic
function calculateAnova() {
var errorDiv = document.getElementById('error-msg');
var resultSection = document.getElementById('result-section');
var anovaBody = document.getElementById('anova-body');
var conclusionText = document.getElementById('conclusion-text');
errorDiv.style.display = 'none';
errorDiv.innerHTML = '';
resultSection.style.display = 'none';
// 1. Get Inputs
var raw_a1b1 = document.getElementById('cell_a1b1').value;
var raw_a1b2 = document.getElementById('cell_a1b2').value;
var raw_a2b1 = document.getElementById('cell_a2b1').value;
var raw_a2b2 = document.getElementById('cell_a2b2').value;
// 2. Parse Data
var parseData = function(str) {
return str.split(/[\s,]+/).filter(function(n) { return n !== '' && !isNaN(n); }).map(Number);
};
var d_a1b1 = parseData(raw_a1b1);
var d_a1b2 = parseData(raw_a1b2);
var d_a2b1 = parseData(raw_a2b1);
var d_a2b2 = parseData(raw_a2b2);
// 3. Validate
if (d_a1b1.length === 0 || d_a1b2.length === 0 || d_a2b1.length === 0 || d_a2b2.length === 0) {
errorDiv.style.display = 'block';
errorDiv.innerHTML = "Please enter valid numerical data in all four fields.";
return;
}
// Check for balanced design (recommended for simple 2-way)
var n = d_a1b1.length;
if (d_a1b2.length !== n || d_a2b1.length !== n || d_a2b2.length !== n) {
errorDiv.style.display = 'block';
errorDiv.innerHTML = "Warning: Unbalanced design detected (unequal sample sizes).This calculator uses standard formulas which assume equal sample sizes (Balanced Design) for interaction calculation accuracy. Results may be approximate.";
}
// 4. Calculations
var sum = function(arr) { return arr.reduce(function(a, b) { return a + b; }, 0); };
var sumSq = function(arr) { return arr.reduce(function(a, b) { return a + (b * b); }, 0); };
// Group Sums and Counts
var s_a1b1 = sum(d_a1b1), n_a1b1 = d_a1b1.length;
var s_a1b2 = sum(d_a1b2), n_a1b2 = d_a1b2.length;
var s_a2b1 = sum(d_a2b1), n_a2b1 = d_a2b1.length;
var s_a2b2 = sum(d_a2b2), n_a2b2 = d_a2b2.length;
// Total
var allData = [].concat(d_a1b1, d_a1b2, d_a2b1, d_a2b2);
var N_total = allData.length;
var GrandTotal = sum(allData);
var CF = (GrandTotal * GrandTotal) / N_total;
var SS_Total = sumSq(allData) – CF;
// Factor A (Rows) Calculations
var Row1Total = s_a1b1 + s_a1b2;
var Row2Total = s_a2b1 + s_a2b2;
var n_row1 = n_a1b1 + n_a1b2;
var n_row2 = n_a2b1 + n_a2b2;
var SS_A = ((Row1Total * Row1Total) / n_row1 + (Row2Total * Row2Total) / n_row2) – CF;
// Factor B (Cols) Calculations
var Col1Total = s_a1b1 + s_a2b1;
var Col2Total = s_a1b2 + s_a2b2;
var n_col1 = n_a1b1 + n_a2b1;
var n_col2 = n_a1b2 + n_a2b2;
var SS_B = ((Col1Total * Col1Total) / n_col1 + (Col2Total * Col2Total) / n_col2) – CF;
// Subtotal (Cells)
var SS_Cells = ((s_a1b1*s_a1b1)/n_a1b1 + (s_a1b2*s_a1b2)/n_a1b2 + (s_a2b1*s_a2b1)/n_a2b1 + (s_a2b2*s_a2b2)/n_a2b2) – CF;
// Interaction (AxB)
var SS_AxB = SS_Cells – SS_A – SS_B;
// Error (Within)
var SS_Error = SS_Total – SS_Cells;
// Degrees of Freedom
var a_levels = 2; // Fixed 2×2
var b_levels = 2;
var df_A = a_levels – 1;
var df_B = b_levels – 1;
var df_AxB = df_A * df_B;
var df_Total = N_total – 1;
var df_Error = df_Total – df_A – df_B – df_AxB;
// Mean Squares
var MS_A = SS_A / df_A;
var MS_B = SS_B / df_B;
var MS_AxB = SS_AxB / df_AxB;
var MS_Error = SS_Error / df_Error;
// F-Statistics
var F_A = MS_A / MS_Error;
var F_B = MS_B / MS_Error;
var F_AxB = MS_AxB / MS_Error;
// P-Values
var P_A = calculatePValue(F_A, df_A, df_Error);
var P_B = calculatePValue(F_B, df_B, df_Error);
var P_AxB = calculatePValue(F_AxB, df_AxB, df_Error);
// Formatting
var decimals = parseInt(document.getElementById('rounding').value);
var alpha = parseFloat(document.getElementById('alphaLevel').value);
var fmt = function(num) { return num.toFixed(decimals); };
var fmtP = function(p) { return p < 0.0001 ? "< 0.0001" : p.toFixed(decimals); };
var checkSig = function(p) {
return p < alpha ? 'Yes' : 'No';
};
// Render Table
var html = ";
// Row A
html += '
';
html += '
Factor A (Rows)
';
html += '
' + fmt(SS_A) + '
';
html += '
' + df_A + '
';
html += '
' + fmt(MS_A) + '
';
html += '
' + fmt(F_A) + '
';
html += '
' + fmtP(P_A) + ' (' + checkSig(P_A) + ')
';
html += '
';
// Row B
html += '
';
html += '
Factor B (Columns)
';
html += '
' + fmt(SS_B) + '
';
html += '
' + df_B + '
';
html += '
' + fmt(MS_B) + '
';
html += '
' + fmt(F_B) + '
';
html += '
' + fmtP(P_B) + ' (' + checkSig(P_B) + ')
';
html += '
';
// Interaction
html += '
';
html += '
Interaction (A × B)
';
html += '
' + fmt(SS_AxB) + '
';
html += '
' + df_AxB + '
';
html += '
' + fmt(MS_AxB) + '
';
html += '
' + fmt(F_AxB) + '
';
html += '
' + fmtP(P_AxB) + ' (' + checkSig(P_AxB) + ')
';
html += '
';
// Error
html += '
';
html += '
Error (Within)
';
html += '
' + fmt(SS_Error) + '
';
html += '
' + df_Error + '
';
html += '
' + fmt(MS_Error) + '
';
html += '
–
';
html += '
–
';
html += '
';
// Total
html += '
';
html += '
Total
';
html += '
' + fmt(SS_Total) + '
';
html += '
' + df_Total + '
';
html += '
–
';
html += '
–
';
html += '
–
';
html += '
';
anovaBody.innerHTML = html;
// Conclusion Text
var txt = "
Interpretation:
";
txt += "
";
txt += "
Factor A: The effect is " + (P_A < alpha ? "statistically significant" : "not significant") + ".
";
txt += "
Factor B: The effect is " + (P_B < alpha ? "statistically significant" : "not significant") + ".
";
txt += "
Interaction: The interaction effect is " + (P_AxB < alpha ? "statistically significant" : "not significant") + ".