Exercise_Week_5

Author

Céline Spitzli

Task Week 5

Task 1: Write your own functions

Input:  is the same as the word function

Task: Create 2 functions:

A function which calculates a persons BMI based on their height and weight weight = kilogram height = m

BMI <- function(weight_kg, height_m){
  weight_kg / ((height_m)^2)
}

BMI(100, 1.80)
[1] 30.8642

A function which converts degrees Celcius to Farenheight

Celsius_to_Farenheight <- function(celsius){
  (celsius * (9/5)) + 32
}

Celsius_to_Farenheight(20)
[1] 68

A function which calculates the (Euclidean) distance between two sets of coordinates (x1, y1 and x2,y2)

euclidean_distance <- \(x1,x2,y1,y2){
  sqrt((x2-x1)^2 + (y2-y1)^2)
}

euclidean_distance(1,4,2,5)
[1] 4.242641

Task 2: Prepare Analysis

In the next tasks we will look for “meet” patterns in our wild boar data. To simplify this, we will only use a subset of our wild boar data: The individuals Rosa and Sabi for the timespan 01.04.2015 - 15.04.2015. Use the dataset wildschwein_BE_2056.csv (on moodle). Import the csv as a data.frame and filter it with the aforementioned criteria. You do not need to convert the data.frame to an sf object.

library(readr)
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
wildschwein_alle <- read.delim("wildschwein_BE_2056.csv", ",", header = T)

wildschwein_filter <- wildschwein_alle |> 
  filter(TierName %in% c("Rosa", "Sabi") &
  DatetimeUTC >= "2015-04-01" &
    DatetimeUTC <= "2015-04-15")

Task 3: Create Join Key

Have a look at your dataset. You will notice that samples are taken at every full hour, quarter past, half past and quarter to. The sampling time is usually off by a couple of seconds.

To compare Rosa and Sabi’s locations, we first need to match the two animals temporally. For that we can use a join, but need identical time stamps to serve as a join key. We therefore need to slightly adjust our time stamps to a common, concurrent interval.

The task is therefore to round the minutes of DatetimeUTC to a multiple of 15 (00, 15, 30,45) and store the values in a new column1. You can use the lubridate function round_date() for this. See the examples here to see how this goes.

library(lubridate)

Attaching package: 'lubridate'
The following objects are masked from 'package:base':

    date, intersect, setdiff, union
wildschwein_filter$DatetimeUTC <- as.POSIXct(wildschwein_filter$DatetimeUTC, format = "%Y-%m-%dT%H:%M:%OSZ", tz="UTC")

wildschwein_filter <- wildschwein_filter |> 
  mutate(DateTimeRound = round_date(DatetimeUTC, unit = "minutes")
  )

Task 4: Measuring distance at concurrent locations

To measure the distance between concurrent locations, we need to follow the following steps.

  1. Split the wildschwein_filter object into one data.frame per animal
  2. Join2 these datasets by the new Datetime column created in the last task. The joined observations are temporally close.
  3. In the joined dataset, calculate Euclidean distances between concurrent observations and store the values in a new column
  4. Use a reasonable threshold on distance to determine if the animals are also spatially close enough to constitute a meet (we use 100 meters). Store this Boolean information (TRUE/FALSE) in a new column
# Split Rosa and Sabi in two data frames

sabi <- wildschwein_filter |> 
  filter(TierName %in% "Sabi")

rosa <- wildschwein_filter |> 
  filter(TierName %in% "Rosa")

# Join Sabi and Rosa via DateTimeRound

wildschwein_joined <- inner_join(rosa, sabi, by = "DateTimeRound", suffix = c("_Rosa", "_Sabi"))

# Function for Euclidean Distance
euclidean_distance <- function(wildschwein_joined){
  sqrt((wildschwein_joined$E_Rosa - wildschwein_joined$E_Sabi)^2 + (wildschwein_joined$N_Rosa - wildschwein_joined$N_Sabi)^2)
}

# apply for Rosa and Sabi
wildschwein_joined$Eu_distance <- euclidean_distance(wildschwein_joined)

# Meeting yes or no

wildschwein_joined <- wildschwein_joined |> 
  mutate(
    is_meeting = Eu_distance <= 100 # True if distance is 100m or less
  )

Task 5: Visualize data

