#' Generate Response Curves
#'
#' Given an environmental data set, fitted models, and a directory to output plots, this function generates response curves for each predictor in the model. The response curves depict the predicted change in probability of presence as a function of the environmental predictor while holding all other predictors constant at their mean values.
#'
#' @param env_bg Object returned by get_env_bg
#' @param env_pres Object returned by get_env_pres
#' @param pnp_model Object returned by `fit_plug_and_play` or `fit_density_ratio`
#' @param n.int Number of points along which to calculate the response curve
#' @param envMeans A vector of means for each environmental predictor in the dataset. (not used)
#' @param envSDs A vector of standard deviations for each environmental predictor in the dataset.(not used)
#'
#' @return This function generates a set of marginal predictions for each environmental variable, holding other variables constant
#' @author Cory Merow, modified by Brian Maitner
#' @importFrom stats approx density
#' @importFrom dplyr bind_rows
get_response_curves <- function(env_bg,
env_pres,
pnp_model,
n.int = 1000,
envMeans = NULL,
envSDs = NULL
){
# get env means and SDs
if(is.null(envMeans) & all(!is.na(env_bg$env_mean))){
envMeans <- env_bg$env_mean
}
if(is.null(envSDs) & all(!is.na(env_bg$env_sd))){
envSDs <- env_bg$env_sd
}
# make env gradients
x.vals <- apply(env_bg$env,MARGIN = 2,
FUN = function(x){
mi <- quantile(x = x,probs = 0.03,na.rm=TRUE)
ma <- quantile(x = x,probs = 0.97,na.rm=TRUE)
ra <- ma-mi
seq(mi-.5*ra,ma+.5*ra, length = n.int)
}, simplify = FALSE)
# make labels on real scale
best.var <- names(x.vals)
# if(!is.null(envMeans) & !is.null(envSDs)){
#
# xTickLabs=lapply(seq_along(best.var),function(x){
# (x.vals[[x]]*as.numeric(envSDs[x][1])) + as.numeric(envMeans[x][1])
# })
# } else { xTickLabs=x.vals }
#
# names(xTickLabs) <- best.var
if(is.null(envMeans) | is.null(envSDs)) {
message("Response curves only work if your predictors are standardized. There's no error here; you just won't get response curve plots.")
return(invisible(NULL))
}
# these density estimates are only used if a pnp presence or abscence function is omitted
pd <- apply(X = env_pres$env,
MARGIN = 2,
FUN = function(x){density(x,adjust=2)})
bgd <- apply(X = env_bg$env,
MARGIN = 2,
FUN = function(x){density(x,adjust=2)})
pd_newdat <- data.frame()
bgd_newdat <- data.frame()
# what would be useful:
# value type background vs presence vs prediction
# environmental variable
# value
marginal_vals <- NULL
for(k in seq_along(best.var)){
newdat <- data.frame(matrix(rep(rep(0, n.int),
length(best.var)),
ncol = length(best.var)))
names(newdat) <- best.var
newdat[best.var[[k]]] <- x.vals[[best.var[k]]]
if(inherits(pnp_model,"dr_model")){
pr <- project_density_ratio(dr_model = pnp_model,
data = newdat)
}
if(inherits(pnp_model,"pnp_model")){
pr <- project_plug_and_play(pnp_model = pnp_model,
data = newdat)
}
# get background curve
# Use different methods depending on whether presence and/or background density were part of the model
if(inherits(pnp_model,"pnp_model")){
# presence
if(pnp_model$f1_bs) {
#If bs WAS done, use a do.call for each iteration and average them
f1_est <- 0
#It would be good to include a foreach option
for(i in 1:length(pnp_model$f1)){
f1_est <-
f1_est +
do.call(what = paste('pnp_',pnp_model$f1_method,sep = ""),
list(data = newdat,
method = "predict",
object = pnp_model$f1[[i]]))
}
pd_newdat <- data.frame(y = f1_est/length(pnp_model$f1) %>%
exp())
}else{
#If bs wasn't done, just use one do.call
pd_newdat <- data.frame(y = do.call(what = paste('pnp_', pnp_model$f1_method, sep = ""),
list(data = newdat,
method = "predict",
object = pnp_model$f1)))
if(length(pd_newdat) > 0){pd_newdat <- exp(pd_newdat)}
}
#background
if(pnp_model$f0_bs) {
#If bs WAS done, use a do.call for each iteration and average them
f0_est <- 0
#It would be good to include a foreach option
for(i in 1:length(pnp_model$f0)){
f0_est <-
f0_est +
do.call(what = paste('pnp_',pnp_model$f0_method,sep = ""),
list(data = newdat,
method = "predict",
object = pnp_model$f0[[i]]))
}
bgd_newdat <- data.frame(y = f0_est/length(pnp_model$f0) %>% exp())
}else{
#If bs wasn't done, just use one do.call
bgd_newdat <- data.frame(y= do.call(what = paste('pnp_',pnp_model$f0_method,sep = ""),
list(data = newdat,
method = "predict",
object = pnp_model$f0)))
if(length(bgd_newdat) > 0){bgd_newdat <- exp(bgd_newdat)}
}
}
if(length(pd_newdat) == 0){
# estimate presence density at new points
pd_newdat <- approx(x = pd[[best.var[k]]]$x,
y = pd[[best.var[k]]]$y,
xout = newdat[best.var[[k]]] %>% unlist())
pd_newdat$y[which(is.na(pd_newdat$y))] <- 0
}
if( length(bgd_newdat) == 0){
# estimate background density at new points
bgd_newdat <- approx(x = bgd[[best.var[k]]]$x,
y = bgd[[best.var[k]]]$y,
xout = newdat[best.var[[k]]] %>% unlist())
bgd_newdat$y[which(is.na(bgd_newdat$y))] <- 0
}
out_k <- data.frame(variable = best.var[[k]],
x_values = newdat[best.var[[k]]] %>% unname(),
prediction = pr,
background_density = bgd_newdat$y,
presence_density = pd_newdat$y
) %>%`rownames<-`(NULL)
# out_k %>%
# mutate(std_pred = prediction/sum(prediction)*sum(background_density))%>%
# ggplot(mapping = aes(x=x_values,
# y=std_pred))+
# geom_line(color="blue",size=1.5)+
# geom_line(mapping = aes(x=x_values,y=presence_density))+
# geom_line(mapping = aes(x=x_values,y=background_density))+
# ylab(NULL)+
# xlab(best.var[[k]])
marginal_vals <- marginal_vals %>%
dplyr::bind_rows(out_k)
}
return(marginal_vals)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.