edge_zones
returns edge-lists defined by behavioural zones (Couzin
2002). The function expects a distance based edge-list generated by
edge_dist
(optionally with directions measured by
direction_step
and edge_direction
), zone thresholds, labels
and (optionally) a blind volume.
Arguments
- edges
distance based edge-list generated by
edge_dist
, optionally with direction columns fromdirection_step
andedge_direction
(see Details)- zone_thresholds
upper thresholds to define behavioural zones, eg. c(10, 20, 30) defines behavioural zones (0-10], (10-20], (20-30]
- zone_labels
labels for zones defined by zone_thresholds, must match zone_thresholds in length
- blind_volume
(optional) interindividual direction to define symmetrical window outside of focal individual's perception, eg. 2 becomes (-2, 2), see Details
Value
edge_zones
returns the input edges
appended with a zone
column indicating the behavioural zone, using the zone label provided.
See details for appending outputs using modify-by-reference in the FAQ.
A message is returned when a zone column already exists in the input
edges
, because it will be overwritten.
Details
edge_zones
uses interindividual distances, and optionally directions,
to assign neighboring individuals to a focal individual's behavioural zones.
The user provides zone thresholds (eg. 25 m, 100 m, 250 m) along with zone
labels (eg. zone of repulsion, zone of orientation, zone of attraction),
according to their objectives, study species and system. The optional blind
volume can be provided to define a range of interindividual directions that
correspond to the limits of the focal individual's perception.
Two workflows for this function exist, depending on if the blind volume argument is used:
a) If the blind volume is not provided, simply provide your distance based
edge-lists from edge_dist
with zone thresholds and labels.
b) If the blind volume is provided, the following order of functions is
expected to ensure the relevant direction columns are available:
direction_step(DT)
edges <- edge_dist(DT)
dyad_id(edges)
dyad_directions <- edge_direction(edges, DT)
edge_zones(dyad_directions)
Interindividual distances are converted into behavioural zones using
cut
. The thresholds provided are used as cut points for a series of
intervals that are open on the left and closed on the right, starting at 0.
See details in base::cut()
.
The (optional) blind volume defines the range of interindividual directions
between the focal individual (ID1) and the neighbour (ID2) that is outside
of the focal individual's perception. The interindividual direction (column
"direction_dyad" from edge_direction
) is made relative to the focal
individual's movement direction (column "direction" from
direction_step
). The argument blind_volume expects a single value to
define a symmetrical window behind the focal individual's movement direction
eg. where blind_volume = 2, the symmetrical window is from (-2, 2).
The edges
must be a data.table
. If your data is a
data.frame
, you can convert it by reference using
data.table::setDT()
or by reassigning using
data.table::data.table()
.
References
The behavioural zones metric is defined in Couzin et al. 2002 (doi:10.1006/jtbi.2002.3065 ).
See examples of measuring behavioural zones:
See also
edge_dist direction_step edge_direction
Other Distance functions:
distance_to_centroid()
,
distance_to_leader()
,
edge_nn()
Other Direction functions:
direction_group()
,
direction_polarization()
,
direction_step()
,
direction_to_centroid()
,
direction_to_leader()
,
edge_alignment()
,
edge_delay()
,
edge_direction()
,
edge_dist()
,
leader_direction_group()
,
leader_edge_delay()
Examples
# Load data.table
library(data.table)
# Read example data
DT <- fread(system.file("extdata", "DT.csv", package = "spatsoc"))
# Cast the character column to POSIXct
DT[, datetime := as.POSIXct(datetime, tz = 'UTC')]
#> ID X Y datetime population
#> <char> <num> <num> <POSc> <int>
#> 1: A 715851.4 5505340 2016-11-01 00:00:54 1
#> 2: A 715822.8 5505289 2016-11-01 02:01:22 1
#> 3: A 715872.9 5505252 2016-11-01 04:01:24 1
#> 4: A 715820.5 5505231 2016-11-01 06:01:05 1
#> 5: A 715830.6 5505227 2016-11-01 08:01:11 1
#> ---
#> 14293: J 700616.5 5509069 2017-02-28 14:00:54 1
#> 14294: J 700622.6 5509065 2017-02-28 16:00:11 1
#> 14295: J 700657.5 5509277 2017-02-28 18:00:55 1
#> 14296: J 700610.3 5509269 2017-02-28 20:00:48 1
#> 14297: J 700744.0 5508782 2017-02-28 22:00:39 1
# Temporal grouping
group_times(DT, datetime = 'datetime', threshold = '20 minutes')
#> ID X Y datetime population minutes timegroup
#> <char> <num> <num> <POSc> <int> <int> <int>
#> 1: A 715851.4 5505340 2016-11-01 00:00:54 1 0 1
#> 2: A 715822.8 5505289 2016-11-01 02:01:22 1 0 2
#> 3: A 715872.9 5505252 2016-11-01 04:01:24 1 0 3
#> 4: A 715820.5 5505231 2016-11-01 06:01:05 1 0 4
#> 5: A 715830.6 5505227 2016-11-01 08:01:11 1 0 5
#> ---
#> 14293: J 700616.5 5509069 2017-02-28 14:00:54 1 0 1393
#> 14294: J 700622.6 5509065 2017-02-28 16:00:11 1 0 1394
#> 14295: J 700657.5 5509277 2017-02-28 18:00:55 1 0 1440
#> 14296: J 700610.3 5509269 2017-02-28 20:00:48 1 0 1395
#> 14297: J 700744.0 5508782 2017-02-28 22:00:39 1 0 1396
# Edge list generation
edges <- edge_dist(
DT,
threshold = 100,
id = 'ID',
coords = c('X', 'Y'),
timegroup = 'timegroup',
returnDist = TRUE,
fillNA = FALSE
)
# Calculate behavioural zones
edge_zones(
edges,
zone_thresholds = c(25, 50, 75),
zone_labels = c('repulsion', 'orientation', 'attraction')
)
#> timegroup ID1 ID2 distance zone
#> <int> <char> <char> <num> <fctr>
#> 1: 1 G B 5.782904 repulsion
#> 2: 1 H E 65.061671 attraction
#> 3: 1 B G 5.782904 repulsion
#> 4: 1 E H 65.061671 attraction
#> 5: 2 H E 79.659918 <NA>
#> ---
#> 17174: 1440 I C 2.831071 repulsion
#> 17175: 1440 C F 9.372972 repulsion
#> 17176: 1440 I F 7.512922 repulsion
#> 17177: 1440 C I 2.831071 repulsion
#> 17178: 1440 F I 7.512922 repulsion
# Alternatively, if a user wants to specify a blind volume,
# we need to measure directions
direction_step(
DT = DT,
id = 'ID',
coords = c('X', 'Y'),
crs = 32736
)
#> ID X Y datetime population minutes timegroup
#> <char> <num> <num> <POSc> <int> <int> <int>
#> 1: A 715851.4 5505340 2016-11-01 00:00:54 1 0 1
#> 2: A 715822.8 5505289 2016-11-01 02:01:22 1 0 2
#> 3: A 715872.9 5505252 2016-11-01 04:01:24 1 0 3
#> 4: A 715820.5 5505231 2016-11-01 06:01:05 1 0 4
#> 5: A 715830.6 5505227 2016-11-01 08:01:11 1 0 5
#> ---
#> 14293: J 700616.5 5509069 2017-02-28 14:00:54 1 0 1393
#> 14294: J 700622.6 5509065 2017-02-28 16:00:11 1 0 1394
#> 14295: J 700657.5 5509277 2017-02-28 18:00:55 1 0 1440
#> 14296: J 700610.3 5509269 2017-02-28 20:00:48 1 0 1395
#> 14297: J 700744.0 5508782 2017-02-28 22:00:39 1 0 1396
#> direction
#> <units>
#> 1: -2.65649015 [rad]
#> 2: 2.17592086 [rad]
#> 3: -1.98432277 [rad]
#> 4: 1.90650150 [rad]
#> 5: -0.04059949 [rad]
#> ---
#> 14293: 2.10901157 [rad]
#> 14294: 0.13663566 [rad]
#> 14295: -1.78096501 [rad]
#> 14296: 2.84652173 [rad]
#> 14297: NA [rad]
# Edge list generation
edges <- edge_dist(
DT,
threshold = 100,
id = 'ID',
coords = c('X', 'Y'),
timegroup = 'timegroup',
returnDist = TRUE,
fillNA = FALSE
)
# Generate dyad id
dyad_id(edges, id1 = 'ID1', id2 = 'ID2')
#> timegroup ID1 ID2 distance dyadID
#> <int> <char> <char> <num> <char>
#> 1: 1 G B 5.782904 B-G
#> 2: 1 H E 65.061671 E-H
#> 3: 1 B G 5.782904 B-G
#> 4: 1 E H 65.061671 E-H
#> 5: 2 H E 79.659918 E-H
#> ---
#> 17174: 1440 I C 2.831071 C-I
#> 17175: 1440 C F 9.372972 C-F
#> 17176: 1440 I F 7.512922 F-I
#> 17177: 1440 C I 2.831071 C-I
#> 17178: 1440 F I 7.512922 F-I
# Interindividual directions
dyad_directions <- edge_direction(
edges,
DT,
id = 'ID',
coords = c('X', 'Y'),
crs = 32736,
timegroup = 'timegroup'
)
# Calculate behavioural zones
edge_zones(
dyad_directions,
zone_thresholds = c(25, 50, 75),
zone_labels = c('repulsion', 'orientation', 'attraction'),
blind_volume = 2
)
#> timegroup ID1 ID2 dyadID distance direction
#> <int> <char> <char> <char> <num> <units>
#> 1: 1 G B B-G 5.782904 -1.360181 [rad]
#> 2: 1 H E E-H 65.061671 -2.176427 [rad]
#> 3: 1 B G B-G 5.782904 -1.340945 [rad]
#> 4: 1 E H E-H 65.061671 -2.997704 [rad]
#> 5: 2 H E E-H 79.659918 -1.247578 [rad]
#> ---
#> 17174: 1440 I C C-I 2.831071 1.201647 [rad]
#> 17175: 1440 C F C-F 9.372972 1.093179 [rad]
#> 17176: 1440 I F F-I 7.512922 1.201647 [rad]
#> 17177: 1440 C I C-I 2.831071 1.093179 [rad]
#> 17178: 1440 F I F-I 7.512922 1.171399 [rad]
#> direction_dyad zone
#> <units> <fctr>
#> 1: 0.932704118 [rad] blind
#> 2: -2.236466737 [rad] attraction
#> 3: -2.208889158 [rad] repulsion
#> 4: 0.905132780 [rad] blind
#> 5: 3.015321726 [rad] <NA>
#> ---
#> 17174: 2.145953261 [rad] repulsion
#> 17175: -0.262152781 [rad] repulsion
#> 17176: -0.007124986 [rad] repulsion
#> 17177: -0.995639711 [rad] blind
#> 17178: 3.134467675 [rad] repulsion
print(dyad_directions[, .SD[1:3], by = zone])
#> zone timegroup ID1 ID2 dyadID distance direction
#> <fctr> <int> <char> <char> <char> <num> <units>
#> 1: blind 1 G B B-G 5.782904 -1.3601809 [rad]
#> 2: blind 1 E H E-H 65.061671 -2.9977039 [rad]
#> 3: blind 4 G B B-G 21.129001 2.6080387 [rad]
#> 4: attraction 1 H E E-H 65.061671 -2.1764270 [rad]
#> 5: attraction 8 G B B-G 51.547342 1.3768655 [rad]
#> 6: attraction 9 B G B-G 66.724550 -2.0891759 [rad]
#> 7: repulsion 1 B G B-G 5.782904 -1.3409449 [rad]
#> 8: repulsion 4 B G B-G 21.129001 2.9834377 [rad]
#> 9: repulsion 4 E H E-H 11.961466 -0.4069487 [rad]
#> 10: <NA> 2 H E E-H 79.659918 -1.2475775 [rad]
#> 11: <NA> 2 E H E-H 79.659918 0.3979917 [rad]
#> 12: <NA> 3 H E E-H 84.345303 2.0780751 [rad]
#> 13: orientation 5 H E E-H 31.498449 -1.9542746 [rad]
#> 14: orientation 6 G B B-G 27.816927 2.1861675 [rad]
#> 15: orientation 6 B G B-G 27.816927 2.0805732 [rad]
#> direction_dyad
#> <units>
#> 1: 0.9327041 [rad]
#> 2: 0.9051328 [rad]
#> 3: -0.5080933 [rad]
#> 4: -2.2364667 [rad]
#> 5: 0.7594540 [rad]
#> 6: -1.9736797 [rad]
#> 7: -2.2088892 [rad]
#> 8: 2.6335007 [rad]
#> 9: 1.0767375 [rad]
#> 10: 3.0153217 [rad]
#> 11: -0.1262723 [rad]
#> 12: 1.8450857 [rad]
#> 13: -0.8990115 [rad]
#> 14: -2.5959567 [rad]
#> 15: 0.5456379 [rad]