From 48c6c5bc8eca5be239f431089fccffdb946d714d Mon Sep 17 00:00:00 2001 From: DylanCarbone Date: Mon, 17 Jun 2024 10:49:21 +0100 Subject: [PATCH] fix of detect_jags function --- DESCRIPTION | 5 +- NAMESPACE | 1 - R/bayesian_meta_analysis.R | 16 +++- R/detect_jags.r | 53 ++++++++++-- .../package_notes_and_benchmarking.Rmd | 85 +++++++++++++++++++ man/bma.Rd | 5 +- .../testthat/helper-bayesian_meta_analysis.R | 15 +++- tests/testthat/test-bayesian_meta_analysis.R | 31 ++++--- vignettes/vignette.Rmd | 5 -- 9 files changed, 181 insertions(+), 35 deletions(-) create mode 100644 benchmarking/package_notes_and_benchmarking.Rmd diff --git a/DESCRIPTION b/DESCRIPTION index 2c707b0..b9d0c56 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -39,14 +39,15 @@ Imports: RColorBrewer, reshape2, jagsUI, - runjags + rjags Suggests: covr, knitr, rmarkdown, snowfall, sparta, - testthat (>= 3.0.0) + testthat (>= 3.0.0), + runjags VignetteBuilder: knitr Config/testthat/edition: 3 diff --git a/NAMESPACE b/NAMESPACE index 827e29a..cdc5e0d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -25,4 +25,3 @@ importFrom(car,logit) importFrom(coda,as.mcmc) importFrom(coda,mcmc.list) importFrom(reshape2,dcast) -importFrom(runjags,testjags) diff --git a/R/bayesian_meta_analysis.R b/R/bayesian_meta_analysis.R index e0e7d19..7796e0b 100644 --- a/R/bayesian_meta_analysis.R +++ b/R/bayesian_meta_analysis.R @@ -25,6 +25,7 @@ #' @param save.sppars Logical. Should the species-specific parameters be monitored? Defaults to TRUE #' @param CI defines the credible intervals of the posterior distribution to report. Defaults the 95th percentile #' @param seed Option to set a custom seed to initialize JAGS chains, for reproducibility. Should be an integer. This argument will be deprecated in the next version, but you can always set the outside the function yourself. +#' @param jags_path The full path to the JAGS executable. The default value is null. If null, will search the default installation path of the operating system. If specified, the path will be set to the JAGS_HOME system variable. #' @details There are a number of model to choose from: #' \itemize{ #' \item{\code{"smooth"}}{ The default option. Indicator defined by Growth rates, with Ruppert smoother, allowing for species to join late. Error on the first year of each species' time-series is assumed to be zero. The indicator is the expected value of the geometric mean across species (with missing species imputed). @@ -81,14 +82,21 @@ bma <- function (data, save.sppars = TRUE, incl.2deriv = FALSE, CI = 95, - seed = NULL){ + seed = NULL, + jags_path = NULL){ set.seed(seed = seed) # Check if JAGS is installed -if (!detect_jags()) { -stop("No installation of JAGS has been detected. You can install JAGS from https://sourceforge.net/projects/mcmc-jags/files/JAGS/", - call. = FALSE) +if (!detect_jags(jags_path)) { + stop( + "JAGS could not be found\n", + "If you have not installed JAGS, please install it from: https://sourceforge.net/projects/mcmc-jags/\n", + "If JAGS has been installed to the default location, restart the console, and this error should not re-occur. If it does, specify the full path to the JAGS executable", + "To quickly recover the path of the jags executable you can run the following:\n", + "library(rjags)\n", + "runjags::findjags()" + ) } # Check to see that column names are present diff --git a/R/detect_jags.r b/R/detect_jags.r index 649a45e..e29bf91 100644 --- a/R/detect_jags.r +++ b/R/detect_jags.r @@ -1,6 +1,49 @@ # Internal function to detect JAGS installation. -#' @importFrom runjags testjags -#' -detect_jags <- function(){ - return(suppressWarnings(runjags::testjags(silent = TRUE)$JAGS.found)) -} \ No newline at end of file +#' +detect_jags <- function(jags_path){ + + # Get the operating system type + os_type <- Sys.info()["sysname"] + + if(!is.null(jags_path)){ + + message("A non-default jags installation path has been specified. Setting jags path as an environment variable") + + # Set JAGS_HOME variable + Sys.setenv(JAGS_HOME = jags_path) + + return(TRUE) + + } else { + + if (os_type == "Windows") { + + # Search the default installation path for Windows + user_home <- Sys.getenv("USERPROFILE") + jags_dir <- file.path(user_home, "AppData", "Local", "Programs", "JAGS") + + jags_path <- list.files(jags_dir, full.name = TRUE, recursive = TRUE, pattern = "*jags-terminal.exe") + + } else if (os_type == "Darwin") { + + # Search the default installation path for macOS + jags_path <- list.files("/usr/local/bin/JAGS", full.name = TRUE, recursive = TRUE, pattern = "*jags-terminal.exe") + + } else { + + message("Unsupported OS type, returning false for JAGS installation. To bypass, please specify the path to the jags executable in jags_path") + return(FALSE) + + } + + if(length(jags_path) > 0){ + + return(TRUE) + + } else { + + return(FALSE) + + } + } +} diff --git a/benchmarking/package_notes_and_benchmarking.Rmd b/benchmarking/package_notes_and_benchmarking.Rmd new file mode 100644 index 0000000..eb618ed --- /dev/null +++ b/benchmarking/package_notes_and_benchmarking.Rmd @@ -0,0 +1,85 @@ +--- +title: "BRCindicators - Notes of core functionality and benchmarking" +author: "Dylan Carbone" +date: "June 2024" +output: + html_document: + keep_md: yes + toc: yes +--- +**This shows how us to use the indicator pipeline to create biodiversity indicators such as those for DEFRA Biodiversity Indicators in Your Pocke.** + +**BRCindicators works with yearly estimates of species abundance or occurrence and aggregate them into an scaled indicator value with bootstrapped confidence intervals.** + +First, we create some example data. NOTE, the format is the same as the data created within the sparta vignette. +```{r create_some_data} +# Create data +n <- 8000 # size of dataset +nyr <- 50 # number of years in data +nSamples <- 200 # set number of dates +nSites <- 100 # set number of sites +set.seed(125) # set a random seed + +# Create somes dates +first <- as.Date(strptime("1950/01/01", "%Y/%m/%d")) +last <- as.Date(strptime(paste(1950+(nyr-1),"/12/31", sep=''), "%Y/%m/%d")) +dt <- last-first +rDates <- first + (runif(nSamples)*dt) + +# taxa are set semi-randomly +taxa_probabilities <- seq(from = 0.1, to = 0.7, length.out = 26) +taxa <- sample(letters, size = n, TRUE, prob = taxa_probabilities) + +# sites are visited semi-randomly +site_probabilities <- seq(from = 0.1, to = 0.7, length.out = nSites) +site <- sample(paste('A', 1:nSites, sep=''), size = n, TRUE, prob = site_probabilities) + +# the date of visit is selected semi-randomly from those created earlier +time_probabilities <- seq(from = 0.1, to = 0.7, length.out = nSamples) +time_period <- sample(rDates, size = n, TRUE, prob = time_probabilities) + +myData <- data.frame(taxa, site, time_period) +``` + +```{r} +# Load sparta +library(sparta) + +# First format our data +formattedOccData <- formatOccData(taxa = myData$taxa, + site = myData$site, + survey = myData$time_period) + +# I create a function that takes a species name and runs my model +occ_mod_function <- function(taxa_name){ + + # Note that this will write you results to your computer + # the location is set to your user folder + occ_out <- sparta::occDetFunc(taxa_name = as.character(taxa_name), + n_iterations = 200, + burnin = 15, + occDetdata = formattedOccData$occDetdata, + spp_vis = formattedOccData$spp_vis, + write_results = TRUE, + output_dir = '~/Testing_indicator_pipe', + seed = 123) +} +# I then run this +para_out <- sapply(unique(myData$taxa), occ_mod_function) + +``` + +**Now that we have some species trends data to work with, we can use the first function in BRCindicators. This function reads in all the output files from sparta and returns a simple summary table that we can use for calculating the indicator.** + +```{r set_up_run} +library(BRCindicators) + +# All we have to supply is the directory where out data is saved +# You will note this is the 'output_dir' passed to sparta above. +trends_summary <- summarise_occDet(para_out) + +# Lets see the summary +head(trends_summary[,1:5]) +``` + +**Returned from this function is a summary of the data as a matrix. In each row we have the year, specified in the first column, and each subsequent column is a species.** \ No newline at end of file diff --git a/man/bma.Rd b/man/bma.Rd index 30532e2..50d04e3 100644 --- a/man/bma.Rd +++ b/man/bma.Rd @@ -24,7 +24,8 @@ bma( save.sppars = TRUE, incl.2deriv = FALSE, CI = 95, - seed = NULL + seed = NULL, + jags_path = NULL ) } \arguments{ @@ -71,6 +72,8 @@ Here you specify which log scale the data is on ('loge', 'log10', or 'logit'). D \item{CI}{defines the credible intervals of the posterior distribution to report. Defaults the 95th percentile} \item{seed}{Option to set a custom seed to initialize JAGS chains, for reproducibility. Should be an integer. This argument will be deprecated in the next version, but you can always set the outside the function yourself.} + +\item{jags_path}{The full path to the JAGS executable. The default value is null. If null, will search the default installation path of the operating system. If specified, the path will be set to the JAGS_HOME system variable.} } \value{ Returns a dataframe with 7 columns: Year, Index.Mprime, lowerCI.Mprime, upperCI.Mprime, Index.M, lowerCI.M and, upperCI.M. diff --git a/tests/testthat/helper-bayesian_meta_analysis.R b/tests/testthat/helper-bayesian_meta_analysis.R index dd8d3b1..eded9c6 100644 --- a/tests/testthat/helper-bayesian_meta_analysis.R +++ b/tests/testthat/helper-bayesian_meta_analysis.R @@ -24,7 +24,8 @@ bma_objects <- function (data, save.sppars = TRUE, incl.2deriv = FALSE, CI = 95, - seed = NULL){ + seed = NULL, + jags_path = NULL){ # To capture objects output = list() @@ -32,9 +33,15 @@ output = list() set.seed(seed = seed) # Check if JAGS is installed -if (!detect_jags()) { -stop("No installation of JAGS has been detected. You can install JAGS from https://sourceforge.net/projects/mcmc-jags/files/JAGS/", - call. = FALSE) +if (!detect_jags(jags_path)) { + stop( + "JAGS could not be found\n", + "If you have not installed JAGS, please install it from: https://sourceforge.net/projects/mcmc-jags/\n", + "If JAGS has been installed to the default location, restart the console, and this error should not re-occur. If it does, specify the full path to the JAGS executable", + "To quickly recover the path of the jags executable you can run the following:\n", + "library(rjags)\n", + "runjags::findjags()" + ) } # Check to see that column names are present diff --git a/tests/testthat/test-bayesian_meta_analysis.R b/tests/testthat/test-bayesian_meta_analysis.R index 0f79cae..ca33051 100644 --- a/tests/testthat/test-bayesian_meta_analysis.R +++ b/tests/testthat/test-bayesian_meta_analysis.R @@ -1,17 +1,22 @@ -test_that("Does the function stop when there is no jags installation?", { +test_that("Does the function stop when there is no JAGS installation?", { # Mock `detect_jags` to return FALSE with_mocked_bindings( - "detect_jags" = function() FALSE, + "detect_jags" = function(jags_path = NULL) { + FALSE + }, { - expect_error(bma(bayesian_meta_analysis_fake_data), regexp = "No installation of JAGS has been detected") + expect_error( + bma(bayesian_meta_analysis_fake_data), + regexp = "JAGS could not be found" + ) } ) }) test_that("Does it correctly detect missing columns in the input data?", { # skip the test if JAGS is not installed - if (!detect_jags()) { - skip("JAGS software not detectable") + if (!detect_jags(jags_path = NULL)) { + skip("JAGS could not be found") } expect_error(bma(subset(bayesian_meta_analysis_fake_data, select = -c(index))), @@ -21,8 +26,8 @@ test_that("Does it correctly detect missing columns in the input data?", { test_that("Does it correctly detect a missing standard error column?", { # skip the test if JAGS is not installed - if (!detect_jags()) { - skip("JAGS software not detectable") + if (!detect_jags(jags_path = NULL)) { + skip("JAGS could not be found") } expect_error(bma(subset(bayesian_meta_analysis_fake_data, select = -c(se)), seFromData = TRUE), @@ -32,8 +37,8 @@ test_that("Does it correctly detect a missing standard error column?", { test_that("Does it correctly return an error if a deprecated model, in this case smooth_det, is chosen?", { # skip the test if JAGS is not installed - if (!detect_jags()) { - skip("JAGS software not detectable") + if (!detect_jags(jags_path = NULL)) { + skip("JAGS could not be found") } expect_error(bma(bayesian_meta_analysis_fake_data, model = "smooth_det"), @@ -43,8 +48,8 @@ test_that("Does it correctly return an error if a deprecated model, in this case test_that("Does the function output, assuming jags is available, return a dataframe?", { # skip the test if JAGS is not installed - if (!detect_jags()) { - skip("JAGS software not detectable") + if (!detect_jags(jags_path = NULL)) { + skip("JAGS could not be found") } expect_equal(class(suppressWarnings(bma(bayesian_meta_analysis_fake_data, plot = FALSE))), "data.frame") @@ -52,8 +57,8 @@ test_that("Does the function output, assuming jags is available, return a datafr test_that("Does the function return a Markov Chain Monte Carlo (MCMC) output object?", { # skip the test if jagsUI is not installed - if (!detect_jags()) { - skip("JAGS software not detectable") + if (!detect_jags(jags_path = NULL)) { + skip("JAGS could not be found") } expect_equal(class(suppressWarnings(bma_objects(bayesian_meta_analysis_fake_data, plot = TRUE)$comb.samples)), "mcmc.list") diff --git a/vignettes/vignette.Rmd b/vignettes/vignette.Rmd index 89f8b0d..ef12169 100644 --- a/vignettes/vignette.Rmd +++ b/vignettes/vignette.Rmd @@ -6,11 +6,6 @@ output: html_document: keep_md: yes toc: yes -vignette: > - %\VignetteIndexEntry{BRCindicators} - %\usepackage[utf8]{inputenc} - %\VignetteEncoding{UTF-8} - %\VignetteEngine{knitr::rmarkdown} --- ```{r knitr_setup, echo=FALSE}