This vignette shows how to compute neighborhood basal area with
calba. We start from a simple simulated plot, then use
neigh_ba() for model-ready summaries. We then illustrate
multiple radii, low-level helper functions, and basic edge correction
options.
Simulate a modest plot with 500 trees, four species, 50x50 m extent, and basal areas between 20 and 200 (e.g., cm^2).
library(calba)
library(ggplot2)
set.seed(42)
side <- 50
n <- 500
trees <- data.frame(
species = sample(c("oak", "pine", "birch", "maple"), n, replace = TRUE),
gx = runif(n, 0, side),
gy = runif(n, 0, side),
ba = runif(n, 20, 200)
)
ggplot(trees, aes(gx, gy, col = species)) +
geom_point() +
coord_fixed() +
theme_bw()neigh_ba()neigh_ba() computes conspecific and total basal area,
neighbor counts, and derived metrics for a single radius.
Optionally, we can add decay-weighted summaries by supplying
mu_values. This appends a long table of distance-weighted
basal area for each decay parameter, which is returned in the
decay component.
nb <- neigh_ba(
sp = trees$species,
gx = trees$gx,
gy = trees$gy,
ba = trees$ba,
r = 5,
mu_values = c(2, 6)
)
head(nb$summary)## tree_id species con_ba total_ba con_count total_count prop_con_ba het_ba
## 1 1 oak 551.5438 2539.628 4 19 0.2171751 1988.0838
## 2 2 oak 232.2601 1534.218 3 14 0.1513866 1301.9581
## 3 3 oak 592.0395 1105.628 6 12 0.5354780 513.5886
## 4 4 oak 509.0855 1245.698 6 12 0.4086749 736.6124
## 5 5 pine 601.2436 2226.411 5 19 0.2700506 1625.1673
## 6 6 maple 394.3903 1969.297 4 17 0.2002696 1574.9068
## het_count competition_index
## 1 15 133.66461
## 2 11 109.58701
## 3 6 92.13568
## 4 6 103.80816
## 5 14 117.17952
## 6 13 115.84101
We can inspect the full structure of the returned object:
## List of 2
## $ summary:'data.frame': 500 obs. of 10 variables:
## ..$ tree_id : int [1:500] 1 2 3 4 5 6 7 8 9 10 ...
## ..$ species : chr [1:500] "oak" "oak" "oak" "oak" ...
## ..$ con_ba : num [1:500] 552 232 592 509 601 ...
## ..$ total_ba : num [1:500] 2540 1534 1106 1246 2226 ...
## ..$ con_count : num [1:500] 4 3 6 6 5 4 6 8 1 1 ...
## ..$ total_count : num [1:500] 19 14 12 12 19 17 19 23 9 17 ...
## ..$ prop_con_ba : num [1:500] 0.217 0.151 0.535 0.409 0.27 ...
## ..$ het_ba : num [1:500] 1988 1302 514 737 1625 ...
## ..$ het_count : num [1:500] 15 11 6 6 14 13 13 15 8 16 ...
## ..$ competition_index: num [1:500] 133.7 109.6 92.1 103.8 117.2 ...
## $ decay :'data.frame': 1000 obs. of 5 variables:
## ..$ tree_id : int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...
## ..$ species : chr [1:1000] "oak" "oak" "oak" "oak" ...
## ..$ mu : num [1:1000] 2 2 2 2 2 2 2 2 2 2 ...
## ..$ con_ba : num [1:1000] 157.6 61.1 88.1 102.4 115.8 ...
## ..$ total_ba: num [1:1000] 692 554 180 204 381 ...
nb$decay is a long table of decay-weighted basal area for each mu.
## tree_id species mu con_ba total_ba
## 1 1 oak 2 157.61987 692.3895
## 2 2 oak 2 61.13062 554.2654
## 3 3 oak 2 88.08783 180.0602
## 4 4 oak 2 102.40837 203.6150
## 5 5 pine 2 115.84979 380.6603
## 6 6 maple 2 62.66209 491.2417
Use edge_correction = "safe" to return NA for focal
trees within r of the plot boundary. By default, bounds are the min and
max of gx and gy. Supply bounds = c(xmin, xmax, ymin, ymax) if your plot
is larger than the observed coordinates.
nb_bounds <- neigh_ba(
sp = trees$species,
gx = trees$gx,
gy = trees$gy,
ba = trees$ba,
r = 5,
edge_correction = "safe",
bounds = c(0, 50, 0, 50)
)$summary
head(nb_bounds)## tree_id species con_ba total_ba con_count total_count prop_con_ba het_ba
## 1 1 oak 551.5438 2539.628 4 19 0.2171751 1988.0838
## 2 2 oak NA NA NA NA NA NA
## 3 3 oak 592.0395 1105.628 6 12 0.5354780 513.5886
## 4 4 oak 509.0855 1245.698 6 12 0.4086749 736.6124
## 5 5 pine 601.2436 2226.411 5 19 0.2700506 1625.1673
## 6 6 maple NA NA NA NA NA NA
## het_count competition_index
## 1 15 133.66461
## 2 NA NA
## 3 6 92.13568
## 4 6 103.80816
## 5 14 117.17952
## 6 NA NA
Then in Low-level helpers you keep the detailed
explanation of the exponential and exponential-normal kernels and the
ba_decay() code.
neigh_multi_r()Reuse a single distance structure across radii.
multi <- neigh_multi_r(
sp = trees$species,
gx = trees$gx,
gy = trees$gy,
ba = trees$ba,
r_values = c(3, 5, 10),
dist_weighted = FALSE
)
multi_r5 <- subset(multi, radius == 5)
head(multi_r5)## tree_id species radius con_ba total_ba con_count total_count prop_con_ba
## 501 1 oak 5 551.5438 2539.628 4 19 0.2171751
## 502 2 oak 5 232.2601 1534.218 3 14 0.1513866
## 503 3 oak 5 592.0395 1105.628 6 12 0.5354780
## 504 4 oak 5 509.0855 1245.698 6 12 0.4086749
## 505 5 pine 5 601.2436 2226.411 5 19 0.2700506
## 506 6 maple 5 394.3903 1969.297 4 17 0.2002696
## het_ba het_count competition_index
## 501 1988.0838 15 133.66461
## 502 1301.9581 11 109.58701
## 503 513.5886 6 92.13568
## 504 736.6124 6 103.80816
## 505 1625.1673 14 117.17952
## 506 1574.9068 13 115.84101
calba provides several lower-level functions used by
neigh_ba() and neigh_multi_r():
ba_simple() for unweighted or distance-weighted basal
area at one radiusba_decay() for decay kernels (exponential or
exponential-normal)count_con() and count_total() for neighbor
countsba_decay()ba_decay() computes distance–weighted basal area using
either of two kernels.
Exponential:
\[ w(d, \mu) = \exp\left(-\frac{d}{\mu}\right) \]
Exponential-normal (Gaussian in distance):
\[ w(d, \mu) = \exp\left(-\frac{d^2}{\mu^2}\right) \]
Neighbors contribute ba * w(d, mu) to the focal tree,
where d is Euclidean distance and mu controls
the decay scale.
mu_vals <- c(2, 6)
decay_exp <- ba_decay(
mu_values = mu_vals,
sp = trees$species,
gx = trees$gx,
gy = trees$gy,
ba = trees$ba,
r = 5,
exponential_normal = FALSE
)
head(decay_exp$con_ba_matrix)## [,1] [,2]
## [1,] 157.61987 334.6172
## [2,] 61.13062 143.7360
## [3,] 88.08783 306.0831
## [4,] 102.40837 281.1512
## [5,] 115.84979 342.8400
## [6,] 62.66209 210.8749
decay_expnorm <- ba_decay(
mu_values = mu_vals,
sp = trees$species,
gx = trees$gx,
gy = trees$gy,
ba = trees$ba,
r = 5,
exponential_normal = TRUE
)
head(decay_expnorm$con_ba_matrix)## [,1] [,2]
## [1,] 141.78479 394.8385
## [2,] 52.13371 177.6364
## [3,] 30.15202 375.5627
## [4,] 77.55324 338.8034
## [5,] 52.24974 433.3304
## [6,] 19.18204 263.5829
ba_simple_out <- ba_simple(
sp = trees$species,
gx = trees$gx,
gy = trees$gy,
ba = trees$ba,
r = 5,
dist_weighted = TRUE
)
str(ba_simple_out)## List of 2
## $ con_ba : num [1:500] 315.2 91.1 156 169.9 184.3 ...
## $ total_ba: num [1:500] 1328 1224 307 356 668 ...