#' Adds cruise behavior
#'
#' Finds cruise behavior that meet given threshold parameters
#'
#' @usage AddCruiseBehavior(df, min_agl, min_speed, threshold_agl)
#' @param df dataframe
#' @param min_agl distance (in meters) above ground
#' @param min_speed minimum speed of bird
#' @param threshold_agl any locations above this threshold of agl ('above ground
#' level') are labeled "cruise"
#'
#' @return dataframe with behavior column that has "cruise"
#' @export
#'
#' @details should run AddNestBehavior, AddRoostBehavior, and AddCruiseBehavior
#' prior to this function
AddCruiseBehavior <- function(df = df,
min_agl = 200,
min_speed = 5,
threshold_agl = 250) {
df_cruise <- df %>%
dplyr::mutate(bh_cruise = as.character(NA) ) %>%
dplyr::mutate(bh_cruise = dplyr::if_else(agl >= min_agl &
speed >= min_speed, "Cruise", bh_cruise)) %>%
dplyr::mutate(bh_cruise = dplyr::if_else(agl >= threshold_agl, "Cruise",
bh_cruise)) %>%
dplyr::mutate(
bh_cruise_tf = dplyr::if_else(!is.na(bh_cruise), TRUE, FALSE),
bh_cruise_seq = sequence(rle(bh_cruise_tf)$lengths) * bh_cruise_tf) %>%
dplyr::select(-bh_cruise_tf)
return(df_cruise)
}
#' Adds flight behavior
#'
#' Finds location data that meet given threshold parameters for flights, which
#' include the start point, mid-flight, and final location of a flight.
#'
#' @usage AddFlightBehavior(df, min_speed, min_step_length, max_step_time,
#' threshold_agl)
#' @param df dataframe
#' @param min_speed minimum speed of bird
#' @param min_step_length distance (in meters) between locations
#' @param max_step_time maximum time between locations
#' @param threshold_agl any locations above this threshold of agl ('above ground
#' level') are labeled "cruise"
#'
#' @return dataframe with columns for flight_index, flight_step, and
#' flight_length
#' @export
#'
#' @details adds 'bh_flight' to dataframe
AddFlightBehavior <- function(df,
min_speed = 5,
min_step_length = 50,
max_step_time = 20,
threshold_agl = 100){
df_flight <- df %>%
plyr::mutate(bh_flight = as.character(NA)) %>%
plyr::mutate(bh_flight = dplyr::if_else(speed >= min_speed &
step_time < max_step_time & step_length > min_step_length, "Flight",
bh_flight)) %>%
plyr::mutate(bh_flight = dplyr::if_else(agl >= threshold_agl, "Flight",
bh_flight))
return(df_flight)
}
#' Adds home and conspecific edge distances to 'baea' dataframe
#'
#' Creates Raster Layers of homerange kernels based on home centroids
#'
#' @param baea dataframe of baea locations
#' @param nest_set dataframe of nests
#' @param base base Raster that sets the projection, extent, and dimensions of
#' the study area
#' @param output_dir directory for output files (distance, homerange)
#' @param max_r maximum radius to calculate the homerange raster from each
#' df_home centroid
#' @param write_home_dist logical, write home nest distance raster to file.
#' Default is FALSE.
#' @param write_con_dist logical, write conspecific nest distance raster to
#' file. Default is FALSE.
#' @param write_con_dist_nest logical, write conspecific nest distance with all
#' values centered on zero at the nest as raster to file. Default is FALSE.
#' @param write_edge_dist logical, write territorial edge distance raster to
#' file. Default is FALSE.
#' @param write_terr_edge logical, write territorial edge raster to file.
#' Default is FALSE.
#'
#' @return baea
#'
#' @importFrom magrittr "%>%"
#' @export
#'
#' @details Creates folders for every year in output directory
AddHomeConEdgeDistanceBAEA <- function(baea,
nest_set,
base,
output_dir = getwd(),
max_r,
write_home_dist = FALSE,
write_con_dist = FALSE,
write_con_dist_nest = FALSE,
write_edge_dist = FALSE,
write_terr_edge = FALSE){
id <- "nest_site"
name <- "name"
# if (output_dir != getwd()) unlink(output_dir, recursive=TRUE)
if (!dir.exists(output_dir)) dir.create(output_dir)
if (write_home_dist | write_edge_dist | write_edge_dist | write_terr_edge){
for (k in sort(unique(baea$year))) dir.create(file.path(output_dir, k),
showWarnings = FALSE)
}
distance_df <- data.frame(year = numeric(), id=character(),
home_dist_min=numeric(), home_dist_max=numeric(), con_dist_min=numeric(),
con_dist_max=numeric(), edge_dist_min=numeric(), edge_dist_max=numeric())
cellsize <- res(base)[1]
max_r_cells <- ceiling(max_r/cellsize)
xmin <- xmin(base)
ymin <- ymin(base)
for (i in 1:nrow(nest_set)){
nest_set[i, "x"] <- CenterXYInCell(nest_set[i,"long_utm"],
nest_set[i,"lat_utm"], xmin, ymin, cellsize)[1]
nest_set[i, "y"] <- CenterXYInCell(nest_set[i,"long_utm"],
nest_set[i,"lat_utm"], xmin, ymin, cellsize)[2]
}
for (i in sort(unique(baea$year))){
baea_year <- baea %>% dplyr::filter(year == i)
active_year <- paste0("active_", i)
col <- which(colnames(nest_set) == active_year)
df_all <- nest_set[which(nest_set[,col] == TRUE), ]
year_nest <- unique(baea_year$nest_site)
df_home <- df_all %>% dplyr::filter(nest_site %in% year_nest)
df_all_sp <- SpatialPointsDataFrame(df_all[,c("x","y")], df_all,
proj4string=crs(base))
homerange_ids <- df_home[,id]
total <- length(homerange_ids)
for (j in 1:nrow(df_home)) {
hr_nest_site <- df_home[j,] %>% dplyr::select(id) %>% dplyr::pull()
id_year_xy <- baea %>%
dplyr::filter(nest_site == hr_nest_site) %>%
dplyr::filter(year == i) %>%
dplyr::mutate(x = long_utm) %>%
dplyr::mutate (y = lat_utm) %>%
dplyr::select(x,y)
sv <- baea$nest_site == hr_nest_site & baea$year == i
sv <- ifelse(is.na(sv), FALSE, sv)
home <- df_home[j,]
ifelse(is.null(name), home_name <- j, home_name <- home[,name])
writeLines(noquote(paste0("Calculating nest and edge distances for ",
i, ": ", home_name, " (", j, " of ", total, ").")))
home_sp <- sp::SpatialPointsDataFrame(home[,c("x","y")], home,
proj4string=crs(base))
xy <- c(home_sp@coords[,"x"], home_sp@coords[,"y"])
cell_extent <- raster::extent(xy[1]-(cellsize/2), xy[1]+(cellsize/2),
xy[2]-(cellsize/2), xy[2]+(cellsize/2))
cell <- setValues(raster(cell_extent,crs=projection(base),res=cellsize),j)
home_ext <- raster::extend(cell, c(max_r_cells, max_r_cells), value=NA)
home_dist <- raster::distanceFromPoints(home_ext, home[,c("x","y")])
plot(home_dist)
if (write_home_dist == TRUE) {
filename <- file.path(output_dir, i, paste0("HomeDist_", home_name,
".tif"))
raster::writeRaster(home_dist, filename=filename, format="GTiff",
overwrite=TRUE)
writeLines(noquote(paste("Writing:", filename)))
}
base_crop <- raster::raster(raster::extent(home_ext), resolution=30,
crs=raster::crs(home_ext))
rm(home_ext)
base_crop <- raster::setValues(base_crop, runif(ncell(base_crop), 1, 10))
con_dist <- raster::distanceFromPoints(base_crop,
df_all_sp[which(df_all_sp$nest_area != home$nest_area),])
# raster::plot(con_dist)
if (write_con_dist == TRUE) {
filename <- file.path(output_dir, i, paste0("ConDist_", home_name,
".tif"))
writeLines(noquote(paste0("Writing: ", filename)))
writeRaster(con_dist, filename=filename, format="GTiff",
overwrite=TRUE)
}
fun <- function(x){ raster::extract(con_dist, home_sp) - x }
con_dist_nest <- calc(con_dist, fun)
if (write_con_dist_nest == TRUE) {
filename <- file.path(output_dir, i, paste0("ConDistNest_", home_name,
".tif"))
writeLines(noquote(paste0("Writing: ", filename)))
writeRaster(con_dist_nest, filename=filename, format="GTiff",
overwrite=TRUE)
}
baea[sv, "con_dist"] <- raster::extract(con_dist, id_year_xy)
baea[sv, "con_dist_min"] <- cellStats(con_dist, min)
baea[sv, "con_dist_nest"] <- raster::extract(con_dist, home_sp)
k <- nrow(distance_df) + 1
distance_df[k, "con_dist_min"] <- cellStats(con_dist, min)
distance_df[k, "con_dist_max"] <- cellStats(con_dist, max)
distance_df[k, "con_dist_max"] <- raster::extract(con_dist, home_sp)
rm(con_dist)
global_dist_crop <- distanceFromPoints(base_crop, df_all_sp)
rm(base_crop)
cent_dist <- overlay(home_dist, global_dist_crop, fun = function(x,y){
ifelse(x != y, NA, x)})
baea[sv, "home_dist"] <- raster::extract(home_dist, id_year_xy)
distance_df[k, "home_dist_min"] <- cellStats(home_dist, min)
distance_df[k, "home_dist_max"] <- cellStats(home_dist, max)
cent_bounds <- boundaries(cent_dist)
rm(home_dist)
if (write_terr_edge == TRUE) {
terr_edge <- cent_bounds
terr_edge[terr_edge == 0] <- NA
terr_edge_poly <- rasterToPolygons(terr_edge, n=4, # fun=function(x){x==1},
digits = 8, dissolve=FALSE)
file_dir <- file.path(output_dir, i, "TerrEdge_Shapefiles")
if(!dir.exists(file_dir)) dir.create(file_dir)
writeLines(noquote(paste0("Writing: ", file.path(file_dir, paste0(
"TerrEdge_", home_name)))))
rgdal::writeOGR(terr_edge_poly, dsn = file_dir, layer = paste0(
"TerrEdge_", home_name), driver = "ESRI Shapefile", overwrite_layer =
TRUE)
rm(terr_edge_poly)
}
cent_bounds <- subs(cent_bounds, data.frame(from=c(0,1), to=c(NA,1)))
edge_dist_abs <- distance(cent_bounds)
rm(cent_bounds) # new
edge_dist <- overlay(cent_dist, edge_dist_abs, fun=function(x,y)
{ifelse(!is.na(x), y*-1, y*1)})
rm(cent_dist, edge_dist_abs)
if (write_edge_dist == TRUE) {
filename <- file.path(output_dir, i, paste0("EdgeDist_", home_name,
".tif"))
writeLines(noquote(paste0("Writing: ", filename)))
writeRaster(edge_dist, filename=filename, format="GTiff",
overwrite=TRUE)
edge_dist_shift <- calc(edge_dist, function(x) x - cellStats(edge_dist,
min))
filename <- file.path(output_dir, i, paste0("EdgeDistShift_", home_name,
".tif"))
writeLines(noquote(paste0("Writing: ", filename)))
writeRaster(edge_dist_shift, filename=filename, format="GTiff",
overwrite=TRUE)
rm(edge_dist_shift)
}
baea[sv, "edge_dist"] <- raster::extract(edge_dist, id_year_xy)
baea[sv, "edge_dist_min"] <- cellStats(edge_dist, min)
rm(sv, id_year_xy)
distance_df[k, "year"] <- i
distance_df[k, "id"] <- home_name
distance_df[k, "edge_dist_min"] <- cellStats(edge_dist, min)
distance_df[k, "edge_dist_max"] <- cellStats(edge_dist, max)
rm(edge_dist)
}
}
filepath <- file.path(output_dir, "Raster_Distance_Metrics.csv")
writeLines(noquote(paste0("Writing: ", filepath)))
write.csv(distance_df, filepath)
baea$con_dist_shift <- baea$con_dist - baea$con_dist_min
baea$edge_dist_shift <- baea$edge_dist - baea$edge_dist_min
return(baea)
}
#' Creates and exports homerange kernels
#'
#' Creates RasterLayers of homerange kernels based on home centroids
#'
#' @usage AddHomeRangeKernelsBAEA(baea, nest_set, set_name, base, output_dir,
#' max_r, home_inflection, home_scale, avoid_inflection, avoid_scale,
#' min_prob, write_distance, write_homerange)
#'
#' @param baea dataframe of all homerange centroids
#' @param nest_set dataframe of nests
#' @param set_name character, name of nest set
#' @param base base Raster that sets the projection, extent, and dimensions of
#' the study area
#' @param output_dir directory for output files (distance, homerange)
#' @param max_r maximum radius to calculate the homerange raster from each
#' df_home centroid
#' @param home_inflection inflection point of the Logistic function that governs
#' the home kernel
#' @param home_scale scale parameter of the Logistic function that governs the
#' scale parameter
#' @param avoid_inflection inflection point of the Logistic function that
#' governs the conspecific avoidance kernel
#' @param avoid_scale scale parameter of the Logistic function that governs
#' the conspecific avoidance kernel
#' @param min_prob numeric, minimum probablity threshold; all probabilities
#' below this value will be rounded to zero. Default is 0.
#' @param write_distance logical, write distance raster to file. Default is
#' FALSE.
#' @param write_homerange logical, write home range raster to file. Default is
#' FALSE.
#'
#' @return A list containing homerange kernel Rasters for all the df_home
#' centroids
#'
#' @importFrom magrittr "%>%"
#' @export
#'
#' @details Create a folder for every year in the output directory
#'
AddHomeRangeKernelsBAEA <- function(baea,
nest_set,
set_name,
base,
output_dir = getwd(),
max_r,
home_inflection,
home_scale,
avoid_inflection,
avoid_scale,
min_prob = 0,
write_distance = TRUE,
write_homerange = TRUE){
id <- "nest_site"
name <- "name"
# unlink(output_dir, recursive=TRUE)
if(!dir.exists(output_dir)) {
dir.create(output_dir)
for (k in sort(unique(baea$year))) dir.create(file.path(output_dir, k))
}
for (i in sort(unique(baea$year))){
baea_year <- baea %>% filter(year == i)
active_year <- paste0("active_", i)
col <- which(colnames(nest_set) == active_year)
df_all <- nest_set[which(nest_set[,col] == TRUE), ] %>%
mutate(x = long_utm) %>%
mutate(y = lat_utm)
year_nest <- unique(baea_year$nest_site)
df_home <- df_all %>% dplyr::filter(nest_site %in% year_nest)
homeranges_year <- CreateHomeRangeKernelsBAEA(df_all, df_home, base, max_r,
home_inflection, home_scale, avoid_inflection, avoid_scale, min_prob,
id, name, output_dir=file.path(output_dir, i), write_distance,
write_homerange)
for (j in 1:length(homeranges_year)){
homerange_year <- homeranges_year[[j]]
hr_nest_site <- gsub("X", "", names(homerange_year))
id_year_xy <- baea %>%
filter(nest_site == hr_nest_site) %>%
filter(year == i) %>%
mutate(x = long_utm) %>%
mutate (y = lat_utm) %>%
select(x,y)
baea_name <- unique(baea %>%
filter(nest_site == hr_nest_site) %>%
select(id))[1,1]
ExportKMLRasterOverlay(raster = homerange_year,
color_pal = rev(jet2.col(255)), alpha=0.75, zip=TRUE,
method="ngb", overwrite=TRUE, maxpixels = 300000, blur=10,
colNA="transparent", outfile=paste0("HomeRange_", baea_name),
output_dir=file.path(output_dir, i))
id_year_xy_extract <- extract(homerange_year, id_year_xy)
sv <- baea$nest_site == hr_nest_site & baea$year == i
sv <- ifelse(is.na(sv), FALSE, sv)
baea[sv, set_name] <- id_year_xy_extract
}
}
return(baea)
}
#' Adds nest behavior to baea dataframe
#'
#' Finds nest attendance behavior that meet given threshold parameters
#'
#' @param df dataframe
#' @param distance_threshold distance (in meters) from location to nest to assign
#' a location as "nest" behavior
#'
#' @return dataframe with 'bh_nest' column that has "nest"
#' @export
#'
#' @details need to run AddNestData() prior to running this
#'
AddNestBehavior <- function(df = df,
distance_threshold = 50) {
df <- df
df <- df %>%
mutate(bh_nest = ifelse(nest_dist <= distance_threshold, "Nest", NA))
return(df)
}
#' Adds nest and conspecific distances
#'
#' Adds nest and conspecific distances to dataframe
#'
#' @usage AddNestConDist(df, nests_con_dist)
#'
#' @param df dataframe of locations, must have coordinate columns
#'
#' @return dataframe with "nest_dist" and "con_dist" columns
#' @export
#'
#' @details The nest_con_dist has to have structure of list[[year]][[nest_id]]
#'
AddNestConDist<- function(df,
nest_con_dist = nest_con_dist) {
df <- df
nest_con_dist <- nest_con_dist
AddDistances <- function(df){
df <- df
coordinates(df) <- cbind(df$long_utm, df$lat_utm)
proj4string(df) <- sp::CRS("+proj=utm +zone=19 +datum=NAD83")
nest_id <- unique(df$nest_id)
year <- unique(df$year)
dists <- nest_con_dist[[as.character(year)]][[nest_id]]
df$nest_dist <- round(as.vector(unlist(raster::extract(dists, df, layer=1,
nl=1))))
df$con_dist <- round(as.vector(unlist(raster::extract(dists, df, layer=2,
nl=1))))
output <- as.data.frame(df)
return(output)
}
output <- ddply(df, .(year, id), AddDistances)
output$x <- NULL
output$y <- NULL
return(output)
}
#' Add perch behavior
#'
#' Finds perch behavior that meets given threshold parameters
#'
#' @usage AddPerchBehavior(df, max_speed)
#'
#' @param df dataframe
#' @param max_speed numeric, speed over which behavior is no longer considered
#' perch.
#'
#' @return dataframe with behavior column that has "perch"
#' @export
#'
AddPerchBehavior <- function(df = df,
max_speed = 5) {
df <- df
df$bh_perch <- ifelse(df$speed < max_speed, "perch", df$behavior)
return(df)
}
#' Adds roost behavior to dataframe
#'
#' Finds roost arrivals and departures that meet given threshold parameters
#'
#' @usage AddRoostBehavior(df, at_roost_distance_threshold, depart_timediff_max,
#' arrive_timediff_max)
#'
#' @param df dataframe
#' @param at_roost_distance_threshold numeric max distance away from roost
#' @param depart_timediff_max max diff between start of day and depart
#' @param arrive_timediff_max max diff between end of day and arrival
#'
#' @return dataframe with 'bh_roost' column that has arrive, depart, and roost
#' @export
#'
#' @details Adds 'bh_roost' column
AddRoostBehavior <- function(df,
at_roost_distance_threshold = 50,
depart_timediff_max = 1000,
arrive_timediff_max = 1000){
df <- df
df_departure <- df %>% filter(datetime < solarnoon)
df_arrival <- df %>% filter(datetime > solarnoon)
depart <- df_departure %>%
group_by(date, id) %>%
mutate(away_from_roost =
if_else(dist_first > at_roost_distance_threshold | bh_nest == "Nest",
1, 0)) %>%
mutate(depart_roost = away_from_roost == 1 &
!duplicated(away_from_roost == 1)) %>%
mutate(lead_depart = lead(depart_roost, 1)) %>%
mutate(roost = ifelse(lead_depart == 1, "Depart", NA)) %>%
mutate(pos_depart = which(roost == "Depart")[1]) %>%
mutate(pos_all = 1) %>%
mutate(pos_cumsum = cumsum(pos_all)) %>%
mutate(roost = ifelse(pos_cumsum < pos_depart, "Roost", roost)) %>%
ungroup() %>%
dplyr::select(id, datetime, roost) %>%
mutate(roost_depart = TRUE)
arrive <- df_arrival %>%
group_by(date, id) %>%
arrange(desc(datetime)) %>%
mutate(away_from_roost =
if_else(dist_last > at_roost_distance_threshold | bh_nest == "Nest",
1, 0)) %>%
mutate(arrive_roost = away_from_roost == 1 &
!duplicated(away_from_roost == 1)) %>%
mutate(lead_arrive = lead(arrive_roost, 1)) %>%
mutate(roost = ifelse(lead_arrive == 1, "Arrive", NA)) %>%
mutate(pos_arrive = which(roost == "Arrive")[1]) %>%
mutate(pos_all = 1) %>%
mutate(pos_cumsum = cumsum(pos_all)) %>%
mutate(roost = ifelse(pos_cumsum < pos_arrive, "Roost", roost)) %>%
arrange(id, datetime) %>%
ungroup() %>%
dplyr::select(id, datetime, roost) %>%
mutate(roost_arrive = TRUE)
df_roost <- full_join(arrive, depart, by = c("id", "datetime")) %>%
arrange(id, datetime) %>%
mutate(bh_roost = coalesce(roost.x, roost.y)) %>%
dplyr::select(id, datetime, bh_roost)
df_final <- left_join(df, df_roost, by = c("id", "datetime"))
return(df_final)
}
#' Adds 'season' to dataframe
#'
#' Adds 'season' column to original dataframe. Seasons start at 3-19, 6-20,
#' 9-21, and 12-20 for "Spring", "Summer", "Fall", and "Winter", respectively.
#'
#' @usage AddSeason(df, date_col)
#'
#' @param df dataframe
#' @param by date column. Default is "date".
#'
#' @return dataframe with 'season' column
#' @export
#'
#'
AddSeason <- function(df,
date_col = "date"){
df <- df
df$date <- df[,date_col]
numeric_date <- 100*month(df$date) + day(df$date)
cuts <- base::cut(numeric_date, breaks = c(0, 0319, 0620, 0921, 1220, 1231))
levels(cuts) <- c("winter", "spring", "summer", "fall", "winter")
cuts <- as.character(cuts)
df$season <- cuts
return(df)
}
#' Adds time step proportions
#'
#' Adds time_steps, day_min, time_after_start, and time_proportion data
#'
#' @param df dataframe
#' @param by grouping column. Default is "id"
#' @param time_step time step length, based on lubriate times. Default is
#' "15 min".
#' @param tz timezone for dataset. Default is "Etc/GMT+5"
#'
#' @return dataframe with time_steps, day_min, time_after_start, and
#' time_proportion data
#' @export
#'
#' @details need to run AddSolarTimes() prior to running this function
#'
AddTimeStepProportion <- function(df = df,
by = "id",
time_step = "15 min",
tz = "Etc/GMT+5") {
df <- df
df$by <- df[,by]
DailyTimeStepCount <- function (df=df){
days <- subset(df, select=c("id", "date", "hr_before_sunrise",
"hr_after_sunset"))
days <- plyr::ddply(days, plyr::.(date), function(x) x[1, ]) # first records
days$time_steps <- NA
days$day_min <- NA
for (i in 1:nrow(days)) {
day <- days[i,]
days[i,"time_steps"] <- length(seq(day[,"hr_before_sunrise"],
day[,"hr_after_sunset"], time_step))
days[i,"day_min"] <- as.integer(difftime(day[,"hr_after_sunset"],
day[,"hr_before_sunrise"],tz=tz, units = ("mins")))
}
return(days)
}
df2 <- plyr::ddply(df, plyr::.(by), DailyTimeStepCount)
df2 <- merge(df, df2, all.x=TRUE)
df2$time_after_start <- as.integer(difftime(df2$datetime,
df2$hr_before_sunrise, tz=tz, units = ("mins")))
df2$time_proportion <- df2$time_after_start/df2$day_min
df2$by <- NULL
return(df2)
}
#' Analyses overlap of homeranges in paired nest locations
#'
#' Analyzes pair locations to determine mid-way point betweeen nests and
#' proportion of overlapping locations
#'
#' @usage AnalyzePairLocation(pair, nests, points, mid_length, zoom)
#'
#' @param pair pair to be analyzed, first nest is analyzed
#' @param nests nest locations
#' @param points baea locations
#' @param mid_length length of mid-line.
#' @param zoom integer (2-22) of google map zoom, default = 10.
#'
#' @return Multiple output: writes .csv, plots, and dataframe
#'
#' @importFrom magrittr "%>%"
#' @export
#'
AnalyzePairLocations <- function(pair,
nests,
points,
mid_length,
zoom = 12){
crs_utm <- "+proj=utm +zone=19 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"
crs_proj <- "+proj=longlat +datum=WGS84"
nests_pair <- nests[nests$name %in% pair,]
nests_pair_df <- as.data.frame(nests_pair)
pair_dist <- round(sqrt(sum((c(nests_pair$long_utm[1], nests_pair$lat_utm[1])-
c(nests_pair$long_utm[2], nests_pair$lat_utm[2]))^2)))/1000
points1 <- points[points$id == pair[1], ]
mid_pt_df <- cbind.data.frame(long_utm = (sum(nests_pair$long_utm))/2,
lat_utm = (sum(nests_pair$lat_utm))/2)
mid_pt <- SpatialPointsDataFrame(mid_pt_df[c("long_utm", "lat_utm")],
bbox=NULL, data=mid_pt_df, proj4string=CRS(crs_utm))
angle1 <- ConvertAngle(CalculateAngleToPoint(nests_pair$long_utm[1],
nests_pair$lat_utm[1], nests_pair$long_utm[2], nests_pair$lat_utm[2]) +
(pi/2))
angle2 <- ConvertAngle(CalculateAngleToPoint(nests_pair$long_utm[1],
nests_pair$lat_utm[1], nests_pair$long_utm[2], nests_pair$lat_utm[2]) -
(pi/2))
mid_ends_df <- data.frame(long_utm=NA, lat_utm=NA)
mid_ends_df[1,]<- CoordinatesFromAngleLength(mid_pt_df[1,], angle1,mid_length)
mid_ends_df[2,]<- CoordinatesFromAngleLength(mid_pt_df[1,], angle2,mid_length)
mid_ends <- SpatialPointsDataFrame(mid_ends_df[c("long_utm", "lat_utm")],
bbox=NULL, data=mid_ends_df, proj4string=CRS(crs_utm))
mid_line <- CreateSpatialLines(df=mid_ends_df, long="long_utm", lat="lat_utm",
crs=crs_utm)
nests_pair_df <- as.data.frame(nests_pair) %>% dplyr::select(long_utm,lat_utm)
poly_df <- rbind(nests_pair_df[1,], mid_ends_df[1,], nests_pair_df[2,],
mid_ends_df[2,])
poly_sp <- CreateSpatialPolygons(poly_df, long="long_utm", lat="lat_utm",
crs=crs_utm)
points1_inside <- as.data.frame(points1[poly_sp, "home_dist"])
points1_inside_count <- nrow(points1_inside)
points1_inside$home_nest <- pair[1]
points1_inside$con_nest <- pair[2]
points1_inside$pair_dist <- pair_dist
points1_inside$mid_length <- mid_length
points1_inside <- points1_inside %>% dplyr::select(home_nest, pair_dist,
everything(), con_nest)
out_folder <- file.path(getwd(), "Points_Inside", mid_length)
ifelse(!dir.exists(out_folder), dir.create(out_folder), FALSE)
write.csv(points1_inside, file=file.path(out_folder, paste0(pair[1], "_",
pair[2], ".csv")), row.names = FALSE)
poly_sp_df <- tidy(poly_sp)
centroids <- coordinates(poly_sp)
x <- centroids[,1]
y <- centroids[,2]
poly_spdf <- SpatialPolygonsDataFrame(poly_sp, data=data.frame(x=x, y=y,
row.names=row.names(poly_sp)))
rgdal::writeOGR(obj=poly_spdf, dsn = file.path(getwd(), "Polys"),
layer=paste0(pair[1], "_", pair[2]), driver = "ESRI Shapefile",
overwrite_layer = TRUE)
out_folder <- file.path(image_output, "Pair Maps", mid_length)
ifelse(!dir.exists(out_folder), dir.create(out_folder), FALSE)
out_folder <- file.path(image_output, "Pair Locations", mid_length)
ifelse(!dir.exists(out_folder), dir.create(out_folder), FALSE)
# Location Graphs
gg <- ggplot() + theme_no_legend +
geom_polygon(data=poly_sp_df, aes(x=long, y=lat), fill="dodgerblue1",
colour="black", size=1) +
geom_path(data=as.data.frame(coordinates(mid_line)), aes(x=long_utm,
y=lat_utm), colour="grey80", size=1, linetype=2)
x_diff <- diff(range(poly_sp_df$long))
y_diff <- diff(range(poly_sp_df$lat))
axis_max <- which.max(c(x_diff, y_diff))
if (axis_max == 1) {
y_mean <- mean(range(poly_sp_df$lat))
y_add <- diff(range(poly_sp_df$long)/2)
gg <- gg + coord_fixed(ratio=1, ylim=c(y_mean - y_add, y_mean + y_add),
xlim = range(poly_sp_df$long))
} else {
x_mean <- mean(range(poly_sp_df$long))
x_add <- diff(range(poly_sp_df$lat)/2)
gg <- gg + coord_fixed(ratio=1, xlim=c(x_mean - x_add, x_mean + x_add),
ylim = range(poly_sp_df$lat))
}
gg <- gg + geom_point(data=as.data.frame(points1), aes(x=long_utm,y=lat_utm),
colour="red", size=1) +
geom_point(data=points1_inside, aes(x=long_utm,y=lat_utm),
colour="yellow", size=1.25) +
ggtitle(paste0(pair[1], " - ", pair[2], " (n=", points1_inside_count,
")"))
plot(gg)
SaveGGPlot(paste0(pair[1], "_", pair[2], ".jpeg"), file.path(image_output,
"Pair Locations", mid_length))
# GG Maps
points1_inside_sp <- points1[poly_sp, "home_dist"]
points1_inside_wgs84 <- as.data.frame(spTransform(points1_inside_sp,
CRS(crs_proj)))
points1_wgs84 <- as.data.frame(spTransform(points1, CRS(crs_proj)))
mid_pt_wgs84 <- as.data.frame(spTransform(mid_pt, CRS(crs_proj)))
mid_ends_wgs84 <- spTransform(mid_ends, CRS(crs_proj))
poly_wgs84 <- tidy(spTransform(poly_sp, CRS(crs_proj)))
points1_inside_count <- nrow(points1_inside_wgs84)
ptspermm <- 2.83464567
title_text <- paste0(pair[1], " - ", pair[2], " (n=", points1_inside_count,
")")
nest_map <- get_map(location = c(lon=mid_pt_wgs84[1,3],
lat=mid_pt_wgs84[1,4]), color="color", source="google",
maptype="hybrid", zoom=zoom)
nest_ggmap <- ggmap(nest_map, extent="device", ylab="Latitude",
xlab="Longitude", legend="right")
# Sys.sleep(2)
bb <- attr(nest_map, "bb")
# bb_diag <- bb$ll.lat - bb$ur.lat
scalebar.length = 5
sbar <- data.frame(long_start = c(bb$ll.lon + 0.1*(bb$ur.lon - bb$ll.lon)),
long_end = c(bb$ll.lon + 0.25*(bb$ur.lon - bb$ll.lon)),
lat_start = c(bb$ll.lat + 0.1*(bb$ur.lat - bb$ll.lat)),
lat_end = c(bb$ll.lat + 0.1*(bb$ur.lat - bb$ll.lat)),
bb_diag = bb$ur.lat - bb$ll.lat,
scalebar.length = scalebar.length)
map_title <- cbind.data.frame(name=title_text, x = (bb$ll.lon + bb$ur.lon)/2,
y = bb$ur.lat - 0.01)
sbar$distance <- geosphere::distVincentyEllipsoid(c(sbar$long_start,
sbar$lat_start), c(sbar$long_end,sbar$lat_end))
sbar$long_end <- sbar$long_start +
((sbar$long_end-sbar$long_start)/sbar$distance) * scalebar.length*1000
gg <-
nest_ggmap +
geom_polygon(data=poly_wgs84, aes(x=long, y=lat), alpha=0.8,
fill="dodgerblue1", color="black", size=0.2) +
geom_path(data=as.data.frame(coordinates(mid_ends_wgs84)), aes(x=long_utm,
y=lat_utm), colour="grey80", size=1, linetype=2) +
geom_point(data=points1_wgs84, aes(x=long, y=lat), shape=19, alpha=.9,
color="red", size=.75, stroke=1, na.rm=TRUE) +
geom_point(data=points1_inside_wgs84, aes(x=long_utm,y=lat_utm), shape=19,
alpha=.75, color="yellow", size=2, stroke=1, na.rm=TRUE) +
geom_segment(data = sbar, aes(x=long_start, xend=long_end, y=lat_start,
yend=lat_end), size=1.25, arrow=arrow(angle=90, length=unit(0.2, "cm"),
ends="both", type="open"), color="white") +
geom_text(data = sbar, aes(x = (long_start + long_end)/2, y = lat_start +
0.025*(bb_diag), label=paste(format(scalebar.length),'km')),
hjust=0.5, vjust=.7, size=18/ptspermm, color="white") +
geom_text(data = map_title, aes(x=x, y=y, label=name), size=24/ptspermm,
color="white") +
theme(legend.justification=c(1,1), legend.position=c(1,1))
print(gg)
SaveGGPlot(paste0(pair[1], "_", pair[2], ".jpeg"), file.path(image_output,
"Pair Maps", mid_length), bg = "black")
return(points1_inside)
}
#' Converts nest alphanumeric id to nest numeric id
#'
#' Converts alphanumeric "nest_id" column to a numeric "nest_id_num" column,
#' useful for creating RasterLayers associated with nests
#'
#' @usage ConvertNestIdToNum(df)
#'
#' @param df input dataframe with "nest_id" column
#'
#' @return A dataframe with a numberic "nest_id_num" column
#' @export
#'
#' @details If a "nest_id_num" column doesn't exist, the function
#' automatically creates one.
#'
ConvertNestIdToNum <- function(df){
df <- df
if(!"nest_id" %in% colnames(df)) {
df$nest_id <- df$nest_site
}
if(!"nest_id_num" %in% colnames(df)) {
df$nest_id_num <- NA
}
nest_id <- df$nest_id
territory_number <- sapply(strsplit(nest_id, "[A-Z]"), "[", 1)
nest_letter <- stringr::str_extract(nest_id, "[A-Z]")
nest_number <- sapply(strsplit(nest_id, "[A-Z]"), "[", 2)
nest_number[is.na(nest_number)] <- ""
letters <- LETTERS[1:26] # had only gone to "k" in 2012
numbers <- formatC(1:26, width = 2, format = "d", flag = "0")
for (i in 1:length(letters)){
nest_letter <- gsub(letters[i], numbers[i], nest_letter)
}
df$nest_id_num <- as.numeric(sprintf("%s%s%s", territory_number, nest_letter,
nest_number))
return(df)
}
#' Converts nest numeric id to nest alphanumeric id
#'
#' Converts a numeric "nest_id_num" column to an alphanumeric "nest_id" column
#'
#' @usage ConvertNestIdToNum(df)
#'
#' @param df input dataframe with "nest_id_num" column
#'
#' @return A dataframe with a numberic "nest_id" column
#' @export
#'
#' @details If a "nest_id" column doesn't exist, the function automatically
#' creates one
ConvertNestNumToId <- function(df){
df <- df
if(!"nest_id" %in% colnames(df)) {
df$nest_id <- NA
}
nest_id_num <- df$nest_id_num
letters <- LETTERS[1:26] # had only gone to "k" in 2012
numbers <- formatC(1:26, width = 2, format = "d", flag = "0")
for (i in 1:length(nest_id_num)){
if (nchar(nest_id_num[i]) == 3){
territory_number<- sprintf("%03d", as.numeric(substr(nest_id_num[i],1,1)))
nest_letter <- substr(nest_id_num[i], 2, 3)
for (j in 1:length(letters)){
nest_letter <- gsub(numbers[j], letters[j], nest_letter)
}
df$nest_id[i] <- paste(territory_number, nest_letter, sep="")
}
if (nchar(nest_id_num[i]) == 4){
territory_number<- sprintf("%03d", as.numeric(substr(nest_id_num[i],1,2)))
nest_letter <- substr(nest_id_num[i], 3, 4)
for (j in 1:length(letters)){
nest_letter <- gsub(numbers[j], letters[j], nest_letter)
}
df$nest_id[i] <- paste(territory_number, nest_letter, sep="")
}
if (nchar(nest_id_num[i]) == 5){
territory_number <- substr(nest_id_num[i], 1, 3)
nest_letter <- substr(nest_id_num[i], 4, 5)
for (j in 1:length(letters)){
nest_letter <- gsub(numbers[j], letters[j], nest_letter)
}
df$nest_id[i] <- paste(territory_number, nest_letter, sep="")
}
if (nchar(nest_id_num[i]) == 7){
territory_number <- substr(nest_id_num[i], 1, 3)
nest_letter <- substr(nest_id_num[i], 4, 5)
nest_number <- substr(nest_id_num[i], 6, 7)
for (j in 1:length(letters)){
nest_letter <- gsub(numbers[j], letters[j], nest_letter)
}
df$nest_id[i] <- paste(territory_number, nest_letter, nest_number,
sep="")
}
if (nchar(nest_id_num[i]) == 8){
territory_number <- substr(nest_id_num[i], 1, 4)
nest_letter <- substr(nest_id_num[i], 5, 6)
nest_number <- substr(nest_id_num[i], 7, 8)
for (j in 1:length(letters)){
nest_letter <- gsub(numbers[j], letters[j], nest_letter)
}
df$nest_id[i] <- paste(territory_number, nest_letter, nest_number,
sep="")
}
}
return(df)
}
#' Convert step data coordinates to WGS84
#'
#' Converts "x", "y" columns to coordinates to lat/long WGS84 (for Google)
#'
#' @usage ConvertStepDataCoordinates(df)
#'
#' @param df input dataframe with "x", "y" columns
#' @param crs string of projection for "x", "y" columns, default is for Maine
#' BAEA GPS data (UTM Zone 19N).
#'
#' @return A dataframe with added "long", "lat" columns
#' @export
#'
#' @details
#'
ConvertStepDataCoordinates <- function(df,
crs = "+proj=utm +zone=19 ellps=WGS84"){
df <- df
sp::coordinates(df) <- c("x", "y")
sp::proj4string(df) <- sp::CRS(crs)
res <- sp::spTransform(df, CRS("+proj=longlat +datum=WGS84"))
long_lat <- sp::coordinates(res)
colnames(long_lat) <- c("long", "lat")
output <- cbind.data.frame(df, long_lat)
output$optional <- NULL
return(output)
}
#' Creates colors based on any factor in the dataframe
#'
#' Creates and/or displays dataframe of "by" variable and associated colors#'
#'
#' @usage CreateColorsByAny(by, df, r_pal, b_pal, output, plot, ...)
#'
#' @param by variable to determine colors. Specific outcomes for: "behavior",
#' "id", or "sex"
#' @param df dataframe with "by" variable - only required if "by" is not
#' "behavior", "id", or "sex"
#' @param pal dataframe with "by" variable - only required if "by" is not
#' "behavior", "id", or "sex"
#' @param r_pal color palette for CreateVarsColors(), default is NULL
#' @param b_pal color palette from RColorBrewer for CreateVarsColors(), default
#' is "Set1".
#' @param output color palette from RColorBrewer for CreateVarsColors(),
#' default is "Set1"
#' @param plot logical, whether or not to display names and colors, default is
#' FALSE
#' @param ... additional parameters for CreateColorsByMetadata()
#'
#' @return df with "by" variable and hexidecimal colors
#' @export
#'
#' @details Used in several other functions. Color palettes determined
#' automatically for "behavior", "id", and "sex". Others set by pal or b_pal.
#' Requires 'kml' associated functions.
CreateColorsByAny <- function (by,
df,
pal = NULL,
r_pal = NULL,
b_pal = "Set1",
output = TRUE,
plot = FALSE,
...) {
if (!is.null(by)){
if (by == "behavior" || by == "id" || by == "sex") {
if (by == "behavior") by_colors <- CreateColorsByMetadata(file=
"Data/Assets/behavior_colors.csv", metadata_id="behavior")
if (by == "id") by_colors <- CreateColorsByMetadata(file=
"Data/GPS/GPS_Deployments.csv", metadata_id="deploy_location")
if (by == "sex") by_colors <- CreateColorsByMetadata(file=
"Data/Assets/behavior_colors.csv", metadata_id="sex")
} else {
by_colors <- CreateColorsByVar(df=df, by=by, pal=pal, r_pal = r_pal, b_pal =
b_pal)
}
} else {
by_colors <- CreateColorsByVar(df=df, by=by, pal=pal, r_pal = r_pal, b_pal =
b_pal)
}
if (plot == TRUE) PlotColorPie(by_colors)
if (output == TRUE) return(by_colors)
}
#' Creates conspecific and nest distance raster for each baea in data
#'
#' @param baea dataframe of baea locations
#' @param nest_set dataframe of nests
#' @param base base Raster that sets the projection, extent, and dimensions of
#' the study area
#' @param output_dir directory for output files (distance, homerange)
#' @param max_r maximum radius to calculate the homerange raster from each
#' df_home centroid
#' @param write_con_nest_all logical, write con_nest_all raster to file.
#' Default is TRUE
#'
#' @return RasterLayer
#'
#' @importFrom magrittr "%>%"
#' @export
#'
#' @details Creates folders for every year in output directory
#'
CreateConNestDistRasters <- function(baea,
nest_set,
base = base,
output_dir = "Output/Analysis/Territorial",
max_r = 30000,
write_con_nest_all = TRUE){
if (!dir.exists(output_dir)) dir.create(output_dir)
for (k in sort(unique(baea$year))) dir.create(file.path(output_dir, k),
showWarnings = FALSE)
raster_files <- vector()
cellsize <- raster::res(base)[1]
max_r_cells <- ceiling(max_r/cellsize)
xmin <- xmin(base)
ymin <- ymin(base)
for (i in 1:nrow(nest_set)){
nest_set[i, "x"] <- CenterXYInCell(nest_set[i, "long_utm"],
nest_set[i, "lat_utm"], xmin, ymin, cellsize)[1]
nest_set[i, "y"] <- CenterXYInCell(nest_set[i, "long_utm"],
nest_set[i, "lat_utm"], xmin, ymin, cellsize)[2]
}
nest_set_sf <- sf::st_as_sf(x = nest_set, coords = c("x", "y"), crs = 32619)
for (i in unique(baea$id)){
baea_i <- baea %>% dplyr::filter(id == i)
for (j in sort(unique(baea_i$year))){
baea_k <- baea_i %>% dplyr::filter(year == j)
nest_k_xy <- baea_k %>% dplyr::slice(1) %>% dplyr::select(nest_long_utm,
nest_lat_utm) %>% as.vector()
nest_k_id <- baea_k %>% dplyr::slice(1) %>% dplyr::select(nest_site) %>%
dplyr::pull()
home_k_x <- CenterXYInCell(nest_k_xy[1], nest_k_xy[2], xmin, ymin,
cellsize)[[1]] # home nest long
home_k_y <- CenterXYInCell(nest_k_xy[1], nest_k_xy[2], xmin, ymin,
cellsize)[[2]] # home nest lat
home_k_xy <- tibble::tibble(x = home_k_x, y = home_k_y)
home_k_sf <- sf::st_as_sf(x = home_k_xy, coords = c("x", "y"), crs=32619)
cell_extent <- raster::extent(home_k_x - (cellsize/2),
home_k_x + (cellsize/2), home_k_y - (cellsize/2),
home_k_y + (cellsize/2))
cell <- raster::setValues(raster(cell_extent, crs = projection(base),
res = cellsize), j)
home_ext <- raster::extend(cell, c(max_r_cells, max_r_cells), value = NA)
summary(home_ext)
home_dist <- raster::distance(home_ext)
home_dist[home_dist > max_r] <- NA
filter_quo <- paste0("active_", j, " == TRUE")
nest_set_sf_j <- nest_set_sf %>%
seplyr::filter_se(filter_quo) %>%
dplyr::filter(nest_site != nest_k_id) # conspecific nests
home_k_buff <- sf::st_buffer(home_k_sf, max_r)
nests_k <- sf::st_contains(home_k_buff, nest_set_sf_j)
nest_set_sf_k <- nest_set_sf_j %>% dplyr::slice(unlist(nests_k))
con_dist <- raster::distanceFromPoints(home_ext,
sf::st_coordinates(nest_set_sf_k)) # raster of nests
# Nearest neighbor nest distance at home nest
home_con_dist <- raster::extract(con_dist, home_k_xy)
con_dist_home <- raster::calc(con_dist, function(x){home_con_dist - x})
con_dist_zero <- raster::calc(con_dist_home, function(x){if_else(x >= 0,
x, 0)}) # created to compare to con_dist_home, but not used)
con_nest_k <- raster::overlay(home_dist, con_dist_home,
fun = function(x,y){round(x + y)})
filename_k <- file.path(output_dir, j, paste0("ConNest_", i, ".tif"))
raster::writeRaster(con_nest_k, filename = filename_k, format = "GTiff",
overwrite = TRUE)
writeLines(noquote(paste("Writing:", filename_k)))
raster_files <- append(raster_files, filename_k)
}
}
con_nest <- list()
for(i in 1:length(raster_files)){con_nest[[i]] <- raster(raster_files[i])}
con_nest_all <- do.call(raster::merge, con_nest)
filename <- "Output/Analysis/Territorial/ConNest_All.tif"
if(isTRUE(write_con_nest_all)){
raster::writeRaster(con_nest_all, filename = filename, format = "GTiff",
overwrite = TRUE)
}
writeLines(noquote(paste("Writing:", filename)))
return(con_nest_all)
}
#' Create homerange kernels for the BAEA nests
#'
#' Creates RasterLayers of homerange kernels based on home centroids
#'
#' @usage CreateHomeRangeKernelsBAEA(df_all, df_home, base, max_r,
#' home_inflection, home_scale, avoid_inflection, avoid_scale, output_dir,
#' id, write_distance, write_homerange)
#'
#' @param df_all dataframe of all homerange centroids
#' @param df_home dataframe of homerange centroids to calculate homerange
#' kernels (these must be a subset of the df_all dataframe), Default is to
#' use 'df_all' dataframe
#' @param base base Raster that sets the projection, extent, and dimensions of
#' the study area
#' @param max_r maximum radius to calculate the homerange raster from each
#' df_home centroid
#' @param home_inflection inflection point of the Logistic function that
#' governs the home kernel
#' @param home_scale scale parameter of the Logistic function that governs the
#' scale parameter
#' @param avoid_inflection inflection point of the Logistic function that
#' governs the conspecific avoidance kernel
#' @param avoid_scale scale parameter of the Logistic function that governs the
#' conspecific avoidance kernel
#' @param min_prob numeric, minimum probablity threshold; all probabilities
#' below this value will be rounded to zero. Default is 0.
#' @param id column name of df_home that identifies the homerange. Default is
#' NULL, which sets the names to df_home row number.
#' @param name column name of df_home that identifies the name of the homerange
#' and is used to write the file name of the .tif Default is 'id', which sets
#' the names to df_home row number if 'id' is NULL.
#' @param output_dir directory for output files (distance, homerange)
#' @param write_distance logical, write distance raster to file. Default is
#' FALSE.
#' @param write_homerange logical, write home range raster to file. Default is
#' FALSE.
#'
#' @return A list containing homerange kernel Rasters for all the df_home
#' centroids.
#' @export
#'
#'
CreateHomeRangeKernelsBAEA <- function(df_all,
df_home = df_all,
base,
max_r,
home_inflection,
home_scale,
avoid_inflection,
avoid_scale,
min_prob,
id = NULL,
name = id,
output_dir,
write_distance = FALSE,
write_homerange = FALSE) {
cellsize <- raster::res(base)[1]
max_r_cells <- ceiling(max_r/cellsize)
xmin <- raster::xmin(base)
ymin <- raster::ymin(base)
df_all_sp <- sp::SpatialPointsDataFrame(df_all[,c("x","y")], df_all,
proj4string=crs(base))
homerange_ids <- df_home[,id]
total <- length(homerange_ids)
homerange_kernels <- as.list(setNames(rep(NA,length(homerange_ids)),
homerange_ids), homerange_ids)
for (j in 1:nrow(df_home)) {
home <- df_home[j,]
ifelse(is.null(name), home_name <- j, home_name <- home[,name])
writeLines(noquote(paste0("Calculating homerange for: ", home_name,
" (", j, " of ", total, ").")))
home_sp <- sp::SpatialPointsDataFrame(home[,c("x","y")], home,
proj4string=crs(base))
xy <- CenterXYInCell(home_sp@coords[,"x"], home_sp@coords[,"y"],
xmin, ymin, cellsize)
cell_extent <- raster::extent(xy[1]-(cellsize/2), xy[1]+(cellsize/2), xy[2]-
(cellsize/2), xy[2]+(cellsize/2))
cell <- raster::setValues(raster::raster(cell_extent,
crs=raster::projection(base), res=cellsize), j)
home_ext <- raster::extend(cell, c(max_r_cells, max_r_cells), value=NA)
home_dist <- raster::distanceFromPoints(home_ext, home[,c("x","y")])
home_kern <- raster::calc(home_dist, fun = function(x){(1/(exp((-(x -
home_inflection)) / home_scale) + 1))})
base_crop <- raster::crop(base, extent(home_ext))
global_dist_crop <- raster::distanceFromPoints(base_crop, df_all_sp)
if (write_distance == TRUE) {
filename <- paste0(output_dir,"/ConDist_", home_name, ".tif")
global_dist_crop <- raster::distanceFromPoints(base_crop, df_all_sp)
raster::writeRaster(global_dist_crop, filename=filename, format="GTiff",
overwrite=TRUE)
writeLines(noquote(paste("Writing:", filename)))
} else {
global_dist_crop <- raster::distanceFromPoints(base_crop, df_all_sp)
}
cent_dist <- raster::overlay(home_dist, global_dist_crop, fun=function (x,y)
{ifelse(x != y, NA, x)})
cent_bounds <- raster::boundaries(cent_dist)
cent_bounds <- raster::subs(cent_bounds, data.frame(from=c(0,1),
to=c(NA,1)))
edge_dist_abs <- raster::distance(cent_bounds)
edge_dist <- raster::overlay(cent_dist, edge_dist_abs, fun=function(x,y)
{ifelse(!is.na(x), y*-1, y*1)})
avoid_kern <- raster::calc(edge_dist, fun = function(x){(1/(exp((-(x -
avoid_inflection)) / avoid_scale) + 1))})
homerange_kern <- raster::overlay(avoid_kern, home_kern, fun=function(x,y){
p <- y*x
})
homerange_kern[homerange_kern < min_prob] <- 0
if (write_homerange == TRUE) {
filename <- paste0(output_dir,"/HomeRange_",home_name, ".tif")
writeLines(noquote(paste0("Writing: ", filename)))
raster::writeRaster(homerange_kern, filename=filename, format="GTiff",
overwrite=TRUE)
}
homerange_kernels[[j]] <- homerange_kern
names(homerange_kernels[[j]]) <- df_home[j, id]
}
return(homerange_kernels)
}
#' Create homerange kernels based on interpolating empiricial x,y location data
#'
#' Creates RasterLayers of homerange kernels based on home centroids
#'
#' @usage CreateHomeRangeKernelsInterpolate(df_all, df_home, base, max_r, id,
#' name, min_prob, output_dir, write_homerange)
#'
#' @param df_all dataframe of all homerange centroids
#' @param df_home dataframe of homerange centroids to calculate homerange
#' kernels (these must be a subset of the df_all dataframe), Default is to
#' use 'df_all' dataframe
#' @param base base Raster that sets the projection, extent, and dimensions of
#' the study area
#' @param max_r maximum radius to calculate the homerange raster from each
#' df_home centroid
#' @param id column name of df_home that identifies the homerange.
#' @param name column name of df_home that identifies the name of the homerange
#' and is used to write the name of the .tif file. Default is 'id', which
#' sets the names to df_home row number if 'id' is NULL.
#' @param min_prob numeric, minimum probablity threshold; all probabilities
#' below this value will be rounded to zero. Default is 0.
#' @param output_dir directory for output files (distance, homerange)
#' @param write_distance logical, write distance range raster to file. Default
#' is FALSE
#' @param write_homerange logical, write home range raster to file. Default is
#' FALSE
#'
#' @return A list containing homerange kernel Rasters for all the df_home
#' centroids
#' @export
#'
#' @details Used inside AddHomeRangeKernelsBAEA()
#'
CreateHomeRangeKernelsInterpolate <- function(df_all,
df_home = df_all,
base,
max_r,
id,
name = NULL,
min_prob = 0,
output_dir,
write_distance = FALSE,
write_homerange = FALSE) {
cellsize <- raster::res(base)[1]
max_r_cells <- ceiling(max_r/cellsize)
xmin <- raster::xmin(base)
ymin <- raster::ymin(base)
df_all_sp <- SpatialPointsDataFrame(df_all[,c("x","y")], df_all,
proj4string=raster::crs(base))
homerange_ids <- df_home[,id]
total <- length(homerange_ids)
homerange_kernels <- as.list(setNames(rep(NA,length(homerange_ids)),
homerange_ids), homerange_ids)
for (j in 1:nrow(df_home)) {
home <- df_home[j,]
ifelse(is.null(name), home_name <- j, home_name <- home[,name])
writeLines(noquote(paste0("Calculating homerange for: ", home_name,
" (", j, " of ", total, ").")))
home_sp <- sp::SpatialPointsDataFrame(home[,c("x","y")], home,
proj4string=raster::crs(base))
xy <- CenterXYInCell(home_sp@coords[,"x"], home_sp@coords[,"y"],
xmin, ymin, cellsize)
cell_extent <- raster::extent(xy[1]-(cellsize/2), xy[1]+(cellsize/2), xy[2]-
(cellsize/2), xy[2]+(cellsize/2))
cell <- setValues(raster::raster(cell_extent, crs=raster::projection(base),
res=cellsize),j)
home_ext <- raster::extend(cell, c(max_r_cells, max_r_cells), value=NA)
### NEW SECTION STARTS HERE ###
df_all$r_value <- 0
df_all[df_all[,id] == home[1,id], "r_value"] <- 1
all <- CreateRasterFromPointsAndBase(df_all, "r_value", "x", "y",
base=home_ext)
xy <- data.frame(xyFromCell(all, 1:ncell(all)))
xy_values <- raster::getValues(all)
# thin plate spline model
tps_model <- fields::Tps(xy, xy_values)
# use model to predict values at all locations
homerange_kern <- raster::interpolate(home_ext, tps_model)
### NEW SECTION ENDS HERE ###
homerange_kern[homerange_kern < min_prob] <- 0
if (write_homerange == TRUE) {
filename <- paste0(output_dir,"/HomeRange_",home_name, ".tif")
writeLines(noquote(paste0("Writing: ", filename)))
writeRaster(homerange_kern, filename=filename, format="GTiff",
overwrite=TRUE)
ExportKMLRasterOverlay(homerange_kern, alpha =.8, outfile=paste0(name,
"_Interpolate"), output_dir=getwd())
}
homerange_kernels[[j]] <- homerange_kern
names(homerange_kernels[[j]]) <- df_home[j, name]
}
return(homerange_kernels)
}
#' Create home range kernels using a Pareto distribution
#'
#' Creates RasterLayers of homerange kernels based on home centroids
#'
#' @usage CreateHomeRangeKernelsParetoGamma(df_all, df_home, base, max_r,
#' home_shape, home_scale, min_prob, id, name, output_dir, write_homerange)
#'
#' @param df_all dataframe of all homerange centroids
#' @param df_home dataframe of homerange centroids to calculate homerange
#' kernels (these must be a subset of the df_all dataframe), Default is to
#' use 'df_all' dataframe.
#' @param base base Raster that sets the projection, extent, and dimensions of
#' the study area
#' @param max_r maximum radius to calculate the homerange raster from each
#' df_home centroid
#' @param home_shape inflection point of the Logistic function that governs the
#' home kernel
#' @param home_scale scale parameter of the Logistic function that governs the
#' scale parameter
#' @param id column name of df_home that identifies the homerange. Default is
#' NULL, which sets the names to df_home row number.
#' @param name column name of df_home that identifies the name of the homerange
#' and is used to write the name of the .tif file. Default is 'id', which
#' sets the names to df_home row number if'id' is NULL.
#' @param min_prob numeric, minimum probablity threshold; all probabilities
#' below this value will be rounded to zero. Default is 0.
#' @param output_dir directory for output files (distance, homerange)
#' @param write_homerange logical, write home range raster to file. Default is
#' FALSE
#'
#' @return A list containing homerange kernel Raster for all the df_home
#' centroids
#' @export
#'
CreateHomeRangeKernelsPareto <- function(df_all,
df_home = df_all,
base = base,
max_r,
home_shape,
home_scale,
id = "nest_site",
name ="nest_id",
min_prob = 0,
output_dir = getwd(),
write_homerange = TRUE){
source('C:/Work/R/Functions/sim/move.R')
cellsize <- res(base)[1]
max_r_cells <- ceiling(max_r/cellsize)
xmin <- xmin(base)
ymin <- ymin(base)
df_sp <- SpatialPointsDataFrame(df_all[,c("x","y")], df_all,
proj4string=crs(base))
# base <- crop(base, df_sp, snap='out')
# base <- extend(base, c(max_r_cells/2, max_r_cells/2), value=11)
homerange_ids <- df_home$nest_id
total <- length(homerange_ids)
homerange_kernels <- as.list(setNames(rep(NA,length(homerange_ids)),
homerange_ids), homerange_ids)
for (j in 1:nrow(df_home)) {
writeLines(noquote(paste("Calculating homerange", j, "of", total)))
home <- df_home[j,]
home_sp <- SpatialPointsDataFrame(home[,c("x","y")], home,
proj4string=crs(base))
xy <- CenterXYInCell(home_sp@coords[,"x"], home_sp@coords[,"y"],
xmin, ymin, cellsize)
cell_extent <- extent(xy[1]-(cellsize/2), xy[1]+(cellsize/2), xy[2]-
(cellsize/2), xy[2]+(cellsize/2))
cell <- setValues(raster(cell_extent, crs=projection(base), res=cellsize),j)
home_ext <- extend(cell, c(max_r_cells, max_r_cells), value=NA)
home_dist <- distanceFromPoints(home_ext, home[,c("x","y")])
homerange_kern <- calc(home_dist, fun = function(x){texmex::dgpd(x/1000,
sigma=scale, xi=shape, u=0)})
homerange_kern[homerange_kern < min_prob] <- 0
if (write_homerange == TRUE) {
k <- home[,id]
filename <- paste0(output_dir,"/homerange_", k, ".tif")
writeLines(noquote(paste0("Writing: ", filename)))
writeRaster(homerange_kern, filename=filename, overwrite=TRUE)
}
homerange_kernels[[j]] <- homerange_kern
names(homerange_kernels[[j]]) <- df_home[j, name]
}
return(homerange_kernels)
}
#' Create home range kernels based on Pareto and Gamma functions
#'
#' Creates RasterLayers of homerange kernels based on home centroids
#'
#' @param df_all dataframe of all homerange centroids
#' @param df_home dataframe of homerange centroids to calculate homerange
#' kernels (these must be a subset of the df_all dataframe), Default is to
#' use 'df_all' dataframe
#' @param base base Raster that sets the projection, extent, and dimensions of
#' the study area
#' @param max_r maximum radius to calculate the homerange raster from each
#' df_home centroid
#' @param pareto_shape shape parameter of the Logistic function that governs
#' the home kernel
#' @param pareto_scale scale parameter of the Logistic function that governs
#' the home kernel
#' @param gamma_shape shape parameter of the Gamma function that governs the
#' conspecific avoidance kernel
#' @param gamma_scale scale parameter of the Gamma function that governs the
#' conspecific avoidance kernel
#' @param id column name of df_home that identifies the homerange. Default is
#' NULL, which sets the names to df_home row number.
#' @param output_dir directory for output files (distance, homerange)
#' @param write_distance logical, write distance raster to file. Default is
#' FALSE.
#' @param write_homerange logical, write home range raster to file. Default is
#' FALSE
#'
#' @return A list containing homerange kernel Rasters for all the df_home
#' centroids
#' @export
#'
CreateHomeRangeKernelsParetoGamma <- function(df_all,
df_home = df_all,
base = base,
max_r,
pareto_shape,
pareto_scale,
gamma_shape,
gamma_scale,
id = "nest_id",
output_dir = getwd(),
write_distance = TRUE,
write_homerange = TRUE){
cellsize <- raster::res(base)[1]
max_r_cells <- ceiling(max_r/cellsize)
xmin <- xmin(base)
ymin <- ymin(base)
df_sp <- sp::SpatialPointsDataFrame(df_all[,c("x","y")], df_all,
proj4string=crs(base))
base <- raster::crop(base, df_sp, snap='out')
base <- raster::extend(base, c(max_r_cells/2, max_r_cells/2), value=11)
writeLines(noquote(paste("Calculating global distance")))
if (write_distance == TRUE) {
ifelse(exists("i"), i <- i , i <- 1)
filename <- paste0(output_dir,"/global_dist_", sprintf("%03d", i), ".tif")
global_dist <- raster::distanceFromPoints(base, df_sp, filename=filename,
overwrite=TRUE)
writeLines(noquote(paste("Writing:", filename)))
} else {
global_dist <- raster::distanceFromPoints(base, df_sp)
}
homerange_ids <- df_home$nest_id
total <- length(homerange_ids)
homerange_kernels <- as.list(setNames(rep(NA,length(homerange_ids)),
homerange_ids), homerange_ids)
for (j in 1:nrow(df_home)) {
writeLines(noquote(paste("Calculating homerange", j, "of", total)))
home <- df_home[j,]
home_sp <- SpatialPointsDataFrame(home[,c("x","y")], home,
proj4string=crs(base))
xy <- CenterXYInCell(home_sp@coords[,"x"], home_sp@coords[,"y"],
xmin, ymin, cellsize)
cell_extent <- extent(xy[1]-(cellsize/2), xy[1]+(cellsize/2), xy[2]-
(cellsize/2), xy[2]+(cellsize/2))
cell <- setValues(raster(cell_extent, crs=projection(base), res=cellsize),j)
home_ext <- extend(cell, c(max_r_cells, max_r_cells), value=NA)
home_dist <- distanceFromPoints(home_ext, home[,c("x","y")])
home_kern <- calc(home_dist, fun = function(x){VGAM::dgpd(x/1000, 0,
scale=pareto_scale, shape=pareto_shape)})
global_dist_crop <- crop(global_dist, home_dist)
cent_dist <- overlay(home_dist, global_dist_crop, fun=function (x,y)
{ifelse(x != y, NA, x)})
cent_bounds <- boundaries(cent_dist)
cent_bounds <- subs(cent_bounds, data.frame(from=c(0,1), to=c(NA,1)))
edge_dist_abs <- distance(cent_bounds)
edge_dist <- overlay(cent_dist, edge_dist_abs, fun=function(x,y)
{ifelse(!is.na(x), y*-1, y*1)})
edge_dist_shift <- calc(edge_dist, function(x) x - cellStats(edge_dist,
min))
avoid_kern <- calc(edge_dist_shift, fun = function(x){dgamma(x/1000, scale =
gamma_scale, shape = gamma_shape)})
homerange_kern <- overlay(avoid_kern, home_kern, fun=function(x,y){
p <- y*x})
if (write_homerange == TRUE) {
k <- home[,id]
filename <- paste0(output_dir,"/homerange_", k, "_",sprintf("%03d",
i), ".tif")
writeLines(noquote(paste0("Writing: ", filename)))
writeRaster(homerange_kern, filename=filename, overwrite=TRUE)
}
homerange_kernels[[j]] <- homerange_kern
names(homerange_kernels[[j]]) <- df_home[j,"nest_id"]
}
return(homerange_kernels)
}
#' Create a dataframe of flight path segments
#'
#' Adds flight path segments, which includes locations before and after "flight"
#' behavior. Segments are sequentially numbered for each individual. Used for
#' visualization and analysis of flight paths. Some locations may be represented
#' twice because they are both the start and end of a path.
#'
#' @param df dataframe
#'
#' @import dplyr
#' @importFrom magrittr "%>%"
#' @return dataframe with columns for 'id', 'behavior', and 'path_seg'.
#' @export
#'
#' @details adds 'path_seg' to dataframe
CreateFlightPathSegments <- function(df){
df_split <- df %>%
as.data.frame(.) %>%
group_by(id) %>%
mutate(datetime_lead = lead(datetime, 1)) %>%
mutate(step_time2 = as.integer(difftime(datetime_lead, datetime,
units = "mins"))) %>%
mutate(step_time_prev = lag(step_time2, 1, default = 0)) %>%
mutate(split_time = if_else(step_time_prev > 20, 1, 0)) %>%
mutate(split_time_grp = cumsum(split_time)) %>%
group_by(split_time_grp) %>%
mutate(behavior_lead = lead(behavior, 1)) %>%
mutate(start_flight = if_else(behavior_lead == "Flight" &
behavior != "Flight", 1, 0)) %>%
mutate(behavior_lag = lag(behavior, 1)) %>%
mutate(end_flight = if_else(behavior_lag == "Flight" &
behavior != "Flight", 1, 0)) %>%
mutate(bh_flight_tf = if_else(behavior == "Flight", TRUE, FALSE),
bh_flight_seq = (sequence(rle(bh_flight_tf)$lengths) * bh_flight_tf)) %>%
ungroup() %>%
dplyr::select(-c(datetime_lead, step_time2, split_time, split_time_grp,
step_time_prev, behavior_lead, behavior_lag, bh_flight_tf))
df_path <- df_split %>%
group_by(id) %>%
filter(start_flight != 0 | end_flight != 0 | bh_flight_seq != 0) %>%
mutate(datetime_lead = lead(datetime, 1)) %>%
mutate(step_time2 = as.integer(difftime(datetime_lead, datetime,
units = "mins"))) %>%
mutate(step_time_prev = lag(step_time2, 1, default = 0)) %>%
mutate(split_time = if_else(step_time_prev > 20, 1, 0)) %>%
mutate(split_time_grp = cumsum(split_time)) %>%
group_by(id, split_time_grp) %>%
mutate(first_loc = ifelse(row_number()==1, 1, 0)) %>%
ungroup(.) %>%
dplyr::select(-c(datetime_lead, step_time2, split_time, step_time_prev))
df_dup <- df_path %>%
filter(start_flight == 1 & end_flight == 1) %>%
mutate(first_loc = 1)
df_out <- rbind(df_path, df_dup) %>%
arrange(id, datetime, first) %>%
group_by(id) %>%
mutate(path_seg = cumsum(first_loc)) %>%
ungroup(.) %>%
dplyr::select(-c(start_flight, end_flight, first_loc))
return(df_out)
}
#' Extracts flight data
#'
#' Extracts the data associated with 'flight' for each bird, based on speed
#' data.
#'
#' @usage ExtractFlightData(df)
#'
#' @param df String, dataframe with locations.
#' @param min_speed Numeric, minimum speed to be classified as flight.
#'
#' @return A dataframe of "flight" data
#' @export
#'
#' @examples
#'
ExtractFlightSpeed <- function(df,
min_speed = 2) {
df <- df
# get data that only fits the "flight" criteria
flight <- df[which(df$speed>min_speed),]
return(flight)
}
#' Extract 'momentuHMM' transition matrix probabilities
#'
#' @usage ExtractTransitionProbabilities(model, alpha = 0.95)
#' @param model = object
#' @param alpha = p-value for CI
#'
#' @details This function is based on momentuHMM:::plotStationary function.
#' There may be some extraneous code because it was difficult to extract only
#' the necessary code for creating the transition matrix.
#' @return a tibble
#' @export
#'
ExtractTransitionProbabilities <- function(model,
alpha = 0.95){
model <- momentuHMM:::delta_bc(model)
data <- model$data
nbStates <- length(model$stateNames)
beta <- model$mle$beta
plotCI <- TRUE
if(nrow(beta)/model$conditions$mixtures==1){
stop("No covariate effect to plot")
}
if(!is.null(model$mod$hessian) & plotCI){
Sigma <- model$mod$Sigma
} else {
Sigma <- NULL
plotCI <- FALSE
}
formula <- model$conditions$formula
newForm <- momentuHMM:::newFormulas(formula, nbStates,
model$conditions$betaRef, hierarchical = TRUE)
newformula <- newForm$newformula
recharge <- hierRecharge <- newForm$recharge
covs <- momentuHMM:::getCovs(model, covs = NULL, unique(model$data$ID))
nbG0covs <- 0
nbRecovs <- 0
g0covs <- NULL
recovs <- NULL
rawCovs <- model$rawCovs
covIndex <- 1:ncol(rawCovs)
nbCovs <- ncol(stats::model.matrix(newformula,data))-1 # drop intercept col
mixtures <- model$conditions$mixtures
gamInd <- (length(model$mod$estimate)-(nbCovs+1)*nbStates*(nbStates-1)*
mixtures+1):(length(model$mod$estimate))-(ncol(model$covsPi)*
(mixtures-1))-ifelse(nbRecovs,(nbRecovs+1)+
(nbG0covs+1),0)-ncol(model$covsDelta)*(nbStates-1)*
(!model$conditions$stationary)*mixtures
# loop over covariates
for(cov in covIndex) {
gridLength <- 101
hGridLength <- gridLength
inf <- min(rawCovs[,cov],na.rm=TRUE)
sup <- max(rawCovs[,cov],na.rm=TRUE)
# set all covariates to their mean, except for "cov"
# (which takes a grid of values from inf to sup)
tempCovs <- data.frame(matrix(covs[names(rawCovs)][[1]],
nrow = hGridLength, ncol = 1))
if(ncol(rawCovs)>1){
for(i in 2:ncol(rawCovs)){
tempCovs <- cbind(tempCovs,rep(covs[names(rawCovs)][[i]],gridLength))
}
tempCovs[,cov] <- rep(seq(inf,sup,length=gridLength),
each=hGridLength/gridLength)
}
names(tempCovs) <- names(rawCovs)
tmpcovs <- covs[names(rawCovs)]
for(i in which(!unlist(lapply(rawCovs, is.factor)))){
tmpcovs[i] <- round(covs[names(rawCovs)][i],2)
}
quantSup <- qnorm(1 - (1 - alpha)/2)
tmpSplineInputs <- momentuHMM:::getSplineFormula(newformula, m$data,
tempCovs)
desMat <- model.matrix(tmpSplineInputs$formula,
data = tmpSplineInputs$covs)
trMat <- momentuHMM:::trMatrix_rcpp(nbStates, beta, desMat,
model$conditions$betaRef)
for (i in 1:nbStates) {
for (j in 1:nbStates) {
if (cov == 1 && i == 1 && j == 1){
covars <- tempCovs %>% slice(0)
df_trans <- bind_cols(covars, tibble(start_st = integer(),
end_st = integer(), prob = numeric(), lci = numeric(),
uci = numeric()))
}
covars <- tempCovs
prob <- trMat[i, j, ]
start_st <- rep(i, nrow(covars))
end_st <- rep(j, nrow(covars))
print(paste0("Start ", "cov: ", cov, " i: ", i, " j: ", j))
dN <- t(apply(desMat, 1, function(x)
tryCatch(numDeriv::grad(momentuHMM:::get_gamma,
model$mod$estimate[gamInd][unique(c(model$conditions$betaCons))],
covs = matrix(x, nrow = 1), nbStates = nbStates,
i = i, j = j, betaRef = model$conditions$betaRef,
betaCons = model$conditions$betaCons,
workBounds = model$conditions$workBounds$beta),
error = function(e) NA)))
se <- t(apply(dN, 1, function(x)
tryCatch(suppressWarnings(sqrt(x %*%
Sigma[gamInd[unique(c(model$conditions$betaCons))],
gamInd[unique(c(model$conditions$betaCons))]] %*% x)),
error = function(e) NA)))
if (!all(is.na(se))) {
lci <- 1/(1 + exp(-(log(trMat[i, j, ]/(1 -
trMat[i, j, ])) - quantSup * (1/(trMat[i,
j, ] - trMat[i, j, ]^2)) * se)))
uci <- 1/(1 + exp(-(log(trMat[i, j, ]/(1 -
trMat[i, j, ])) + quantSup * (1/(trMat[i,
j, ] - trMat[i, j, ]^2)) * se)))
lci <- as.vector(lci)
uci <- as.vector(uci)
} else {
lci <- rep(NA, nrow(covars))
uci <- rep(NA, nrow(covars))
}
trans_probs <- tibble(start_st, end_st, prob, lci, uci)
df_trans_ij <- bind_cols(covars, trans_probs) %>%
as_tibble(.)
df_trans <- bind_rows(df_trans, df_trans_ij)
print(paste0("End cov: ", cov, "i: ", i, " j: ", j))
}
}
}
df_trans_final <- dplyr::as_tibble(df_trans)
return(df_trans_final)
}
#' Extract movement data
#'
#' Extracts detected movements (non-stationary between locations) data for each
#' bird.
#'
#' @usage ExtractMovements(df, by, min_step_length, max_step_length)
#'
#' @param df Dataframe with location data which includes "step_length" and
#' "step_time" columns.
#' @param by String, column name of unique identifier to split data, default is
#' "id".
#' @param min_step_length Numeric, threshold distance for movement
#' classification. Default is 50.
#' @param max_step_time Numeric, threshold difference in time for movement
#' classification. Default is 20.
#'
#' @return A dataframe of selected movements
#' @export
#'
ExtractMovements <- function(df,
by = "id",
min_step_length = 50,
max_step_time = 20){
df <- df
movements <- plyr::ddply(df, by, function(df){
movements <- df[which(df$step_length >= min_step_length &
df$step_time <= max_step_time), ]})
return(movements)
}
#' Extracts roost data
#'
#' Extracts dataframe of sex, arr_diff_min, and dep_diff_min
#'
#' @usage ExtractRoostData(df)
#'
#' @param df Dataframe of location data with "sex", "datetime", "behavior",
#' "hr_after_sunset", and "hr_before_sunrise" columns.
#'
#' @return a dataframe
#' @details Used in other functions.
#'
ExtractRoostData <- function(df = df){
arrive <- subset(df, behavior=="arrive")
arrive$arr_diff_min <- as.integer(difftime(arrive$hr_after_sunset,
arrive$datetime))
arrive <- subset(arrive, select=c("sex", "arr_diff_min"))
arrive$dep_diff_min <- NA
arrive$roost <- "arrive"
depart <- subset(df, behavior=="depart")
depart$dep_diff_min <- as.integer(difftime(depart$datetime,
depart$hr_before_sunrise))
depart <- subset(depart, select=c("sex", "dep_diff_min"))
depart$arr_diff_min <- NA
depart$roost <- "depart"
output <- rbind(arrive, depart)
output$diff_min <- NA
output$diff_min <- ifelse(!is.na(output$arr_diff_min), output$arr_diff_min,
output$dep_diff_min)
return(output)
}
#' Filter Locations by Nest Behavior Criteria
#'
#' @usage FilterByNestCriteria(df, min_daily_nest_dist, roll_days,
#' min_roll_days_nest_dist, seasons)
#'
#' @param df dataframe of locations
#' @param min_daily_nest_dist numeric, bird's daily minimum distance from nest
#' to meet the criteria
#' @param roll_days numberic, number of days for rolling mean calculation of
#' nest distance
#' @param min_roll_days_nest_dist numeric, bird's daily minimum distance from
#' nest to meet the criteria
#' @param seasons seasons to keep (e.g., c("spring","summer")).
#'
#' @return dataframe
#' @export
#'
#' @import dplyr
#'
FilterByNestCriteria <- function(df,
min_daily_nest_dist = 100,
roll_days = NA,
min_roll_days_nest_dist = NA,
seasons = c("spring", "summer")){
df <- df
df <- df %>% filter(season %in% seasons)
df_sum <- df %>%
group_by(id, date) %>%
summarize(nest_dist_dy_mean = mean(nest_dist),
nest_dist_min = min(nest_dist)) %>%
mutate(nest_dist_met = if_else(nest_dist_min < min_daily_nest_dist, TRUE,
FALSE)) %>%
ungroup()
if(!is.na(roll_days) && !is.na(min_roll_days_nest_dist)) {
df_sum <- df %>%
group_by(id, date) %>%
mutate(
nest_dist_run = zoo::rollmean(nest_dist_dy_mean, roll_days, fill=NA,
na.pad=TRUE, align="left"),
roll_dist_met = if_else(nest_dist_run < min_roll_days_nest_dist,
TRUE, FALSE)) %>%
ungroup()
} else {
df_sum <- df_sum %>% mutate(roll_dist_met = TRUE)
}
df_final <- left_join(df, df_sum, by = c("id", "date")) %>%
filter(!is.na(nest_dist_met) && !is.na(roll_dist_met)) %>%
filter(nest_dist_met == TRUE, roll_dist_met == TRUE) #%>%
# dplyr::select(-c(nest_dist_dy_mean, nest_dist_min, nest_dist_met,
# roll_dist_met))
return(df_final)
}
#' Filter Locations by Roost Criteria
#'
#' @usage FilterByRoostBehavior(df, min_daily_nest_dist, roll_days,
#' min_roll_days_nest_dist, seasons)
#'
#' @param df dataframe of locations
#' @param overnight_distance_threshold numeric, distance that last PM location
#' and first AM location must be less than for it to be considered a
#' confirmed roost location
#' @param number_am_loc numeric, number of GPS locations needed for AM window,
#' default is 7.
#' @param number_pm_loc numeric, number of GPS locations needed for PM window,
#' default is 7.
#' @param tz timezone, default is "Etc/GMT+5"
#'
#' @return dataframe
#' @export
#'
#' @import dplyr
#'
FilterByRoostCriteria <- function(df = df,
overnight_distance_threshold = 100,
number_pm_loc = 7,
number_am_loc = 7,
tz = "Etc/GMT+5"){
df <- df
df$time_after_start <- as.integer(difftime(df$datetime,
df$hr_before_sunrise, tz=tz, units = ("mins")))
df$time_before_end <- as.integer(difftime(df$hr_after_sunset, df$datetime,
tz=tz, units = ("mins")))
df$two_hr_after_sunrise <- df$hr_before_sunrise + hours(2)
df$two_hr_before_sunset <- df$hr_after_sunset - hours(2)
df$sunrise_window_loc <- df$datetime <= df$two_hr_after_sunrise
df$sunset_window_loc <- df$datetime >= df$two_hr_before_sunset
sumstats <- df %>%
group_by(id, date) %>%
summarize(
total_loc = n(),
am_loc = sum(sunrise_window_loc, na.rm=TRUE),
pm_loc = sum(sunset_window_loc, na.rm=TRUE)) %>%
mutate(next_date = lead(date, 1),
next_day_GPS = (next_date - date),
next_am_loc = lead(am_loc, 1)) %>%
ungroup()
df_sum <- left_join(df, sumstats, by = c("id","date"))
roost_arrival_confirmed <- df_sum %>%
filter(last == "Last" &
step_length <= overnight_distance_threshold &
next_day_GPS == 1 &
pm_loc >= 7 &
next_am_loc >= 7) %>%
dplyr::select(id, date)
roost_departure_confirmed <- roost_arrival_confirmed %>%
mutate(date = date + 1) # the mornings after "last_roost_confirmed" dates
roost_arrival_intervals <- inner_join(df, roost_arrival_confirmed,
by = c("date", "id")) %>% filter(datetime > solarnoon)
# to "confirm" arrival based on overnight distance
roost_departure_intervals <- inner_join(df, roost_departure_confirmed,
by = c("date", "id")) %>% filter(datetime < solarnoon)
roost_final <- rbind(roost_arrival_intervals, roost_departure_intervals) %>%
arrange(id, datetime) %>%
dplyr::select(-c(time_before_end, two_hr_after_sunrise,
two_hr_before_sunset, sunrise_window_loc, sunset_window_loc))
}
#' Filter locations by individual and dates
#'
#' Used to filter full dataset to individual(s) within a specified date range.
#'
#' @param df Dataframe with locations.
#' @param id Column name of unique identifier. Default is "id".
#' @param individual String, individual/s (from id column) to keep, format
#' should be c(id, id), default is to keep all.
#' @param start Start date filter, default is 1970-01-01.
#' @param end End date filter, default is current date.
#' @param behavior String of specific behaviors to maintain. Default is all.
#'
#' @return A dataframe with subsetted rows
#' @export
#'
#' @details Defaults are specific to my file directories and locations
FilterLocations <- function(df = df,
id = "id",
individual = NULL,
start = NULL,
end = NULL,
behavior = NULL){
if (is.null(start) || start == ""){
start <- "2013-01-01"
}
if (is.null(end) || end == ""){
today <- Sys.Date()
end <- format(today, format="%Y-%m-%d")
}
starts <- paste("Start date: ", start, sep="")
ends <- paste("End date: ", end, sep="")
writeLines(noquote(starts))
writeLines(noquote(ends))
end <- as.POSIXct(end)
end <- trunc(end, "days") + 60*60*24
df <- df[df$datetime >= as.POSIXct(start) & df$datetime <= end,]
row.names(df) <- NULL
if(all(is.null(individual)) || individual == ""){
writeLines(noquote ("All individuals included"))
} else {
writeLines(noquote(paste("Filtered to individual(s):", individual, sep="")))
df <- df[df[,id] %in% individual,]
row.names(df) <- NULL
}
if(is.null(behavior)){
writeLines(noquote ("All behaviors included"))
} else {
writeLines(noquote(paste("Filtered to behavior(s):", behavior, sep="")))
df <- df[df[,"behavior"] %in% behavior,]
row.names(df) <- NULL
}
return(df)
}
#' Compares two times and returns greater or lesser value
#'
#' Examines two time columns, returns the greater or lesser value and inserts
#' that value in a result column
#'
#' @usage IfElseTimedateCompare(df, col1, col2, result, default_tz, tz)
#'
#' @param df Dataframe of location data.
#' @param col1 Column name, col1 is compared to col2
#' @param sign String, either ">" or "<" for returning greater than or less than
#' values, respectively. Default is ">".
#' @param col2 Column name, col2 is compared to col1.
#' @param result String, name of column to insert results. Default is "result".
#' @param default_tz String, timezone that timedate reverts to, based on OS
#' time.
#' @param tz String, timezone of original data (may be different from
#' default_tz).
#'
#' @return Original dataframe with a new "result" column
#'
#' @details Used in RoostArrivalDeparture(). Ensures that result is in the
#' correct timezone.
#'
IfElseTimedateCompare <- function(df = df,
col1 = "col1",
sign = ">",
col2 = "col2",
result = "result",
default_tz = default_tz,
tz = tz) {
safe.ifelse <- function(cond, yes, no) {
structure(ifelse(cond, yes, no), class = class(yes))
}
df$col1<-df[,col1]
df$col2<-df[,col2]
df$result <- NA
if (sign == ">"){
df$result <- safe.ifelse(df$col1 >= df$col2, df$col1, df$col2)
}
if (sign == "<"){
df$result <- safe.ifelse(df$col1 <= df$col2, df$col1, df$col2)
}
df$result <- force_tz(df$result, tzone = default_tz)
df$result <- with_tz(df$result, tzone=tz)
df$col1 <- NULL
df$col2 <- NULL
df_length <- length(df)
colnames(df)[df_length] <- result
return(df)
}
#' Finds time value that is not NA
#'
#' Examines two time columns, if one is NA, the other time is returned.
#'
#' @usage IfElseTimedateNA(df, col1, col2, result, default_tz, tz)
#'
#' @param df Dataframe of location data.
#' @param col1 Column name, column checked to if is NA. If not NA, then col1 is
#' returned.
#' @param col2 Column name, if col1 is NA, then col2 is returned.
#' @param result String, name of column to insert results. Default is "result".
#' @param default_tz String, timezone that timedate reverts to, based on OS
#' time.
#' @param tz string, timezone of original data (may be different from
#' default_tz).
#'
#' @return A dataframe with a new 'result' column.
#' @export
#'
#' @details Ensure that result is in the correct timezone. Used in
#' RoostArrivalDeparture().
#'
IfElseTimedateNA <- function(df = df,
col1 = "col1",
col2 = "col2",
result = "result",
default_tz = default_tz,
tz = tz) {
safe.ifelse <- function(cond, yes, no) {
structure(ifelse(cond, yes, no), class = class(yes))
}
df$col1<-df[,col1]
df$col2<-df[,col2]
df$result <- NA
df$result <- safe.ifelse(is.na(df$col1), df$col2, df$col1)
df$result <- force_tz(df$result, tzone = default_tz)
df$result <- with_tz(df$result, tzone=tz)
df$col1 <- NULL
df$col2 <- NULL
df_length <- length(df)
colnames(df)[df_length] <- result
return(df)
}
#' Plots daily behavior proportions as bars
#'
#' Plots proportion of behavioral states during a day as a bar graph, with
#' adjustable number of breaks.
#'
#' @usage PlotBehaviorProportionBar(df, breaks, title)
#'
#' @param df Dataframe with "sex", "behavior", and "time_proportion" columns.
#' @param breaks Numeric, number of breaks in daily period.
#' @param title Character, main title of plot. Default is "Daily Behavior
#' Distributions".
#'
#' @return Facetted plot of behavior proportion over daily period.
#' @export
#'
#' @details Behavioral colors come from:
#' "Data/Assets/behavior_colors.csv".
#'
PlotBehaviorProportionBar <- function(df = df,
breaks = 20,
title = NA){
if(is.na(title)) title <- "Daily Behavior Distributions"
behavior_colors <- CreateColorsByMetadata(file=
"Data/Assets/behavior_colors.csv", metadata_id="behavior")
df$behavior <- factor(df$behavior)
CutProportion <- function(data, breaks = breaks) {
b <- seq(0, 1, length=2*breaks+1)
brk <- b[0:breaks*2+1]
k <- cut(data, breaks=brk)
}
CutProportionMid <- function(data,breaks=breaks) {
b <- seq(0, 1, length=2*breaks+1)
brk <- b[0:breaks*2+1]
mid <- b[1:breaks*2]
k <- cut(data, breaks=brk)
mid[k]
}
Capitalize <- function(string) {
substr(string, 1, 1) <- toupper(substr(string, 1, 1))
string
}
sex_names <- list('female'="Female", 'male'="Male")
sex_labeller <- function(variable, value){
return(sex_names[value])
}
df$bins <- CutProportion(df$time_proportion, breaks)
df$bins_mid <- factor(CutProportionMid(df$time_proportion, breaks))
melted <- reshape::melt(plyr::ddply(df, plyr::.(sex, bins_mid),
function(x){prop.table(table(x$behavior))}))
names(melted)[names(melted) == 'variable'] <- 'behavior'
melted$bins_mid <- as.numeric(as.character(melted$bins_mid))
ggplot(melted, aes(x = bins_mid, y=value, ymax=1, fill= behavior)) +
facet_grid(~ sex, labeller = labeller(sex = Capitalize)) +
geom_bar(stat="identity") +
scale_fill_manual(values = behavior_colors, name = "Behavior") +
scale_x_continuous(breaks=seq(0, 1, .1)) +
theme(panel.spacing = unit(1, "lines")) +
theme(plot.title=element_text(size=20)) +
theme(text=element_text(size=18, colour="black")) +
theme(axis.text=element_text(colour="black")) +
labs(x="Daily Period",
y="Behavior Proportion",
title=title) +
theme(plot.title = element_text(hjust = 0.5)) +
theme(panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank()) +
theme(panel.background = element_rect(fill = "white", color = "black")) +
theme(strip.background = element_rect(colour = "black", fill = "white"))
}
#' Plots daily behavior proportions as lines
#'
#' Plots proportion of behavioral states during a day as a line, with
#' adjustable number of breaks.
#'
#' @usage PlotBehaviorProportionLine(df, breaks, title)
#'
#' @param df Dataframe with "sex", "behavior", and "time_proportion" columns.
#' @param breaks Numeric, number of breaks in daily period.
#' @param title Character, main title of plot. Default is "Daily Behavior
#' Distributions".
#'
#' @return Facetted plot of behavior proportion over daily period.
#' @export
#'
PlotBehaviorProportionLine <- function(df = df,
breaks = 20,
title = NA){
if(is.na(title)) title <- "Daily Behavior Distributions"
df$behavior <- factor(df$behavior)
behavior_colors <- CreateColorsByMetadata(file=
"Data/Assets/behavior_colors.csv", metadata_id="behavior")
CutProportion <- function(data,breaks=breaks) {
b <- seq(0, 1, length=2*breaks+1)
brk <- b[0:breaks*2+1]
k <- cut(data, breaks=brk)
}
CutProportionMid <- function(data,breaks=breaks) {
b <- seq(0, 1, length=2*breaks+1)
brk <- b[0:breaks*2+1]
mid <- b[1:breaks*2]
k <- cut(data, breaks=brk)
mid[k]
}
Capitalize <- function(string) {
substr(string, 1, 1) <- toupper(substr(string, 1, 1))
string
}
df$bins <- CutProportion(df$time_proportion, breaks)
df$bins_mid <- factor(CutProportionMid(df$time_proportion, breaks))
melted <- reshape::melt(plyr::ddply(df, plyr::.(sex, bins_mid),
function(x){prop.table(table(x$behavior))}))
names(melted)[names(melted) == 'variable'] <- 'behavior'
melted$bins_mid <- as.numeric(as.character(melted$bins_mid))
ggplot(melted, aes(x = bins_mid, y=value, ymax=1, group= behavior, color=
behavior)) + geom_line(stat="identity", size=1.5) +
facet_grid(~ sex, labeller = labeller(sex = Capitalize)) +
theme(panel.spacing=unit(1, "lines")) +
scale_color_manual(values=behavior_colors) +
scale_x_continuous(breaks=seq(0,1, .1)) +
theme(plot.title=element_text(size=20)) +
theme(text=element_text(size=18, colour="black")) +
theme(axis.text=element_text(colour="black")) + labs(x="Daily Period",
y="Behavior Proportion", title=title) +
theme(plot.title = element_text(hjust = 0.5)) +
theme(panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank()) +
theme(panel.background = element_rect(fill = "white", color = "black")) +
theme(strip.background = element_rect(colour = "black", fill = "white"))
}
#' Plot 3D raster of selected cells given a probability raster and sample size
#'
#' @param prob_raster Raster
#' @param sample_n integer sample size of selected cells from probability raster
#'
#' @return Raster
#' @export
#'
PlotProbabilityRaster <- function(prob_raster,
sample_n = 5000){
#IMPORTANT - Process to plot probability plot
destination_xy <- tibble(x = vector(mode = "numeric", sample_n),
y = vector(mode = "numeric", sample_n))
for (i in seq_len(sample_n)){
destination_cell <- suppressWarnings(sampling::strata(data = data.frame(
cell = 1:raster::ncell(prob_raster)), stratanames = NULL, size = 1,
method = "systematic", pik = prob_raster@data@values))
while(is.na(destination_cell[1,1])) {
destination_cell <- suppressWarnings(sampling::strata(data=data.frame(
cell = 1:raster::ncell(prob_raster)), stratanames = NULL, size = 1,
method="systematic", pik = prob_raster@data@values))
}
destination_xy[i, ] <- raster::xyFromCell(prob_raster, destination_cell[,1])
}
destination_raster <- rasterize(destination_xy, prob_raster, field = 1,
fun = 'sum', background = NA, mask = FALSE, update = FALSE,
updateValue = 'all', filename = "", na.rm = TRUE)
if(FALSE) plot(prob_raster)
if(FALSE) plot(destination_raster)
Plot3DRaster(destination_raster, col = viridis::viridis(20),
main = "Probability Plot")
}
#' Plot step lengths histogram
#'
#' Plots a histogram of the step-lengths for each bird
#'
#' @param df Dataframe with flights.
#' @param id String, column name of unique identifier. Default = "id".
#' @param xlim Numeric, x-value limit. Default is NULL.
#' @param bin_width Numeric, bin size. Default is: x-value range/30
#'
#' @return A plot of step-length distances
#' @export
#'
PlotStepLengths <- function(df,
id = "id",
xlim = NULL,
bin_width = NULL){
df <- df
sum_move <- SummarizeSE(df, "step_length", "id", na_rm=TRUE)
id_colors <- CreateColorsByID(output=TRUE)
grid <- seq(min(df$step_length, na.rm=TRUE), max(df$step_length, na.rm=TRUE),
length = 100)
probs = c(0.5, 0.75, 0.95)
sumstats <- ddply(df, id, function(df){
quantile(df$step_length, probs = probs, na.rm=TRUE)
})
q_probs<-paste("q",probs, sep="")
colnames(sumstats)[2:(length(probs)+1)] <- q_probs
if (is.null(xlim)) xlim <- max(df$step_length, na.rm=TRUE)
g <- ggplot(df, aes(x=step_length, fill=id)) + facet_wrap( ~ id) +
scale_fill_manual(values=id_colors) +
theme(legend.position="none") +
theme(plot.title=element_text(size=22)) +
theme(text=element_text(size=20, colour="black")) +
theme(axis.text=element_text(colour="black")) +
xlab("Step length") + ylab("Density") + scale_x_continuous(limits=c(0,xlim))
if (is.null(bin_width)) bin_width = xlim/30
g <- g + geom_bar(aes(y = ..density.., fill=id), colour="black",
binwidth=bin_width)
build <- ggplot_build(g)
sumstats$xmax <- max(build$panel$ranges[[1]]$x.range)
sumstats$ymax <- max(build$panel$ranges[[1]]$y.range)
g + geom_vline(data=sumstats, aes(xintercept=q0.5), linetype="longdash",
size=1, colour="black") +
geom_vline(data=sumstats, aes(xintercept=q0.75), linetype="dashed",
size=1, colour="grey20") +
geom_vline(data=sumstats, aes(xintercept=q0.95), linetype="dashed",
size=1, colour="grey30") +
geom_text(data=sumstats, aes(x=q0.5 + (xmax*0.02), y=ymax*.75,
label=paste("Median:", "\n", signif(q0.5,3), sep="")),
color="black", hjust=0) +
geom_text(data=sumstats, aes(x=q0.75+(xmax*0.02), y=ymax*.5,
label=paste("75%:", "\n", signif(q0.75,3), sep="")),
color = "grey20", hjust=0) +
geom_text(data=sumstats, aes(x=q0.95+(xmax*0.02), y=ymax*.25,
label=paste("95%:", "\n", signif(q0.95,3), sep="")),
color = "grey30", hjust=0)
}
#' Plot roost behavior ECDF
#'
#' Plots roost empirical distribution funtion and fitted Weibull cumulative
#' distribution function
#'
#' @usage PlotRoostECDF(df, pars)
#'
#' @param df Dataframe of location data.
#' @param pars List of simulation parameters with male/female, arrive/depart,
#' shape/scale.
#'
#' @return Facetted plot with roost data and fitted Weibull distributions
#'
#' @import ggplot2
#' @export
#'
#' @details Empirical distribution function extends to 15 min past the end of
#' last time.
PlotRoostECDF <- function(df = baea,
pars = baea_pars) {
df <- ExtractRoostData(df)
df2 <- ExtractRoostPars(pars)
df[df=="m"]<-"male"
df2[df2=="m"]<-"male"
df[df=="f"]<-"female"
df2[df2=="f"]<-"female"
df2$diff_min<-.85*(max(df$diff_min)+15)
df2$lab<-paste("shape: ",round(df2$shape,2))
df2$lab2<-paste("scale: ", round(df2$scale,2))
vec <- with(df, seq(0, max(diff_min)+15, length=max(diff_min)+16))
weibull <- ddply(df2, .(sex,roost), function(df) {
data.frame(diff_min=vec,
density = pweibull(vec, shape=df$shape, scale=df$scale))
})
df2$density<-.25*(max(weibull$density))
df2$density2<-.15*(max(weibull$density))
ggplot(df,aes(x=diff_min)) +
stat_ecdf(aes(colour=sex), size=1) +
geom_line(aes(x=diff_min, y=density), data=weibull,
colour="orange", size=1) +
geom_text(aes(x=diff_min, y=density, label=lab),
data=df2) +
geom_text(aes(x=diff_min, y=density2, label=lab2),
data=df2) +
facet_grid(roost ~ sex) +
theme(plot.title=element_text(size=22)) +
theme(text=element_text(size=20, colour="black")) +
theme(axis.text=element_text(colour="black")) +
labs(x='Time Difference from Start/End of Sim Day',
y='Cumulative Probability Density',
title="Roost Data with Fitted Weibull Distributions",
colour= "Sex")
}
#' Plots roost behavior probability distribution
#'
#' Plots roost times and fitted Weibull probability distributions
#'
#' @usage PlotRoostHistogram(df, pars)
#'
#' @param df Dataframe of location data
#' @param pars List of simulation parameters with male/female, arrive/depart,
#' shape/scale
#' @param binwidth Numeric, bin size. Default is 15.
#'
#' @return Facetted plot with roost data and fitted weibull distributions
#' @export
#'
#' @details Weibull probability function extends 15 min past last time.
#'
PlotRoostHistogram <- function(df,
pars,
binwidth = 15) {
df <- ExtractRoostData(df)
df2 <- ExtractRoostPars(pars)
df[df=="m"] <- "male"
df2[df2=="m"] <- "male"
df[df=="f"] <- "female"
df2[df2=="f"] <- "female"
df2$diff_min <- .85*max(df$diff_min)+15
df2$lab <- paste("shape: ", round(df2$shape,2))
df2$lab2 <- paste("scale: ", round(df2$scale,2))
grid <- with(df, seq(0, max(diff_min)+15, length=max(diff_min)+16))
weibull <- ddply(df2, .(sex,roost), function(df) {
data.frame(diff_min=grid,
density = dweibull(grid, shape=df$shape, scale=df$scale))
})
df2$density <- max(weibull$density)
df2$density2 <- .85*df2$density
ggplot(df) +
geom_histogram(aes(x=diff_min, y=..density..), binwidth=binwidth) +
geom_line(aes(x=diff_min, y=density), data=weibull,
colour = "orange", size=1) +
geom_text(aes(x=diff_min, y=density, label=lab),
data=df2) +
geom_text(aes(x=diff_min, y=density2, label=lab2),
data=df2) +
facet_grid(roost ~ sex) +
theme(plot.title=element_text(size=22)) +
theme(text=element_text(size=20, colour="black")) +
theme(axis.text=element_text(colour="black")) +
labs(x='Time Difference from Start/End of Sim Day',
y='Probability Density',
title="Histogram of Roost Data with Fitted Weibull Distributions")
}
#------------------------------------------------------------------------------#
################################ OLD CODE ######################################
#------------------------------------------------------------------------------#
#' ExtractTransitionProbabilitiesOLD <- function(x,
#' alpha = 0.95){
#' animals = NULL
#' covs = NULL
#' breaks = "Sturges"
#' hist.ylim = NULL
#' sepAnimals = FALSE
#' sepStates = FALSE
#' col = NULL
#' cumul = TRUE
#' plotTracks = TRUE
#' plotCI = FALSE
#' plotStationary = FALSE
#' m <- x
#' m <- momentuHMM:::delta_bc(m)
#' nbAnimals <- length(unique(m$data$ID))
#' nbStates <- length(m$stateNames)
#' distnames <- names(m$conditions$dist)
#' if (is.null(hist.ylim)) {
#' hist.ylim <- vector("list", length(distnames))
#' names(hist.ylim) <- distnames
#' }
#' for (i in distnames) {
#' if (!is.null(hist.ylim[[i]]) & length(hist.ylim[[i]]) != 2){
#' stop("hist.ylim$", i,
#' " needs to be a vector of two values (ymin,ymax)")
#' }
#' }
#' if (!is.null(col) & length(col) >= nbStates) {
#' col <- col[1:nbStates]
#' }
#' if (!is.null(col) & length(col) < nbStates) {
#' warning(paste0("Length of 'col' should be at least number of states - ",
#' "argument ignored"))
#' if (nbStates < 8) {
#' pal <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2",
#' "#D55E00", "#CC79A7")
#' col <- pal[1:nbStates]
#' } else {
#' hues <- seq(15, 375, length = nbStates + 1)
#' col <- hcl(h = hues, l = 65, c = 100)[1:nbStates]
#' }
#' }
#' if (is.null(col) & nbStates < 8) {
#' pal <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2",
#' "#D55E00", "#CC79A7")
#' col <- pal[1:nbStates]
#' }
#' if (is.null(col) & nbStates >= 8) {
#' hues <- seq(15, 375, length = nbStates + 1)
#' col <- hcl(h = hues, l = 65, c = 100)[1:nbStates]
#' }
#' if (sepStates | nbStates < 2) {
#' cumul <- FALSE
#' }
#' if (inherits(x, "miSum")) {
#' plotEllipse <- m$plotEllipse
#' } else {
#' plotEllipse <- FALSE
#' }
#' muffWarn <- function(w) {
#' if (any(grepl(
#' "zero-length arrow is of indeterminate angle and so skipped", w)))
#' invokeRestart("muffleWarning")
#' }
#' if (is.null(animals)) {
#' animalsInd <- 1:nbAnimals
#' } else {
#' if (is.character(animals)) {
#' animalsInd <- NULL
#' for (zoo in 1:length(animals)) {
#' if (length(which(unique(m$data$ID) == animals[zoo])) ==
#' 0)
#' stop("Check 'animals' argument, ID not found")
#' animalsInd <- c(animalsInd, which(unique(m$data$ID) ==
#' animals[zoo]))
#' }
#' }
#' if (is.numeric(animals)) {
#' if (length(which(animals < 1)) > 0 | length(which(animals >
#' nbAnimals)) > 0)
#' stop("Check 'animals' argument, index out of bounds")
#' animalsInd <- animals
#' }
#' }
#' nbAnimals <- length(animalsInd)
#' ID <- unique(m$data$ID)[animalsInd]
#' if (nbStates > 1) {
#' if (inherits(x, "miSum")){
#' states <- m$Par$states
#' } else {
#' cat("Decoding state sequence... ")
#' states <- momentuHMM:::viterbi(m)
#' cat("DONE\n")
#' }
#' } else {
#' states <- rep(1, nrow(m$data))
#' }
#' if (sepStates | nbStates == 1) {
#' w <- rep(1, nbStates)
#' } else {
#' w <- rep(NA, nbStates)
#' for (state in 1:nbStates) w[state] <- length(which(states ==
#' state))/length(states)
#' }
#' if (all(c("x", "y") %in% names(m$data))) {
#' x <- list()
#' y <- list()
#' if (plotEllipse)
#' errorEllipse <- list()
#' for (zoo in 1:nbAnimals) {
#' ind <- which(m$data$ID == ID[zoo])
#' x[[zoo]] <- m$data$x[ind]
#' y[[zoo]] <- m$data$y[ind]
#' if (plotEllipse)
#' errorEllipse[[zoo]] <- m$errorEllipse[ind]
#' }
#' }
#' if (is.null(covs)) {
#' covs <- m$data[which(m$data$ID %in% ID), ][1, ]
#' for (j in names(m$data)[which(unlist(lapply(m$data, function(x)
#' any(class(x) %in% momentuHMM:::meansList))))]) {
#' if (inherits(m$data[[j]], "angle")){
#' covs[[j]] <-
#' CircStats::circ.mean(m$data[[j]][which(m$data$ID %in%
#' ID)][!is.na(m$data[[j]][which(m$data$ID %in% ID)])])
#' } else {
#' covs[[j]] <- mean(m$data[[j]][which(m$data$ID %in% ID)],
#' na.rm = TRUE)
#' }
#' }
#' } else {
#' if (!is.data.frame(covs)) {
#' stop("covs must be a data frame")
#' }
#' if (nrow(covs) > 1){
#' stop("covs must consist of a single row")
#' }
#' if (!all(names(covs) %in% names(m$data))){
#' stop("invalid covs specified")
#' }
#' if (any(names(covs) %in% "ID")) {
#' covs$ID <- factor(covs$ID, levels = unique(m$data$ID))
#' }
#' for (j in names(m$data)[which(names(m$data) %in% names(covs))]) {
#' if (inherits(m$data[[j]], "factor")) {
#' covs[[j]] <- factor(covs[[j]], levels = levels(m$data[[j]]))
#' }
#' if (is.na(covs[[j]])){
#' stop("check value for ", j)
#' }
#' }
#' for (j in names(m$data)[which(!(names(m$data) %in% names(covs)))]) {
#' if (inherits(m$data[[j]], "factor")) {
#' covs[[j]] <- m$data[[j]][which(m$data$ID %in% ID)][1]
#' } else if (inherits(m$data[[j]], "angle")) {
#' covs[[j]] <-
#' CircStats::circ.mean(m$data[[j]][which(m$data$ID %in%
#' ID)][!is.na(m$data[[j]][which(m$data$ID %in%
#' ID)])])
#' } else if (any(class(m$data[[j]]) %in% meansList)) {
#' covs[[j]] <- mean(m$data[[j]][which(m$data$ID %in%
#' ID)], na.rm = TRUE)
#' }
#' }
#' }
#' formula <- m$conditions$formula
#' newForm <- momentuHMM:::newFormulas(formula, nbStates)
#' formulaStates <- newForm$formulaStates
#' formterms <- newForm$formterms
#' newformula <- newForm$newformula
#' nbCovs <- ncol(model.matrix(newformula, m$data)) - 1
#' Par <- m$mle[distnames]
#' nc <- meanind <- vector("list", length(distnames))
#' names(nc) <- names(meanind) <- distnames
#' for (i in distnames) {
#' nc[[i]] <- apply(m$conditions$fullDM[[i]], 1:2,
#' function(x) !all(unlist(x) == 0))
#' if (m$conditions$circularAngleMean[[i]]) {
#' meanind[[i]] <- which((apply(m$conditions$fullDM[[i]][1:nbStates,
#' , drop = FALSE], 1, function(x) !all(unlist(x) ==
#' 0))))
#' if (length(meanind[[i]])) {
#' angInd <- which(is.na(match(gsub("cos",
#' "", gsub("sin", "", colnames(nc[[i]]))),
#' colnames(nc[[i]]), nomatch = NA)))
#' sinInd <- colnames(nc[[i]])[which(grepl("sin",
#' colnames(nc[[i]])[angInd]))]
#' nc[[i]][meanind[[i]], sinInd] <- ifelse(nc[[i]][meanind[[i]],
#' sinInd], nc[[i]][meanind[[i]], sinInd], nc[[i]][meanind[[i]],
#' gsub("sin", "cos", sinInd)])
#' nc[[i]][meanind[[i]], gsub("sin", "cos",
#' sinInd)] <- ifelse(nc[[i]][meanind[[i]], gsub("sin",
#' "cos", sinInd)], nc[[i]][meanind[[i]],
#' gsub("sin", "cos", sinInd)], nc[[i]][meanind[[i]],
#' sinInd])
#' }
#' }
#' }
#' tmPar <- lapply(Par, function(x) c(t(x)))
#' parCount <- lapply(m$conditions$fullDM, ncol)
#' for (i in distnames[unlist(m$conditions$circularAngleMean)]) {
#' parCount[[i]] <- length(unique(gsub("cos", "",
#' gsub("sin", "", colnames(m$conditions$fullDM[[i]])))))
#' }
#' parindex <- c(0, cumsum(unlist(parCount))[-length(m$conditions$fullDM)])
#' names(parindex) <- distnames
#' for (i in distnames) {
#' if (!is.null(m$conditions$DM[[i]])) {
#' Par[[i]] <- m$mod$estimate[parindex[[i]] + 1:parCount[[i]]]
#' if (m$conditions$circularAngleMean[[i]]) {
#' names(Par[[i]]) <- unique(gsub("cos", "",
#' gsub("sin", "", colnames(m$conditions$fullDM[[i]]))))
#' }
#' else names(Par[[i]]) <- colnames(m$conditions$fullDM[[i]])
#' }
#' }
#' Par <- lapply(Par, function(x) c(t(x)))
#' beta <- m$mle$beta
#' nbCovsDelta <- ncol(m$covsDelta) - 1
#' foo <- length(m$mod$estimate) - (nbCovsDelta + 1) * (nbStates - 1) + 1
#' delta <- m$mod$estimate[foo:length(m$mod$estimate)]
#' tmpPar <- Par
#' tmpConditions <- m$conditions
#' for (i in distnames[which(m$conditions$dist %in% momentuHMM:::angledists)]){
#' if (!m$conditions$estAngleMean[[i]]) {
#' tmpConditions$estAngleMean[[i]] <- TRUE
#' tmpConditions$userBounds[[i]] <- rbind(matrix(rep(c(-pi,
#' pi), nbStates), nbStates, 2, byrow = TRUE), m$conditions$bounds[[i]])
#' tmpConditions$workBounds[[i]] <- rbind(matrix(rep(c(-Inf,
#' Inf), nbStates), nbStates, 2, byrow = TRUE),
#' m$conditions$workBounds[[i]])
#' tmpConditions$cons[[i]] <- c(rep(1, nbStates), m$conditions$cons[[i]])
#' tmpConditions$workcons[[i]] <- c(rep(0, nbStates),
#' m$conditions$workcons[[i]])
#' if (!is.null(m$conditions$DM[[i]])) {
#' tmpPar[[i]] <- c(rep(0, nbStates), Par[[i]])
#' if (is.list(m$conditions$DM[[i]])) {
#' tmpConditions$DM[[i]]$mean <- ~1
#' } else {
#' tmpDM <- matrix(0, nrow(tmpConditions$DM[[i]]) +
#' nbStates, ncol(tmpConditions$DM[[i]]) + nbStates)
#' tmpDM[nbStates + 1:nrow(tmpConditions$DM[[i]]),
#' nbStates + 1:ncol(tmpConditions$DM[[i]])] <- tmpConditions$DM[[i]]
#' diag(tmpDM)[1:nbStates] <- 1
#' tmpConditions$DM[[i]] <- tmpDM
#' }
#' } else {
#' Par[[i]] <- Par[[i]][-(1:nbStates)]
#' }
#' }
#' }
#' tmpInputs <- momentuHMM:::checkInputs(nbStates, tmpConditions$dist, tmpPar,
#' tmpConditions$estAngleMean, tmpConditions$circularAngleMean,
#' tmpConditions$zeroInflation, tmpConditions$oneInflation,
#' tmpConditions$DM, tmpConditions$userBounds, tmpConditions$cons,
#' tmpConditions$workcons, m$stateNames)
#' tmpp <- tmpInputs$p
#' splineInputs <- momentuHMM:::getSplineDM(distnames, tmpInputs$DM, m, covs)
#' covs <- splineInputs$covs
#' DMinputs <- momentuHMM:::getDM(covs, splineInputs$DM, tmpInputs$dist,
#' nbStates, tmpp$parNames, tmpp$bounds, tmpPar, tmpConditions$cons,
#' tmpConditions$workcons, tmpConditions$zeroInflation,
#' tmpConditions$oneInflation, tmpConditions$circularAngleMean)
#' fullDM <- DMinputs$fullDM
#' DMind <- DMinputs$DMind
#' wpar <- momentuHMM:::n2w(tmpPar, tmpp$bounds, beta, delta, nbStates,
#' tmpInputs$estAngleMean, tmpInputs$DM, DMinputs$cons, DMinputs$workcons,
#' tmpp$Bndind)
#' nc <- meanind <- vector("list", length(distnames))
#' names(nc) <- names(meanind) <- distnames
#' for (i in distnames) {
#' nc[[i]] <- apply(fullDM[[i]], 1:2, function(x) !all(unlist(x) == 0))
#' if (tmpInputs$circularAngleMean[[i]]) {
#' meanind[[i]] <- which((apply(fullDM[[i]][1:nbStates, ,drop = FALSE], 1,
#' function(x) !all(unlist(x) == 0))))
#' if (length(meanind[[i]])) {
#' angInd <- which(is.na(match(gsub("cos", "", gsub("sin", "",
#' colnames(nc[[i]]))), colnames(nc[[i]]), nomatch = NA)))
#' sinInd <- colnames(nc[[i]])[which(grepl("sin",
#' colnames(nc[[i]])[angInd]))]
#' nc[[i]][meanind[[i]], sinInd] <- ifelse(nc[[i]][meanind[[i]],
#' sinInd], nc[[i]][meanind[[i]], sinInd], nc[[i]][meanind[[i]],
#' gsub("sin", "cos", sinInd)])
#' nc[[i]][meanind[[i]], gsub("sin", "cos", sinInd)] <-
#' ifelse(nc[[i]][meanind[[i]], gsub("sin",
#' "cos", sinInd)], nc[[i]][meanind[[i]], gsub("sin", "cos", sinInd)],
#' nc[[i]][meanind[[i]], sinInd])
#' }
#' }
#' }
#' par <- momentuHMM:::w2n(wpar, tmpp$bounds, tmpp$parSize, nbStates, nbCovs,
#' tmpInputs$estAngleMean, tmpInputs$circularAngleMean,
#' tmpInputs$consensus, stationary = FALSE, DMinputs$cons,
#' fullDM, DMind, DMinputs$workcons, 1, tmpInputs$dist,
#' tmpp$Bndind, nc, meanind, m$covsDelta, tmpConditions$workBounds)
#' inputs <- momentuHMM:::checkInputs(nbStates, m$conditions$dist, Par,
#' m$conditions$estAngleMean,
#' m$conditions$circularAngleMean, m$conditions$zeroInflation,
#' m$conditions$oneInflation, m$conditions$DM, m$conditions$userBounds,
#' m$conditions$cons, m$conditions$workcons, m$stateNames)
#' p <- inputs$p
#' Fun <- lapply(inputs$dist, function(x) paste("d", x,
#' sep = ""))
#' zeroMass <- oneMass <- vector("list", length(inputs$dist))
#' names(zeroMass) <- names(oneMass) <- distnames
#' stateNames <- m$stateNames
#' if (is.null(stateNames)) {
#' stateNames <- NULL
#' for (i in 1:nbStates) stateNames <- c(stateNames, paste("state",i))
#' }
#' legText <- stateNames
#' tmpcovs <- covs
#' for (i in which(mapply(is.numeric, covs))) {
#' tmpcovs[i] <- round(covs[i], 2)
#' }
#' for (i in which(mapply(is.factor, covs))) {
#' tmpcovs[i] <- as.character(covs[[i]])
#' }
#' if (inherits(m, "miSum")) {
#' if (length(m$conditions$optInd)) {
#' Sigma <- matrix(0, length(m$mod$estimate), length(m$mod$estimate))
#' Sigma[(1:length(m$mod$estimate))[-m$conditions$optInd],
#' (1:length(m$mod$estimate))[-m$conditions$optInd]] <-
#' m$MIcombine$variance
#' } else {
#' Sigma <- m$MIcombine$variance
#' }
#' } else if (!is.null(m$mod$hessian)) {
#' Sigma <- m$mod$Sigma
#' } else {
#' Sigma <- NULL
#' plotCI <- FALSE
#' }
#' for (i in distnames) {
#' if (sepAnimals) {
#' genData <- list()
#' for (zoo in 1:nbAnimals) {
#' ind <- which(m$data$ID == ID[zoo])
#' genData[[zoo]] <- m$data[[i]][ind]
#' }
#' } else {
#' ind <- which(m$data$ID %in% ID)
#' genData <- m$data[[i]][ind]
#' }
#' zeroMass[[i]] <- rep(0, nbStates)
#' oneMass[[i]] <- rep(0, nbStates)
#' if (m$conditions$zeroInflation[[i]] | m$conditions$oneInflation[[i]]) {
#' if (m$conditions$zeroInflation[[i]]){
#' zeroMass[[i]] <- par[[i]][nrow(par[[i]]) - nbStates *
#' m$conditions$oneInflation[[i]] - (nbStates - 1):0, ]
#' }
#' if (m$conditions$oneInflation[[i]]){
#' oneMass[[i]] <- par[[i]][nrow(par[[i]]) - (nbStates - 1):0, ]
#' par[[i]] <- par[[i]][-(nrow(par[[i]]) - (nbStates *
#' m$conditions$oneInflation[[i]] -
#' nbStates * m$conditions$zeroInflation[[i]] -
#' 1):0), , drop = FALSE]
#' }
#' }
#' infInd <- FALSE
#' if (inputs$dist[[i]] %in% momentuHMM:::angledists) {
#' if (i == "angle" & ("step" %in% distnames)){
#' if (inputs$dist$step %in%
#' momentuHMM:::stepdists & m$conditions$zeroInflation$step){
#' if (all(c("x", "y") %in% names(m$data))){
#' infInd <- TRUE
#' }
#' }
#' }
#' }
#' covNames <- momentuHMM:::getCovNames(m, p, i)
#' DMterms <- covNames$DMterms
#' DMparterms <- covNames$DMparterms
#' if (inputs$consensus[[i]]) {
#' for (jj in 1:nbStates) {
#' if (!is.null(DMparterms$mean[[jj]])){
#' DMparterms$kappa[[jj]] <- c(DMparterms$mean[[jj]],
#' DMparterms$kappa[[jj]])
#' }
#' }
#' }
#' factorterms <- names(m$data)[unlist(lapply(m$data, is.factor))]
#' factorcovs <- paste0(rep(factorterms,
#' times = unlist(lapply(m$data[factorterms], nlevels))),
#' unlist(lapply(m$data[factorterms], levels)))
#' if (length(DMterms)) {
#' for (jj in 1:length(DMterms)) {
#' cov <- DMterms[jj]
#' form <- formula(paste("~", cov))
#' varform <- all.vars(form)
#' if (any(varform %in% factorcovs)) {
#' factorvar <- factorcovs %in% varform
#' DMterms[jj] <- rep(factorterms,
#' times = unlist(lapply(m$data[factorterms],
#' nlevels)))[which(factorvar)]
#' }
#' }
#' }
#' DMterms <- unique(DMterms)
#' if (length(DMparterms)) {
#' for (ii in 1:length(DMparterms)){
#' for (state in 1:nbStates){
#' if (length(DMparterms[[ii]][[state]])) {
#' for (jj in 1:length(DMparterms[[ii]][[state]])) {
#' cov <- DMparterms[[ii]][[state]][jj]
#' form <- formula(paste("~", cov))
#' varform <- all.vars(form)
#' if (any(varform %in% factorcovs)) {
#' factorvar <- factorcovs %in% varform
#' DMparterms[[ii]][[state]][jj] <- rep(factorterms,
#' times = unlist(lapply(m$data[factorterms],
#' nlevels)))[which(factorvar)]
#' }
#' }
#' DMparterms[[ii]][[state]] <- unique(DMparterms[[ii]][[state]])
#' }
#' }
#' }
#' }
#' covmess <- ifelse(!m$conditions$DMind[[i]], paste0(": ",
#' paste0(DMterms, " = ", tmpcovs[DMterms], collapse = ", ")), "")
#' genDensities <- list()
#' genFun <- Fun[[i]]
#' if (inputs$dist[[i]] %in% momentuHMM:::angledists) {
#' grid <- seq(-pi, pi, length = 1000)
#' } else if (inputs$dist[[i]] %in% momentuHMM:::integerdists) {
#' grid <- seq(0, max(m$data[[i]], na.rm = TRUE))
#' } else if (inputs$dist[[i]] %in% momentuHMM:::stepdists) {
#' grid <- seq(0, max(m$data[[i]], na.rm = TRUE), length = 10000)
#' } else {
#' grid <- seq(min(m$data[[i]], na.rm = TRUE), max(m$data[[i]],
#' na.rm = TRUE), length = 10000)
#' }
#' for (state in 1:nbStates) {
#' genArgs <- list(grid)
#' for (j in 1:(nrow(par[[i]])/nbStates)) {
#' genArgs[[j + 1]] <- par[[i]][(j - 1) * nbStates + state, ]
#' }
#' if (inputs$dist[[i]] == "gamma") {
#' shape <- genArgs[[2]]^2/genArgs[[3]]^2
#' scale <- genArgs[[3]]^2/genArgs[[2]]
#' genArgs[[2]] <- shape
#' genArgs[[3]] <- 1/scale
#' }
#' if (m$conditions$zeroInflation[[i]] | m$conditions$oneInflation[[i]]) {
#' genDensities[[state]] <- cbind(grid, (1 - zeroMass[[i]][state] -
#' oneMass[[i]][state]) * w[state] * do.call(genFun, genArgs))
#' } else if (infInd) {
#' genDensities[[state]] <- cbind(grid, (1 - zeroMass$step[state]) *
#' w[state] * do.call(genFun, genArgs))
#' } else {
#' genDensities[[state]] <- cbind(grid, w[state] * do.call(genFun,
#' genArgs))
#' }
#' for (j in p$parNames[[i]]) {
#' for (jj in DMparterms[[j]][[state]]) {
#' if (!is.factor(m$data[, jj])) {
#' gridLength <- 101
#' inf <- min(m$data[, jj], na.rm = T)
#' sup <- max(m$data[, jj], na.rm = T)
#' tempCovs <- data.frame(matrix(covs[jj][[1]],
#' nrow = gridLength, ncol = 1))
#' if (length(DMterms) > 1){
#' for (ii in DMterms[which(!(DMterms %in% jj))]){
#' tempCovs <- cbind(tempCovs, rep(covs[[ii]], gridLength))
#' }
#' names(tempCovs) <- c(jj, DMterms[which(!(DMterms %in% jj))])
#' tempCovs[, jj] <- seq(inf, sup, length = gridLength)
#' }
#' } else {
#' gridLength <- nlevels(m$data[, jj])
#' tempCovs <- data.frame(matrix(covs[jj][[1]],
#' nrow = gridLength, ncol = 1))
#' if (length(DMterms) > 1){
#' for (ii in DMterms[which(!(DMterms %in% jj))]){
#' tempCovs <- cbind(tempCovs, rep(covs[[ii]], gridLength))
#' }
#' names(tempCovs) <- c(jj, DMterms[which(!(DMterms %in% jj))])
#' tempCovs[, jj] <- as.factor(levels(m$data[, jj]))
#' }
#' }
#' for (ii in DMterms[which(unlist(lapply(m$data[DMterms],
#' is.factor)))]) {
#' tempCovs[[ii]] <- factor(tempCovs[[ii]],
#' levels = levels(m$data[[ii]]))
#' }
#' tmpSplineInputs <- momentuHMM::getSplineDM(i, inputs$DM, m,tempCovs)
#' tempCovs <- tmpSplineInputs$covs
#' DMinputs <- getDM(tempCovs, tmpSplineInputs$DM[i],
#' inputs$dist[i], nbStates, p$parNames[i],
#' p$bounds[i], Par[i], m$conditions$cons[i],
#' m$conditions$workcons[i], m$conditions$zeroInflation[i],
#' m$conditions$oneInflation[i],
#' m$conditions$circularAngleMean[i])
#' fullDM <- DMinputs$fullDM
#' DMind <- DMinputs$DMind
#' nc[[i]] <- apply(fullDM[[i]], 1:2, function(x) !all(unlist(x) == 0))
#' if (inputs$circularAngleMean[[i]]) {
#' meanind[[i]] <- which((apply(fullDM[[i]][1:nbStates, ,
#' drop = FALSE], 1, function(x) !all(unlist(x) == 0))))
#' if (length(meanind[[i]])) {
#' angInd <- which(is.na(match(gsub("cos", "", gsub("sin", "",
#' colnames(nc[[i]]))), colnames(nc[[i]]), nomatch = NA)))
#' sinInd <- colnames(nc[[i]])[which(grepl("sin",
#' colnames(nc[[i]])[angInd]))]
#' nc[[i]][meanind[[i]], sinInd] <- ifelse(nc[[i]][meanind[[i]],
#' sinInd], nc[[i]][meanind[[i]], sinInd],
#' nc[[i]][meanind[[i]], gsub("sin", "cos", sinInd)])
#' nc[[i]][meanind[[i]], gsub("sin", "cos", sinInd)] <-
#' ifelse(nc[[i]][meanind[[i]],
#' gsub("sin", "cos", sinInd)],
#' nc[[i]][meanind[[i]], gsub("sin", "cos", sinInd)],
#' nc[[i]][meanind[[i]], sinInd])
#' }
#' }
#' gradfun <- function(wpar, k) {
#' momentuHMM:::w2n(wpar, p$bounds[i], p$parSize[i], nbStates,
#' nbCovs, inputs$estAngleMean[i], inputs$circularAngleMean[i],
#' inputs$consensus[i], stationary = TRUE, DMinputs$cons[i],
#' fullDM, DMind, DMinputs$workcons[i], gridLength,
#' inputs$dist[i], p$Bndind[i], nc[i], meanind[i], m$covsDelta,
#' m$conditions$workBounds[i])[[i]][(which(tmpp$parNames[[i]] ==
#' j) - 1) * nbStates + state, k]
#' }
#' est <- momentuHMM:::w2n(c(m$mod$estimate[parindex[[i]] +
#' 1:parCount[[i]]], beta), p$bounds[i], p$parSize[i],
#' nbStates, nbCovs, inputs$estAngleMean[i],
#' inputs$circularAngleMean[i], inputs$consensus[i],
#' stationary = TRUE, DMinputs$cons[i], fullDM,
#' DMind, DMinputs$workcons[i], gridLength,
#' inputs$dist[i], p$Bndind[i], nc[i], meanind[i],
#' m$covsDelta,
#' m$conditions$workBounds[i])[[i]][(which(tmpp$parNames[[i]] ==
#' j) - 1) * nbStates + state, ]
#' if (plotCI) {
#' dN <- t(mapply(function(x) tryCatch(numDeriv::grad(gradfun,
#' c(m$mod$estimate[parindex[[i]] + 1:parCount[[i]]],
#' beta), k = x), error = function(e) NA), 1:gridLength))
#' se <- t(apply(dN[, 1:parCount[[i]]], 1,
#' function(x) tryCatch(suppressWarnings(sqrt(x %*%
#' Sigma[parindex[[i]] + 1:parCount[[i]],
#' parindex[[i]] + 1:parCount[[i]]] %*% x)),
#' error = function(e) NA)))
#' uci <- est + qnorm(1 - (1 - alpha)/2) * se
#' lci <- est - qnorm(1 - (1 - alpha)/2) * se
#' do.call(plot, c(list(tempCovs[, jj], est,
#' ylim = range(c(lci, est, uci), na.rm = TRUE),
#' xaxt = "n", xlab = jj, ylab = paste(i,
#' ifelse(j == "kappa", "concentration",
#' j), "parameter"), main = paste0(stateNames[state],
#' ifelse(length(tempCovs[,
#' DMparterms[[j]][[state]][-which(DMparterms[[j]][[state]] == jj)]]),
#' paste0(": ",
#' paste(DMparterms[[j]][[state]][-which(DMparterms[[j]][[state]] == jj)], "=",
#' tmpcovs[,
#' DMparterms[[j]][[state]][-which(DMparterms[[j]][[state]] == jj)]],
#' collapse = ", ")), "")), type = "l", lwd = lwd,
#' cex.main = cex.main), arg))
#' if (!all(is.na(se))) {
#' ciInd <- which(!is.na(se))
#' withCallingHandlers(do.call(arrows, c(list(as.numeric(tempCovs[ciInd,
#' jj]), lci[ciInd], as.numeric(tempCovs[ciInd,
#' jj]), uci[ciInd], length = 0.025, angle = 90,
#' code = 3, col = gray(0.5), lwd = lwd),
#' arg)), warning = muffWarn)
#' }
#' } else {
#' do.call(plot, c(list(tempCovs[, jj], est,
#' xaxt = "n", xlab = jj, ylab = paste(i,
#' ifelse(j == "kappa", "concentration", j), "parameter"),
#' main = paste0(stateNames[state],
#' ifelse(length(tempCovs[,
#' DMparterms[[j]][[state]][-which(DMparterms[[j]][[state]] ==
#' jj)]]), paste0(": ",
#' paste(DMparterms[[j]][[state]][-which(DMparterms[[j]][[state]] ==
#' jj)], "=",
#' tmpcovs[, DMparterms[[j]][[state]][-which(DMparterms[[j]][[state]] ==
#' jj)]], collapse = ", ")), "")), type = "l", lwd = lwd,
#' cex.main = cex.main), arg))
#' }
#' if (is.factor(tempCovs[, jj])){
#' do.call(axis, c(list(1, at = tempCovs[, jj],
#' labels = tempCovs[, jj]), arg))
#' } else {
#' do.call(axis, c(list(1), arg))
#' }
#' }
#' }
#' }
#' } # FINISHED (and working) distnames loop
#' # This is the section that plots the transition probabilities
#' if (nbStates > 1) {
#' gamInd <- (length(m$mod$estimate) - (nbCovs + 1) * nbStates *
#' (nbStates - 1) + 1):(length(m$mod$estimate)) - ncol(m$covsDelta) *
#' (nbStates - 1) * (!m$conditions$stationary)
#' quantSup <- qnorm(1 - (1 - alpha)/2)
#' if (nrow(beta) > 1) {
#' rawCovs <- m$rawCovs[which(m$data$ID %in% ID), ,
#' drop = FALSE]
#' for (cov in 1:ncol(rawCovs)) { #THIS IS TRUE START OF LOOP,
#' if (!is.factor(rawCovs[, cov])) {
#' gridLength <- 101
#' inf <- min(rawCovs[, cov], na.rm = T)
#' sup <- max(rawCovs[, cov], na.rm = T)
#' tempCovs <- data.frame(matrix(covs[names(rawCovs)][[1]],
#' nrow = gridLength, ncol = 1))
#' if (ncol(rawCovs) > 1) {
#' for (i in 2:ncol(rawCovs)) {
#' tempCovs <- cbind(tempCovs,
#' rep(covs[names(rawCovs)][[i]], gridLength))
#' tempCovs[, cov] <- seq(inf, sup, length = gridLength)
#' }
#' }
#' } else {
#' gridLength <- nlevels(rawCovs[, cov])
#' tempCovs <- data.frame(matrix(covs[names(rawCovs)][[1]],
#' nrow = gridLength, ncol = 1))
#' if (ncol(rawCovs) > 1)
#' for (i in 2:ncol(rawCovs)) {
#' tempCovs <- cbind(tempCovs, rep(covs[names(rawCovs)][[i]],
#' gridLength))
#' tempCovs[, cov] <- as.factor(levels(rawCovs[, cov]))
#' }
#' }
#' names(tempCovs) <- names(rawCovs)
#' tmpcovs <- covs[names(rawCovs)]
#' for (i in which(unlist(lapply(rawCovs, is.factor)))) {
#' tempCovs[[i]] <- factor(tempCovs[[i]], levels = levels(rawCovs[,i]))
#' tmpcovs[i] <- as.character(tmpcovs[[i]])
#' }
#' for (i in which(!unlist(lapply(rawCovs, is.factor)))) {
#' tmpcovs[i] <- round(covs[names(rawCovs)][i], 2)
#' }
#' tmpSplineInputs <- momentuHMM:::getSplineFormula(newformula, m$data,
#' tempCovs)
#' desMat <- model.matrix(tmpSplineInputs$formula,
#' data = tmpSplineInputs$covs)
#' trMat <- momentuHMM:::trMatrix_rcpp(nbStates, beta, desMat,
#' m$conditions$betaRef)
#' for (i in 1:nbStates) {
#' for (j in 1:nbStates) {
#' if (cov == 1 && i == 1 && j == 1){
#' covars <- tempCovs %>% slice(0)
#' df_trans <- bind_cols(covars, tibble(start_st = integer(),
#' end_st = integer(), prob = numeric(), lci = numeric(),
#' uci = numeric()))
#' }
#' covars <- tempCovs
#' prob <- trMat[i, j, ]
#' start_st <- rep(i, nrow(covars))
#' end_st <- rep(j, nrow(covars))
#' print(paste0("Start ", "cov: ", cov, " i: ", i, " j: ", j))
#' dN <- t(apply(desMat, 1, function(x)
#' tryCatch(numDeriv::grad(momentuHMM:::get_gamma,
#' m$mod$estimate[gamInd][unique(c(m$conditions$betaCons))],
#' covs = matrix(x, nrow = 1), nbStates = nbStates,
#' i = i, j = j, betaRef = m$conditions$betaRef,
#' betaCons = m$conditions$betaCons,
#' workBounds = m$conditions$workBounds$beta),
#' error = function(e) NA)))
#' se <- t(apply(dN, 1, function(x)
#' tryCatch(suppressWarnings(sqrt(x %*%
#' Sigma[gamInd[unique(c(m$conditions$betaCons))],
#' gamInd[unique(c(m$conditions$betaCons))]] %*% x)),
#' error = function(e) NA)))
#' if (!all(is.na(se))) {
#' lci <- 1/(1 + exp(-(log(trMat[i, j, ]/(1 -
#' trMat[i, j, ])) - quantSup * (1/(trMat[i,
#' j, ] - trMat[i, j, ]^2)) * se)))
#' uci <- 1/(1 + exp(-(log(trMat[i, j, ]/(1 -
#' trMat[i, j, ])) + quantSup * (1/(trMat[i,
#' j, ] - trMat[i, j, ]^2)) * se)))
#' lci <- as.vector(lci)
#' uci <- as.vector(uci)
#' } else {
#' lci <- rep(NA, nrow(covars))
#' uci <- rep(NA, nrow(covars))
#' }
#' trans_probs <- tibble(start_st, end_st, prob, lci, uci)
#' df_trans_ij <- bind_cols(covars, trans_probs) %>%
#' as_tibble(.)
#' df_trans <- bind_rows(df_trans, df_trans_ij)
#' print(paste0("End cov: ", cov, "i: ", i, " j: ", j))
#' }
#' }
#' }
#' }
#' }
#' df_trans_final <- dplyr::as_tibble(df_trans)
#' return(df_trans_final)
#' }
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.