Exercise 4A

Exercise 4A

Libraries

library("sf")
Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; sf_use_s2() is TRUE
library("dplyr")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
library("readr")
library(ggplot2)

Read Data

wildschwein <- read_delim("wildschwein_BE_2056.csv", ",")
Rows: 51246 Columns: 6
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): TierID, TierName
dbl  (3): CollarID, E, N
dttm (1): DatetimeUTC

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ruth <- wildschwein |>
    st_as_sf(coords = c("E", "N"), crs = 2056, remove = FALSE) |> # remove = F Keeps "E" and "N" columns
    filter(
      TierName == "Ruth", 
      DatetimeUTC >= "2015-07-01", 
      DatetimeUTC < "2015-07-03"
      )

Visualize

ggplot(ruth) +
  geom_sf() +
  geom_path(aes(E,N))

Task 1: Calculate distances to previous/next fixes

Fixes are taken every 15 minutes. Calculate: pos[n-3] to pos[n] pos[n-2] to pos[n] pos[n-1] to pos[n] pos[n] to pos[n+1] pos[n] to pos[n+2] pos[n] to pos[n+3]

Function

distance_by_element <- function(later, now) {
  as.numeric(
    st_distance(later, now, by_element = TRUE)
  )
}

Store distances

ruth <- ruth |>
    mutate(
        nMinus3 = distance_by_element(lag(geometry, 3), geometry),  # distance to pos -45 minutes
        nMinus2 = distance_by_element(lag(geometry, 2), geometry),  # distance to pos -30 minutes
        nMinus1 = distance_by_element(lag(geometry, 1), geometry),  # distance to pos -15 minutes
        nPlus1  = distance_by_element(geometry, lead(geometry, 1)), # distance to pos +15 mintues
        nPlus2  = distance_by_element(geometry, lead(geometry, 2)),  # distance to pos +30 minutes
        nPlus3  = distance_by_element(geometry, lead(geometry, 3))  # distance to pos +45 minutes
    )

Calculate mean distance

ruth <- ruth |>
    rowwise() |> # rowwise, because it cannot be calculated for rows with NAs
    mutate(
        stepMean = mean(c(nMinus3, nMinus2, nMinus1, nPlus1, nPlus2, nPlus3))
    ) |>
    ungroup()

ruth
Simple feature collection with 180 features and 13 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: 2568161 ymin: 1205617 xmax: 2570123 ymax: 1207095
Projected CRS: CH1903+ / LV95
# A tibble: 180 × 14
   TierID TierName CollarID DatetimeUTC                E        N
   <chr>  <chr>       <dbl> <dttm>                 <dbl>    <dbl>
 1 018A   Ruth        13974 2015-06-30 22:01:14 2570123. 1206473.
 2 018A   Ruth        13974 2015-06-30 22:15:32 2570031. 1206402.
 3 018A   Ruth        13974 2015-06-30 22:31:41 2569584. 1206247.
 4 018A   Ruth        13974 2015-06-30 22:46:38 2569207. 1206117.
 5 018A   Ruth        13974 2015-06-30 23:01:46 2568947. 1206275.
 6 018A   Ruth        13974 2015-06-30 23:16:39 2568911. 1206339.
 7 018A   Ruth        13974 2015-06-30 23:30:22 2568992. 1206293.
 8 018A   Ruth        13974 2015-06-30 23:45:09 2568914. 1206338.
 9 018A   Ruth        13974 2015-07-01 00:00:13 2568906. 1206297.
10 018A   Ruth        13974 2015-07-01 00:15:41 2568951. 1206308.
# ℹ 170 more rows
# ℹ 8 more variables: geometry <POINT [m]>, nMinus3 <dbl>, nMinus2 <dbl>,
#   nMinus1 <dbl>, nPlus1 <dbl>, nPlus2 <dbl>, nPlus3 <dbl>, stepMean <dbl>

Task 2: Specify threshold

