Detects corridor behaviour by finding segments where the animal moves quickly in a spatially consistent direction. Corridors are characterised by high segment speed combined with low circular variance of travel direction among spatially neighbouring segments.
Usage
mt_corridor(
x,
speed_threshold = NULL,
circvar_threshold = NULL,
min_segments = 2L,
verbose = FALSE
)Arguments
- x
A
move2object. Multi-track input is handled track-by-track viamove2::mt_segments(); the input may be in any CRS (geographic or projected). Rows with empty geometries are dropped from the computation with an informational notice and re-padded withNAin the output.- speed_threshold
Numeric. Per-segment speed (metres / second) at or above which a segment is "fast." If
NULL(default), the 0.75 quantile of within-object segment speeds is used and a warning names the resolved value.- circvar_threshold
Numeric in
[0, 1]. Circular variance of pseudo-azimuths within a segment's neighbourhood at or below which the segment is "directionally consistent." IfNULL(default), the 0.25 quantile of valid within-object circular variances is used and a warning names the resolved value.- min_segments
Integer. Minimum number of qualifying neighbours required for a segment to be classified as a corridor (default 2).
- verbose
Logical. If
TRUE, prints a one-line summary of how many segments were flagged. DefaultFALSE. Independent of the default-threshold, irregular-sampling, and empty-geometry notices, which are shown regardless.
Value
The input move2 object with five added columns, each of
length nrow(x):
corridorfactor with levels
"corridor"and"not corridor".corridor_speedper-segment speed (m/s).
corridor_azimuthper-segment travel azimuth (degrees).
corridor_circvarcircular variance of pseudo-azimuths within the neighbourhood.
corridor_n_neighboursnumber of segments found within the search radius.
Track-final rows, rows with empty geometries, and segments whose
neighbourhood circular variance cannot be computed all carry NA
in the per-segment columns; their corridor factor level is
"not corridor".
Details
The algorithm:
Build per-segment linestrings with
move2::mt_segments()and take their midpoints withsf::st_line_interpolate(). Both are track-aware; cross-track midpoints are never produced.For each segment, find all other midpoints within its own half-length search radius via an
sfspatial index (R-tree). The search uses the input CRS if projected, or a local azimuthal-equidistant projection (move2::mt_aeqd_crs()) if the input is in longitude/latitude.Compute a pseudo-azimuth (
(2 * azimuth) mod 2*pi, working in radians) so parallel opposite directions collapse onto the same value: animals walking north and south along the same corridor are treated as directionally consistent.Compute the circular variance of pseudo-azimuths within each neighbourhood.
Flag a segment as corridor if its speed is at least
speed_threshold, its circular variance is at mostcircvar_threshold, and the corridor-qualifying neighbours within its search radius outnumber the non-qualifying ones (at leastmin_segmentsqualifying neighbours required).
Thresholds are user-supplied. When either is left as NULL the
function falls back to a within-object quantile (0.75 of segment
speeds; 0.25 of valid circular variances) and emits a warning
naming the resolved numeric. For comparable corridor maps across
individuals or populations, supply explicit thresholds: e.g.
speed_threshold = quantile(as.numeric(mt_speed(all_tracks, units = "m/s")), 0.75, na.rm = TRUE) computed once on the pooled
cohort and reused per individual.
This is a port of the move::corridor() concept (LaPoint et al. 2013)
to the move2 / sf stack, using modern spatial indexing.
References
LaPoint S, Gallery P, Wikelski M, Kays R (2013). Animal behavior, cost-based corridor models, and real corridors. Landscape Ecology, 28, 1615–1630. doi:10.1007/s10980-013-9910-0
Examples
if (FALSE) { # \dontrun{
library(move2)
fishers <- mt_read(mt_example())
out <- mt_corridor(fishers)
table(out$corridor)
## fixed thresholds for cross-individual comparability:
all_speeds <- as.numeric(mt_speed(fishers, units = "m/s"))
out2 <- mt_corridor(
fishers,
speed_threshold = stats::quantile(all_speeds, 0.75, na.rm = TRUE),
circvar_threshold = 0.2
)
} # }