| Title: | Calculating Density-Independent Niche Breadth Indices from Abundance Data |
| Version: | 0.1.0 |
| Description: | Deriving isodar-based niche breadth indices from abundance data of two or more habitats, including several methods based on pairwise isodars, multidimensional isodars, and isodar-adjusted inequality. |
| License: | GPL-3 |
| Encoding: | UTF-8 |
| RoxygenNote: | 7.3.3 |
| Imports: | tibble, dplyr, lmodel2 |
| NeedsCompilation: | no |
| Packaged: | 2026-04-08 11:42:42 UTC; shadu |
| Author: | Shahar Dubiner |
| Maintainer: | Shahar Dubiner <dubiner@mail.tau.ac.il> |
| Repository: | CRAN |
| Date/Publication: | 2026-04-13 15:10:02 UTC |
isoniche: Calculating Density-Independent Niche Breadth Indices from Abundance Data
Description
Deriving isodar-based niche breadth indices from abundance data of two or more habitats, including several methods based on pairwise isodars, multidimensional isodars, and isodar-adjusted inequality.
Author(s)
Maintainer: Shahar Dubiner dubiner@mail.tau.ac.il (ORCID)
Authors:
Itai Granot
Jonathan Belmaker
Fit pairwise isodars between two or more habitats
Description
Fits pairwise isodar relationships between all habitat pairs using
lmodel2::lmodel2() (Model II regression). Each output row represents
the relationship:
habitat\_y = intercept + slope \times habitat\_x
Usage
fit_isodar(data, n_habitats = ncol(data), flip_intercept = TRUE)
Arguments
data |
A data frame of abundance data with one column per habitat. |
n_habitats |
Integer (>= 2). Number of habitat columns to use, starting at column 1. |
flip_intercept |
Logical. If TRUE (default), flip axes when intercept < 0. |
Details
If the fitted intercept is negative, the relationship is flipped (axes swapped) to provide a biologically interpretable representation (negative intercepts are meaningless in this context) and model refitted.
The sd column is the residual SD from vertical residuals in the reported equation.
Value
A tibble with one row per habitat pair containing:
-
habitat_x,habitat_y slope, intercept
sd: residual SD in the reported equation
-
p_slope,p_intercept flipped: TRUE if axes were flipped (due to int<0), FALSE otherwise
Examples
set.seed(1)
isod <- simulate_isodars(1, 2, 5, 1, noise = 2, n = 10)
fit_isodar(isod, n_habitats = 3)
Compute the isodar-adjusted inequality index for one or more total abundances
Description
Reconstructs habitat abundances for each requested total abundance by solving a weighted least-squares system defined by the pairwise isodars:
habitat_y - slope \cdot habitat_x = intercept
Usage
isodar_adj_niche(
isodars,
abundances = NULL,
weights = NULL,
alpha = 0.1,
sig_weights = c(sig = 1, nonsig = 0),
method = c("gini"),
plot = TRUE,
max_search = 10000
)
Arguments
isodars |
A data frame returned by |
abundances |
Numeric vector of total abundances. If NULL, the minimal total abundance yielding occupancy in all habitats ("baseline") is chosen when possible; otherwise a default exploratory sequence is used |
weights |
Weighting scheme. One of:
|
alpha |
Numeric in (0, 1). Significance threshold used when |
sig_weights |
Numeric vector of length 2 giving weights for significant and non-significant
isodars when |
method |
Character. Currently only |
plot |
Logical. If TRUE, plots adjusted niche breadth versus total abundance |
max_search |
Integer. Maximum total abundance to search when |
Details
The reconstruction is constrained to be nonnegative and to sum to the requested total abundance (active-set heuristic). Niche breadth is then computed from the reconstructed habitat vector; currently defined as:
niche breadth = 1 - Gini(x)
of isodar-reconstructed abundances at a given N.
Value
A tibble with one row per total abundance containing:
-
total_abundance niche_breadth
one column per habitat with reconstructed abundance
Examples
set.seed(1)
isod <- simulate_isodars(1, 2, 5, 1, noise = 2, n = 10)
INB <- fit_isodar(isod, n_habitats = 3)
isodar_adj_niche(INB, max_search = 100) # automatically checks only baseline abundance
isodar_adj_niche(INB, abundances = c(15, 30, 45), max_search = 100) # set specific values
Multidimensional isodar-based niche breadth indices
Description
Computes vector- and orthogonal isodar-based niche breadth components
from abundance data across all habitats simultaneously, generalizing the
slope (density-dependent) and intercept/baseline (density-independent)
components of isodars to n dimensions.
Usage
ndim_isoniche(data, n_habitats = ncol(data), scale = TRUE, weights = TRUE)
Arguments
data |
A data frame of abundance data (one column per habitat). |
n_habitats |
Integer (>=2). Number of habitat columns to use, starting at column 1. |
scale |
Logical. If |
weights |
Logical. If |
Details
Both indices return values between 0 and 1, where 1 indicates a perfect generalist and 0 a specialist. Habitat axes can optionally be weighted by inverse residual variance.
The dominant density-dependent axis v is obtained from the first right singular
vector of the mean-centered abundance matrix X_c. For the vector component,
per-habitat residual variances are estimated from residuals after removing this axis:
R = X_c - (X_c v) v^\top.
The orthogonal component is computed from the mean abundance vector \mu, but
normalized to compositional space to remove dependence on total abundance:
p = \mu / \sum \mu.
The neutral (equal-use) composition is p_0 = (1/n, \dots, 1/n).
Baseline preference is then:
r = p - p_0.
For the orthogonal component, per-habitat residual variances are estimated from residuals after removing the neutral axis:
R_0 = X_c - (X_c v_0) v_0^\top.
Value
A tibble with vector, orthogonal, and n_habitats.
Examples
set.seed(1)
isod <- simulate_isodars(1, 2, 5, 1, noise = 2, n = 10)
Pairwise isodar-based niche breadth indices
Description
Computes niche breadth indices from a set of pairwise isodars (slopes and
intercepts) in the format of the output table of fit_isodar().
Two methods are available: a weighted mean of isodar components and a
weighted inverse variance of the isodars' divergence from neutrality.
Usage
pairwise_isoniche(
data,
method = c("inverse_variance", "mean"),
weights = NULL,
alpha = 0.1,
sig_weights = c(sig = 1, nonsig = 0)
)
Arguments
data |
A data frame returned by |
method |
Character. One of |
weights |
Weighting scheme for pairwise isodars. One of:
|
alpha |
Numeric in (0, 1). Significance threshold used when |
sig_weights |
Numeric vector of length 2 giving weights for significant and non-significant
isodars when |
Value
A one-row tibble with columns intercept, slope, and method.
Examples
set.seed(1)
isod <- simulate_isodars(1, 2, 5, 1, noise = 2, n = 10)
INB <- fit_isodar(isod, n_habitats = 3)
pairwise_isoniche(INB, method = "inverse_variance", weights = "1/var")
pairwise_isoniche(INB, method = "inverse_variance", weights = "sig",
sig_weights = c(sig = 1, nonsig = 0.25), alpha = 0.1)
Simulate abundances across three habitats
Description
Simulates abundance data for three habitats across n sites using
sequential linear relationships (isodars) with Gaussian noise:
hab2 is generated from hab1 using
slope1andint1hab3 is generated from hab2 using
slope2andint2
Usage
simulate_isodars(
slope1,
slope2,
int1,
int2,
noise = 1,
n = 30,
hab1_max = 100/(slope1^1.2) - int1
)
Arguments
slope1 |
Numeric. Isodar slope for |
slope2 |
Numeric. Isodar slope for |
int1 |
Numeric. Isodar intercept for |
int2 |
Numeric. Isodar intercept for |
noise |
Numeric (>= 0). Standard deviation of Gaussian noise. |
n |
Integer (> 0). Number of simulated sites. |
hab1_max |
Integer. maximum abundance value in habitat 1 (other maxima calculated from hab1_max). Default is derived to generally suit the isodar parameters, but is arbitrary. |
Details
The output includes simple per-site niche metrics (CV and Gini) computed from the three habitat abundances.
Value
A tibble with one row per simulated site containing:
hab1, hab2, hab3: simulated abundances (nonnegative integers)
total_abundance: hab1 + hab2 + hab3
mean_abundance: total_abundance divided by 3
sd: scaled standard deviation of habitat abundances
cv: coefficient of variation (NA if mean_abundance == 0)
gini: Gini coefficient of habitat abundances
Examples
set.seed(1)
simulate_isodars(1, 2, 5, 1, noise = 2, n = 10)