Skip to contents

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.

Usage

edge_zones(
  edges = NULL,
  zone_thresholds = NULL,
  zone_labels = NULL,
  blind_volume = NULL
)

Arguments

edges

distance based edge-list generated by edge_dist, optionally with direction columns from direction_step and edge_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:

  1. direction_step(DT)

  2. edges <- edge_dist(DT)

  3. dyad_id(edges)

  4. dyad_directions <- edge_direction(edges, DT)

  5. 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:

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]