Correlation, regression and survival · Choose a method

Saturation binding: Kd and Bmax by nonlinear regression, nonspecific binding and comparing conditions

Fit specific binding (total minus nonspecific) with a one-site model by nonlinear regression in each experiment, check ligand depletion, and compare Kd as pKd and Bmax as a ratio across independent experiments. Python and R code.

By Licklider · Published · Last reviewed · How this page was made · Markdown

On this page
  1. Which analysis for your question
  2. Worked example: a treatment that removes receptors
  3. Before you analyse
  4. Check what an AI assistant ran
  5. Report it
  6. References

Quick answer. In a saturation binding experiment, subtract nonspecific binding from total binding at each radioligand concentration (or fit both together), then fit specific binding = Bmax × [L] / (Kd + [L]) by nonlinear regression (GraphPad notes that it is “better to globally fit total and nonspecific binding, without subtracting”; subtracting is simpler and used here); use a Scatchard plot only to display data. Use concentrations from about 0.1 to 10 × Kd and keep bound ligand below 10% of added ligand (or fit a model that accounts for depletion). To compare conditions, fit each condition in each independent experiment and compare pKd (−log10 Kd) and log Bmax across experiments: paired by experiment when the conditions were assayed side by side, otherwise with Welch’s t-test. A global fit that shares one Kd across experiments called an unchanged Kd “different” in 13.0% of our simulated studies, and one ratio per experiment did so in 4.5%.

Terms used below. Radioligand: a labelled ligand whose binding is measured. [L]: the free radioligand concentration (close to the added concentration when depletion is small). Total binding: binding with radioligand alone. Nonspecific binding (NSB): binding that remains in the presence of excess unlabelled competitor, rising roughly in proportion to [L]. Specific binding: total minus nonspecific (here, each total well minus the mean nonspecific binding at the same concentration in the same experiment). Kd: the concentration that occupies half the receptors (affinity; lower means tighter). pKd: −log10 of Kd in mol/L; 1 nM is pKd 9. Bmax: the total number of binding sites, usually in fmol/mg protein. Ligand depletion: so much ligand is bound that the free concentration falls below the added concentration. One-site model: specific binding = Bmax × [L] / (Kd + [L]), one class of binding sites. Geometric mean: the back-transformed mean of the logs. Ki, pKi: the affinity of an unlabelled competitor, and −log10 Ki. Extra-sum-of-squares F-test: compares a fit with a shared parameter against one with separate parameters. Nonlinear regression: fitting the curve itself by least squares, without transforming the data. Welch’s t-test: compares two groups without assuming equal spreads. Scatchard plot: bound/free against bound, a straight-line transformation of the binding curve. Global fit: one model fitted to several data sets with some parameters shared. Independent experiment: a separate membrane preparation assayed on its own occasion. 95% confidence interval (CI): the range of values compatible with the data. Power: the chance of detecting an effect that is really there. False positive: a “significant” result when there is no real effect.

Which analysis for your question

Question Analysis Report
What are Kd and Bmax? Specific binding (or total and NSB fitted together), one-site model by nonlinear regression, in each experiment Geometric mean Kd (mean pKd ± SD) and geometric mean Bmax, n experiments
Does a treatment or mutation change Kd or Bmax? One log ratio per experiment for each parameter, paired t-test across experiments; Welch’s t-test on log values if conditions were not assayed side by side Ratio with 95% CI, n experiments (at least 3, preferably 5 or more)
A single experiment with two conditions The extra-sum-of-squares F-test (shared vs separate Kd) describes that experiment only; repeat before claiming a difference Both Kd values with CIs, labelled as one experiment
Does a drug bind with different affinity to two receptors? Competition binding (Ki), compared as pKi per experiment (comparing IC50 values) pKi difference with 95% CI
Is there more than one binding site? Compare one-site and two-site fits in each experiment; claim two sites only if it repeats Both fits and the comparison

