library(data.table) library(sf) library(terra) library(ggplot2) library(patchwork) library(colorspace) # for gams library(mgcv)
data <- fread("data/results/data_patch_summary_ppa.csv") points <- fread("data/results/data_patch_points_ppa.csv")
points <- points[, c("id", "patch", "x", "y", "date")] points <- st_as_sf( points, coords = c("x", "y"), crs = 2039 )
# load rasters ndvi <- rast("data/rasters/raster_hula_ndvi_2039.tif") vis <- rast("data/rasters/raster_hula_visibility.tif")
ndvi_samp <- terra::extract( ndvi, vect(points) ) vis_samp <- terra::extract( vis, vect(points) ) points <- st_drop_geometry(points) setDT(points) points[, c("ndvi", "vis") := list( ndvi_samp$raster_hula_ndvi_2039, vis_samp$raster_hula_visibility )]
rm(vis, ndvi) gc()
# mean ndvi and vis per patch and date points <- points[, lapply(.SD, mean), by = c("id", "patch", "date")] # save fwrite( points, "data/results/data_patch_env.csv" )
# load data patch summary data <- fread("data/results/data_patch_summary_ppa.csv") patch_env <- fread("data/results/data_patch_env.csv")
data <- merge( data, patch_env )
# link rrv rrv <- fread("data/results/data_daily_rrv.csv") rrv$date <- as.character(rrv$date) data$date <- as.character(data$date)
# change name of TAG to id in RRV setnames(rrv, "TAG", "id") data <- merge( data, rrv, by = c("id", "date"), all.x = T ) # filter data <- data[!is.na(sp) & !is.na(treat)]
data[, duration_bw_patches := ( (time_start - data.table::shift(time_end)) / 60 # in minutes ), by = c("id", "date")]
# plot histogram of duration between patches p <- ggplot(data) + geom_histogram( aes(duration_bw_patches, y = ..density..) ) + facet_grid(sp ~ treat) + labs( x = "duration between patches (mins)" ) p + scale_x_log10() ggsave( p, filename = "figures/fig_duration_bw_patches.png" )
p <- ggplot(data) + geom_jitter( aes( duration_bw_patches, dist_bw_patch, col = treat ) ) + geom_hline( yintercept = 100, lty = 2 ) + geom_vline( xintercept = 30, lty = 2 ) + scale_x_sqrt() + scale_y_sqrt() + facet_grid(~sp) ggsave( p, filename = "figures/fig_distance_duration_bw_patches.png" )
# patch switches patch_switches <- data[, list( N = .N, total_dist = sum(dist_bw_patch, na.rm = T), mean_duration = mean(duration) / 3600, # in hours tracking_duration = (max(time_end) - min(time_start)) / 3600 # in hours ), by = c("id", "date", "sp", "rrv_calc", "treat")] patch_switches <- patch_switches[!is.na(sp)] # convert to patch switches per hour patch_switches[, dist_ph := total_dist / tracking_duration] # remove NA values patch_switches <- patch_switches[!is.na(rrv_calc)] # asign sp as factor patch_switches[, sp := factor(sp, levels = c( "Pycnonotus", "Passer", "Acrocephalus" ))]
Examine the number of patch switches in relation to RRV.
ggplot(patch_switches) + geom_jitter( aes( rrv_calc, N / tracking_duration, col = treat ) ) + geom_smooth( aes( rrv_calc, N / tracking_duration ), method = "gam", formula = as.formula( "y ~ s(x, k = 3)" ) ) + facet_grid(~sp)
# scale patch switches by tracking duration patch_switches[, n_per_hr := N / tracking_duration] # fit gam mod_ps <- gam( n_per_hr ~ s(rrv_calc, k = 3, by = sp) + s(sp, bs = "re"), data = patch_switches ) # visualise gam gratia::draw(mod_ps) summary(mod_ps) # write summary to file writeLines( capture.output( summary(mod_ps) ), con = "data/results/mod_summary_rrv_n_patches.txt" )
This code below is only to create clean outputs for the LaTeX supplementary material.
# get model as tex code for supplement texreg::texreg( list(mod_ps), custom.model.names = c("Coefficients"), single.row = T, dcolumn = T, custom.coef.names = c( "Intercept", "WGI - bulbul", "WGI - sparrow", "WGI - warbler", "Species" ), caption = "Generalised additive model coefficients for residence patch switches." ) # for word file texreg::wordreg( l = list(mod_ps), file = "docs/model_patch_switches.docx", custom.model.names = c("Coefficients"), single.row = T, dcolumn = T, custom.coef.names = c( "Intercept", "WGI - bulbul", "WGI - sparrow", "WGI - warbler", "Species" ), caption = "Generalised additive model coefficients for residence patch switches." )
# make prediction table pred_data_patches_rrv <- CJ( sp = as.factor(unique(data$sp)), id = "new", treat = as.factor(unique(data$treat)), rrv_calc = seq(0, 20, 0.5) ) # filter for unrealistic pred_data_patches_rrv <- pred_data_patches_rrv[( (treat == "NonMoulting" & rrv_calc == 0) | (treat == "Moulting" & between(rrv_calc, 2, 12)) | (treat == "Manipulated" & between(rrv_calc, 12, 20)) )] # get prediction pred_ps <- predict( mod_ps, newdata = pred_data_patches_rrv, allow.new.levels = T, se.fit = T ) pred_data_patches_rrv$pred <- pred_ps$fit pred_data_patches_rrv$se <- pred_ps$se.fit
# prepare summary statistics for switches per hour and wing gap index patch_switches_summary <- patch_switches[, unlist( lapply(.SD, function(x) { list( mean = mean(x), sd = sd(x) ) }), recursive = FALSE ), .SDcols = c("rrv_calc", "n_per_hr"), by = c("sp", "treat")]
Plotting code for patch switches per hour of tracking, in relation to wing gap index.
# save as object and write intermediate to file fig_patch_switches <- ggplot(patch_switches) + geom_jitter( aes( rrv_calc, n_per_hr, col = treat ), shape = 1 ) + geom_ribbon( data = pred_data_patches_rrv[!(sp == "Pycnonotus" & rrv_calc > 17) & !sp == "Acrocephalus"], aes( rrv_calc, ymin = pred - se, ymax = pred + se ), fill = "transparent", col = "grey", lty = 1 ) + geom_line( data = pred_data_patches_rrv[!(sp == "Pycnonotus" & rrv_calc > 17) & !sp == "Acrocephalus"], aes( rrv_calc, pred ), col = "indianred" ) + geom_linerange( data = patch_switches_summary, aes( rrv_calc.mean, ymin = n_per_hr.mean - n_per_hr.sd, ymax = n_per_hr.mean + n_per_hr.sd ) ) + geom_linerange( data = patch_switches_summary, aes( rrv_calc.mean, n_per_hr.mean, xmin = rrv_calc.mean - rrv_calc.sd, xmax = rrv_calc.mean + rrv_calc.sd ) ) + geom_point( data = patch_switches_summary, aes( rrv_calc.mean, n_per_hr.mean, fill = treat ), shape = 21, size = 2 ) + facet_grid( ~sp ) + scale_fill_discrete_sequential( palette = "Batlow", l1 = 30, l2 = 60, breaks = c("NonMoulting", "Moulting", "Manipulated"), labels = c("Non-molting", "Molting", "Manipulated") ) + scale_colour_discrete_sequential( palette = "Batlow", l1 = 50, l2 = 50, guide = "none" ) + facet_grid( cols = vars(sp), scales = "free", labeller = labeller( sp = c( "Acrocephalus" = "Clamorous\nreed warbler", "Passer" = "House sparrow", "Pycnonotus" = "White-spectacled\nbulbul" ) ) ) + theme_test( base_size = 10, base_family = "Arial" ) + theme( legend.position = "top", strip.background = element_blank(), strip.text = element_text( face = "italic" ) ) + labs( x = "Wing gap index (More gappy wing →)", # x = NULL, y = "Patch switches / hr", fill = NULL ) # save to file ggsave( fig_patch_switches, filename = "figures/fig_patch_switches.png", width = 120, height = 70, units = "mm" )
# plot rrv with errors per treatment, and patch distance w/ errors per trt psdf <- patch_switches[, unlist(lapply(.SD, function(x) { list( mean = as.numeric(mean(x)), sd = sd(x, na.rm = T) ) }), recursive = F), .SDcols = c("dist_ph", "rrv_calc"), by = c("sp", "treat") ]
patch_switches[, c("sp", "treat") := lapply( .SD, as.factor ), .SDcols = c("sp", "treat")] mod1 <- gam( dist_ph ~ s(rrv_calc, by = sp, k = 3) + s(sp, bs = "re"), # s(sp, rrv_calc, bs = "re"), data = patch_switches ) summary(mod1) gratia::draw(mod1)
# save model summary mod_summary <- summary(mod1) writeLines( capture.output( mod_summary ), con = "data/results/mod_summary_rrv_movement.txt" )
This code below is only to create clean outputs for the LaTeX supplementary material.
# get model as tex code for supplement texreg::texreg( list(mod1), custom.model.names = c("Coefficients"), single.row = T, dcolumn = T, custom.coef.names = c( "Intercept", "WGI - bulbul", "WGI - sparrow", "WGI - warbler", "Species" ), caption = "Generalised additive model coefficients for distance between residence patches." ) # for word file texreg::wordreg( list(mod1), file = "docs/model_patch_distances.docx", custom.model.names = c("Coefficients"), single.row = T, dcolumn = T, custom.coef.names = c( "Intercept", "WGI - bulbul", "WGI - sparrow", "WGI - warbler", "Species" ), caption = "Generalised additive model coefficients for distance between residence patches." )
# summarise patch switches by species and treatments patch_distance_summary <- patch_switches[treat != "Manipulated" | (treat == "Manipulated" & rrv_calc > 12), list( mean_dist_ph = mean(dist_ph, na.rm = TRUE), sd_dist_ph = sd(dist_ph, na.rm = TRUE) ), by = c("sp", "treat")] # save small data fwrite( patch_distance_summary, file = "data/results/data_patch_distance_summary.csv" )
# make prediction table pred_data <- CJ( sp = as.factor(unique(data$sp)), id = "new", treat = as.factor(unique(data$treat)), rrv_calc = seq(0, 20, 0.5) ) # filter for unrealistic pred_data <- pred_data[( (treat == "NonMoulting" & rrv_calc == 0) | (treat == "Moulting" & between(rrv_calc, 2, 12)) | (treat == "Manipulated" & between(rrv_calc, 12, 20)) )] # get prediction pred <- predict(mod1, newdata = pred_data, allow.new.levels = T, se.fit = T) pred_data$pred <- pred$fit pred_data$se <- pred$se.fit # explore ggplot(patch_switches[dist_ph < 900]) + # geom_jitter( # aes( # rrv_calc, dist_ph, # col = treat # ), # shape = 1 # )+ geom_point( data = pred_data, aes( rrv_calc, pred ) ) + facet_grid( ~sp )
# set factor order of species names psdf[, sp := factor(sp, levels = c( "Pycnonotus", "Passer", "Acrocephalus" ))]
# plot figure fig_moult_move <- ggplot(psdf) + geom_hline( yintercept = 100, col = "grey", lty = 2 ) + geom_jitter( data = patch_switches[dist_ph < 900], aes( rrv_calc, dist_ph, col = treat ), shape = 1 ) + geom_ribbon( data = pred_data[!(sp == "Pycnonotus" & rrv_calc > 17) & !sp == "Acrocephalus"], aes( rrv_calc, ymin = pred - se, ymax = pred + se ), fill = "transparent", col = "grey", lty = 1 ) + geom_line( data = pred_data[!(sp == "Pycnonotus" & rrv_calc > 17) & !sp == "Acrocephalus"], aes( rrv_calc, pred ), col = "indianred" ) + geom_linerange( aes( rrv_calc.mean, ymin = dist_ph.mean - dist_ph.sd, ymax = dist_ph.mean + dist_ph.sd ) ) + geom_linerange( aes( rrv_calc.mean, dist_ph.mean, xmin = rrv_calc.mean - rrv_calc.sd, xmax = rrv_calc.mean + rrv_calc.sd ) ) + geom_point( aes( rrv_calc.mean, dist_ph.mean, fill = treat ), shape = 21, size = 2 ) + scale_fill_discrete_sequential( palette = "Batlow", l1 = 30, l2 = 60, breaks = c("NonMoulting", "Moulting", "Manipulated"), labels = c("Non-molting", "Molting", "Manipulated") ) + scale_colour_discrete_sequential( palette = "Batlow", l1 = 50, l2 = 50, guide = "none" ) + # scale_y_sqrt()+ facet_grid( cols = vars(sp), scales = "free", labeller = labeller( sp = c( "Acrocephalus" = "Clamorous\nreed warbler", "Passer" = "House sparrow", "Pycnonotus" = "White-spectacled\nbulbul" ) ) ) + coord_cartesian( ylim = c(0, NA) ) + theme_test( base_size = 10, base_family = "Arial" ) + theme( legend.position = "top", strip.background = element_blank(), strip.text = element_text( face = "italic" ) ) + labs( x = "Wing gap index (More gappy wing →)", y = "Between-patch distance (m)", fill = NULL ) ggsave( fig_moult_move, filename = "figures/fig_moult_move.png", width = 120, height = 70, units = "mm" )
# explore the data ggplot(data) + geom_jitter( aes( vis, duration / (3600), col = treat ) ) + facet_grid(treat ~ sp) + coord_cartesian( ylim = c(0, 2) )
# handle variable as factor data[, sp := factor(sp, levels = c( "Pycnonotus", "Passer", "Acrocephalus" ))] # convert to hours data[, duration_hr := duration / (3600)] # fit a gam with few knots mod_duration_rrv <- gam( duration_hr ~ s(rrv_calc, by = sp, k = 3) + vis + ndvi + s(sp, bs = "re"), data = data ) # plot model gratia::draw(mod_duration_rrv) # examine model summary summary(mod_duration_rrv)
# save model summary mod_summary_duration <- summary(mod_duration_rrv) writeLines( capture.output( mod_summary_duration ), con = "data/results/mod_summary_duration_rrv.txt" )
This code below is only to create clean outputs for the LaTeX supplementary material.
# get model as tex code for supplement texreg::texreg( list(mod_duration_rrv), custom.model.names = c("Coefficients"), single.row = T, dcolumn = T, custom.coef.names = c( "Intercept", "Visibility index", "NDVI", "WGI - bulbul", "WGI - sparrow", "WGI - warbler", "Species" ), caption = "Generalised additive model coefficients for residence patch duration." ) # for word file texreg::wordreg( list(mod_duration_rrv), file = "docs/model_patch_duration.docx", custom.model.names = c("Coefficients"), single.row = T, dcolumn = T, custom.coef.names = c( "Intercept", "Visibility index", "NDVI", "WGI - bulbul", "WGI - sparrow", "WGI - warbler", "Species" ), caption = "Generalised additive model coefficients for residence patch duration." )
# prepare predictor data # make prediction table pred_data_duration_rrv <- CJ( sp = as.factor(unique(data$sp)), id = "new", treat = as.factor(unique(data$treat)), rrv_calc = seq(0, 20, 0.5), ndvi = 0.4, # taken from the data mean vis = 0.33 # from the data mean ) # filter for unrealistic pred_data_duration_rrv <- pred_data_duration_rrv[( (treat == "NonMoulting" & rrv_calc == 0) | (treat == "Moulting" & between(rrv_calc, 2, 12)) | (treat == "Manipulated" & between(rrv_calc, 12, 20)) )] # get prediction pred_duration <- predict( mod_duration_rrv, newdata = pred_data_duration_rrv, allow.new.levels = T, se.fit = T ) pred_data_duration_rrv$pred <- pred_duration$fit pred_data_duration_rrv$se <- pred_duration$se.fit
# make summary table patch_duration_summary <- data[, unlist( lapply(.SD, function(x) { list( mean = mean(x, na.rm = T), sd = sd(x, na.rm = T) ) }), recursive = F ), .SDcols = c("duration_hr", "rrv_calc"), by = c("sp", "treat"), ]
# prepare figure fig_patch_duration_rrv <- ggplot(data) + geom_jitter( aes( rrv_calc, duration_hr, col = treat ), shape = 1, size = 0.5 ) + geom_ribbon( data = pred_data_duration_rrv[!(sp == "Pycnonotus" & rrv_calc > 17) & !sp == "Passer"], aes( rrv_calc, ymin = pred - se, ymax = pred + se ), fill = "transparent", col = "grey", lty = 1 ) + geom_line( data = pred_data_duration_rrv[!(sp == "Pycnonotus" & rrv_calc > 17) & !sp == "Passer"], aes( rrv_calc, pred ), col = "indianred" ) + geom_linerange( data = patch_duration_summary, aes( rrv_calc.mean, ymin = duration_hr.mean - duration_hr.sd, ymax = duration_hr.mean + duration_hr.sd ) ) + geom_linerange( data = patch_duration_summary, aes( rrv_calc.mean, duration_hr.mean, xmin = rrv_calc.mean - rrv_calc.sd, xmax = rrv_calc.mean + rrv_calc.sd ) ) + geom_point( data = patch_duration_summary, aes( rrv_calc.mean, duration_hr.mean, fill = treat ), shape = 21, size = 2 ) + coord_cartesian( ylim = c(0, 5) ) + scale_fill_discrete_sequential( palette = "Batlow", l1 = 30, l2 = 60, breaks = c("NonMoulting", "Moulting", "Manipulated"), labels = c("Non-molting", "Molting", "Manipulated") ) + scale_colour_discrete_sequential( palette = "Batlow", l1 = 50, l2 = 50, guide = "none" ) + # scale_y_sqrt()+ facet_grid( cols = vars(sp), scales = "free", labeller = labeller( sp = c( "Acrocephalus" = "Clamorous\nreed warbler", "Passer" = "House sparrow", "Pycnonotus" = "White-spectacled\nbulbul" ) ) ) + theme_test( base_size = 10, base_family = "Arial" ) + theme( legend.position = "top", strip.background = element_blank(), strip.text = element_text( face = "italic" ) ) + labs( x = "Wing gap index (More gappy wing →)", y = "Duration in patch (hrs)", fill = NULL ) ggsave( fig_patch_duration_rrv, filename = "figures/fig_patch_duration_rrv.png", width = 120, height = 70, units = "mm" )
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.