Mapping species richness in attribute space

Bruno Vilela

2025-07-07

Overview

Species richness and community structure can also be represented in attribute space, where axes correspond to any quantitative information that can be attributed to a species. The letsR package provides tools to construct and analyze presence–absence matrices (PAMs) in attribute space, allowing researchers to examine biodiversity patterns beyond geography and environment.

This vignette demonstrates how to:

  1. Build a PAM in attribute space using lets.attrpam();
  2. Visualize species richness with lets.plot.attrpam();
  3. Compute descriptors per attribute cell using lets.attrcells();
  4. Aggregate descriptors to the species level with lets.summarizer.cells(); and
  5. Cross-map attribute metrics to geographic space for integrative analysis.
# Load the package
library(letsR)

Simulating trait data and building the attribute space PAM

We begin by generating a dataset of 2,000 species with two correlated traits:

set.seed(123)
n <- 2000
Species  <- paste0("sp", 1:n)
trait_a  <- rnorm(n)
trait_b  <- trait_a * 0.2 + rnorm(n)
df       <- data.frame(Species, trait_a, trait_b)

# Build the attribute-space PAM
attr_obj <- lets.attrpam(df, n_bins = 30)

Visualizing richness in attribute space

The lets.plot.attrpam() function plots the richness surface across the bivariate trait space.

lets.plot.attrpam(attr_obj)

Each cell represents a unique combination of traits (binned values of trait_a and trait_b), and the color intensity indicates the number of species falling within that bin.

Computing attribute-space descriptors

The function lets.attrcells() quantifies structural properties of each cell in the trait space, including measures of centrality, isolation, and border proximity.

attr_desc <- lets.attrcells(attr_obj, perc = 0.2)
head(attr_desc)
#>   Cell_attr Weighted Mean Distance to midpoint Mean Distance to midpoint
#> 3         1                          -2.326864                 -2.353019
#> 4         2                          -2.249095                 -2.275839
#> 5         3                          -2.174679                 -2.202012
#> 6         4                          -2.103971                 -2.131885
#> 7         5                          -2.037358                 -2.065836
#> 8         6                          -1.975254                 -2.004267
#>   Minimum Zero Distance Minimum 20% Zero Distance Distance to MCP border
#> 3                     0                 0.7875427                      0
#> 4                     0                 0.7238193                      0
#> 5                     0                 0.6742795                      0
#> 6                     0                 0.6362405                      0
#> 7                     0                 0.6116810                      0
#> 8                     0                 0.5974101                      0
#>   Frequency Weighted Distance
#> 3                    2.401182
#> 4                    2.325796
#> 5                    2.253747
#> 6                    2.185353
#> 7                    2.120959
#> 8                    2.060930

We can visualize these metrics using lets.plot.attrcells():

lets.plot.attrcells(attr_obj, attr_desc)

Each panel represents a different descriptor (e.g., distance to midpoint, distance to border, weighted isolation) mapped across the trait space.

Summarizing descriptors by species

To derive species-level summaries, we can aggregate descriptor values across all cells occupied by each species using the lets.summarizer.cells() function.

attr_desc_by_sp <- lets.summaryze.cells(attr_obj, attr_desc, func = mean)
head(attr_desc_by_sp)
#>   Species Weighted Mean Distance to midpoint Mean Distance to midpoint
#> 1     sp1                        -0.50820192                -0.4896199
#> 2     sp2                        -0.12253919                -0.1470435
#> 3     sp3                        -0.84093748                -0.8298832
#> 4     sp4                        -0.65172785                -0.6818160
#> 5     sp5                        -0.07626174                -0.1050365
#> 6     sp6                        -0.95462516                -0.9441664
#>   Minimum Zero Distance Minimum 20% Zero Distance Distance to MCP border
#> 1             0.4618802                 1.1195434              1.2701706
#> 2             0.8164966                 1.2218190              1.5011107
#> 3             0.3265986                 0.8310473              0.7745967
#> 4             0.2309401                 0.9311691              1.0392305
#> 5             0.8082904                 1.2360965              1.6041613
#> 6             0.2309401                 0.7661288              0.6733003
#>   Frequency Weighted Distance
#> 1                   0.8225743
#> 2                   0.6921972
#> 3                   1.0446166
#> 4                   0.9069837
#> 5                   0.6857976
#> 6                   1.1319803

This produces a data frame in which each row corresponds to a species, and each column corresponds to the mean descriptor value across the cells where that species occurs. `

Linking attribute space to geographic space

When a geographic PAM generated by lets.presab() is supplied through the y argument, lets.attrcells() links the species occurring in each attribute cell to the geographic cells occupied by those species. This enables the computation of additional descriptors in geographic space.

data("PAM")

n <- length(PAM$Species_name)
Species <- PAM$Species_name
trait_a <- rnorm(n)
trait_b <- trait_a * 0.2 + rnorm(n)
df <- data.frame(Species, trait_a, trait_b)

x <- lets.attrpam(df, n_bins = 4)

cell_desc_geo <- lets.attrcells(x, y = PAM)
head(cell_desc_geo)
#>   Cell_attr Frequency         Area Isolation (Min.) Isolation (1st Qu.)
#> 3         1       625 7.610774e+12        101354.56            995744.9
#> 4         2         0 0.000000e+00             0.00                 0.0
#> 5         3       104 1.277753e+12        101354.56            435455.5
#> 6         4        15 1.822784e+11        110577.35            156797.2
#> 7         5        72 8.858890e+11         96965.99            322461.4
#> 8         6       497 6.048791e+12         91839.61            857643.9
#>   Isolation (Median) Isolation (Mean) Isolation (3rd Qu.) Isolation (Max.)
#> 3          1642232.9        1747128.1           2384391.6          4749476
#> 4                0.0              0.0                 0.0                0
#> 5           672554.2         722752.7            942685.7          2959492
#> 6           331739.8         644769.6            663456.3          2894931
#> 7           491756.2         513232.8            686374.2          1284485
#> 8          1352699.2        1517451.6           2012096.3          4548857
#>   Weighted Mean Distance to midpoint Mean Distance to midpoint
#> 3                         -1.5126554                -1.5627376
#> 4                         -1.0102709                -1.0708381
#> 5                         -1.1194498                -1.1624284
#> 6                         -1.7279145                -1.7480804
#> 7                         -1.1689967                -1.1913948
#> 8                         -0.3147603                -0.3520894
#>   Minimum Zero Distance Minimum 10% Zero Distance Distance to MCP border
#> 3             0.8660254                 0.8660254              0.0000000
#> 4             0.0000000                 0.0000000              0.0000000
#> 5             0.8660254                 0.8660254              0.0000000
#> 6             1.7320508                 1.7320508              0.0000000
#> 7             1.2247449                 1.2247449              0.8660254
#> 8             0.8660254                 0.8660254              0.8660254
#>   Frequency Weighted Distance
#> 3                    1.988764
#> 4                    1.385760
#> 5                    1.506749
#> 6                    1.928870
#> 7                    1.489442
#> 8                    1.181192

When y is provided, the output includes additional variables:

These variables allow direct integration of position in attribute space with occupancy and isolation patterns in geographic space.

The resulting descriptors can also be plotted:

lets.plot.attrcells(x, cell_desc_geo)

References

Vilela, B. & Villalobos, F. (2015). letsR: a new R package for data handling and analysis in macroecology. Methods in Ecology and Evolution, 6(10), 1229–1234.

mirror server hosted at Truenetwork, Russian Federation.