diff --git a/.Rbuildignore b/.Rbuildignore index 57dc6c86..f86e1bfa 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -18,3 +18,5 @@ ^rsconnect$ ^LICENSE\.md$ + + diff --git a/DESCRIPTION b/DESCRIPTION index 62404abc..af322d79 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -44,6 +44,7 @@ Imports: shinyjs (>= 2.0.0), sortable (>= 0.4.4), stringr (>= 1.4.0), + tidyr (>= 1.2.0), yaml (>= 2.2.1) VignetteBuilder: knitr Roxygen: list(markdown = TRUE) diff --git a/NAMESPACE b/NAMESPACE index e8937fc7..7542ed76 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,6 +21,7 @@ export(makeChartExport) export(makeChartParams) export(makeChartSummary) export(makeMapping) +export(makeMeta) export(mappingColumn) export(mappingColumnUI) export(mappingDomain) @@ -76,6 +77,8 @@ importFrom(stringr,str_replace_all) importFrom(stringr,str_split) importFrom(stringr,str_to_title) importFrom(stringr,str_to_upper) +importFrom(tidyr,replace_na) +importFrom(tidyr,starts_with) importFrom(utils,hasName) importFrom(utils,zip) importFrom(yaml,as.yaml) diff --git a/R/app_startup.R b/R/app_startup.R index bf9f9d90..0f23cc26 100644 --- a/R/app_startup.R +++ b/R/app_startup.R @@ -3,7 +3,7 @@ #' Prepare inputs for safetyGraphics app - run before app is initialized. #' #' @param domainData named list of data.frames to be loaded in to the app. Sample AdAM data from the safetyData package used by default -#' @param meta data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}. +#' @param meta data frame containing the metadata for use in the app. If no metadata is provided (default value is NULL), metatdata is generated by `makeMeta()`. #' @param charts list of charts in the format produced by safetyGraphics::makeChartConfig() #' @param mapping list specifying the initial mapping values for each data mapping for each domain (e.g. list(aes= list(id_col='USUBJID', seq_col='AESEQ')). #' @param autoMapping boolean indicating whether the app should attempt to automatically detect data standards and generate mappings for the data provided. Values specified in the `mapping` parameter overwrite automatically generated mappings when both are found. Defaults to true. @@ -22,7 +22,7 @@ #' #' @export app_startup<-function(domainData=NULL, meta=NULL, charts=NULL, mapping=NULL, autoMapping=NULL, filterDomain=NULL, chartSettingsPaths=NULL){ - # Process charts metadata + # If charts are not provided, load them from chartSettingsPath or the safetyCharts package if(is.null(charts)){ if(is.null(chartSettingsPaths)){ charts <- makeChartConfig() @@ -31,13 +31,8 @@ app_startup<-function(domainData=NULL, meta=NULL, charts=NULL, mapping=NULL, aut } } - # Attempt to bind chart functions if none are provided - charts <- charts %>% map(function(chart){ - if(!hasName(chart,"functions")){ - chart <- prepareChart(chart) - } - return(chart) - }) + # Prepare charts - fill in defaults, build metadata, bind functions + charts <- charts %>% map(prepareChart) # Drop charts where order is negative orderDrops <- charts[purrr::map_lgl(charts, function(chart) chart$order < 0)] @@ -74,6 +69,9 @@ app_startup<-function(domainData=NULL, meta=NULL, charts=NULL, mapping=NULL, aut } } + # generate a full list of metadata if none is provided + if(is.null(meta)) meta <- makeMeta(charts) + # generate mappings and data standards mappingObj <- makeMapping(domainData, meta, autoMapping, mapping) diff --git a/R/detectStandard.R b/R/detectStandard.R index 0b6ab402..ea555b77 100644 --- a/R/detectStandard.R +++ b/R/detectStandard.R @@ -5,19 +5,19 @@ #' This function compares the columns in the provided \code{"data"} with the required columns for a given data standard/domain combination. The function is designed to work with the SDTM and ADaM CDISC() standards for clinical trial data by default. Additional standards can be added by modifying the \code{"meta"} data set included as part of this package. #' #' @param data A data frame in which to detect the data standard - required. -#' @param meta the metadata containing the data standards. - default = safetyGraphics::meta +#' @param meta the metadata containing the data standards. #' @param domain the domain to evaluate - should match a value of \code{meta$domain}. Uses the first value in \code{meta$domain} if no value is provided. #' #' @return A data frame describing the detected standard for each \code{"text_key"} in the provided metadata. Columns are \code{"domain"}, \code{"text_key"}, \code{"column"} and \code{"standard"}. #' @examples -#' detectStandard(data=safetyData::adam_adae) #aes domain evaluated by default -#' detectStandard(data=safetyData::adam_adlbc,domain="labs" ) +#' detectStandard(data=safetyData::adam_adae, meta=safetyCharts::meta_aes) +#' detectStandard(data=safetyData::adam_adlbc,meta=safetyCharts::meta_labs, domain="labs" ) #' #' @importFrom stringr str_detect #' #' @export -detectStandard <- function(data, domain=NULL, meta=safetyGraphics::meta){ +detectStandard <- function(data, domain=NULL, meta=NULL){ if(is.null(domain)){ domain<-unique(meta$domain)[1] } diff --git a/R/evaluateStandard.R b/R/evaluateStandard.R index 282a0535..55c8a128 100644 --- a/R/evaluateStandard.R +++ b/R/evaluateStandard.R @@ -13,7 +13,7 @@ #' # Match is TRUE #' evaluateStandard( #' data=safetyData::adam_adlbc, -#' meta=meta, +#' meta=safetyCharts::meta_labs, #' domain="labs", #' standard="adam" #' ) @@ -21,7 +21,7 @@ #' # Match is FALSE #' evaluateStandard( #' data=safetyData::adam_adlbc, -#' meta=meta, +#' meta=safetyCharts::meta_labs, #' domain="labs", #' standard="sdtm" #' ) @@ -74,32 +74,43 @@ evaluateStandard <- function(data, meta, domain, standard){ )%>% select(.data$text_key, .data$current, .data$valid) - stopifnot(nrow(compare_summary[["mapping"]])>0) - - # count valid/invalid data elements - compare_summary[["total_count"]] <- compare_summary[["mapping"]] %>% nrow() - compare_summary[["valid_count"]] <- compare_summary[["mapping"]] %>% filter(.data$valid) %>% nrow() - compare_summary[["invalid_count"]] <- compare_summary[["mapping"]] %>% filter(!.data$valid) %>% nrow() - compare_summary[["match_percent"]] <- compare_summary[["valid_count"]] / compare_summary[["total_count"]] - - standard_formatted <- standard + standard_formatted <- standard if(standard=="adam"){ standard_formatted = "ADaM" }else if(standard=="sdtm"){ standard_formatted="SDTM" } - if (compare_summary[["invalid_count"]]==0) { - compare_summary[["match"]] <- "full" - compare_summary[["label"]] <- standard_formatted - } else if(compare_summary[["valid_count"]]>0) { - compare_summary[["match"]] <- "partial" - compare_summary[["label"]] <- paste0("Partial ",standard_formatted) - compare_summary[["details"]]<-paste0("(", compare_summary[["valid_count"]], "/" ,compare_summary[["total_count"]], " cols/fields matched)") - } else { + if(nrow(compare_summary[["mapping"]])>0){ + # count valid/invalid data elements + compare_summary[["total_count"]] <- compare_summary[["mapping"]] %>% nrow() + compare_summary[["valid_count"]] <- compare_summary[["mapping"]] %>% filter(.data$valid) %>% nrow() + compare_summary[["invalid_count"]] <- compare_summary[["mapping"]] %>% filter(!.data$valid) %>% nrow() + compare_summary[["match_percent"]] <- compare_summary[["valid_count"]] / compare_summary[["total_count"]] + + if (compare_summary[["invalid_count"]]==0) { + compare_summary[["match"]] <- "full" + compare_summary[["label"]] <- standard_formatted + } else if(compare_summary[["valid_count"]]>0) { + compare_summary[["match"]] <- "partial" + compare_summary[["label"]] <- paste0("Partial ",standard_formatted) + compare_summary[["details"]]<-paste0("(", compare_summary[["valid_count"]], "/" ,compare_summary[["total_count"]], " cols/fields matched)") + } else { + compare_summary[["match"]] <- "none" + compare_summary[["label"]] <- "No Match" + } + }else{ + # No values provided for standard in this domain + compare_summary[["total_count"]] <- 0 + compare_summary[["valid_count"]] <- NA + compare_summary[["invalid_count"]] <- NA + compare_summary[["match_percent"]] <- 0 compare_summary[["match"]] <- "none" compare_summary[["label"]] <- "No Match" } + + + return(compare_summary) } \ No newline at end of file diff --git a/R/makeMapping.R b/R/makeMapping.R index 1ae554a3..c98f66a0 100644 --- a/R/makeMapping.R +++ b/R/makeMapping.R @@ -1,7 +1,7 @@ #' Create data mapping based on data standards and user input #' #' @param domainData named list of data.frames to be loaded in to the app. Sample AdAM data from the safetyData package used by default -#' @param meta data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}. +#' @param meta data frame containing the metadata for use in the app. #' @param customMapping optional list specifying initial mapping values within each data mapping (e.g. list(aes= list(id_col='USUBJID', seq_col='AESEQ')). #' @param autoMapping boolean indicating whether the app should use `safetyGraphics::detectStandard()` to detect data standards and automatically generate mappings for the data provided. Values specified in the `customMapping` parameter overwrite auto-generated mappings when both are found. Defaults to true. #' diff --git a/R/makeMeta.R b/R/makeMeta.R new file mode 100644 index 00000000..d26e9a82 --- /dev/null +++ b/R/makeMeta.R @@ -0,0 +1,106 @@ +#' Create a metadata object table for a set of charts +#' +#' Generates metadata object for a list of charts. `makeMeta()` looks for metadata in 3 locations for each `chart` object: +#' - Domain-level metadata saved as meta_{chart$name} in the chart$package namespace +#' - Chart-specific metadata saved as meta_{chart$domain} in the chart$package namespace +#' - Chart-specific metadata saved directly to the chart object as chart$meta +#' After checking all charts, all metadata files are stacked in to a single dataframe and returned. If duplicate metadata rows (domain + text_key) are found, an error is thrown. +#' +#' @param charts list of safetyGraphics chart objects for which to create metadata +#' +#' @return tibble of metadata with the following columns: +#' \describe{ +#' \item{domain}{Data domain} +#' \item{text_key}{Text key indicating the setting name. \code{'--'} delimiter indicates a field level data mapping} +#' \item{col_key}{Key for the column mapping} +#' \item{field_key}{Key for the field mapping (if any)} +#' \item{type}{type of mapping - "field" or "column"} +#' \item{label}{Label} +#' \item{description}{Description} +#' \item{multiple}{Mapping supports multiple columns/fields } +#' \item{standard_adam}{Default values for the ADaM data standard} +#' \item{standard_sdtm}{Default values for the SDTM data standard} +#' } +#' +#' @importFrom tidyr replace_na starts_with +#' @export + +makeMeta <- function(charts){ + message(paste0("-Generating meta data for ",length(charts), " charts.")) + # Check each chart to see if {package}::meta_{domain} or {package}::meta_{name} exists + sources <- charts %>% map(function(chart){ + pkg<-ifelse(is.null(chart$package), 'safetyCharts',chart$package) + files<-paste0('meta_',c(chart$name, chart$domain)) %>% map(~list(file=.x, pkg=pkg)) + return(files) + }) %>% + flatten %>% + unique + + pkg_dfs<-sources %>% map(function(src){ + packagePath <- paste0('package:',src$pkg) + file_found <- exists( + src$file, + where=packagePath, + inherits=FALSE + ) + if(file_found){ + this_meta <- get( + src$file, + pos=packagePath, + inherits=FALSE + ) + + if(is.data.frame(this_meta)){ + this_meta <- this_meta%>% + mutate(source = paste0(src$pkg, "::",src$file)) + return(this_meta) + } + } + }) + + ## check for meta bound directly to the charts + chart_dfs <- charts %>% map(function(chart){ + if(is.data.frame(chart$meta)){ + this_meta <- chart$meta %>% mutate(source = paste0('charts$', chart$name, "$meta")) + return(this_meta) + }else{ + if(!is.null(chart$meta)) warning(paste0("Ignoring non-data.frame object found in charts$", chart$name, "$meta")) + } + }) + + ## make sure dfs have required columns + dfs<-c(pkg_dfs,chart_dfs) + required_cols <- c("domain","text_key","col_key","type") + dfs <- dfs%>% + keep(is.data.frame)%>% + keep(function(df){ + has_cols <- all(required_cols %in% names(df)) + if(!has_cols) warning(paste(df[1,'source'],"dropped from meta because of missing required columns.")) + return(has_cols) + }) + + ## combine list of dfs into single df + if(length(dfs)>0){ + meta<-bind_rows(dfs) + #%>% mutate_at(vars(tidyr::starts_with('standard_')), ~tidyr::replace_na(., "")) + + # Throw error if duplicate records are found + dupes <- duplicated(meta%>%select(.data$domain, .data$text_key)) + if(any(dupes)){ + dupeIDs <- meta[dupes,]%>% + mutate(domain_text_key=paste(.data$domain,.data$text_key,sep="-"))%>% + pull(.data$domain_text_key)%>% + unique%>% + paste(collapse="\n") + stop(paste("Duplicate rows in metadata for:\n",dupeIDs)) + } + + sources <- meta %>% pull(source) %>% unique %>% paste(collapse=" ") + message(paste0("-Meta object created using the following source(s): ",sources)) + return(meta) + } else { + stop("No metadata found. ") + } + +} + diff --git a/R/meta.R b/R/meta.R deleted file mode 100644 index 8df6856a..00000000 --- a/R/meta.R +++ /dev/null @@ -1,20 +0,0 @@ -#' Metadata data frame containing information about the data mapping used to configure safetyGraphics charts. One record per unique data mapping -#' -#' @format A data frame with 31 rows and 7 columns -#' \describe{ -#' \item{domain}{Data domain} -#' \item{text_key}{Text key indicating the setting name. \code{'--'} delimiter indicates a field level data mapping} -#' \item{col_key}{Key for the column mapping} -#' \item{field_key}{Key for the field mapping (if any)} -#' \item{type}{type of mapping - "field" or "column"} -#' \item{label}{Label} -#' \item{description}{Description} -#' \item{multiple}{Mapping supports multiple columns/fields } -#' \item{standard_adam}{Default values for the ADaM data standard} -#' \item{standard_sdtm}{Default values for the SDTM data standard} -#' } -#' -#' @source Created for this package - - -"meta" diff --git a/R/mod_safetyGraphicsServer.R b/R/mod_safetyGraphicsServer.R index 89126bde..0d7e4b85 100644 --- a/R/mod_safetyGraphicsServer.R +++ b/R/mod_safetyGraphicsServer.R @@ -5,7 +5,7 @@ #' @param input Shiny input object #' @param output Shiny output object #' @param session Shiny session object -#' @param meta data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}. +#' @param meta data frame containing the metadata for use in the app. #' @param domainData named list of data.frames to be loaded in to the app. #' @param mapping current mapping #' @param charts list of charts to include in the app diff --git a/R/mod_safetyGraphicsUI.R b/R/mod_safetyGraphicsUI.R index c810437f..81a55b9b 100644 --- a/R/mod_safetyGraphicsUI.R +++ b/R/mod_safetyGraphicsUI.R @@ -2,7 +2,7 @@ #' #' #' @param id module ID -#' @param meta data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}. +#' @param meta data frame containing the metadata for use in the app. #' @param domainData named list of data.frames to be loaded in to the app. #' @param mapping data.frame specifying the initial values for each data mapping. If no mapping is provided, the app will attempt to generate one via \code{detectStandard()} #' @param standards a list of information regarding data standards. Each list item should use the format returned by safetyGraphics::detectStandard. diff --git a/R/prepareChart.R b/R/prepareChart.R index 75410628..71ffebc4 100644 --- a/R/prepareChart.R +++ b/R/prepareChart.R @@ -38,70 +38,72 @@ prepareChart <- function(chart){ ) #### Bind Workflow functions to chart object #### - - all_functions <- as.character(utils::lsf.str(".GlobalEnv")) - - if(utils::hasName(chart, "package")){ - package_functions <- as.character(utils::lsf.str(paste0("package:",chart$package))) - all_functions<-c(all_functions,package_functions) - } + if(!hasName(chart,"functions")){ - #search functions that include the charts name or the workflow function names - chart_function_names <- c() - for(query in c(chart$name, unlist(chart$workflow)) ){ - matches<-all_functions[str_detect(query, all_functions)] - chart_function_names <- c(chart_function_names, matches) - } + all_functions <- as.character(utils::lsf.str(".GlobalEnv")) + + if(utils::hasName(chart, "package")){ + package_functions <- as.character(utils::lsf.str(paste0("package:",chart$package))) + all_functions<-c(all_functions,package_functions) + } - chart$functions <- lapply(chart_function_names, match.fun) - names(chart$functions) <- chart_function_names + #search functions that include the charts name or the workflow function names + chart_function_names <- c() + for(query in c(chart$name, unlist(chart$workflow)) ){ + matches<-all_functions[str_detect(query, all_functions)] + chart_function_names <- c(chart_function_names, matches) + } + + chart$functions <- lapply(chart_function_names, match.fun) + names(chart$functions) <- chart_function_names - # Define UI function unless one is provided - if(chart$type=="plot"){ - chart$functions$ui<-plotOutput - chart$functions$server<-renderPlot - chart$functions$main<-chart$functions[[chart$workflow$main]] - }else if(chart$type=="html"){ - chart$functions$ui<-htmlOutput - chart$functions$server<-renderText - chart$functions$main<-chart$functions[[chart$workflow$main]] - }else if(chart$type=="table"){ - chart$functions$ui<-DT::dataTableOutput - chart$functions$server<-function(expr){ - DT::renderDataTable( - expr, - rownames = FALSE, - options = list( - pageLength = 20, - ordering = FALSE, - searching = FALSE + # Define UI function unless one is provided + if(chart$type=="plot"){ + chart$functions$ui<-plotOutput + chart$functions$server<-renderPlot + chart$functions$main<-chart$functions[[chart$workflow$main]] + }else if(chart$type=="html"){ + chart$functions$ui<-htmlOutput + chart$functions$server<-renderText + chart$functions$main<-chart$functions[[chart$workflow$main]] + }else if(chart$type=="table"){ + chart$functions$ui<-DT::dataTableOutput + chart$functions$server<-function(expr){ + DT::renderDataTable( + expr, + rownames = FALSE, + options = list( + pageLength = 20, + ordering = FALSE, + searching = FALSE + ) ) - ) - } - chart$functions$main<-chart$functions[[chart$workflow$main]] - }else if(chart$type=="htmlwidget"){ - # Helper functions for html widget render - widgetOutput <- function(outputId, width = "100%", height = "400px") { - htmlwidgets::shinyWidgetOutput(outputId, chart$workflow$widget, width, height, package=chart$package) - } + } + chart$functions$main<-chart$functions[[chart$workflow$main]] + }else if(chart$type=="htmlwidget"){ + # Helper functions for html widget render + widgetOutput <- function(outputId, width = "100%", height = "400px") { + htmlwidgets::shinyWidgetOutput(outputId, chart$workflow$widget, width, height, package=chart$package) + } - renderWidget <- function(expr, env = parent.frame(), quoted = FALSE) { - if (!quoted) { expr <- substitute(expr) } # force quoted - htmlwidgets::shinyRenderWidget(expr, widgetOutput, env, quoted = TRUE) + renderWidget <- function(expr, env = parent.frame(), quoted = FALSE) { + if (!quoted) { expr <- substitute(expr) } # force quoted + htmlwidgets::shinyRenderWidget(expr, widgetOutput, env, quoted = TRUE) + } + + chart$functions$ui<-widgetOutput + chart$functions$server<-renderWidget + chart$functions$main<-htmlwidgets::createWidget + chart$workflow$main <- "htmlwidgets::createWidget" + }else if(chart$type=="module"){ + chart$functions$ui<-chart$functions[[chart$workflow$ui]] + chart$functions$server<-callModule + chart$functions$main <- chart$functions[[chart$workflow$server]] } - chart$functions$ui<-widgetOutput - chart$functions$server<-renderWidget - chart$functions$main<-htmlwidgets::createWidget - chart$workflow$main <- "htmlwidgets::createWidget" - }else if(chart$type=="module"){ - chart$functions$ui<-chart$functions[[chart$workflow$ui]] - chart$functions$server<-callModule - chart$functions$main <- chart$functions[[chart$workflow$server]] + # Print a message summarizing + message<-paste0(chart$name,": Loaded ", length(chart$functions)," functions: ", paste(names(chart$functions),collapse=",")) + message(message) } - - # Print a message summarizing - message<-paste0(chart$name,": Loaded ", length(chart$functions)," functions: ", paste(names(chart$functions),collapse=",")) - return(chart) } \ No newline at end of file diff --git a/R/safetyGraphicsApp.R b/R/safetyGraphicsApp.R index d918ea2d..9ba1a102 100644 --- a/R/safetyGraphicsApp.R +++ b/R/safetyGraphicsApp.R @@ -1,7 +1,7 @@ #' Run the core safetyGraphics App #' #' @param domainData named list of data.frames to be loaded in to the app. Sample AdAM data from the safetyData package used by default -#' @param meta data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}. +#' @param meta data frame containing the metadata for use in the app. If no metadata is provided, metatdata is generated by `makeMeta()`. #' @param charts list of charts in the format produced by safetyGraphics::makeChartConfig() #' @param mapping list specifying the initial mapping values for each data mapping for each domain (e.g. list(aes= list(id_col='USUBJID', seq_col='AESEQ')). #' @param autoMapping boolean indicating whether the app should attempt to automatically detect data standards and generate mappings for the data provided. Values specified in the `mapping` parameter overwrite automatically generated mappings when both are found. Defaults to true. @@ -20,7 +20,7 @@ safetyGraphicsApp <- function( aes=safetyData::adam_adae, dm=safetyData::adam_adsl ), - meta = safetyGraphics::meta, + meta = NULL, charts=NULL, mapping=NULL, autoMapping=TRUE, diff --git a/R/safetyGraphicsInit.R b/R/safetyGraphicsInit.R index b5927804..39762f63 100644 --- a/R/safetyGraphicsInit.R +++ b/R/safetyGraphicsInit.R @@ -118,7 +118,7 @@ safetyGraphicsInit <- function(charts=makeChartConfig(), delayTime=1000, maxFile shinyjs::show(id="sg-app") config<- app_startup( domainData = domainData() %>% keep(~!is.null(.x)), - meta = safetyGraphics::meta, + meta = NULL, charts= charts(), #mapping=NULL, filterDomain="dm", diff --git a/data-raw/makeMeta.R b/data-raw/makeMeta.R deleted file mode 100644 index ff61458f..00000000 --- a/data-raw/makeMeta.R +++ /dev/null @@ -1,7 +0,0 @@ -# Note: expected to be run from the root package directory -library(tidyverse) -library(usethis) - -#Copy metadata to /data -meta<-read_csv("data-raw/meta.csv") -usethis::use_data(meta, overwrite = TRUE) diff --git a/data-raw/meta.csv b/data-raw/meta.csv deleted file mode 100644 index 4973a088..00000000 --- a/data-raw/meta.csv +++ /dev/null @@ -1,31 +0,0 @@ -text_key,domain,col_key,field_key,type,label,description,multiple,standard_adam,standard_sdtm -id_col,aes,id_col,,column,ID column,Unique subject identifier variable name.,FALSE,USUBJID,USUBJID -seq_col,aes,seq_col,,column,Sequence column,Event sequence number variable name,FALSE,AESEQ,AESEQ -stdy_col,aes,stdy_col,,column,AE Start day column,Event start day variable name,FALSE,ASTDY,AESTDY -endy_col,aes,endy_col,,column,AE End day column,Event end day variable name,FALSE,AENDY,AEENDY -term_col,aes,term_col,,column,Preferred Term Column,Dictionary-Derived Term,FALSE,AEDECOD,AEDECOD -bodsys_col,aes,bodsys_col,,column,AE Body System,Body System or Organ Class,FALSE,AEBODSYS,AEBODSYS -id_col,labs,id_col,,column,ID column,Unique subject identifier variable name.,FALSE,USUBJID,USUBJID -value_col,labs,value_col,,column,Value column,Lab result variable name.,FALSE,AVAL,LBSTRESN -measure_col,labs,measure_col,,column,Measure column,Lab measure variable name,FALSE,PARAM,LBTEST -normal_col_low,labs,normal_col_low,,column,Lower Limit of Normal column,Lower limit of normal variable name,FALSE,A1LO,LBSTNRLO -normal_col_high,labs,normal_col_high,,column,Upper Limit of Normal column,Upper limit of normal variable name,FALSE,A1HI,LBSTNRHI -studyday_col,labs,studyday_col,,column,Study Day column,Visit day variable name,FALSE,ADY,LBDY -visit_col,labs,visit_col,,column,Visit column,Visit variable name,FALSE,VISIT,VISIT -visitn_col,labs,visitn_col,,column,Visit Number column,Visit number variable name,FALSE,VISITNUM,VISITNUM -measure_values--ALT,labs,measure_col,ALT,field,Alanine Aminotransferase value,Value used for Alanine Aminotransferase in the specified measure column,FALSE,Alanine Aminotransferase (U/L),Alanine Aminotransferase -measure_values--AST,labs,measure_col,AST,field,Aspartate Aminotransferase value,Value used for Aspartate Aminotransferase in the specified measure column,FALSE,Aspartate Aminotransferase (U/L),Aspartate Aminotransferase -measure_values--TB,labs,measure_col,TB,field,Total Bilirubin value,Value used for Total Bilirubin in the specified measure column,FALSE,Bilirubin (umol/L),Bilirubin -measure_values--ALP,labs,measure_col,ALP,field,Alkaline Phosphatase value,Value used for Alkaline Phosphatase in the specified measure column,FALSE,Alkaline Phosphatase (U/L),Alkaline Phosphatase -unit_col,labs,unit_col,,column,Unit column,Unit of measure variable name,FALSE,,LBSTRESU -baseline_flag_col,labs,baseline_flag_col,,column,Baseline column,An optional list defining which column represent the baseline visit(s) of the study.,FALSE,, -baseline_flag_values,labs,baseline_flag_col,values,field,Baseline values,An optional list defining which values (one or more) represent the baseline visit(s) of the study.,TRUE,, -analysis_flag_col,labs,analysis_flag_col,,column,Analysis column,An optional list defining which column represent the analysis visit(s) of the study.,FALSE,, -analysis_flag_values,labs,analysis_flag_col,values,field,Analysis values,An optional list defining which values (one or more) represent the analysis visit(s) of the study.,TRUE,, -id_col,dm,id_col,,column,ID column,Unique subject identifier variable name.,FALSE,USUBJID,USUBJID -treatment_col,dm,treatment_col,,column,Treatment Column,Treatment Column,FALSE,ARM,ARM -treatment_values--group1,dm,treatment_col,group1,field,Treatment 1,Treatment 1,FALSE,, -treatment_values--group2,dm,treatment_col,group2,field,Treatment 2,Treatment 2,FALSE,, -sex_col,dm,sex_col,,column,Sex Column,Sex Column,FALSE,SEX,SEX -race_col,dm,race_col,,column,Race Column,Race Column,FALSE,RACE,RACE -age_col,dm,age_col,,column,Age Column,Age Column,FALSE,AGE,AGE diff --git a/data/meta.rda b/data/meta.rda deleted file mode 100644 index 8be670d4..00000000 Binary files a/data/meta.rda and /dev/null differ diff --git a/man/app_startup.Rd b/man/app_startup.Rd index 4be6aed4..cccaa5ba 100644 --- a/man/app_startup.Rd +++ b/man/app_startup.Rd @@ -17,7 +17,7 @@ app_startup( \arguments{ \item{domainData}{named list of data.frames to be loaded in to the app. Sample AdAM data from the safetyData package used by default} -\item{meta}{data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}.} +\item{meta}{data frame containing the metadata for use in the app. If no metadata is provided (default value is NULL), metatdata is generated by \code{makeMeta()}.} \item{charts}{list of charts in the format produced by safetyGraphics::makeChartConfig()} diff --git a/man/detectStandard.Rd b/man/detectStandard.Rd index dc021561..b627b42c 100644 --- a/man/detectStandard.Rd +++ b/man/detectStandard.Rd @@ -4,14 +4,14 @@ \alias{detectStandard} \title{Detect the data standard used for a data set} \usage{ -detectStandard(data, domain = NULL, meta = safetyGraphics::meta) +detectStandard(data, domain = NULL, meta = NULL) } \arguments{ \item{data}{A data frame in which to detect the data standard - required.} \item{domain}{the domain to evaluate - should match a value of \code{meta$domain}. Uses the first value in \code{meta$domain} if no value is provided.} -\item{meta}{the metadata containing the data standards. - default = safetyGraphics::meta} +\item{meta}{the metadata containing the data standards.} } \value{ A data frame describing the detected standard for each \code{"text_key"} in the provided metadata. Columns are \code{"domain"}, \code{"text_key"}, \code{"column"} and \code{"standard"}. @@ -23,7 +23,7 @@ This function attempts to detect the clinical data standard used in a given R da This function compares the columns in the provided \code{"data"} with the required columns for a given data standard/domain combination. The function is designed to work with the SDTM and ADaM CDISC(\url{https://www.cdisc.org/}) standards for clinical trial data by default. Additional standards can be added by modifying the \code{"meta"} data set included as part of this package. } \examples{ -detectStandard(data=safetyData::adam_adae) #aes domain evaluated by default -detectStandard(data=safetyData::adam_adlbc,domain="labs" ) +detectStandard(data=safetyData::adam_adae, meta=safetyCharts::meta_aes) +detectStandard(data=safetyData::adam_adlbc,meta=safetyCharts::meta_labs, domain="labs" ) } diff --git a/man/evaluateStandard.Rd b/man/evaluateStandard.Rd index 5c8f97b0..f1ef1c25 100644 --- a/man/evaluateStandard.Rd +++ b/man/evaluateStandard.Rd @@ -25,7 +25,7 @@ Determines whether the required data elements in a data standard are found in a # Match is TRUE evaluateStandard( data=safetyData::adam_adlbc, - meta=meta, + meta=safetyCharts::meta_labs, domain="labs", standard="adam" ) @@ -33,7 +33,7 @@ evaluateStandard( # Match is FALSE evaluateStandard( data=safetyData::adam_adlbc, - meta=meta, + meta=safetyCharts::meta_labs, domain="labs", standard="sdtm" ) diff --git a/man/makeMapping.Rd b/man/makeMapping.Rd index 6e8168a0..e4b40b5a 100644 --- a/man/makeMapping.Rd +++ b/man/makeMapping.Rd @@ -9,7 +9,7 @@ makeMapping(domainData, meta, autoMapping, customMapping) \arguments{ \item{domainData}{named list of data.frames to be loaded in to the app. Sample AdAM data from the safetyData package used by default} -\item{meta}{data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}.} +\item{meta}{data frame containing the metadata for use in the app.} \item{autoMapping}{boolean indicating whether the app should use \code{safetyGraphics::detectStandard()} to detect data standards and automatically generate mappings for the data provided. Values specified in the \code{customMapping} parameter overwrite auto-generated mappings when both are found. Defaults to true.} diff --git a/man/makeMeta.Rd b/man/makeMeta.Rd new file mode 100644 index 00000000..60050fa2 --- /dev/null +++ b/man/makeMeta.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/makeMeta.R +\name{makeMeta} +\alias{makeMeta} +\title{Create a metadata object table for a set of charts} +\usage{ +makeMeta(charts) +} +\arguments{ +\item{charts}{list of safetyGraphics chart objects for which to create metadata} +} +\value{ +tibble of metadata with the following columns: +\describe{ +\item{domain}{Data domain} +\item{text_key}{Text key indicating the setting name. \code{'--'} delimiter indicates a field level data mapping} +\item{col_key}{Key for the column mapping} +\item{field_key}{Key for the field mapping (if any)} +\item{type}{type of mapping - "field" or "column"} +\item{label}{Label} +\item{description}{Description} +\item{multiple}{Mapping supports multiple columns/fields } +\item{standard_adam}{Default values for the ADaM data standard} +\item{standard_sdtm}{Default values for the SDTM data standard} +} +} +\description{ +Generates metadata object for a list of charts. \code{makeMeta()} looks for metadata in 3 locations for each \code{chart} object: +\itemize{ +\item Domain-level metadata saved as meta_{chart$name} in the chart$package namespace +\item Chart-specific metadata saved as meta_{chart$domain} in the chart$package namespace +\item Chart-specific metadata saved directly to the chart object as chart$meta +After checking all charts, all metadata files are stacked in to a single dataframe and returned. If duplicate metadata rows (domain + text_key) are found, an error is thrown. +} +} diff --git a/man/meta.Rd b/man/meta.Rd deleted file mode 100644 index d38e7f71..00000000 --- a/man/meta.Rd +++ /dev/null @@ -1,31 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/meta.R -\docType{data} -\name{meta} -\alias{meta} -\title{Metadata data frame containing information about the data mapping used to configure safetyGraphics charts. One record per unique data mapping} -\format{ -A data frame with 31 rows and 7 columns -\describe{ -\item{domain}{Data domain} -\item{text_key}{Text key indicating the setting name. \code{'--'} delimiter indicates a field level data mapping} -\item{col_key}{Key for the column mapping} -\item{field_key}{Key for the field mapping (if any)} -\item{type}{type of mapping - "field" or "column"} -\item{label}{Label} -\item{description}{Description} -\item{multiple}{Mapping supports multiple columns/fields } -\item{standard_adam}{Default values for the ADaM data standard} -\item{standard_sdtm}{Default values for the SDTM data standard} -} -} -\source{ -Created for this package -} -\usage{ -meta -} -\description{ -Metadata data frame containing information about the data mapping used to configure safetyGraphics charts. One record per unique data mapping -} -\keyword{datasets} diff --git a/man/safetyGraphicsApp.Rd b/man/safetyGraphicsApp.Rd index 20251721..5ff05020 100644 --- a/man/safetyGraphicsApp.Rd +++ b/man/safetyGraphicsApp.Rd @@ -7,7 +7,7 @@ safetyGraphicsApp( domainData = list(labs = safetyData::adam_adlbc, aes = safetyData::adam_adae, dm = safetyData::adam_adsl), - meta = safetyGraphics::meta, + meta = NULL, charts = NULL, mapping = NULL, autoMapping = TRUE, @@ -19,7 +19,7 @@ safetyGraphicsApp( \arguments{ \item{domainData}{named list of data.frames to be loaded in to the app. Sample AdAM data from the safetyData package used by default} -\item{meta}{data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}.} +\item{meta}{data frame containing the metadata for use in the app. If no metadata is provided, metatdata is generated by \code{makeMeta()}.} \item{charts}{list of charts in the format produced by safetyGraphics::makeChartConfig()} diff --git a/man/safetyGraphicsServer.Rd b/man/safetyGraphicsServer.Rd index 9ec00b23..ece88603 100644 --- a/man/safetyGraphicsServer.Rd +++ b/man/safetyGraphicsServer.Rd @@ -22,7 +22,7 @@ safetyGraphicsServer( \item{session}{Shiny session object} -\item{meta}{data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}.} +\item{meta}{data frame containing the metadata for use in the app.} \item{mapping}{current mapping} diff --git a/man/safetyGraphicsUI.Rd b/man/safetyGraphicsUI.Rd index ab47189a..99b312a5 100644 --- a/man/safetyGraphicsUI.Rd +++ b/man/safetyGraphicsUI.Rd @@ -9,7 +9,7 @@ safetyGraphicsUI(id, meta, domainData, mapping, standards) \arguments{ \item{id}{module ID} -\item{meta}{data frame containing the metadata for use in the app. See the preloaded file (\code{?safetyGraphics::meta}) for more data specifications and details. Defaults to \code{safetyGraphics::meta}.} +\item{meta}{data frame containing the metadata for use in the app.} \item{domainData}{named list of data.frames to be loaded in to the app.} diff --git a/tests/testthat/module_examples/chartsTab/app.R b/tests/testthat/module_examples/chartsTab/app.R index 013bc3f6..b7feeeec 100644 --- a/tests/testthat/module_examples/chartsTab/app.R +++ b/tests/testthat/module_examples/chartsTab/app.R @@ -14,7 +14,15 @@ domainData <- list( dm=safetyData::adam_adsl ) -mapping <- makeMapping(domainData, meta=safetyGraphics::meta, autoMapping=TRUE, customMapping=NULL) + +meta <- rbind( + safetyCharts::meta_labs, + safetyCharts::meta_aes, + safetyCharts::meta_dm, + safetyCharts::meta_hepExplorer +) + +mapping <- makeMapping(domainData, meta=meta, autoMapping=TRUE, customMapping=NULL) dataR<-reactive({domainData}) mappingR<-reactive({mapping$mapping}) diff --git a/tests/testthat/module_examples/filterTab/app.R b/tests/testthat/module_examples/filterTab/app.R index 4bba9255..63f5575f 100644 --- a/tests/testthat/module_examples/filterTab/app.R +++ b/tests/testthat/module_examples/filterTab/app.R @@ -5,6 +5,14 @@ library(safetyGraphics) #reactlogReset() +meta <- rbind( + safetyCharts::meta_labs, + safetyCharts::meta_aes, + safetyCharts::meta_dm, + safetyCharts::meta_hepExplorer +) + + ui <- tagList( shinyjs::useShinyjs(), tags$head( diff --git a/tests/testthat/module_examples/mapping/app.R b/tests/testthat/module_examples/mapping/app.R index 743853bc..188aa6af 100644 --- a/tests/testthat/module_examples/mapping/app.R +++ b/tests/testthat/module_examples/mapping/app.R @@ -2,6 +2,15 @@ library(shiny) library(safetyGraphics) library(dplyr) + +meta <- rbind( + safetyCharts::meta_labs, + safetyCharts::meta_aes, + safetyCharts::meta_dm, + safetyCharts::meta_hepExplorer +) + + #reactlogReset() allData <- list(labs=safetyData::adam_adlbc, aes=safetyData::adam_adae) labs_default <- meta %>% diff --git a/tests/testthat/module_examples/mappingColumn/app.R b/tests/testthat/module_examples/mappingColumn/app.R index 86c813e1..c4f58159 100644 --- a/tests/testthat/module_examples/mappingColumn/app.R +++ b/tests/testthat/module_examples/mappingColumn/app.R @@ -4,6 +4,14 @@ library(dplyr) reactlogReset() +meta <- rbind( + safetyCharts::meta_labs, + safetyCharts::meta_aes, + safetyCharts::meta_dm, + safetyCharts::meta_hepExplorer +) + + id_meta <- meta%>%filter(domain=="labs")%>%filter(col_key=="id_col") measure_meta <- meta%>%filter(domain=="labs")%>%filter(col_key=="measure_col") id_default<-data.frame( diff --git a/tests/testthat/module_examples/mappingDomain/app.R b/tests/testthat/module_examples/mappingDomain/app.R index a32585d3..31344b3b 100644 --- a/tests/testthat/module_examples/mappingDomain/app.R +++ b/tests/testthat/module_examples/mappingDomain/app.R @@ -2,19 +2,25 @@ library(shiny) library(safetyGraphics) library(dplyr) +meta <- rbind( + safetyCharts::meta_labs, + safetyCharts::meta_aes, + safetyCharts::meta_dm, + safetyCharts::meta_hepExplorer +) #reactlogReset() -measure_meta <- safetyGraphics::meta%>%filter(domain=="labs")%>%filter(col_key=="measure_col") +measure_meta <- meta%>%filter(domain=="labs")%>%filter(col_key=="measure_col") mm_default<-data.frame( text_key = c("measure_col", "measure_col--ALP"), current = c("PARAM","Alkaline Phosphatase (U/L)"), stringsAsFactors = FALSE ) -labs_default <- safetyGraphics::meta %>% +labs_default <- meta %>% filter(domain=="labs")%>% mutate(current=standard_sdtm)%>% select(text_key,current) -aes_default <- safetyGraphics::meta %>% +aes_default <- meta %>% filter(domain=="aes")%>% mutate(current=standard_sdtm)%>% select(text_key,current) @@ -35,16 +41,16 @@ ui <- tagList( mappingDomainUI("ex2",measure_meta,safetyData::adam_adlbc,mm_default), tableOutput("ex2Out"), h2("Example 3: AE Domain - no defaults"), - mappingDomainUI("ex3",safetyGraphics::meta%>%filter(domain=="aes"),safetyData::adam_adae), + mappingDomainUI("ex3", meta%>%filter(domain=="aes"),safetyData::adam_adae), tableOutput("ex3Out"), h2("Example 4: AE Domain - with defaults"), - mappingDomainUI("ex4",safetyGraphics::meta%>%filter(domain=="aes"),safetyData::adam_adae, aes_default), + mappingDomainUI("ex4", meta%>%filter(domain=="aes"),safetyData::adam_adae, aes_default), tableOutput("ex4Out"), h2("Example 5: Labs Domain - no defaults"), - mappingDomainUI("ex5",safetyGraphics::meta%>%filter(domain=="labs"),safetyData::adam_adlbc), + mappingDomainUI("ex5", meta%>%filter(domain=="labs"),safetyData::adam_adlbc), tableOutput("ex5Out"), h2("Example 6: Labs Domain - with defaults"), - mappingDomainUI("ex6",safetyGraphics::meta%>%filter(domain=="labs"),safetyData::adam_adlbc,labs_default), + mappingDomainUI("ex6", meta%>%filter(domain=="labs"),safetyData::adam_adlbc,labs_default), tableOutput("ex6Out"), ) ) @@ -57,19 +63,19 @@ server <- function(input,output,session){ exportTestValues(ex2_data = { ex2() }) output$ex2Out<-renderTable(ex2()) - ex3<-callModule(mappingDomain, "ex3", safetyGraphics::meta%>%filter(domain=="aes"), safetyData::adam_adae) + ex3<-callModule(mappingDomain, "ex3", meta%>%filter(domain=="aes"), safetyData::adam_adae) exportTestValues(ex3_data = { ex3() }) output$ex3Out<-renderTable(ex3()) - ex4<-callModule(mappingDomain, "ex4", safetyGraphics::meta%>%filter(domain=="aes"), safetyData::adam_adae) + ex4<-callModule(mappingDomain, "ex4", meta%>%filter(domain=="aes"), safetyData::adam_adae) exportTestValues(ex4_data = { ex4() }) output$ex4Out<-renderTable(ex4()) - ex5<-callModule(mappingDomain, "ex5", safetyGraphics::meta%>%filter(domain=="labs"), safetyData::adam_adlbc) + ex5<-callModule(mappingDomain, "ex5", meta%>%filter(domain=="labs"), safetyData::adam_adlbc) exportTestValues(ex5_data = { ex5() }) output$ex5Out<-renderTable(ex5()) - ex6<-callModule(mappingDomain, "ex6", safetyGraphics::meta%>%filter(domain=="labs"), labsafetyData::adam_adlbcs) + ex6<-callModule(mappingDomain, "ex6", meta%>%filter(domain=="labs"), labsafetyData::adam_adlbcs) exportTestValues(ex6_data = { ex6() }) output$ex6Out<-renderTable(ex6()) diff --git a/tests/testthat/module_examples/settingsMapping/app.R b/tests/testthat/module_examples/settingsMapping/app.R index a1f597ca..50669117 100644 --- a/tests/testthat/module_examples/settingsMapping/app.R +++ b/tests/testthat/module_examples/settingsMapping/app.R @@ -7,6 +7,13 @@ partialMapping <- data.frame( current=c("ID","myID","measure") ) +meta <- rbind( + safetyCharts::meta_labs, + safetyCharts::meta_aes, + safetyCharts::meta_dm, + safetyCharts::meta_hepExplorer +) + fullMapping<-read.csv('custom_mapping.csv') ui <- tagList( @@ -27,9 +34,9 @@ ui <- tagList( ) ) server <- function(input,output,session){ - callModule(settingsMapping, "NoMapping", metaIn = safetyGraphics::meta) - callModule(settingsMapping, "PartialMapping", metaIn = safetyGraphics::meta, mapping=reactive({partialMapping}) ) - callModule(settingsMapping, "FullMapping", metaIn = safetyGraphics::meta, mapping=reactive({fullMapping})) + callModule(settingsMapping, "NoMapping", metaIn = meta) + callModule(settingsMapping, "PartialMapping", metaIn = meta, mapping=reactive({partialMapping}) ) + callModule(settingsMapping, "FullMapping", metaIn = meta, mapping=reactive({fullMapping})) } shinyApp(ui, server) \ No newline at end of file diff --git a/tests/testthat/test_detectStandard.R b/tests/testthat/test_detectStandard.R index bef136cf..69e4224f 100644 --- a/tests/testthat/test_detectStandard.R +++ b/tests/testthat/test_detectStandard.R @@ -4,7 +4,7 @@ library(safetyData) library(stringr) test_that("a list with the expected properties and structure is returned",{ - a<- detectStandard(data.frame()) + a<- detectStandard(data.frame(),meta=safetyCharts::meta_labs) expect_is(a,"list") expect_named(a,c("details","standard","label","standard_percent")) @@ -18,45 +18,43 @@ test_that("a list with the expected properties and structure is returned",{ }) test_that("correct standards are identified",{ - expect_equal(detectStandard(data=safetyData::adam_adlbc,domain='labs')[["standard"]],"adam") - expect_equal(detectStandard(data=safetyData::adam_adlbc,domain='labs')[["details"]][["sdtm"]][["match"]], "partial") - expect_equal(detectStandard(data=safetyData::adam_adlbc,domain='labs')[["details"]][["adam"]][["match"]], "full") + expect_equal(detectStandard(data=safetyData::adam_adlbc,meta=safetyCharts::meta_labs,domain='labs')[["standard"]],"adam") + expect_equal(detectStandard(data=safetyData::adam_adlbc,meta=safetyCharts::meta_labs,domain='labs')[["details"]][["sdtm"]][["match"]], "partial") + expect_equal(detectStandard(data=safetyData::adam_adlbc,meta=safetyCharts::meta_labs,domain='labs')[["details"]][["adam"]][["match"]], "full") adam_params <- c("Alanine Aminotransferase (U/L)","Aspartate Aminotransferase (U/L)","Bilirubin (umol/L)","Alkaline Phosphatase (U/L)") adam_test_data<-data.frame(USUBJID="001",AVAL=10,PARAM=adam_params,VISIT="Visit 1",VISITNUM=1,ADY=0,A1LO=0,A1HI=20,PARAMCD="K") - expect_equal(detectStandard(data=adam_test_data, domain="labs")[["standard"]],"adam") - expect_equal(detectStandard(data=adam_test_data, domain="labs")[["details"]][["adam"]][["match"]], "full") - expect_equal(detectStandard(data=adam_test_data, domain="labs")[["details"]][["sdtm"]][["match"]], "partial") + expect_equal(detectStandard(data=adam_test_data, meta=safetyCharts::meta_labs, domain="labs")[["standard"]],"adam") + expect_equal(detectStandard(data=adam_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["adam"]][["match"]], "full") + expect_equal(detectStandard(data=adam_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["sdtm"]][["match"]], "partial") sdtm_params<-c("Alanine Aminotransferase","Aspartate Aminotransferase","Bilirubin","Alkaline Phosphatase") sdtm_test_data<-data.frame(USUBJID="001",LBSTRESN=10,LBTEST=sdtm_params,VISIT="Visit 1",VISITNUM=1,LBDY=0,LBSTNRLO=0,LBSTNRHI=20,LBSTRESU="K") - expect_equal(detectStandard(sdtm_test_data, domain="labs")[["standard"]],"sdtm") - expect_equal(detectStandard(sdtm_test_data, domain="labs")[["details"]][["sdtm"]][["match"]], "full") - expect_equal(detectStandard(sdtm_test_data, domain="labs")[["details"]][["adam"]][["match"]], "partial") + expect_equal(detectStandard(sdtm_test_data, meta=safetyCharts::meta_labs, domain="labs")[["standard"]],"sdtm") + expect_equal(detectStandard(sdtm_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["sdtm"]][["match"]], "full") + expect_equal(detectStandard(sdtm_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["adam"]][["match"]], "partial") empty_test_data<-data.frame("") - expect_equal(detectStandard(empty_test_data)[["standard"]],"none") - expect_equal(detectStandard(empty_test_data)[["details"]][["adam"]][["match"]], "none") - expect_equal(detectStandard(empty_test_data)[["details"]][["sdtm"]][["match"]], "none") + expect_equal(detectStandard(empty_test_data, meta=safetyCharts::meta_labs)[["standard"]],"none") + expect_equal(detectStandard(empty_test_data, meta=safetyCharts::meta_labs)[["details"]][["adam"]][["match"]], "none") + expect_equal(detectStandard(empty_test_data, meta=safetyCharts::meta_labs)[["details"]][["sdtm"]][["match"]], "none") case_sensitive_test_data<-data.frame(usubjid="001",AVAL=10,PARAM=adam_params,VISIT="Visit 1",VISITNUM=1,ADY=0,A1LO=0,A1HI=20,PARAMCD="K") - expect_equal(detectStandard(case_sensitive_test_data, domain="labs")[["standard"]],"adam") - expect_equal(detectStandard(case_sensitive_test_data, domain="labs")[["details"]][["adam"]][["match"]], "full") - expect_equal(detectStandard(case_sensitive_test_data, domain="labs")[["details"]][["sdtm"]][["match"]], "partial") + expect_equal(detectStandard(case_sensitive_test_data, meta=safetyCharts::meta_labs, domain="labs")[["standard"]],"adam") + expect_equal(detectStandard(case_sensitive_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["adam"]][["match"]], "full") + expect_equal(detectStandard(case_sensitive_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["sdtm"]][["match"]], "partial") #NOTE: adam takes precedence over sdtm sdtm_and_adam_test_data<-cbind(adam_test_data,sdtm_test_data) - expect_equal(detectStandard(sdtm_and_adam_test_data, domain="labs")[["standard"]],"adam") - expect_equal(detectStandard(sdtm_and_adam_test_data, domain="labs")[["details"]][["adam"]][["match"]], "full") - expect_equal(detectStandard(sdtm_and_adam_test_data, domain="labs")[["details"]][["sdtm"]][["match"]], "full") + expect_equal(detectStandard(sdtm_and_adam_test_data, meta=safetyCharts::meta_labs, domain="labs")[["standard"]],"adam") + expect_equal(detectStandard(sdtm_and_adam_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["adam"]][["match"]], "full") + expect_equal(detectStandard(sdtm_and_adam_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["sdtm"]][["match"]], "full") #NOTE: adam takes precedence over sdtm in partial matches as well sdtm_and_adam_partial_test_data<-data.frame(USUBJID="001",VISIT="Visit 1") - expect_equal(detectStandard(sdtm_and_adam_partial_test_data, domain="labs")[["standard"]],"adam") - expect_equal(detectStandard(sdtm_and_adam_partial_test_data, domain="labs")[["details"]][["adam"]][["match"]],"partial") - expect_equal(detectStandard(sdtm_and_adam_partial_test_data, domain="labs")[["details"]][["sdtm"]][["match"]],"partial") - - + expect_equal(detectStandard(sdtm_and_adam_partial_test_data, meta=safetyCharts::meta_labs, domain="labs")[["standard"]],"adam") + expect_equal(detectStandard(sdtm_and_adam_partial_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["adam"]][["match"]],"partial") + expect_equal(detectStandard(sdtm_and_adam_partial_test_data, meta=safetyCharts::meta_labs, domain="labs")[["details"]][["sdtm"]][["match"]],"partial") }) diff --git a/tests/testthat/test_evaluateStandard.R b/tests/testthat/test_evaluateStandard.R index 5879a51e..a446b6ed 100644 --- a/tests/testthat/test_evaluateStandard.R +++ b/tests/testthat/test_evaluateStandard.R @@ -2,16 +2,15 @@ context("Tests for the evaluateStandard() function") library(safetyGraphics) test_that("basic test cases evaluate as expected",{ - expect_equal(evaluateStandard(data=safetyData::adam_adlbc, domain="labs", meta= meta, standard="sdtm")[["match"]],"partial") - expect_equal(evaluateStandard(data=safetyData::adam_adlbc, domain="labs", meta= meta, standard="adam")[["match"]],"full") - expect_equal(evaluateStandard(data=safetyData::adam_adae, domain="aes", meta= meta, standard="sdtm")[["match"]],"partial") - expect_equal(evaluateStandard(data=safetyData::adam_adae, domain="aes", meta= meta, standard="adam")[["match"]],"full") - expect_equal(evaluateStandard(data=data.frame(), domain="labs", meta= meta, standard="sdtm")[["match"]],"none") + expect_equal(evaluateStandard(data=safetyData::adam_adlbc, domain="labs", meta= safetyCharts::meta_labs, standard="sdtm")[["match"]],"partial") + expect_equal(evaluateStandard(data=safetyData::adam_adlbc, domain="labs", meta= safetyCharts::meta_labs, standard="adam")[["match"]],"full") + expect_equal(evaluateStandard(data=safetyData::adam_adae, domain="aes", meta= safetyCharts::meta_aes, standard="sdtm")[["match"]],"partial") + expect_equal(evaluateStandard(data=safetyData::adam_adae, domain="aes", meta= safetyCharts::meta_aes, standard="adam")[["match"]],"full") + expect_equal(evaluateStandard(data=data.frame(), domain="labs", meta= safetyCharts::meta_labs, standard="sdtm")[["match"]],"none") }) test_that("a list with the expected properties and structure is returned",{ - a<- evaluateStandard(data=data.frame(),domain="labs", meta=meta, standard="adam") - + a<- evaluateStandard(data=data.frame(),domain="labs", meta=safetyCharts::meta_labs, standard="adam") expect_is(a,"list") expect_named(a,c('standard', 'mapping', 'total_count','valid_count', 'invalid_count','match_percent', 'match',"label")) expect_is(a[["standard"]],"character") @@ -22,26 +21,25 @@ test_that("a list with the expected properties and structure is returned",{ }) test_that("expected number of checks (in)valid",{ - expect_equal(evaluateStandard(data=safetyData::adam_adlbc, domain="labs", meta=meta, standard="sdtm")[["valid_count"]],4) - expect_equal(evaluateStandard(data=safetyData::adam_adlbc, domain="labs", meta=meta, standard="sdtm")[["invalid_count"]],9) + expect_equal(evaluateStandard(data=safetyData::adam_adlbc, domain="labs", meta=safetyCharts::meta_labs, standard="sdtm")[["valid_count"]],4) + expect_equal(evaluateStandard(data=safetyData::adam_adlbc, domain="labs", meta=safetyCharts::meta_labs, standard="sdtm")[["invalid_count"]],5) labs_edit <- safetyData::adam_adlbc labs_edit$LBTEST <- labs_edit$PARAM - a<-evaluateStandard(data=labs_edit, domain="labs", meta=meta, standard="sdtm") + a<-evaluateStandard(data=labs_edit, domain="labs", meta=safetyCharts::meta_labs, standard="sdtm") expect_equal(a[["valid_count"]],5) - expect_equal(a[["invalid_count"]],8) - expect_equal(a[["total_count"]],13) - expect_equal(round(a[["match_percent"]],3), .385) + expect_equal(a[["invalid_count"]],4) + expect_equal(a[["total_count"]],9) + expect_equal(a[["match_percent"]], 5/9) expect_true(a[["mapping"]]%>%filter(text_key=="measure_col")%>%select(valid)%>%unlist) }) test_that("invalid options throw errors",{ - expect_error(evaluateStandard(data=list(a=1,b=2), domain="labs", meta=meta, standard="sdtm")) - expect_error(evaluateStandard(data="notadataframe",domain="labs", meta=meta, standard="sdtm")) - expect_error(evaluateStandard(data=safetyData::adam_adlbc,domain="labs", meta=meta, standard=123)) - expect_error(evaluateStandard(data=safetyData::adam_adlbc,domain="labs", meta=meta, standard="notarealstandard")) - expect_error(evaluateStandard(data=safetyData::adam_adlbc,domain="labs", meta=meta, standard="adam", includeFieldsIsNotAnOptionNow="yesPlease")) + expect_error(evaluateStandard(data=list(a=1,b=2), domain="labs", meta=safetyCharts::meta_labs, standard="sdtm")) + expect_error(evaluateStandard(data="notadataframe",domain="labs", meta=safetyCharts::meta_labs, standard="sdtm")) + expect_error(evaluateStandard(data=safetyData::adam_adlbc,domain="labs", meta=safetyCharts::meta_labs, standard="notarealstandard")) + expect_error(evaluateStandard(data=safetyData::adam_adlbc,domain="labs", meta=safetyCharts::meta_labs, standard="adam", includeFieldsIsNotAnOptionNow="yesPlease")) expect_error(evaluateStandard(data=safetyData::adam_adlbc,domain="labs", meta=list(), standard="sdtm")) expect_error(evaluateStandard(data=safetyData::adam_adlbc,domain="labs", meta=safetyData::adam_adlbc, standard="sdtm")) }) \ No newline at end of file diff --git a/tests/testthat/test_makeMapping.R b/tests/testthat/test_makeMapping.R index ada8b40d..c28d962a 100644 --- a/tests/testthat/test_makeMapping.R +++ b/tests/testthat/test_makeMapping.R @@ -9,15 +9,22 @@ testData<- list( dm=safetyData::adam_adsl ) +meta <- rbind( + safetyCharts::meta_labs, + safetyCharts::meta_aes, + safetyCharts::meta_dm, + safetyCharts::meta_hepExplorer +) + myCustomMapping<-list( aes = list(id_col='USUBJID', seq_col='MY_SEQ'), labs = list(id_col='customID') ) -ex1<-makeMapping(testData, safetyGraphics::meta, TRUE, NULL) -ex2<-makeMapping(testData, safetyGraphics::meta, FALSE, NULL) -ex3<-makeMapping(testData, safetyGraphics::meta, TRUE, myCustomMapping) -ex4<-makeMapping(testData, safetyGraphics::meta, FALSE, myCustomMapping) +ex1<-makeMapping(testData, meta, TRUE, NULL) +ex2<-makeMapping(testData, meta, FALSE, NULL) +ex3<-makeMapping(testData, meta, TRUE, myCustomMapping) +ex4<-makeMapping(testData, meta, FALSE, myCustomMapping) test_that("object with the correct properties is returned",{ expect_named(ex1, c("standard", "mapping")) @@ -77,7 +84,7 @@ test_that("customMapping overwrites autoMapping values",{ test_that("unique domains in customMapping are added",{ myCustomMapping2 <- myCustomMapping myCustomMapping2$customDomain <- list(id_col="customID", other_col="other") - ex5<-makeMapping(testData, safetyGraphics::meta, TRUE, myCustomMapping2) + ex5<-makeMapping(testData, meta, TRUE, myCustomMapping2) expect_equal(unique(ex5$mapping$domain), c("aes", "labs", "customDomain", "dm")) #2 rows added @@ -93,7 +100,7 @@ test_that("unique domains in customMapping are added",{ test_that("unique mapping values for existing domains in customMapping are added",{ myCustomMapping3 <- myCustomMapping myCustomMapping3$aes$other_col <- "other" - ex6<-makeMapping(testData, safetyGraphics::meta, TRUE, myCustomMapping3) + ex6<-makeMapping(testData, meta, TRUE, myCustomMapping3) #1 row added expect_equal(nrow(ex6$mapping), nrow(ex1$mapping)+1) @@ -106,7 +113,7 @@ test_that("nested values in custom mapping work as expected",{ myCustomMapping4$labs$measure_values$ALT <- "AnotherAlt" myCustomMapping4$labs$measure_values$OTHER <- "Other" myCustomMapping4$aes$fake_values <- list(other1="Other1", other2="other2") - ex7<-makeMapping(testData, safetyGraphics::meta, TRUE, myCustomMapping4) + ex7<-makeMapping(testData, meta, TRUE, myCustomMapping4) #1 row added expect_equal(nrow(ex7$mapping), nrow(ex1$mapping)+3) diff --git a/tests/testthat/test_makeMeta.R b/tests/testthat/test_makeMeta.R new file mode 100644 index 00000000..93aa8f1e --- /dev/null +++ b/tests/testthat/test_makeMeta.R @@ -0,0 +1,144 @@ +context("Tests for the makeMeta() function") +library(safetyGraphics) +library(safetyCharts) + +# User Requirements +# [*] Chart-level metadata (e.g. meta_hepExplorer) is loaded when found +# [*] Domain-level metadata is loaded for a single domain when found +# [*] Domain-level metadata for multiple domains is loaded when found +# [*] Metadata is loaded as expected for multiple charts +# [*] Metadata saved to chart.meta is loaded +# [*] Metadata saved to chart.meta is loaded with chart-level and domain-level metadata. +# [*] Metadata that is not a dataframe is not loaded and a message is printed. +# [*] Metadata with incorrect columns is not loaded and a message is printed. +# [*] If no metadata is found for a chart, a warning message is printed. +# [*] An error is thrown if duplicate rows of metadata are found +# [*] An error is thrown if no metadata is found + +testChart <-list( + env="safetyGraphics", + name="ageDist", + label="Age Distribution", + type="plot", + domain="dm", + package="safetyCharts", + workflow=list( + main="ageDist" + ) +) + +test_that("Domain-level metadata is loaded for a single domain when found.",{ + testMeta <- makeMeta(list(testChart)) %>% select(-source) + expect_equal(testMeta, safetyCharts::meta_dm) +}) + +test_that("Domain-level metadata for multiple domains is loaded when found",{ + multiDomainChart <- testChart + multiDomainChart$domain <- c("dm","aes") + multiDomainMeta <- makeMeta(list(multiDomainChart)) %>% select(-source) + expect_equal(multiDomainMeta, rbind(safetyCharts::meta_dm, safetyCharts::meta_aes)) +}) + +test_that("Chart-level metadata (e.g. meta_hepExplorer) is loaded when found",{ + testChart <-list( + env="safetyGraphics", + name="hepExplorer", + package="safetyCharts", + domain="none" + ) + chartMeta <- makeMeta(list(testChart)) %>% select(-source) + expect_equal(chartMeta, safetyCharts::meta_hepExplorer) + + #Chart that chart-level and domain-level metadata stack + testChart$domain="labs" + chartMeta <- makeMeta(list(testChart)) %>% select(-source) + expect_equal(chartMeta, rbind(safetyCharts::meta_hepExplorer, safetyCharts::meta_labs)) +}) + +test_that("metadata for multiple charts loads when found",{ + testCharts <-list( + list(name='chart1', domain=c('aes','dm'),package='safetyCharts'), + list(name='chart2', domain=c('labs','dm')) #package defaults to safetyCharts if not specified + ) + chartMeta <- makeMeta(testCharts) %>% select(-source) + expect_equal(chartMeta, rbind(safetyCharts::meta_aes, safetyCharts::meta_dm, safetyCharts::meta_labs)) +}) + +helloMeta <- tribble( + ~text_key, ~domain, ~label, ~description, + "x_col", "hello", "x position", "x position for points in hello world chart", + "y_col", "hello", "y position", "y position for points in hello world chart" +) %>% mutate( + col_key = text_key, + type="column" +) +helloChart <- list(name='hello',meta=helloMeta) + +test_that("metadata saved to chart.meta is loaded",{ + chartMeta <- makeMeta(list(helloChart)) %>% select(-source) + expect_equal(chartMeta,helloMeta) +}) + +test_that("Metadata saved to chart.meta is loaded with chart-level and domain-level metadata.",{ + hepChart <-list( + env="safetyGraphics", + name="hepExplorer", + package="safetyCharts", + domain="labs" + ) + charts<-list(helloChart,hepChart) + chartMeta <- makeMeta(charts) %>% select(-source) + expect_equal(chartMeta,bind_rows(safetyCharts::meta_hepExplorer, safetyCharts::meta_labs, helloMeta)) +}) + +test_that("chart.meta that is not a dataframe is not loaded and a message is printed.",{ + badHello <-list( + list(name='hello',meta="not-a-df"), + list(name="labChart",domain="labs") + ) + expect_warning(makeMeta(badHello)) + expect_equal(suppressWarnings(makeMeta(badHello))%>%select(-source), safetyCharts::meta_labs) +}) + +test_that("Metadata with incorrect columns is not loaded and a message is printed.",{ + badHello2 <- list( + list(name='hello',meta=helloMeta%>%rename(id=text_key)), + list(name="labChart",domain="labs") + ) + expect_warning(makeMeta(badHello2)) + expect_equal(suppressWarnings(makeMeta(badHello2))%>%select(-source), safetyCharts::meta_labs) +}) + +test_that("An error is thrown if duplicate rows of metadata are found",{ + dupLabMeta <- tribble( + ~text_key, ~domain, ~label, ~description, + "id_col", "labs", "ID", "ID" + ) %>% mutate( + col_key = text_key, + type="column" + ) + dupTest <- list( + list(name='myLabChart',meta=dupLabMeta), + list(name="thierLabChart",domain="labs") + ) + expect_error(makeMeta(dupTest)) + + helloDupMeta <- tribble( + ~text_key, ~domain, ~label, ~description, + "x_col", "hello", "x position", "x position for points in hello world chart", + "x_col", "hello", "x position (again)" , "x position for points in hello world chart" + ) %>% mutate( + col_key = text_key, + type="column" + ) + helloDup <- list(list(name='helloDup',meta=helloDupMeta)) + expect_error(makeMeta(helloDup)) +}) + +test_that("An error is thrown if no metadata is found",{ + noMetaTest <- list( + list(name='myLabChart',domain="slabs"), + list(name="thierLabChart",domain="crabs") + ) + expect_error(makeMeta(noMetaTest)) +}) \ No newline at end of file diff --git a/tests/testthat/test_mod_mappingColumn.R b/tests/testthat/test_mod_mappingColumn.R index c41612d7..5f8eb487 100644 --- a/tests/testthat/test_mod_mappingColumn.R +++ b/tests/testthat/test_mod_mappingColumn.R @@ -8,6 +8,13 @@ skip_on_cran() app <- ShinyDriver$new("./module_examples/mappingColumn") initial<-app$getAllValues() +meta <- rbind( + safetyCharts::meta_labs, + safetyCharts::meta_aes, + safetyCharts::meta_dm, + safetyCharts::meta_hepExplorer +) + test_that("UI function stops with invalid inputs (non-data.frame)",{ skip_on_cran() id_meta <- meta%>%filter(domain=="labs")%>%filter(col_key=="id_col") diff --git a/tests/testthat/test_mod_mappingDomain.R b/tests/testthat/test_mod_mappingDomain.R index 51d9eeb2..01c94519 100644 --- a/tests/testthat/test_mod_mappingDomain.R +++ b/tests/testthat/test_mod_mappingDomain.R @@ -6,13 +6,20 @@ library(testthat) library(stringr) library(dplyr) +meta <- rbind( + safetyCharts::meta_labs, + safetyCharts::meta_aes, + safetyCharts::meta_dm, + safetyCharts::meta_hepExplorer +) + skip_on_cran() app <- ShinyDriver$new("./module_examples/mappingDomain") initial<-app$getAllValues() test_that("UI function stops with invalid inputs (non-data.frame)",{ skip_on_cran() - id_meta <- safetyGraphics::meta%>%filter(domain=="labs")%>%filter(col_key=="id_col") + id_meta <- meta%>%filter(domain=="labs")%>%filter(col_key=="id_col") id_mapping_list<-list(id_col="USUBJID") expect_error(mappingDomainUI("test1.1", list(id_col="USUBJID"), safetyData::adam_adlbc)) #invalid metadata expect_error(mappingDomainUI("test1.2", id_meta, "invalid_data_option")) #invalid data @@ -24,10 +31,10 @@ test_that("the correct number of inputs are created (1 per field/column)",{ inputs <- names(initial$input) expect_length(str_subset(inputs,"ex1"),5) expect_length(str_subset(inputs,"ex2"),5) - expect_length(str_subset(inputs,"ex3"),nrow(safetyGraphics::meta %>% filter(domain=="aes"))) - expect_length(str_subset(inputs,"ex4"),nrow(safetyGraphics::meta %>% filter(domain=="aes"))) - expect_length(str_subset(inputs,"ex5"),nrow(safetyGraphics::meta %>% filter(domain=="labs"))) - expect_length(str_subset(inputs,"ex6"),nrow(safetyGraphics::meta %>% filter(domain=="labs"))) + expect_length(str_subset(inputs,"ex3"),nrow( meta %>% filter(domain=="aes"))) + expect_length(str_subset(inputs,"ex4"),nrow( meta %>% filter(domain=="aes"))) + expect_length(str_subset(inputs,"ex5"),nrow( meta %>% filter(domain=="labs"))) + expect_length(str_subset(inputs,"ex6"),nrow( meta %>% filter(domain=="labs"))) }) test_that("output are data frames with the have expected values",{ @@ -41,10 +48,10 @@ test_that("output are data frames with the have expected values",{ #all exported values have the correct number of rows expect_equal(nrow(initial$export$ex1_data),5) expect_equal(nrow(initial$export$ex2_data),5) - expect_equal(nrow(initial$export$ex3_data),nrow(safetyGraphics::meta %>% filter(domain=="aes"))) - expect_equal(nrow(initial$export$ex4_data),nrow(safetyGraphics::meta %>% filter(domain=="aes"))) - expect_equal(nrow(initial$export$ex5_data),nrow(safetyGraphics::meta %>% filter(domain=="labs"))) - expect_equal(nrow(initial$export$ex6_data),nrow(safetyGraphics::meta %>% filter(domain=="labs"))) + expect_equal(nrow(initial$export$ex3_data),nrow( meta %>% filter(domain=="aes"))) + expect_equal(nrow(initial$export$ex4_data),nrow( meta %>% filter(domain=="aes"))) + expect_equal(nrow(initial$export$ex5_data),nrow( meta %>% filter(domain=="labs"))) + expect_equal(nrow(initial$export$ex6_data),nrow( meta %>% filter(domain=="labs"))) })