diff --git a/DESCRIPTION b/DESCRIPTION index be69d218..048f549f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -18,11 +18,11 @@ License: MIT + file LICENSE Encoding: UTF-8 LazyData: true RoxygenNote: 6.1.1 -Suggests: +Suggests: testthat, shinytest, knitr -Imports: +Imports: dplyr, htmlwidgets, purrr, diff --git a/NAMESPACE b/NAMESPACE index 3acbd77b..c39c9361 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -16,6 +16,7 @@ import(rmarkdown) import(shinyjs) importFrom(dplyr,"filter") importFrom(dplyr,filter) +importFrom(dplyr,full_join) importFrom(haven,read_sas) importFrom(magrittr,"%>%") importFrom(purrr,keep) diff --git a/R/checkColumn.R b/R/checkColumn.R index 3674be7b..c6bb0db1 100644 --- a/R/checkColumn.R +++ b/R/checkColumn.R @@ -16,27 +16,27 @@ #' testSettings$filters[[1]]<-list(value_col="RACE",label="Race") #' testSettings$filters[[2]]<-list(value_col=NULL,label="No Column") #' testSettings$filters[[3]]<-list(value_col="NotAColumn",label="Invalid Column") -#' +#' #' #pass ($valid == TRUE) #' safetyGraphics:::checkColumn(key=list("id_col"), -#' settings=testSettings, adlbc) -#' +#' settings=testSettings, adlbc) +#' #' #pass #' safetyGraphics:::checkColumn(key=list("filters",1,"value_col"), -#' settings=testSettings, adlbc) -#' +#' settings=testSettings, adlbc) +#' #' #NULL column pass #' safetyGraphics:::checkColumn(key=list("filters",2,"value_col"), -#' settings=testSettings, adlbc) -#' +#' settings=testSettings, adlbc) +#' #' #invalid column fails #' safetyGraphics:::checkColumn(key=list("filters",3,"value_col"), -#' settings=testSettings, adlbc) +#' settings=testSettings, adlbc) #' @keywords internal checkColumn <- function(key, settings, data){ stopifnot(typeof(key)=="list",typeof(settings)=="list") - + current <- list(key=key) current$text_key <- paste( unlist(current$key), collapse='--') current$type <- "column" diff --git a/R/checkNumeric.R b/R/checkNumeric.R index 435d4627..588c95b4 100644 --- a/R/checkNumeric.R +++ b/R/checkNumeric.R @@ -10,11 +10,11 @@ #' @examples #' testSettings<-generateSettings(standard="AdAM") #' #pass ($valid == FALSE) -#' safetyGraphics:::checkNumeric(key=list("id_col"),settings=testSettings, data=adlbc) -#' +#' safetyGraphics:::checkNumeric(key=list("id_col"),settings=testSettings, data=adlbc) +#' #' #pass ($valid == TRUE) -#' safetyGraphics:::checkNumeric(key=list("value_col"),settings=testSettings, data=adlbc) -#' +#' safetyGraphics:::checkNumeric(key=list("value_col"),settings=testSettings, data=adlbc) +#' #' @keywords internal checkNumeric <- function(key, settings, data){ diff --git a/R/data_checks.R b/R/data_checks.R new file mode 100644 index 00000000..0ae20a0b --- /dev/null +++ b/R/data_checks.R @@ -0,0 +1 @@ +#Statistical Checks \ No newline at end of file diff --git a/R/generateSettings.R b/R/generateSettings.R index ac5530d1..7a2963c7 100644 --- a/R/generateSettings.R +++ b/R/generateSettings.R @@ -1,104 +1,120 @@ #' Generate a settings object based on a data standard #' -#' This function returns a settings object for the eDish chart based on the specified data standard. +#' This function returns a settings object for the eDish chart based on the specified data standard. #' #' The function is designed to work with the SDTM and AdAM CDISC() standards for clinical trial data. Currently, eDish is the only chart supported. #' -#' @param standard The data standard for which to create settings. Valid options are "SDTM", "AdAM" or "None". Default: \code{"SDTM"} -#' @param chart The chart for which standards should be generated ("eDish" only for now) . Default: \code{"eDish"}. +#' @param standard The data standard for which to create settings. Valid options are "SDTM", "AdAM" or "None". Default: \code{"None"}. +#' @param charts The chart or chart(s) for which settings should be generated. Default: \code{NULL} (uses all available charts). +#' @param useDefaults Specifies whether default values from settingsMetadata should be included in the settings object. Default: \code{TRUE}. #' @param partial Boolean for whether or not the standard is a partial standard. Default: \code{FALSE}. #' @param partial_keys Optional character vector of the matched settings if partial is TRUE. Settings should be identified using the text_key format described in ?settingsMetadata. Setting is ignored when partial is FALSE. Default: \code{NULL}. +#' @param custom_settings a tibble with text_key and customValue columns specifiying customizations to be applied to the settings object. Default: \code{NULL}. #' @return A list containing the appropriate settings for the selected chart -#' -#' @examples -#' -#' generateSettings(standard="SDTM") +#' +#' @examples +#' +#' generateSettings(standard="SDTM") #' generateSettings(standard="SdTm") #also ok #' generateSettings(standard="ADaM") #' pkeys<- c("id_col","measure_col","value_col") #' generateSettings(standard="adam", partial=TRUE, partial_keys=pkeys) -#' -#' generateSettings(standard="a different standard") +#' +#' generateSettings(standard="a different standard") #' #returns shell settings list with no data mapping -#' +#' #' \dontrun{ -#' generateSettings(standard="adam",chart="AEExplorer") #Throws error. Only eDish supported so far. +#' generateSettings(standard="adam",chart="AEExplorer") #Throws error. Only eDish supported so far. #' } -#' -#' @importFrom dplyr "filter" +#' +#' @importFrom dplyr "filter" full_join #' @importFrom stringr str_split #' @importFrom rlang .data -#' +#' #' @export -generateSettings <- function(standard="None", chart="eDish", partial=FALSE, partial_keys=NULL){ - if(tolower(chart)!="edish"){ - stop(paste0("Can't generate settings for the specified chart ('",chart,"'). Only the 'eDish' chart is supported for now.")) - } - +generateSettings <- function(standard="None", charts=NULL, useDefaults=TRUE, partial=FALSE, partial_keys=NULL, custom_settings=NULL){ + # Check that partial_keys is supplied if partial is true if (is.null(partial_keys) & partial ) { stop("partial_keys must be supplied if the standard is partial") } - + # Coerce options to lowercase standard<-tolower(standard) - chart<-tolower(chart) - + if(!is.null(charts)){ + charts<-tolower(charts) + } + + ############################################################################# + # get keys & default values for settings using a data standard (data and field mappings) + ############################################################################ # Build a table of data mappings for the selected standard and partial settings - standardList<-c("adam","sdtm") #TODO: automatically generate this from metadata + standardList<-safetyGraphics::standardsMetadata%>%select(-.data$text_key)%>%names + if(standard %in% standardList){ - dataMappings <- safetyGraphics::getSettingsMetadata( - charts = chart, + dataDefaults <- safetyGraphics::getSettingsMetadata( + charts = charts, cols=c("text_key",standard,"setting_required") - ) %>% + ) %>% filter(.data$setting_required)%>% - rename("column_name" = standard)%>% - filter(.data$column_name != '') - - if(partial){ - dataMappings<-dataMappings%>%filter(.data$text_key %in% partial_keys) - } + select(-.data$setting_required)%>% + rename("dataDefault" = standard)%>% + filter(.data$dataDefault != '') + }else{ + dataDefaults<-tibble(text_key=character(),dataDefault=character(), .rows=0) } - - # build shell settings for each chart - # TODO: move these to `/data` eventually - shells<-list() - shells[["edish"]]<-list( - id_col = NULL, - value_col = NULL, - measure_col = NULL, - normal_col_low = NULL, - normal_col_high = NULL, - studyday_col=NULL, - visit_col = NULL, - visitn_col = NULL, - filters = NULL, - group_cols = NULL, - measure_values = list(ALT = NULL, - AST = NULL, - TB = NULL, - ALP = NULL), - baseline = list(value_col=NULL, - values=list()), - analysisFlag = list(value_col=NULL, - values=list()), - - x_options = c("ALT", "AST", "ALP"), - y_options = c("TB", "ALP"), - visit_window = 30, - r_ratio_filter = TRUE, - r_ratio_cut = 0, - showTitle = TRUE, - warningText = "Caution: This interactive graphic is not validated. Any clinical recommendations based on this tool should be confirmed using your organizations standard operating procedures." - ) - - # loop through dataMappings and apply them to the shell - if(standard %in% standardList){ - for(row in 1:nrow(dataMappings)){ - shells[[chart]]<-setSettingsValue(settings = shells[[chart]], key = textKeysToList(dataMappings[row,"text_key"])[[1]], value = dataMappings[row, "column_name"]) - } + + if(partial){ + dataDefaults <-dataDefaults%>%filter(.data$text_key %in% partial_keys) + } + + ############################################################################# + # get keys & default values for settings not using a data standard + ############################################################################# + if(useDefaults){ + otherDefaults <- safetyGraphics::getSettingsMetadata( + charts = charts, + filter = !.data$column_mapping & !.data$field_mapping, + cols=c("text_key","default") + )%>% + rename("otherDefault"="default") + }else{ + otherDefaults <- tibble(text_key=character(),otherDefault=character(), .rows=0) + } + + ############################################################################# + # merge all keys & default values + ############################################################################# + key_values <- full_join(dataDefaults, otherDefaults, by="text_key") + key_values <- key_values %>% mutate(default=ifelse(is.na(.data$dataDefault),.data$otherDefault,.data$dataDefault)) + + ############################################################################# + # Apply custom settings (if any) + ############################################################################# + if(!is.null(custom_settings)){ + key_values<-full_join(key_values, custom_settings, by="text_key") + } else { + key_values$customValue<-NA + } + + key_values<-key_values %>% mutate(value=ifelse(is.na(.data$customValue), .data$default, .data$customValue)) + + ############################################################################# + # create shell settings object + ############################################################################# + shell<-generateShell(charts=charts) + + ######################################################################################### + # populate the shell settings by looping through key_values and apply them to the shell + ######################################################################################### + for(row in 1:nrow(key_values)){ + shell<-setSettingsValue( + settings = shell, + key = textKeysToList(key_values[row,"text_key"])[[1]], + value = key_values[row, "value"][[1]] + ) } - return(shells[[chart]]) -} \ No newline at end of file + return(shell) +} diff --git a/R/generateShell.R b/R/generateShell.R new file mode 100644 index 00000000..f0dac6d7 --- /dev/null +++ b/R/generateShell.R @@ -0,0 +1,34 @@ +#' Generate a default settings shell based on settings metadata +#' +#' This function returns a default settings object based on the chart(s) specified. +#' +#' The function is designed to work with valid safetyGraphics charts. +#' +#' @param charts The chart or chart(s) to include in the shell settings object +#' @return A list containing a setting shell (all values = NA) for the selected chart(s) +#' +#' @examples +#' +#' safetyGraphics:::generateShell(charts = "eDish") +#' +#' @keywords internal + +generateShell <- function(charts=NULL){ + keys <- safetyGraphics::getSettingsMetadata( + charts = charts, + cols=c("text_key") + ) %>% textKeysToList() + + shell <- list() + + for (i in 1:length(keys) ) { + shell<-setSettingsValue( + key=keys[[i]], + value=NULL, + settings=shell, + forceCreate=TRUE + ) + } + + return(shell) +} diff --git a/R/setSettingsValue.R b/R/setSettingsValue.R index 8052d237..e0cf4f53 100644 --- a/R/setSettingsValue.R +++ b/R/setSettingsValue.R @@ -5,6 +5,7 @@ #' @param key a list (like those provided by \code{getSettingKeys()}) defining the position of parameter in the settings object. #' @param value the value to set #' @param settings The settings list used to generate a chart like \code{eDISH()} +#' @param forceCreate Specifies whether the function should create a new list() when none exisits. This most commonly occurs when deeply nested objects. #' @return the updated settings object #' #' @examples @@ -21,17 +22,26 @@ #' @keywords internal -setSettingsValue <- function(key, value, settings){ - stopifnot( - typeof(settings)=="list" - ) +setSettingsValue <- function(key, value, settings, forceCreate=FALSE){ + + if(typeof(settings)!="list"){ + if(forceCreate){ + settings=list() + }else{ + stop("Settings is not a valid list object. Set forceCreate to TRUE and re-run if you want to create a new list and continue.") + } + } firstKey <- key[[1]] if(length(key)==1){ - settings[[firstKey]]<-value + if(is.null(value)){ + settings[firstKey]<-list(NULL) + }else{ + settings[[firstKey]]<-value + } return(settings) }else{ - settings[[firstKey]]<-setSettingsValue(settings = settings[[firstKey]],key = key[2:length(key)], value) + settings[[firstKey]]<-setSettingsValue(settings = settings[[firstKey]],key = key[2:length(key)], value=value, forceCreate=forceCreate) return(settings) } } \ No newline at end of file diff --git a/R/settingsMetadata.R b/R/settingsMetadata.R index 92882d95..e2ba463e 100644 --- a/R/settingsMetadata.R +++ b/R/settingsMetadata.R @@ -15,6 +15,7 @@ #' \item{field_mapping}{Flag indicating whether the setting corresponds to a field-level mapping in the data} #' \item{field_column_key}{Key for the column that provides options for the field-level mapping in the data} #' \item{setting_cat}{Setting category (data, measure, appearance)} +#' \item{default}{Default value for non-data settings} #' } #' #' @source Created for this package diff --git a/R/trimData.R b/R/trimData.R index f50fe288..b7e72c54 100644 --- a/R/trimData.R +++ b/R/trimData.R @@ -22,10 +22,10 @@ trimData <- function(data, settings, chart="edish"){ ## Remove columns not in settings ## col_names <- colnames(data) - + allKeys <- getSettingsMetadata(charts=chart, filter_expr = .data$column_mapping, cols = c("text_key","setting_type")) dataKeys <- allKeys %>% filter(.data$setting_type !="vector") %>% pull(.data$text_key) %>% textKeysToList() - + # Add items in vectors to list individually dataVectorKeys <- allKeys %>% filter(.data$setting_type =="vector") %>% pull(.data$text_key) %>% textKeysToList() for(key in dataVectorKeys){ @@ -37,12 +37,12 @@ trimData <- function(data, settings, chart="edish"){ sub <- current[[i]] if(typeof(sub)=="list"){ newKey[[1+length(newKey)]]<-"value_col" - } - dataKeys[[1+length(dataKeys)]]<-newKey + } + dataKeys[[1+length(dataKeys)]]<-newKey } } } - + settings_values <- map(dataKeys, function(x) {return(getSettingValue(x, settings))}) common_cols <- intersect(col_names,settings_values) @@ -50,22 +50,25 @@ trimData <- function(data, settings, chart="edish"){ data_subset <- select(data, unlist(common_cols)) ## Remove rows if baseline or analysisFlag is specified ## + baselineSetting<-settings[['baseline']][['value_col']] + baselineMissing <- is.null(baselineSetting) + analysisSetting<-settings[['analysisFlag']][['value_col']] + analysisMissing <- is.null(analysisSetting) - if(!is.null(settings[['baseline']][['value_col']]) | !is.null(settings[['analysisFlag']][['value_col']])) { + if(!baselineMissing | !analysisMissing) { # Create Baseline String - baseline_string <- ifelse(!is.null(settings[['baseline']][['value_col']]), + baseline_string <- ifelse(!baselineMissing, paste(settings[['baseline']][['value_col']], "%in% settings[['baseline']][['values']]"), "") # Create AnalysisFlag String - analysis_string <- ifelse(!is.null(settings[['analysisFlag']][['value_col']]), + analysis_string <- ifelse(!analysisMissing, paste(settings[['analysisFlag']][['value_col']], "%in% settings[['analysisFlag']][['values']]"), "") # Include OR operator if both are specified - operator <- ifelse(!is.null(settings[['baseline']][['value_col']]) & !is.null(settings[['analysisFlag']][['value_col']]), - "|","") + operator <- ifelse(!baselineMissing & !analysisMissing, "|", "") # Create filter string and make it an expression filter_string <- paste(baseline_string, operator, analysis_string) diff --git a/README.md b/README.md index 9b95cc03..7e148e01 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -[![Travis-CI Build Status](https://travis-ci.org/ASA-DIA-InteractiveSafetyGraphics/safetyGraphics.svg?branch=master)](https://travis-ci.org/ASA-DIA-InteractiveSafetyGraphics/safetyGraphics) [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/safetyGraphics)](https://cran.r-project.org/package=safetyGraphics) +[![Travis-CI Build Status](https://travis-ci.org/SafetyGraphics/safetyGraphics.svg?branch=master)](https://travis-ci.org/SafetyGraphics/safetyGraphics) [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/safetyGraphics)](https://cran.r-project.org/package=safetyGraphics) # safetyGraphics: Clinical Trial Safety Graphics with R -The **safetyGraphics** package provides a framework for evaluation of clinical trial safety in R. The initial release focuses on Evaluation of Drug-Induced Serious Hepatotoxicity (eDISH). A prototype of the eDish interactive graphic is available [here](https://asa-dia-interactivesafetygraphics.github.io/safety-eDISH/test/) and is shown below. +The **safetyGraphics** package provides a framework for evaluation of clinical trial safety in R. The initial release focuses on Evaluation of Drug-Induced Serious Hepatotoxicity (eDISH). A prototype of the eDish interactive graphic is available [here](https://safetygraphics.github.io/safety-eDISH/test/) and is shown below. -This package is being built in conjunction with the [safety-eDISH](https://github.com/ASA-DIA-InteractiveSafetyGraphics/safety-eDISH) javascript library. Both packages are under active development with beta testing and an initial release planned for early 2019. +This package is being built in conjunction with the [safety-eDISH](https://github.com/safetyGraphics/safety-eDISH) javascript library. Both packages are under active development with beta testing and an initial release planned for early 2019. ![edishgif](https://user-images.githubusercontent.com/3680095/45834450-02b3a000-bcbc-11e8-8172-324c2fe43521.gif) @@ -21,7 +21,7 @@ The Shiny app provides a simple interface for: - Viewing and exporting the interactive graphics ```r -devtools::install_github("ASA-DIA-InteractiveSafetyGraphics/safetyGraphics") +devtools::install_github("SafetyGraphics/safetyGraphics") library("safetyGraphics") chartBuilderApp() #open the shiny application ``` @@ -31,7 +31,7 @@ chartBuilderApp() #open the shiny application Users can also initialize customized standalone charts with a few lines of code. ```r -devtools::install_github("ASA-DIA-InteractiveSafetyGraphics/safetyGraphics") +devtools::install_github("safetyGraphics/safetyGraphics") library("safetyGraphics") eDISH(data=adlbc, id_col = "USUBJID", diff --git a/data-raw/csv_to_rda.R b/data-raw/csv_to_rda.R index de6c8b5f..07dfc3cb 100644 --- a/data-raw/csv_to_rda.R +++ b/data-raw/csv_to_rda.R @@ -3,8 +3,14 @@ library(usethis) ablbc <- read.csv("data-raw/adlbc.csv") usethis::use_data(adlbc, overwrite = TRUE) -settingsMetadata <- read.csv("data-raw/settingsMetadata.csv") +partialSettingsMetadata <- read.csv("data-raw/settingsMetadata.csv") + +#merge defaults on to settingsMetadata +defaults <- readRDS("data-raw/defaults.rda") #why is this not working... grrrr + +settingsMetadata <- merge(partialSettingsMetadata, defaults, by="text_key") + usethis::use_data(settingsMetadata, overwrite = TRUE) standardsMetadata <- read.csv("data-raw/standardsMetadata.csv") -usethis::use_data(standardsMetadata, overwrite = TRUE) \ No newline at end of file +usethis::use_data(standardsMetadata, overwrite = TRUE) diff --git a/data-raw/defaults.rda b/data-raw/defaults.rda new file mode 100644 index 00000000..018b5ccd Binary files /dev/null and b/data-raw/defaults.rda differ diff --git a/data-raw/generateDefaults.R b/data-raw/generateDefaults.R new file mode 100644 index 00000000..cd92d952 --- /dev/null +++ b/data-raw/generateDefaults.R @@ -0,0 +1,29 @@ +defaults <- tribble(~text_key, ~default, + "id_col", NULL, + "value_col", NULL, + "measure_col", NULL, + "measure_values--ALT", NULL, + "measure_values--AST", NULL, + "measure_values--TB", NULL, + "measure_values--ALP", NULL, + "normal_col_low", NULL, + "normal_col_high", NULL, + "studyday_col",NULL, + "visit_col", NULL, + "visitn_col", NULL, + "filters", NULL, + "group_cols", NULL, + "baseline--value_col", NULL, + "baseline--values", list(), + "analysisFlag--value_col", NULL, + "analysisFlag--values", list(), + "x_options", c("ALT", "AST", "ALP"), + "y_options", c("TB", "ALP"), + "visit_window", 30, + "r_ratio_filter", TRUE, + "r_ratio_cut", 0, + "showTitle", TRUE, + "warningText", "Caution: This interactive graphic is not validated. Any clinical recommendations based on this tool should be confirmed using your organizations standard operating procedures." + ) + +saveRDS(defaults, file="data-raw/defaults.rda") diff --git a/data/adlbc.rda b/data/adlbc.rda index aa28c2db..aea28611 100644 Binary files a/data/adlbc.rda and b/data/adlbc.rda differ diff --git a/data/settingsMetadata.rda b/data/settingsMetadata.rda index 525b0f1d..175251fa 100644 Binary files a/data/settingsMetadata.rda and b/data/settingsMetadata.rda differ diff --git a/data/standardsMetadata.rda b/data/standardsMetadata.rda index 4aaca682..638a5e66 100644 Binary files a/data/standardsMetadata.rda and b/data/standardsMetadata.rda differ diff --git a/inst/htmlwidgets/eDISH.yaml b/inst/htmlwidgets/eDISH.yaml index aa307410..17ad864a 100644 --- a/inst/htmlwidgets/eDISH.yaml +++ b/inst/htmlwidgets/eDISH.yaml @@ -4,11 +4,11 @@ dependencies: src: htmlwidgets/lib/d3-3.5.17 script: d3.v3.min.js - name: webcharts - version: 1.11.1 - src: htmlwidgets/lib/webcharts-1.11.1 + version: 1.11.3 + src: htmlwidgets/lib/webcharts-1.11.3 script: webcharts.js stylesheet: webcharts.css - name: safety-eDish - version: 0.16.2 - src: htmlwidgets/lib/safety-eDISH-0.16.2 + version: 0.16.3 + src: htmlwidgets/lib/safety-eDISH-0.16.3 script: safetyedish.js diff --git a/inst/htmlwidgets/lib/safety-eDISH-0.16.2/safetyedish.js b/inst/htmlwidgets/lib/safety-eDISH-0.16.3/safetyedish.js similarity index 99% rename from inst/htmlwidgets/lib/safety-eDISH-0.16.2/safetyedish.js rename to inst/htmlwidgets/lib/safety-eDISH-0.16.3/safetyedish.js index 0ce8b7f1..03550241 100644 --- a/inst/htmlwidgets/lib/safety-eDISH-0.16.2/safetyedish.js +++ b/inst/htmlwidgets/lib/safety-eDISH-0.16.3/safetyedish.js @@ -2,8 +2,8 @@ typeof exports === 'object' && typeof module !== 'undefined' ? (module.exports = factory(require('webcharts'))) : typeof define === 'function' && define.amd - ? define(['webcharts'], factory) - : (global.safetyedish = factory(global.webCharts)); + ? define(['webcharts'], factory) + : (global.safetyedish = factory(global.webCharts)); })(this, function(webcharts) { 'use strict'; @@ -217,8 +217,8 @@ studyday_col: 'DY', value_col: 'STRESN', measure_col: 'TEST', - normal_col_low: 'STNRLO', normal_col_high: 'STNRHI', + normal_col_low: null, visit_col: null, visitn_col: null, group_cols: null, @@ -407,8 +407,8 @@ label: filter.label ? filter.label : filter.value_col - ? filter.value_col - : filter + ? filter.value_col + : filter }; if ( @@ -432,8 +432,8 @@ label: group.label ? group.label : group.value_col - ? group.value_col - : filter + ? group.value_col + : filter }; if ( defaultDetails.find(function(f) { @@ -464,8 +464,8 @@ label: detail.label ? detail.label : detail.value_col - ? detail.value_col - : detail + ? detail.value_col + : detail }); }); settings.details = defaultDetails; @@ -718,8 +718,8 @@ label: filter.label ? filter.label : filter.value_col - ? filter.value_col - : filter + ? filter.value_col + : filter }; return filter; }); @@ -922,7 +922,7 @@ ///////////////////////// // Remove invalid rows ///////////////////////// - var numerics = ['value_col', 'studyday_col', 'normal_col_low', 'normal_col_high']; + var numerics = ['value_col', 'studyday_col', 'normal_col_high']; chart.imputed_data = chart.initial_data.filter(function(f) { return true; }); @@ -1864,10 +1864,10 @@ config.display == 'relative_uln' ? ' [xULN]' : config.display == 'relative_baseline' - ? ' [xBaseline]' - : config.display == 'absolute' - ? ' [raw values]' - : null; + ? ' [xBaseline]' + : config.display == 'absolute' + ? ' [raw values]' + : null; //Update axis labels. config.x.label = config.measure_values[config.x.column] + unit; @@ -2848,10 +2848,12 @@ visitn: config.visitn_col ? +m[config.visitn_col] : null, studyday: +m[config.studyday_col], value: +m[config.value_col], - lln: +m[config.normal_col_low], + lln: config.normal_col_low ? +m[config.normal_col_low] : null, uln: +m[config.normal_col_high], population_extent: measureObj.population_extent, - outlier_low: +m[config.value_col] < +m[config.normal_col_low], + outlier_low: config.normal_col_low + ? +m[config.value_col] < +m[config.normal_col_low] + : null, outlier_high: +m[config.value_col] > +m[config.normal_col_high] }; obj.outlier = obj.outlier_low || obj.outlier_high; @@ -3240,10 +3242,10 @@ ([0, 4, 5, 6, 7, 8, 9].indexOf(lastDigit) > -1 ? 'th' : lastDigit === 3 - ? 'rd' - : lastDigit === 2 - ? 'nd' - : 'st'); + ? 'rd' + : lastDigit === 2 + ? 'nd' + : 'st'); return text; }) .join(' and ') + @@ -3673,7 +3675,7 @@ .style('font-size', '0.7em') .style('padding-top', '0.1em') .text( - 'Points are shown for values above the current reference value. Mouseover a line to see the reference line for that lab.' + 'Points are filled for values above the current reference value. Mouseover a line to see the reference line for that lab.' ); } @@ -3745,10 +3747,10 @@ config.display == 'relative_uln' ? 'Values are plotted as multiples of the upper limit of normal for the measure.' : config.display == 'relative_baseline' - ? "Values are plotted as multiples of the partipant's baseline value for the measure." - : config.display == 'absolute' - ? ' Values are plotted using the raw units for the measure.' - : null; + ? "Values are plotted as multiples of the partipant's baseline value for the measure." + : config.display == 'absolute' + ? ' Values are plotted using the raw units for the measure.' + : null; var axisLabels = chart.svg .selectAll('.axis') diff --git a/inst/htmlwidgets/lib/webcharts-1.11.1/webcharts.css b/inst/htmlwidgets/lib/webcharts-1.11.3/webcharts.css similarity index 99% rename from inst/htmlwidgets/lib/webcharts-1.11.1/webcharts.css rename to inst/htmlwidgets/lib/webcharts-1.11.3/webcharts.css index cc3fcb48..a64215a3 100644 --- a/inst/htmlwidgets/lib/webcharts-1.11.1/webcharts.css +++ b/inst/htmlwidgets/lib/webcharts-1.11.3/webcharts.css @@ -1,4 +1,3 @@ - @import url(//fonts.googleapis.com/css?family=Open+Sans:400,300); /*------------------------------------------------------------------------------------------------\ Small Multiple Layout \------------------------------------------------------------------------------------------------*/ diff --git a/inst/htmlwidgets/lib/webcharts-1.11.1/webcharts.js b/inst/htmlwidgets/lib/webcharts-1.11.3/webcharts.js similarity index 99% rename from inst/htmlwidgets/lib/webcharts-1.11.1/webcharts.js rename to inst/htmlwidgets/lib/webcharts-1.11.3/webcharts.js index 51a61ca2..e6fe9061 100644 --- a/inst/htmlwidgets/lib/webcharts-1.11.1/webcharts.js +++ b/inst/htmlwidgets/lib/webcharts-1.11.3/webcharts.js @@ -4,9 +4,9 @@ : typeof define === 'function' && define.amd ? define(['d3'], factory) : (global.webCharts = factory(global.d3)); -})(this, function(d3) { +})(typeof self !== 'undefined' ? self : this, function(d3) { 'use strict'; - var version = '1.11.1'; + var version = '1.11.3'; function init(data) { var _this = this; @@ -433,7 +433,7 @@ return f instanceof Date; }); }) - .entries(this.raw_data) + .entries(this.filtered_data) .sort(function(a, b) { return d3.min(b.values) - d3.min(a.values); }) @@ -1592,7 +1592,7 @@ } function makeLegend() { - var scale$$1 = arguments.length > 0 && arguments[0] !== undefined + var scale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.colorScale; var label = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; @@ -1638,7 +1638,7 @@ var legend_data = custom_data || - scale$$1 + scale .domain() .slice(0) .filter(function(f) { @@ -1670,7 +1670,7 @@ .attr('class', 'legend-item') .style({ 'list-style-type': 'none', 'margin-right': '1em' }); new_parts.append('span').attr('class', 'legend-mark-text').style('color', function(d) { - return scale$$1(d.label); + return scale(d.label); }); new_parts .append('svg') @@ -1695,16 +1695,16 @@ leg_parts.selectAll('.legend-color-block').select('.legend-mark').remove(); leg_parts.selectAll('.legend-color-block').each(function(e) { - var svg$$1 = d3.select(this); + var svg = d3.select(this); if (e.mark === 'circle') { - svg$$1.append('circle').attr({ + svg.append('circle').attr({ cx: '.5em', cy: '.5em', r: '.45em', class: 'legend-mark' }); } else if (e.mark === 'line') { - svg$$1.append('line').attr({ + svg.append('line').attr({ x1: 0, y1: '.5em', x2: '1em', @@ -1714,7 +1714,7 @@ class: 'legend-mark' }); } else if (e.mark === 'square') { - svg$$1.append('rect').attr({ + svg.append('rect').attr({ height: '1em', width: '1em', class: 'legend-mark', @@ -1726,10 +1726,10 @@ .selectAll('.legend-color-block') .select('.legend-mark') .attr('fill', function(d) { - return d.color || scale$$1(d.label); + return d.color || scale(d.label); }) .attr('stroke', function(d) { - return d.color || scale$$1(d.label); + return d.color || scale(d.label); }) .each(function(e) { d3.select(this).attr(e.attributes); @@ -1743,7 +1743,7 @@ return d.label; }); - if (scale$$1.domain().length > 0) { + if (scale.domain().length > 0) { var legendDisplay = (this.config.legend.location === 'bottom' || this.config.legend.location === 'top') && !this.parent @@ -3335,8 +3335,8 @@ } /*------------------------------------------------------------------------------------------------\ - Check equality of two arrays (https://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript) -\------------------------------------------------------------------------------------------------*/ + Check equality of two arrays (https://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript) + \------------------------------------------------------------------------------------------------*/ // Warn if overriding existing method if (Array.prototype.equals) @@ -3782,6 +3782,7 @@ } function layout$4() { + //Add sort container. this.sortable.wrap = this.wrap .select('.table-top') .append('div') @@ -3970,8 +3971,8 @@ if (next >= this.config.nPages) next = this.config.nPages - 1; // nothing after the last page /**-------------------------------------------------------------------------------------------\ - Left side - \-------------------------------------------------------------------------------------------**/ + Left side + \-------------------------------------------------------------------------------------------**/ this.pagination.wrap .insert('span', ':first-child') @@ -3998,8 +3999,8 @@ .text('<<'); /**-------------------------------------------------------------------------------------------\ - Right side - \-------------------------------------------------------------------------------------------**/ + Right side + \-------------------------------------------------------------------------------------------**/ this.pagination.wrap .append('span') @@ -4353,8 +4354,8 @@ this.events.onDatatransform.call(this); /**-------------------------------------------------------------------------------------------\ - Code below associated with the former paradigm of a d3.nest() data array. - \-------------------------------------------------------------------------------------------**/ + Code below associated with the former paradigm of a d3.nest() data array. + \-------------------------------------------------------------------------------------------**/ if (config.row_per) { var rev_order = config.row_per.slice(0).reverse(); diff --git a/man/generateSettings.Rd b/man/generateSettings.Rd index f4bb5e9c..2c14b94e 100644 --- a/man/generateSettings.Rd +++ b/man/generateSettings.Rd @@ -4,17 +4,22 @@ \alias{generateSettings} \title{Generate a settings object based on a data standard} \usage{ -generateSettings(standard = "None", chart = "eDish", partial = FALSE, - partial_keys = NULL) +generateSettings(standard = "None", charts = NULL, + useDefaults = TRUE, partial = FALSE, partial_keys = NULL, + custom_settings = NULL) } \arguments{ -\item{standard}{The data standard for which to create settings. Valid options are "SDTM", "AdAM" or "None". Default: \code{"SDTM"}} +\item{standard}{The data standard for which to create settings. Valid options are "SDTM", "AdAM" or "None". Default: \code{"None"}.} -\item{chart}{The chart for which standards should be generated ("eDish" only for now) . Default: \code{"eDish"}.} +\item{charts}{The chart or chart(s) for which settings should be generated. Default: \code{NULL} (uses all available charts).} + +\item{useDefaults}{Specifies whether default values from settingsMetadata should be included in the settings object. Default: \code{TRUE}.} \item{partial}{Boolean for whether or not the standard is a partial standard. Default: \code{FALSE}.} \item{partial_keys}{Optional character vector of the matched settings if partial is TRUE. Settings should be identified using the text_key format described in ?settingsMetadata. Setting is ignored when partial is FALSE. Default: \code{NULL}.} + +\item{custom_settings}{a tibble with text_key and customValue columns specifiying customizations to be applied to the settings object. Default: \code{NULL}.} } \value{ A list containing the appropriate settings for the selected chart diff --git a/man/generateShell.Rd b/man/generateShell.Rd new file mode 100644 index 00000000..d66a4d57 --- /dev/null +++ b/man/generateShell.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/generateShell.R +\name{generateShell} +\alias{generateShell} +\title{Generate a default settings shell based on settings metadata} +\usage{ +generateShell(charts = NULL) +} +\arguments{ +\item{charts}{The chart or chart(s) to include in the shell settings object} +} +\value{ +A list containing a setting shell (all values = NA) for the selected chart(s) +} +\description{ +This function returns a default settings object based on the chart(s) specified. +} +\details{ +The function is designed to work with valid safetyGraphics charts. +} +\examples{ + +safetyGraphics:::generateShell(charts = "eDish") + +} +\keyword{internal} diff --git a/man/setSettingsValue.Rd b/man/setSettingsValue.Rd index 250bc4c4..dcced802 100644 --- a/man/setSettingsValue.Rd +++ b/man/setSettingsValue.Rd @@ -4,7 +4,7 @@ \alias{setSettingsValue} \title{Set the value for a given named parameter} \usage{ -setSettingsValue(key, value, settings) +setSettingsValue(key, value, settings, forceCreate = FALSE) } \arguments{ \item{key}{a list (like those provided by \code{getSettingKeys()}) defining the position of parameter in the settings object.} @@ -12,6 +12,8 @@ setSettingsValue(key, value, settings) \item{value}{the value to set} \item{settings}{The settings list used to generate a chart like \code{eDISH()}} + +\item{forceCreate}{Specifies whether the function should create a new list() when none exisits. This most commonly occurs when deeply nested objects.} } \value{ the updated settings object diff --git a/man/settingsMetadata.Rd b/man/settingsMetadata.Rd index 7574fe69..dcadfa89 100644 --- a/man/settingsMetadata.Rd +++ b/man/settingsMetadata.Rd @@ -17,6 +17,7 @@ \item{field_mapping}{Flag indicating whether the setting corresponds to a field-level mapping in the data} \item{field_column_key}{Key for the column that provides options for the field-level mapping in the data} \item{setting_cat}{Setting category (data, measure, appearance)} + \item{default}{Default value for non-data settings} }} \source{ Created for this package diff --git a/tests/testthat/test_generateSettings.R b/tests/testthat/test_generateSettings.R index 78dbc96b..f99a356c 100644 --- a/tests/testthat/test_generateSettings.R +++ b/tests/testthat/test_generateSettings.R @@ -5,19 +5,17 @@ setting_names<-c("id_col","value_col","measure_col","normal_col_low","normal_col test_that("a list with the expected properties and structure is returned for all standards",{ expect_is(generateSettings(standard="None"),"list") - expect_named(generateSettings(standard="None"),setting_names) - expect_named(generateSettings(standard="None")[["measure_values"]], c("ALT","AST","TB","ALP")) + expect_equal(sort(names(generateSettings(standard="None"))),sort(setting_names)) + expect_equal(sort(names(generateSettings(standard="None")[["measure_values"]])), sort(c("ALT","AST","TB","ALP"))) expect_is(generateSettings(standard="ADaM"),"list") - expect_named(generateSettings(standard="ADaM"),setting_names) - expect_named(generateSettings(standard="ADaM")[["measure_values"]], c("ALT","AST","TB","ALP")) - + expect_equal(sort(names(generateSettings(standard="ADaM"))),sort(setting_names)) + expect_equal(sort(names(generateSettings(standard="ADaM")[["measure_values"]])), sort(c("ALT","AST","TB","ALP"))) expect_is(generateSettings(standard="SDTM"),"list") - expect_named(generateSettings(standard="SDTM"),setting_names) - expect_named(generateSettings(standard="SDTM")[["measure_values"]], c("ALT","AST","TB","ALP")) -}) + expect_equal(sort(names(generateSettings(standard="SDTM"))),sort(setting_names)) + expect_equal(sort(names(generateSettings(standard="SDTM")[["measure_values"]])), sort(c("ALT","AST","TB","ALP")))}) -test_that("a warning is thrown if chart isn't eDish",{ +test_that("a warning is thrown if chart isn't found in the chart list",{ expect_error(generateSettings(chart="aeexplorer")) expect_error(generateSettings(chart="")) expect_silent(generateSettings(chart="eDish")) @@ -30,13 +28,13 @@ test_that("data mappings are null when setting=none, character otherwise",{ none_settings <- generateSettings(standard="None") for(text_key in data_setting_keys){ key<-textKeysToList(text_key)[[1]] - expect_null(getSettingValue(settings=none_settings,key=key)) + expect_equal(getSettingValue(settings=none_settings,key=key),NULL) } other_settings <- generateSettings(standard="a different standard") for(text_key in data_setting_keys){ key<-textKeysToList(text_key)[[1]] - expect_null(getSettingValue(settings=other_settings,key=key)) + expect_equal(getSettingValue(settings=other_settings,key=key),NULL) } sdtm_settings <- generateSettings(standard="SDTM") @@ -73,7 +71,7 @@ test_that("data mappings are null when setting=none, character otherwise",{ if (text_key %in% c("id_col","measure_col","measure_values--ALT")) { expect_is(getSettingValue(settings=partial_adam_settings,key=key),"character") } else { - expect_null(getSettingValue(settings=partial_adam_settings,key=key)) + expect_equal(getSettingValue(settings=partial_adam_settings,key=key),NULL) } } @@ -86,4 +84,28 @@ test_that("data mappings are null when setting=none, character otherwise",{ #Testing failure when partial is true with no specified columns expect_error(partial_settings_no_cols <- generateSettings(standard="ADaM", partial=TRUE)) + + #Test useDefaults + noDefaults <- generateSettings(standard="adam",useDefaults=FALSE) + option_keys<-c("x_options", "y_options", "visit_window", "r_ratio_filter", "r_ratio_cut", "showTitle", "warningText") + + #non data mappings are NA + for(text_key in option_keys){ + key<-textKeysToList(text_key)[[1]] + expect_equal(getSettingValue(settings=noDefaults,key=key),NULL) + } + + #data mappings are filled as expected + for(text_key in data_setting_keys){ + key<-textKeysToList(text_key)[[1]] + expect_is(getSettingValue(settings=noDefaults,key=key),"character") + } + + #Test customSettings + customizations<- tibble(text_key=c("id_col","warningText","measure_values--ALT"),customValue=c("customID","This is a custom warning","custom ALT")) + customSettings<-generateSettings(standard="adam",custom_settings=customizations) + expect_equal(getSettingValue(settings=customSettings,key=list("id_col")),"customID") + expect_equal(getSettingValue(settings=customSettings,key=list("warningText")),"This is a custom warning") + expect_equal(getSettingValue(settings=customSettings,key=list("measure_values","ALT")),"custom ALT") + expect_equal(getSettingValue(settings=customSettings,key=list("measure_col")),"PARAM") }) diff --git a/tests/testthat/test_generateShell.R b/tests/testthat/test_generateShell.R new file mode 100644 index 00000000..f0dbbba7 --- /dev/null +++ b/tests/testthat/test_generateShell.R @@ -0,0 +1,13 @@ +context("Tests for the generateShell() function") +library(safetyGraphics) + +default <- generateShell() + +test_that("a list with the expected properties and structure is returned by default",{ + expect_type(default, "list") + expect_equal(default[["id_col"]],NULL) + expect_equal(default[["measure_values"]][["ALT"]],NULL) + expect_null(default[["not_a_setting"]]) +}) + +# TODO: Add tests for the charts parameter once multiple charts are added \ No newline at end of file diff --git a/tests/testthat/test_getRequiredSettings.R b/tests/testthat/test_getRequiredSettings.R index b1d463cc..ea3fed4a 100644 --- a/tests/testthat/test_getRequiredSettings.R +++ b/tests/testthat/test_getRequiredSettings.R @@ -4,15 +4,15 @@ library(testthat) defaultRequiredSettings <- list( list("id_col"), - list("value_col"), list("measure_col"), + list("measure_values","ALP"), list("measure_values","ALT"), list("measure_values","AST"), list("measure_values","TB"), - list("measure_values","ALP"), - list("normal_col_low"), list("normal_col_high"), - list("studyday_col") + list("normal_col_low"), + list("studyday_col"), + list("value_col") ) diff --git a/tests/testthat/test_getSettingValue.R b/tests/testthat/test_getSettingValue.R index 59f5ac00..ea32427a 100644 --- a/tests/testthat/test_getSettingValue.R +++ b/tests/testthat/test_getSettingValue.R @@ -14,7 +14,7 @@ test_that("different data types for `key` parameter work as expected",{ expect_equal(getSettingValue(key="id_col",settings=testSettings),"USUBJID") expect_equal(getSettingValue(key=c("measure_values","ALT"),settings=testSettings),"Aminotransferase, alanine (ALT)") expect_equal(getSettingValue(key=list("measure_values","ALT"),settings=testSettings),"Aminotransferase, alanine (ALT)") - expect_equal(getSettingValue(key=list("measure_values",1),settings=testSettings),"Aminotransferase, alanine (ALT)") + expect_equal(getSettingValue(key=list("measure_values",2),settings=testSettings),"Aminotransferase, alanine (ALT)") }) test_that("returns null if the setting isn't found",{