GraphPad’s guide warns: “Don’t use the slope and intercept of a linear regression line to determine values for Bmax and Kd … The problem is that the transformation distorts the experimental error” (GraphPad). The NIH Assay Guidance Manual says saturation experiments should be run “at <10% total ligand binding at all concentrations tested (0.1 x Kd to 10 x Kd)”, that “ideally, nonspecific binding should be less than 50% of the total binding”, and that bound radioligand should stay below “10% of the total amount added to avoid ligand depletion” (Auld et al. 2012). Hulme and Trevethick explain that “pKd is normally distributed, but Kd is not”, so analyses should produce “estimates of pKd and their associated errors” (Hulme & Trevethick 2010).

Worked example: a treatment that removes receptors

Constructed data: total and nonspecific binding (fmol/mg protein) at 8 radioligand concentrations (0.1 to 10 nM; true Kd 1 nM), triplicate wells, in control and treated membranes prepared side by side in each of 5 independent experiments. By design, treatment lowers Bmax by 30% and leaves Kd unchanged; Kd varies between days and preparations (standard deviations of 0.10 and 0.08 on the log scale), Bmax between preparations (0.10), and wells scatter by about 6%; the 13.0% figure below depends on this preparation-to-preparation variation in Kd. The random seed was the first one tried and was not chosen for its result. Stored code and data: binding.csv, model.py, make_data.py, analysis.py, analysis.R and the analysis output; analysis.py and analysis.R print the same output.

Experiment Control Bmax (fmol/mg) Control Kd (nM) Treated Bmax Treated Kd
1 443 1.08 329 1.07
2 525 1.15 429 1.09
3 614 0.93 352 0.92
4 573 1.36 315 1.09
5 540 0.89 330 1.07
Comparison, treated ÷ control (one ratio per experiment, paired, n = 5) Result
Bmax 0.65 (95% CI 0.53 to 0.81), p = 0.005
Kd 0.98 (95% CI 0.82 to 1.17), p = 0.76
Control Kd across experiments geometric mean 1.07 nM (pKd 8.97 ± 0.07)
Global fit of all 240 wells, Kd shared within each condition Kd ratio 1.00, F(1, 228) = 0.00, p = 0.95

The treatment reduced the number of receptors without changing their affinity, and both conclusions come with intervals from 5 experiments. In this data set the global fit happened to agree, but in 2,000 simulated studies of this design (simulation.py, the simulation output):

Scenario Bmax, one ratio per experiment, p < 0.05 Kd, one ratio per experiment Kd, global fit pooling wells
Bmax 30% lower, Kd unchanged 97.0% (power) 4.5% (false positives) 13.0% (false positives)
Kd 1.5 times higher, Bmax unchanged 4.5% (false positives) 98.4% (power) 100.0%

The global fit treats 240 wells as independent evidence about Kd, while Kd varies between membrane preparations; one ratio per experiment keeps false positives near 5% and, with 5 experiments, detects a 1.5-fold change in Kd almost every time.

The code expects one row per well with columns experiment, condition (control or treated), ligand_nM, well, total and nonspecific binding (fmol/mg protein); rename your columns and labels to match, and run the code in the folder that holds the CSV file. Python needs NumPy, pandas and SciPy; the R code uses base R only.

# Condensed: analysis.py also gives the Scatchard estimates and the global fit
import numpy as np, pandas as pd
from scipy import stats
from scipy.optimize import curve_fit

d = pd.read_csv("binding.csv")
d["specific"] = d.total - d.groupby(["experiment", "condition", "ligand_nM"]).nonspecific.transform("mean")
one_site = lambda l, bmax, kd: bmax * l / (kd + l)
fits = d.groupby(["experiment", "condition"]).apply(lambda x: pd.Series(curve_fit(one_site, x.ligand_nM, x.specific, p0=[x.specific.max(), x.ligand_nM.median()])[0], index=["bmax", "kd"]))
for p in ("bmax", "kd"):
    r = np.log(fits[p].unstack()["treated"] / fits[p].unstack()["control"])         # one log ratio per experiment
    t = stats.ttest_1samp(r, 0); print(p, np.exp(r.mean()), np.exp(t.confidence_interval()), t.pvalue)
