We compared the daily trajectories of black capuchins in pine plantations vs INP to investigate how travel distances reflect movement patterns and ecological requirements in contrasting landscapes. The availability and spatial distribution of sleeping sites are recognized as critical factors influencing the daily movement patterns of arboreal primates, determining where individuals begin and end their activity periods (Fruth et al., 2018). To integrate this factor into our analysis, we calculated the straight-line distance between the morning and evening sleeping sites, which were defined as locations recorded within 15 min after sunrise or before sunset. Daily sunrise and sunset times were computed using the ‘suncalc’ R package (Thieurmel et al., 2019), ensuring temporal accuracy across the study period. Only complete tracking days were included in the analysis, defined as days with eight evenly spaced locations recorded at 90-minute intervals (±15 minutes), capturing the full extent of daily activity.
library(amt)
library(tidyverse)
library(sf)
library(adehabitatLT)
library(fitdistrplus)
library(cowplot)
library(lmtest)
library(MuMIn)
library(lme4)
library(caret)
library(flextable)
library(glmmTMB)
library(purrr)
library(showtext)
font_add("Calibri", "C:/Windows/Fonts/calibri.ttf")
font_add("Calibri Bold", "C:/Windows/Fonts/calibrib.ttf")
font_add("Calibri Italic", "C:/Windows/Fonts/calibrii.ttf")
showtext_auto()locs <- readRDS('files/hr.rds')%>%
rename (id = individual.local.identifier,
lat = location.lat,
lon = location.long,
t = timestamp)
locs <- locs %>%
mutate(
t = as.POSIXct(sprintf("%s-%02d-%02d %02d:%02d:%02d",
year,
month(t),
day(t),
hour(t),
minute(t),
second(t)),
tz = attr(t, "tzone")))
locs %>% group_by(area) %>% summarise(locations = n())Including the Shape file of Timber companies to have landscape features
shp <- st_read("files/UNION.shp")
crs_shp <- st_crs(shp)
locs_ara <- locs %>% filter (area == "Arauco")
locs_pni <- locs %>% filter (area == "PN Iguazu")
locs_ara_sf <- locs_ara %>%
st_as_sf(coords = c('lon', 'lat'),
crs = 4326) %>%
st_transform(crs_shp)
shp <- shp %>%
mutate(tipouso_grouped = ifelse(tipouso == "BNSM", "BNSM", "plantations")) %>%
mutate(sensibilidad = case_when(
tipouso == "PITA" & apl >= 2013 & apl <= 2017 ~ "sensible",
TRUE ~ "insensible"))
locs_ara_sf <- locs_ara_sf %>%
st_join(shp[, c("tipouso_grouped")])
locs_ara_sf <- st_transform(locs_ara_sf, 4326)
locs_ara2 <- locs_ara_sf %>%
mutate(lon = st_coordinates(.)[, 1],
lat = st_coordinates(.)[, 2]) %>%
st_drop_geometry()Unifying the processed data, and make Track XYT object
locs <- bind_rows(locs_ara2,locs_pni)
locs_track <- locs %>%
make_track(.x = lat,
.y = lon,
.t = t,
id = id,
year = year,
grupo = grupo,
month = month,
tipouso_grouped = tipouso_grouped,
area=area,
crs = 32721,
all_cols = TRUE)Continue with data processing
locs <- locs %>%
mutate(date = as.Date(t)) %>%
group_by(id, year, date) %>%
mutate(count_locs = n()) %>%
ungroup()
locs <- locs %>%
mutate(id = case_when(
id == "spo" & year == 2022 ~ "spo.22",
id == "spo" & year == 2014 ~ "spo.14",
TRUE ~ id))
locs <- locs %>%
mutate(
t = case_when(
id %in% c("col.oto", "gua.tilo", "pan.pri", "tri.pri", 'spo.22') ~ t - lubridate::hours(3),
TRUE ~ t ))
locs_clean <- locs %>%
filter(count_locs > 8)
intervals <- locs_clean %>%
group_by(id, year, date) %>%
arrange(t, .by_group = TRUE) %>%
mutate(
interval_minutes = as.numeric(difftime(t, lag(t), units = "mins"))
) %>%
ungroup()
intervals_filtered <- intervals %>% filter(!is.na(interval_minutes))
locs_clean_filtered <- intervals %>%
filter(is.na(interval_minutes) | interval_minutes <= 200) %>%
group_by(id, year, date) %>%
filter(lead(interval_minutes, default = 0) <= 200 | is.na(lead(interval_minutes))) %>%
ungroup()
locs_clean_filtered <- locs_clean_filtered %>%
mutate(
id2 = id,
id = paste0(tolower(substr(grupo, 1, 3)), ".",
tolower(substr(month, 1, 3)), ".",
substr(year, 3, 4)))
locs_clean_filtered <-
locs_clean_filtered %>%
mutate(date = as.Date(t)) %>%
group_by(id, date) %>%
arrange(t, .by_group = TRUE) %>%
mutate(
daily_track_min = as.numeric(difftime(max(t), min(t), units = "mins")),
daily_track_h = as.numeric(difftime(max(t), min(t), units = "hours"))
) %>%
ungroup()
locs_full_day <- locs_clean_filtered %>%
filter(daily_track_h > 8)
date_counts <- locs_full_day %>%
group_by(area, id) %>%
summarise(num_dates = n_distinct(date))
total_dates_by_area <- date_counts %>%
group_by(area) %>%
summarise(total_num_dates = sum(num_dates), .groups = "drop")
locs_clean_filtered <- locs_clean_filtered %>%
mutate(area = recode(area, "Arauco" = "Plantations", "PN Iguazu" = "INP"))ggplot(intervals_filtered, aes(x = interval_minutes)) +
geom_histogram(binwidth = 8, fill = "midnightblue", color = "black", alpha = 0.7) +
labs(
title = "Intervals between locations distribution",
x = "Interval (min)",
y = "Frequency") +
theme_minimal() +
theme(text = element_text(family = 'Calibri', size =34))we still have some big gaps in the data, intervals up to 400 min.
locs_full_day <- locs_clean_filtered %>%
filter(daily_track_h > 8)
date_counts <- locs_full_day %>%
group_by(area, id) %>%
summarise(num_dates = n_distinct(date))
total_dates_by_area <- date_counts %>%
group_by(area) %>%
summarise(total_num_dates = sum(num_dates), .groups = "drop")First I am creating the SF object to extract UTM coordinates (\(X\) and \(Y\)), using complex number then I obtain \(Z = X + iY\). The total daily trajectory includes the sum of all steps conducted within a same day. There are still some strange data that showed length above 7000 m, these days were removed becuase there were linked to location that not are from the monkeys (inside buildings for instance)
locs_sf <- locs_full_day %>%
st_as_sf(coords = c('lon', 'lat'), crs = 4326) %>%
st_transform(crs = 32721)
locs_sf_coords <- st_coordinates(locs_sf)
locs_full_day <- locs_full_day %>%
mutate(
X = locs_sf_coords[,"X"],
Y = locs_sf_coords[,"Y"],
Z = X + 1i * Y
)
steps_data <- locs_full_day %>%
group_by(area, id, date) %>%
arrange(t, .by_group = TRUE) %>%
mutate(S = c(Mod(diff(Z)), NA)) %>%
summarise(
mean_S = mean(S, na.rm = TRUE),
sd_S = sd(S, na.rm = TRUE),
sum_S = sum(S, na.rm = TRUE),
prop_plantations = mean(tipouso_grouped == "plantations", na.rm = TRUE),
.groups = "drop"
)
steps_data <- steps_data %>%
filter(sum_S < 7000)Exploring, little processing is still needed
steps_data <- steps_data %>%
mutate(area = recode(area, "Arauco" = "Plantations", "PN Iguazu" = "INP"))
ggplot(steps_data, aes(x = area, y = sum_S, fill = area)) +
geom_jitter(alpha = 0.1, width = 0.2, size= 3, height = 20) +
geom_boxplot(alpha = 0.7, lwd = 1.2, outlier.shape = NA) +
scale_fill_manual(values = c("Plantations" = "#8B4513", "INP" = "#228B22")) +
scale_y_continuous(limits = c(0, 3700), breaks = seq(0, 3700, by = 300)) +
labs(
x = "Study Site",
y = "Daily trajectory (m)") +
theme_minimal() +
theme(legend.position = "none",
text = element_text(family = 'Calibri', size = 34),
axis.title.x = element_text(vjust = -4),
axis.title.y = element_text(vjust = 5),
panel.background = element_rect(fill = "white", color = NA),
plot.background = element_rect(fill = "white", color = NA),
plot.margin = unit(c(1, 1, 1, 1), "cm"))locs_full_day <- locs_full_day %>%
mutate(
speed = ifelse(!is.na(S) & !is.na(interval_minutes) & interval_minutes > 0, S / interval_minutes, NA))speed <- locs_full_day %>%
group_by(area, id, date) %>%
arrange(t, .by_group = TRUE) %>%
summarise(
mean_S = mean(speed, na.rm = TRUE),
sd_S = sd(S, na.rm = TRUE),
prop_plantations = mean(tipouso_grouped == "plantations", na.rm = TRUE),
.groups = "drop")speed %>%
filter(area=='Plantations') %>%
ggplot(aes(x = prop_plantations, y = speed)) +
geom_jitter(width= 0.01, alpha = 0.5, size = 2, color = "grey24") + # Puntos para cada día
geom_smooth(method = "glm", color = "darkred", size = 3, se = TRUE) +
labs(x = "Daily proportions of locacions within plantations",
y = "Mean daily speed (m/min)"
) +
theme_minimal() +
theme(legend.position = "none",
text = element_text(family = 'Calibri', size = 34),
axis.title.x = element_text(vjust = -4),
axis.title.y = element_text(vjust = 5),
panel.background = element_rect(fill = "white", color = NA),
plot.background = element_rect(fill = "white", color = NA),
plot.margin = unit(c(1, 1, 1, 1), "cm"))locs_first_last <- locs_full_day %>%
group_by(id, date) %>%
slice_min(order_by = t, n = 1) %>%
mutate(time_label = "first") %>%
bind_rows(
locs_full_day %>%
group_by(id, date) %>%
slice_max(order_by = t, n = 1) %>%
mutate(time_label = "last")
) %>%
ungroup()
locs_full_day <- locs_full_day %>%
mutate(date = as.Date(date))
get_sun_times <- function(date, lat, lon) {
sun_times <- getSunlightTimes(
date = date, lat = lat, lon = lon,
keep = c("sunrise", "sunset"),
tz = "America/Argentina/Buenos_Aires")
return(sun_times)
}
sun_times_list <- pmap(
list(locs_full_day$date, locs_full_day$lat, locs_full_day$lon),
get_sun_times)
sun_data <- bind_rows(sun_times_list)
locs_full_day <- bind_cols(locs_full_day, sun_times_df)
locs_full_day <- locs_full_day %>%
mutate(
sunrise = format(sunrise, "%H:%M:%S"),
sunset = format(sunset, "%H:%M:%S"))
locs_first_last <- locs_first_last %>%
mutate(month_join = month(t))
sun_data <- sun_data %>%
mutate(month_join = month(date))
locs_first_last <- locs_first_last %>%
mutate(
horario = format(t, format = "%H:%M:%S"))
sun_data <- sun_data %>%
mutate(
sunrise_horario = format(sunrise_datetime, format = "%H:%M:%S"),
sunset_horario = format(sunset_datetime, format = "%H:%M:%S"))
sun_data <- sun_data %>%
mutate(month_join = month(date)) %>%
group_by(month_join) %>%
slice(1) %>%
ungroup() %>%
mutate(
sunrise_horario = format(sunrise_datetime, format = "%H:%M:%S"),
sunset_horario = format(sunset_datetime, format = "%H:%M:%S"))
locs_with_sun_info <-
locs_first_last %>%
left_join(sun_data_unique, by = "month_join") %>%
mutate(
t_horario = as.POSIXct(paste("2024-01-01", horario)),
sunrise_period = as.POSIXct(paste("2024-01-01", sunrise_horario)),
sunset_period = as.POSIXct(paste("2024-01-01", sunset_horario)),
t_to_sunrise = if_else(
time_label == "first",
as.numeric(difftime(
t_horario,
sunrise_period,
units = "mins")),
NA_real_),
t_to_sunset = if_else(
time_label == "last",
as.numeric(difftime(
sunset_period,
t_horario,
units = "mins")),
NA_real_))
locs_with_sun_info <- locs_with_sun_info %>%
dplyr::select(-sunrise_period, sunset_period, sunset,sunrise)
locs_with_sun_info <- locs_with_sun_info %>%
mutate(
time_to_sun = coalesce(t_to_sunrise, t_to_sunset)) %>%
dplyr::select(-t_to_sunrise, -t_to_sunset)
locs_with_sun <- locs_with_sun_info %>%
filter(time_to_sun >= -15 & time_to_sun <= 15)locs_with_sun <- locs_with_sun %>%
group_by(id, date.x) %>%
mutate(
X_first = na_if(first(X[time_label == "first"]), NA),
Y_first = na_if(first(Y[time_label == "first"]), NA),
X_last = na_if(first(X[time_label == "last"]), NA),
Y_last = na_if(first(Y[time_label == "last"]), NA),
distance_ss = if_else(
!is.na(X_first) & !is.na(Y_first) & !is.na(X_last) & !is.na(Y_last),
sqrt((X_last - X_first)^2 + (Y_last - Y_first)^2),
NA_real_
)
) %>%
ungroup() %>%
dplyr::select(-X_first, -Y_first, -X_last, -Y_last) Checking some specific data
demos1 <- locs_full_day %>%
filter((id == "gua.may.22" & date == as.Date("2022-05-25")))%>%
mutate(hour = hour(t))
demos2 <- locs_full_day %>%
filter((id == "gun.nov.10" & date == as.Date("2010-11-22")))%>%
mutate(hour = hour(t))
sf_demos1 <- st_as_sf(demos1, coords = c("lon", "lat"), crs = 4326)
sf_demos2 <- st_as_sf(demos2, coords = c("lon", "lat"), crs = 4326)
first_point1 <- sf_demos1 %>% filter(t == min(t))
last_point1 <- sf_demos1 %>% filter(t == max(t))
first_point1_utm <- st_transform(first_point1, crs = 32721)
last_point1_utm <- st_transform(last_point1, crs = 32721)
distance_meters1 <- st_distance(first_point1_utm, last_point1_utm)
distance_meters1 <- as.numeric(distance_meters1)
mid_x <- (st_coordinates(first_point1)[1,1] + st_coordinates(last_point1)[1,1]) / 2
mid_y <- (st_coordinates(first_point1)[1,2] + st_coordinates(last_point1)[1,2]) / 2
first_point2 <- sf_demos2 %>% filter(t == min(t))
last_point2 <- sf_demos2 %>% filter(t == max(t))
first_point2_utm <- st_transform(first_point2, crs = 32721)
last_point2_utm <- st_transform(last_point2, crs = 32721)
distance_meters2 <- st_distance(first_point2_utm, last_point2_utm)
distance_meters2 <- as.numeric(distance_meters2)
mid_x2 <- (st_coordinates(first_point2)[1,1] + st_coordinates(last_point2)[1,1]) / 2
mid_y2 <- (st_coordinates(first_point2)[1,2] + st_coordinates(last_point2)[1,2]) / 2
sf_demos1_df <- sf_demos1 %>%
mutate(lon = st_coordinates(.)[,1], lat = st_coordinates(.)[,2])
sf_demos2_df <- sf_demos2 %>%
mutate(lon = st_coordinates(.)[,1], lat = st_coordinates(.)[,2])ggplot() +
geom_path(data = sf_demos1_df, aes(x = lon, y = lat), color = "grey23", size = 1.4, linetype = "solid") +
geom_sf(data = sf_demos1, size = 4, color = "grey5") +
geom_segment(data = NULL,
aes(x = st_coordinates(first_point1)[1,1],
y = st_coordinates(first_point1)[1,2],
xend = st_coordinates(last_point1)[1,1],
yend = st_coordinates(last_point1)[1,2]),
color = "midnightblue", linetype = "dashed", size = 1.4) +
annotate("text", x = mid_x, y = mid_y + 0.0002, label = paste0(round(distance_meters1, 1), " m"),
color = "midnightblue", size = 8, angle = -12.5, fontface = "bold") +
annotate("text", x = st_coordinates(first_point1)[1,1] + 0.0008,
y = st_coordinates(first_point1)[1,2] + 0.00005,
label = "Sunrise", color = "goldenrod4", size = 8, fontface = "bold") +
annotate("text", x = st_coordinates(last_point1)[1,1],
y = st_coordinates(last_point1)[1,2] - 0.00025,
label = "Sunset", color = "darkred", size = 8, fontface = "bold") +
labs(title = "Daily trakectory of Columba, 2022-04-24",
x = "Longitude",
y = "Latitud") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, vjust = 0.5),
legend.position = "top",
legend.title = element_blank(),
text = element_text(family = 'Calibri', size = 34),
plot.title = element_text(hjust = 0.5),
axis.title.x = element_text(vjust = -3),
axis.title.y = element_text(vjust = 4),
panel.background = element_rect(fill = "white", color = NA),
plot.background = element_rect(fill = "white", color = NA),
plot.margin = unit(c(1, 1, 1, 1), "cm"))We will keep only complete tracking days, defined as days with eight evenly spaced locations recorded at 90-minute intervals (±15 minutes).
locs_day <- locs_with_sun %>%
group_by(id, date) %>%
mutate(
time_diff = difftime(t, lag(t), units = "mins"),
valid_intervals = sum(abs(time_diff - 90) <= 15, na.rm = TRUE)) %>%
filter(n() == 8 & valid_intervals == 7) %>%
ungroup()ggplot(locs_with_sun, aes(x = distance_ss, fill = area)) +
geom_density(alpha = 0.5) +
scale_fill_manual(values = c("Plantations" = "#8B4513", "INP" = "#228B22")) +
scale_y_continuous(labels = scales::comma)+
scale_x_continuous(limits = c(0,3000))+
labs(
x = "Distance from morning to evening sleeping site (m)",
y = "Density")+
guides(fill = guide_legend(title = NULL)) +
theme_minimal()+
theme(text = element_text(family = 'Calibri', size = 34),
axis.title.x = element_text(vjust = -4),
axis.title.y = element_text(vjust = 5),
panel.background = element_rect(fill = "white", color = NA),
plot.background = element_rect(fill = "white", color = NA),
plot.margin = unit(c(1, 1, 1, 1), "cm"))Minimum, mean and maximum daily temperature and precipitation (obtained for the Iguazú International Airport by the National Meteorological Service of Argentina), as these climatic factors may influence primate movement patterns (Asensio et al., 2012)
colores <- c('Plantations' = 'orange3', 'INP' = 'palegreen4')
colores2 <- c('Plantations' = '#f3c554', 'INP' = '#afeeb3')normal_fit <- fitdist(locs_day$sum_S2, "norm")
lognormal_fit <- fitdist(locs_day$sum_S2, "lnorm")
gamma_fit <- fitdist(locs_day$sum_S2, "gamma")
cdf_sum_S2 <- cdfcomp(
list(lognormal_fit, normal_fit, gamma_fit),
main = "",
legendtext = c("Log-normal", "Normal", "Gamma"),
fitcol = c("darkred", "orange3", "goldenrod1"),
plotstyle = "ggplot") +
geom_line(size = 1.2) +
theme(
axis.title = element_text(size = 42),
axis.text = element_text(size = 42),
axis.text.x = element_text(angle = 45, vjust = 0.8),
legend.position = c(0.8, 0.8),
legend.text = element_text(size = 40))
qq_sum_S2 <- qqcomp(
list(lognormal_fit, normal_fit, gamma_fit),
main = "",
fitcol = c("darkred", "orange3", "goldenrod1"),
plotstyle = "ggplot") +
geom_line(size = 1.2) +
theme_bw() +
theme(
axis.title = element_text(size = 42),
axis.text = element_text(size = 42),
axis.text.x = element_text(angle = 45, vjust = 0.8),
legend.position = "none")
plot_grid(qq_sum_S2, cdf_sum_S2, NULL, ncol = 3, rel_widths = c(1.5, 1.5, 0.75))aic_values <- data.frame(
Distribution = c("Normal", "Lognormal", "Gamma"),
AIC = c(normal_fit$aic, lognormal_fit$aic, gamma_fit$aic)) %>%
mutate(deltaAIC = AIC - min(AIC)) %>%
arrange(AIC)
aic_table <- aic_values %>%
flextable() %>%
theme_tron_legacy() %>%
colformat_num(j = c("AIC", "deltaAIC"), digits = 3) %>%
bold(part = "header") %>%
autofit()
aic_tableDistribution | AIC | deltaAIC |
|---|---|---|
Normal | 9,726.277 | 0.00000 |
Gamma | 9,786.895 | 60.61803 |
Lognormal | 9,848.748 | 122.47118 |
AIC table Best fit distributions for response variable (daily travel)
locs_day <- locs_day %>%
mutate(
distance_ss_scaled = scale(distance_ss, center = TRUE, scale = TRUE),
t_mean_scaled = scale(t_mean, center = TRUE, scale = TRUE),
precip_scaled = scale(precip, center = TRUE, scale = TRUE),
t_min_scaled = scale(t_min, center = TRUE, scale = TRUE))
locs_day <- locs_day %>%
mutate(food = case_when(
estacion2 == "invierno" ~ "low",
TRUE ~ "high"))m0 <- lmer(sum_S2 ~ 1 + (1 | grupo), data = locs_day)
m1 <- lmer(sum_S2 ~ area + (1 | grupo), data = locs_day)
m2 <- lmer(sum_S2 ~ area + distance_ss_scaled + (1 | grupo), data = locs_day)
m3 <- lmer(sum_S2 ~ area * distance_ss_scaled + (1 | grupo), data = locs_day)
m4 <- lmer(sum_S2 ~ area * food + distance_ss_scaled + (1 | grupo), data = locs_day)
m5 <- lmer(sum_S2 ~ area * distance_ss_scaled + food + (1 | grupo), data = locs_day)
m6 <- lmer(sum_S2 ~ area + t_min_scaled + (1 | grupo), data = locs_day)
m7 <- lmer(sum_S2 ~ area + t_min_scaled + precip_scaled + (1 | grupo), data = locs_day)
m8 <- lmer(sum_S2 ~ area + distance_ss_scaled + t_min_scaled + precip_scaled + (1 | grupo), data = locs_day)
m9 <- lmer(sum_S2 ~ area * distance_ss_scaled + t_min_scaled + precip_scaled + (1 | grupo), data = locs_day)
m10 <- lmer(sum_S2 ~ area + precip_scaled + distance_ss_scaled + t_min_scaled + (1 | grupo), data = locs_day)
m11 <- lmer(sum_S2 ~ area + t_min_scaled * distance_ss_scaled + precip_scaled + (1 | grupo), data = locs_day)
m12 <- lmer(sum_S2 ~ area * distance_ss_scaled + food + t_min_scaled + precip_scaled + (1 | grupo), data = locs_day)
m13 <- lmer(sum_S2 ~ area + distance_ss_scaled + food + t_min_scaled + precip_scaled + (1 | grupo), data = locs_day)
m14 <- lmer(sum_S2 ~ area * distance_ss_scaled + precip_scaled + (1 | grupo), data = locs_day)
m15 <- lmer(sum_S2 ~ area * food + t_min_scaled + (1 | grupo), data = locs_day)
m16 <- lmer(sum_S2 ~ area + distance_ss_scaled + food + daily_length + precip_scaled + (1 | grupo), data = locs_day)
m17 <- lmer(sum_S2 ~ area * distance_ss_scaled + daily_length + (1 | grupo), data = locs_day)
m18 <- lmer(sum_S2 ~ area * food + daily_length + t_min_scaled + (1 | grupo), data = locs_day)
m19 <- lmer(sum_S2 ~ area * daily_length + distance_ss_scaled + food + precip_scaled + (1 | grupo), data = locs_day)
m20 <- lmer(sum_S2 ~ area * daily_length * distance_ss_scaled + food + precip_scaled + (1 | grupo), data = locs_day)
m21<- lmer(sum_S2 ~ area * distance_ss_scaled + daily_length + food + t_min_scaled + precip_scaled + (1 | grupo), data = locs_day)model_aic <- AIC(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20, m21)
model_aic$deltaAIC <- model_aic$AIC - min(model_aic$AIC)
model_aic$Rank <- rank(model_aic$deltaAIC, ties.method = "first")
model_aic$Model <- c(
"Null model", #m0
"Study site", #m1
"Study site + Sleeping Sites Distance", #m2
"Study site * Sleeping Sites Distance", #m3
"Study site + Fruit Season + Sleeping Sites Distance", #m4
"Study site * Sleeping Sites Distance + Fruit Season", #m5
"Study site + Min. Temperature", #m6
"Study site + Min. Temperature + Precipitation", #m7
"Study site + Sleeping Sites Distance + Min. Temperature + Precipitation", #m8
"Study site * Sleeping Sites Distance + Min. Temperature + Precipitation", #m9
"Study site + Sleeping Sites Distance + Min. Temperature + Precipitation", #m10
"Study site + Min. Temperature * Sleeping Sites Distance + Precipitation", #m11
"Study site * Sleeping Sites Distance + Fruit Season + Min. Temperature + Precipitation", #m12
"Study site + Sleeping Sites Distance + Fruit Season + Min. Temperature + Precipitation", #m13
"Study site * Sleeping Sites Distance + Precipitation", #m14
"Study site * Fruit Season + Min. Temperature", #m15
"Study site + Sleeping Sites Distance + Fruit Season + Daily Length + Precipitation", #m16
"Study site * Sleeping Sites Distance + Daily Length", #m17
"Study site * Fruit Season + Daily lenght + Min. Temperature", #m18
"Study site * Daily length + Sleeping Sites Distance + Fruit Season + Precipitation", #m19
"Study site * Daily length * Sleeping Sites Distance + Fruit Season + Precipitation", #m20
"Study site * Sleeping Sites Distance + Daily Length + Fruit Season + Min. Temperature + Precipitation") #m21
model_table <- model_aic[order(model_aic$Rank), c("Rank", "Model", "df", "AIC", "deltaAIC")]
model_table <- model_table %>% arrange(Rank)
model_table %>%
flextable() %>%
theme_tron_legacy() %>%
colformat_num(j = c("AIC", "deltaAIC"), digits = 3) %>%
bold(part = "header") %>%
set_caption("AIC Model Comparison for Study Site Effects") %>%
autofit()Rank | Model | df | AIC | deltaAIC |
|---|---|---|---|---|
1 | Study site * Sleeping Sites Distance + Daily Length + Fruit Season + Min. Temperature + Precipitation | 10 | 9,467.830 | 0.000000 |
2 | Study site * Sleeping Sites Distance + Fruit Season + Min. Temperature + Precipitation | 9 | 9,475.603 | 7.772724 |
3 | Study site * Sleeping Sites Distance + Min. Temperature + Precipitation | 8 | 9,488.406 | 20.576256 |
4 | Study site * Fruit Season + Daily lenght + Min. Temperature | 8 | 9,503.292 | 35.462014 |
5 | Study site + Sleeping Sites Distance + Fruit Season + Min. Temperature + Precipitation | 8 | 9,508.242 | 40.412077 |
6 | Study site * Fruit Season + Min. Temperature | 7 | 9,511.325 | 43.494519 |
7 | Study site + Min. Temperature * Sleeping Sites Distance + Precipitation | 8 | 9,513.471 | 45.641324 |
8 | Study site + Sleeping Sites Distance + Min. Temperature + Precipitation | 7 | 9,520.213 | 52.383413 |
9 | Study site + Sleeping Sites Distance + Min. Temperature + Precipitation | 7 | 9,520.213 | 52.383413 |
10 | Study site + Min. Temperature + Precipitation | 6 | 9,527.070 | 59.239589 |
11 | Study site + Min. Temperature | 5 | 9,533.672 | 65.842111 |
12 | Study site * Daily length * Sleeping Sites Distance + Fruit Season + Precipitation | 12 | 9,550.382 | 82.552308 |
13 | Study site * Sleeping Sites Distance + Fruit Season | 7 | 9,595.433 | 127.603250 |
14 | Study site * Sleeping Sites Distance + Daily Length | 7 | 9,599.418 | 131.588258 |
15 | Study site * Daily length + Sleeping Sites Distance + Fruit Season + Precipitation | 9 | 9,600.521 | 132.691392 |
16 | Study site * Sleeping Sites Distance + Precipitation | 7 | 9,600.847 | 133.016548 |
17 | Study site * Sleeping Sites Distance | 6 | 9,608.300 | 140.469961 |
18 | Study site + Sleeping Sites Distance + Fruit Season + Daily Length + Precipitation | 8 | 9,613.366 | 145.535870 |
19 | Study site + Fruit Season + Sleeping Sites Distance | 7 | 9,617.597 | 149.766521 |
20 | Study site + Sleeping Sites Distance | 5 | 9,640.340 | 172.510322 |
21 | Study site | 4 | 9,647.128 | 179.298477 |
22 | Null model | 3 | 9,666.865 | 199.035172 |
Table A.1. The table presents a set of candidate models ranked according to Akaike’s Information Criterion (AIC), with the best-supported model (lowest AIC) listed first. The response variable is the daily trajectory length of black capuchin monkeys (Sapajus nigritus), modeled as a function of different ecological and environmental covariates. The best-ranked model includes interactions between Study Site and Sleeping Sites, as well as Fruit Season, Minimum Temperature, and Precipitation. The ΔAIC values indicate the relative support for each model, and “df” the degrees of freedom.
## Linear mixed model fit by REML ['lmerMod']
## Formula:
## sum_S2 ~ area * distance_ss_scaled + daily_length + food + t_min_scaled +
## precip_scaled + (1 | grupo)
## Data: locs_day
##
## REML criterion at convergence: 9447.8
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.88224 -0.70006 0.09481 0.64915 2.67262
##
## Random effects:
## Groups Name Variance Std.Dev.
## grupo (Intercept) 3839 61.96
## Residual 473853 688.37
## Number of obs: 599, groups: grupo, 8
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 2283.761 635.102 3.596
## areaPlantations 403.969 86.748 4.657
## distance_ss_scaled 140.085 40.217 3.483
## daily_length -17.739 49.644 -0.357
## foodlow 158.756 89.674 1.770
## t_min_scaled 6.509 35.733 0.182
## precip_scaled 35.505 29.682 1.196
## areaPlantations:distance_ss_scaled -318.562 63.795 -4.993
##
## Correlation of Fixed Effects:
## (Intr) arPlnt dstn__ dly_ln foodlw t_mn_s prcp_s
## areaPlnttns -0.422
## dstnc_ss_sc -0.065 0.178
## daily_lngth -0.996 0.364 0.040
## foodlow -0.426 0.076 0.032 0.409
## t_min_scald 0.366 0.039 -0.044 -0.389 0.144
## precip_scld -0.016 -0.146 0.132 0.022 0.074 -0.153
## arPlnttn:__ 0.035 0.050 -0.649 -0.020 -0.059 0.049 -0.226
s2_dss_raw <-
ggplot(locs_day,
aes(x = distance_ss,
y = sum_S2,
color = area)) +
geom_point(
aes(shape = area),
size = 3.2,
alpha = 0.3) +
geom_smooth(
aes(fill = area), method = "lm",
se = TRUE,
linewidth = 2.8) +
scale_color_manual(values = colores,
name = "Study Site") +
scale_fill_manual(values = colores2,
name = "Study Site") +
scale_shape_manual(
values = c("Plantations" = 16, "INP" = 17),
name = "Study Site") +
labs(
x = "Distance Between Sleeping Sites (m)",
y = "Daily Trajectories (m)") +
guides(
color = guide_legend(
override.aes = list(
shape = c(16, 17),
size = 5)),
shape = "none") +
theme_classic() +
theme(
text = element_text(family = 'Calibri', size = 34),
legend.position = 'bottom',
legend.box.margin = margin(t = 50, b = 10),
legend.title = element_text(size = 34),
legend.text = element_text(size = 30),
legend.key.size = unit(1.5, "lines"),
legend.spacing.x = unit(0.5, "cm"),
legend.spacing.y = unit(0.3, "cm"),
axis.title.x = element_text(size = 34, vjust = -3),
axis.title.y = element_text(size = 34, vjust = 3),
axis.text = element_text(size = 30),
plot.margin = unit(c(1, 1, 1, 1), 'cm'))
s2_dss_rawr_squared <- r.squaredGLMM(m21)
r_squared <- data.frame(
Metric = c("Marginal R² (R²m)", "Conditional R² (R²c)"),
Value = c(r_squared[1, 1], r_squared[1, 2]))
r_squared %>%
flextable() %>%
colformat_num(j = "Value", digits = 2) %>%
set_caption("R² Values for best model - capuchins daily trajectories") %>%
bold(part = "header") %>%
autofit()Metric | Value |
|---|---|
Marginal R² (R²m) | 0.51 |
Conditional R² (R²c) | 0.77 |
qqnorm(residuals(m21), cex = 1,
cex.axis = 2.3,
cex.lab = 2.3,
cex.main = 2.3)
qqline(residuals(m21), col='darkred', cex=9)plot(fitted(m21), residuals(m21),
xlab = "Adjusted values", ylab = "Residuals",
main = "Residuals vs. Adjusted values",
cex.lab = 2.3,
cex.main = 2.3,
cex.axis = 2.3)
abline(h = 0, col = "red")set.seed(123)
folds <- createFolds(locs_day$sum_S2, k = 10, list = TRUE)
errors <- numeric(length(folds))
for (i in seq_along(folds)) {
train_data <- locs_day[-folds[[i]], ]
test_data <- locs_day[folds[[i]], ]
model <- lmer(sum_S2 ~ area * distance_ss_scaled + food + t_min_scaled +
precip_scaled + (1 | grupo),
data = train_data) # Aquí usamos train_data
predictions <- predict(model, newdata = test_data, allow.new.levels = TRUE)
errors[i] <- mean((predictions - test_data$sum_S2)^2, na.rm = TRUE)
}
mean_cv_error <- mean(errors, na.rm = TRUE)
cat("RMSE cross-validation:", sqrt(mean_cv_error), "\n")## RMSE cross-validation: 692.1672
model_no_random <- lm(sum_S2 ~ area * distance_ss_scaled + food + t_min_scaled + precip_scaled,
data = locs_day)
errors_no_random <- numeric(length(folds))
for (i in seq_along(folds)) {
train_data <- locs_day[-folds[[i]], ]
test_data <- locs_day[folds[[i]], ]
model <- lm(sum_S2 ~ area * distance_ss_scaled + food + t_min_scaled + precip_scaled,
data = train_data)
predictions <- predict(model, newdata = test_data)
errors_no_random[i] <- mean((predictions - test_data$sum_S2)^2, na.rm = TRUE)
}
mean_cv_error_no_random <- mean(errors_no_random, na.rm = TRUE)
cat("Mean RMSE without random effect:", sqrt(mean_cv_error_no_random), "\n")## Mean RMSE without random effect: 692.2336
The linear mixed model indicates that capuchin group identity (random effect) accounts for some variation in daily travel distance, but the majority of the variance is explained by the fixed effects. The marginal R² (0.147) suggests that environmental and spatial predictors explain about 15% of the variation, while the conditional R² (0.149) shows that including the random effect adds little explanatory power. The RMSE values (692.17 vs. 692.23) are nearly identical, reinforcing that group-level variation does not substantially improve predictive accuracy. However, significant fixed effects—such as the interaction between study site and sleeping site distance, and greater travel distances in plantations—highlight the influence of habitat structure on capuchin movement patterns.
locs_day_pine <- locs_day %>% filter(area == 'Plantations')
dano <- read_csv ('files/dano_nuevo_area.csv')
dano <- dano %>%
separate(mes,
into = c("mes", "day"),
sep = "-") dano <- dano %>%
rename(year= day)
dano <- dano %>%
mutate(year = paste0("20", year))
dano$grupo <- factor(dano$grupo,
levels = c('Grupo 1', 'Grupo 2', 'Grupo 3', 'Grupo 4'),
labels = c('Columba', 'Pandemia', 'Triangulo', 'Gualicho'))
monthly_dano <- dano %>%
group_by(grupo, mes, year) %>%
summarise(media_dano = mean(m2, na.rm = TRUE))
monthly_dano$year <- as.integer(monthly_dano$year)
monthly_dano <- monthly_dano %>%
rename(month = mes)
locs_day_pine$year <- as.integer(locs_day_pine$year)
locs_day_pine <- locs_day_pine %>%
left_join(monthly_dano, by = c("grupo" = "grupo", "month" = "month", "year" = "year"))ggplot(locs_day_pine, aes(x = media_dano, y = sum_S2)) +
geom_jitter(
size = 3,
alpha = 0.2,
color = 'black',
shape = 21,
fill = 'grey60',
width = 0.08,
height = 0.1) +
geom_smooth(
method = "lm",
linewidth = 1.8,
color = "midnightblue",
fill = "lightblue",
se = TRUE,
alpha = 0.3) +
labs(
y = "Daily trajectories (m)",
x = expression("Monthly bark-stripping per transect (m"^2*")")) +
theme_bw() +
guides(
size = "none",
alpha = "none",
color = "none") +
theme(
text = element_text(family = "Calibri", size = 34),
axis.text.x = element_text(color = "grey15", angle = 45, hjust = 0.5, vjust = 0.6),
axis.text.y = element_text(color = "grey15"),
axis.title.x = element_text(face = "bold", margin = margin(t = 20)),
axis.title.y = element_text(face = "bold", vjust = 3),
plot.margin = unit(c(1, 1, 1, 1), "cm"))cor_test_result <- cor.test(locs_day_pine$media_dano, locs_day_pine$sum_S2,
method = "pearson", use = "complete.obs")
print(cor_test_result)##
## Pearson's product-moment correlation
##
## data: locs_day_pine$media_dano and locs_day_pine$sum_S2
## t = 1.8221, df = 329, p-value = 0.06934
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.007931638 0.205539895
## sample estimates:
## cor
## 0.09995422