Now, visualize the meets spatially in a way that you think reasonable. For example in the plot as shows below. To produce this plot we:

  • Used the individual dataframes from rosa and sabi (from the previous task)
  • Used the joined dataset (also from the previous task), filtered to only the meets
  • Manually changed the x and y axis limits
library(ggplot2)

meets_data <- wildschwein_joined |> filter(is_meeting == TRUE)

ggplot() +
  geom_point(data = rosa, aes(E,N, colour = "Rosa"), alpha = 0.2) +
  geom_point(data = sabi, aes(E,N, colour = "Sabi"), alpha = 0.2) +
  geom_point(data = meets_data, aes(x = E_Rosa, y = N_Rosa, colour = "Meets"), shape = 21, fill = "NA", size = 3, stroke = 1) +
   scale_color_manual(values = c("Rosa" = "red", "Sabi" = "cyan", "Meets" = "black")) +
  labs(colour = "Regular Locations") +
  theme_minimal()

Task 6 (optional): Visualize data as timecube with plotly

Finally, you can nicely visualize the meeting patterns and trajectories in a Space-Time-Cube (Hägerstraand 1970) with the package plotly. There are some nice ressources available online.

library(plotly)

Attaching package: 'plotly'
The following object is masked from 'package:ggplot2':

    last_plot
The following object is masked from 'package:stats':

    filter
The following object is masked from 'package:graphics':

    layout
# Angenommen, "wildschwein_joined" enthält die Spalten für E (Easting), N (Northing), und Datetime
# Konvertiere den Datetime in eine numerische Form (Zeitstempel für die z-Achse)
wildschwein_joined <- wildschwein_joined |> 
  mutate(time_numeric = as.numeric(DatetimeUTC_Rosa))

# 3D Space-Time-Cube Plot erstellen
plot_ly() |> 
  # Rosa's Trajektorie (rote Linie)
  add_trace(
    data = rosa, type = 'scatter3d',  x = ~E, y = ~N, z = ~(DateTimeRound), mode = "lines", name = "Rosa") |> 
  # Sabi's Trajektorie (blaue Linie)
  add_trace(
    data = sabi, type = 'scatter3d',  x = ~E, y = ~N, z = ~(DateTimeRound), mode = "lines", name = "Sabi") |> 
  # Treffen (Meets) als schwarze Punkte
  add_trace(
    data = meets_data, type = 'scatter3d',  x = ~E_Rosa, y = ~N_Rosa, z = ~(DateTimeRound), mode = "points", name = "Meets") |> 
  # Layout und Achsen benennen
  layout(
    title = 'Space-Time Cube: Rosa & Sabi Meets',
    scene = list(
      xaxis = list(title = 'Easting (E)'),
      yaxis = list(title = 'Northing (N)'),
      zaxis = list(title = 'Time (DateTime)'),
      aspectmode = 'cube'
    )
  )
# Filtering Date between 2015-04-01 and 2015-04-04
sabi_14 <- sabi |> 
  filter(
    DateTimeRound >= "2015-04-01" &
      DateTimeRound <= "2015-04-04"
  )

rosa_14 <- rosa |> 
  filter(
    DateTimeRound >= "2015-04-01" &
      DateTimeRound <= "2015-04-04"
  )

# new plotly
# 3D Space-Time-Cube Plot erstellen
plot_ly() |> 
  # Rosa's Trajektorie (rote Linie)
  add_trace(
    data = rosa_14, type = 'scatter3d',  x = ~E, y = ~N, z = ~(DateTimeRound), mode = "lines", name = "Rosa") |> 
  # Sabi's Trajektorie (blaue Linie)
  add_trace(
    data = sabi_14, type = 'scatter3d',  x = ~E, y = ~N, z = ~(DateTimeRound), mode = "lines", name = "Sabi") |> 
  # Treffen (Meets) als schwarze Punkte
  add_trace(
    data = meets_data, type = 'scatter3d',  x = ~E_Rosa, y = ~N_Rosa, z = ~(DateTimeRound), mode = "points", name = "Meets") |> 
  # Layout und Achsen benennen
  layout(
    title = 'Space-Time Cube: Rosa & Sabi Meets',
    scene = list(
      xaxis = list(title = 'Easting (E)'),
      yaxis = list(title = 'Northing (N)'),
      zaxis = list(title = 'Time (DateTime)'),
      aspectmode = 'cube'
    )
  )