summary(ruth)
    TierID            TierName            CollarID    
 Length:180         Length:180         Min.   :13974  
 Class :character   Class :character   1st Qu.:13974  
 Mode  :character   Mode  :character   Median :13974  
                                       Mean   :13974  
                                       3rd Qu.:13974  
                                       Max.   :13974  
                                                      
  DatetimeUTC                          E                 N          
 Min.   :2015-06-30 22:01:14.0   Min.   :2568162   Min.   :1205617  
 1st Qu.:2015-07-01 09:27:08.5   1st Qu.:2568471   1st Qu.:1205917  
 Median :2015-07-01 22:23:19.0   Median :2568877   Median :1206042  
 Mean   :2015-07-01 22:03:18.7   Mean   :2568801   Mean   :1206102  
 3rd Qu.:2015-07-02 10:35:05.5   3rd Qu.:2568919   3rd Qu.:1206090  
 Max.   :2015-07-02 21:46:01.0   Max.   :2570123   Max.   :1207095  
                                                                    
          geometry      nMinus3             nMinus2         
 POINT        :180   Min.   :   0.7328   Min.   :   0.3887  
 epsg:2056    :  0   1st Qu.:   5.3496   1st Qu.:   4.7802  
 +proj=some...:  0   Median :  21.6565   Median :  15.6777  
                     Mean   : 146.1967   Mean   : 108.7790  
                     3rd Qu.: 137.1378   3rd Qu.:  71.0626  
                     Max.   :1370.0820   Max.   :1339.5191  
                     NA's   :3           NA's   :2          
    nMinus1              nPlus1              nPlus2         
 Min.   :   0.1296   Min.   :   0.1296   Min.   :   0.3887  
 1st Qu.:   4.4568   1st Qu.:   4.4568   1st Qu.:   4.7802  
 Median :  11.6751   Median :  11.6751   Median :  15.6777  
 Mean   :  64.5200   Mean   :  64.5200   Mean   : 108.7790  
 3rd Qu.:  48.0356   3rd Qu.:  48.0356   3rd Qu.:  71.0626  
 Max.   :1155.2635   Max.   :1155.2635   Max.   :1339.5191  
 NA's   :1           NA's   :1           NA's   :2          
     nPlus3             stepMean      
 Min.   :   0.7328   Min.   :  1.708  
 1st Qu.:   5.3496   1st Qu.:  6.348  
 Median :  21.6565   Median : 23.815  
 Mean   : 146.1967   Mean   : 95.157  
 3rd Qu.: 137.1378   3rd Qu.:109.299  
 Max.   :1370.0820   Max.   :757.062  
 NA's   :3           NA's   :6        
ggplot(ruth, aes(x = stepMean)) +
  geom_histogram()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 6 rows containing non-finite outside the scale range
(`stat_bin()`).

ggplot(ruth, aes(y = stepMean)) +
  geom_boxplot()
Warning: Removed 6 rows containing non-finite outside the scale range
(`stat_boxplot()`).

Static points defined as the points for which stepMean is smaller than the average stepMean.

ruth <- ruth |>
    mutate(static = stepMean < mean(stepMean, na.rm = TRUE))

Task 3 Visualize trajectories

ruth |>
    ggplot(aes(E, N, colour = static)) + 
    geom_path() + 
    geom_point() +
    coord_fixed() +
    theme(legend.position = "bottom")

Task 4: Segment-based analysis

Function to assign ID to segments

rle_id <- function(vec) { #Input is a vector of the data frame (e.g. static)
    x <- rle(vec)$lengths
    as.factor(rep(seq_along(x), times = x))
}

Assign segement IDs to ruth

ruth <- ruth |>
    mutate(segment_id = rle_id(static))

Visualize moving segments colorizing segment IDs

ruth_filter <- ruth |>
    filter(!static)

ruth_filter |>
    ggplot(aes(E, N, colour = segment_id)) + 
    geom_path() + 
    geom_point() +
    coord_fixed() +
    theme(legend.position = "bottom")