itv_btv_ratio(df, sp_col, trait_cols)

Partition total trait variance into within-species (ITV) and between-species (BTV) components. Returns the ITV/total ratio per trait.

ITVvariance partitioning
Args:df — individual-level datasp_col — species columntrait_cols — traits
itv_btv_ratio <- function(df, sp_col, trait_cols) {
  results <- lapply(trait_cols, function(trait) {
    x  <- df[[trait]]
    sp <- df[[sp_col]]
    
    x  <- x[!is.na(x)]
    sp <- sp[!is.na(df[[trait]])]
    
    total_var <- var(x)
    sp_means  <- tapply(x, sp, mean, na.rm = TRUE)
    btv       <- var(sp_means[sp])          # between-species variance
    itv       <- total_var - btv            # within-species variance
    
    data.frame(trait     = trait,
               ITV       = itv,
               BTV       = btv,
               Total     = total_var,
               ITV_ratio = itv / total_var * 100)
  })
  do.call(rbind, results)
}
# ── Example ──────────────────────────────────────────────────────
result <- itv_btv_ratio(iris,
                        sp_col     = "Species",
                        trait_cols = c("Sepal.Length","Sepal.Width",
                                       "Petal.Length","Petal.Width"))
print(result)
# A high ITV_ratio means within-species variation dominates