Repeated measurements over time · Choose a method
Glucose tolerance test statistics: total AUC, incremental AUC or the time course?
Decide the question first. For overall glucose handling, compare one area under the curve per mouse with Welch's t-test; if fasting glucose may differ, plan to add the incremental AUC. Skip per-time-point t-tests. R and Python code.
On this page
Quick answer. Decide before the test which question you are asking. “Do the groups handle a glucose load differently overall?” Compute one area under the curve (AUC) per mouse with the trapezoid rule and compare the groups with Welch’s t-test (Welch’s ANOVA for three or more groups). If your groups may differ in fasting glucose (diet, obesity or diabetes models), plan from the start to report the incremental AUC (area above each mouse’s own 0-minute value) next to the total AUC, because the total AUC then mostly repeats the fasting difference. “When do the curves differ?” Analyse the whole time course with a model that knows the measurements come from the same mice (a mixed ANOVA with the Greenhouse–Geisser correction, or a mixed model in which the correlation between readings falls as the time between them grows). If you need comparisons at particular times, name them in advance and take them from that model, with Holm’s adjustment; do not run a separate t-test at every time point and read the stars.
Terms used below. GTT: glucose tolerance test; glucose is measured at set times after a glucose dose. AUC: area under the glucose–time curve, in mmol/L × min. Trapezoid rule: adds up the area between each pair of neighbouring time points, which works with uneven spacing. Total AUC: the whole area under the curve. Incremental AUC: the area after subtracting the mouse’s fasting (0-minute) glucose; parts below fasting count as negative here. Welch’s t-test: compares two means without assuming equal spread. Welch’s ANOVA: the version of one-way ANOVA that does not assume equal spread; Games–Howell is its pairwise follow-up. Mixed ANOVA: one factor between mice (diet) and one within mice (time). AR(1): a correlation pattern in which readings closer in time are more alike. Satterthwaite degrees of freedom: the small-sample adjustment a mixed model uses for its tests. Greenhouse–Geisser correction: lowers the degrees of freedom when the time points are not equally correlated, which is usual for a GTT; ε (epsilon) is the size of that correction, 1 meaning none.
Choose the analysis by the question
| Your question | Analysis | Why |
|---|---|---|
| Overall glucose handling after the load | Total AUC per mouse, then Welch’s t-test | One number per mouse, so n is the number of mice (Matthews et al. 1990) |
| Handling of the load itself, when groups may differ in fasting glucose (planned in advance) | Incremental AUC per mouse, then Welch’s t-test, reported with the time course and fasting glucose | Separates the response to the load from the starting level (Ayala et al. 2010) |
| Whether, and when, the curves diverge | Mixed ANOVA with the Greenhouse–Geisser correction, or a mixed model with AR(1) or unstructured correlation; planned comparisons at a few named times taken from that model (not separate t-tests), with Holm’s adjustment | Uses all time points and the pairing within each mouse |
| Fasting glucose itself | Welch’s t-test on the 0-minute values | A separate outcome; report it alongside either AUC |
Pick one primary analysis and write it in your plan before the experiment. Matthews and colleagues advise that summary measures “ideally … should be chosen before the data are collected. This avoids any temptation to choose a particular summary measure because it shows a maximal difference between groups.” Reporting whichever AUC gives the smaller p-value inflates false positives. A random-intercept mixed model on its own is not enough here: it assumes all six readings are equally correlated, and the guide on repeated measures ANOVA vs mixed model found that a random-intercept model gave 7.3% false positives in that situation.
Matthews and colleagues explain why a t-test at every time point fails: “A commonly used method which compares groups at a series of time points, possibly with t tests, is flawed on both counts” (Matthews et al. 1990). The tests at neighbouring times reuse the same mice, so they are not independent, and six tests at α = 0.05 raise the chance of at least one false positive to about 26% if they were independent. The summary-measure route they recommend is exactly the AUC route above.
Worked example: same mice, three answers
Constructed data: 8 chow and 8 high-fat-diet (HFD) mice, glucose measured at 0, 15, 30, 60, 90 and 120 minutes. In these data the HFD mice start higher, and their rise above fasting is only slightly larger. Stored code and data: gtt.csv, analysis.py, analysis.R and their output. Both languages print the same output; the snippets below are condensed versions of those scripts.
| Outcome | Chow (mean) | HFD (mean) | Difference, HFD − chow (95% CI) | Welch’s t-test |
|---|---|---|---|---|
| Fasting glucose (mmol/L) | 7.6 | 9.2 | 1.6 (1.0 to 2.2) | t = 5.98, df = 11.5, p < 0.001 |
| Total AUC (mmol/L × min) | 1575.4 | 1821.9 | 246.5 (127.4 to 365.6) | t = 4.44, df = 14.0, p < 0.001 |
| Incremental AUC (mmol/L × min) | 665.1 | 719.9 | 54.8 (−43.0 to 152.6) | t = 1.21, df = 13.1, p = 0.248 |
The total AUC difference is large, but most of it is the fasting difference carried across the whole test: total AUC minus incremental AUC is the fasting value × 120 minutes, so 191.7 of the 246.5 units come from fasting glucose alone. Above their own fasting level, the difference between the groups is small and uncertain: the interval for the incremental AUC runs from 43 units lower to 153 units higher (up to about 23% above the chow mean), so a worse response in the HFD group remains possible; a larger study would be needed to settle it. A fair summary is “higher fasting glucose; the response to the load was not clearly different at this sample size”, not “glucose intolerant” and not “normal glucose tolerance”.
The time course is consistent with this. In the mixed ANOVA, the group effect (are the curves at different heights?) is large, F(1, 14) = 20.95, p < 0.001, while the group-by-time interaction (do the curves have different shapes?) gives F(5, 70) = 2.00 with Greenhouse–Geisser ε = 0.45 and a corrected p = 0.147 (uncorrected 0.089): a curve shifted upward, without clear evidence of a different shape. Separate t-tests at each time point are “significant” at all six times, from p = 0.028 at 15 minutes to p < 0.001 at 0 and 120 minutes, because a shifted curve is higher at every time; they restate the fasting difference six times.
import numpy as np, pandas as pd
from scipy import stats
d = pd.read_csv("gtt.csv") # columns: group, mouse, time, glucose
def areas(g):
g = g.sort_values("time")
return pd.Series({"auc": np.trapezoid(g.glucose, g.time),
"iauc": np.trapezoid(g.glucose - g.glucose.iloc[0], g.time)})
per = d.groupby(["group", "mouse"]).apply(areas, include_groups=False).reset_index()
for col in ["auc", "iauc"]:
hfd, chow = per.loc[per.group == "HFD", col], per.loc[per.group == "chow", col]
r = stats.ttest_ind(hfd, chow, equal_var=False) # Welch's t-test
print(col, round(hfd.mean() - chow.mean(), 1), r.confidence_interval(), r)
d <- read.csv("gtt.csv")
trap <- function(t, y) sum(diff(t) * (head(y, -1) + tail(y, -1)) / 2)
per <- do.call(rbind, lapply(split(d, d$mouse), function(g) {
g <- g[order(g$time), ]
data.frame(group = g$group[1], auc = trap(g$time, g$glucose),
iauc = trap(g$time, g$glucose - g$glucose[1]))
}))
t.test(auc ~ factor(group, levels = c("HFD", "chow")), data = per) # Welch by default
t.test(iauc ~ factor(group, levels = c("HFD", "chow")), data = per)
For the time course in R, afex::aov_ez("mouse", "glucose", d, between = "group", within = "time") prints the Greenhouse–Geisser-corrected p in its summary(); in Python, pingouin.mixed_anova(..., correction=True) reports p_GG_corr (full calls in analysis.py and analysis.R). For a mixed model whose correlation falls with the time between readings, nlme::gls(glucose ~ group * factor(time), data = d, correlation = corCAR1(form = ~ time | mouse)) handles uneven spacing; here its group × time test gives p = 0.44 (gls_check.R, output). If your sheet has one row per mouse and one column per time, reshape it to one row per reading first: d.melt(id_vars=["group", "mouse"], var_name="time", value_name="glucose") in pandas, or tidyr::pivot_longer() in R.
Before you compute an area
- One AUC per mouse, then the test. Averaging the group’s curve and computing one area per group leaves nothing to test; the mouse is the unit (what counts as n).
- Use the actual times. Sampling at 0, 15, 30, 60, 90 and 120 minutes is uneven; the trapezoid rule over the real times weights each interval correctly, whereas summing the readings does not.
- Say which AUC. Write “total” or “incremental (above each mouse’s 0-minute value)”, and whether areas below baseline were counted as negative (as here) or set to zero; these give different numbers.
- Keep the time course in the figure. Ayala and colleagues recommend that when fasting glucose differs, “a time course of absolute glucose levels should still be presented along with a calculation of the area under the curve above baseline glucose” (Ayala et al. 2010).
- Check the dose. Dosing glucose per gram of body weight gives obese mice more glucose for the same lean mass. In one study, obese mice had a 75% higher AUC than lean mice when dosed by lean mass and 87% when dosed by body weight (Jørgensen et al. 2017); the authors recommend dosing by lean mass. State the dosing basis in the Methods.
- Mice that miss a reading. If a reading’s row is absent, the trapezoid code above silently bridges the gap, and if the 0-minute row is absent, it uses the next reading as the baseline, which is wrong; if the cell is blank instead, that mouse’s AUC becomes NaN (NA in R) and drops out of the test. Decide in advance what you will do (for example, exclude a mouse missing the 0-minute or the peak reading from the AUC analysis), and report it. A mixed ANOVA drops that mouse entirely; a mixed model keeps its other readings, which is valid when the reading is missing for a reason unrelated to its value (a failed measurement, a lost sample) but not when, for example, a sick mouse missed the late readings.
Insulin tolerance tests
The same choices apply to an insulin tolerance test, where glucose falls instead of rising, so the incremental AUC is negative. Expressing glucose as a percentage of each mouse’s 0-minute value is common, but Ayala and colleagues note that this “is a valid means of presenting results if the groups being compared have equivalent fasting glucose levels”; when fasting glucose differs, a smaller relative fall can be misread as insulin resistance. Show absolute glucose as well. Whichever you choose, decide it before the experiment, compute one summary per mouse, name it in the Methods and compare with Welch’s t-test.
Check what an AI assistant ran
If an assistant analysed your GTT, look for these in its code:
- A t-test per time point reported as the main result. Replace it with the AUC route or a mixed ANOVA.
- The AUC computed on the group mean curve instead of per mouse. Recompute per mouse.
np.trapezoid(y)ortrapz(y)without the time values, which assumes equal spacing. Pass the times.- Student’s t-test (
equal_var=True,var.equal = TRUE). Use Welch’s. - An uncorrected repeated-measures p-value. For a mixed ANOVA, report the Greenhouse–Geisser-corrected p. For a mixed model, check that it is not a random intercept only, and report the p-value it gives with its degrees of freedom (Satterthwaite for
lmerTest; residual df fornlme::gls). - Welch’s df. Welch’s degrees of freedom are usually not whole numbers; an exact df of n₁ + n₂ − 2 often means Student’s t-test was run, although Welch’s df can come close when the spreads happen to be equal (14.0 for the total AUC above, with
equal_var=False). - A two-way ANOVA without the mouse. An ordinary two-way ANOVA of group × time treats 96 readings as 96 mice. Use the mixed ANOVA, which knows which readings belong to one mouse.
Report it
Methods:
Glucose tolerance was summarised as the area under the glucose–time curve for each mouse (trapezoid rule over the sampling times, 0–120 minutes), [total / incremental above each mouse’s 0-minute value, with areas below baseline counted as negative]. Groups were compared with Welch’s t-test (n = [8] mice per group); this was the pre-specified primary analysis. Glucose was dosed at [2] g/kg [lean mass / body weight]. Fasting glucose was compared separately. The time course was analysed with a mixed ANOVA ([group/diet] between mice, time within mice) with the Greenhouse–Geisser correction (afex [1.3-1] in R [4.3.3]) [or: a generalised least squares model with continuous-time AR(1) correlation between readings (nlme [3.1-164]), with planned comparisons at [named times] taken from the model and adjusted by Holm’s method].
Results:
The HFD group had higher fasting glucose than the chow group (difference 1.6 mmol/L, 95% CI 1.0 to 2.2) and a larger total AUC (difference 246.5 mmol/L × min, 95% CI 127.4 to 365.6), but the incremental AUC did not differ clearly (difference 54.8, 95% CI −43.0 to 152.6; Welch’s t = 1.21, df = 13.1, p = 0.248).
References
- Matthews JNS, Altman DG, Campbell MJ, Royston P (1990). Analysis of serial measurements in medical research. BMJ 300:230–235. doi:10.1136/bmj.300.6719.230
- Ayala JE, Samuel VT, Morton GJ, et al. (2010). Standard operating procedures for describing and performing metabolic tests of glucose homeostasis in mice. Disease Models & Mechanisms 3:525–534. doi:10.1242/dmm.006239
- Jørgensen MS, Tornqvist KS, Hvid H (2017). Calculation of glucose dose for intraperitoneal glucose tolerance tests in lean and obese mice. Journal of the American Association for Laboratory Animal Science 56:95–97. PMC5250502
- afex 1.3-1, Analysis of Factorial Experiments:
aov_ezdocumentation. CRAN - pingouin 0.7.0,
mixed_anovadocumentation. pingouin-stats.org
How this page was made
- Written and published by Licklider. Recommendations cite peer-reviewed methods papers and official software documentation listed under References; cited passages were checked against the source text.
- The worked example uses constructed data. Its numbers were produced by stored code (Python 3.13 with SciPy 1.18.1, pandas 3.0.5 and pingouin 0.7.0; R 4.3.3 with afex 1.3-1), and the two languages print identical output.
- Separate review passes checked the statistics, the citations and readability before publication.