diff --git a/.Rbuildignore b/.Rbuildignore index 85a907a..70f2dd5 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,3 +1,5 @@ +^renv$ +^renv\.lock$ ^.*\.Rproj$ ^\.Rproj\.user$ ^ReadMe.md @@ -11,3 +13,6 @@ hex_sticker.R ^_pkgdown\.yml$ ^docs$ ^pkgdown$ +^vignettes/sas-macros.Rmd +^altdoc$ +^_quarto$ diff --git a/.github/workflows/R-Build-Test_cleanupBranch.yml b/.github/workflows/R-Build-Test_cleanupBranch.yml index 38cd358..5cec1e0 100644 --- a/.github/workflows/R-Build-Test_cleanupBranch.yml +++ b/.github/workflows/R-Build-Test_cleanupBranch.yml @@ -10,7 +10,7 @@ name: R on: push: - branches: [] #branches: [ "cleanup_edits_SM" ] + branches: [ "cleanup_edits_SM" ] permissions: contents: read @@ -22,8 +22,12 @@ jobs: fail-fast: true matrix: r-version: ['release'] - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ubuntu-latest, windows-latest, macos-latest] #[ubuntu-latest] + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + permissions: + contents: write steps: - uses: actions/checkout@v4 @@ -33,10 +37,22 @@ jobs: r-version: ${{ matrix.r-version }} use-public-rspm: true + - name: Cache R + uses: actions/cache@v4 + with: + path: ${{ env.R_LIBS_USER }} + key: ${{ runner.os }}-r-${{ matrix.r-version }}-${{ hashFiles('DESCRIPTION') }}-${{ hashFiles('**/renv.lock') }} + restore-keys: | + ${{ runner.os }}-r-${{ matrix.r-version }}-${{ hashFiles('**/renv.lock') }} + ${{ runner.os }}-r-${{ matrix.r-version }} + + + - name: Install dependencies + if: steps.cache-r.outputs.cache-hit != 'true' uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: any::rcmdcheck + extra-packages: any::rcmdcheck,altdoc,quarto,roxygen2,remotes needs: check - name: Check Package @@ -44,4 +60,20 @@ jobs: with: upload-snapshots: true build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' + error-on: '"error"' + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package + diff --git a/.github/workflows/altdoc_quarto.yaml b/.github/workflows/altdoc_quarto.yaml new file mode 100644 index 0000000..8090f53 --- /dev/null +++ b/.github/workflows/altdoc_quarto.yaml @@ -0,0 +1,65 @@ +# Workflow derived from https://github.com/CIDA-CSPH/CIDAtools/pkgdown.yaml + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + release: + types: [published] + workflow_dispatch: + +name: altdoc_quarto_site + +jobs: + build_doc: + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + r-version: ['release'] + # Only restrict concurrency for non-PR jobs + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - name: Set up R ${{ matrix.r-version }} + uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.r-version }} + use-public-rspm: true + + - name: Install dependencies + uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: local::.,any::rcmdcheck,any::altdoc,any::quarto,any::roxygen2 + needs: check + + - name: Cache R + uses: actions/cache@v4 + with: + path: ${{ env.R_LIBS_USER }} + key: ${{ runner.os }}-r-${{ hashFiles('DESCRIPTION') }} + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true + + - name: Run Roxygen2 + run: Rscript -e 'roxygen2::roxygenise()' + + - name: Build Altdoc Site + run: Rscript -e 'altdoc::render_docs(path = ".", verbose = FALSE, parallel = FALSE, freeze = FALSE)' + + - name: Deploy to GitHub pages 🚀 + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.4.1 + with: + clean: false + branch: gh-pages + folder: docs diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml deleted file mode 100644 index ed7650c..0000000 --- a/.github/workflows/pkgdown.yaml +++ /dev/null @@ -1,48 +0,0 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help -on: - push: - branches: [main, master] - pull_request: - branches: [main, master] - release: - types: [published] - workflow_dispatch: - -name: pkgdown - -jobs: - pkgdown: - runs-on: ubuntu-latest - # Only restrict concurrency for non-PR jobs - concurrency: - group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - permissions: - contents: write - steps: - - uses: actions/checkout@v3 - - - uses: r-lib/actions/setup-pandoc@v2 - - - uses: r-lib/actions/setup-r@v2 - with: - use-public-rspm: true - - - uses: r-lib/actions/setup-r-dependencies@v2 - with: - extra-packages: any::pkgdown, local::. - needs: website - - - name: Build site - run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) - shell: Rscript {0} - - - name: Deploy to GitHub pages 🚀 - if: github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@v4.4.1 - with: - clean: false - branch: gh-pages - folder: docs diff --git a/.gitignore b/.gitignore index 3c84d79..0290339 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,10 @@ inst/doc *.DS_Store docs +/tests/testthat/*.rds + + +/.quarto/ +altdoc/freeze.rds +_quarto/* +!_quarto/_freeze/ diff --git a/DESCRIPTION b/DESCRIPTION index 1069bfe..e8e0227 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,26 +1,28 @@ Package: CIDAtools Title: This package contains tools for CIDA projects -Version: 0.1.2 +Version: 0.2.0 Authors@R: - c(person("CIDA Research Tools Committee", role = c("aut", "cre"), email = "ryan.a.peterson@cuanschutz.edu")) + c(person("CIDA Research Tools Committee", role = c("aut", "cre"), email = "CIDA-RT@olucdenver.onmicrosoft.com")) Description: This package contains the numerous templates and tools to make life at CIDA (part of the Colorado School of Public Health) happier and more efficient! -Depends: R (>= 3.5.0) +Depends: R (>= 4.0) Imports: dplyr, generics, flextable, table1, - shiny + shiny, + fs Suggests: - git2r, - survey, - xlsx, + git2r, + survey, + quarto, + xlsx, knitr, - pander, + pander, arsenal, rmarkdown, DT, - covr, + covr, shinythemes, stats, Hmisc, @@ -30,9 +32,11 @@ Suggests: tableone, cardx, stats, - broom.helpers + broom.helpers, + testthat (>= 3.0.0) +Config/testthat/edition: 3 License: CC0 Encoding: UTF-8 -RoxygenNote: 7.3.2 -VignetteBuilder: knitr +RoxygenNote: 7.3.3 +VignetteBuilder: quarto, knitr URL: https://cida-csph.github.io/CIDAtools/ diff --git a/NAMESPACE b/NAMESPACE index 012de44..c39a0c7 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -18,14 +18,40 @@ export(convertIntervalNotation) export(create_project) export(find_nearest) export(getProjectData) +export(get_default_value) +export(get_defaults) +export(get_full_project_path) +export(get_global_default_analyst) +export(get_global_default_path) +export(get_project_analyst) +export(get_project_drive_path) +export(get_project_github) +export(get_project_location) +export(get_project_meta_data) +export(get_project_name) +export(get_project_pi) export(list_kables) export(nLevelsP) export(nrowP) +export(open_project) export(pvalr) export(randblinder_shiny_tool) export(read_xlsx_color) export(removeAnalyst) +export(remove_global_default_analyst) +export(remove_global_default_path) export(setAnalyst) +export(setPermanentAnalyst) +export(set_default_value) +export(set_full_project_path) +export(set_global_default_analyst) +export(set_global_default_path) +export(set_project_analyst) +export(set_project_github) +export(set_project_location) +export(set_project_meta_data) +export(set_project_name) +export(set_project_pi) export(sum_ignore_NA) export(vec_power) import(flextable) @@ -41,3 +67,4 @@ importFrom(stats,wilcox.test) importFrom(table1,stats.apply.rounding) importFrom(table1,stats.default) importFrom(table1,table1) +importFrom(utils,head) diff --git a/NEWS.md b/NEWS.qmd similarity index 68% rename from NEWS.md rename to NEWS.qmd index ba3b7b5..0cd882b 100644 --- a/NEWS.md +++ b/NEWS.qmd @@ -1,3 +1,11 @@ +--- +title: "CIDATools - News" +format: html +--- +# 0.2.0 +- Refactored most functions to use consistent camelCase naming conventions +- Deprecated some unused/unsupported functions (if you encounter a deprecated function which you are actively using, please email CIDA-RT@olucdenver.onmicrosoft.com) + # 0.1.1 - Data only argument implemented diff --git a/R/backup_project.R b/R/backup_project.R deleted file mode 100644 index 1c512f1..0000000 --- a/R/backup_project.R +++ /dev/null @@ -1,176 +0,0 @@ -#'Backup Project Directory -#' -#'This function backs up a CIDA project to the shared (P) CIDA drive. The backup directory -#'can either be existing (in which only changed files/folders are updated), or -#'nonexisting, in which case a full project backup is created. -#' -#'@param path_from Path from where the folders should be copied (project -#' directory location). -#'@param path_to Path to where the folders should be copied (P drive, only used -#' if specified). -#'@param exclude files/folders NOT to be backed up to the P-drive (useful for -#'larger files that don't change often). Currently not used. -#'@param recreate should backup be created from the ground up? -#' (can take longer, but useful for projects with many changes) -#' @param data_only should only subdirs including "data" (DataRaw/ and DataProcessed/) be backed up? -#' @param readme forces backup of project readme -#' @return This function has verbose output to ensure the back up is working, and -#' ultimately returns a success indicator that's returned by file.copy. -#' -#'@export -backup_project <- function(path_from = getwd(), - path_to = NULL, - exclude = c(".DS_Store", ".Rproj.user", ".git"), - recreate = FALSE, - data_only = TRUE, - readme = TRUE) { - - # Check args, make into absolute paths - path_from <- normalizePath(path_from) - - # Get proper path to Shared drive - if(missing(path_to)) { - - path_to <- ProjectLocation() - if(path_to == "") - stop("Please first set project location, e.g., CIDAtools::SetProjectLocation('Branches/EmergencyMedicine/ThisProject')") - - if(!dir.exists(CIDAtools::CIDA_drive_path())) - stop("Please ensure the CIDA drive is mounted, or set `path_to`") - - } - - path_to <- normalizePath(path_to) - - ## Check if specific project folder exists on P drive - backup_path <- file.path(path_to) - if(!dir.exists(backup_path)) { - message("Note: '", backup_path, "' not found; directory was created.") - dir.create(backup_path) - } else if (!recreate){ - message("Note: backup path already exists, and will be updated unless cancelled.") - message("Backup path:\n", backup_path, - "\nProject path:\n", - path_from) - } else { - message("Note: backup path already exists, and will be completely overwritten since recreate == TRUE.") - message("Backup path:\n", backup_path, - "\nProject path:\n", - path_from, "\n\nType 'yes' to confirm.") - delete_old <- readline() - - if(delete_old != "yes") - stop("Cancelled") - unlink(backup_path, recursive=TRUE) - dir.create(backup_path) - } - - message("\nDetermining current backup situation...") - - files_to_copy <- - list.files(path_from, recursive = T, all.files = T) - dirs_to_copy <- list.dirs(path_from, recursive = T, full.names = F)[-1] - - if(length(exclude)) { - files_to_exclude <- c( - unlist(sapply(exclude[dir.exists(exclude)], list.files, recursive = TRUE, - all = TRUE, full.names = T)), - exclude[!dir.exists(exclude)]) - - files_to_copy <- files_to_copy[!(files_to_copy %in% files_to_exclude)] - - dirs_to_exclude <- c( - unlist(sapply(exclude[dir.exists(exclude)], list.dirs, recursive = TRUE, - full.names = T))) - - dirs_to_copy <- dirs_to_copy[!(dirs_to_copy %in% dirs_to_exclude)] - } - - if(data_only) { - string_matches <- "dataraw|dataprocessed" - if(readme) - string_matches <- "readme|dataraw|dataprocessed" - - # find large files (>= 250 MB) - large_idx <- file.size(files_to_copy)/1e6 >= 250 - - # find file matches - file_matches <- grepl(string_matches, files_to_copy, ignore.case = TRUE) - dir_matches <- grepl(string_matches, dirs_to_copy, ignore.case = TRUE) - - files_to_copy <- files_to_copy[large_idx | file_matches] - dirs_to_copy <- dirs_to_copy[large_idx | dir_matches] - } - - ## Check if any files can be ignored using time last modified time - check <- file.exists(file.path(backup_path, files_to_copy)) - if(any(check)) { - to_mtime <- file.mtime(file.path(backup_path, files_to_copy)) - - # If no file found, set last modified time into future (kind of a hack) - to_mtime[is.na(to_mtime)] <- Sys.time() +500 - - from_mtime <- file.mtime(file.path(path_from, files_to_copy)) - files_to_copy <- files_to_copy[abs(difftime(to_mtime, from_mtime, units = "secs")) > 1] - } - - # Check and don't copy dirs if they already exist - dirs_to_copy <- dirs_to_copy[!dir.exists(file.path(backup_path, dirs_to_copy))] - - message("\nI'm about to create or update ",length(dirs_to_copy)," subdirectories and ", - length(files_to_copy), " files.", - "'\nType 'yes' to confirm, or 'list' to list changes.") - val <- readline() - if(val == "list") { - cat("Subdirs:", dirs_to_copy, sep = "\n") - cat("\n\nFiles:", files_to_copy, sep = "\n") - message("'\n\n Type 'yes' to confirm.") - val <- readline() - } - - stopifnot(val == "yes") - - if(length(dirs_to_copy)) { - message("Creating ", length(dirs_to_copy)," subdirectories...") - pb <- dplyr::progress_estimated(length(dirs_to_copy)) - r1 <- sapply(1:length(dirs_to_copy), function(i) { - pb$tick()$print() - dir.create(file.path(backup_path, dirs_to_copy[i])) - }) - } else - r1 <- T - - if(length(files_to_copy)) { - message("\nCopying/updating ", length(files_to_copy), " files...") - pb <- dplyr::progress_estimated(length(files_to_copy)) - r2 <- sapply(1:length(files_to_copy), function(i) { - pb$tick()$print() - file.copy(file.path(path_from, files_to_copy[i]), - file.path(backup_path, files_to_copy[i]), - overwrite = TRUE, copy.date = TRUE) - - }) - } else - r2 <- T - - result <- all(r1) & all(r2) - create_backup_info(backup_path) - - return(invisible(result)) -} - -create_backup_info <- function(path) { - fileConn<- file(file.path(path, "backup_info.md")) - lines <- c( - "This is a backup of the actual project directory. ", - "", - "DO NOT EDIT THIS DIRECTORY.", - "", - "If you do, changes may be overwritten by future backups.", - "", - paste0("This directory was last backed up at ", Sys.time()), - "" - ) - writeLines(lines, fileConn) - close(fileConn) -} diff --git a/R/cida_drive_path.R b/R/cida_drive_path.R deleted file mode 100644 index fc468e4..0000000 --- a/R/cida_drive_path.R +++ /dev/null @@ -1,71 +0,0 @@ -#' Get CIDA drive path -#' -#' This function attempts to get the proper path for the CIDA drive either on -#' Windows or Mac. -#' -#' @param file (optional) Path to subdirectory/file within CIDA drive -#' -#' @return Full (absolute) file path of CIDA drive -#' @export -#' -#' @examples -#' # Read data from P1234PIname project -#' \dontrun{ -#' df <- read.csv(CIDA_drive_path("BRANCHES/Pulmonary/P1234PIname/DataRaw/data.csv")) -#' } -#' - -CIDA_drive_path <- function(file = "") { - - # Get operating system (note that MacOS and Linux return unix) - os <- .Platform$OS.type - - if (os == "unix") { # MacOS/Linux - - # Two potential places drive could exist - if (dir.exists("/Volumes/sph-cida")) { - path <- "/Volumes/sph-cida" - } else { - stop("Nothing found at /Volumes/sph-cida.", - " Please ensure drive is mounted and you have entered your", - " password to access the drive (and are logged into the VPN if", - " needed.)") - } - - } else if (os == "windows") { # Windows - - # Only one spot drive can be mounted for Windows - if (dir.exists("P:/")) { - path <- "P:/" - } else { - stop("Nothing found at P:/.", - " Please ensure drive is mounted and you have entered your", - " password to access the drive (and are logged into the VPN if", - " needed.)") - } - - - } else { - - stop("Operating system could not be identified") - - } - - # Combine CIDA drive path with user provided subdirectory/file - file_path <- file.path(path, file) - - # Check if full path exists (first as file, second as directory) - if (!dir.exists(file_path) & !file.exists(file_path)) { - - # TODO: consider adding function to search for partial paths and suggest - # alternatives - - stop("Nothing found at path ", file_path, - "\nCheck spelling of path, and ensure drive is mounted and you have", - " entered your password to access the drive (and are logged into the", - " VPN if needed.)") - } - - # Return full path - return(file_path) -} diff --git a/R/cida_table1.R b/R/cida_table1.R index c99678b..e9b30c6 100644 --- a/R/cida_table1.R +++ b/R/cida_table1.R @@ -1,4 +1,4 @@ -#' Create a table one +#' Create a table one - To be deprecated #' #' #' This is a function created to provide characteristics of a study group with @@ -155,6 +155,8 @@ cida_table1 <- function(data, useSciNotation = FALSE ) { + deprecation_warn("cida_table1.cida_table1") + # Check variables are in provided data if (any(!(includeVars %in% colnames(data))) & if (!is.null(names(includeVars))) { @@ -493,7 +495,7 @@ cida_table1 <- function(data, } } -#' Internal function for p-value calculation in cida_table1 +#' Internal function for p-value calculation in cida_table1 - To be deprecated #' #' @param x the row_variable #' @param name the variables name @@ -512,6 +514,7 @@ pvalue <- function(x, include_total = include_total, nonParametricVars = nonParametricVars) { + deprecation_warn("cida_table1.pvalue") # Construct vectors of data y, and groups (strata) g if (isTRUE(include_total)) { diff --git a/R/create_project.R b/R/create_project.R deleted file mode 100644 index 17342cc..0000000 --- a/R/create_project.R +++ /dev/null @@ -1,284 +0,0 @@ -#'Create Project Directory + readme files -#' -#'This function creates the standard project organization structure for CIDA -#'within a folder that already exists. -#' -#'@param path Where should they be created? Default is the working directory. -#'@param template Which subdirectories to create -#'@param ProjectName Name of project, or "" for blank -#'@param PI Name of PI and credentials, or "" for blank -#'@param analyst Name of Analyst(s), or "" for blank -#'@param datalocation Location of project on CIDA Drive, or "" for blank -#'@param gitlocation Location project on GitHub -#'@return This function creates the desired project subdirectories and readmes, -#' as well as a standard .gitignore file files. It will not overwrite the file -#' however if it does not exist. It does not return anything. -#'@keywords project createproject -#' -#'@seealso proj_setup() is the internal wrapper for this that gets called when -#' using the RStudio GUI to create a project -#' -#'@export -create_project <- function(path = getwd(), - template = c('Admin', 'Background', 'Code', 'DataRaw', - 'DataProcessed', 'Dissemination', 'Reports'), - ProjectName = "", PI = "", analyst = "", datalocation = "", - gitlocation = "") { - - if(!dir.exists(path)) - dir.create(path, recursive = TRUE, showWarnings = FALSE) - - # has meta been provided? - meta <- !all(c(ProjectName, PI, analyst, datalocation) %in% "") - - # set which ReadMe.md files to create - template <- match.arg(template, several.ok = T) - - # Overall readme - - readme <- c(paste0("**Project Name**: ", ProjectName, " "), - paste0("**PI**: ", PI, " "), - paste0("**Analyst**: ", analyst, " "), - paste0("**CIDA drive Location**: ", proj.location.handler(datalocation), " "), - paste0("**GitHub Location**: ", gitlocation, " "), - "", - "Details about the folders:", - '', - "File | Description", - "---|----------------------------------------------------------", - paste("Admin | contains the scope of work and other", - "administrative documents"), - paste("Background | contains the background information for", - "the analysis"), - "Code | contains all R scripts for this project", - "DataRaw | contain all raw data provided by investigators", - "DataProcessed | contains the processed data used for analysis", - paste("Dissemination | contains any materials produced for", - "dissemination, ie. Abstracts, Posters, Papers"), - "Reports | contains all output, rmarkdown files and report") - - - # write to readme file - if(!file.exists(file.path(path, "ReadMe.md"))) - writeLines(paste0(readme, collapse = '\n'), - con = file.path(path, "ReadMe.md")) - - # Create subdirectory readmes - create_readme(template = template, path = path) - - # Add .ProjData directory containing metadata - if(meta){ - dir.create(paste0(path, '/.ProjData')) - ProjData <- list(ProjectName = ProjectName, PI = PI, - analyst = analyst, datalocation = datalocation, - gitlocation = gitlocation) - write.dcf(ProjData, file.path(path, '/.ProjData/Data.dcf')) - } - - # add to current gitignore if exists - if(file.exists(file.path(path, '.gitignore'))){ - gitignore <- readLines(con = file.path(path, '.gitignore')) - } else { - gitignore <- NULL - } - - # add R template gitignore - # (source: https://github.com/github/gitignore/blob/master/R.gitignore) - gitignore <- paste0(c(gitignore, - "# History files", - ".Rhistory", - ".Rapp.history", - - "# Session Data files", - ".RData", - - "# User-specific files", - ".Ruserdata", - - "# Example code in package build process", - "*-Ex.R", - - "# Output files from R CMD build", - "/*.tar.gz", - - "# Output files from R CMD check", - "/*.Rcheck/", - - "# RStudio files", - ".Rproj.user/", - - "# produced vignettes", - "vignettes/*.html", - "vignettes/*.pdf", - - paste0("# OAuth2 token, see https://github.com/", - "hadley/httr/releases/tag/v0.3"), - ".httr-oauth", - - "# knitr and R markdown default cache directories", - "/*_cache/", - "/cache/", - - "# Temporary files created by R markdown", - "*.utf8.md", - "*.knit.md"), collapse = '\n') - - # by file type - gitignore <- paste0(c(gitignore, - "# R Data files", - "*.RData", - "*.rda", - "*.rdata", - "*.rda", - "# Text files", - "*.csv", - "*.txt", - "*.dat", - "# Excel", - "*.xls*", - "# SAS", - "*.sas7bdat", - "*.xport", - "# Access", - "*.mdb"), collapse = '\n') - - # by Folder - gitignore <- paste0(c(gitignore, - "DataRaw/*", - "DataProcessed/*", - "!*/ReadMe.md"), collapse = '\n') - - writeLines(gitignore, con = file.path(path, '.gitignore')) - - # Create .Rproj file - rproj <- paste0(c("Version: 1.0", - "", - "RestoreWorkspace: Default", - "SaveWorkspace: Default", - "AlwaysSaveHistory: Default", - "", - "EnableCodeIndexing: Yes", - "UseSpacesForTab: Yes", - "NumSpacesForTab: 2", - "Encoding: UTF-8", - "", - "RnwWeave: knitr", - "LaTeX: pdfLaTeX"), collapse = "\n") - - if(!file.exists(file.path(path, paste0(basename(path), ".Rproj")))) - writeLines(rproj, con = file.path(path, paste0(basename(path), ".Rproj"))) - - ## Copy over SOW - message("Project created. Please remember to copy the scope of work to to Admin/ subdirectory.") - - invisible(template) -} - -proj_setup <- function(path, ...){ - # ensure path exists - dots <- list(...) - ProjectName <- paste0(path) - - create_project(path, ProjectName = paste0(path), PI = dots$PI, - analyst = dots$analyst, datalocation = dots$datalocation, - gitlocation = dots$gitlocation) - - # for project info - dir.create(paste0(path, '/.ProjData')) - ProjData <- list(ProjectName = ProjectName, PI = dots$PI, - analyst = dots$analyst, datalocation = dots$datalocation, - gitlocation = dots$gitlocation) - write.dcf(ProjData, file.path(path, '/.ProjData/Data.dcf')) - -} - -create_readme <- function(template = c('Admin', 'Background', 'Code', 'DataRaw', - 'DataProcessed', 'Dissemination', - 'Reports'), path = getwd()){ - # set which ReadMe.md files to create - template <- match.arg(template, several.ok = T) - - # create list with lines for each template - readme <- list() - - readme$Admin <- c("# Admin ", - " ", - "This folder contains the scope of work and other relevant files from CIDA admin. ", - " ", - "Details about the files: ", - " ", - "File | Description", - "---|---------------------------------------------------------------------", - " ", - "") - readme$Background <- c("# Background ", - " ", - "This folder contains documents provided by investigators and the data analysis plan. ", - " ", - "Details about the files: ", - " ", - "File | Description", - "---|---------------------------------------------------------------------", - " ") - readme$Code <- c("This folder contains all the code. ", - " ", - "Details about the files in this folder:", - " ", - "File | Description", - "---|---------------------------------------------------------------------", - " ") - readme$DataProcessed <- c("# Processed Data ", - " ", - "Scripts that created the files in this folder: ", - " ", - "File | Script | Description", - "---|------------------|---------------------------------------------------", - " ") - readme$DataRaw <- c("# Raw Data", - " ", - "Details about the files: ", - " ", - "File | Details", - "---|---------------------------------------------------------------------", - " ", - " ") - - readme$Dissemination <- c("# Dissemination", - " ", - "This folder contains abstracts, posters, papers and anything else produced for dissemination. ", - " ", - "Details about the files: ", - " ", - "File | Description", - "---|---------------------------------------------------------------------", - " ", - " ") - readme$Reports <- c("# Reports", - " ", - "This folder contains the rmarkdown scripts and pdf output of reports. ", - " ", - "Details about the files: ", - " ", - "File | Description", - "---|---------------------------------------------------------------------", - " ") - - # Function for creating the directory - createDir <- function(x){ - paste0(path, '/', x) - } - - createFiles <- function(x){ - file.path(path, paste0(x, '/ReadMe.md')) - } - - readme <- readme[template] - - pathnames <- sapply(names(readme), createDir) - dir_created <- lapply(pathnames, dir.create, showWarnings = F, recursive = T) - con <- lapply(names(readme), createFiles) - doNotOverwrite <- sapply(con, file.exists) - readme <- readme[!doNotOverwrite] - con <- con[!doNotOverwrite] - files_created <- mapply(writeLines, lapply(readme, paste0, collapse = '\n'), con) -} diff --git a/R/default.R b/R/default.R new file mode 100644 index 0000000..5fceb98 --- /dev/null +++ b/R/default.R @@ -0,0 +1,272 @@ +#' Set Global Default Analyst Value +#' +#' +#' This function allows you to set the default analyst at the user level and +#' if possible changes the default analyst in the template for new projects. +#' +#' @param analyst_name A string containing the analyst name +#' @param update_template Bool whether or not to update analyst in the project template. +#' @return A message stating the name has been changed. +#' @keywords options Analyst +#' @export +#' +set_global_default_analyst <- function(analyst_name,update_template=FALSE){ + analyst_name <- check_string_param_value(analyst_name,'analyst_name') + # Save to user cida_defaults.dcf + set_default_value('analyst_name',analyst_name) + + # Save to project templates + if(update_template){ + set_template_analyst(analyst_name) + } + return(paste('The default analyst name has been changed to', + analyst_name)) +} + +#' Get Default Analyst Value +#' +#' +#' This function allows you to get the default analyst. +#' +#' @return The default analyst or an empty string if not set. +#' @keywords options Analyst +#' @export +#' +get_global_default_analyst <- function(){ + value <- get_default_value('analyst_name') + return(value) +} + + + +#' Remove Default Analyst from ~/cida_defaults.dcf +#' +#' This function removes the default analyst set with set_global_default_analyst() +#' from the users ~/cida_defaults.dcf. +#' +#' +#' @return Message indicating success or failure +#' @keywords Analyst remove +#' @export +#' +#' +remove_global_default_analyst <- function(){ + to_save <- NULL + defaults <- read_global_defaults() + msg <- "" + if(!is.null(defaults)){ + to_save <- list() + for (element in names(defaults)) { + if(element!="analyst_name"){ + to_save[element]=defaults[element] + } + } + write_global_defaults(to_save) + msg <- paste('The default analyst has been removed.') + }else{ + warning("Analyst not removed: global default file not found.") + msg <- paste("Analyst not removed: global default file not found.") + } + return(msg) +} + + + +#' Sets a default drive path in ~/cida_defaults.dcf +#' +#' This function sets a default path at the user level to access the project +#' drive. If the drive is not detected automatically this file will be used to +#' set a default path if set. +#' +#' @param path Path to the main project(CIDA) drive +#' +#' @return Message that path was set. +#' @export +#' +set_global_default_path <- function(path=""){ + path <- check_string_param_value(path,'global_default_path') + set_default_value('path',path) + return(paste('The default project path has been changed to',path)) +} + +#' removes the default drive path in ~/cida_defaults.dcf +#' +#' This function removed the default path at the user level to access the project +#' drive. +#' +#' @export +#' +remove_global_default_path <- function(){ + set_default_value('path',"") +} + + +#' Get Default drive path +#' +#' +#' This function returns the user level default drive path set in ~/cida_defaults.dcf +#' +#' @return The default path +#' @keywords options path +#' @export +#' +get_global_default_path <- function(){ + path <- '' + path <- get_default_value('path') + return(path) +} + +#' Sets a default parameter in ~/cida_defaults.dcf +#' +#' This function sets a default parameter at the user level. +#' +#' @param parameter parameter name +#' @param value new value +#' +#' +#' @export +#' +set_default_value <- function(parameter,value){ + defaults <- get_defaults() + if(parameter %in% names(defaults)){ + defaults[parameter] <- value + }else{ + defaults[parameter] <- value + } + save_global_defaults(defaults) +} + +#' Get a specific user level default +#' +#' +#' This function returns a specific user level defaults set in ~/cida_defaults.dcf +#' +#' @param parameter The name of the specific parameter to lookup. +#' @return The user level defaults named parameter +#' @keywords options path +#' @export +#' +get_default_value <- function(parameter){ + default_value <- "" + defaults <- get_defaults() + if( parameter %in% names(defaults)){ + default_value <- defaults[parameter][1,1] + }else{ + warning("Parameter:",parameter," does not exist in default values.\n") + } + return(default_value) +} + + +#' Get a list of all user level defaults +#' +#' +#' This function returns the user level defaults set in ~/cida_defaults.dcf +#' +#' @return The user level defaults +#' @keywords options path +#' @export +#' +get_defaults <- function(){ + default_values <- NULL + + tmp <- read_global_defaults() + if(!is.null(tmp)){ + default_values <- tmp + } + return(default_values) +} + +#' Get CIDA Defaults read from ~/cida_defaults.dcf +#' Use fs to get a cross platform path to the user directory to store +#' cida_defaults.dcf then read cida_defaults.dcf and return the object. +#' +#' @returns the default object stored in cida_defaults.dcf +#' +#' @noRd +#' @noMd +#' +read_global_defaults <- function(){ + default <- NULL + + home_dir <- fs::path_home() + + path <-fs::path_join(c(home_dir,"/cida_defaults.dcf")) + + if(file.exists(file.path(path))){ + default <- read.dcf(file.path(path), all = T) + }else{ + warning("~/cida_defaults.dcf at full path:",path," does not exist.\nNothing was loaded.") + } + + return(default) +} + +#' Write global defaults to ~/cida_defaults.dcf +#' Use fs to get a cross platform path to the user directory to store +#' cida_defaults.dcf then write cida_defaults.dcf. +#' +#' @returns bool for success or failure +#' +#' @noRd +#' @noMd +#' + +write_global_defaults <- function( defaults_to_write){ + home_dir <- fs::path_home() + path <-fs::path_join(c(home_dir,"/cida_defaults.dcf")) + write.dcf(defaults_to_write, file.path(path)) + + return(TRUE) +} + +#' Save CIDA Defaults to ~/cida_defaults.dcf +#' +#' Use fs to get a cross platform path to the user directory to store +#' cida_defaults.dcf then save cida_defaults.dcf avoids inadvertent removal of +#' default values by first reading in the file, then overwriting the values provided, +#' preserving any not specified. To remove default values use remove_global_default(). +#' +#' @param new_default a list of new default values +#' +#' @noRd +#' @noMd +#' +save_global_defaults<- function(new_default){ + to_save <- NULL + + defaults <- read_global_defaults() + if(!is.null(defaults) ){ + to_save <- defaults + for (element in names(new_default)) { + to_save[element]=new_default[element] + } + }else{ + to_save <- new_default + } + write_global_defaults(to_save) +} + + +#' Save template analyst to CIDA project template +#' +#' Save analyst to the CIDA project template for new projects. +#' +#' @param analyst_name Name of the default analyst for new projects. +#' +#' @noRd +#' @noMd +#' + +set_template_analyst <- function(analyst_name=""){ + site_path = R.home(component = "home") + project_setup <- paste0(site_path, + '/library/CIDAtools/rstudio/', + 'templates/project/proj_setup.dcf') + if(file.access(project_setup, 2) == -1) + stop(paste0('You do not have permission to change\n', + 'New CIDA Project Template')) + DCF <- read.dcf(file.path(project_setup), all = T) + DCF$Default[DCF$Parameter == 'analyst' & !is.na(DCF$Parameter)] <- analyst_name + write.dcf(DCF, file.path(project_setup)) +} diff --git a/R/find_nearest.R b/R/find_nearest.R index 4814c8d..4a540a1 100644 --- a/R/find_nearest.R +++ b/R/find_nearest.R @@ -1,4 +1,4 @@ -#' Find the nearest observation to another observation +#' Find the nearest observation to another observation - To be deprecated #' #' #' This function finds the nearest y to every x. Y's may be duplicated. @@ -21,6 +21,9 @@ find_nearest <- function(x, y, direction = c('both', 'ascending', 'descending'), returnIndex = FALSE) { + + deprecation_warn("find_nearest.find_nearest") + direction <- match.arg(direction) a <- switch(direction, both = T, ascending = T, descending = F) d <- switch(direction, both = T, ascending = F, descending = T) @@ -59,7 +62,7 @@ find_nearest <- function(x, y, -#' Internal function for find_nearest +#' Internal function for find_nearest - To be deprecated #' #' #' @param x first value @@ -69,6 +72,9 @@ find_nearest <- function(x, y, #' @describeIn find_nearest function for finding lower(upper) value getlower <- function(x, y, upper = FALSE){ + + deprecation_warn("find_nearest.getlower") + n <- length(y) z <- c(y, x) j <- i <- order(z, decreasing = upper) diff --git a/R/misc_fns.R b/R/misc_fns.R index 34c7549..82cbbd5 100644 --- a/R/misc_fns.R +++ b/R/misc_fns.R @@ -1,45 +1,6 @@ -#' Set Default Analyst Value -#' -#' -#' This function allows you to set the option CIDAtools.analyst permanently -#' (until you change it or reinstall CIDAtools) and will -#' simultanesouly change the default in New Cida Project Template. -#' -#' @param AnalystName A string containing the analyst name -#' @return A message stating the name has been changed. -#' @keywords options Analyst -#' @export -#' -setAnalyst <- function(AnalystName){ - if(!is.character(AnalystName)) stop('Analyst Name must be a character string') - if(length(AnalystName) > 1) { - warning('Only First String is Used') - AnalystName <- AnalystName[1] - } - AnalErr <- try(setPermanentAnalyst(AnalystName), silent = T) - msg1 <- NULL - if(!is.null(AnalErr)) msg1 <- paste0('Default Analyst can not be ', - 'saved permanently.\n', - 'You will need to set for each ', - 'R session.\n') - site_path = R.home(component = "home") - Project_setup <- paste0(site_path, - '/library/CIDAtools/rstudio/', - 'templates/project/proj_setup.dcf') - if(file.access(Project_setup, 2) == -1) - stop(paste0(msg1, - 'You do not have permission to change\n', - 'New CIDA Project Template')) - DCF <- read.dcf(file.path(Project_setup), all = T) - DCF$Default[DCF$Parameter == 'analyst' & - !is.na(DCF$Parameter)] <- AnalystName - write.dcf(DCF, file.path(Project_setup)) - return(paste('The default analyst name has been changed to', - getOption('CIDAtools.analyst'))) -} -#' Get pretty numbers of rows +#' Get pretty numbers of rows - To be deprecated #' #' #' Retrieve the number of rows in dataframe of matrix with commas inserted for @@ -54,10 +15,11 @@ setAnalyst <- function(AnalystName){ nrowP <- function(x){ + deprecation_warn("misc_fns.nrowP") format(nrow(x), big.mark = ',', trim = T) } -#' Get pretty number of levels +#' Get pretty number of levels - To be deprecated #' #' #' Just a wrapper for format(nlevels) with big.mark = , and trim = T @@ -69,75 +31,13 @@ nrowP <- function(x){ #' nLevelsP <- function(x){ + deprecation_warn("misc_fns.nLevelsP") format(nlevels(x), big.mark = ',', trim = T) } -#' Set Default Analyst Value -#' -#' -#' This is an internal function that writes the Default Analyst name to the -#' users Rprofile. -#' -#' @param Name A string containing the analyst name -#' -setPermanentAnalyst <- function(Name){ - options(CIDAtools.analyst = Name) - fname = file.path("~/.Rprofile") - opts <- character() - if(file.exists(fname)){ - opts <- readLines(fname) - } - opts[grep('options\\(CIDAtools.analyst = ', opts, invert = T)] -> opts - opts <- c(opts, paste0("options(CIDAtools.analyst = '", - paste0(Name), "')")) - if(!file.create(fname, showWarnings = F)) - stop() - writeLines(opts, fname) -} -#' Remove Default Analyst from ~/.Rprofile -#' -#' This function removes the default analyst set with setAnalyst() from the users -#' .Rprofile. If this is the only entry in .Rprofile it will remove the file as well. -#' -#' @param quiet should a message indicating result be returned, if TRUE will only -#' return TRUE or FALSE -#' -#' @return Message indicating sucess or failue -#' @keywords Analyst remove -#' @export -#' -#' -removeAnalyst <- function(quiet = F){ - fname = file.path("~/.Rprofile") - if(file.access(fname, 4) != 0){ - if(!quiet){ - return('User does not have an Rprofile or Rprofile can not be read') - } - return(FALSE) - } - opts <- readLines(fname) - opts[grep('options\\(CIDAtools.analyst = ', opts, invert = T)] -> opts - if(file.access(fname, 2) != 0){ - if(!quiet){ - return('You do not have permission to write to users Rprofile') - } - return(FALSE) - } - if(length(opts) == 0){ - file.remove(fname) - if(!quiet){ - return('Users .Rprofile is empty and was deleted') - } - return(TRUE) - } - writeLines(opts, fname) - if(!quiet) - return('options(CIDAtools.analyst) has been removed from users profile') - return(TRUE) -} -#' Convert Interval Notation +#' Convert Interval Notation - To be deprecated #' #' Converts a vector from Interval Notation to less than equal to, less than, #' etc. @@ -149,6 +49,7 @@ removeAnalyst <- function(quiet = F){ #' @export #' convertIntervalNotation <- function(x){ + deprecation_warn("misc_fns.convertIntervalNotation") if(!is.character(x)) stop('x must be a character vector') x <- gsub('\\(-Inf, ', '', x) x <- gsub(',Inf\\)', '', x) @@ -160,7 +61,7 @@ convertIntervalNotation <- function(x){ return(x) } -#' Round and don't drop trailing zeros +#' Round and don't drop trailing zeros - To be deprecated #' #' Shorter wrapper for format(x, digits = n, nsmall = n) #' @@ -178,10 +79,11 @@ convertIntervalNotation <- function(x){ #' #' Round <- function(x, n){ + deprecation_warn("misc_fns.Round") format(x, digits = n, nsmall = n) } -#' Sum ignoring NAs +#' Sum ignoring NAs - To be deprecated #' #' Will sum values returning NA only if all values are NA, otherise will ignore #' @@ -213,6 +115,7 @@ Round <- function(x, n){ sum_ignore_NA <- function(...){ + deprecation_warn("misc_fns.sum_ignore_NA") arguments <- list(...) arguments <- lapply(arguments, unlist) x <- sapply(arguments, length) @@ -226,7 +129,7 @@ sum_ignore_NA <- function(...){ }) } -#' Vectorized power estimates +#' Vectorized power estimates - To be deprecated #' #' #' This function allows you to use power.t.test, power.prop.test, etc in @@ -253,7 +156,7 @@ sum_ignore_NA <- function(...){ #' vec_power <- function(fun = stats::power.t.test, ...){ - + deprecation_warn("misc_fns.vec_power") args <- list(...) params <- expand.grid(args, stringsAsFactors = FALSE)[,length(args):1] @@ -270,17 +173,14 @@ vec_power <- function(fun = stats::power.t.test, ...){ return(na.omit(results)) } -# Helper for pwr package version of power fns. +#' Helper for pwr package version of power fns. - To be deprecated +#' @param x description +#' @param ... description +#' tidy.power.htest <- function(x, ...) { + deprecation_warn("misc_fns.tidy.power.htest") class(x) <- "list" as.data.frame(x) } -# helper function to cleanup project location -proj.location.handler <- function(loc="") { - loc <- gsub("/Volumes/sph-cida", "", loc) - loc <- gsub("P:/", "", loc) - loc <- gsub(".*BRANCHES", "BRANCHES", loc) - loc <- gsub("/$", "", loc) - return(loc) -} + diff --git a/R/project.R b/R/project.R new file mode 100644 index 0000000..492d0ba --- /dev/null +++ b/R/project.R @@ -0,0 +1,649 @@ +#' Get Project drive path +#' +#' This function attempts to get the proper path for the Project(CIDA) drive either on +#' Windows or Mac automatically. It returns the full CIDA drive(remote) path +#' with the relative path (if provided) appended to the drive path. +#' +#' If open_project() has been called with a remote path specified the remote path +#' will be used first. +#' +#' If that is not set it will try to determine the drive path. If the expected +#' path is not found it will try to load the project metadata path and if that +#' fails it looks for a global default path in the user cida_defaults.dcf file. +#' +#' @param file (optional) Path to subdirectory/file within the main project(CIDA) drive +#' +#' @return Full (absolute) file path of project(CIDA) drive plus the subdirectory/file provided. +#' @export +#' +#' @examples +#' # Read data from P1234PIname project +#' \dontrun{ +#' df <- read.csv(get_project_drive_path("BRANCHES/Pulmonary/P1234PIname/DataRaw/data.csv")) +#' } +#' + +get_project_drive_path <- function(file = "") { + path <- "" + if(options("cida_tools.remote_current_project_path") != ""){ + #get project path + path <- options("cida_tools.remote_current_project_path") + #remove everything after BRANCHES + path <- sub("/BRANCHES.*","",path) + }else{ + # Get operating system (note that MacOS and Linux return unix) + os <- .Platform$OS.type + + + ## TODO Set a global default path somewhere and then iterativly parse each + # sub-directory to test instead of these static sub-directories of the CIDA path + + if (os == "unix") { # MacOS/Linux + + # Four potential places drive could exist based on path used for mapping + # and case sensitivity of the file system + # Then check manually set project data in .ProjData/Data.dcf + if (dir.exists("/Volumes/sph-cida/BRANCHES")) { + path <- "/Volumes/sph-cida/BRANCHES" + } else if(dir.exists("/Volumes/branches")){ + path <- "/Volumes/branches" + }else if(dir.exists("/Volumes/sph/SPH-CIDA/BRANCHES")){ + path <- "/Volumes/sph/SPH-CIDA/BRANCHES" + }else if(dir.exists("/Volumes/dept")){ + path <- "/Volumes/dept/SPH/SPH-CIDA/BRANCHES" + }else if (dir.exists("/Volumes/SPH-CIDA")) { + path <- "/Volumes/SPH-CIDA/BRANCHES" + }else if(dir.exists("/Volumes/SPH")){ + path <- "/Volumes/SPH/SPH-CIDA/BRANCHES" + }else if(dir.exists("/Volumes/DEPT")){ + path <- "/Volumes/DEPT/SPH/SPH-CIDA/BRANCHES" + }else { + path <- get_default_path() + if(path==""){ + stop("Nothing found at /Volumes/dept || SPH || SPH-CIDA || BRANCHES", + " Please ensure drive is mounted and you have entered your", + " password to access the drive (and are logged into the VPN if", + " needed.)", + " If still experiencing issues try set_project_data_path() or ", + " set_global_default_path()" + ) + }else{ + if(! dir.exists(path)){ + stop("Automatic Path: Failed\nDefault Path:",path,": Failed\n", + " If still experiencing issues try set_project_data_path() or ", + " set_global_default_path()") + } + } + } + + } else if (os == "windows") { # Windows + + # Only one spot drive can be mounted for Windows + if (dir.exists("P:/")) { + path <- "P:/" + if(dir.exists("P:/dept/SPH/SPH-CIDA/BRANCHES")){ + path <- "P:/dept/SPH/SPH-CIDA/BRANCHES" + }else if(dir.exists("P:/SPH/SPH-CIDA/BRANCHES")){ + path <- "P:/SPH/SPH-CIDA/BRANCHES" + }else if(dir.exists("P:/SPH-CIDA/BRANCHES")){ + path <- "P:/SPH-CIDA/BRANCHES" + }else if(dir.exists("P:/BRANCHES")){ + path <- "P:/BRANCHES" + } + }else { + path <- get_default_path() + if(path==""){ + stop("Nothing found at P:/.", + " Please ensure drive is mounted and you have entered your", + " password to access the drive (and are logged into the VPN if", + " needed.)", + " If still experiencing issues try set_project_data_path() or ", + " set_global_default_path()" + ) + }else{ + if(! dir.exists(path)){ + stop("Automatic Path: Failed\nDefault Path:",path,": Failed (does not exist)\n", + " If still experiencing issues try set_project_data_path() or ", + " set_global_default_path()") + } + } + } + } else { + stop("Operating system could not be identified") + } + } + + # Combine CIDA drive path with user provided subdirectory/file + if(file !=""){ + file_path <- file.path(path, file) + }else{ + file_path <- path + } + + # Check if full path exists (first as file, second as directory) + if (!dir.exists(file_path) & !file.exists(file_path)) { + + # TODO: consider adding function to search for partial paths and suggest + # alternatives + + stop("Nothing found at path ", file_path, + "\nCheck spelling of path, and ensure drive is mounted and you have", + " entered your password to access the drive (and are logged into the", + " VPN if needed.)") + } + + # Return full path + return(fs::path(file_path)) +} + + + +#'Create Project Directory + readme files +#' +#'This function creates the standard project organization structure for CIDA +#'within a folder that already exists. +#' +#'@param path Where should they be created? Default is the working directory. +#'@param template Which subdirectories to create +#'@param project_name Name of project, (required) +#'@param pi Name of PI and credentials, or "" for blank +#'@param analyst Name of Analyst(s), (required) +#'@param data_location Location of project on CIDA Drive, or "" for blank +#'@param git_location Location project on GitHub +#'@return This function creates the desired project subdirectories and readmes, +#' as well as a standard .gitignore file files. It will not overwrite the file +#' however if it does not exist. It does not return anything. +#'@keywords project createproject +#' +#'@seealso proj_setup() is the internal wrapper for this that gets called when +#' using the RStudio GUI to create a project +#' +#'@export +create_project <- function(path = getwd(), + template = c('Admin', 'Background', 'Code', 'DataRaw', + 'DataProcessed', 'Dissemination', 'Reports'), + project_name, pi = "", analyst, data_location = "", + git_location = "") { + if (missing(project_name) || !nzchar(trimws(project_name))){ + stop(" 'project_name' is required and cannot be empty.", call. = FALSE) + } + if( ! dir.exists(path) ){ + dir.create(path, recursive = TRUE, showWarnings = FALSE) + } + + # has meta been provided? + # meta <- !all(c(project_name, pi, analyst, data_location,git_location) %in% "") + + + # set which ReadMe.md files to create + template <- match.arg(template, several.ok = T) + + # Overall readme + + readme <- c(paste0("**Project Name**: ", project_name, " "), + paste0("**PI**: ", pi, " "), + paste0("**Analyst**: ", analyst, " "), + paste0("**CIDA drive Location**: ", proj_location_handler(data_location), " "), + paste0("**GitHub Location**: ", git_location, " "), + "", + "Details about the folders:", + '', + "File | Description", + "---|----------------------------------------------------------", + paste("Admin | contains the scope of work and other", + "administrative documents"), + paste("Background | contains the background information for", + "the analysis"), + "Code | contains all R scripts for this project", + "DataRaw | contain all raw data provided by investigators", + "DataProcessed | contains the processed data used for analysis", + paste("Dissemination | contains any materials produced for", + "dissemination, ie. Abstracts, Posters, Papers"), + "Reports | contains all output, rmarkdown files and report") + + + # write to readme file + if(!file.exists(file.path(path, "README.md"))) + writeLines(paste0(readme, collapse = '\n'), + con = file.path(path, "README.md")) + + # Create subdirectory readmes + create_readme(template = template, path = path) + + # Add .ProjData directory containing metadata + #if(meta){ + if (! dir.exists(paste0(path, '/.ProjData'))){ + dir.create(paste0(path, '/.ProjData')) + } + proj_data <- list(ProjectName = project_name, PI = pi, + analyst = analyst, datalocation = data_location, + gitlocation = git_location) + write.dcf(proj_data, file.path(path, '/.ProjData/Data.dcf')) + #} + + # add to current gitignore if exists + if(file.exists(file.path(path, '.gitignore'))){ + gitignore <- readLines(con = file.path(path, '.gitignore')) + } else { + gitignore <- NULL + } + + # add R template gitignore + # (source: https://github.com/github/gitignore/blob/master/R.gitignore) + gitignore <- paste0(c(gitignore, + "# History files", + ".Rhistory", + ".Rapp.history", + + "# Session Data files", + ".RData", + + "# User-specific files", + ".Ruserdata", + + "# Example code in package build process", + "*-Ex.R", + + "# Output files from R CMD build", + "/*.tar.gz", + + "# Output files from R CMD check", + "/*.Rcheck/", + + "# RStudio files", + ".Rproj.user/", + + "# produced vignettes", + "vignettes/*.html", + "vignettes/*.pdf", + + paste0("# OAuth2 token, see https://github.com/", + "hadley/httr/releases/tag/v0.3"), + ".httr-oauth", + + "# knitr and R markdown default cache directories", + "/*_cache/", + "/cache/", + + "# Temporary files created by R markdown", + "*.utf8.md", + "*.knit.md"), collapse = '\n') + + # by file type + gitignore <- paste0(c(gitignore, + "# R Data files", + "*.RData", + "*.rda", + "*.rdata", + "*.rda", + "# Text files", + "*.csv", + "*.txt", + "*.dat", + "# Excel", + "*.xls*", + "# SAS", + "*.sas7bdat", + "*.xport", + "# Access", + "*.mdb"), collapse = '\n') + + # by Folder + gitignore <- paste0(c(gitignore, + "DataRaw/*", + "DataProcessed/*", + "!*/README.md"), collapse = '\n') + + writeLines(gitignore, con = file.path(path, '.gitignore')) + + # Create .Rproj file + rproj <- paste0(c("Version: 1.0", + "", + "RestoreWorkspace: Default", + "SaveWorkspace: Default", + "AlwaysSaveHistory: Default", + "", + "EnableCodeIndexing: Yes", + "UseSpacesForTab: Yes", + "NumSpacesForTab: 2", + "Encoding: UTF-8", + "", + "RnwWeave: knitr", + "LaTeX: pdfLaTeX"), collapse = "\n") + + if(!file.exists(file.path(path, paste0(basename(path), ".Rproj")))) + writeLines(rproj, con = file.path(path, paste0(basename(path), ".Rproj"))) + + # TODO: We should search for both the global (home directory) and local (project directory) .Rprofiles. + # TODO: This uses '~', is this portable to Windows (and is RProfile stored in the same place on Windows)? + rprofile <- paste0(c('if( file.exists(fs::path_expand("~/.Rprofile") ) ){', + 'source(path.expand("~/.Rprofile"))', + '}', + 'library(CIDATools)', + paste0('CIDATools::open_project(localpath="',path,'")')), + collapse="\n") + if(!file.exists(file.path(path,"/.Rprofile"))) + writeLines(rprofile, con = file.path(path,"/.Rprofile")) + + ## Copy over SOW + message("Project created. Please remember to copy the scope of work to to Admin/ subdirectory.") + + invisible(template) +} + +proj_setup <- function(path, ...){ + # ensure path exists + dots <- list(...) + project_name <- paste0(path) + analyst_val <- dots$analyst + if(is.null(analyst_val) || !nzchar(trimws(analyst_val))){ + analyst_val <- "UNKNOWN - please update with set_project_analyst()" + warning("No analyst name was provided. Please set it with", + "CIDAtools::set_project_analyst('Your Name').", + call. = FALSE) + } + create_project(path, project_name = project_name, pi = dots$PI, + analyst = analyst_val, data_location = dots$datalocation, + git_location = dots$gitlocation) + + # Commenting out as this is written in create_project. + #dir.create(paste0(path, '/.ProjData')) + #proj_data <- list(ProjectName = project_name, PI = dots$PI, + # analyst = dots$analyst, datalocation = dots$datalocation, + # gitlocation = dots$gitlocation) + #write.dcf(proj_data, file.path(path, '/.ProjData/Data.dcf')) + +} + +create_readme <- function(template = c('Admin', 'Background', 'Code', 'DataRaw', + 'DataProcessed', 'Dissemination', + 'Reports'), path = getwd()){ + # set which ReadMe.md files to create + template <- match.arg(template, several.ok = T) + + # create list with lines for each template + readme <- list() + + readme$Admin <- c("# Admin ", + " ", + "This folder contains the scope of work and other relevant files from CIDA admin. ", + " ", + "Details about the files: ", + " ", + "File | Description", + "---|---------------------------------------------------------------------", + " ", + "") + readme$Background <- c("# Background ", + " ", + "This folder contains documents provided by investigators and the data analysis plan. ", + " ", + "Details about the files: ", + " ", + "File | Description", + "---|---------------------------------------------------------------------", + " ") + readme$Code <- c("This folder contains all the code. ", + " ", + "Details about the files in this folder:", + " ", + "File | Description", + "---|---------------------------------------------------------------------", + " ") + readme$DataProcessed <- c("# Processed Data ", + " ", + "Scripts that created the files in this folder: ", + " ", + "File | Script | Description", + "---|------------------|---------------------------------------------------", + " ") + readme$DataRaw <- c("# Raw Data", + " ", + "Details about the files: ", + " ", + "File | Details", + "---|---------------------------------------------------------------------", + " ", + " ") + + readme$Dissemination <- c("# Dissemination", + " ", + "This folder contains abstracts, posters, papers and anything else produced for dissemination. ", + " ", + "Details about the files: ", + " ", + "File | Description", + "---|---------------------------------------------------------------------", + " ", + " ") + readme$Reports <- c("# Reports", + " ", + "This folder contains the rmarkdown scripts and pdf output of reports. ", + " ", + "Details about the files: ", + " ", + "File | Description", + "---|---------------------------------------------------------------------", + " ") + + # Function for creating the directory + createDir <- function(x){ + paste0(path, '/', x) + } + + createFiles <- function(x){ + file.path(path, paste0(x, '/README.md')) + } + + readme <- readme[template] + + pathnames <- sapply(names(readme), createDir) + dir_created <- lapply(pathnames, dir.create, showWarnings = F, recursive = T) + con <- lapply(names(readme), createFiles) + doNotOverwrite <- sapply(con, file.exists) + readme <- readme[!doNotOverwrite] + con <- con[!doNotOverwrite] + files_created <- mapply(writeLines, lapply(readme, paste0, collapse = '\n'), con) +} + + +#' pull project files from remote directory +#' + +#'Backup Project Directory +#' +#'This function backs up a CIDA project to the shared (P) CIDA drive. The backup directory +#'can either be existing (in which only changed files/folders are updated), or +#'nonexisting, in which case a full project backup is created. +#' +#'@param path_from Path from where the folders should be copied (project +#' directory location). +#'@param path_to Path to where the folders should be copied (P drive, only used +#' if specified). +#'@param exclude files/folders NOT to be backed up to the P-drive (useful for +#'larger files that don't change often). Currently not used. +#'@param recreate should backup be created from the ground up? +#' (can take longer, but useful for projects with many changes) +#' @param data_only should only subdirs including "data" (DataRaw/ and DataProcessed/) be backed up? +#' @param readme forces backup of project readme +#' @return This function has verbose output to ensure the back up is working, and +#' ultimately returns a success indicator that's returned by file.copy. +#' +#'@export +backup_project <- function(path_from = getwd(), + path_to = NULL, + exclude = c(".DS_Store", ".Rproj.user", ".git"), + recreate = FALSE, + data_only = TRUE, + readme = TRUE) { + + # Check args, make into absolute paths + path_from <- normalizePath(path_from) + + # Get proper path to Shared drive + if(missing(path_to)) { + path_to <- get_project_location() + if(path_to == "") + stop("Please first set project location, e.g., CIDAtools::set_project_location('BRANCHES/EmergencyMedicine/ThisProject')") + + if(!dir.exists(CIDAtools::get_project_drive_path())) + stop("Please ensure the CIDA drive is mounted, or set `path_to`") + + } + + path_to <- normalizePath(path_to) + + ## Check if specific project folder exists on P drive + backup_path <- file.path(path_to) + if(!dir.exists(backup_path)) { + message("Note: '", backup_path, "' not found; directory was created.") + dir.create(backup_path) + } else if (!recreate){ + message("Note: backup path already exists, and will be updated unless cancelled.") + message("Backup path:\n", backup_path, + "\nProject path:\n", + path_from) + } else { + message("Note: backup path already exists, and will be completely overwritten since recreate == TRUE.") + message("Backup path:\n", backup_path, + "\nProject path:\n", + path_from, "\n\nType 'yes' to confirm.") + delete_old <- readline() + + if(delete_old != "yes") + stop("Cancelled") + unlink(backup_path, recursive=TRUE) + dir.create(backup_path) + } + + message("\nDetermining current backup situation...") + + files_to_copy <- + list.files(path_from, recursive = T, all.files = T) + dirs_to_copy <- list.dirs(path_from, recursive = T, full.names = F)[-1] + + if(length(exclude)) { + files_to_exclude <- c( + unlist(sapply(exclude[dir.exists(exclude)], list.files, recursive = TRUE, + all = TRUE, full.names = T)), + exclude[!dir.exists(exclude)]) + + files_to_copy <- files_to_copy[!(files_to_copy %in% files_to_exclude)] + + dirs_to_exclude <- c( + unlist(sapply(exclude[dir.exists(exclude)], list.dirs, recursive = TRUE, + full.names = T))) + + dirs_to_copy <- dirs_to_copy[!(dirs_to_copy %in% dirs_to_exclude)] + } + + if(data_only) { + string_matches <- "dataraw|dataprocessed" + if(readme) + string_matches <- "readme|dataraw|dataprocessed" + + # find large files (>= 250 MB) + large_idx <- file.size(files_to_copy)/1e6 >= 250 + + # find file matches + file_matches <- grepl(string_matches, files_to_copy, ignore.case = TRUE) + dir_matches <- grepl(string_matches, dirs_to_copy, ignore.case = TRUE) + + files_to_copy <- files_to_copy[large_idx | file_matches] + dirs_to_copy <- dirs_to_copy[large_idx | dir_matches] + } + + ## Check if any files can be ignored using time last modified time + check <- file.exists(file.path(backup_path, files_to_copy)) + if(any(check)) { + to_mtime <- file.mtime(file.path(backup_path, files_to_copy)) + + # If no file found, set last modified time into future (kind of a hack) + to_mtime[is.na(to_mtime)] <- Sys.time() +500 + + from_mtime <- file.mtime(file.path(path_from, files_to_copy)) + files_to_copy <- files_to_copy[abs(difftime(to_mtime, from_mtime, units = "secs")) > 1] + } + + # Check and don't copy dirs if they already exist + dirs_to_copy <- dirs_to_copy[!dir.exists(file.path(backup_path, dirs_to_copy))] + + message("\nI'm about to create or update ",length(dirs_to_copy)," subdirectories and ", + length(files_to_copy), " files.", + "'\nType 'yes' to confirm, or 'list' to list changes.") + val <- readline() + if(val == "list") { + cat("Subdirs:", dirs_to_copy, sep = "\n") + cat("\n\nFiles:", files_to_copy, sep = "\n") + message("'\n\n Type 'yes' to confirm.") + val <- readline() + } + + stopifnot(val == "yes") + + if(length(dirs_to_copy)) { + message("Creating ", length(dirs_to_copy)," subdirectories...") + pb <- dplyr::progress_estimated(length(dirs_to_copy)) + r1 <- sapply(1:length(dirs_to_copy), function(i) { + pb$tick()$print() + dir.create(file.path(backup_path, dirs_to_copy[i])) + }) + } else + r1 <- T + + if(length(files_to_copy)) { + message("\nCopying/updating ", length(files_to_copy), " files...") + pb <- dplyr::progress_estimated(length(files_to_copy)) + r2 <- sapply(1:length(files_to_copy), function(i) { + pb$tick()$print() + file.copy(file.path(path_from, files_to_copy[i]), + file.path(backup_path, files_to_copy[i]), + overwrite = TRUE, copy.date = TRUE) + + }) + } else + r2 <- T + + result <- all(r1) & all(r2) + create_backup_info(backup_path) + + return(invisible(result)) +} + +create_backup_info <- function(path) { + fileConn<- file(file.path(path, "backup_info.md")) + lines <- c( + "This is a backup of the actual project directory. ", + "", + "DO NOT EDIT THIS DIRECTORY.", + "", + "If you do, changes may be overwritten by future backups.", + "", + paste0("This directory was last backed up at ", Sys.time()), + "" + ) + writeLines(lines, fileConn) + close(fileConn) +} + + + +#' Open Project +#' This function sets up the project to work on so the paths can easily be determined. +#' When both paths are specified path functions will reference the local copy. +#' When one is specified path functions will reference the local or remote copy whichever was specified. +#' Future updates will add some functionality to automate tasks. +#' +#' @param local_project_folder This is a local copy of the project folder +#' @param remote_project_folder This is the location of the shared drive copy of the project folder +#' +#' @export +open_project <- function(local_project_folder="",remote_project_folder=""){ + options(cida_tools.current_project_path = local_project_folder) + options(cida_tools.remote_current_project_path = remote_project_folder) +} + + + + + diff --git a/R/project_internal.R b/R/project_internal.R new file mode 100644 index 0000000..c719a63 --- /dev/null +++ b/R/project_internal.R @@ -0,0 +1,180 @@ +#' +#' get_default_path() - checks the current project remote path first then +#' project metadata file then checks user path file to return a default path to +#' the CIDA Drive if no path was found automatically. +#' +#' @return path of project(CIDA) drive +#' @noRd +#' @noMd +#' +#' + +get_default_path <- function(){ + path <- "" + ## TODO. Check project and then check User/Global Default + + if(! is.null(options("cida_tools.remote_current_project_path")) && options("cida_tools.remote_current_project_path")!=""){ + tmpPath=as.character(options("cida_tools.remote_current_project_path")) + if(fs::dir_exists(tmpPath)){ + path <- tmpPath + # TODO: Fix this + path <- sub("BRANCHES.*","",path) + } + } + + if(is.null(path) || path==""){ + # Attempt to load project meta data and pull the path from it. + project_location=get_full_project_path() + project_dir=get_project_location() + + + if( (! is.null(project_location)&& project_location!="") && (! is.null(project_dir) && project_dir!="")){ + path <- find_drive_location(project_location,project_dir) + }else if(! is.null(project_location)){ + path <- project_location + }#else if(! is.null(project_dir)){ + #} + } + + if(is.null(path) || path==""){ + #Attempt to load the global default path + path <- get_global_default_path() + } + + if(is.null(path) || path==""){ + warning("Failed to load project or global defaul location.") + } + return(path) +} + + +#' Internal Function to return Project Data path for use in the other methods +#' that read .ProjData/Data.dcf. If options for the local/remote path are specified +#' they will supersede the current directory upwards traversal to find .ProjData. +#' If the paths are empty the normal traversal will be used that will fail after 3 parent +#' directories. +#' +#' @noMd +#' @noRd +#' +get_project_data_dir <- function(){ + path <- "" + + if(!is.null(options("cida_tools.current_project_path")) && options("cida_tools.current_project_path") !=""){ + tmpPath <- fs::path(options("cida_tools.current_project_path")) + checkSuffix <- fs::path_join(c(tmpPath,'.ProjData/')) + if(fs::dir_exists(checkSuffix)){ + path <- checkSuffix + } + }else if(!is.null(options("cida_tools.remote_current_project_path")) && options("cida_tools.remote_current_project_path") !=""){ + tmpPath <- as.character(options("cida_tools.remote_current_project_path")) + checkSuffix <- fs::path_join(c(tmpPath,'.ProjData/')) + if(fs::dir_exists(checkSuffix)){ + path <- checkSuffix + } + } + + if(path==""){ + ## TODO There should be a way to find the top project directory and not use + # the ../ relative navigation below that will fail after 3 subfolders. + if(fs::dir_exists('.ProjData/')){ + path <- '.ProjData/' + }else if(fs::dir_exists('../.ProjData/')){ + path <- '../.ProjData/' + }else if(fs::dir_exists('../../.ProjData/')){ + path <- '../../.ProjData/' + }else if(fs::dir_exists('../../../.ProjData/')){ + path <- '../../../.ProjData/' + }else{ + warning(".ProjData directory not found in project.",call.=FALSE,immediate. = TRUE) + path <- '.ProjData/' + } + } + + return(fs::path(path)) +} + + + +#' Internal Function to return Project Data path for use in the other methods +#' that read .ProjData/Data.dcf +#' +#' @noMd +#' @noRd +#' +get_project_data_path <- function(){ + path <- get_project_data_dir() + path <- fs::path_join(c(path,"Data.dcf")) + return(path) +} + + +#' Internal Function to save Project Data for use in the other methods +#' that update values in .ProjData/Data.dcf +#' +#' @noMd +#' @noRd +#' +save_project_data <- function(project_metadata){ + to_save <- NULL + path <- get_project_data_dir() + print(paste("Path",path)) + + current_meta_data <- get_project_meta_data() + if(!is.null(path)){ + directory=fs::path_dir(path ) + if(!fs::dir_exists(directory)){ + fs::dir_create(path, recursive = TRUE, showWarnings = F) + } + } + + if(!is.null(current_meta_data) ){ + to_save <- current_meta_data + for (element in names(project_metadata)) { + to_save[element]=project_metadata[element] + } + }else{ + to_save <- project_metadata + } + dcfFile <- paste(path,"/Data.dcf", sep="") + write_project_data(to_save,dcfFile) +} + + +#' Internal Function to write Project Data .ProjData/Data.dcf +#' +#' @param project_metadata project metadata to save +#' @param path path to save the data to. +#' +#' @noMd +#' @noRd +#' +write_project_data <- function(project_metadata,path){ + write.dcf(project_metadata, fs::path(path)) + return(TRUE) +} + + +#' helper function to cleanup project location +#' @param loc project location path to clean up +#' @noMd +#' @noRd +#' +proj_location_handler <- function(loc="") { + loc <- gsub("/Volumes/sph-cida", "", loc) + loc <- gsub("P:/", "", loc) + loc <- gsub(".*BRANCHES", "BRANCHES", loc) + loc <- gsub("/$", "", loc) + return(loc) +} + + +#' Function to call to setup the package +#' +#' +#' @noMd +#' @noRd +.onLoad <- function(libname,pkgname){ + options(cida_tools.current_project_path="") + options(cida_tools.remote_current_project_path="") +} diff --git a/R/project_meta_data.R b/R/project_meta_data.R index 98c8702..a204183 100644 --- a/R/project_meta_data.R +++ b/R/project_meta_data.R @@ -3,19 +3,15 @@ #' This function allows you to set the project analyst. #' This will overwrite the current value if exists. #' -#' @param AnalystName A string containing the analyst name +#' @param analyst_name A string containing the analyst name #' @return A message stating the name has been changed. #' @keywords options Analyst ProjData #' @export #' -SetProjectAnalyst <- function(AnalystName){ - if(!is.character(AnalystName)) stop('Analyst Name must be a character string') - if(length(AnalystName) > 1) { - warning('Only First String is Used') - AnalystName <- AnalystName[1] - } - SetProjectData('analyst', AnalystName) - return(paste('The Project Analyst name has been changed to', AnalystName)) +set_project_analyst <- function(analyst_name){ + analyst_name <- check_string_param_value(analyst_name,'analyst_name') + set_project_meta_data('analyst', analyst_name) + return(paste('The Project Analyst Name has been changed to', analyst_name)) } #' Set Project Name @@ -23,19 +19,15 @@ SetProjectAnalyst <- function(AnalystName){ #' This function allows you to set the project name. This will overwrite the #' current value if exists. #' -#' @param ProjectName A string containing the analyst name +#' @param project_name A string containing the analyst name #' @return A message stating the name has been changed. #' @keywords options ProjectName ProjData #' @export #' -SetProjectName <- function(ProjectName){ - if(!is.character(ProjectName)) stop('Project Name must be a character string') - if(length(ProjectName) > 1) { - warning('Only First String is Used') - ProjectName <- ProjectName[1] - } - SetProjectData('ProjectName', ProjectName) - return(paste('The Project name has been changed to', ProjectName)) +set_project_name <- function(project_name){ + project_name <- check_string_param_value(project_name,'project_name') + set_project_meta_data('ProjectName', project_name) + return(paste('The project name has been changed to', project_name)) } #' Set PI Name @@ -43,19 +35,15 @@ SetProjectName <- function(ProjectName){ #' This function allows you to set the Project's PI. This will overwrite the #' current value if exists. #' -#' @param PI A string containing the analyst name +#' @param pi A string containing the analyst name #' @return A message stating the name has been changed. #' @keywords options PI ProjData #' @export #' -SetProjectPI <- function(PI){ - if(!is.character(PI)) stop('PI Name must be a character string') - if(length(PI) > 1) { - warning('Only First String is Used') - PI <- PI[1] - } - SetProjectData('PI', PI) - return(paste('The Project PI has been changed to', PI)) +set_project_pi <- function(pi){ + pi <- check_string_param_value(pi,'PI') + set_project_meta_data('PI', pi) + return(paste('The Project PI has been changed to', pi)) } #' Set Project Location @@ -68,17 +56,43 @@ SetProjectPI <- function(PI){ #' @keywords options location ProjData #' @export #' -SetProjectLocation <- function(path){ - if(!is.character(path)) stop('Path must be a character string') - if(length(path) > 1) { - warning('Only First String is Used') - path <- path[1] - } - path <- proj.location.handler(path) - SetProjectData('datalocation', path) +set_project_location <- function(path){ + path <- check_string_param_value(path,'path') + path <- proj_location_handler(path) + set_project_meta_data('datalocation', path) return(paste('The Project Location has been changed to', path)) } +#' Set Project GitHub Location +#' +#' This function allows you to set the Project's GitHub location. +#' This will overwrite the current value if exists. +#' +#' @param git_url A string containing the URL to the GitHub repository for this project. +#' @return A message stating the name has been changed. +#' @keywords options location ProjData +#' @export +#' +set_project_github <- function(git_url=''){ + git_url <- check_string_param_value(git_url,'git_url') + set_project_meta_data('gitlocation', git_url) + return(paste('The Project GitHub Location has been changed to', git_url)) +} + +#' Get Project GitHub Location +#' +#' This function returns the Project GitHub location or blank if it's not set. +#' +#' @return A character string with the project GitHub +#' @keywords options ProjData ProjectGitHub +#' @export +#' + +get_project_github <- function(){ + git_url <- get_project_meta_data('gitlocation') + return(git_url) +} + #' Get Project Analyst #' #' This function returns the Project Analyst Name. If none exists, it @@ -90,23 +104,12 @@ SetProjectLocation <- function(path){ #' @export #' -ProjectAnalyst <- function(){ - if(file.exists(file.path('.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('.ProjData/Data.dcf'), all = T) - if('analyst' %in% names(ProjData)) return(ProjData$analyst) - } - if(file.exists(file.path('../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../.ProjData/Data.dcf'), all = T) - if('analyst' %in% names(ProjData)) return(ProjData$analyst) +get_project_analyst <- function(){ + analyst <- get_project_meta_data('analyst') + if(analyst==""){ + analyst <- getOption('CIDAtools.analyst', default="") } - if(file.exists(file.path('../../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../../.ProjData/Data.dcf'), all = T) - if('analyst' %in% names(ProjData)) return(ProjData$analyst) - } - if(!is.null(getOption('CIDAtools.analyst'))){ - return(getOption('CIDAtools.analyst')) - } - return('') + return(analyst) } #' Get Project Name @@ -118,21 +121,9 @@ ProjectAnalyst <- function(){ #' @export #' -ProjectName <- function(){ - if(file.exists(file.path('.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('.ProjData/Data.dcf'), all = T) - if('ProjectName' %in% names(ProjData)) return(ProjData$ProjectName) - } - - if(file.exists(file.path('../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../.ProjData/Data.dcf'), all = T) - if('ProjectName' %in% names(ProjData)) return(ProjData$ProjectName) - } - if(file.exists(file.path('../../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../../.ProjData/Data.dcf'), all = T) - if('ProjectName' %in% names(ProjData)) return(ProjData$ProjectName) - } - return('') +get_project_name <- function(){ + project_name <- get_project_meta_data('ProjectName') + return(project_name) } #' Get PI Name @@ -144,22 +135,9 @@ ProjectName <- function(){ #' @export #' -ProjectPI <- function(){ - if(file.exists(file.path('.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('.ProjData/Data.dcf'), all = T) - if('PI' %in% names(ProjData)) return(ProjData$PI) - } - if(file.exists(file.path('../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../.ProjData/Data.dcf'), all = T) - if('PI' %in% names(ProjData)) return(ProjData$PI) - } - if(file.exists(file.path('../../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../../.ProjData/Data.dcf'), all = T) - if('PI' %in% names(ProjData)) return(ProjData$PI) - } - - - return('') +get_project_pi <- function(){ + project_pi <- get_project_meta_data('PI') + return(project_pi) } #' Get Project data location on CIDA Drive @@ -176,87 +154,145 @@ ProjectPI <- function(){ #' } #' -ProjectLocation <- function(path = ''){ - - if(file.exists(file.path('.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('.ProjData/Data.dcf'), all = T) - if('datalocation' %in% names(ProjData)){ - temp_path <- CIDA_drive_path(ProjData$datalocation) - return(file.path(temp_path, path)) - } +get_project_location <- function(path = ''){ + temp_path <- get_project_meta_data('datalocation') + full_path <- fs::path("") + if( temp_path!="" ){ + full_path <- fs::path_join(c(temp_path, path)) + }else{ + message('Project location not found, use set_project_meta_data("datalocation", x).') } + return(full_path) +} - if(file.exists(file.path('../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../.ProjData/Data.dcf'), all = T) - if('datalocation' %in% names(ProjData)){ - temp_path <- CIDA_drive_path(ProjData$datalocation) - return(file.path(temp_path, path)) - } - } - if(file.exists(file.path('../../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../../.ProjData/Data.dcf'), all = T) - if('datalocation' %in% names(ProjData)){ - temp_path <- CIDA_drive_path(ProjData$datalocation) - return(file.path(temp_path, path)) - } - } - message('Project location not found, use SetProjectData("datalocation", x).') - return("") +#' Sets the default full path to the project. +#' +#' @param path full path to the project folder +#' +#' @return message indicating the path has been saved. +#' @export +#' +#' +set_full_project_path <- function(path=''){ + path <- check_string_param_value(path,'default_full_path_to_project') + set_project_meta_data('default_full_path_to_project', path) + return(paste('The project default full path has been changed to', path)) +} + +#' Gets the currently set full path to the project from .ProjData/Data.dcf +#' +#' @return full path to project +#' @export +#' +get_full_project_path <- function(){ + project_path <- get_project_meta_data('default_full_path_to_project') + return(project_path) } + #' Set data for project #' #' Allows you to set misc project data parameters #' for Project Name, Analyst, or PI recommend you use specific function #' -#' @param Parameter Project Parameter to be set -#' @param Value Value to set to project parameter +#' +#' @param parameter Project Parameter to be set +#' @param value Value to set to project parameter #' @export #' #' -SetProjectData <- function(Parameter, Value){ - if (!is.character(Parameter) | !is.character(Parameter)) - stop('Parameter must be a character string of length one') - if(!is.character(Value)) stop('Value must be a character string') - if(length(Value) > 1) { - warning('Only First String is Used') - Value <- Value[1] +set_project_meta_data <- function(parameter, value){ + parameter <- check_string_param_value(parameter,'parameter') + value <- check_string_param_value(value,'value') + if(parameter=='datalocation'){ + value <- proj_location_handler(value) } - if(Parameter=='datalocation'){ - Value <- proj.location.handler(Value) - } - if(file.exists(file.path('.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('.ProjData/Data.dcf'), all = T) - } else{ - dir.create(paste0('.ProjData/'), recursive = T, showWarnings = F) - ProjData <- list() + + proj_data <- get_full_project_data() + + if(parameter %in% names(proj_data)){ + proj_data[parameter] <- value + }else{ + proj_data[parameter] <- value } - ProjData[Parameter] <- Value - write.dcf(ProjData, file.path('.ProjData/Data.dcf')) + + save_project_data(proj_data) } #' Get data for project #' -#' Allows you to get misc project data parameters +#' Allows you to get any project data parameters or all parameters. Either specify +#' the desired parameter or with no parameter it will return all available parameters. +#' +#' Possible parameters values include: +#' +#' - analyst - Analyst's Name +#' +#' - ProjectName - Project Name +#' +#' - PI - PI Name +#' +#' - datalocation - Poject folder location under the CIDA PATH. +#' +#' - default_full_path_to_project - Project default path which is the default full path to the project files. Includes the local filesystem path to network mount point and network path to project folder. #' -#' @param param Project parameter to be gotten +#' - gitlocation - GitHub URL for the project code +#' +#' +#' @param param Project parameter to return or if not specified to return all parameter/value pairs. #' @export #' -getProjectData <- function(param){ - if(file.exists(file.path('.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('.ProjData/Data.dcf'), all = T) - if(param %in% names(ProjData)) return(ProjData[[param]]) - } - if(file.exists(file.path('../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../.ProjData/Data.dcf'), all = T) - if(param %in% names(ProjData)) return(ProjData[[param]]) - } - if(file.exists(file.path('../../.ProjData/Data.dcf'))){ - ProjData <- read.dcf(file.path('../../.ProjData/Data.dcf'), all = T) - if(param %in% names(ProjData)) return(ProjData[[param]]) +get_project_meta_data <- function(param=''){ + value <- '' + project_data <- get_full_project_data() + if(is.null(param) || param==''){ + + value <- project_data + + }else if( !is.null(project_data)){ + #value <- project_data + if(param %in% names(project_data)){ + value <- project_data[[param]] + }else{ + warning(paste(c(param," not found in project data.")),call.=FALSE,immediate. = TRUE) + } + }else{ + warning(paste(c("get_project_meta_data(",param,") returned NULL project data.")),call.=FALSE,immediate. = TRUE) } - return('') + + return(value) + +} + + +#' Internal Function to return Project Data object for use in the other methods +#' that read .ProjData/Data.dcf +#' +#' @noMd +#' @noRd +#' + +get_full_project_data <- function(){ + proj_data <- NULL + path <- get_project_data_path() + if(is.null(path) || path == "" ){ + warning(".ProjData/Data.dcf file not found in project.",call.=FALSE,immediate. = TRUE) + }else if(path !=""){ + #print(paste0("ERROR:",path,"::")) + if(fs::file_exists(path) && fs::file_size(path)>0 ){ + proj_data <- read.dcf(file.path(path), all = T) + }else if(fs::file_exists(path) && fs::file_size(path)==0){ + warning(paste(path," File is empty.",sep="")) + }else if(! fs::file_exists(path) ){ + warning(paste(path," File does not exist.",sep="")) + } + } + return(proj_data) } + + + + diff --git a/R/randomizer_and_blinder_app.R b/R/randomizer_and_blinder_app.R index fd75e0e..5aa8d88 100755 --- a/R/randomizer_and_blinder_app.R +++ b/R/randomizer_and_blinder_app.R @@ -1,9 +1,11 @@ -#' Randomizer and blinder tool +#' Randomizer and blinder tool - To be deprecated #' #' See the inst/ folder for the main code for this function #' #' @export randblinder_shiny_tool <- function() { + deprecation_warn("randomizer_and_blinder_app.randblinder_shiny_tool") + appFile <- system.file("shiny_app/randblinder.R", package = "CIDAtools") if (appFile == "") { stop("Could not find the Shiny app file. Try re-installing CIDAtools.", call. = FALSE) diff --git a/R/read_xlsx_color.R b/R/read_xlsx_color.R index 03128d9..a710a29 100644 --- a/R/read_xlsx_color.R +++ b/R/read_xlsx_color.R @@ -1,4 +1,4 @@ -#' Read in xlsx with fill colour +#' Read in xlsx with fill colour - To be deprecated #' #' Reads in the fill colour of excel workbooks. Creates a data frame for each #' sheet in a list if mutliple sheets are requested. Creates a colour column for @@ -23,6 +23,9 @@ #' @keywords Excel colour color xlsx #' read_xlsx_color <- function(file, colorColumns, sheet = NULL, header = T){ + + deprecation_warn("read_xlsx_color.read_xlsx_color") + if(!requireNamespace("xlsx", quietly = TRUE)) stop("package 'xlsx' is required.") if(!is.list(colorColumns) & is.numeric(colorColumns)) diff --git a/R/reporting_fns.R b/R/reporting_fns.R index 8caa498..1542a54 100644 --- a/R/reporting_fns.R +++ b/R/reporting_fns.R @@ -1,4 +1,4 @@ -#' Pretty p-values +#' Pretty p-values - To be deprecated #' #' This function helps print p-values in RMD output #' @@ -12,7 +12,7 @@ #' @export #' pvalr <- function(pvals, sig.limit = .001, digits = 3, html = FALSE, equal_sign = "") { - + deprecation_warn("reporting_fns.pvalr") roundr <- function(x, digits = 1) { res <- sprintf(paste0('%.', digits, 'f'), x) zzz <- paste0('0.', paste(rep('0', digits), collapse = '')) @@ -34,7 +34,7 @@ pvalr <- function(pvals, sig.limit = .001, digits = 3, html = FALSE, equal_sign }, sig.limit = sig.limit) } -#' List tables with the same columns +#' List tables with the same columns - To be deprecated #' #' This function will print a group of tables together in a decently pretty way. #' May need a bit of finagling. @@ -48,7 +48,7 @@ pvalr <- function(pvals, sig.limit = .001, digits = 3, html = FALSE, equal_sign #' @export list_kables <- function(tabs, bo = c("striped", "condensed"), ...) { - + deprecation_warn("reporting_fns.list_kables") idx <- sapply(tabs, nrow) tabs %>% diff --git a/R/temp_refactored_message.R b/R/temp_refactored_message.R new file mode 100644 index 0000000..94257c0 --- /dev/null +++ b/R/temp_refactored_message.R @@ -0,0 +1,121 @@ +# Functions to warn users of refactored methods and provide the renamed function. +# These are expected to be short term/temporary functions to aid in transition +# after refactoring to provide consistent naming across the package. +# Perhaps remove following deprecation of the methods marked for deprecation. + + +#' @inherit get_project_drive_path +#' @export +CIDA_drive_path <- function(file="") { + renamed_warn(function_name="CIDA_drive_path", replacement_name="get_project_drive_path") + #warning( paste(c("CIDA_drive_path() renamed to get_project_drive_path()")),immediate. = TRUE) + return(get_project_drive_path(file)) +} + + +#' @inherit set_project_name +#' @export +SetProjectName <- function(project_name){ + renamed_warn(function_name="SetProjectName", replacement_name="set_project_name") + #warning( paste(c("SetProjectName(ProjectName) renamed to set_project_name(project_name)")),immediate. = TRUE) + return(set_project_name(project_name)) +} + +#' @inherit set_project_analyst +#' @export +SetProjectAnalyst <- function(analyst_name){ + renamed_warn(function_name="SetProjectAnalyst", replacement_name="set_project_analyst") + #warning( paste(c("SetProjectAnalyst() renamed to set_project_analyst()")),immediate. = TRUE) + return(set_project_analyst(analyst_name)) +} + + +#' @inherit set_project_pi +#' @export +SetProjectPI <- function(pi){ + renamed_warn(function_name="SetProjectPI", replacement_name="set_project_pi") + #warning( paste(c("SetProjectPI() renamed to set_project_pi()")),immediate. = TRUE) + return(set_project_pi(pi)) +} + + +#' @inherit set_project_location +#' @export +SetProjectLocation <- function(path){ + renamed_warn(function_name="SetProjectLocation", replacement_name="set_project_location") + #warning( paste(c("SetProjectLocation() renamed to set_project_location()")),immediate. = TRUE) + return(set_project_location(path)) +} + +#' @inherit get_project_analyst +#' @export +ProjectAnalyst <- function(){ + renamed_warn(function_name="ProjectAnalyst", replacement_name="get_project_analyst") + #warning( paste(c("ProjectAnalyst() renamed to get_project_analyst()")),immediate. = TRUE) + return(get_project_analyst()) +} + +#' @inherit get_project_name +#' @export +ProjectName <- function(){ + renamed_warn(function_name="ProjectName", replacement_name="get_project_name") + #warning( paste(c("ProjectName() renamed to get_project_name()")),immediate. = TRUE) + return(get_project_name()) +} + +#' @inherit get_project_pi +#' @export +ProjectPI <- function(){ + renamed_warn(function_name="ProjectPI", replacement_name="get_project_pi") + #warning( paste(c("ProjectPI() renamed to get_project_pi()")),immediate. = TRUE) + return(get_project_pi()) +} + +#' @inherit get_project_location +#' @export +ProjectLocation <- function(){ + renamed_warn(function_name="ProjectLocation", replacement_name="get_project_location") + #warning( paste(c("ProjectLocation() renamed to get_project_location()")),immediate. = TRUE) + return(get_project_location()) +} + +#' @inherit set_project_meta_data +#' @export +SetProjectData <- function(parameter,value){ + renamed_warn(function_name="SetProjectData", replacement_name="set_project_meta_data") + #warning( paste(c("SetProjectData() renamed to set_project_meta_data()")),immediate. = TRUE) + set_project_meta_data(parameter,value) +} + +#' @inherit get_project_meta_data +#' @export +getProjectData <- function(param){ + renamed_warn(function_name="getProjectData", replacement_name="get_project_meta_data") + #warning( paste(c("getProjectData() renamed to get_project_meta_data()")),immediate. = TRUE) + return(get_project_meta_data(param)) +} + +#' @inherit set_project_analyst +#' @export +setAnalyst <- function(analyst_name){ + renamed_warn(function_name="setAnalyst", replacement_name="set_project_analyst") + #warning( paste(c("setAnalyst() renamed to set_project_analyst()")),immediate. = TRUE) + return(set_project_analyst(analyst_name)) +} + +#' @inherit set_global_default_analyst +#' @export +setPermanentAnalyst <- function(analyst_name, update_template=FALSE){ + renamed_warn(function_name="setPermanentAnalyst", replacement_name="set_global_default_analyst") + #warning( paste(c("setPermanentAnalyst() renamed to set_global_default_analyst()")),immediate. = TRUE) + return(set_global_default_analyst(analyst_name, update_template)) +} + + +#' @inherit remove_global_default_analyst +#' @export +removeAnalyst <- function(){ + renamed_warn(function_name="removeAnalyst", replacement_name="remove_global_default_analyst") + warning( paste(c("removeAnalyst() renamed to remove_global_default_analyst()")),immediate. = TRUE) + return(remove_global_default_analyst()) +} diff --git a/R/util_internal.R b/R/util_internal.R new file mode 100644 index 0000000..38a72a9 --- /dev/null +++ b/R/util_internal.R @@ -0,0 +1,129 @@ +#' Internal Utility Functions + +#' Sets the contact email address. +#' +#' +#' +#' @return The email address to contact. +#' +#' @noRd +#' @noMd +#' +warning_email <- function(){ + email <- "cida-rt@olucdenver.onmicrosoft.com" + return(email) +} + +#' Check String Parameter Values for errors +#' +#' +#' @param value parameter value to check +#' @return the value to be used after checking it is a character value and not an array or returning the first value of the array. +#' +#' @noRd +#' @noMd +#' +check_string_param_value <- function(value="",parameter=""){ + + if(!is.character(value)) stop(parameter,' must be a character string') + if(length(value) > 1) { + warning('Only First String is Used') + value <- value[1] + } + return(value) +} + + + +#' Find and return the beginning of the full path up to the start of the common path. +#' +#' @importFrom utils head +#' +#' @param full_path The full path to search for the partial path in. +#' @param partial_path The partial path which may start any were in the full path. +#' @return The beginning of the full path proceeding the start of the partial path. +#' +#' @noRd +#' @noMd +#' +find_drive_location <- function(full_path="",partial_path=""){ + parts_full<- fs::path_split(full_path)[[1]] + parts_partial <- fs::path_split(partial_path)[[1]] + common_index_start=1 + if(parts_partial[common_index_start]=="/"){ + common_index_start=2 + } + match_index <- -1 + for (i in seq_along(parts_full)){ + if(parts_full[i]==parts_partial[common_index_start]){ + oldI=i + is_match=TRUE + for (j in common_index_start:length(parts_partial)){ + if(parts_partial[j] != parts_full[i]){ + is_match=FALSE + break + } + i <- i+1 + } + if(is_match){ + match_index<-oldI-1 + } + i=oldI + } + } + + drive_parts <- head(parts_full,match_index) + drive_path <- fs::path_join(drive_parts)[[1]] + return(drive_path) +} + + + + +#' Deprecation Warning for functions flagged to be deprecated +#' deprecation_warn() - print a warning that the function will be deprecated. +#' +#' @param function_name Function name the warning was called from. +#' +#' @noRd +#' @noMd +#' +deprecation_warn <- function(function_name=""){ + warning(paste(c(function_name,"() has been deprecated and will be removed in ", + "future package versions.\nPlease contact ", + warning_email(), + " if you regularly use this ", + "function\nand would like to see it stay.")), + call.=FALSE,immediate. = TRUE) +} + + + +#' Deprecated Warning for functions already deprecated +#' +#' deprecated_warn() - function to call for deprecated functions listing the +#' version that removed the function +#' +#' @param function_name Version of package function was removed. +#' @param version Version of package function was removed. +#' +#' @noRd +#' @noMd +#' +deprecated_warn <- function(function_name="", version=""){ + warning(paste(c(function_name,"() was deprecated in version ",version)),call.=FALSE,immediate. = TRUE) +} + +#' Deprecated Warning for renamed functions. +#' renamed_warn() - Functon which notifies the user that the called function +#' has been renamed. +#' +#' @param function_name The old function name. +#' @param replacement_name The new function name. +#' @noRd +#' @noMd +renamed_warn <- function(function_name="", replacement_name="") { + warning(paste(c(function_name, "() has been renamed to ", replacement_name, "(). Please use the updated function name in new code.")), call.=FALSE, immediate.=TRUE) +} + + diff --git a/README.md b/README.md index 3c8ab6f..4df9b57 100644 --- a/README.md +++ b/README.md @@ -1,107 +1,147 @@ +# CIDATools + + # CIDAtools -[![R-CMD-check](https://github.com/CIDA-CSPH/CIDAtools/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/CIDA-CSPH/CIDAtools/actions/workflows/R-CMD-check.yaml) +
+ +
R-CMD-check
+
## Overview -This package contains numerous templates and tools to make life at CIDA (part -of the Colorado School of Public Health) happier and more efficient! +This package contains numerous templates and tools to make life at CIDA +(part of the Colorado School of Public Health) happier and more +efficient! + +## Installing CIDAtools To install `CIDAtools` on your local machine: -``` -# install.packages("devtools") -devtools::install_github('CIDA-CSPH/CIDAtools') -``` + install.packages("pak") # Only required if pak is not installed + pak::pak('CIDA-CSPH/CIDAtools') + +> [!NOTE] +> If you are encountering issues with the new version of CIDAtools (`v0.2.0+`), you can install the older version using: +> +>
pak::pak("CIDA-CSPH/CIDAtools@v0.1.2")
## Creating a new project -After `CIDAtools` is installed, a new CIDA project can be created using the -Rstudio GUI (File>New Project>New Directory>New CIDA Project). +After `CIDAtools` is installed, a new CIDA project can be created using +the Rstudio GUI (File\>New Project\>New Directory\>New CIDA Project). -Or, to create a new project folder structure from the R console, -navigate to the main project directory, and run: +Or, to create a new project folder structure from the R console, +navigate to the main project directory, and run: -``` -create_project() -``` + create_project(project_name="My Project",analyst = "Your Name") -Feel free to set the project name, PI, and analyst via the `ProjectName`, `PI`, or `analyst` -arguments respectively, and see `?create_project` for more details. If any of these are -specified, they are stored as text in a hidden subdirectory called .ProjData, and can -be called in subsequent R code anywhere in the project using `ProjectName()`, `ProjectPI()`, and -`ProjectAnalyst()`. +Feel free to set the project name, PI, and analyst via the +`ProjectName`, `PI`, or `analyst` arguments respectively, and see +`?create_project` for more details. If any of these are specified, they +are stored as text in a hidden subdirectory called .ProjData, and can be +called in subsequent R code anywhere in the project using +`ProjectName()`, `ProjectPI()`, and `ProjectAnalyst()`. ## Creating a new CIDA report -**Templates** are useful for creating new documents with the correct CIDA *formatting*. - -`CIDAtools` includes templates that can make it easy to create a new CIDA report. -To use this functionality in Rstudio, first ensure the package is installed, then: +**Templates** are useful for creating new documents with the correct +CIDA *formatting*. -1) Click on "New R Markdown" -2) In the pop-up, select "From template" -3) You should see CIDA report templates to choose from. +`CIDAtools` includes templates that can make it easy to create a new +CIDA report. To use this functionality in Rstudio, first ensure the +package is installed, then: -Alternatively, source code for templates is available in inst/rmarkdown/templates/. +1. Click on “New R Markdown” +2. In the pop-up, select “From template” +3. You should see CIDA report templates to choose from. -Note: the CIDA Word report template contains multiple files, which are needed to specify the format for Word output. -Therefore, CIDA Word reports must have their own subdirectory to start. +Alternatively, source code for templates is available in +inst/rmarkdown/templates/. +Note: the CIDA Word report template contains multiple files, which are +needed to specify the format for Word output. Therefore, CIDA Word +reports must have their own subdirectory to start. ## Outlines for CIDA reports -**Outlines** are intended to provide an idea of the *content* necessary within each type of CIDA report. - -`CIDAtools` includes outlines for the following reports in inst/outlines/: - -- CIDA Analysis Plan [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Analysis-Plan-Outline.docx) -- CIDA Comprehensive Report [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Comprehensive-Report-Outline.docx) -- CIDA Exploratory Report [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Exploratory-Report-Outline.docx) -- CIDA Omics Study Report [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Omics-Outline.docx) -- CIDA Study Design [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Study-Design-Outline.docx) - -## Backing up CIDA projects - -CIDA project data and reports should be either kept on the CIDA shared drive (the P drive), or backed up (i.e. copied) to the shared drive on a regular basis. - -Since the P drive can sometimes be slow to read/write on, CIDA members can work on a project locally if they regularly back up the project to the P drive. To help with this, we've written the function `backup_project` which will automatically back up a project folder to the P drive (to the "Projects" subdirectory by default, but this can be specified with the `subdir_to` argument). Alternatively, the main project folder can simply be copied and pasted to the P drive manually. +**Outlines** are intended to provide an idea of the *content* necessary +within each type of CIDA report. + +`CIDAtools` includes outlines for the following reports in +inst/outlines/: + +- CIDA Analysis Plan + [\[download\]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Analysis-Plan-Outline.docx) +- CIDA Comprehensive Report + [\[download\]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Comprehensive-Report-Outline.docx) +- CIDA Exploratory Report + [\[download\]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Exploratory-Report-Outline.docx) +- CIDA Omics Study Report + [\[download\]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Omics-Outline.docx) +- CIDA Study Design + [\[download\]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Study-Design-Outline.docx) + +## Backing up CIDA projects + +CIDA project data and reports should be either kept on the CIDA shared +drive (the P drive), or backed up (i.e. copied) to the shared drive on a +regular basis. + +Since the P drive can sometimes be slow to read/write on, CIDA members +can work on a project locally if they regularly back up the project to +the P drive. To help with this, we’ve written the function +`backup_project` which will automatically back up a project folder to +the P drive (to the “Projects” subdirectory by default, but this can be +specified with the `subdir_to` argument). Alternatively, the main +project folder can simply be copied and pasted to the P drive manually. Within a project directory, run: -``` -backup_project() -``` -This will copy over the entire local project (all files and directories) to a project of the same name in the P drive. A backup_info.md file will also be produced that indicates when the backup was performed. + backup_project() + +This will copy over the entire local project (all files and directories) +to a project of the same name in the P drive. A backup_info.md file will +also be produced that indicates when the backup was performed. -If the project directory already exists in the P drive, only files/directories that have changed since the last backup will be copied over. This speeds up the process. +If the project directory already exists in the P drive, only +files/directories that have changed since the last backup will be copied +over. This speeds up the process. -Files located in the backup directory that are not in the project directory are not deleted. This means if you have large files, anytime you rename them and re-run the backup function, the storage needed will double since both files will remain in the backup folder. To avoid this, specify `recreate = TRUE` to fully recreate the current directory from the ground up. +Files located in the backup directory that are not in the project +directory are not deleted. This means if you have large files, anytime +you rename them and re-run the backup function, the storage needed will +double since both files will remain in the backup folder. To avoid this, +specify `recreate = TRUE` to fully recreate the current directory from +the ground up. ## Documentation -The package website is available [here](https://cida-csph.github.io/CIDAtools). -We plan to keep track of SAS macros and useful R packages in Article there (package vignettes). +The package website is available +[here](https://cida-csph.github.io/CIDAtools). We plan to keep track of +SAS macros and useful R packages in Article there (package vignettes). ## Using snippets -CIDA functions can be used in snippets (if you have a header snippet already in your Rstudio options): +CIDA functions can be used in snippets (if you have a header snippet +already in your Rstudio options): Example of a header snippet using Project Data: -``` -snippet header - ########################################### - # Project: `r CIDAtools::ProjectName()` - # Author: `r CIDAtools::ProjectAnalyst()` - # Date: `r paste(format(Sys.Date(), '%m/%d/%Y'))` - # ######################################### -``` -## Other functionality + snippet header + ########################################### + # Project: `r CIDAtools::ProjectName()` + # Author: `r CIDAtools::ProjectAnalyst()` + # Date: `r paste(format(Sys.Date(), '%m/%d/%Y'))` + # ######################################### -This package also contains functions for reading excel files with color columns -and the Table1 function. +## Other functionality -Please feel free to file an issue request if you encounter errors or would like -to request new features. If reporting a bug, please provide a reproducible example. +This package also contains functions for reading excel files with color +columns and the Table1 function. +Please feel free to file an issue request if you encounter errors or +would like to request new features. If reporting a bug, please provide a +reproducible example. diff --git a/README.qmd b/README.qmd new file mode 100644 index 0000000..f25f77d --- /dev/null +++ b/README.qmd @@ -0,0 +1,114 @@ +--- +title: "CIDATools" +format: html +--- + +# CIDAtools + +[![R-CMD-check](https://github.com/CIDA-CSPH/CIDAtools/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/CIDA-CSPH/CIDAtools/actions/workflows/R-CMD-check.yaml) + +## Overview + +This package contains numerous templates and tools to make life at CIDA (part +of the Colorado School of Public Health) happier and more efficient! + +To install `CIDAtools` on your local machine: + +``` + # install.packages("pak") + pak::pak('CIDA-CSPH/CIDAtools') + +``` + +## Creating a new project + +After `CIDAtools` is installed, a new CIDA project can be created using the +Rstudio GUI (File>New Project>New Directory>New CIDA Project). + +Or, to create a new project folder structure from the R console, +navigate to the main project directory, and run: + +``` +create_project(project_name="My Project",analyst = "Your Name") +``` + +Feel free to set the project name, PI, and analyst via the `ProjectName`, `PI`, or `analyst` +arguments respectively, and see `?create_project` for more details. If any of these are +specified, they are stored as text in a hidden subdirectory called .ProjData, and can +be called in subsequent R code anywhere in the project using `ProjectName()`, `ProjectPI()`, and +`ProjectAnalyst()`. + +## Creating a new CIDA report + +**Templates** are useful for creating new documents with the correct CIDA *formatting*. + +`CIDAtools` includes templates that can make it easy to create a new CIDA report. +To use this functionality in Rstudio, first ensure the package is installed, then: + +1) Click on "New R Markdown" +2) In the pop-up, select "From template" +3) You should see CIDA report templates to choose from. + +Alternatively, source code for templates is available in inst/rmarkdown/templates/. + +Note: the CIDA Word report template contains multiple files, which are needed to specify the format for Word output. +Therefore, CIDA Word reports must have their own subdirectory to start. + + +## Outlines for CIDA reports + +**Outlines** are intended to provide an idea of the *content* necessary within each type of CIDA report. + +`CIDAtools` includes outlines for the following reports in inst/outlines/: + +- CIDA Analysis Plan [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Analysis-Plan-Outline.docx) +- CIDA Comprehensive Report [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Comprehensive-Report-Outline.docx) +- CIDA Exploratory Report [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Exploratory-Report-Outline.docx) +- CIDA Omics Study Report [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Omics-Outline.docx) +- CIDA Study Design [[download]](https://github.com/CIDA-CSPH/CIDAtools/raw/master/inst/outlines/CIDA-Study-Design-Outline.docx) + +## Backing up CIDA projects + +CIDA project data and reports should be either kept on the CIDA shared drive (the P drive), or backed up (i.e. copied) to the shared drive on a regular basis. + +Since the P drive can sometimes be slow to read/write on, CIDA members can work on a project locally if they regularly back up the project to the P drive. To help with this, we've written the function `backup_project` which will automatically back up a project folder to the P drive (to the "Projects" subdirectory by default, but this can be specified with the `subdir_to` argument). Alternatively, the main project folder can simply be copied and pasted to the P drive manually. + +Within a project directory, run: +``` +backup_project() +``` + +This will copy over the entire local project (all files and directories) to a project of the same name in the P drive. A backup_info.md file will also be produced that indicates when the backup was performed. + +If the project directory already exists in the P drive, only files/directories that have changed since the last backup will be copied over. This speeds up the process. + +Files located in the backup directory that are not in the project directory are not deleted. This means if you have large files, anytime you rename them and re-run the backup function, the storage needed will double since both files will remain in the backup folder. To avoid this, specify `recreate = TRUE` to fully recreate the current directory from the ground up. + +## Documentation + +The package website is available [here](https://cida-csph.github.io/CIDAtools). +We plan to keep track of SAS macros and useful R packages in Article there (package vignettes). + +## Using snippets + +CIDA functions can be used in snippets (if you have a header snippet already in your Rstudio options): + +Example of a header snippet using Project Data: +``` +snippet header + ########################################### + # Project: `r CIDAtools::ProjectName()` + # Author: `r CIDAtools::ProjectAnalyst()` + # Date: `r paste(format(Sys.Date(), '%m/%d/%Y'))` + # ######################################### +``` + +## Other functionality + +This package also contains functions for reading excel files with color columns +and the Table1 function. + +Please feel free to file an issue request if you encounter errors or would like +to request new features. If reporting a bug, please provide a reproducible example. + + diff --git a/_pkgdown.yml b/_pkgdown.yml deleted file mode 100644 index 0cbb31a..0000000 --- a/_pkgdown.yml +++ /dev/null @@ -1,4 +0,0 @@ -url: https://cida-csph.github.io/CIDAtools/ -template: - bootstrap: 5 - diff --git a/altdoc/pkgdown.yml b/altdoc/pkgdown.yml new file mode 100644 index 0000000..de8ee21 --- /dev/null +++ b/altdoc/pkgdown.yml @@ -0,0 +1,4 @@ +urls: + reference: https:/cida-csph.github.io/CIDAtools/man + article: https:/cida-csph.github.io/CIDAtools/vignettes + diff --git a/altdoc/quarto_website.yml b/altdoc/quarto_website.yml new file mode 100644 index 0000000..66e7828 --- /dev/null +++ b/altdoc/quarto_website.yml @@ -0,0 +1,42 @@ +project: + type: website + output-dir: ../website + +# Note: freeze functionality can be set at a project level or for individual .qmd files +# execute: +# freeze: false + +website: + title: "$ALTDOC_PACKAGE_NAME" + code-links: true + navbar: + search: true + right: + - icon: github + href: $ALTDOC_PACKAGE_URL_GITHUB + aria-label: $ALTDOC_PACKAGE_NAME GitHub + sidebar: + collapse-level: 1 + contents: + - text: Home + file: index.qmd + - section: $ALTDOC_VIGNETTE_BLOCK + - section: $ALTDOC_MAN_BLOCK + - text: News + file: $ALTDOC_NEWS + - text: Changelog + file: $ALTDOC_CHANGELOG + - text: License + file: $ALTDOC_LICENSE + - text: Licence + file: $ALTDOC_LICENCE + - text: Code of conduct + file: $ALTDOC_CODE_OF_CONDUCT + - text: Citation + file: $ALTDOC_CITATION + +format: + html: + code-link: true +# theme: cosmo +# number-sections: false diff --git a/inst/rmarkdown/templates/data_dict_html/skeleton/skeleton.Rmd b/inst/rmarkdown/templates/data_dict_html/skeleton/skeleton.Rmd index 805a048..70f836a 100644 --- a/inst/rmarkdown/templates/data_dict_html/skeleton/skeleton.Rmd +++ b/inst/rmarkdown/templates/data_dict_html/skeleton/skeleton.Rmd @@ -1,9 +1,9 @@ --- title: "Data Dictionary" author: | - | Project: `r CIDAtools::ProjectName()` - | Analyst: `r CIDAtools::ProjectAnalyst()` - | Investigator(s): `r CIDAtools::ProjectPI()` + | Project: `r CIDAtools::get_project_name()` + | Analyst: `r CIDAtools::get_project_analyst()` + | Investigator(s): `r CIDAtools::get_project_pi()` | Date generated: `r paste(format(Sys.Date(), '%B %d, %Y'))` output: html_document: diff --git a/inst/rmarkdown/templates/report_html/skeleton/skeleton.Rmd b/inst/rmarkdown/templates/report_html/skeleton/skeleton.Rmd index b029dcd..6dbcc97 100755 --- a/inst/rmarkdown/templates/report_html/skeleton/skeleton.Rmd +++ b/inst/rmarkdown/templates/report_html/skeleton/skeleton.Rmd @@ -1,11 +1,11 @@ --- title: Report author: | - | Project: `r CIDAtools::ProjectName()` + | Project: `r CIDAtools::get_project_name()` | - | Analyst: `r CIDAtools::ProjectAnalyst()` + | Analyst: `r CIDAtools::get_project_analyst()` | - | Investigator(s): `r CIDAtools::ProjectPI()` + | Investigator(s): `r CIDAtools::get_project_pi()` | | Report generated: `r paste(format(Sys.Date(), '%B %d, %Y'))` output: diff --git a/inst/rmarkdown/templates/report_pdf/skeleton/skeleton.Rmd b/inst/rmarkdown/templates/report_pdf/skeleton/skeleton.Rmd index 95ed1d1..7276b44 100755 --- a/inst/rmarkdown/templates/report_pdf/skeleton/skeleton.Rmd +++ b/inst/rmarkdown/templates/report_pdf/skeleton/skeleton.Rmd @@ -34,9 +34,9 @@ library(kableExtra) library(CIDAtools) ``` -**Project**: `r CIDAtools::ProjectName()` \newline -**Analyst**: `r CIDAtools::ProjectAnalyst()`\newline -**Investigator(s)**: `r CIDAtools::ProjectPI()`\newline +**Project**: `r CIDAtools::get_project_name()` \newline +**Analyst**: `r CIDAtools::get_project_analyst()`\newline +**Investigator(s)**: `r CIDAtools::get_project_pi()`\newline **Report generated**: `r paste(format(Sys.Date(), '%B %d, %Y'))`\newline diff --git a/man/CIDA_drive_path.Rd b/man/CIDA_drive_path.Rd index a4d2253..0f2f987 100644 --- a/man/CIDA_drive_path.Rd +++ b/man/CIDA_drive_path.Rd @@ -1,25 +1,34 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/cida_drive_path.R +% Please edit documentation in R/temp_refactored_message.R \name{CIDA_drive_path} \alias{CIDA_drive_path} -\title{Get CIDA drive path} +\title{Get Project drive path} \usage{ CIDA_drive_path(file = "") } \arguments{ -\item{file}{(optional) Path to subdirectory/file within CIDA drive} +\item{file}{(optional) Path to subdirectory/file within the main project(CIDA) drive} } \value{ -Full (absolute) file path of CIDA drive +Full (absolute) file path of project(CIDA) drive plus the subdirectory/file provided. } \description{ -This function attempts to get the proper path for the CIDA drive either on -Windows or Mac. +This function attempts to get the proper path for the Project(CIDA) drive either on +Windows or Mac automatically. It returns the full CIDA drive(remote) path +with the relative path (if provided) appended to the drive path. +} +\details{ +If open_project() has been called with a remote path specified the remote path +will be used first. + +If that is not set it will try to determine the drive path. If the expected +path is not found it will try to load the project metadata path and if that +fails it looks for a global default path in the user cida_defaults.dcf file. } \examples{ # Read data from P1234PIname project \dontrun{ -df <- read.csv(CIDA_drive_path("BRANCHES/Pulmonary/P1234PIname/DataRaw/data.csv")) +df <- read.csv(get_project_drive_path("BRANCHES/Pulmonary/P1234PIname/DataRaw/data.csv")) } } diff --git a/man/ProjectAnalyst.Rd b/man/ProjectAnalyst.Rd index 882ad9a..babf32f 100644 --- a/man/ProjectAnalyst.Rd +++ b/man/ProjectAnalyst.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{ProjectAnalyst} \alias{ProjectAnalyst} \title{Get Project Analyst} @@ -14,6 +14,3 @@ This function returns the Project Analyst Name. If none exists, it will return the value of CIDAtools.analyst option or blank if the option is not set. } -\keyword{Analyst} -\keyword{ProjData} -\keyword{options} diff --git a/man/ProjectLocation.Rd b/man/ProjectLocation.Rd index 1f91ba6..ed56d11 100644 --- a/man/ProjectLocation.Rd +++ b/man/ProjectLocation.Rd @@ -1,13 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{ProjectLocation} \alias{ProjectLocation} \title{Get Project data location on CIDA Drive} \usage{ -ProjectLocation(path = "") -} -\arguments{ -\item{path}{(optional) a relative path to a particular place in the project} +ProjectLocation() } \value{ full (absolute) file path including the project location on CIDA drive diff --git a/man/ProjectName.Rd b/man/ProjectName.Rd index e8d47cc..3f933a0 100644 --- a/man/ProjectName.Rd +++ b/man/ProjectName.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{ProjectName} \alias{ProjectName} \title{Get Project Name} @@ -12,6 +12,3 @@ A character string with the project name \description{ This function returns the Project Name or blank if none exists. } -\keyword{ProjData} -\keyword{ProjectName} -\keyword{options} diff --git a/man/ProjectPI.Rd b/man/ProjectPI.Rd index 7317cf0..df5bff0 100644 --- a/man/ProjectPI.Rd +++ b/man/ProjectPI.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{ProjectPI} \alias{ProjectPI} \title{Get PI Name} @@ -12,6 +12,3 @@ A character string with the PI name \description{ This function returns the PI Name or blank if none exists. } -\keyword{PI} -\keyword{ProjData} -\keyword{options} diff --git a/man/Round.Rd b/man/Round.Rd index 9fbfe7e..2765ad4 100644 --- a/man/Round.Rd +++ b/man/Round.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/misc_fns.R \name{Round} \alias{Round} -\title{Round and don't drop trailing zeros} +\title{Round and don't drop trailing zeros - To be deprecated} \usage{ Round(x, n) } diff --git a/man/SetProjectAnalyst.Rd b/man/SetProjectAnalyst.Rd index 883653a..7112187 100644 --- a/man/SetProjectAnalyst.Rd +++ b/man/SetProjectAnalyst.Rd @@ -1,13 +1,13 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{SetProjectAnalyst} \alias{SetProjectAnalyst} \title{Set Project Analyst} \usage{ -SetProjectAnalyst(AnalystName) +SetProjectAnalyst(analyst_name) } \arguments{ -\item{AnalystName}{A string containing the analyst name} +\item{analyst_name}{A string containing the analyst name} } \value{ A message stating the name has been changed. @@ -16,6 +16,3 @@ A message stating the name has been changed. This function allows you to set the project analyst. This will overwrite the current value if exists. } -\keyword{Analyst} -\keyword{ProjData} -\keyword{options} diff --git a/man/SetProjectData.Rd b/man/SetProjectData.Rd index 20b86e0..c6842d1 100644 --- a/man/SetProjectData.Rd +++ b/man/SetProjectData.Rd @@ -1,15 +1,15 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{SetProjectData} \alias{SetProjectData} \title{Set data for project} \usage{ -SetProjectData(Parameter, Value) +SetProjectData(parameter, value) } \arguments{ -\item{Parameter}{Project Parameter to be set} +\item{parameter}{Project Parameter to be set} -\item{Value}{Value to set to project parameter} +\item{value}{Value to set to project parameter} } \description{ Allows you to set misc project data parameters diff --git a/man/SetProjectLocation.Rd b/man/SetProjectLocation.Rd index 15f710c..5bebea3 100644 --- a/man/SetProjectLocation.Rd +++ b/man/SetProjectLocation.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{SetProjectLocation} \alias{SetProjectLocation} \title{Set Project Location} @@ -16,6 +16,3 @@ A message stating the name has been changed. This function allows you to set the Project's location on the CIDA drive. This will overwrite the current value if exists. } -\keyword{ProjData} -\keyword{location} -\keyword{options} diff --git a/man/SetProjectName.Rd b/man/SetProjectName.Rd index f123856..720bb87 100644 --- a/man/SetProjectName.Rd +++ b/man/SetProjectName.Rd @@ -1,13 +1,13 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{SetProjectName} \alias{SetProjectName} \title{Set Project Name} \usage{ -SetProjectName(ProjectName) +SetProjectName(project_name) } \arguments{ -\item{ProjectName}{A string containing the analyst name} +\item{project_name}{A string containing the analyst name} } \value{ A message stating the name has been changed. @@ -16,6 +16,3 @@ A message stating the name has been changed. This function allows you to set the project name. This will overwrite the current value if exists. } -\keyword{ProjData} -\keyword{ProjectName} -\keyword{options} diff --git a/man/SetProjectPI.Rd b/man/SetProjectPI.Rd index 44a1bd1..e6f79a9 100644 --- a/man/SetProjectPI.Rd +++ b/man/SetProjectPI.Rd @@ -1,13 +1,13 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{SetProjectPI} \alias{SetProjectPI} \title{Set PI Name} \usage{ -SetProjectPI(PI) +SetProjectPI(pi) } \arguments{ -\item{PI}{A string containing the analyst name} +\item{pi}{A string containing the analyst name} } \value{ A message stating the name has been changed. @@ -16,6 +16,3 @@ A message stating the name has been changed. This function allows you to set the Project's PI. This will overwrite the current value if exists. } -\keyword{PI} -\keyword{ProjData} -\keyword{options} diff --git a/man/backup_project.Rd b/man/backup_project.Rd index c86452e..a8ec040 100644 --- a/man/backup_project.Rd +++ b/man/backup_project.Rd @@ -1,8 +1,8 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/backup_project.R +% Please edit documentation in R/project.R \name{backup_project} \alias{backup_project} -\title{Backup Project Directory} +\title{pull project files from remote directory} \usage{ backup_project( path_from = getwd(), @@ -35,6 +35,9 @@ This function has verbose output to ensure the back up is working, and ultimately returns a success indicator that's returned by file.copy. } \description{ +Backup Project Directory +} +\details{ This function backs up a CIDA project to the shared (P) CIDA drive. The backup directory can either be existing (in which only changed files/folders are updated), or nonexisting, in which case a full project backup is created. diff --git a/man/cida_table1.Rd b/man/cida_table1.Rd index 8ded192..dd9eb02 100644 --- a/man/cida_table1.Rd +++ b/man/cida_table1.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/cida_table1.R \name{cida_table1} \alias{cida_table1} -\title{Create a table one} +\title{Create a table one - To be deprecated} \usage{ cida_table1( data, diff --git a/man/convertIntervalNotation.Rd b/man/convertIntervalNotation.Rd index c5f26ae..013dfed 100644 --- a/man/convertIntervalNotation.Rd +++ b/man/convertIntervalNotation.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/misc_fns.R \name{convertIntervalNotation} \alias{convertIntervalNotation} -\title{Convert Interval Notation} +\title{Convert Interval Notation - To be deprecated} \usage{ convertIntervalNotation(x) } diff --git a/man/create_project.Rd b/man/create_project.Rd index ef5e821..b8e39a5 100644 --- a/man/create_project.Rd +++ b/man/create_project.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/create_project.R +% Please edit documentation in R/project.R \name{create_project} \alias{create_project} \title{Create Project Directory + readme files} @@ -8,11 +8,11 @@ create_project( path = getwd(), template = c("Admin", "Background", "Code", "DataRaw", "DataProcessed", "Dissemination", "Reports"), - ProjectName = "", - PI = "", - analyst = "", - datalocation = "", - gitlocation = "" + project_name, + pi = "", + analyst, + data_location = "", + git_location = "" ) } \arguments{ @@ -20,15 +20,15 @@ create_project( \item{template}{Which subdirectories to create} -\item{ProjectName}{Name of project, or "" for blank} +\item{project_name}{Name of project, (required)} -\item{PI}{Name of PI and credentials, or "" for blank} +\item{pi}{Name of PI and credentials, or "" for blank} -\item{analyst}{Name of Analyst(s), or "" for blank} +\item{analyst}{Name of Analyst(s), (required)} -\item{datalocation}{Location of project on CIDA Drive, or "" for blank} +\item{data_location}{Location of project on CIDA Drive, or "" for blank} -\item{gitlocation}{Location project on GitHub} +\item{git_location}{Location project on GitHub} } \value{ This function creates the desired project subdirectories and readmes, diff --git a/man/find_nearest.Rd b/man/find_nearest.Rd index dee74b6..12826ff 100644 --- a/man/find_nearest.Rd +++ b/man/find_nearest.Rd @@ -3,7 +3,7 @@ \name{find_nearest} \alias{find_nearest} \alias{getlower} -\title{Find the nearest observation to another observation} +\title{Find the nearest observation to another observation - To be deprecated} \usage{ find_nearest( x, diff --git a/man/getProjectData.Rd b/man/getProjectData.Rd index 4d0163f..03a7535 100644 --- a/man/getProjectData.Rd +++ b/man/getProjectData.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/project_meta_data.R +% Please edit documentation in R/temp_refactored_message.R \name{getProjectData} \alias{getProjectData} \title{Get data for project} @@ -7,8 +7,24 @@ getProjectData(param) } \arguments{ -\item{param}{Project parameter to be gotten} +\item{param}{Project parameter to return or if not specified to return all parameter/value pairs.} } \description{ -Allows you to get misc project data parameters +Allows you to get any project data parameters or all parameters. Either specify +the desired parameter or with no parameter it will return all available parameters. +} +\details{ +Possible parameters values include: + + - analyst - Analyst's Name + + - ProjectName - Project Name + + - PI - PI Name + + - datalocation - Poject folder location under the CIDA PATH. + + - default_full_path_to_project - Project default path which is the default full path to the project files. Includes the local filesystem path to network mount point and network path to project folder. + + - gitlocation - GitHub URL for the project code } diff --git a/man/get_default_value.Rd b/man/get_default_value.Rd new file mode 100644 index 0000000..5121b26 --- /dev/null +++ b/man/get_default_value.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default.R +\name{get_default_value} +\alias{get_default_value} +\title{Get a specific user level default} +\usage{ +get_default_value(parameter) +} +\arguments{ +\item{parameter}{The name of the specific parameter to lookup.} +} +\value{ +The user level defaults named parameter +} +\description{ +This function returns a specific user level defaults set in ~/cida_defaults.dcf +} +\keyword{options} +\keyword{path} diff --git a/man/get_defaults.Rd b/man/get_defaults.Rd new file mode 100644 index 0000000..f70580c --- /dev/null +++ b/man/get_defaults.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default.R +\name{get_defaults} +\alias{get_defaults} +\title{Get a list of all user level defaults} +\usage{ +get_defaults() +} +\value{ +The user level defaults +} +\description{ +This function returns the user level defaults set in ~/cida_defaults.dcf +} +\keyword{options} +\keyword{path} diff --git a/man/get_full_project_path.Rd b/man/get_full_project_path.Rd new file mode 100644 index 0000000..53d72a7 --- /dev/null +++ b/man/get_full_project_path.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{get_full_project_path} +\alias{get_full_project_path} +\title{Gets the currently set full path to the project from .ProjData/Data.dcf} +\usage{ +get_full_project_path() +} +\value{ +full path to project +} +\description{ +Gets the currently set full path to the project from .ProjData/Data.dcf +} diff --git a/man/get_global_default_analyst.Rd b/man/get_global_default_analyst.Rd new file mode 100644 index 0000000..6ac9655 --- /dev/null +++ b/man/get_global_default_analyst.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default.R +\name{get_global_default_analyst} +\alias{get_global_default_analyst} +\title{Get Default Analyst Value} +\usage{ +get_global_default_analyst() +} +\value{ +The default analyst or an empty string if not set. +} +\description{ +This function allows you to get the default analyst. +} +\keyword{Analyst} +\keyword{options} diff --git a/man/get_global_default_path.Rd b/man/get_global_default_path.Rd new file mode 100644 index 0000000..c81cf7c --- /dev/null +++ b/man/get_global_default_path.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default.R +\name{get_global_default_path} +\alias{get_global_default_path} +\title{Get Default drive path} +\usage{ +get_global_default_path() +} +\value{ +The default path +} +\description{ +This function returns the user level default drive path set in ~/cida_defaults.dcf +} +\keyword{options} +\keyword{path} diff --git a/man/get_project_analyst.Rd b/man/get_project_analyst.Rd new file mode 100644 index 0000000..d995998 --- /dev/null +++ b/man/get_project_analyst.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{get_project_analyst} +\alias{get_project_analyst} +\title{Get Project Analyst} +\usage{ +get_project_analyst() +} +\value{ +A character string with the analyst name +} +\description{ +This function returns the Project Analyst Name. If none exists, it +will return the value of CIDAtools.analyst option or blank if the option +is not set. +} +\keyword{Analyst} +\keyword{ProjData} +\keyword{options} diff --git a/man/get_project_drive_path.Rd b/man/get_project_drive_path.Rd new file mode 100644 index 0000000..e67c484 --- /dev/null +++ b/man/get_project_drive_path.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project.R +\name{get_project_drive_path} +\alias{get_project_drive_path} +\title{Get Project drive path} +\usage{ +get_project_drive_path(file = "") +} +\arguments{ +\item{file}{(optional) Path to subdirectory/file within the main project(CIDA) drive} +} +\value{ +Full (absolute) file path of project(CIDA) drive plus the subdirectory/file provided. +} +\description{ +This function attempts to get the proper path for the Project(CIDA) drive either on +Windows or Mac automatically. It returns the full CIDA drive(remote) path +with the relative path (if provided) appended to the drive path. +} +\details{ +If open_project() has been called with a remote path specified the remote path +will be used first. + +If that is not set it will try to determine the drive path. If the expected +path is not found it will try to load the project metadata path and if that +fails it looks for a global default path in the user cida_defaults.dcf file. +} +\examples{ +# Read data from P1234PIname project +\dontrun{ +df <- read.csv(get_project_drive_path("BRANCHES/Pulmonary/P1234PIname/DataRaw/data.csv")) +} + +} diff --git a/man/get_project_github.Rd b/man/get_project_github.Rd new file mode 100644 index 0000000..62147b4 --- /dev/null +++ b/man/get_project_github.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{get_project_github} +\alias{get_project_github} +\title{Get Project GitHub Location} +\usage{ +get_project_github() +} +\value{ +A character string with the project GitHub +} +\description{ +This function returns the Project GitHub location or blank if it's not set. +} +\keyword{ProjData} +\keyword{ProjectGitHub} +\keyword{options} diff --git a/man/get_project_location.Rd b/man/get_project_location.Rd new file mode 100644 index 0000000..645b6e7 --- /dev/null +++ b/man/get_project_location.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{get_project_location} +\alias{get_project_location} +\title{Get Project data location on CIDA Drive} +\usage{ +get_project_location(path = "") +} +\arguments{ +\item{path}{(optional) a relative path to a particular place in the project} +} +\value{ +full (absolute) file path including the project location on CIDA drive +} +\description{ +Get Project data location on CIDA Drive +} +\examples{ +# Read data from current project +\dontrun{ +df <- read.csv(ProjectLocation("DataRaw/my_proj_data.csv")) +} + +} diff --git a/man/get_project_meta_data.Rd b/man/get_project_meta_data.Rd new file mode 100644 index 0000000..f31da4a --- /dev/null +++ b/man/get_project_meta_data.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{get_project_meta_data} +\alias{get_project_meta_data} +\title{Get data for project} +\usage{ +get_project_meta_data(param = "") +} +\arguments{ +\item{param}{Project parameter to return or if not specified to return all parameter/value pairs.} +} +\description{ +Allows you to get any project data parameters or all parameters. Either specify +the desired parameter or with no parameter it will return all available parameters. +} +\details{ +Possible parameters values include: + + - analyst - Analyst's Name + + - ProjectName - Project Name + + - PI - PI Name + + - datalocation - Poject folder location under the CIDA PATH. + + - default_full_path_to_project - Project default path which is the default full path to the project files. Includes the local filesystem path to network mount point and network path to project folder. + + - gitlocation - GitHub URL for the project code +} diff --git a/man/get_project_name.Rd b/man/get_project_name.Rd new file mode 100644 index 0000000..b333c4f --- /dev/null +++ b/man/get_project_name.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{get_project_name} +\alias{get_project_name} +\title{Get Project Name} +\usage{ +get_project_name() +} +\value{ +A character string with the project name +} +\description{ +This function returns the Project Name or blank if none exists. +} +\keyword{ProjData} +\keyword{ProjectName} +\keyword{options} diff --git a/man/get_project_pi.Rd b/man/get_project_pi.Rd new file mode 100644 index 0000000..6ab6300 --- /dev/null +++ b/man/get_project_pi.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{get_project_pi} +\alias{get_project_pi} +\title{Get PI Name} +\usage{ +get_project_pi() +} +\value{ +A character string with the PI name +} +\description{ +This function returns the PI Name or blank if none exists. +} +\keyword{PI} +\keyword{ProjData} +\keyword{options} diff --git a/man/list_kables.Rd b/man/list_kables.Rd index d796e2a..fe84d02 100644 --- a/man/list_kables.Rd +++ b/man/list_kables.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/reporting_fns.R \name{list_kables} \alias{list_kables} -\title{List tables with the same columns} +\title{List tables with the same columns - To be deprecated} \usage{ list_kables(tabs, bo = c("striped", "condensed"), ...) } diff --git a/man/nLevelsP.Rd b/man/nLevelsP.Rd index 8296816..bac292e 100644 --- a/man/nLevelsP.Rd +++ b/man/nLevelsP.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/misc_fns.R \name{nLevelsP} \alias{nLevelsP} -\title{Get pretty number of levels} +\title{Get pretty number of levels - To be deprecated} \usage{ nLevelsP(x) } diff --git a/man/nrowP.Rd b/man/nrowP.Rd index 08f9f02..6becb84 100644 --- a/man/nrowP.Rd +++ b/man/nrowP.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/misc_fns.R \name{nrowP} \alias{nrowP} -\title{Get pretty numbers of rows} +\title{Get pretty numbers of rows - To be deprecated} \usage{ nrowP(x) } diff --git a/man/open_project.Rd b/man/open_project.Rd new file mode 100644 index 0000000..140ba9a --- /dev/null +++ b/man/open_project.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project.R +\name{open_project} +\alias{open_project} +\title{Open Project +This function sets up the project to work on so the paths can easily be determined. +When both paths are specified path functions will reference the local copy. +When one is specified path functions will reference the local or remote copy whichever was specified. +Future updates will add some functionality to automate tasks.} +\usage{ +open_project(local_project_folder = "", remote_project_folder = "") +} +\arguments{ +\item{local_project_folder}{This is a local copy of the project folder} + +\item{remote_project_folder}{This is the location of the shared drive copy of the project folder} +} +\description{ +Open Project +This function sets up the project to work on so the paths can easily be determined. +When both paths are specified path functions will reference the local copy. +When one is specified path functions will reference the local or remote copy whichever was specified. +Future updates will add some functionality to automate tasks. +} diff --git a/man/pvalr.Rd b/man/pvalr.Rd index 0666344..b9dd867 100644 --- a/man/pvalr.Rd +++ b/man/pvalr.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/reporting_fns.R \name{pvalr} \alias{pvalr} -\title{Pretty p-values} +\title{Pretty p-values - To be deprecated} \usage{ pvalr(pvals, sig.limit = 0.001, digits = 3, html = FALSE, equal_sign = "") } diff --git a/man/pvalue.Rd b/man/pvalue.Rd index 26f8a24..3b3567c 100644 --- a/man/pvalue.Rd +++ b/man/pvalue.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/cida_table1.R \name{pvalue} \alias{pvalue} -\title{Internal function for p-value calculation in cida_table1} +\title{Internal function for p-value calculation in cida_table1 - To be deprecated} \usage{ pvalue( x, @@ -27,5 +27,5 @@ across grouped variables.} use non-parametric hypothesis testing} } \description{ -Internal function for p-value calculation in cida_table1 +Internal function for p-value calculation in cida_table1 - To be deprecated } diff --git a/man/randblinder_shiny_tool.Rd b/man/randblinder_shiny_tool.Rd index 4bd408f..02b6185 100644 --- a/man/randblinder_shiny_tool.Rd +++ b/man/randblinder_shiny_tool.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/randomizer_and_blinder_app.R \name{randblinder_shiny_tool} \alias{randblinder_shiny_tool} -\title{Randomizer and blinder tool} +\title{Randomizer and blinder tool - To be deprecated} \usage{ randblinder_shiny_tool() } diff --git a/man/read_xlsx_color.Rd b/man/read_xlsx_color.Rd index 7488d40..b5da1c3 100644 --- a/man/read_xlsx_color.Rd +++ b/man/read_xlsx_color.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/read_xlsx_color.R \name{read_xlsx_color} \alias{read_xlsx_color} -\title{Read in xlsx with fill colour} +\title{Read in xlsx with fill colour - To be deprecated} \usage{ read_xlsx_color(file, colorColumns, sheet = NULL, header = T) } diff --git a/man/removeAnalyst.Rd b/man/removeAnalyst.Rd index 8f4a0b4..d9c34e8 100644 --- a/man/removeAnalyst.Rd +++ b/man/removeAnalyst.Rd @@ -1,21 +1,15 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/misc_fns.R +% Please edit documentation in R/temp_refactored_message.R \name{removeAnalyst} \alias{removeAnalyst} -\title{Remove Default Analyst from ~/.Rprofile} +\title{Remove Default Analyst from ~/cida_defaults.dcf} \usage{ -removeAnalyst(quiet = F) -} -\arguments{ -\item{quiet}{should a message indicating result be returned, if TRUE will only -return TRUE or FALSE} +removeAnalyst() } \value{ -Message indicating sucess or failue +Message indicating success or failure } \description{ -This function removes the default analyst set with setAnalyst() from the users -.Rprofile. If this is the only entry in .Rprofile it will remove the file as well. +This function removes the default analyst set with set_global_default_analyst() + from the users ~/cida_defaults.dcf. } -\keyword{Analyst} -\keyword{remove} diff --git a/man/remove_global_default_analyst.Rd b/man/remove_global_default_analyst.Rd new file mode 100644 index 0000000..9ece61b --- /dev/null +++ b/man/remove_global_default_analyst.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default.R +\name{remove_global_default_analyst} +\alias{remove_global_default_analyst} +\title{Remove Default Analyst from ~/cida_defaults.dcf} +\usage{ +remove_global_default_analyst() +} +\value{ +Message indicating success or failure +} +\description{ +This function removes the default analyst set with set_global_default_analyst() + from the users ~/cida_defaults.dcf. +} +\keyword{Analyst} +\keyword{remove} diff --git a/man/remove_global_default_path.Rd b/man/remove_global_default_path.Rd new file mode 100644 index 0000000..27afa31 --- /dev/null +++ b/man/remove_global_default_path.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default.R +\name{remove_global_default_path} +\alias{remove_global_default_path} +\title{removes the default drive path in ~/cida_defaults.dcf} +\usage{ +remove_global_default_path() +} +\description{ +This function removed the default path at the user level to access the project +drive. +} diff --git a/man/setAnalyst.Rd b/man/setAnalyst.Rd index 2257e4b..0f77a29 100644 --- a/man/setAnalyst.Rd +++ b/man/setAnalyst.Rd @@ -1,21 +1,18 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/misc_fns.R +% Please edit documentation in R/temp_refactored_message.R \name{setAnalyst} \alias{setAnalyst} -\title{Set Default Analyst Value} +\title{Set Project Analyst} \usage{ -setAnalyst(AnalystName) +setAnalyst(analyst_name) } \arguments{ -\item{AnalystName}{A string containing the analyst name} +\item{analyst_name}{A string containing the analyst name} } \value{ A message stating the name has been changed. } \description{ -This function allows you to set the option CIDAtools.analyst permanently -(until you change it or reinstall CIDAtools) and will -simultanesouly change the default in New Cida Project Template. +This function allows you to set the project analyst. +This will overwrite the current value if exists. } -\keyword{Analyst} -\keyword{options} diff --git a/man/setPermanentAnalyst.Rd b/man/setPermanentAnalyst.Rd index 6d8c4d2..82e8dc0 100644 --- a/man/setPermanentAnalyst.Rd +++ b/man/setPermanentAnalyst.Rd @@ -1,15 +1,20 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/misc_fns.R +% Please edit documentation in R/temp_refactored_message.R \name{setPermanentAnalyst} \alias{setPermanentAnalyst} -\title{Set Default Analyst Value} +\title{Set Global Default Analyst Value} \usage{ -setPermanentAnalyst(Name) +setPermanentAnalyst(analyst_name, update_template = FALSE) } \arguments{ -\item{Name}{A string containing the analyst name} +\item{analyst_name}{A string containing the analyst name} + +\item{update_template}{Bool whether or not to update analyst in the project template.} +} +\value{ +A message stating the name has been changed. } \description{ -This is an internal function that writes the Default Analyst name to the -users Rprofile. +This function allows you to set the default analyst at the user level and +if possible changes the default analyst in the template for new projects. } diff --git a/man/set_default_value.Rd b/man/set_default_value.Rd new file mode 100644 index 0000000..57ab7d9 --- /dev/null +++ b/man/set_default_value.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default.R +\name{set_default_value} +\alias{set_default_value} +\title{Sets a default parameter in ~/cida_defaults.dcf} +\usage{ +set_default_value(parameter, value) +} +\arguments{ +\item{parameter}{parameter name} + +\item{value}{new value} +} +\description{ +This function sets a default parameter at the user level. +} diff --git a/man/set_full_project_path.Rd b/man/set_full_project_path.Rd new file mode 100644 index 0000000..62883c3 --- /dev/null +++ b/man/set_full_project_path.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{set_full_project_path} +\alias{set_full_project_path} +\title{Sets the default full path to the project.} +\usage{ +set_full_project_path(path = "") +} +\arguments{ +\item{path}{full path to the project folder} +} +\value{ +message indicating the path has been saved. +} +\description{ +Sets the default full path to the project. +} diff --git a/man/set_global_default_analyst.Rd b/man/set_global_default_analyst.Rd new file mode 100644 index 0000000..e437e58 --- /dev/null +++ b/man/set_global_default_analyst.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default.R +\name{set_global_default_analyst} +\alias{set_global_default_analyst} +\title{Set Global Default Analyst Value} +\usage{ +set_global_default_analyst(analyst_name, update_template = FALSE) +} +\arguments{ +\item{analyst_name}{A string containing the analyst name} + +\item{update_template}{Bool whether or not to update analyst in the project template.} +} +\value{ +A message stating the name has been changed. +} +\description{ +This function allows you to set the default analyst at the user level and +if possible changes the default analyst in the template for new projects. +} +\keyword{Analyst} +\keyword{options} diff --git a/man/set_global_default_path.Rd b/man/set_global_default_path.Rd new file mode 100644 index 0000000..f32ecf8 --- /dev/null +++ b/man/set_global_default_path.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default.R +\name{set_global_default_path} +\alias{set_global_default_path} +\title{Sets a default drive path in ~/cida_defaults.dcf} +\usage{ +set_global_default_path(path = "") +} +\arguments{ +\item{path}{Path to the main project(CIDA) drive} +} +\value{ +Message that path was set. +} +\description{ +This function sets a default path at the user level to access the project +drive. If the drive is not detected automatically this file will be used to +set a default path if set. +} diff --git a/man/set_project_analyst.Rd b/man/set_project_analyst.Rd new file mode 100644 index 0000000..352217d --- /dev/null +++ b/man/set_project_analyst.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{set_project_analyst} +\alias{set_project_analyst} +\title{Set Project Analyst} +\usage{ +set_project_analyst(analyst_name) +} +\arguments{ +\item{analyst_name}{A string containing the analyst name} +} +\value{ +A message stating the name has been changed. +} +\description{ +This function allows you to set the project analyst. +This will overwrite the current value if exists. +} +\keyword{Analyst} +\keyword{ProjData} +\keyword{options} diff --git a/man/set_project_github.Rd b/man/set_project_github.Rd new file mode 100644 index 0000000..913e57d --- /dev/null +++ b/man/set_project_github.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{set_project_github} +\alias{set_project_github} +\title{Set Project GitHub Location} +\usage{ +set_project_github(git_url = "") +} +\arguments{ +\item{git_url}{A string containing the URL to the GitHub repository for this project.} +} +\value{ +A message stating the name has been changed. +} +\description{ +This function allows you to set the Project's GitHub location. +This will overwrite the current value if exists. +} +\keyword{ProjData} +\keyword{location} +\keyword{options} diff --git a/man/set_project_location.Rd b/man/set_project_location.Rd new file mode 100644 index 0000000..37e85dd --- /dev/null +++ b/man/set_project_location.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{set_project_location} +\alias{set_project_location} +\title{Set Project Location} +\usage{ +set_project_location(path) +} +\arguments{ +\item{path}{A string containing the file path to the project location on CIDA drive} +} +\value{ +A message stating the name has been changed. +} +\description{ +This function allows you to set the Project's location on the CIDA drive. +This will overwrite the current value if exists. +} +\keyword{ProjData} +\keyword{location} +\keyword{options} diff --git a/man/set_project_meta_data.Rd b/man/set_project_meta_data.Rd new file mode 100644 index 0000000..49250a7 --- /dev/null +++ b/man/set_project_meta_data.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{set_project_meta_data} +\alias{set_project_meta_data} +\title{Set data for project} +\usage{ +set_project_meta_data(parameter, value) +} +\arguments{ +\item{parameter}{Project Parameter to be set} + +\item{value}{Value to set to project parameter} +} +\description{ +Allows you to set misc project data parameters +for Project Name, Analyst, or PI recommend you use specific function +} diff --git a/man/set_project_name.Rd b/man/set_project_name.Rd new file mode 100644 index 0000000..9d68219 --- /dev/null +++ b/man/set_project_name.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{set_project_name} +\alias{set_project_name} +\title{Set Project Name} +\usage{ +set_project_name(project_name) +} +\arguments{ +\item{project_name}{A string containing the analyst name} +} +\value{ +A message stating the name has been changed. +} +\description{ +This function allows you to set the project name. This will overwrite the +current value if exists. +} +\keyword{ProjData} +\keyword{ProjectName} +\keyword{options} diff --git a/man/set_project_pi.Rd b/man/set_project_pi.Rd new file mode 100644 index 0000000..31e1e25 --- /dev/null +++ b/man/set_project_pi.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/project_meta_data.R +\name{set_project_pi} +\alias{set_project_pi} +\title{Set PI Name} +\usage{ +set_project_pi(pi) +} +\arguments{ +\item{pi}{A string containing the analyst name} +} +\value{ +A message stating the name has been changed. +} +\description{ +This function allows you to set the Project's PI. This will overwrite the +current value if exists. +} +\keyword{PI} +\keyword{ProjData} +\keyword{options} diff --git a/man/sum_ignore_NA.Rd b/man/sum_ignore_NA.Rd index 90b2692..c037d37 100644 --- a/man/sum_ignore_NA.Rd +++ b/man/sum_ignore_NA.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/misc_fns.R \name{sum_ignore_NA} \alias{sum_ignore_NA} -\title{Sum ignoring NAs} +\title{Sum ignoring NAs - To be deprecated} \usage{ sum_ignore_NA(...) } diff --git a/man/tidy.power.htest.Rd b/man/tidy.power.htest.Rd new file mode 100644 index 0000000..a0d43c9 --- /dev/null +++ b/man/tidy.power.htest.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/misc_fns.R +\name{tidy.power.htest} +\alias{tidy.power.htest} +\title{Helper for pwr package version of power fns. - To be deprecated} +\usage{ +\method{tidy}{power.htest}(x, ...) +} +\arguments{ +\item{x}{description} + +\item{...}{description} +} +\description{ +Helper for pwr package version of power fns. - To be deprecated +} diff --git a/man/vec_power.Rd b/man/vec_power.Rd index 6f9ddea..60917e8 100644 --- a/man/vec_power.Rd +++ b/man/vec_power.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/misc_fns.R \name{vec_power} \alias{vec_power} -\title{Vectorized power estimates} +\title{Vectorized power estimates - To be deprecated} \usage{ vec_power(fun = stats::power.t.test, ...) } diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..3bfc391 --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(CIDAtools) + +test_check("CIDAtools") diff --git a/tests/testthat/test_default.R b/tests/testthat/test_default.R new file mode 100644 index 0000000..f06d2f6 --- /dev/null +++ b/tests/testthat/test_default.R @@ -0,0 +1,83 @@ +home_dir <- fs::path_home() +temp_path <-fs::path_join(c(home_dir,"/cida_defaults.dcf")) + + +test_that("create temporary dcf file and test reading it", { + dcf_content <- list( path="~/test_drive", analyst_name="Analyst Name") + write.dcf(dcf_content, file.path(temp_path)) + + # Process the DCF file using your function + default_data <- read_global_defaults() + + # Expectations + expect_equal(default_data$path, "~/test_drive") + expect_equal(default_data$analyst_name, "Analyst Name") + + + # Clean up the temporary file + #unlink(temp_dcf_file) +}) + +test_that("test getter functions", { + + default_data <- get_defaults() + + # Expectations + expect_equal(default_data$path, "~/test_drive") + expect_equal(default_data$analyst_name, "Analyst Name") + +}) + +test_that("test getter functions", { + + analyst_name <- get_default_value("analyst_name") + expect_equal(analyst_name, "Analyst Name") + + path <- get_global_default_path() + analyst_name <- get_global_default_analyst() + # Expectations + expect_equal(path, "~/test_drive") + expect_equal(analyst_name, "Analyst Name") + + + expect_warning(non_existent <- get_default_value("name"),"Parameter:name does not exist in default values.") + expect_equal(non_existent,'') + +}) + +test_that("test setter functions",{ + msg1 <- set_global_default_analyst("Analyst Name2") + msg2 <- set_global_default_path("~/test_drive2") + expect_equal(msg1,"The default analyst name has been changed to Analyst Name2") + expect_equal(msg2,"The default project path has been changed to ~/test_drive2") + + path <- get_global_default_path() + analyst_name <- get_global_default_analyst() + expect_equal(path, "~/test_drive2") + expect_equal(analyst_name, "Analyst Name2") + +}) + +test_that("test remove functions",{ + remove_global_default_path() + remove_global_default_analyst() + path <- get_global_default_path() + expect_warning(analyst_name <- get_global_default_analyst(),"Parameter:analyst_name does not exist in default values.") + expect_equal(path, "") + expect_equal(analyst_name, "") +}) + + +test_that("test updating the template with set_global_default_analyst",{ + msg1 <- set_global_default_analyst("Analyst Name3",update_template=FALSE) + expect_equal(msg1,"The default analyst name has been changed to Analyst Name3") +}) + +unlink(temp_path) + +test_that("test getting values after deletion",{ + w <- capture_warnings(path <- get_global_default_path()) + expect_match(w, "~/cida_defaults\\.dcf at full path:.*cida_defaults\\.dcf does not exist\\.\\nNothing was loaded\\.",fixed=FALSE, all = FALSE) + expect_match(w, "Parameter:path does not exist in default values\\.",fixed=FALSE, all=FALSE) + expect_equal(path,'') +}) diff --git a/tests/testthat/test_misc_fns.R b/tests/testthat/test_misc_fns.R new file mode 100644 index 0000000..e69de29 diff --git a/tests/testthat/test_project.R b/tests/testthat/test_project.R new file mode 100644 index 0000000..791450c --- /dev/null +++ b/tests/testthat/test_project.R @@ -0,0 +1,147 @@ +home_dir <- fs::path_home() +test_drive_dir <- fs::path_expand("~/test_drive") +fs::dir_create(path=test_drive_dir) +test_project_path <- "BRANCHES/dr_test/test_project/" + +unlink(paste(test_drive_dir,"/",test_project_path,sep="")) +unlink(paste(test_drive_dir,"/","BRANCHES/dr_test/",sep="")) + +full_path <- paste0(test_drive_dir,"/",test_project_path) + + + +test_that("test project creation",{ + create_project(path=full_path, + project_name="Test Project", pi="Dr. Test",analyst ="Test Name", + data_location ="BRANCHES/dr_test/test_project", + git_location="CIDA/Test_test_project" ) + expect_equal(file.exists(paste0(full_path,"/Admin/README.md")), TRUE) + expect_equal(file.exists(paste0(full_path,"/Background/README.md")), TRUE) + expect_equal(file.exists(paste0(full_path,"/Code/README.md")), TRUE) + expect_equal(file.exists(paste0(full_path,"/DataProcessed/README.md")), TRUE) + expect_equal(file.exists(paste0(full_path,"/DataRaw/README.md")), TRUE) + expect_equal(file.exists(paste0(full_path,"/Dissemination/README.md")), TRUE) + expect_equal(file.exists(paste0(full_path,"/README.md")), TRUE) + expect_equal(file.exists(paste0(full_path,"/Reports/README.md")), TRUE) + expect_equal(dir.exists(paste0(full_path,"/.ProjData")), TRUE) + expect_equal(file.exists(paste0(full_path,"/.ProjData/Data.dcf")), TRUE) + expect_equal(file.exists(paste0(full_path,"/test_project.Rproj")), TRUE) + expect_equal(file.exists(paste0(full_path,"/.Rprofile")), TRUE) +}) +test_that("create_project errors when project_name is missing", { + expect_error( + create_project(path = tempdir(), analyst = "Test"), + "'project_name' is required and cannot be empty." + ) +}) + +#test_that("create_project errors when analyst is missing", { +# expect_error( +# create_project(path = tempdir(), project_name = "Test"), +# "'analyst' is required and cannot be empty." +# ) +#}) + +test_that("create_project errors when project_name is empty string", { + expect_error( + create_project(path = tempdir(), project_name = "", analyst = "Test"), + "'project_name' is required and cannot be empty." + ) +}) + +#test_that("create_project errors when analyst is empty string", { +# expect_error( +# create_project(path = tempdir(), project_name = "Test", analyst = ""), +# "'analyst' is required and cannot be empty." +# ) +#}) + +test_that("metadata file is always created", { + temp_path <- file.path(tempdir(), "test_meta_always") + unlink(temp_path, recursive = TRUE) + create_project(path = temp_path, + project_name = "Meta Test", + analyst = "Test Analyst") + expect_true(dir.exists(file.path(temp_path, ".ProjData"))) + expect_true(file.exists(file.path(temp_path, ".ProjData/Data.dcf"))) + unlink(temp_path, recursive = TRUE) +}) + +test_that("test open_project",{ + open_project(remote_project_folder=full_path) + expect_equal(as.character(options("cida_tools.remote_current_project_path")), full_path) +}) + +test_that("test project meta data",{ + options(cida_tools.remote_current_project_path= "") + + # Process the DCF file using your function + w <- capture_warnings(github <- get_project_github()) + expect_match(w,".ProjData directory not found in project.",all=FALSE) + expect_match(w,".ProjData/Data.dcf File does not exist.",all=FALSE) + expect_equal(github, "") + + w <- capture_warnings(proj_name <- get_project_name()) + expect_match(w,".ProjData directory not found in project.",all=FALSE) + expect_match(w,".ProjData/Data.dcf File does not exist.",all=FALSE) + expect_equal(proj_name, "") + w <- capture_warnings(pi <- get_project_pi()) + expect_match(w,".ProjData directory not found in project.",all=FALSE) + expect_match(w,".ProjData/Data.dcf File does not exist.",all=FALSE) + expect_equal(pi, "") + w <- capture_warnings(analyst <- get_project_analyst()) + expect_match(w,".ProjData directory not found in project.",all=FALSE) + expect_match(w,".ProjData/Data.dcf File does not exist.",all=FALSE) + expect_equal(analyst,"") + w <- capture_warnings(location <- get_project_location()) + expect_match(w,".ProjData directory not found in project.",all=FALSE) + expect_match(w,".ProjData/Data.dcf File does not exist.",all=FALSE) + expect_equal(location,fs::path("")) + + open_project(remote_project_folder=full_path) + # Process the DCF file using your function + github <- get_project_github() + proj_name <- get_project_name() + pi <- get_project_pi() + analyst <- get_project_analyst() + location <- get_project_location() + # Expectations + expect_equal(github, "CIDA/Test_test_project") + expect_equal(proj_name, "Test Project") + expect_equal(pi, "Dr. Test") + expect_equal(analyst,"Test Name") + expect_equal(location,fs::path("BRANCHES/dr_test/test_project/")) + + options(cida_tools.remote_current_project_path= "") + + setwd(full_path) + rm(github, proj_name, pi, analyst, location) + # Process the DCF file using your function + github <- get_project_github() + proj_name <- get_project_name() + pi <- get_project_pi() + analyst <- get_project_analyst() + location <- get_project_location() + # Expectations + expect_equal(github, "CIDA/Test_test_project") + expect_equal(proj_name, "Test Project") + expect_equal(pi, "Dr. Test") + expect_equal(analyst,"Test Name") + expect_equal(location,fs::path("BRANCHES/dr_test/test_project/")) + +}) + +test_that("get project drive path",{ + open_project(remote_project_folder=full_path) + drive_path <- get_project_drive_path() + expect_equal(drive_path,test_drive_dir) + + options(cida_tools.remote_current_project_path= "") + errMsg <- tryCatch({get_project_drive_path()}, error=function(x) {geterrmessage()}) + expect_match(errMsg, "Nothing found at (.*?) ensure drive is mounted and you have entered your password to access the drive \\(and are logged into the VPN if needed\\.\\) If still experiencing issues try set_project_data_path\\(\\) or set_global_default_path\\(\\)") + #expect_equal(errMsg, "Nothing found at /Volumes/dept || SPH || SPH-CIDA || BRANCHES Please ensure drive is mounted and you have entered your password to access the drive (and are logged into the VPN if needed.) If still experiencing issues try set_project_data_path() or set_global_default_path()") + # Since the above call to get_project_drive_path() will error out, drive_path retains the old value from the first call. Commenting out for now to prevent the check. + #expect_equal(drive_path,"") +}) + +unlink(paste(test_drive_dir,"/",test_project_path,sep="")) diff --git a/tests/testthat/test_project_internal.R b/tests/testthat/test_project_internal.R new file mode 100644 index 0000000..6cc475d --- /dev/null +++ b/tests/testthat/test_project_internal.R @@ -0,0 +1,39 @@ +home_dir <- fs::path_home() + +global_path <-fs::path_join(c(home_dir,"/cida_defaults.dcf")) + +test_drive_dir <- fs::path_expand("~/test_drive") +fs::dir_create(path=test_drive_dir) +test_project_path <- "BRANCHES/dr_test/test_project5" +full_project_dir <- paste(test_drive_dir,test_project_path,"/.ProjData/",sep="") +fs::dir_create(path= full_project_dir) + +test_that("test the get_default_path function",{ + w <- capture_warnings(test_path <- get_default_path()) + expect_equal(test_path,"") + expect_match(w,".ProjData/Data.dcf File does not exist.",all=FALSE) + expect_match(w,".ProjData directory not found in project.",all=FALSE) + + #Create Global Default File + dcf_content <- list( path="~/test_drive", analyst_name="Analyst Name") + write.dcf(dcf_content, file.path(global_path)) + w <- capture_warnings(test_path <- get_default_path()) + full_path_test <- as.character(fs::path_abs("~/test_drive")) + expect_equal(test_path,full_path_test) + + #Create Project MetaData File + setwd(paste(test_drive_dir,test_project_path,sep="")) + dcf_content <- list( ProjectName="Test Project 5", PI="Dr. Test",analyst="Analyst Name",datalocation="Branches/dr_test/test_project5",gitlocation="CIDATools/Test_test_project5",default_full_path_to_project="~/test_drive/Branches/dr_test/test_project5") + w <- capture_warnings(save_project_data(dcf_content)) + #expect_match(w,".ProjData/Data.dcf File does not exist.",all=FALSE) + + + w <- capture_warnings(test_path <- get_default_path()) + full_path_test <- fs::path_abs("~/test_drive") + expect_equal(test_path,full_path_test) + + +}) + + +unlink(global_path) diff --git a/tests/testthat/test_project_meta_data.R b/tests/testthat/test_project_meta_data.R new file mode 100644 index 0000000..330c0c1 --- /dev/null +++ b/tests/testthat/test_project_meta_data.R @@ -0,0 +1,62 @@ +home_dir <- fs::path_home() +test_drive_dir <- fs::path_expand("~/test_drive/") +fs::dir_create(path=test_drive_dir) +test_project_path <- "BRANCHES/dr_test/test_project" +full_project_dir <- paste(test_drive_dir,test_project_path,"/.ProjData/",sep="") +fs::dir_create(path= full_project_dir) + +unlink(paste(full_project_dir,"Data.dcf",sep="")) + +test_that("create a test project dcf file and test getter functions", { + setwd(paste(test_drive_dir,test_project_path,sep="")) + dcf_content <- list( ProjectName="Test Project 5", PI="Dr. Test",analyst="Analyst Name",datalocation="BRANCHES/dr_test/test_project",gitlocation="CIDATools/Test_test_project") + + w <- capture_warnings(save_project_data(dcf_content)) + expect_match(w,".ProjData/Data.dcf File does not exist.", perl=TRUE ,all=FALSE) + #expect_warning(save_project_data(dcf_content),".ProjData/Data.dcf file not found in project.") + + # Process the DCF file using your function + github <- get_project_github() + proj_name <- get_project_name() + pi <- get_project_pi() + analyst <- get_project_analyst() + location <- get_project_location() + # Expectations + expect_equal(github, "CIDATools/Test_test_project") + expect_equal(proj_name, "Test Project 5") + expect_equal(pi, "Dr. Test") + expect_equal(analyst,"Analyst Name") + expect_equal(location,fs::path("BRANCHES/dr_test/test_project/")) + + }) + + test_that("create a test project dcf file and test setter/getter functions", { + set_project_analyst("Analyst 2") + set_project_name("Project 1") + set_project_pi("Dr. Test2") + set_project_location("BRANCHES/dr_test/test_project2/") + set_project_github("CIDATools/Test2_test_project2") + + expect_equal(get_project_analyst(),"Analyst 2") + expect_equal(get_project_name(),"Project 1") + expect_equal(get_project_pi(),"Dr. Test2") + expect_equal(get_project_location(),fs::path("BRANCHES/dr_test/test_project2/")) + expect_equal(get_project_github(),"CIDATools/Test2_test_project2") + + }) + +test_that("test setting/getting full project path",{ + test_full_path <- fs::path_abs(fs::path_join(c(test_drive_dir,test_project_path))) + + w <- capture_warnings(before_set<-get_full_project_path()) + expect_match(w,"default_full_path_to_project not found in project data.",all=FALSE) + expect_equal(before_set,"") + + msg <- set_full_project_path(path=test_full_path) + expect_match(msg,paste("The project default full path has been changed to ",test_full_path,sep=""), all=FALSE) + + + +}) + +unlink(paste(full_project_dir,"Data.dcf",sep="")) diff --git a/tests/testthat/test_util_internal.R b/tests/testthat/test_util_internal.R new file mode 100644 index 0000000..fa55a29 --- /dev/null +++ b/tests/testthat/test_util_internal.R @@ -0,0 +1,4 @@ +test_that("test check_string_param_value", { + expect_error(val<-check_string_param_value(1,"test") ,"test must be a character string") + expect_warning(val<-check_string_param_value(c("string1","string2"),"test") ,"Only First String is Used") +}) diff --git a/vignettes/.gitignore b/vignettes/.gitignore deleted file mode 100644 index 097b241..0000000 --- a/vignettes/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.html -*.R diff --git a/vignettes/CIDA_BIOS_Cluster.Rmd b/vignettes/CIDA_BIOS_Cluster.Rmd deleted file mode 100644 index a3d1120..0000000 --- a/vignettes/CIDA_BIOS_Cluster.Rmd +++ /dev/null @@ -1,262 +0,0 @@ ---- -title: "Computing on the CSPH Biostats Cluster" -author: "Research Tools Committee" -date: "Last Updated: `r Sys.Date()`" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Computing on the CSPH Biostats Cluster} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = TRUE) -``` - -## Definitions -- **HPC** - High-performance Computing -- **Node** - A single computer in the cluster's network. Most HPC clusters have a *head node* and one or more *compute nodes* -- **Head Node** - A node within the cluster which serves as the user's access/login point to the cluster. Depending on cluster configuration, the head node may also be responsible for scheduling and distributing jobs to the compute nodes. -- **Compute Node** - A node within the cluster which is designated for running user-submitting jobs. Compute nodes usually offer large amounts of computational resources (CPU cores, RAM, etc). -- **Cluster** - A group of networked computers, usually running cluster-management software to coordinate resource sharing among multiple users. -- **Job** - A computational task executed on the cluster. A submitted job will be scheduled and executed on one of the compute nodes. - -## Introduction to HPC (High-Performance Computing) - -An HPC cluster is a group of networked high-performance computers (*nodes*). - -A typical cluster will have multiple *compute nodes* which can perform heavy computation, as well as a *head node* which serves as the user's access point to the cluster, and may also be responsible for scheduling jobs among the *compute nodes*. -The *compute nodes* in an cluster typically have compute resources (CPU Cores, RAM, Disk Space) which far exceed those of a typical laptop or desktop computer. - -Because HPC clusters are intended to serve a group of people (i.e. A biostatistics department) rather than a single user, HPC clusters use the concept of [jobs](#def_job) to allow for multiple users to effectively share the cluster's resources. - -When a user is ready to run something (an analysis, processing pipeline, etc) on the cluster, they will submit a new *job* to the cluster. The cluster will then schedule and run the job as soon as compute resources are available. - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster/cluster_basic_diagram.png") -``` - -The example figure above shows an example cluster with three users. Each user connects to the Head Node to submit their jobs. - - User 1 has submitted two jobs, which are both running on Compute Node 1. User 2 has submitted a single job, which is also running on Compute Node 2. User 3 has submitted a job which requires a larger amount of compute resources (CPU cores, RAM, etc). This job runs on Compute Node 2 to provide the user with the resources they requested. - -HPC clusters are useful for: - -1. Performing analyses which take a long time to run (i.e. A large-scale analysis which takes hours to complete) -2. Performing analyses which are too resource-intensive (require too much RAM, Disk Space, etc) to run on a typical computer. - -## CSPH Biostats HPC Cluster - -The CSPH Biostats cluster consists of four nodes. The `csphbiostats.ucdenver.pvt` node serves as both a head node and one of the compute nodes (i.e. Submitted jobs may also run on this node), and the `cidalappc[1-3].ucdenver.pvt` nodes serve as compute nodes. - -```{r, echo=FALSE, out.width="100%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster/Biostats_HPC_diagram.png") -``` - -The CIDA/Biostats server uses the [SLURM](https://slurm.schedmd.com) system to manage job scheduling and resource management on the cluster. - -## Accessing the CSPH Biostats Cluster - -To access the CSPH Biostats cluster, first submit a support ticket on the [SOM IS web page](https://medschool.cuanschutz.edu/informationservices) requesting: - -1. Access to the 'CSPH/CIDA Biostats Cluster'. -2. (optional) A directory under `/biostats_share` (i.e. `/biostats_share/`). - -Once approved, an account will be created for you on the server. - -To log in to the CSPH Biostats Cluster, you can use SSH from the command line or an SSH client of your choice. - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster/biostats_hpc_ssh.png") -``` - -If you are connecting from the command line (like the above example), run: - -``` -ssh @csphbiostats.ucdenver.pvt -``` - -where `` is your CU system username (i.e Your username for UCDAccess, Outlook, etc) - -On login, you will be prompted for a password which will be your CU system password (i.e. Your password for UCDAccess, Outlook, etc). - -Once you've successfully logged in, you should see a prompt like the final line in the screenshot, showing that you are logged in to `csphbiostats.ucdenver.pvt`. - -To make future logins more convenient, you could configure an SSH config profile and RSA key pair, which will enable password-less login. - -## Submitting a Job on the CSPH Biostats Cluster - -In the sections below, I will describe a few different ways of submitting a job on the cluster, along with their potential use cases. - -### Using `sbatch` -The most common way of submitting a job on the cluster is to use the `sbatch` command. - -To submit a job using `sbatch`, you should first create a batch script which will list the commands to be executed as part of your job. - -The below example shows a simple batch script `my_batch.sh` which executes a single R script. - -``` -#!/bin/bash -#SBATCH --job-name=my_batch -#SBATCH --output=my_batch.log -#SBATCH --error=my_batch.err - -Rscript my_analysis.R -``` - -The first line: - -```#!/bin/bash``` - - is required, and is used to determine how your script will be executed. In this case, the script will be executed using `bash`. - -The next few lines will be parsed by SLURM to set parameters/options for your batch job. - -``` -#SBATCH --job-name=my_batch -#SBATCH --output=my_batch.log -#SBATCH --error=my_batch.err -``` - -In order: - -1. `--job-name` - Sets a name for your job. -2. `--output` - Sets the output log file for your job. Any log messsages or outputs from your script will be sent to this file. -3. `--error` - Sets the error log file for your job. Any log or error messages produced by your script will be sent to this file. - -Any comment line containing `#SBATCH` before the first command in your script will be parsed by SLURM. - -Although `#SBATCH` lines are not required, I recommend at least providing the `--output` and `--error` options, since otherwise your output and error streams will both be directed to the default file `slurm-.out` - -We can submit this job by running: - -``` -sbatch my_batch.sh -``` - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster/cluster_sbatch.png") -``` - -When we execute the `sbatch` command, SLURM will assign the job an ID and schedule the job to execute. In this case, our job is assigned ID `6179` (first arrow in the figure). - -By using the `squeue` command, we can obtain the status of all jobs currently scheduled across the cluster (including those submitted by other users). - -Using the assigned job ID, we can use the `JOBID` column to identify our job in the queue (second arrow in the figure). - -The `squeue` also provides some useful information about our job: - -- The `ST` column tells us that our job is in the running (`R`) state. -- The `TIME` column tells us that our job has been running for 9 seconds. -- The `NODELIST(REASON)` column tells us that our job is executing on the `csphbiostats.ucdenver.pvt` node. - - -#### When to use `sbatch` -Using `sbatch` is most beneficial for long-running scripts or analyses. After the job has been submitted using `sbatch`, your job will execute on the cluster until completion. You can continue to work on the cluster (submitting other jobs, etc) or log out without affecting any of your running jobs. - -You can monitor the progress of your job using by checking your log (`--output`) and error (`--error`) output files to see any outputs/messages printed by your script. - -Additionally, you can use the `squeue` command to obtain other information about your job, including the current state (`ST`), the elapsed runtime (`TIME`), and location of your job (`NODELIST`). - -### Using `srun` - -Submitting a job using SLURM's `srun` command will schedule and run the job as soon as possible. When the job begins to run, you will see the output of the job in your terminal as it executes. - -Similar to running a script locally on the command line (i.e. `./my_script.sh`), you will not be able to execute other commands in your terminal window until the submitted job is complete. - -An example below shows execution of a simple shell script using `srun`. - -The command: - -``` -srun --exclude=csphbiostats.ucdenver.pvt ./my_script.sh -``` - -will schedule a new job to run the script `./my_script.sh`. - -The `--exclude` flag tells SLURM to schedule the job on any node except the node(s) listed. In this case, we exclude the `csphbiostats.ucdenver.pvt` node to ensure our job runs on one of the `cidalappc[1-3].ucdenver.pvt` nodes (and the first line of the script output shows our job ran on `cidalappc01`). - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster/cluster_srun.png") -``` - -#### Interactive Jobs -`srun` is also useful for running *interactive* jobs. An interactive job opens a terminal session on a compute node, allowing you to run commands and script interactively. - -Interactive jobs are useful for running quick commands or scripts, or anytime you'd like to directly monitor the output of your script/command. - -The command: - -``` -srun --pty --exclude=csphbiostats.ucdenver.pvt /bin/bash -i -``` - -will schedule a new interactive job on a compute node. - -This command is similar to the previous `srun` command we used but has a few key differences: - -1. The addition of the `--pty` flag tells SLURM that this is an interactive job. -2. The command `/bin/bash -i` will execute an interactive shell on the compute node. - -After submitting the job, we see the prompt string has changed from: - -```[hillandr@csphbiostats job_example]``` - - to - - ```[hillandr@cidalappc01 job_example]```. - -This indicates that we are now running an interactive job on the compute node `cidalappc01`. - -At this point, we can execute any commands or scripts normally. - -To end the interactive job, type `exit`. - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster/interactive_job.png") -``` - -#### When to use `srun` - -`srun` is useful for running interactive jobs with fast-running commands/scripts, or for debugging issues with a larger script you will eventually submit using `sbatch`. - -I don't recommend using `srun` for long-running jobs, as if you disconnect from the cluster while the `srun` command is still executing, the job may be cancelled. - -## Uploading Data to the CSPH Biostats Cluster - -To upload and download data from the cluster, it is most convenient to use SFTP. There are multiple ways to use SFTP, including through the command line using the `sftp` command (Mac/Unix-like systems only) - -On Mac, the [Cyberduck](https://cyberduck.io) application is a free and intuitive GUI SFTP client. On Windows systems, [WinSCP](https://winscp.net/eng/index.php) is another popular choice. - -The below screenshots show an example of connecting to `csphbiostats.ucdenver.pvt` using Cyberduck on Mac. - -First, open Cyberduck and click the 'Open Connection' button on the top bar. - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster/cyberduck_1.png") -``` - -Next, ensure that the 'SFTP' option is selected in the dropdown, then input your SSH credentials. - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster/cyberduck_2.png") -``` - -If successful, you should see a file browser interface showing your home directory on `csphbiostats.ucdenver.pvt`. - -You can use the interface to navigate and download and existing files. You can also drag-and-drop files from your local machine to upload them to the cluster. - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster/cyberduck_3.png") -``` - -### Networked Storage - -The CSPH Biostats cluster uses a shared filesystem for many important directories, including `/home` and `/biostats_share`. This means that any files (scripts, data, etc) you upload to one of these directories on `csphbiostats.ucdenver.pvt` will be accessible from any node in the cluster. - -Similarly, any output files generated from a job running on a compute node will also be accessible from `csphbiostats.ucdenver.pvt`, making it easy to download the results of a job. - -### Other SLURM Resources - -The SLURM system has an excellent [website](https://slurm.schedmd.com/documentation.html), with documentation for each command. I recommend reading the documentation for at least the [sbatch](https://slurm.schedmd.com/sbatch.html) command, as it contains information about many configuration options not listed in this document. - diff --git a/vignettes/CIDA_BIOS_Cluster_Interactive_IDEs.Rmd b/vignettes/CIDA_BIOS_Cluster_Interactive_IDEs.Rmd deleted file mode 100644 index 2fe6c1e..0000000 --- a/vignettes/CIDA_BIOS_Cluster_Interactive_IDEs.Rmd +++ /dev/null @@ -1,607 +0,0 @@ ---- -title: "RStudio/JupyterLab on the CSPH Biostats Cluster" -author: "Research Tools Committee" -date: "Last Updated: `r Sys.Date()`" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{RStudio/JupyterLab on the CSPH Biostats Cluster} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = TRUE) -``` - -## A. Introduction - -This document will guide you through running interactive RStudio (and/or JupyterLab) sessions on the Biostats cluster. - -Once configured, you'll be able to easily submit RStudio/JupyterLab SLURM jobs, and access them through your browser. - -We'll cover: - -1. [First-time Setup](#first-time-setup) - Some one-time, prerequisite configuration steps on your local computer to enable connections to RStudio and JupyterLab. -2. [Launching RStudio Sessions](#launching-an-rstudio-session) - How to launch an RStudio session on the cluster and connect from your browser. -3. [Launching JupyterLab Sessions](#launching-a-jupyterlab-session) - How to launch a JupyterLab session on the cluster and connect from your browser. -4. [Quitting RStudio/JupyterLab Sessions](#quit-the-rstudiojupyterlab-session) - How to quit an RStudio/JupterLab session. -6. [(Optional) Additional Options](#optional-additional-options-and-job-customization) - Some additional options and information which may be useful. - -If you've never used the `csphbiostats` cluster before, you'll need to request an account. Information on how to access the cluster is available in the [Accessing the CSPH Biostats Cluster](https://cida-csph.github.io/CIDAtools/articles/CIDA_BIOS_Cluster.html#accessing-the-csph-biostats-cluster) section of the main Biostats HPC article. - -If you previously followed this guide to set up RStudio/JupyterLab and just need a refresher on how to launch an RStudio/JupyterLab job, check out the [Quickstart](#quickstart-for-returning-users) section. - -### A1. Motivation -Using RStudio/JupyterLab on the `csphbiostats` cluster allows you to: - -- Use the cluster's significant [computational resources](https://cida-csph.github.io/CIDAtools/articles/CIDA_BIOS_Cluster.html#csph-biostats-hpc-cluster) to work with larger datasets than would be possible on a local machine, while coding interactively in a familiar environment. -- Offload time consuming analysis tasks from your local computer to the cluster (your RStudio/JupyterLab job will keep running on the cluster, even if you log out!) -- Running RMarkdown/Quarto/Jupyter Notebooks and generating reports directly from the cluster. -- Generate and view visualizations in real-time. - -### A2. Capabilities - -The RStudio container runs R 4.5.0, and supports the usual RStudio functions including RMarkdown/Quartio notebooks, interactive plotting, etc. For convenience, the RStudio container has a variety of commonly used packages pre-installed, including the `tidyverse` family, and also packages many system libraries needed for compiling R packages from source. - -The JupyterLab container supports running Jupyter Notebooks (`.ipynb`), and supports all JupyterLab functions. By default, the JupyterLab container has the following kernels installed: - -- Python 3.13 -- R 4.5.0 -- Julia 1.11.5 - - -## B. Questions, Comments, Issues - -This project is [hosted on GitHub here](https://github.com/CIDA-CSPH/Biostats-Cluster-Tools). - -If you have questions, encounter difficulties, or have suggestions for improvements, feel free to either [open an issue on GitHub](https://github.com/CIDA-CSPH/Biostats-Cluster-Tools/issues) or email me directly. - -## 1. First-time Setup - -Although the RStudio/JupyterLab instance will run on an HPC compute node, you'll log in to the cluster normally (via SSH), and access then RStudio/JupyterLab interface through your local browser. - -In order for this to work correctly, we need to configure a few SSH options when logging in to the cluster. These SSH options should only need to be configured once. - -### 1A. Locate SSH Config File - -The simplest way to configure SSH connections is to use the SSH `config` file, which allows us to define persistent options that will be used each time we log in to the cluster (rather than having to remember which parameters to pass on the command line each time). - -On Mac/Unix-like systems, this file is located at `~/.ssh/config`, and on Windows it is located at `C:/Users//.ssh/config`. - -If you don't see a file named `config` in that location that's OK, just create it with your text editor of choice. - -**Note:** Some GUI clients (like PuTTY on Windows) do not support port forwarding to Unix sockets (requried functionality to use RStudio/JupyterLab on the cluster). However, modern command-line versions of SSH on Mac and Windows do support this. - -### 1B. Add SSH Configuration options - -Open up the `config` file in your text editor of choice. If you had a pre-existing `config` file, check if you have an entry with `Host csphbiostats.ucdenver.pvt` or `HostName csphbiostats.ucdenver.pvt`. If you already have an entry you can modify it instead of creating a new entry. - -**IMPORTANT:** If you have an existing `config`, and there is an entry that begins with `Host *`, you should add the new configuration we make **above** the existing `Host *` section to ensure that our new configuration will take precedence. - -#### 1B.1 SSH Config Template - -Configure your entry to look something like the below entry template, replacing the three highlighted `your_username` placeholders with the username you use to log into the cluster with SSH: - -
-
Host biostats
-    HostName csphbiostats.ucdenver.pvt
-    User your_username
-    Port 22
-    LocalForward 8895 /tmp/jupyter-your_username.sock
-    LocalForward 8896 /tmp/rstudio-your-username.sock
-
-
- -#### 1B.2 Fully-configured SSH Config Example - -As an example, a fully-configured entry looks like this: - -``` -Host biostats - HostName csphbiostats.ucdenver.pvt - User coopdale - Port 22 - LocalForward 8895 /tmp/jupyter-coopdale.sock - LocalForward 8896 /tmp/rstudio-coopdale.sock -``` - -The three `your_username` placeholders from the template have been replaced with the user's username `coopdale`. - -#### 1B.3 SSH Config Explanation -As a quick breakdown of the above configuration options: - -The `Host biostats` line assigns this configuration the alias/name 'biostats'. We can use this name when running SSH to automatically use all of the configuration options we specified, like: - -```{bash, eval=FALSE, echo=TRUE} -ssh biostats -``` - -The `User` field should be your cluster username, and `Port` can be set to `22` (the default port for SSH). - -The two key elements are the `LocalForward` fields: - -``` - LocalForward 8895 /tmp/jupyter-.sock - LocalForward 8896 /tmp/rstudio-.sock -``` - -These options tell the SSH client to forward local traffic on these ports to specific Unix socket paths on the cluster, allowing you to access the running RStudio/JupyterLab jobs. - -In this case, port `8895` will be used for JupyterLab and port `8896` will be used for RStudio, but feel free to customize these to any non-reserved ports you like (most ports in the 8800-8999 range should be available). - -Once configured, save and close the file. - -### 1C. Test the SSH Connection - -Now, we'll run a quick check to verify that the SSH configuration is working as expected. - -First, we need to open a terminal window, which varies slightly by platform: - -| OS | Command | -|-----|------| -| Windows | Search for 'Powershell' or 'Command Prompt' | -| Mac | Search for 'Terminal' | - -Once the terminal window is open, type: - -```{bash, eval=FALSE, echo=TRUE} -ssh biostats -``` - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_ssh_2.png") -``` - - -Once you've logged in via SSH, open a web browser on your local machine (but keep the SSH window open!) and enter: - -```{bash, eval=FALSE, echo=TRUE} -localhost:8895 -``` - -in the address bar. If you assigned different ports in your config file, modify the address accordingly. - -In the browser, you should see an error screen. This is expected. - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster_Interactive_IDEs/localhost_test.png") -``` - -Moving back to your SSH window, you should see some error messages populate the screen: - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_ssh_local_forward_test.png") -``` - -If you see these error messages in your SSH window, Congratulations! - -This means you've configured SSH correctly! The error messages appear because the browser is attempting to connect, but there is nothing on the other end (yet) to accept the connection. - -These error messages will continue to appear in your SSH window as long as you keep the `localhost:8895` browser tab open. Feel free to close the browser tab now and type `clear` in your SSH window to clear the messages from your terminal screen. - - -#### 1C.1 Troubleshooting - -If you don't see the error messages in your SSH window: - -1. Make sure the `localhost:` you're visiting in browser matches one of the `LocalForward ` lines in your SSH config file. -2. Check that you're logging in with the `ssh biostats` alias from your SSH config file. -3. Verify that these ports aren't being used by something else on your machine (i.e. a local Jupyter Notebook). - - -### 1D. Get Launch scripts - -To launch an RStudio/JupyterLab session, you'll need a copy of the `rstudio_helper.sh` and `jupyter_helper.sh` scripts. These scripts help automate some of the setup for RStudio/JupyterLab sessions. - -In your SSH window, navigate to your home directory (`cd ~`) and run: - -```{bash, eval=FALSE, echo=TRUE} -cp /biostats_share/hillandr/containers/scripts/rstudio_helper.sh . -cp /biostats_share/hillandr/containers/scripts/jupyter_helper.sh . -``` - -To make copies of both scripts in your home directory (`~`). - -## 2. Launching an RStudio Session - -Once you have copies of the launch scripts, in your SSH window try running: - -```{bash, eval=FALSE, echo=TRUE} -./rstudio_helper.sh -``` - -You should see a message `Submitted batch job `. This is the Job ID for your RStudio job, which you'll need again when you want to shut down the RStudio session. This ID will change each time you launch a new job. - -Now, run `squeue`. - -You should see an entry for your Job ID, similar to my example below. - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_launch.png") -``` - -This job will also produce two output files `rstudio_helper.out` and `rstudio_helper.err` which will log outputs or errors that the system encounters. - -If you *don't* see your Job ID in the `squeue` list, try inspecting the two above files for any error messages. - -### 2A. Connect to RStudio - -If you can see your RStudio job running in `squeue`, go back to your web browser and visit - -```{bash, eval=FALSE, echo=TRUE} -localhost:8896 -``` - -in the address bar. - -You should see a loading screen, and eventually the RStudio interface! - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_interface.png") -``` - -Congratulations! You can now use RStudio on the cluster! - -Feel free to try out the interface and verify that everything works as expected. - -When you're finished, shut down the RStudio job by following the instructions in [Quit the RStudio/JupyterLab Job](#quit-the-rstudiojupyterlab-session) - -#### 2A.1 Troubleshooting - -If you *don't* see the RStudio interface in your browser: - -1. Verify that you used the correct port in the browser. (If you used the default config, RStudio is `8896`). -2. Double check your SSH config file and make sure your `LocalForward` directives match the template from [1B.1 SSH Config Template](#b-1-ssh-config-template) -2. Run `squeue` again and verify that your job is still running. If the job is not running, check `rstudio_helper.err` and `rstudio_helper.out` for more information. - - -### 2B. Customizing the RStudio Job - -The `rstudio_helper.sh` script essentially just automates some cleanup tasks and submits a new `sbatch` batch script which launches RStudio. - -If you open `rstudio_helper.sh` and scroll down to the `sbatch <<==SBATCH=SCRIPT==` section, you can customize the parameters of the underlying SLURM job to suit your needs: - -```{bash, eval=FALSE, echo=TRUE} -# This command redirects the rest of this script to a sbatch call. -sbatch <<==SBATCH=SCRIPT== -#!/bin/bash -#SBATCH --job-name=rstudio_helper -#SBATCH --output=rstudio_helper.out -#SBATCH --error=rstudio_helper.err -#SBATCH --exclude=csphbiostats.ucdenver.pvt -#SBATCH --mem=64G -#SBATCH --ntasks=1 -#SBATCH --cpus-per-task=8 - -# Launch the container. -apptainer run \ - --no-mount /etc/localtime \ - --bind /biostats_share:/biostats_share \ -/biostats_share/hillandr/containers/rstudio.sif - -==SBATCH=SCRIPT== - -``` - -The default `rstudio_helper.sh` script submits a job which: - -- Runs on any node *except* the head node `--exclude=csphbiostats.ucdenver.pvt` -- Requests 8 CPU Cores `--cpus-per-task=8` -- Requests 64GB of RAM `--mem=64G` - -You can change any of these values to meet your needs. - -The available resources of each compute node are listed in the article [Computing on the CSPH Biostats Cluster](https://cida-csph.github.io/CIDAtools/articles/CIDA_BIOS_Cluster.html#csph-biostats-hpc-cluster). - -## 3. Launching a JupyterLab Session -Once you have copies of the launch scripts, try running: - -```{bash, eval=FALSE, echo=TRUE} -./jupyter_helper.sh -``` - -You should see a message `Submitted batch job `. This is the Job ID for your JupyterLab job, which you'll need again when you want to shut down the JupyterLab session. This ID will change each time you launch a new job. - -Now, run `squeue`. - -You should see an entry for your Job ID, similar to my example below. - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_jupyter_launch.png") -``` - -This job will also produce two output files `jupyter_helper.out` and `jupyter_helper.err` which will log outputs or errors that the system encounters. - -If you *don't* see your Job ID in the `squeue` list, try inspecting the two above files for any error messages. - -**IMPORTANT:** The first time you launch JupyterLab, it will create a Python `virtualenv` under `~/jupyterlab_env`. This process takes time (in my experience, up to 10 minutes). If you are unable to connect to your JupyterLab instance immediately after launching the job, don't worry! The setup process will log output to the output and error logs listed above. - -### 3A. Connect to JupyterLab - -If you can see your JupyterLab job running in `squeue`, go back to your web browser and visit - -```{bash, eval=FALSE, echo=TRUE} -localhost:8895 -``` - -in the address bar. - -You should see a loading screen, and eventually the JupyterLab interface! - -```{r, echo=FALSE, out.width="80%", fig.align="center"} -knitr::include_graphics("figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_jupyter_interface.png") -``` - -Congratulations! You can now use JupyterLab on the cluster! - -Feel free to try out the interface and verify that everything works as expected. - -When you're finished, shut down the JupyterLab job by following the instructions in [Quit the RStudio/JupyterLab Job](#quit-the-rstudiojupyterlab-session) - -#### 3A.1 Troubleshooting - -If you *don't* see the JupyterLab interface in your browser: - -1. Verify that you used the correct port in the browser. (If you used the default config, JupyterLab is `8895`). -2. Double check your SSH config file and make sure your `LocalForward` directives match the template from [1B.1 SSH Config Template](#b-1-ssh-config-template). -3. Run `squeue` again and verify that your job is still running. If the job is not running, check the `jupyter_helper.err` and `jupyter_helper.out` files for more information. -4. If you're launching JupyterLab for the first time, it could take up to 10 minutes for the script to initialize the `/jupyterlab_venv` virtual environment. If the job is running (via `squeue`) but you can't connect through your browser, try waiting ~10 minutes for environment to initialize. - - After the venv setup is complete, future launches of JupyterLab through `./jupyter_helper.sh` should take only a few seconds. - -### 3B. Customizing the JupyterLab Job - -The `jupyter_helper.sh` script essentially just automates some cleanup tasks and submits a new `sbatch` batch script which launches JupyterLab. - -If you open `jupyter_helper.sh` and scroll down to the `sbatch <<==SBATCH=SCRIPT==` section, you can customize the parameters of the underlying SLURM job to suit your needs: - -```{bash, eval=FALSE, echo=TRUE} -sbatch <<==SBATCH=SCRIPT== -#!/bin/bash -#SBATCH --job-name=jupyter_helper -#SBATCH --output=jupyter_helper.out -#SBATCH --error=jupyter_helper.err -#SBATCH --exclude=csphbiostats.ucdenver.pvt -#SBATCH --mem=64G -#SBATCH --ntasks=1 -#SBATCH --cpus-per-task=8 - -# Launch the container. -apptainer run \ - --bind /biostats_share:/biostats_share \ -/biostats_share/hillandr/containers/jupyterlab.sif \ - --notebook-dir "$HOME" -==SBATCH=SCRIPT== -``` - -The default `jupyter_helper.sh` script submits a job which: - -- Runs on any node *except* the head node `--exclude=csphbiostats.ucdenver.pvt` -- Requests 8 CPU Cores `--cpus-per-task=8` -- Requests 64GB of RAM `--mem=64G` - -You can change any of these values to meet your needs. - -The available resources of each compute node are listed in the article [Computing on the CSPH Biostats Cluster](https://cida-csph.github.io/CIDAtools/articles/CIDA_BIOS_Cluster.html#csph-biostats-hpc-cluster). - -## 4. Quit the RStudio/JupyterLab Session -When you're finished using JupyterLab or RStudio, run: - -``` -scancel -``` - -from your SSH window to kill the job (make sure everything is saved!). - -A few things to note: - -1. Like other `sbatch` jobs, the RStudio/JupyterLab jobs will continue to run after you log out of your SSH connection (you can try this yourself!). - - This means you can log out (via SSH), then log back in later and keep using the same session. - - Although you *can* leave RStudio/JupyterLab running, its best to quit the session (using `scancel`) when you're finished to free up resources for other users. -2. **IMPORTANT: Check for a running RStudio/JupyterLab jobs (using `squeue`) before submitting a new one with `./rstudio_helper.sh` or `./jupyter_helper.sh`!!!** - - Submitting a second job will not work, and will likely break your original session as well. - - By running `squeue` you can quickly locate the Job ID of your running `rstudio_helper` or `jupyter_helper` Job (if one is running). You can then either cancel this job with `scancel` or just connect through your browser and keep working. - -## 5. Quickstart (for returning users) - -The complete process for launching a RStudio/JupyterLab instance (once the [first-time setup](#first-time-setup) is complete) looks like: - -1. Open a command prompt and run `ssh biostats`. - - `biostats` is the alias for `csphbiostats.ucdenver.pvt` that we configured in the [first-time setup section](#first-time-setup). -2. Check for a currently running RStudio/JupyterLab session using `squeue`. - - To reconnect to a running session, skip to step 5. - - To cancel the existing session, use `scancel `. -3. If no existing session is running, from your SSH terminal run either `./jupyterlab_helper.sh` or `./rstudio_helper.sh`. - - The script should exit after printing a Job ID for your new session. -4. Verify that your new session is running using `squeue` and look for the Job ID. -5. Open your browser to `localhost:8895` (JupyterLab) or `localhost:8896` (RStudio). -6. Done! - -## 6. Conclusion - -At this point, you should be able to launch, connect to, and cancel RStudio and JupyterLab jobs on the cluster! - -The sections below provide some additional configuration options and information, but these sections are completely optional. - -## 7. (Optional) Additional Options and Job Customization - -This section provides some additional information and configuration options. - - -### 7A. Apptainer Containers - -The JupyterLab and RStudio instances both run inside of Apptainer containers. - -Apptainer (formerly Singularity) containers are stored as self-contained files with the `.sif` extension. - -The benefit of hosting JupyterLab and RStudio within containers is that they offer a consistent environment where all dependencies are installed by default. - -The RStudio and JupyterLab containers are derived from a [base container image](https://github.com/CIDA-CSPH/Biostats-Cluster-Tools/blob/main/containers/RBase/docker/Dockerfile) which holds installation of R, Python, and Julia languages, along with packages/libraries to support installing most other common R/Python libraries. - -#### 7A.1 Bind Mounts -One important concept when working with containers is a 'bind mount'. Containers are like small Linux installations which run in a separate, read-only filesystem. This means we cannot access any files *outside* of the container by default. - -*Bind mounts* allow us to overlay specific parts of the host's filesystem onto the container, so we can read from and write our own files (on the host system) from inside the container. - -By default, Apptainer sets up bind mounts for a few directories including your home directory (`~`), your working directory (`.`) and `/tmp`. - -The `jupyter_helper.sh` and `rstudio_helper.sh` scripts also include an additional bind mount: - -`--bind /biostats_share:/biostats_share` - -which allows us to access the `/biostats_share` directory from inside the container. - -If you find yourself unable to access files from within the container, you can add the specific directory as a bind mount by modifying the `*_helper.sh` script to include additional bind mounts: - -```{bash, eval=FALSE, echo=TRUE} -# This command redirects the rest of this script to a sbatch call. -sbatch <<==SBATCH=SCRIPT== -#!/bin/bash -#SBATCH --job-name=jupyter_helper -#SBATCH --output=jupyter_helper.out -#SBATCH --error=jupyter_helper.err -#SBATCH --exclude=csphbiostats.ucdenver.pvt -#SBATCH --mem=64G -#SBATCH --ntasks=1 -#SBATCH --cpus-per-task=8 - -# Launch the container. -apptainer run \ - --bind /biostats_share:/biostats_share \ - --bind /another_special_directory:/another_special_directory \ -/biostats_share/hillandr/containers/jupyterlab.sif \ - --notebook-dir "$HOME" \ - --venv "$HOME/my_custom_venv" -==SBATCH=SCRIPT== -``` - -The line `--bind /another_special_directory:/another_special_directory` make the `/another_special_directory` path available in the container (make sure to use an absolute path). - -In general, bind mount arguments look like: - -`--bind :` - -To mount `` path on the cluster to ` - %\VignetteIndexEntry{CIDA Computing Resources} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = TRUE) -``` - - -### Introduction - -This document introduces the available computing resources with guidelines and linkes to access/request them. - -Who does this apply to: All members of CIDA (Professor, RA, RI, Senior RI, PRA, Senior PRA) - - - -### Computing Resources Available to CIDA Members -This table lists the computing resources available to CIDA members. Please note that each compute resource has differing policies about storage of PHI/HIPAA data. Please see the data storage guideline for more information. - -| Computing Resource | Description | HIPAA/PHI Data | -| --- | --- | --- | -| Personal Computer/Laptop | Free for CIDA members| Limited | -| CIDA/Biostats HPC | Free for CIDA members | Limited | -| Alpine | Almost Free for CIDA members (if requested resources <= default allocation)| No | -| Commercial computing platforms such as AWS, IBM, ... | Cost depends on the type of requested resouces | No | - -#### Personal Computer\ - -CIDA provides all its members with a PC or Macintosh based on their preference. - - -#### CIDA/Biostats HPC Cluster\ - -The CIDA/Biostats HPC Cluster is an HPC cluster running the SLURM cluster management software. - -This cluster is useful for computations which require large amounts of computing resource or involve long-running tasks. - -Instructions for accessing and using the CIDA/Biostats HPC are available [here](CIDA_BIOS_Cluster.html). - -| |csphbiostats|cidalappc01|cidalappc02|cidalappc03| -| --- | --- |---| --- |---| -|CPU |2x Intel Xeon Gold 61522 22-core CPU | 2x AMD EPYC 7H12 64-Core CPU | 2x AMD EPYC 7H12 64-Core CPU | 2x AMD EPYC 7H12 64-Core CPU | -|Disk storage| 50TB (Shared across all nodes) | " | " | " -|Memory Size | 1TB | 1TB | 512GB | 1TB | -|OS | Rocky Linux 9.5 (RHEL) | " | " | " | -|Software| R, Python, RStudio Server, Jupyter Lab | " | " | " | - - -#### Alpine\ -Alpine is the University of Colorado Boulder Research Computing’s third-generation high performance computing (HPC) cluster. Alpine is a heterogeneous compute cluster currently composed of hardware provided from University of Colorado Boulder, Colorado State University, and Anschutz Medical Campus. Alpine currently offers 317 compute nodes and a total of 18,080 cores. - -Alpine can be securely accessed anywhere, anytime using OpenOnDemand or ssh connectivity to the CURC system. Step-by-step instruction to access Alpine is available at: https://curc.readthedocs.io/en/latest/clusters/alpine/quick-start.html - - -|| Alpine || -|---| :---: |---:| -|Processor |General compute nodes|GPU | -| Nodes | 64 |11 | -|Core |64 × AMD Milan Compute nodes (64 cores/node) |2 × 8 GPU-enabled (3x AMD MI100) atop AMD Milan CPU | -|Memory Size | 239 GB | 2 TiB | -|Cost | Free for defined setting |Free | -|HIPAA compliant |NO |NO | NO | -|OS |RHEL 8.4 |RHEL 8.4 | - - - - -### Useful Links -Health Insurance Portability and Accountability Act (HIPAA): -http://www.hhs.gov/hipaa/for-professionals/index.html - - -Guidance Regarding Methods for De-identification of Protected Health Information in Accordance with the Health Insurance Portability and Accountability Act (HIPAA) Privacy Rule: -http://www.hhs.gov/hipaa/for-professionals/privacy/special-topics/de-identification/index.html diff --git a/vignettes/alpine.Rmd b/vignettes/alpine.Rmd deleted file mode 100644 index b6d76bd..0000000 --- a/vignettes/alpine.Rmd +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: "Alpine HPC" -author: "Research Tools Committee" -date: "2023-07-01" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Alpine HPC} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = TRUE) -``` - -## Alpine - -### Introduction - -This document provides a brief overview of Alpine, the University of Colorado's High Performance Computing Cluster (HPC). Alpine allows researchers across campus access to >18k computer cores, high memory computing cores, and specialized hardware like GPUs. It is available to all University of Colorado Anschutz employees and students. General documentation on Alpine can be found at https://curc.readthedocs.io/en/latest/clusters/alpine/index.html# - -Who does this apply to: All members of CIDA (Professor, RA, RI, Senior RI, PRA, Senior PRA) - -### Definitions - -* `HPC` high performance computing -* `RMACC` Rocky Mountain Advanced Computing Consortium -* `ACCESS-CI` Advanced Cyberinfrastructure Coordination Ecosystem: Services & Support - Cyberinfrastructure -* `XSEDE` Extreme Science and Engineering Discovery Environment - -### Accessing Alpine - -Getting an Alpine account is a 4-step process that is detailed at https://curc.readthedocs.io/en/latest/access/rmacc.html - -1. As CU Anschutz members we will request access as members of the Rocky Mountain Advanced Computing Consortium (RMACC). This is done by first requesting an ACCESS-CI account at https://identity.access-ci.org/new-user -2. After you recieve an ACCESS or XSEDE username, email CU Research Computing (rc-help@colorado.edu) to request an Alpine account. In this email include - * your ACCESS or XSEDE username - * your institutional affiliation (e.g., “University of Awesome”) - * your role (undergraduate graduate student, postdoc, staff, instructor, faculty or affiliated faculty) - * your department - * your first and last name - * your preferred email address for communication -3. You will receive an email confirmation with detailed instructions on how to use Alpine. It may take a few weeks to receive this confirmation after sending the email in Step 2. -4. Now you can log onto Alpine! Note, currently for CU Anscutz members, the only way to access Alpine is via the OnDemand web browser as ssh access is not allowed at this time. - -### Alpine Hardware - -A comprehensive list of all the hardware available on Alpine can be found at https://curc.readthedocs.io/en/latest/clusters/alpine/alpine-hardware.html. Specific hardware available to CU Anschutz memebers will be provided when your account is created. - -### Quick Start - -A quick start guide can be found at https://curc.readthedocs.io/en/latest/clusters/alpine/quick-start.html. Much more detailed information is provided in the account creation confirmation email sent by rc-help@colorado.edu. - diff --git a/vignettes/coding_guidelines.Rmd b/vignettes/coding_guidelines.Rmd deleted file mode 100644 index 4750fe5..0000000 --- a/vignettes/coding_guidelines.Rmd +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: "CIDA-coding-guidelines" -author: "Research Tools Committee" -date: "2024-12-05" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{CIDA-coding-guidelines} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = TRUE) -``` - -## Coding Guidelines and Best Practices - -*Except for binary machine code, all computer code is intended to be read by humans.* - -### Summary - -Within a CIDA project, code should follow CIDA’s standard organizational structure and be consistently tracked in a Git repository on CIDA’s GitHub server. Strive to use best practices for coding conventions. - -### CIDA Standards for Organization - -#### File Organization - -Files should be organized to fit within the general CIDA file structure. Within the root location of a project should be found the folders: - -* Admin – where any administrative files go (i.e., the SOW) -* Background – where any background documents go -* Code – where any code goes -* DataProcessed – where data goes after any manipulation by the statistician -* DataRaw – where any raw data goes from an investigator -* Dissemination – where any files go that have been sent to the investigator, in the state they were sent -* Reports – where any reports, figures, or other output goes - -Within Code/* any code files should be labelled in a usable way and ordered, for example - -* 00_prep.R -* 01_dataread.R -* 01a_dataread_auxilliary.R -* 02_dataclean.R -* ... - -At the conclusion of a project any files labelled as such should be the last version used; and when used together or in sequence result in the final project results. - -#### Experimental code - -* Any code in final scripts at project conclusion and archival should be able to be run in sequence to achieve the result -* Any code that is not included in the result is ‘experimental’ and should be placed into a separate file, or commented out if left in the main scripts - -### Suggestions for easier comprehension - -#### Naming Conventions - -Names should follow one of the following naming conventions consistently within a script (with the exception of pre-existing column titles from other databases), and be concise and meaningful. Avoid naming objects the same or similar names to standard functions. - -* alllowercase – all lowercase letters -* period.separated – words separated by periods -* underscore_separated – words separated by underscores -* camelCase – words denoted by capital letters - -#### Functions - -* If you find yourself copying and pasting code frequently, you’d likely benefit from creating a function. Read the key ideas behind R functions [here](https://r4ds.had.co.nz/functions.html). -* Functions beyond trivial wrappers should start with a header that describes the function, its input(s) and output(s) and any other pertinent information about the function. -* User-created functions should be named distinctly from other common functions. -* Returns from functions should be done explicitly, and not rely on implicit returns. -* Name your created functions as a descriptive verb and use nouns for objects. - -#### Commenting -* The start of a script file should start with a header containing at least the title, the author, the date created, and the purpose of the script. -* Sections of code should be denoted by headers of consistent formatting. -* Any complex or involved code should be commented for what it is doing and why. -* Any non-standard choices in analysis should be commented and the comment include a reference as to why this was done and when the decision made. -* Comments are for the why, not the what. - -### Best practices - -This section describes best practices for R, R Markdown, and general coding. They are not meant to be “enforced”, but if followed, they will make your (and your CIDA collaborators’) lives easier later on. - -#### R Scripts (.R files) -* Avoid using `attach()`, use `with()` instead or another alternative. -* Outside of function calls, use `<-`, not `=,` for assignment. -* Do not use right-hand assignment (e.g., don’t do this: `1 -> x`) -* For non-ubiquitous R packages, avoid using `library()`, and to instead use the :: operator when calling functions from their specific libraries, e.g., `CIDAtools::pvalr`. -* Place spaces around all infix operators (`+`, `-`, `=`, `<-`) and after all commas (not before). -* Use [RStudio’s Projects](https://r4ds.had.co.nz/workflow-projects.html#rstudio-projects) to avoid ever having to set your working directory in your R scripts. Or, use `setwd()` only once at the very top of your script. -* Use the pipe operator (`%>%`), for reasons described [here](https://r4ds.had.co.nz/pipes.html), but keep pipes under 10 steps. Break up large sequences with intermediate objects with meaningful names. - -#### R Markdown (.Rmd files) - -* Familiarize yourself with [R Markdown’s vast array of options and features](https://r4ds.had.co.nz/r-markdown.html#r-markdown). -* Ensure each notebook has a descriptive title, an evocative filename, and a first paragraph that briefly describes the aims of the analysis. -* Before you finish for the day, make sure you can knit the notebook (if you’re using caching, make sure to clear the caches). That will let you fix any problems while the code is still fresh in your mind. This is also a good time to push your new day’s code to GitHub (if you haven’t been doing so already). -* If you want your code to be reproducible in the long-run (i.e. so you can come back to run it next month or next year), you’ll need to track the versions of the packages that your code uses. For this purpose, include a chunk at the end of your notebook (in an appendix) that runs `sessionInfo()`. If you need to reproduce your report in its entirety and with the same versions of packages, you will then know which package and versions you need, and reinstall them `CRAN`. - -#### General best practices for programming - -* If you discover an error in a data file, do not modify it directly, but instead write code to correct the value. Explain (in comments) why you made the fix. -* Use ISO8601 YYYY-MM-DD format for dates so that’s there no ambiguity. -* Keep code to 80 characters or less per line. Exceptions exist for hard-coded constants (such as path names or URLs) which cannot easily be wrapped or shortened. -* Program files should always be ASCII text files. Program files should always be immediately source-able into R or SAS. If you cannot source your file directly into R (SAS), then the file format is not acceptable. Word processing programs like Microsoft Word do not save files as text files – do not save code as Word documents. -* Use a monospace font to write or display code. Variable space fonts like Times New Roman can alter the apparent structure of a program (and its readability). -* Consistently indent your code. Comments should be indented to the same level of indentation of the code to which the comment pertains. Comments can also appear at the end of a code line if space permits. -* For all objects/functions in your code, strive for names that are concise and meaningful. Similarly, ensure the script names are also [concise]{.underline} and [meaningful]{.underline}. - -### Workflow best practices - -Quote from R for Data Science: - -> One day you will need to quit R, go do something else and return to your analysis the next day. One day you will be working on multiple analyses simultaneously that all use R and you want to keep them separate. One day you will need to bring data from the outside world into R and send numerical results and figures from R back out into the world. To handle these real life situations, you need to make two decisions: 1) What about your analysis is “real”, i.e. what will you save as your lasting record of what happened? 2) Where does your analysis “live”? - -Initially, you may consider your analysis to live in your R environment (e.g. the objects listed in the environment pane). However, it’s much easier to recreate this environment from an R script than it is to recreate an R script from the environment! Your analysis therefore lives in your code. So, if you haven’t already, you should instruct RStudio to never preserve your workspace between sessions to foster this attitude and to make your life easier in the long-term. - -```{r, echo=FALSE, out.width="75%", out.height="75%", fig.align='center'} -knitr::include_graphics("figures/coding_guidelines/coding_1.png") -``` - -After changing this, you will notice when you restart RStudio that it will not remember the results of the code you ran last time, because remember – your analysis lives in your code. - -If you are working within an Rstudio Project, you will not usually have to worry about absolute vs relative file paths (as files will automatically be saved/loaded from the location of the main project (or its subdirectories). However, if you are knitting a R Markdown file in the `Reports/*` subdirectory and/or loading files elsewhere, you may consider wrapping file paths inside the `here()` function (from the [here package](https://here.r-lib.org)) to ensure all file paths work as anticipated. If your data live on an external server, you may need to point to that server when reading in data (this would be an absolute file path) rather than saving in `DataRaw/*`. If this is the case, please indicate in the project readme file (or that in `DataRaw/*` the information on where the data exists (and a contact email address for the owners/maintainers of this server). - -### Useful reporting functions: The CIDAtools R Package -* The CIDAtools R package, available [here](https://github.com/CIDA-CSPH/CIDAtools), has a suite of useful functions that makes producing CIDA reports easier. The readme of this package also has information on reporting templates/outlines. -* Please see the package documentation for more information, and contact the [committee chair](mailto:ryan.a.peterson@cuanschutz.edu) with suggestions for making this package more useful. - -### Where to store your code - -* All project files + code, with the exception of data, can be stored anywhere (locally, on OneDrive, etc). -* Project code must be tracked in a Git repository and regularly pushed to GitHub. (see below) -* Project data (stored in `DataRaw/` or `DataProcessed/`) should be backed up to the CIDA drive at least weekly; see this committee’s data storage guidelines and `CIDAtools::BackupProject()`. - -### Tracking code/files in Git and GitHub - -* Your code and files should be committed and pushed to GitHub regularly (daily recommended). -* **Data should not be tracked in Git**. Ensure your repository has a text file titled `.gitignore` at its main level that tells Git software not to track any data related files or file types. See below for a sample .gitignore file that ignores any CSV, XLSX files, as well as any files stored in DataProcessed or DataRaw subdirectories. -* Contact [Ryan Peterson](mailto:ryan.a.peterson@cuanschutz.edu) or [SOM IT](mailto:sph@medschool.zendesk.com) with issues related to GitHub, or SOM IT. - -### Useful Links - -* [R for Data Science](https://r4ds.had.co.nz) -* [Google style guide](https://google.github.io/styleguide/Rguide.html) - -Sample `.gitignore` file, stored at the project-level directory (the top level of your git repository): - -```{r, echo=FALSE, out.width="50%", out.height="50%", fig.align='center'} -knitr::include_graphics("figures/coding_guidelines/coding_2.png") -``` - - - \ No newline at end of file diff --git a/vignettes/cron-jobs.Rmd b/vignettes/cron-jobs.Rmd deleted file mode 100644 index 4eb119e..0000000 --- a/vignettes/cron-jobs.Rmd +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: "Cron Jobs" -author: "Research Tools Committee" -date: "2023-07-01" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Cron Jobs} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = TRUE) -``` - -## Cron Jobs - -### Introduction - -This document provides some description on how to run cron jobs on the biostats server (a computation server that part of the Dept. of Biostatistics and Informatics). The idea of a cron job is that allows a user to schedule when a piece of code is executed. The biostats server is an ideal place to run these as this "computer" is always on and thus it removes the need of an analyst to worry about having their personal computer running when it is time to execute the code. - -Who does this apply to: All members of CIDA (Professor, RA, RI, Senior RI, PRA, Senior PRA) - -### Definitions - -None at this time - -### Accessing the biostats server - -To gain access to the biostats server contact the Research Tools Committee. This is available to all members of CIDA. - -### Steps to a Run Cron Job - -The following is specific to the CIDA biostats server which is based in Linux. Although these steps may seem complicated, most of this only needs to be set up once and the Research Tools Committee is happy to help with this. - -The following example will use a cron job to execute a simple python script, `cron.py`, that generates a small array of data and then saves it. - -``` -import time -import numpy as np - -a = [1,2,3,4] -np.save(f"{time.time()}.npy",a) -``` - -This script will be called by a separate bash script, `cron.sh`. Note that cron jobs could be run directly on the `cron.py` file, however bash script allows the user to provide some extra information to the system to make sure the script is run in the proper environment. - -``` -#!/bin/bash - -# set to use the desired python Anaconda distibution -export PATH=/home/biostats_share/mancchri/anaconda3/bin:$PATH -# make sure the system know to be in the directory below -cd /home/biostats_share/mancchri/test_cron -# run the script below -python cron.py -``` - -To setup the cronjob we need to access the crontab, which is the file that stores active cron jobs for a specific user. Enter this file by running - -`crontab -e` - -Each line in this file will specify a different cron job. To run `cron.sh` every minute add the following to the crontab file. Note, writing to files on Linux can be daunting, but the Research Tools Committee can help with this! - -`*/1 * * * * /home/biostats_share/mancchri/test_cron/cron.sh` - -To view the list of current cron jobs in crontab use - -`crontab -l` - -To delete the cron job so it no longer execute use - -`crontab -r` - - -### Resources - -Information on how to use cron job, especially how to set jobs to run on a given interval see the following - -https://tecadmin.net/crontab-in-linux-with-20-examples-of-cron-schedule/ -https://crontab.guru/examples.html diff --git a/vignettes/data_storage.Rmd b/vignettes/data_storage.Rmd deleted file mode 100644 index 61b09aa..0000000 --- a/vignettes/data_storage.Rmd +++ /dev/null @@ -1,187 +0,0 @@ ---- -title: "CIDA-data-storage-guidelines" -author: "Research Tools Committee" -date: "2022-11-30" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{CIDA-data-storage-guidelines} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = TRUE) -``` - -## CIDA Data Storage Tools - -### Introduction - -This document provides guidelines, recommendations, and current best practices for where code, data, and other documents should be stored and backed up for members of CIDA. These guidelines are intended to explain the pros, cons, and best practices for the data storage tools available to CIDA members. However, a CIDA member may come across exceptions to these guidelines, and the responsibility for proper data handling within a particular project rests on the CIDA member involved. - -Who does this apply to: All members of CIDA (Professor, RA, RI, Senior RI, PRA, Senior PRA) - -### Definitions - -* ‘Code’ refers to any R, SAS, Stata, etc. (scripts stored as plain text formatted files) -* ‘Data’ refers to spreadsheets, tables, or other information used to run analysis on -* ‘Report’ refers to any document which outlines results of analysis for sending to an investigator -* GitLab is the Lhotse CIDA GitLab repository, available here (requires VPN connection) -* ‘Local storage’ refers to any university provided computer with a physical hard drive -* ‘External server’ refers to a server which houses data or runs analysis (except Lhotse) -* ‘Eureka’ is the Virtual Machine run by Health Data Compass (HDC) -* ‘OneDrive for Business’ refers to Microsoft’s file-syncing software licensed by the University -* ‘HPC’ refers to “High Performance Computing” - -### Summary - -* The CIDA (P) Drive is the required ongoing storage location for project data. Other data storage locations may be used temporarily during the course of active work on a project. - -### Data Storage Locations Available to CIDA Members - -#### Local Computer - -* All files for any current projects can be stored on a University provided PC or Macintosh, if and only if the computer’s hard drive is encrypted. -* Data with PID should only be locally stored during active work on a project. -* Pros: data and projects load more quickly when stored locally. -* Cons: no natural/default backup process, can be a hassle to do best security practices manually. -* Best Practices: - * Only keep project data on your computer while working on it, and if you do this often, ensure you frequently save your data to the CIDA drive. - * Prior to travel with a laptop, any old or unneeded projects should be removed from the computer drive and can be restored upon return to campus. - -#### CIDA (P) Drive - -* Mapping depends on operating system. See instructions here for mapping drives. - * MAC: `smb://data.ucdenver.pvt/dept/SPH/SPH-CIDA/CIDA` - * Windows: `\\data.ucdenver.pvt\dept\SPH\SPH-CIDA\CIDA` - * If you have recently started and are having trouble mapping this drive, contact [SOM-IT](https://medschool.cuanschutz.edu/informationservices). -* CIDA project data must be stored here on a permanent basis (with certain exceptions, e.g., projects larger > 16 GB or if the collaboration dictates otherwise). -* The storage under the CIDA Drive is set up as follows: - * CIDA/Branches: Long-standing collaborations, including those operating under MOUs, are treated as Branches, and their data should be stored in a subdirectory of CIDA/Branches. - * CIDA/Projects: Data for projects for the consulting arm (i.e., those with a P-number) should be stored in a subdirectory of CIDA/Projects. Use this [form](https://app.smartsheet.com/b/form/d1d93ae08f4349d48654950eea9b5bbd) to create folders in the P-drive with specific permissions, or this [form](https://app.smartsheet.com/b/form/c22bbec56f8d4607bedc441be60bf8c8) to update the permissions of an existing folder. These forms are directly sent to SOM IT. - * CIDA/Shared - * The CIDA/Shared directory is accessible to all CIDA members who have gained approval from a data manager. Folders are also accessible to external users who have been approved for access. - * Files and directories that you create on the shared drive inherit their permissions from their parent folder. You cannot restrict access to specific directories in accordance with data use agreements without the help of IT. -* Pros: - * All files and directories are backed up nightly; backups are stored for 30 days. - * Collaboration and transfers of data among CIDA members can be quick and easy. - * Data and code are easily findable by CIDA administration and other team members in the case of a CIDA member’s continued absence. -* Con: working directly on this drive can be slow, especially through a VPN. -* Best Practices: - * Up-to-date raw data for all projects should be available in their expected location on this drive at least weekly, and especially at project conclusion, or prior to a project not being actively worked on. - * Eliminate redundancies and intermediate data sets in projects with “big” data; only store the data you need to make code and reports run. - * It is OK not to work directly on the CIDA drive in cases where speed is a concern. If you do, know that all active projects should copy data over to the CIDA drive regularly (weekly), and especially prior to taking leave. The CIDAtools R package, located [here](https://github.com/CIDA-CSPH/CIDAtools), has the function `BackupProject()` that can streamline this process. By default, this function only updates folders/files in DataRaw/* and DataProcessed/* which have changed, so it should not take too long. -* CIDA pays for this server storage on a per-GB-month basis, so be cognizant of the size of the data utilized by your projects. If possible, the project’s scope of work should charge more for data sets and project materials which are anticipated to fall above a threshold of 32 GB. [The OIT’s central file storage rate](https://www1.ucdenver.edu/offices/office-of-information-technology/services/billing-and-rates) should be applied and multiplied to account for anticipated duration of storage. See below. - -__Data storage costs on CIDA drive__ -```{r table1, echo=FALSE, message=FALSE, warnings=FALSE, results='asis'} -tabl <- " -| | Expected 10-year cost ($) | -|---------------|:-------------:|------:|-----:| -| Data packet size (GB) | P-drive | OneDrive for Businness (per user)^1^ | Eureka^2^ | -| 10 | $30 | $600 | $28 | -| 100 | $300 | $600 | $276 | -| 1,000 (1 TB) | $3,000 | $600 | $2,760 | -| 10,000 (10 TB) | $30,000 | $1,200 | $27,600 | -" -cat(tabl) # output the table in a format good for HTML/PDF/docx conversion -``` -^1^Charged to University; not to CIDA -^2^Prices are based on the HDC website. - -#### OneDrive for Business - -* OneDrive for Business is a hybrid local and cloud storage system that allows for up to 5TB of cloud storage. Individual file size is limited to 15 GB. -* Unlike the CIDA drive, files and directories saved to the OneDrive directory are private by default and are backed up to the cloud. -* OneDrive for Business is HIPAA compliant. OIT and SOM IT can access folders created on the directory, but only after a manager enters a data access request that gets approved by HR. -* Files can be downloaded to your local computer from the cloud on an as-needed basis off-site, which ensures a limited amount of data is stored locally. -* Files can also be shared with other individuals with @cuanschutz.edu email addresses via OneDrive for Business. -* Things to be aware of: - * Do not confuse this with a personal OneDrive account! - * Do not install OneDrive for Business on an unencrypted or personal computer. Files may sync (and be downloaded) to the local computer, which would leave potentially sensitive data vulnerable. - * Concurrent use of OneDrive for Business in directories tracked by Git can lead to some syncing issues with OneDrive. This can typically be solved by restarting OneDrive. - * Relevant project data stored in OneDrive should be copied over to the CIDA drive regularly, especially when projects become inactive. - * Certain institutions and groups may have policies against using OneDrive for Business, so please verify with your research group that it is acceptable for your data to live there. - -#### External Servers - -* Depending on the project and the data of interest, the data may be housed in an external server. External servers exist in various forms and require varying workflows. -* Care should be taken that data living on an external server remain on the external server. However, code, reports, and any other files necessary to the project should still be copied to the CIDA drive at regular intervals (exceptions may exist, e.g., if other processes are specified in CIDA’s memorandum of understanding with your research group). - -#### Eureka by Health Data Compass (HDC) - -* Any patient level data on Eureka should only be moved off of the Google Cloud with explicit permission from HDC for that specific project and data. -* Raw data or data with PID should not be copied over to any other location except those approved by HDC. -* Backups of code, reports, and other files should still be copied over to the CIDA drive so that it is accessible to others in CIDA in case of an emergency. -* For projects requiring Eureka, the [Eureka Cost Estimator](https://www.healthdatacompass.org/cloud-analytics-infrastructure/eureka-cost-estimator) can be used to determine the expected costs of a particular project a priori. These costs should be charged to the project’s PI if possible. - -#### GitHub - -* In general, GitHub should be used for everything, except for data. While tracking small data sets in Git and pushing to GitHub is usually harmless, tracking data sets in Git can snowball the storage needed in GitHub and also slow down your git commands. -* Avoid tracking especially large binary data files (e.g. files with db, xls, xlsx, extensions). Instead, convert these files into a text file (e.g. tab-delimited txt file, csv file). This will speed up your git processes and help conserve storage space [see [link](https://stackoverflow.com/questions/17888604/git-with-large-files/19494211#19494211) for more information]. -* Instead of tracking data, one can build in a “[data-check](http://tombuntu.com/index.php/2007/12/21/how-to-use-md5sum-to-verify-data-integrity/)” in the code for the project to ensure the MD5 sums are as expected. -* Please consult the “coding guidelines” document for more information on the best practices for tracking your work in Git and GitHub. -* All repositories on GitHub should be updated frequently, but especially prior to leaving on vacation or any other extended time out of office. - -#### Really, really big data - -* If your data for a particular project is particularly large, you may require or wish to have a data storage solution tailored to that particular project (and funded entirely by the project). For non-Eureka solutions, please contact the SOM IT. -* Consider using CIDA’s HPC option (see below). - -#### CIDA-BIOS High Performance Computing Server - -* The HPC was purchased by CIDA and funds from a U01 grant (Katerina Kechris and Debashis Ghosh are PIs). Therefore, primary priority is given to CIDA & research related to the U01 grant. Secondary priority is given to Ghosh & Kechris group members. [Tertiary access can be attained by requesting access from Dr. Kechris via smartsheet.] -* The server is a Dell PowerEdge R740XD, with Intel Xeon Gold 6152 2.1G X (2) CPU, 44 cores, 1TB memory, 240 SSD X (2) mirrored disk operating system, and ~50TB of usable disk storage. The operating system is CentOS 7.x, and common research software are available such as R, R Studio, MatLab, Python, and Java. -* Server is not HIPAA compliant and therefore no PHI can be stored on the server. -* Backups are available via Wasabi: https://wasabi.com/hot-cloud-storage/. - -#### Unapproved data storage options - -* __Only the options listed above are approved by CIDA for temporary data storage, and only the CIDA drive is approved for ongoing data storage__. Please follow the best practices and ask questions if you have them. -* __The following non-exhaustive list of data storage options are not approved by CIDA__: - * Dropbox - * Google Drive - * OneDrive (personal) - * Unencrypted hard drive or flash drive - -### Data Transfer Options - -```{r table2, echo=FALSE, message=FALSE, warnings=FALSE, results='asis'} -tabl <- " -| Mode of transfer | Notes | -|---------------|:-------------:|------:|-----:| -| CIDA drive | For transfers among CIDA members, the CIDA drive can be used for data transfer | -| OneDrive for Business | University-preferred means of transferring data | -| Redcap | Web-based, useful for ongoing projects where data updates are more frequent, ensures data format stays more consistent | -| External hard/flash drive | Acceptable: CIDA’s 48 TB NAS station, or an encrypted flash drive. Unacceptable: Unencrypted drive, even if the file is password protected - | -| Last resort: Email | Email is not encouraged means of transferring data. In circumstances when no other approach is available, note that although email between CU-affiliated email addresses are automatically encrypted, this is not the case for external emails. You can manually encrypt by putting one of these keywords in brackets in the subject of an email: secure, safemail, or encrypt. Email from any other email system, such as gmail, is not acceptable. - | -| Not acceptable | Non-approved web-based systems including: Dropbox, Google Drive, … Unencrypted flash/hard drives, even if the file is password protected. Email from any other email system, such as gmail | -" -cat(tabl) # output the table in a format good for HTML/PDF/docx conversion -``` - -### Useful Links -Health Insurance Portability and Accountability Act (HIPAA): -http://www.hhs.gov/hipaa/for-professionals/index.html - -Health Information Technology for Economic and Clinical Health (HITECH): -http://www.hhs.gov/hipaa/for-professionals/special-topics/HITECH-act-enforcement-interim-final-rule/index.html - -Guidance Regarding Methods for De-identification of Protected Health Information in Accordance with the Health Insurance Portability and Accountability Act (HIPAA) Privacy Rule: -http://www.hhs.gov/hipaa/for-professionals/privacy/special-topics/de-identification/index.html - -VPN and Remote Desktop: -https://www1.ucdenver.edu/offices/office-of-information-technology/software/how-do-i-use/vpn-and-remote-access - -GitLab: -http://cidagitlab.ucdenver.pvt/ - -OneDrive for Business: -https://www1.ucdenver.edu/offices/office-of-information-technology/software/how-do-i-use/onedrive -https://www1.ucdenver.edu/docs/default-source/offices-oit-documents/how-to-documents/onedrive-staying-secure.pdf?sfvrsn=668bb7b8_4 - -Eureka: -https://www.healthdatacompass.org/cloud-analytics-infrastructure/using-eureka -https://www.healthdatacompass.org/cloud-analytics-infrastructure/eureka-cost-estimator diff --git a/vignettes/figures/CIDA_BIOS_Cluster/Biostats_HPC_diagram.png b/vignettes/figures/CIDA_BIOS_Cluster/Biostats_HPC_diagram.png deleted file mode 100644 index 039c624..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster/Biostats_HPC_diagram.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster/biostats_hpc_ssh.png b/vignettes/figures/CIDA_BIOS_Cluster/biostats_hpc_ssh.png deleted file mode 100644 index 7fd795a..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster/biostats_hpc_ssh.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster/cluster_basic_diagram.png b/vignettes/figures/CIDA_BIOS_Cluster/cluster_basic_diagram.png deleted file mode 100644 index ecb5d83..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster/cluster_basic_diagram.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster/cluster_sbatch.png b/vignettes/figures/CIDA_BIOS_Cluster/cluster_sbatch.png deleted file mode 100644 index 3c18a56..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster/cluster_sbatch.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster/cluster_srun.png b/vignettes/figures/CIDA_BIOS_Cluster/cluster_srun.png deleted file mode 100644 index 7b1c15d..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster/cluster_srun.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster/cyberduck_1.png b/vignettes/figures/CIDA_BIOS_Cluster/cyberduck_1.png deleted file mode 100644 index 4ce28f1..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster/cyberduck_1.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster/cyberduck_2.png b/vignettes/figures/CIDA_BIOS_Cluster/cyberduck_2.png deleted file mode 100644 index d7d642b..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster/cyberduck_2.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster/cyberduck_3.png b/vignettes/figures/CIDA_BIOS_Cluster/cyberduck_3.png deleted file mode 100644 index be6a7e1..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster/cyberduck_3.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster/interactive_job.png b/vignettes/figures/CIDA_BIOS_Cluster/interactive_job.png deleted file mode 100644 index b9958b4..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster/interactive_job.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_jupyter_interface.png b/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_jupyter_interface.png deleted file mode 100644 index e4be007..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_jupyter_interface.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_jupyter_launch.png b/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_jupyter_launch.png deleted file mode 100644 index 7b8d485..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_jupyter_launch.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_diagram.png b/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_diagram.png deleted file mode 100644 index d1676f7..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_diagram.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_interface.png b/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_interface.png deleted file mode 100644 index 830e976..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_interface.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_launch.png b/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_launch.png deleted file mode 100644 index 3f6236b..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_rstudio_launch.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_ssh_2.png b/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_ssh_2.png deleted file mode 100644 index 5ef554d..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_ssh_2.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_ssh_local_forward_test.png b/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_ssh_local_forward_test.png deleted file mode 100644 index 4a7294c..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/biostats_hpc_ssh_local_forward_test.png and /dev/null differ diff --git a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/localhost_test.png b/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/localhost_test.png deleted file mode 100644 index c2a47b7..0000000 Binary files a/vignettes/figures/CIDA_BIOS_Cluster_Interactive_IDEs/localhost_test.png and /dev/null differ diff --git a/vignettes/figures/coding_guidelines/coding_1.png b/vignettes/figures/coding_guidelines/coding_1.png deleted file mode 100644 index cf25844..0000000 Binary files a/vignettes/figures/coding_guidelines/coding_1.png and /dev/null differ diff --git a/vignettes/figures/coding_guidelines/coding_2.png b/vignettes/figures/coding_guidelines/coding_2.png deleted file mode 100644 index 9618e05..0000000 Binary files a/vignettes/figures/coding_guidelines/coding_2.png and /dev/null differ diff --git a/vignettes/figures/git/figure0A.png b/vignettes/figures/git/figure0A.png deleted file mode 100644 index a5acb8a..0000000 Binary files a/vignettes/figures/git/figure0A.png and /dev/null differ diff --git a/vignettes/figures/git/figure0C.png b/vignettes/figures/git/figure0C.png deleted file mode 100644 index 9523104..0000000 Binary files a/vignettes/figures/git/figure0C.png and /dev/null differ diff --git a/vignettes/figures/git/figure1A.png b/vignettes/figures/git/figure1A.png deleted file mode 100644 index 4c6fb41..0000000 Binary files a/vignettes/figures/git/figure1A.png and /dev/null differ diff --git a/vignettes/figures/git/figure1B.png b/vignettes/figures/git/figure1B.png deleted file mode 100644 index 0b98d7b..0000000 Binary files a/vignettes/figures/git/figure1B.png and /dev/null differ diff --git a/vignettes/figures/git/figure1C.png b/vignettes/figures/git/figure1C.png deleted file mode 100644 index 3e5deea..0000000 Binary files a/vignettes/figures/git/figure1C.png and /dev/null differ diff --git a/vignettes/figures/git/figure2A.png b/vignettes/figures/git/figure2A.png deleted file mode 100644 index 2ab8a46..0000000 Binary files a/vignettes/figures/git/figure2A.png and /dev/null differ diff --git a/vignettes/figures/git/figure2B.png b/vignettes/figures/git/figure2B.png deleted file mode 100644 index efe5343..0000000 Binary files a/vignettes/figures/git/figure2B.png and /dev/null differ diff --git a/vignettes/figures/git/figure2C.png b/vignettes/figures/git/figure2C.png deleted file mode 100644 index 9094655..0000000 Binary files a/vignettes/figures/git/figure2C.png and /dev/null differ diff --git a/vignettes/figures/git/figure3A.png b/vignettes/figures/git/figure3A.png deleted file mode 100644 index fc0acda..0000000 Binary files a/vignettes/figures/git/figure3A.png and /dev/null differ diff --git a/vignettes/figures/git/figure3B.png b/vignettes/figures/git/figure3B.png deleted file mode 100644 index d29cb78..0000000 Binary files a/vignettes/figures/git/figure3B.png and /dev/null differ diff --git a/vignettes/figures/git/figure3C.png b/vignettes/figures/git/figure3C.png deleted file mode 100644 index 0eee172..0000000 Binary files a/vignettes/figures/git/figure3C.png and /dev/null differ diff --git a/vignettes/figures/git/figure4A.png b/vignettes/figures/git/figure4A.png deleted file mode 100644 index 43681db..0000000 Binary files a/vignettes/figures/git/figure4A.png and /dev/null differ diff --git a/vignettes/figures/git/figure4B.png b/vignettes/figures/git/figure4B.png deleted file mode 100644 index 791de25..0000000 Binary files a/vignettes/figures/git/figure4B.png and /dev/null differ diff --git a/vignettes/figures/git/figure4C.png b/vignettes/figures/git/figure4C.png deleted file mode 100644 index 1b3a1eb..0000000 Binary files a/vignettes/figures/git/figure4C.png and /dev/null differ diff --git a/vignettes/figures/git/figure4D.png b/vignettes/figures/git/figure4D.png deleted file mode 100644 index e0bbbd0..0000000 Binary files a/vignettes/figures/git/figure4D.png and /dev/null differ diff --git a/vignettes/figures/git/figure5A.png b/vignettes/figures/git/figure5A.png deleted file mode 100644 index e38cfb3..0000000 Binary files a/vignettes/figures/git/figure5A.png and /dev/null differ diff --git a/vignettes/figures/git/sph_cida_wm_blk.png b/vignettes/figures/git/sph_cida_wm_blk.png deleted file mode 100644 index 406c445..0000000 Binary files a/vignettes/figures/git/sph_cida_wm_blk.png and /dev/null differ diff --git a/vignettes/git.Rmd b/vignettes/git.Rmd deleted file mode 100644 index b675dae..0000000 --- a/vignettes/git.Rmd +++ /dev/null @@ -1,548 +0,0 @@ ---- -title: "Tracking code in Git/GitHub" -date: "Last updated: `r Sys.Date()`" -author: "CIDA Research Tools Committee" -output: - html_document: - highlight: default - number_sections: yes - theme: yeti - toc: yes - toc_depth: 3 - toc_float: yes -vignette: > - %\VignetteIndexEntry{git} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r, echo=FALSE, out.width='70%', fig.show='hold'} -knitr::include_graphics("figures/git/sph_cida_wm_blk.png") -``` - ---- - -```{r setup, include=FALSE} -library(CIDAtools) -``` - -# Introduction - -## What is Git? - -According to Git's website, "Git is a free and open source distributed version -control system." So what does that mean? Let's break it down. First, Similarly to R, -Git is available to anyone with a computer and access to the internet free of -charge. Anyone can install and use it, and anyone can contribute to the project -(if they have the technical know-how). - -As for the second half, a version control system (VCS) is a tool that enables -teams as small as a single person or as large as a multinational corporation to -track changes in code over time and to integrate changes made by a -decentralized team of developers. - -For our purposes, Git enables us to create reproducible analysis code bases, -where the full history of the analysis is available to ourselves and those which -we choose to share it with. - -## What is GitHub? - -## Command Line Basics - -In order to use Git from the command line (Terminal or Git Bash), a certain -level of basic commands will be needed to navigate the files on your computer. -Below is a list of commands that will help you navigate your directories and -accomplish basic tasks using the command line. - -- `ls` - List subdirectories and files in current directory -- `pwd` - Print working directory -- `cd` - Change directory (i.e., navigate to a different folder) - - `cd MyFolder` - Move to the folder `MyFolder` located in current working - directory - - `cd Path/To/MyFolder` - Move to the folder `MyFolder` located at - `Path/To/` inside the current working directory - - `cd ..` - Move to parent directory (i.e. one folder back) - - `cd /` - Move to root directory - - `cd ~` - Move to home directory -- `mkdir` - Make directory -- `rm ` - Remove file - -## Notes - -### Terminal / Git Bash - -The instructions which follow attempt to be applicable to both MacOS and Windows -platforms. However, some key differences do exist between the two -operating systems. In most of these situations we have created separate -instructions for Windows and MacOS. However, for sections where MacOS and -Windows are functionally the same, only a single section is provided. In these -sections, some language used may reference Terminal, and in those cases you -should substitute Git Bash if you are using Windows operating system. - -### Main vs Master - -Historically, the default branch in a new Git repository was named `master`. -However, in 2020 a push to remove unnecessary references to slavery led -GitHub and other companies to change the default branch name to `main`. The -instructions which follow will assume the default branch name is `main` and -will show you how to setup your local Git configuration to default to `main`. - -However, due to the relative recency of this change, you may encounter -repositories that have `master` as the primary branch. In such situations, all -the instructions which follow will still be applicable, but you will need to -substitute `main` for `master`. - -# Getting Started - -## Installing Git - -### MacOS - -Open Terminal and run the command `git --version`. If you don't have Git -installed already, you will be prompted to install. Follow the -instructions provided in the Terminal or pop-up window to install Git. - -### Windows - -Git and Git Bash come included as part of the -[Git For Windows](https://gitforwindows.org/) package. -Download and install Git For Windows like other Windows applications. Once -downloaded find the included `.exe` file and open to execute Git Bash. - -## Creating GitHub Account - -Go to and click `Sign Up` in the upper right hand corner. -Follow the instructions to create an account, choosing an account name that is -easily identifiable as belonging to you (i.e. "firstname-lastname" or something -similar). - -__NOTE:__ If you already have a personal GitHub account, you may continue to use -it for your work at CIDA __if__ your account name is easily identifiable as -belonging to you (i.e. if you have an account name like "firstname-lastname" or -something similar). - -## Configure Git - -To associate your local Git configuration with your name and Email, run the -commands below in Terminal or Git Bash. Here, `your_email@cuanschutz.edu` should -be substituted with -the email associated with your GitHub account. If you are using a preexisting -personal GitHub account, this may or may not end with `cuanschutz.edu`. - -```{bash, eval=FALSE, echo=TRUE} -git config --global user.name "Firstname Lastname" -git config --global user.email "your_email@cuanschutz.edu" -``` - -Additionally, your local Git should be configured to make `main` the default -branch name. To do so, run the following command in Terminal/GitBash: - -```{bash, eval=FALSE, echo=TRUE} -git config --global -add init.defaultBranch main -``` - -## Requesting CIDA GitHub Access - -Following account creation, send an email containing your GitHub username to -`ryan peterson cuanschutz edu` and -`max mcgrath cuanschutz edu` to request access to CIDA's GitHub -organization (please send email from your cuanschutz.edu email address). - -## Setting Up SSH - -The below instructions are up-to-date as of 10/05/22. Newer instructions along -with additional troubleshooting may -be available from [GitHub](https://docs.github.com/en/authentication/connecting-to-github-with-ssh) - -### MacOS - -1. Check for Existing SSH Keys - a. Open Terminal - b. Enter `ls -al ~/.ssh` to see if existing SSH keys are present by looking - for the following filenames: - - id_rsa.pub - - id_ecdsa.pub - - id_ed25519 - c. If you see any of these files present, proceed to Step 3. Otherwise - continue with Step 2. -2. Generate a new SSH key - a. Open Terminal - b. Enter `ssh-keygen -t ed25519 -C "your_email@example.com"` substituting in - the email address associated with your GitHub account - c. When you're prompted to "Enter a file in which to save the key," press - Enter. This accepts the default file location. - d. At the prompt, type a secure passphrase - e. Start the ssh-agent in the background by running `eval "$(ssh-agent -s)"` - f. Open the configuration file with `open ~/.ssh/config` - - If the file doesn't exist create it with `touch ~/.ssh/config` then use - the above command to open it - g. Edit `~/.ssh/config` to contain the following lines: - -```{bash, eval=FALSE, echo=TRUE, indent = " "} -Host * - AddKeysToAgent yes - UseKeychain yes - IdentityFile ~/.ssh/id_ed25519 -``` - h. Add your SSH private key to the ssh-agent and store your password in the - keychain by running `ssh-add --apple-use-keychain ~/.ssh/id_ed25519` -3. Add SSH key to GitHub account - a. Copy the SSH public key to your clipboard with - `pbcopy < ~/.ssh/id_ed25519.pub` - b. Open GitHub in a web browser, log in - c. Go the the upper right hand corner, click your profile photo, and - select __Settings__ - d. Select __SSH and GPG keys__ in the menu on the left - e. Click green __New SSH key__ button - f. Enter a title for the SSH key in the __Title__ field (use descriptive - title like "CIDA MacBook Pro") - g. Select __Key type__ as "Authentication Key" - h. Paste your key into the __Key__ field - i. Click __Add SSH key__ -4. Verify connection - a. Test access to GitHub SSH with `ssh -T git@github.com` - b. If you see the following message, verify that the fingerprint you see - matches GitHub's public key fingerprint - ([link](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints)). - If it does, type `Yes` -```{bash, eval=FALSE, echo=TRUE, indent = " "} -> The authenticity of host 'github.com (IP ADDRESS)' cant be established. -> RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8. -> Are you sure you want to continue connecting (yes/no)? -``` - c. Verify that the resulting message contains your username. If you receive - a "permission denied" message, see [Error: Permission denied (publickey)](https://docs.github.com/en/authentication/troubleshooting-ssh/error-permission-denied-publickey) - - -### Windows - -1. In Git Bash, type `ssh-keygen` -2. Press enter to save the SSH key to the default location -3. Enter a password to password protect your SSH key or leave blank and hit -`Enter` to proceed without a password -4. You will recieve a message saying your public key has been saved in -`c/Users/username/.ssh/id_rsa.pub`, type `cat c/Users/username/.ssh/id_rsa.pub` -to output the key -5. Copy and paste the key -6. Add SSH key to GitHub account - a. Open GitHub in a web browser, log in - b. Go the the upper right hand corner, click your profile photo, and - select __Settings__ - c. Select __SSH and GPG keys__ in the menu on the left - d. Click green __New SSH key__ button - e. Enter a title for the SSH key in the __Title__ field (use descriptive - title like "CIDA MacBook Pro") - f. Select __Key type__ as "Authentication Key" - g. Paste your key into the __Key__ field - h. Click __Add SSH key__ - - -## Setting up SSO - -Copy/distill instructions here: - - -1. After being granted access to the CIDA-CSPH GitHub organization and setting -up SSH, go to , log in -2. In the upper-right corner of any page, click your profile photo, then click -__Settings__ -3. Select __SSH and GPG keys__ in the menu on the left -4. To the right of the SSH key you'd like to authorize, click __Configure SSO__. -If you don't see __Configure SSO__, ensure that you have authenticated at least -once with the CIDA-CSPH organization by visiting -, accessing a non-public repository, and -signing in with your CU login -5. You will see __CIDA-CSPH__ listed. Click __Authorize__ to the right. - -## Creating New Project - -1. Create project folder on your local computer by calling -`CIDAtools::create_project()` in `R` -2. Initialize git repository by navigating to folder (`cd Path/To/Folder`) then -using the command `git init` -3. Stage file changes `git add . ` -4. Create initial commit with `git commit -m "Initial commit"` -5. Create empty repository in CIDA-CSPH GitHub organization - a. In a web browser, navigate to - b. Sign in using your CU login - c. Click the green `New repository` button - d. Enter the name of your repository - e. Do __not__ add a template, README, .gitignore, or license file - f. Click `Create repository` -6. Add remote to local repository with -`git remote add origin git@github.com:CIDA-CSPH/.git` (this SSH link -can be copied from the empty GitHub remote repository you've just created). -7. Push work to GitHub with `git push origin main` - -## Cloning Existing Project - -1. Navigate to GitHub remote repository -2. Click green "Code ∨" button -3. Click "SSH" then copy link -4. Clone repository with `git clone git@github.com:CIDA-CSPH/.git` - -# Regular Workflow - -1. Add and commit changes -```{bash, eval=FALSE, echo=TRUE, indent=" "} -cd Path/To/Directory -git add . -git commit -m "My commit message" -``` -2. Fetch and merge any changes (see Handling Merge Conflicts below) -```{bash, eval=FALSE, echo=TRUE, indent=" "} -git fetch origin main -git merge origin/main -## Fix any merge conflicts -git commit -m "Brief description of changes (<=50 characters)" -``` -3. Push all new commits -```{bash, eval=FALSE, echo=TRUE, indent=" "} -git push origin main -``` - -## Handling Merge conflicts - -In the case that another user has modified and committed changes to a file that -you have modified in one of your recent commits, when you run `git pull` you -may be notified that you have a merge conflict and need to resolve those -conflicts before you can push your changes to GitHub. To do so: - -1. After running `git merge origin/main` and being notified that you have -merge conflicts, run `git status` to see which files have conflicts (they -will be listed with `both modified: ` in front of them) - a. Note: On newer version of Git you may receive an error saying "You have - divergent branches and need to specify how to reconcile them" - b. In this case, you can add an indicator to pull without rebasing with - `git merge --no-rebase origin/main` -2. Open those files in a text editor (RStudio, Vim, textEdit, Notepad++, etc.) -3. Here, you will see some sections of code with: - -```{r, eval=FALSE, echo=TRUE, indent=" "} -<<<<<<< HEAD -# Version 1 of Code -======= -# Version 2 of Code ->>>>>>> commit_hash -``` - -4. Here, the section of code between `<<<<<<< HEAD` and `=======` is the local -version of the code, while the code between `=======` and `>>>>>>> commit_hash` -is the version of the code pulled from the remote (i.e., GitHub) -5. To fix the merge conflict, simply select which version of the code you want -to keep and delete the other version along with -`<<<<<<< HEAD` and `=======` and `>>>>>>> commit_hash`. Note that you may also -need to mix and match between the two sections of code, but always delete the -conflict markers. -6. Save your changes -7. Return to Terminal/Git Bash and add commit changes -```{bash, eval=FALSE, echo=TRUE, indent=" "} -git add . -git commit -``` - -# Additional Git Topics - -## Branching - -## Stashing changes - -## Helpful Git Commands - -# FAQ - -
- -__Do we use GitHub? Or GitLab? Didn’t we just switch to GitHub?__ - -Either are currently viable options. We are currently transitioning from -GitLab to GitHub, so if you are picking this up for the first time, I suggest -using GitHub (and will call both “GH” from here on for simplicity). - -
- -__Where does my main analysis code "live"? When I'm committing and pushing to__ -__GitHub/Lab am I just making backups of my work that has its "home" on the__ -__P: drive? Or should the code "live" on the cloud in GitHub/GitLab, and every__ -__time I want to work with it, I should pull it down?__ - -Your code will live on GH. Repos from GH can be cloned to wherever you want; -locally, the P drive, etc. So when you need to run your code, your machine can -read it from a local or network location. It’s best practice to pull from GH -before you need to run anything for a project in case someone’s changed (if -nothing has changed it will say “You repo is up to date”). - -
- -__Should I even then have a version of my code on the P: drive at all?__ - -It’s up to you - -
- -__If I do, and I pull from GitHub/Lab, am I replacing the code on the P:__ -__drive?__ - -Yes, but only if something’s changed on the GitHub server. You can also easily -“checkout” earlier versions of the repository from previous points in time, so -the older code is never lost. - -
- -__One advantage that people talk about a lot for using Git is that it can__ -__"merge" files from multiple people. How does this actually work?. What’s__ -__to prevent person A from pulling the syntax and making edits, person B__ -__pulling the syntax and making edits, and then both people pushing up to a__ -__Git server? Wouldn't there then be 2 versions of the file, neither of them__ -__fully correct? How is this an upgrade from not having Git?__ - -Git will force the person who pushes second to fix any merge issues in the -code before pushing back to GitHub in this case. There are also more tools -available such as branching if this issue comes up often for a particular -project. - -
- -__I don't really use that much version control now anyways, ad-hoc or__ -__otherwise. Is this bad? Have I just not been exposed to projects that__ -__change enough to merit it?__ - -CIDA requires code be tracked in Git and GitHub. Your future self will thank -you. - -
- -__Often in my code I include additional “justification” code that’s__ -__commented out. For example, if I merge two datasets on ID, I also check__ -__the dimensions of the new merged dataset to make sure it is what I expected.__ -__Or, if I write a function, I also hard-code a version of the function__ -__to make sure the function actually does what it’s supposed to. These__ -__examples are a bit trivial, but I think they illustrate well the sort of__ -__“double-checking” that I sometimes include code for. Is this the sort of__ -__thing you think is valuable to include in code as a comment? Or does that__ -__bother some people, and should it be taken out of the syntax after the__ -__double-check has been completed?__ - -I think what you are referring to is “unit testing”, which is in fact good -practice. I would put all new functions you create in a separate -`helper-functions.R` file which can be scripted from your Rmd, and you can also -have your (self-contained) unit tests there as well. - -
- -__Isn't there a CIDA element to the GH platform that we need to use, that__ -__is more "secure" or something? Or are we only supposed to use our personal__ -__GH accounts for all our work?__ - -CIDA has a GitHub "organization" that is part of the CU GitHub Enterprise -account. Membership to this organization can be merged with your personal GitHub -account or a new GitHub account. All university- (CIDA-) related repos should -live under this umbrella. The main page is https://github.com/CIDA-CSPH; you -will need an account invitation; please contact a member of the Research Tools -committee for an invitation. - -
- -# Git Kraken (Legacy) - -This section will walk through how to set up GitKraken to interface with the -CIDA GitHub, allowing you to easily push/pull projects between your working -directory and GitHub. - -First, you will have to download GitKraken at -. Once installed, you will sign in with the -GitHub account associated with the CIDA GitHub. This will take you to the SSO -associated with the CIDA GitHub, which you will then authorize and sign onto. - -```{r, echo=FALSE, out.width="100%", out.height="100%"} -knitr::include_graphics("figures/git/figure0A.png") -knitr::include_graphics("figures/git/figure0C.png") -``` - -Once you have logged into GitKraken with you GitHub account, you will need to -connect it to GitHub. The default GitKraken screen has a panel called -"Integrations": click on GitHub. From here, there are two possibilities: if you -click on "Connect to GitHub" it may take you to the SSO again and you can log in -that way (slightly repetitive). Or, if prompted to use the OAuth or Personal -Access token, you can do the following: go to your "Settings" tab on GitHub, -click on "Developer Settings", and then click on "Personal access tokens" to -generate a token for 90 days, making sure to select "repo" (along with other -scopes as needed). - -```{r, echo=FALSE, out.width="100%", out.height="100%"} -knitr::include_graphics("figures/git/figure1A.png") -knitr::include_graphics("figures/git/figure1B.png") -knitr::include_graphics("figures/git/figure1C.png") -knitr::include_graphics("figures/git/figure2A.png") -knitr::include_graphics("figures/git/figure2B.png") -knitr::include_graphics("figures/git/figure2C.png") -``` - -Ideally, you should be able to automatically connect to GitHub without -generating a personal access token, but GitKraken is moderately cursed. - -Once you have successfully connected to GitHub, you will then need to generate -an SSH key and add to GitHub. To do this, simply click the "Generate SSH key -and add to GitHub" button (optionally adding a title to the SSH key if you -wish). If this step is successful, you will receive a notification within -GitKraken on the lower left, and your screen will now display the SSH key -within GitKraken and under the Settings -> SSH and GPG keys tab on your GitHub: - -```{r, echo=FALSE, out.width="100%", out.height="100%"} -knitr::include_graphics("figures/git/figure3A.png") -knitr::include_graphics("figures/git/figure3B.png") -knitr::include_graphics("figures/git/figure3C.png") -``` - -Congratulations, you should be successfully linked to the CIDA GitHub! - -From here, you can open, clone, and initiate repositories from the CIDA Github -using the, you guessed it, Open a repo, Clone a repo, and Start a local repo -options on the home screen: - -```{r, echo=FALSE, out.width="100%", out.height="100%"} -knitr::include_graphics("figures/git/figure4A.png") -``` - -If you are going to clone a repo, just make sure you are on the GitHub.com -section, and that you select the CIDA repository to clone, as well as where you -would like to clone it to (H: or P: drives, or elsewhere). - -```{r, echo=FALSE, out.width="100%", out.height="100%"} -knitr::include_graphics("figures/git/figure4B.png") -``` - -First, however, you will need to generate another SSH key on GitKraken to add -to your GitHub (at least this is the only way that I can figure). Go to -Preferences -> SSH and then generate a new Private/Public Key, or copy the SSH -Public Key if you already have one: - -```{r, echo=FALSE, out.width="100%", out.height="100%"} -knitr::include_graphics("figures/git/figure4C.png") -``` - -Then return to your GitHub account, and click on SSH and GPG keys under the -settings, click Add new key, and then copy the SSH key into the Key box. You -will then need to Authorize it with the SSO. After that, you should be able to -clone, open, and initialize your repos! - -```{r, echo=FALSE, out.width="100%", out.height="100%"} -knitr::include_graphics("figures/git/figure4D.png") -``` - -Once you have cloned a repo, you can open it to push/pull any changes. This is -done pretty simply via the push or pull commands on the top after opening the -repo. - -```{r, echo=FALSE, out.width="100%", out.height="100%"} -knitr::include_graphics("figures/git/figure5A.png") -``` - -For more details on how to manage pull, push, branching, and other features, -visit https://help.gitkraken.com/gitkraken-client/github-gitkraken-client/ - ---- - -```{r, echo=FALSE, out.width='70%', fig.show='hold'} -knitr::include_graphics("figures/git/sph_cida_wm_blk.png") -``` diff --git a/vignettes/sas-macros.Rmd b/vignettes/sas-macros.Rmd deleted file mode 100644 index cf09f89..0000000 --- a/vignettes/sas-macros.Rmd +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: "CIDA SAS Macros" -date: "Last updated: `r Sys.Date()`" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{CIDA SAS Macros} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>", - echo = FALSE -) - -library(kableExtra) - -``` - - -## List of SAS macros - -SAS macros in CIDAtools can be searched below, and their source code is available [here](https://github.com/CIDA-CSPH/CIDAtools/tree/master/inst/sas). - -```{r} -# eval=rmarkdown::pandoc_available("1.12.3") - -path <- system.file("sas", package = "CIDAtools") - -if(length(path)) { - sas_files <- list.files(path, full.names = T) - - keywords <- sapply(sas_files, function(f) { - lines <- readLines(f) - keys <- lines[grepl("Keywords", lines, ignore.case = T)] - gsub("\\*|\\* |Keywords: |;", "", keys, ignore.case = T) - }) - - sas_index <- data.frame( - name = list.files(path, full.names = F), - keywords = keywords, row.names = NULL - ) - - # DT::datatable(sas_index) - kable(sas_index) %>% - kable_styling(c("striped", "condensed"), full_width = F) -} -``` diff --git a/vignettes/tabling_packages.Rmd b/vignettes/tabling_packages.Rmd deleted file mode 100644 index b8e8966..0000000 --- a/vignettes/tabling_packages.Rmd +++ /dev/null @@ -1,248 +0,0 @@ ---- -title: "Tabling Packages" -author: "Research Tools Committee" -date: "`r Sys.Date()`" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Tabling Packages} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -mtcars <- mtcars -trial <- gtsummary::trial -``` - -## Introduction - -These vignettes will walk through examples for some of the most common tabling packages including gtsummary, kable/kableExtra, table1. All examples here work with the toy datasets such as `mtcars`. - -## gtsummary - -gtsummary is commonly used for its flexibility and compatability with different types of output. The syntax is pretty straightforward and can make a table of all variables with one line of code and minimal adjusting. - -```{r} -gtsummary::tbl_summary(mtcars) -``` - - - -You can stratify by multiple variables using `tbl_strata` -```{r} -trial |> - gtsummary::tbl_strata( - strata = trt, - .tbl_fun = - ~ .x |> - gtsummary::tbl_summary(by = stage) - ) -``` - - -You can split tables by a variable, add missingness, change variable labels, adjust which statistics are presented and more... It is a very flexible package. -```{r} -gtsummary::tbl_summary(trial, - by = trt, - missing = "ifany", - missing_text = "Missing", - label = grade ~ "Tumor Grade", - statistic = list(age~"{median} ({p25},{p75})", - marker ~ "{mean} ({sd})", - gtsummary::all_categorical() ~ "{n}/{N}")) |> - gtsummary::add_p(pvalue_fun = ~ gtsummary::style_pvalue(.x, digits = 2)) |> - gtsummary::add_overall() |> - gtsummary::add_q(method = "fdr") |> - gtsummary::modify_header(label = "**Variables**") |> - gtsummary::bold_labels() |> - gtsummary::italicize_levels() |> - gtsummary::modify_caption("**Table 1**") -``` - -gtsummary has themes that can be adjusted as shown below. This code sets the default gtsummary package theme to be "jama" theme" and will be used for all gtsummary objects unless otherwise specified. - -```{r} -# changing aesthetics using themes -gtsummary::theme_gtsummary_journal("jama", set_theme = T) -gtsummary::tbl_summary(mtcars) -``` - -Themes can apply to more than visual aspects and can set how certain variables are displayed -```{r} -# changing how continuous variables are presented using themes -gtsummary::theme_gtsummary_mean_sd(set_theme = TRUE) -gtsummary::tbl_summary(mtcars) -``` - -Note this theme shows median, mean and IQR - -```{r} -gtsummary::theme_gtsummary_eda(set_theme = TRUE) #note this theme shows median, mean and IQR -gtsummary::tbl_summary(mtcars) -``` - -Explore `?theme_gtsummary` for more ways to set themes for GT Summary Tables. - -Other functions that may be of interest: - -tbl_uvregression() - For running a series of univariate analyses -```{r} -gtsummary::tbl_uvregression( - trial, - method = glm, - y = response, - method.args = list(family = binomial), - exponentiate = TRUE, - include = c("age", "grade", "stage") -) -``` - -tbl_regression() - For summarizing a single regression model. Also supports survival models, and some Bayesian models from the rstanarm and brms packages -```{r} -stats::glm(response ~ trt, data= trial) |> - gtsummary::tbl_regression(exponentiate = TRUE) -``` - - -tbl_stack() or tbl_merge - to combine table results -```{r} -# stacking two tbl_regression objects -t1 <- - stats::glm(response ~ trt, trial, family = binomial) |> - gtsummary::tbl_regression( - exponentiate = TRUE, - label = list(trt ~ "Treatment (unadjusted)") - ) - -t2 <- - stats::glm(response ~ trt + grade + stage + marker, trial, family = binomial) |> - gtsummary::tbl_regression( - include = "trt", - exponentiate = TRUE, - label = list(trt ~ "Treatment (adjusted)") - ) - -gtsummary::tbl_stack(list(t1, t2)) -``` - -```{r} -t3 <- - stats::glm(response ~ trt + grade + age, trial, family = binomial) |> - gtsummary::tbl_regression(exponentiate = TRUE) -t4 <- - survival::coxph(survival::Surv(ttdeath, death) ~ trt + grade + age, trial) |> - gtsummary::tbl_regression(exponentiate = TRUE) - -gtsummary::tbl_merge( - tbls = list(t3, t4), - tab_spanner = c("**Tumor Response**", "**Time to Death**") -) -``` - - -## Flextable - -Flextable plays well with gtsummary with the function `as_flex_table`. This may be of interest as flextable advertises itself as one of the few tabling packages that plays well with HTML, PDF and Word outputs. Most packages handle html well but sometimes struggle with losing capability with word or pdf outputting. Note the `autofit` function should fix any width problems that may occur with tables running off the page. - -```{r} -ft <- flextable::flextable(airquality[ sample.int(10),]) -ft <- flextable::add_header_row(ft, - colwidths = c(4, 2), - values = c("Air quality", "Time") -) -ft <- flextable::theme_vanilla(ft) -ft <- flextable::add_footer_lines(ft, "Daily air quality measurements in New York, May to September 1973.") -ft <- flextable::color(ft, part = "footer", color = "#666666") -ft <- flextable::set_caption(ft, caption = "New York Air Quality Measurements") -ft -``` - -Flextable also offers a variety of themes / settings that can be adjusted. - -```{r} -flextable::flextable(airquality[ sample.int(10),]) |> flextable::theme_box() -``` - -Or changing default settings like below - -```{r} -flextable::set_flextable_defaults( - font.size = 10, theme_fun = flextable::theme_vanilla, - padding = 6, - background.color = "#EFEFEF") -flextable::flextable(airquality[ sample.int(10),]) |> flextable::autofit() -``` - -## Kable/KableExtra - -Kable can be viewed as the base package that can be built on or styled with KableExtra. Note if you load KableExtra, kable will be loaded in the background if it is not already. KableExtra also allows working with piping (%\>% or |\> ) for added simplicity when editing a table. - -The first step, the kable call is pretty simple but is fairly limited in themes etc. - -```{r} -kableExtra::kable(mtcars, align = "lccrr") -``` - -Adding a simple kable_styling() call makes it much better visually - -```{r} -kableExtra::kable(mtcars, align = "lccrr") |> kableExtra::kable_styling() -``` - -Below are a handful of other options found within the "Kable universe". - -```{r} -mtcars |> - kableExtra::kbl(caption = "Recreating booktabs style table") |> - kableExtra::kable_classic(full_width = F, html_font = "Cambria") -``` - -```{r} -mtcars |> - kableExtra::kbl() |> - kableExtra::kable_material(c("striped", "hover")) -``` - -```{r} -mtcars |> - kableExtra::kbl() |> - kableExtra::kable_paper(bootstrap_options = "striped", full_width = F) -``` - -Please visit the following website for more examples on the kable package: - -## Table1 -Table1 uses quick and easy syntax but is not very friendly with testing/pvals. Note the label function is helpful here (changed the names / levels of wt to weight and am to automatic) - -```{r} -Hmisc::label(mtcars$wt) <- "weight" - -mtcars$am <- - factor(mtcars$am, - levels=c(0,1), - labels=c("Automatic", # Reference - "Manual")) - -table1::table1(~ mpg + cyl + wt | am * vs, data=mtcars) -``` - -## tableone -Here is the simplest approach to creating a summary table with the tableone package. -```{r} -tableone::CreateTableOne(data = mtcars) -``` - -You can specify which variables in included and which are factor variables easily in the table call. -```{r} -tableone::CreateTableOne(data = mtcars, - vars = c("mpg", "cyl", "disp", "hp"), - factorVars = c("cyl")) -``` - - - -