# Clonogenic survival assay statistics: plating efficiency, linear-quadratic fits and comparing survival curves

> Normalise colony counts by each condition's plating efficiency, fit the linear-quadratic model per experiment, and compare SF2 or the dose enhancement ratio across independent experiments; pooling dishes in a Poisson model gives false positives. Python and R code.

Canonical: https://www.licklider.ai/guides/clonogenic-survival-assay/
Section: Guides › Correlation, regression and survival
Author: Licklider · Published 2026-11-12 · Last reviewed 2026-11-12 (UTC)

> **Quick answer.** In a clonogenic assay, the **surviving fraction** at each dose is colonies ÷ cells seeded, divided by the **plating efficiency** of the unirradiated (0 Gy) dishes of the same condition and experiment. Fit the **linear-quadratic model**, SF = exp(−(αD + βD²)), to each condition in each **independent experiment**, and compare conditions with one summary per experiment, such as **SF2** (survival at 2 Gy) or the **dose enhancement ratio**, as a paired log ratio across experiments. A model of all dishes pooled must allow for **overdispersion** (quasi-Poisson) and include a plating efficiency for each experiment and condition; use it as a check. In a 5,000-study simulation of the example design with no real effect, a plain Poisson model of the pooled dishes found an "effect" in 38.9% of studies, quasi-Poisson in 7.8%, and SF2 per experiment in 5.3%.

**Terms used below.** *Clonogenic (colony formation) assay*: cells seeded at low density and counted as colonies of at least 50 cells after about 1–3 weeks. *Plating efficiency (PE)*: colonies ÷ cells seeded in the unirradiated dishes of one condition in one experiment; a sensitiser-only 0 Gy dish gives the sensitiser's PE. *Surviving fraction (SF)*: colonies ÷ (cells seeded × the PE of the same condition and experiment). *Linear-quadratic (LQ) model*: SF = exp(−(αD + βD²)), with D the dose in Gy, α (Gy⁻¹) the steepness at low doses and β (Gy⁻²) the extra bending at higher doses. *SF2*: the surviving fraction at 2 Gy, here read from the fitted curve. *Dose enhancement ratio (DER)*: the ratio of the dose of radiation alone to the dose with the sensitiser that gives the same survival; above 1 means sensitisation. *Log ratio*: the logarithm of the ratio sensitiser ÷ control; results are converted back to a ratio. *Cellular cooperation*: plating efficiency that rises with the number of cells seeded. *Poisson model*: a regression for counts that assumes their variance equals their mean. *Overdispersion*: more variation than Poisson allows; the *dispersion* is its size (1 = Poisson), computed from Pearson residuals. *Quasi-Poisson*: a Poisson regression whose standard errors are scaled up by the square root of the dispersion. *Independent experiment*: cells plated and irradiated on a separate 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 is the survival curve of a cell line? | SF per dose from dish means, LQ fit per experiment; mean α, β and SF2 across experiments | α, β, SF2 with spread, n experiments |
| Does a treatment change radiosensitivity? | SF2 (or another summary chosen in advance) per condition per experiment, log ratio sensitiser ÷ control, one-sample t-test across experiments (the paired test) | Ratio with 95% CI, t and df, n experiments |
| How large is the sensitisation? | DER at a survival level inside the measured dose range in every experiment (here SF = 0.1), one per experiment, paired | DER with 95% CI |
| Mechanism unknown, or doses well above 2 Gy | Compare α and β, or the whole curve; SF2 barely moves when a treatment changes only β | Both parameters with CIs |
| Does plating efficiency change with treatment alone? | PE per condition per experiment, compared across experiments | Ratio with 95% CI |
| Colony numbers depend on cells seeded (cellular cooperation) | Seed several densities at every dose and model colonies against cells seeded | Survival from the fitted relation, not a single PE |
| One experiment only | No between-experiment variation can be estimated, so n = 1 | Describe the curves; state the limitation |

The code on this page covers the first three rows and prints PE per experiment and condition; for α and β, use the per-experiment fits the same way (paired log ratio), and the other rows are planning advice.

