Answer
Where does a curve level off? Estimating a plateau point
The short answer
A smooth curve has no single point where it starts to plateau, so you have to define one, and polynomials are the wrong tool for it. Fit a model with a built-in plateau instead: an asymptotic exponential, where the onset can be defined as the point by which 95% of the total drop is complete, or a linear-plateau (broken-stick) model with an estimated breakpoint. Both give the onset as a parameter with a standard error, not a judgement call.
The short answer
A common situation: a measure falls steeply at first and then levels off, and the research question is about where that levelling-off begins. The difficulty is that a smooth curve that approaches a floor never actually becomes flat. Its slope keeps shrinking but never reaches zero, so there is no natural point to find. You have to choose a definition of the onset, and then estimate it with a model that contains that definition as a parameter.
- Asymptotic exponential model. The curve approaches a floor (the asymptote) at a constant proportional rate. Define the onset as the point by which, say, 95% of the total drop has happened. This is a smooth, gradual definition.
- Linear-plateau (broken-stick) model. The curve falls in a straight line and then stays flat after a breakpoint, which the model estimates. This is a sharp definition and suits processes that really do switch off.
- Either way, report an interval. The onset is an estimate, and it is usually much less precise than people expect.
Why polynomial fits cannot answer this
Quadratic and cubic fits are tempting because they are easy, but they have no plateau in them. A quadratic has exactly one flat point, its vertex, and that is where it stops falling and starts rising again. If the data level off, the quadratic still curves back upward beyond the vertex, and the vertex location depends mainly on how far the x-axis happens to extend. A cubic can bend more, but its flat stretches are just as much a by-product of the polynomial form. Searching a polynomial for the place where the slope is nearly zero picks up these artefacts rather than a feature of the data.
A fixed slope threshold ("flat once the slope is below 0.01") has a second problem: the number depends on the units of both axes, so the same threshold means different things for different outcomes or time scales. A relative definition, such as the share of the total drop that is complete, is free of units and comparable across curves.
See it in R and Python
The code simulates 40 points from a curve that starts near 0.9 and falls towards a floor of 0.3, with a true 95%-of-the-drop point of 3.74. It then fits a quadratic, an asymptotic exponential with base R's self-starting SSasymp() model, and a broken-stick model found by trying every breakpoint on a fine grid. The asymptotic model is y = Asym + (R0 - Asym) * exp(-k * x), with k = exp(lrc). The remaining gap to the floor shrinks by the factor exp(-k * x), so 95% of the drop is done when that factor reaches 0.05, at x = log(20) / k. Its 95% interval is computed on the log scale, where the estimate is a simple shift of lrc.
R
set.seed(677612)
x <- seq(0, 10, length.out = 40)
y <- 0.3 + 0.6 * exp(-0.8 * x) + rnorm(40, sd = 0.04) # true curve levels off at 0.3
# True point where 95% of the drop is done: log(20) / 0.8
round(log(20) / 0.8, 2)
# 1. Quadratic: its "flat point" is the vertex, where it turns back up
quad <- lm(y ~ x + I(x^2))
b <- coef(quad)
round(c(vertex = unname(-b[2] / (2 * b[3]))), 2)
# 2. Asymptotic exponential: y = Asym + (R0 - Asym) * exp(-exp(lrc) * x)
fit <- nls(y ~ SSasymp(x, Asym, R0, lrc))
est <- coef(fit); se <- sqrt(diag(vcov(fit)))
round(cbind(estimate = est, se = se), 3)
k <- exp(est["lrc"])
x95 <- log(20) / k # 95% of the drop completed
ci95 <- exp(log(log(20)) - est["lrc"] + c(-1.96, 1.96) * se["lrc"])
round(c(k = unname(k), x95 = unname(x95), lower = ci95[1], upper = ci95[2]), 2)
# 3. Linear-plateau ("broken stick"): straight decline, then flat after c
grid <- seq(0.5, 9.5, by = 0.01)
rss <- sapply(grid, function(cc) deviance(lm(y ~ pmin(x, cc))))
c_hat <- grid[which.min(rss)]
round(c(breakpoint = c_hat), 2)
# Compare fits by residual standard error
round(c(quadratic = sigma(quad), asymptotic = sigma(fit),
broken_stick = sqrt(min(rss) / (40 - 3))), 4)Python
import numpy as np
from scipy.optimize import curve_fit
rng = np.random.default_rng(677612)
x = np.linspace(0, 10, 40)
y = 0.3 + 0.6 * np.exp(-0.8 * x) + rng.normal(0, 0.04, 40) # true curve levels off at 0.3
print("true x95:", round(np.log(20) / 0.8, 2))
# 1. Quadratic: its "flat point" is the vertex, where it turns back up
b2, b1, b0 = np.polyfit(x, y, 2)
print("vertex:", round(-b1 / (2 * b2), 2))
quad_rss = np.sum((y - np.polyval([b2, b1, b0], x)) ** 2)
# 2. Asymptotic exponential: y = Asym + (R0 - Asym) * exp(-exp(lrc) * x)
def asymp(x, Asym, R0, lrc):
return Asym + (R0 - Asym) * np.exp(-np.exp(lrc) * x)
est, cov = curve_fit(asymp, x, y, p0=[y[-5:].mean(), y[0], np.log(0.5)])
se = np.sqrt(np.diag(cov))
for name, e, s in zip(["Asym", "R0", "lrc"], est, se):
print(f"{name:5s} {e:7.3f} {s:6.3f}")
x95 = np.log(20) / np.exp(est[2]) # 95% of the drop completed
ci95 = np.exp(np.log(np.log(20)) - est[2] + np.array([-1.96, 1.96]) * se[2])
print("k:", round(np.exp(est[2]), 3), "x95:", round(x95, 2), "95% CI:", ci95.round(2))
asym_rss = np.sum((y - asymp(x, *est)) ** 2)
# 3. Linear-plateau ("broken stick"): straight decline, then flat after c
grid = np.round(np.arange(0.5, 9.5 + 1e-9, 0.01), 2)
def rss_at(c):
X = np.column_stack([np.ones_like(x), np.minimum(x, c)])
beta = np.linalg.lstsq(X, y, rcond=None)[0]
return np.sum((y - X @ beta) ** 2)
rss = np.array([rss_at(c) for c in grid])
print("breakpoint:", grid[rss.argmin()])
# Compare fits by residual standard error
print("RSE quadratic, asymptotic, broken stick:",
np.round(np.sqrt(np.array([quad_rss, asym_rss, rss.min()]) / (40 - 3)), 4))[1] 3.74
vertex
6.88
estimate se
Asym 0.287 0.011
R0 0.831 0.031
lrc -0.431 0.112
k x95 lower upper
0.65 4.61 3.70 5.74
breakpoint
2.94
quadratic asymptotic broken_stick
0.0564 0.0435 0.0535
All figures come from one seeded run of the R code. Python's random numbers differ from R's, so its estimates differ slightly (95% point 4.18, 95% CI [3.49, 5.02]; breakpoint 2.68; vertex 6.93), but they show the same pattern, including the asymptotic model having the smallest residual standard error.
Reading the results
- The quadratic's vertex (6.88) is not a plateau onset. It sits far to the right of where the curve really flattens, and it marks the point where the fitted parabola begins to climb again, which the true curve never does. The quadratic also fits worst (residual standard error 0.0564).
- The asymptotic model fits best (0.0435) and recovers the floor well: 0.287 against a true 0.3. Its estimated 95% point is 4.61, with a 95% confidence interval of [3.70, 5.74]. That interval contains the true value of 3.74, and its width is a useful warning: with 40 noisy points, the onset is pinned down only to within a couple of units of x.
- The broken-stick breakpoint (2.94) answers a different question. It is where the best straight-line decline meets the best flat line. For a smooth curve that point comes earlier than the 95% point, because the straight line has to cut across the bend. Neither number is wrong; they are different definitions, and the paper should state which one it uses.
The choice of 95% is itself a convention. Using 90% gives log(10) / k, and 99% gives log(100) / k. For the exponential model there is a neat link to the slope-threshold idea: the slope also shrinks by the factor exp(-k * x), so the 95%-of-the-drop point is exactly where the slope has fallen to 5% of its starting value. That turns the vague idea of a nearly flat slope into a relative, unit-free rule.
Practical tips
- Pick the model from what you know about the process. A gradual approach to a floor suggests the asymptotic model; a mechanism that genuinely stops (a saturation point, a policy change) suggests the broken-stick model. Comparing residual standard errors or AIC, as in the example, tells you which shape the data support.
- Mind the scale of the x-axis. If time is on a log scale, the onset is estimated on that scale. Back-transform the estimate and its interval limits to report the onset in real time units, and note that the interval will no longer be symmetric.
- Broken-stick intervals need care. The fit changes in a non-smooth way as the breakpoint moves, so the usual standard errors are only approximate. The
segmentedpackage on CRAN estimates breakpoints with standard errors and has tests for whether a breakpoint exists at all; a bootstrap is a good check. - Many curves at once. If you have hundreds of curves (one per person, site or condition), fitting each separately gives noisy onsets. A nonlinear mixed-effects model, for example
nlme()from the recommendednlmepackage with the sameSSasymp()formula, estimates an average onset and how much it varies between curves, borrowing strength across them. - Do not extrapolate the plateau. A model fitted to the observed range says nothing certain about what happens beyond the last data point.
For background on fitting and checking regression models, see the DASS blog, and Wikipedia's articles on nonlinear regression and segmented regression.
How to report a nonlinear regression in APA style (7th edition)
In the method section, give the model, the fitting method and your definition of the onset: "We fitted an asymptotic exponential model, y = Asym + (R0 − Asym)exp(−kx), by nonlinear least squares. The onset of the plateau was defined as the value of x by which 95% of the total decline was complete, log(20)/k, with a Wald 95% confidence interval computed on the log scale."
In the results, using the figures from the example: "The outcome declined from 0.831 (SE = 0.031) towards an asymptote of 0.287 (SE = 0.011), with rate constant k = 0.65. Ninety-five percent of the decline was complete by x = 4.61, 95% CI [3.70, 5.74]. The model fitted better than a quadratic (residual standard errors 0.0435 and 0.0564)." With many curves, put the parameter estimates in a table and state the onset definition in a table note.
Related tools and guides
- APA 7 formatter for regression
- Which statistical test should I use?
- Nonlinear regression (Wikipedia)
- Segmented regression (Wikipedia)
- segmented package (CRAN)
More answered questions
- Which interaction terms belong in a regression or mixed model?
- Is stepwise regression a good way to choose predictors?
- Bagging, boosting and stacking: how do these ensemble methods differ?
Working with your own data?
General answers only go so far. Send us your situation and we'll reply by email within two business days.
Ask your questionWritten by AskStats with AI assistance. This is general information, not advice for your specific data or study. When the results matter, check your approach with a qualified statistician.