---
title: "Checking a CNDD analysis"
description: "Three checks for conspecific density dependence in R: the habitat confound that hides it, whether rarer species truly show more, and enemies versus competition."
date: "2026-08-01 15:00"
categories: [ecology tutorial, R, community ecology, model diagnostics, plant ecology]
image: thumbnail.png
image-alt: "Seedling survival flat against conspecific density overall but declining within each habitat band, a Simpson's paradox that hides density dependence."
---
```{r setup}
#| include: false
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE,
dev = "png", dpi = 120, fig.path = "figures/",
fig.width = 7, fig.height = 4.4)
library(ggplot2)
theme_te <- theme_minimal(base_size = 12) +
theme(panel.background = element_rect(fill = "white", colour = NA),
plot.background = element_rect(fill = "white", colour = NA),
panel.grid.minor = element_blank(),
plot.title = element_text(face = "bold", size = 12))
theme_set(theme_te)
col_naive <- "#b5651d"; col_adj <- "#3a6b52"; col_ref <- "#555555"
set.seed(418); n <- 1500
habitat <- rnorm(n)
conspec <- 2*habitat + rnorm(n, 0, 1) # species clusters in good habitat
true_cndd <- -0.5
surv <- rbinom(n, 1, plogis(1.0 + true_cndd*conspec + 1.2*habitat))
b_naive <- coef(glm(surv ~ conspec, family = binomial))["conspec"]
b_adj <- coef(glm(surv ~ conspec + habitat, family = binomial))["conspec"]
```
Conspecific negative density dependence is real, important, and one of the hardest quantities in ecology to measure without fooling yourself. The pattern it predicts, worse survival among your own kind, is also produced by things that have nothing to do with density dependence, and the statistics used to estimate it carry biases that can invent it or erase it. These three checks are the ones a CNDD claim most often fails.
## Check 1: is habitat confounding the density?
This is the big one. Species are not scattered at random; they cluster where conditions suit them. That means a seedling in a patch dense with its own kind is usually in *good* habitat, where survival is high, at the very moment it is surrounded by conspecifics. The habitat effect (dense conspecifics, high survival) works against the density-dependence effect (dense conspecifics, low survival), and if you ignore habitat the two can cancel.
```{r confound}
set.seed(418); n <- 1500
habitat <- rnorm(n)
conspec <- 2*habitat + rnorm(n, 0, 1) # clusters in good habitat: conspec tracks habitat
surv <- rbinom(n, 1, plogis(1.0 - 0.5*conspec + 1.2*habitat)) # true CNDD is negative
c(naive = coef(glm(surv ~ conspec, family = binomial))["conspec"],
habitat_adjusted = coef(glm(surv ~ conspec + habitat, family = binomial))["conspec"])
```
The true conspecific effect built into the data is `r sprintf("%.2f", -0.5)`, firmly negative. Ignore habitat and the estimated effect is `r sprintf("%.2f", b_naive)`, essentially zero: the density dependence has been hidden by the tendency of the species to sit in good spots. Put habitat back in and the estimate returns to `r sprintf("%.2f", b_adj)`, negative again. A CNDD analysis that does not control for habitat is not measuring density dependence; it is measuring where the species likes to grow, and the two are tangled by design (Detto et al. 2019 Ecology Letters 22(11):1923-1939).
```{r fig-confound}
#| fig-cap: "Seedling survival against conspecific density. Overall (ochre) the relationship looks flat, no density dependence; split by habitat quality (green bands) it declines within every band. The confound is a Simpson's paradox."
#| fig-alt: "Points of survival against conspecific density; the overall trend is flat while within each habitat band the trend declines, a Simpson's paradox."
dd <- data.frame(conspec = conspec, surv = surv,
band = cut(habitat, quantile(habitat, 0:4/4), include.lowest = TRUE, labels = paste("habitat", 1:4)))
ggplot(dd, aes(conspec, surv)) +
geom_smooth(method = "glm", method.args = list(family = binomial), se = FALSE, colour = col_naive, linewidth = 1.1) +
geom_smooth(aes(group = band), method = "glm", method.args = list(family = binomial), se = FALSE, colour = col_adj, linewidth = 0.6) +
labs(x = "Conspecific density", y = "Survival",
title = "Flat overall, declining within each habitat band")
```
```{r fig-coef}
#| fig-cap: "The estimated conspecific effect three ways. The true value is negative; the naive estimate that ignores habitat is near zero; adding habitat recovers the negative density dependence."
#| fig-alt: "Bar chart of the conspecific coefficient: a negative true value, a near-zero naive estimate, and a negative habitat-adjusted estimate."
dc <- data.frame(est = factor(c("true","naive","habitat-adjusted"), levels = c("true","naive","habitat-adjusted")),
val = c(-0.5, b_naive, b_adj))
ggplot(dc, aes(est, val, fill = est)) +
geom_col(width = 0.6) +
geom_hline(yintercept = 0, colour = col_ref, linewidth = 0.4) +
scale_fill_manual(values = c("true" = col_ref, "naive" = col_naive, "habitat-adjusted" = col_adj), guide = "none") +
labs(x = NULL, y = "Conspecific coefficient", title = "Ignoring habitat erases the density dependence")
```
## Check 2: do rarer species really show stronger density dependence?
A celebrated result is that rare species suffer stronger conspecific density dependence than common ones, which would explain why they stay rare (Comita et al. 2010 Science 329(5989):330-332). The pattern is probably real, but it is exactly the kind of claim the estimation can manufacture, because rare species are estimated from few individuals at low densities, where the density slope is poorly identified and its errors are large and skewed. A relationship between estimated density dependence and abundance can appear from that estimation error alone, with no difference in the underlying biology (Detto et al. 2019). The check is to confirm the pattern survives methods designed to remove the bias, and to be suspicious of any density-dependence-versus-abundance relationship that has not been tested against a null of pure estimation noise.
## Check 3: is it enemies, or just competition?
Even a clean, habitat-controlled, bias-corrected conspecific effect does not prove the Janzen-Connell mechanism. Specialised enemies are one way a seedling does worse among its own kind; competition for light, water and nutrients with close relatives that need exactly the same resources is another, and both produce the same survival-against-density curve. The pattern is silent on the cause. Separating them needs manipulation, not more regression: exclude or kill the enemies with fungicide, insecticide or cages and see whether the density dependence weakens. If survival among conspecifics recovers when the pathogens are removed, enemies were the cause; if it does not, competition was. The distinction matters, because only the enemy mechanism carries the specificity that Janzen and Connell proposed.
## The weight of the caveats
Three checks, and all three make the same point: a conspecific density coefficient is easy to compute and hard to earn. Habitat confounds it, estimation biases it, and its mechanism is ambiguous even when it is real. None of this means CNDD is unimportant, the diversity it can sustain is genuine, but it does mean that the strong versions of the story, that it sets abundances, that it drives the latitudinal diversity gradient, rest on measurements that need habitat controls, bias-aware methods, and ideally experiments before they carry that weight. The mechanism is one of the best ideas in community ecology and one of the easiest to measure badly.
## Related tutorials
- [Janzen-Connell and tree diversity](../janzen-connell-and-diversity/)
- [Conspecific negative density dependence](../conspecific-negative-density-dependence/)
- [Rare-species advantage and coexistence](../rare-species-advantage-and-coexistence/)
- [Confounding and backdoor adjustment](../confounding-and-backdoor-adjustment/)
## References
- Comita LS et al. 2010. Science 329(5989):330-332 (10.1126/science.1190772).
- Detto M et al. 2019. Ecology Letters 22(11):1923-1939 (10.1111/ele.13372).