Franken and colleagues instruct: "In every experiment, the PE must be determined", and "the surviving fraction of cells after any treatment is always calculated taking into account the PE of control cells"; a treatment's effect on the curve can be expressed "as a dose-modifying factor, dose enhancement ratio or sensitizer enhancement ratio" ([Franken et al. 2006](https://doi.org/10.1038/nprot.2006.339)). For a sensitiser, the matching control for the combined treatment is the sensitiser-only 0 Gy dish, so each condition is normalised by its own PE; this separates radiosensitisation from the drug's own toxicity, which shows up as a lower PE. The same protocol recommends a ratio of doses at a given survival level, radiation alone over combined treatment, rather than a ratio of surviving fractions at one dose; it also recommends a drug-only control. The LQ model describes survival as "Sd/S0 = e−(αd+βd²)" with α in Gy⁻¹ and β in Gy⁻² ([Franken et al. 2013](https://doi.org/10.3892/ijo.2013.1857)). Braselmann and colleagues note that the dispersion of colony counts "often appears to be >1.0, mainly due to extra variability between replicated experiments, even after correction for plating efficiencies", and that CFAssay, their R package, scales standard deviations by the square root of the dispersion, which "uses the quasipoisson family of the R-function glm"; its model includes a plating efficiency that "varies between different experiments" ([Braselmann et al. 2015](https://doi.org/10.1186/s13014-015-0529-y)). Brix and colleagues found that in several cell lines PE "increased by one to two orders of magnitude with increasing numbers of cells seeded, thus challenging the concept of cell line-specific, constant PEs" ([Brix et al. 2020](https://doi.org/10.1186/s13014-020-01697-y)).

## Worked example: a sensitiser with no real effect

Constructed data: colonies in 3 dishes per dose, with and without a radiosensitiser, in **5 independent experiments** (120 dishes). Cells were seeded at 200, 400, 1,000 and 3,000 per dish for the 0, 2, 4 and 6 Gy doses, so that every dish gave 67 to 159 colonies. By design, **the sensitiser does not change radiosensitivity on average** (true α 0.30 Gy⁻¹, β 0.03 Gy⁻²), and colonies are exactly proportional to cells seeded (no cellular cooperation), so one PE per condition and experiment is valid here; with real cells that assumption has to be checked. Plating efficiency varies between experiments and conditions, α varies between experiments (and a little between the two conditions of one experiment), and dishes scatter around their expected counts. The data's random seed was the first one tried and was not chosen for its result. Stored code and data: [colonies.csv](/guides/clonogenic-survival-assay/colonies.csv), [model.py](/guides/clonogenic-survival-assay/model.py), [make_data.py](/guides/clonogenic-survival-assay/make_data.py), [analysis.py](/guides/clonogenic-survival-assay/analysis.py), [analysis.R](/guides/clonogenic-survival-assay/analysis.R) and [the analysis output](/guides/clonogenic-survival-assay/analysis_output.txt); analysis.py and analysis.R print the same output.

In experiment 1, the control's 0 Gy dishes gave (113 + 126 + 149) ÷ 3 = 129.3 colonies from 200 cells, a PE of 0.6467 (0.65); at 2 Gy, (128 + 120 + 110) ÷ 3 = 119.3 colonies from 400 cells is 0.2983, so the measured SF at 2 Gy is 0.2983 ÷ 0.6467 = 0.461. SF2 in the table comes from the LQ curve fitted (by least squares on log SF) to the 2, 4 and 6 Gy points, which leaves one degree of freedom per fit; in experiment 4 the fitted sensitiser SF2 (0.486) differs from the measured one (0.435), so state which one you report.

| Experiment | Control PE | Control α (Gy⁻¹) | Control β (Gy⁻²) | Control SF2 | Sensitiser PE | Sensitiser SF2 |
| --- | --- | --- | --- | --- | --- | --- |
| 1 | 0.65 | 0.335 | 0.026 | 0.461 | 0.60 | 0.443 |
| 2 | 0.64 | 0.288 | 0.043 | 0.474 | 0.65 | 0.540 |
| 3 | 0.67 | 0.304 | 0.035 | 0.474 | 0.51 | 0.511 |
| 4 | 0.45 | 0.321 | 0.019 | 0.488 | 0.57 | 0.486 |
| 5 | 0.61 | 0.319 | 0.027 | 0.475 | 0.55 | 0.546 |

| Comparison, sensitiser vs control | Result |
| --- | --- |
| **SF2 ratio, one per experiment (paired, n = 5)** | **1.06 (95% CI 0.96 to 1.17), p = 0.17** |
| Dose enhancement ratio at SF = 0.1, one per experiment (paired) | 0.96 (95% CI 0.88 to 1.05), p = 0.26 |
| All 120 dishes, plain Poisson model with a PE per experiment and condition (not valid: dishes are not independent) | χ²(2) = 10.3, p = 0.0059; dispersion 2.3 |
| Same model, quasi-Poisson | F(2, 106) = 2.18, p = 0.12 |

The plain Poisson model treats every dish as an independent count with Poisson variation, but the counts vary 2.3 times as much as that, so it reports a "significant" sensitiser effect that does not exist. In this data set scaling by the dispersion also removes it (p = 0.12), but quasi-Poisson still treats the dishes as independent; the per-experiment comparison is the test to report. In this example the five SF2 ratios happen to agree closely (95% CI 0.96 to 1.17); with these settings a wider interval is more typical. In 5,000 simulated studies of this design ([simulation.py](/guides/clonogenic-survival-assay/simulation.py), [the simulation output](/guides/clonogenic-survival-assay/simulation_output.txt)):

| Scenario | SF2 per experiment (paired), p < 0.05 | All dishes, Poisson | All dishes, quasi-Poisson |
| --- | --- | --- | --- |
| Sensitiser has no effect (false positives) | 5.3% | **38.9%** | 7.8% |
| Sensitiser raises α by 30% (power) | 58.4% | 100.0% | 99.7% |

These percentages describe this simulated design (5 experiments, 3 dishes per dose, between-experiment variation in PE and α), not colony counts in general. The plain Poisson model's 100.0% "power" is meaningless because it also finds effects that are absent. Quasi-Poisson used the whole curve and detected a 30% rise in α almost always, but its false positives (7.8%) were above 5%: it treats the 120 dishes as independent, while radiosensitivity varies between experiments. SF2 per experiment kept false positives close to 5% and is the safer primary analysis; with 5 experiments it detected the 30% rise in α 58.4% of the time. Use the pooled model only as a check on the per-experiment analysis: its degrees of freedom count dishes, not experiments, whatever the dispersion.

The code expects one row per dish with columns experiment, condition (control or sensitiser), dose_gy, dish, seeded and colonies; rename your columns and labels to match, and run the code in the folder that holds the CSV file. The Python block computes SF2 per experiment (it needs NumPy, pandas 2.2 or later and SciPy); the R block fits the pooled quasi-Poisson model (base R). The full scripts do both.

```python
# SF2 per experiment and condition, then the paired comparison (analysis.py also computes the DER and the pooled models)
import numpy as np, pandas as pd
from scipy import stats

d = pd.read_csv("colonies.csv")
def sf2(x):                                                    # PE from 0 Gy, then a least-squares LQ fit to log SF
    m = x.groupby("dose_gy").apply(lambda g: (g.colonies / g.seeded).mean(), include_groups=False)
    sf = m.drop(0.0) / m.loc[0.0]; D = sf.index.to_numpy()     # a dose with zero colonies in every dish breaks the log
    (a, b), *_ = np.linalg.lstsq(np.column_stack([D, D ** 2]), -np.log(sf.to_numpy()), rcond=None)
    return np.exp(-(2 * a + 4 * b))
s = d.groupby(["experiment", "condition"]).apply(sf2, include_groups=False).unstack()
r = np.log(s["sensitiser"] / s["control"]); t = stats.ttest_1samp(r, 0); ci = t.confidence_interval()
print(f"{np.exp(r.mean()):.2f} ({np.exp(ci.low):.2f} to {np.exp(ci.high):.2f}), t({t.df:.0f}) = {t.statistic:.2f}, p = {t.pvalue:.2g}")
# 1.06 (0.96 to 1.17), t(4) = 1.69, p = 0.17
```

```r
d <- read.csv("colonies.csv")
d$s <- as.numeric(d$condition == "sensitiser"); d$pe <- interaction(d$experiment, d$condition)   # PE per experiment and condition
m0 <- glm(colonies ~ 0 + pe + dose_gy + I(dose_gy^2) + offset(log(seeded)), family = quasipoisson, data = d)
m1 <- update(m0, . ~ . + s:dose_gy + s:I(dose_gy^2))            # sensitiser changes the curve
sum(residuals(m1, type = "pearson")^2) / df.residual(m1)        # dispersion: 2.3
anova(m0, m1, test = "F")                                       # F(2, 106) = 2.18, p = 0.12
```

## Before you analyse

1. **Seed enough cells at each dose for roughly 50 to 200 colonies per dish**, and incubate until colonies in every condition, including sensitiser-treated ones, reach 50 cells; otherwise a drug that slows growth looks like a radiosensitiser.
2. **Check that colonies rise in proportion to cells seeded** at your densities, in control and treated cells; if plating efficiency changes with density (cellular cooperation), seed several densities at every dose and model the relation instead of using one PE.
3. **Determine plating efficiency in every experiment and condition** from its own unirradiated dishes, and report the sensitiser-only PE next to the control PE.
4. **Count colonies of at least 50 cells, blind to condition**, with the same staining and counting rules for every dish. If every dish at a dose has zero colonies, the log-SF fit fails: seed more cells, or analyse that dose with a count model, and say which.
5. **Treat dishes as technical replicates and experiments as n.** Plan at least 3 independent experiments; with 2, the paired test has 1 degree of freedom and the result is preliminary. In any pooled model, include a PE per experiment and condition and report the Pearson dispersion ([count data](/guides/statistical-tests-for-count-data/)).
6. **Choose the summary in advance** (SF2, α, the DER at a survival level inside the measured dose range), rather than picking the dose that differs most.

## Check what an AI assistant ran

1. **The assistant fitted a Poisson model to all dishes and reported a tiny p-value.** Ask for the dispersion, and for the per-experiment comparison.
2. **The assistant computed surviving fractions without each condition's own plating efficiency.** Ask for the PE of the matching unirradiated dishes.
3. **The assistant used dishes as n in a t-test.** Ask for one value per condition per experiment.
4. **The assistant called a DER below 1 sensitisation, or extrapolated the DER beyond the highest dose.** A DER below 1 means no sensitisation (or protection); ask for radiation-alone dose ÷ combined dose at a survival level inside the measured dose range.
5. **The assistant chose the dose with the biggest difference after inspecting the data.** Ask for the summary set in advance.

## Report it

> Colonies of at least 50 cells were counted, blind to condition, in [3] dishes per dose and condition ([0, 2, 4, 6] Gy; [200 to 3,000] cells seeded) in [5] independent experiments. Surviving fractions were calculated with the plating efficiency of the unirradiated dishes of the same condition and experiment, and the linear-quadratic model was fitted per condition and experiment by least squares on log surviving fraction. SF2 and the dose enhancement ratio at SF = [0.1] were compared as log ratios with one-sample t-tests across experiments; a quasi-Poisson model of all dishes, with a plating efficiency per experiment and condition, was used as a check (R [4.3.3]).

> Plating efficiency (printed by analysis.py) was [0.45 to 0.67] in control cells and [0.51 to 0.65] in sensitiser-treated cells. SF2 did not clearly differ between conditions (sensitiser ÷ control [1.06], 95% CI [0.96] to [1.17]; t([4]) = [1.69], p = [0.17]; n = [5] experiments); the data are compatible with anything from a [4]% decrease to a [17]% increase. The dose enhancement ratio at SF = [0.1] was [0.96] (95% CI [0.88] to [1.05]).

Replace the bracketed values with your own.

## References

- Franken NAP, Rodermond HM, Stap J, Haveman J, van Bree C (2006). Clonogenic assay of cells in vitro. *Nature Protocols* 1:2315–2319. [doi:10.1038/nprot.2006.339](https://doi.org/10.1038/nprot.2006.339)
- Franken NAP, Oei AL, Kok HP, et al. (2013). Cell survival and radiosensitisation: modulation of the linear and quadratic parameters of the LQ model. *International Journal of Oncology* 42:1501–1515. [doi:10.3892/ijo.2013.1857](https://doi.org/10.3892/ijo.2013.1857)
- Braselmann H, Michna A, Heß J, Unger K (2015). CFAssay: statistical analysis of the colony formation assay. *Radiation Oncology* 10:223. [doi:10.1186/s13014-015-0529-y](https://doi.org/10.1186/s13014-015-0529-y)
- Brix N, Samaga D, Hennel R, et al. (2020). The clonogenic assay: robustness of plating efficiency-based analysis is strongly compromised by cellular cooperation. *Radiation Oncology* 15:248. [doi:10.1186/s13014-020-01697-y](https://doi.org/10.1186/s13014-020-01697-y)

## Related

- [Statistical tests for count data](https://www.licklider.ai/guides/statistical-tests-for-count-data/)
- [What counts as n?](https://www.licklider.ai/guides/what-counts-as-n/)
- [Drug combination synergy](https://www.licklider.ai/guides/drug-combination-synergy/)
- [Comparing IC50 values](https://www.licklider.ai/guides/compare-ic50-dose-response-curves/)

## How this page was made

- Written and published by Licklider. Recommendations cite peer-reviewed methods papers 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 and pandas 2.2 or later; 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.