d <- read.csv("binding.csv")
d$specific <- d$total - ave(d$nonspecific, d$experiment, d$condition, d$ligand_nM, FUN = mean)
fit <- function(x) coef(nls(specific ~ bmax * ligand_nM / (kd + ligand_nM), data = x, start = list(bmax = max(x$specific), kd = median(x$ligand_nM))))
f <- t(sapply(split(d, list(d$condition, d$experiment)), fit))                     # rows: control.1, treated.1, ...
for (p in c("bmax", "kd")) { r <- log(f[grep("^treated", rownames(f)), p] / f[grep("^control", rownames(f)), p])
  tt <- t.test(r); print(c(ratio = exp(mean(r)), exp(tt$conf.int), p = tt$p.value)) }    # one log ratio per experiment

Before you analyse

  1. Choose the concentration range from about 0.1 to 10 × the expected Kd, with enough points below Kd; a pilot with wide spacing helps if Kd is unknown.
  2. Check ligand depletion: convert bound and added radioligand to the same units (fmol per well, from counts, specific activity, volume and protein per well) and compute bound ÷ added × 100 at the lowest concentrations; the example data are already in fmol/mg, so this check needs your raw counts; above 10%, the free concentration is lower than added and Kd is overestimated unless you fit a model that accounts for depletion.
  3. Measure nonspecific binding at every concentration in separate wells with an excess of unlabelled competitor (commonly about 100 times its Kd or Ki), subtract the mean nonspecific binding at each concentration from each total well, and check that it stays well below total binding near Kd (below half of total binding, ideally much less).
  4. Look at every fit: plot each experiment’s points with its curve, and decide in advance what counts as a failed fit (for example a Kd above the highest concentration tested). The unweighted fit assumes similar scatter at every concentration; if scatter grows with binding, weight the fit or fit on the log scale (the example’s 6% proportional scatter is small enough that the unweighted fit is used).
  5. Normalise Bmax to protein (or cells) per well or preparation, and count independent preparations, not wells, as n (what counts as n).
  6. Prepare and assay the conditions side by side in each experiment, so that the comparison can be paired (paired vs unpaired).

Check what an AI assistant ran

  1. The assistant estimated Kd and Bmax from a Scatchard plot. Ask for nonlinear regression on specific binding (or total and nonspecific together).
  2. The assistant pooled wells from all experiments into one fit and reported a p-value for Kd. Ask for one estimate per experiment and a comparison across experiments.
  3. The assistant averaged Kd values arithmetically. Ask for the mean pKd (geometric mean Kd).
  4. The assistant did not report nonspecific binding or ligand depletion. Ask for both.

Report it

Saturation binding was measured at [8] radioligand concentrations ([0.1]–[10] nM) in triplicate, with nonspecific binding defined by [excess unlabelled competitor]. Specific binding was fitted with a one-site model by nonlinear least squares in each of [5] independent experiments; Kd and Bmax were compared as log ratios (treated ÷ control) with paired t-tests across experiments (R [4.3.3]). [If checked from raw counts:] bound radioligand was below [10]% of added at all concentrations.

Treatment reduced Bmax to [0.65] of control (95% CI [0.53] to [0.81]; p = [0.005]) without a clear change in Kd ([0.98], 95% CI [0.82] to [1.17]; p = [0.76]); control Kd was [1.07] nM (pKd [8.97] ± [0.07], n = [5]).

Replace the bracketed values with your own.

References

  • GraphPad Software. Equation: one site — specific binding. GraphPad Prism Curve Fitting Guide (checked 12 November 2026). graphpad.com
  • Auld DS, Farmen MW, Kahl SD, et al. (2012). Receptor binding assays for HTS and drug discovery. In: Assay Guidance Manual. Bethesda (MD): National Center for Advancing Translational Sciences. ncbi.nlm.nih.gov/books/NBK91992
  • Hulme EC, Trevethick MA (2010). Ligand binding assays at equilibrium: validation and interpretation. British Journal of Pharmacology 161:1219–1237. doi:10.1111/j.1476-5381.2009.00604.x

How this page was made

  • Written and published by Licklider. Recommendations cite peer-reviewed methods papers, the NIH Assay Guidance Manual and 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; R 4.3.3, base R), and the two languages print identical output; the simulation was run in Python.
  • Separate review passes checked the statistics, the citations and readability before publication.