From 82c01822385ff33139b00e9204940aa0cffb2817 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Sun, 17 Apr 2022 06:59:43 -0400 Subject: [PATCH 01/27] create getChartStatus() and add basic tests. #562 --- NAMESPACE | 2 + R/getChartStatus.R | 69 +++++++++++++++++++++ R/mod_safetyGraphicsServer.R | 2 +- R/prepareChart.R | 8 +++ man/getChartStatus.Rd | 47 ++++++++++++++ tests/testthat/test_getChartStatus.R | 92 ++++++++++++++++++++++++++++ 6 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 R/getChartStatus.R create mode 100644 man/getChartStatus.Rd create mode 100644 tests/testthat/test_getChartStatus.R diff --git a/NAMESPACE b/NAMESPACE index 61095cdd..a28e7476 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -59,6 +59,8 @@ importFrom(magrittr,"%>%") importFrom(purrr,keep) importFrom(purrr,map) importFrom(purrr,map2) +importFrom(purrr,map_lgl) +importFrom(purrr,set_names) importFrom(rlang,.data) importFrom(shiny,dataTableOutput) importFrom(shiny,renderDataTable) diff --git a/R/getChartStatus.R b/R/getChartStatus.R new file mode 100644 index 00000000..5890d112 --- /dev/null +++ b/R/getChartStatus.R @@ -0,0 +1,69 @@ +#' Check the status of a chart based on the current mapping +#' +#' Checks a chart's status when column-level chart specifications are provided in chart$dataSpec. Note that safetyGraphicsApp() does not allow a `mapping` value that is not found in `domainData`, so this function only needs to check that an expected parameter exists in `mapping` (not that the specified column is found in the loaded data). +#' +#' Returns a list, with: +#' - `status` (TRUE, FALSE) +#' - `domains` a list specifying wheter all columns are specified in each domain +#' - `columns` a list that matches the structure of chart$dataSpec and indicates which variables are available. +#' +#' @param chart chart object +#' @param mapping the current mapping data.frame +#' +#' @return a list with `status`, `domains` and `columns` properties +#' +#' @examples +#' sample_chart <- list( +#' domains=c("aes","dm"), +#' dataSpec=list( +#' aes=c("id_col","custom_col"), +#' dm=c("id_col","test_col") +#' ) +#' ) +#' +#' sample_mapping <- data.frame( +#' domain=c("aes","aes","dm","dm"), +#' text_key=c("id_col","custom_col","id_col","test_col"), +#' current=c("myID","AEcol","myID","dmCol") +#' ) +#' +#' check <- getChartStatus(chart=ae_chart, mapping=mapping) +#' # check$status=TRUE +#' +#' @importFrom purrr map_lgl set_names +#' @keywords internal + +getChartStatus <- function(chart, mapping){ + stopifnot( + "Can't get status since chart does not have dataSpec associated."=hasName(chart, 'dataSpec') + ) + + # check to see whether each individual column has a mapping defined + colStatus <- names(chart$dataSpec) %>% map(function(domain){ + domainMapping <- generateMappingList(settingsDF=mapping, domain=domain) + requiredCols <- chart$dataSpec[[domain]] + colStatus <- requiredCols %>% map(function(col){ + if(hasName(domainMapping,col)){ + status<-case_when( + domainMapping[[col]]=='' ~ FALSE, + is.na(domainMapping[[col]]) ~ FALSE, + is.character(domainMapping[[col]]) ~ TRUE + ) + } else{ + status<-FALSE + } + return(status) + }) %>% set_names(requiredCols) + return(colStatus) + })%>% set_names(names(chart$dataSpec)) + + # check to see whether all columns in a domain were valid + domainStatus <- colStatus %>% + map(~all(unlist(.x))) %>% + set_names(names(colStatus)) + + # check to see whether all columns in all domains were valid + status <- all(unlist(domainStatus)) + + return(list(columns=colStatus, domains=domainStatus, status=status)) +} \ No newline at end of file diff --git a/R/mod_safetyGraphicsServer.R b/R/mod_safetyGraphicsServer.R index 0d7e4b85..c9a76ec2 100644 --- a/R/mod_safetyGraphicsServer.R +++ b/R/mod_safetyGraphicsServer.R @@ -33,7 +33,7 @@ safetyGraphicsServer <- function(input, output, session, meta, mapping, domainDa callModule(homeTab, "home") - #Initialize Chart UI - Adds subtabs to chart menu - this initializes initializes chart UIs + #Initialize Chart UI - Adds subtabs to chart menu - this initializes the chart UIs charts %>% purrr::map(~chartsNav(.x,session$ns)) #Initialize Chart Servers diff --git a/R/prepareChart.R b/R/prepareChart.R index 71ffebc4..cc19aecf 100644 --- a/R/prepareChart.R +++ b/R/prepareChart.R @@ -37,6 +37,14 @@ prepareChart <- function(chart){ tolower(chart$env)=="safetygraphics" ) + # check to see if data specifications are provided in domain + if(typeof(chart$domain)=="list"){ + if(!hasName(chart,"dataSpec")){ + chart$dataSpec <- chart$domain + } + chart$domain <- names(chart$domain) + } + #### Bind Workflow functions to chart object #### if(!hasName(chart,"functions")){ diff --git a/man/getChartStatus.Rd b/man/getChartStatus.Rd new file mode 100644 index 00000000..2ee7d076 --- /dev/null +++ b/man/getChartStatus.Rd @@ -0,0 +1,47 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/getChartStatus.R +\name{getChartStatus} +\alias{getChartStatus} +\title{Check the status of a chart based on the current mapping} +\usage{ +getChartStatus(chart, mapping) +} +\arguments{ +\item{chart}{chart object} + +\item{mapping}{the current mapping data.frame} +} +\value{ +a list with \code{status}, \code{domains} and \code{columns} properties +} +\description{ +Checks a chart's status when column-level chart specifications are provided in chart$dataSpec. Note that safetyGraphicsApp() does not allow a \code{mapping} value that is not found in \code{domainData}, so this function only needs to check that an expected parameter exists in \code{mapping} (not that the specified column is found in the loaded data). +} +\details{ +Returns a list, with: +\itemize{ +\item \code{status} (TRUE, FALSE) +\item \code{domains} a list specifying wheter all columns are specified in each domain +\item \code{columns} a list that matches the structure of chart$dataSpec and indicates which variables are available. +} +} +\examples{ +sample_chart <- list( + domains=c("aes","dm"), + dataSpec=list( + aes=c("id_col","custom_col"), + dm=c("id_col","test_col") + ) +) + +sample_mapping <- data.frame( + domain=c("aes","aes","dm","dm"), + text_key=c("id_col","custom_col","id_col","test_col"), + current=c("myID","AEcol","myID","dmCol") +) + +check <- getChartStatus(chart=ae_chart, mapping=mapping) +# check$status=TRUE + +} +\keyword{internal} diff --git a/tests/testthat/test_getChartStatus.R b/tests/testthat/test_getChartStatus.R new file mode 100644 index 00000000..f0586ec4 --- /dev/null +++ b/tests/testthat/test_getChartStatus.R @@ -0,0 +1,92 @@ +context("Tests for the getChartStatus() function") +library(safetyGraphics) +library(safetyCharts) + +# Functional Specification +# [*] chart with no data spec throws error +# [*] status returned correctly for valid chart +# [*] status returned correctly when mapping values for a column are '' and NA +# [*] status returned correctly when dataSpec is not found in mapping + +test_that("chart with no data spec throws error",{ + expect_error(chart=list(domains=c("ae","dm"))) +}) + +test_that("status returned correctly for valid chart",{ + ae_chart <- list( + domains=c("aes","dm"), + dataSpec=list( + aes=c("id_col","custom_col"), + dm=c("id_col","test_col") + ) + ) + + mapping <- data.frame( + domain=c("aes","aes","dm","dm"), + text_key=c("id_col","custom_col","id_col","test_col"), + current=c("myID","AEcol","myID","dmCol") + ) + + status<-getChartStatus(chart=ae_chart, mapping=mapping) + expect_true(status$status) + expect_true(status$domains$aes) + expect_true(status$domains$dm) + expect_true(status$columns$aes$id_col) + expect_true(status$columns$aes$custom_col) + expect_true(status$columns$dm$id_col) + expect_true(status$columns$dm$test_col) +}) + + +test_that("status returned correctly for invalid chart",{ + ae_chart <- list( + domains=c("aes","dm"), + dataSpec=list( + aes=c("id_col","custom_col"), + dm=c("id_col","test_col") + ) + ) + + mapping <- data.frame( + domain=c("aes","aes","dm","dm"), + text_key=c("id_col","custom_col","id_col","test_col"), + current=c(NA,"","myID","dmCol") + ) + + status<-getChartStatus(chart=ae_chart, mapping=mapping) + expect_false(status$status) + expect_false(status$domains$aes) + expect_true(status$domains$dm) + expect_false(status$columns$aes$id_col) + expect_false(status$columns$aes$custom_col) + expect_true(status$columns$dm$id_col) + expect_true(status$columns$dm$test_col) +}) + + +test_that("status returned correctly for invalid chart",{ + ae_chart <- list( + domains=c("aes","dm"), + dataSpec=list( + aes=c("id_col","custom_col","another_col"), + dm=c("id_col","test_col") + ) + ) + + mapping <- data.frame( + domain=c("aes","aes","dm","dm"), + text_key=c("id_col","custom_col","id_col","test_col"), + current=c("myID","aesCol","myID","dmCol") + ) + ml<-generateMappingList(settingsDF=mapping, domain='aes') + expect_false(hasName(ml,"another_col")) + status<-getChartStatus(chart=ae_chart, mapping=mapping) + expect_false(status$status) + expect_false(status$domains$aes) + expect_true(status$domains$dm) + expect_true(status$columns$aes$id_col) + expect_true(status$columns$aes$custom_col) + expect_false(status$columns$aes$another_col) + expect_true(status$columns$dm$id_col) + expect_true(status$columns$dm$test_col) +}) From da59bf3103efd3471dbf4f91ca6e866c9a603fb1 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Mon, 18 Apr 2022 09:55:54 -0400 Subject: [PATCH 02/27] starting on UI updates --- R/getChartStatus.R | 6 +++--- R/makeChartSummary.R | 6 +++--- R/mod_safetyGraphicsServer.R | 42 +++++++++++++++++++++++++++--------- inst/www/index.css | 16 ++++++++++++++ 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/R/getChartStatus.R b/R/getChartStatus.R index 5890d112..7617c4f9 100644 --- a/R/getChartStatus.R +++ b/R/getChartStatus.R @@ -8,7 +8,7 @@ #' - `columns` a list that matches the structure of chart$dataSpec and indicates which variables are available. #' #' @param chart chart object -#' @param mapping the current mapping data.frame +#' @param mapping the current mapping data.frame #' #' @return a list with `status`, `domains` and `columns` properties #' @@ -63,7 +63,7 @@ getChartStatus <- function(chart, mapping){ set_names(names(colStatus)) # check to see whether all columns in all domains were valid - status <- all(unlist(domainStatus)) + status <- ifelse(all(unlist(domainStatus)),"valid","invalid") - return(list(columns=colStatus, domains=domainStatus, status=status)) + return(list(chart=chart$name, columns=colStatus, domains=domainStatus, status=status)) } \ No newline at end of file diff --git a/R/makeChartSummary.R b/R/makeChartSummary.R index 450b30f9..cfcb7840 100644 --- a/R/makeChartSummary.R +++ b/R/makeChartSummary.R @@ -24,9 +24,9 @@ makeChartSummary<- function(chart, showLinks=TRUE, class="chart-header"){ links<-NULL } - labelDiv<-div(tags$small("Chart"),chart$label) - typeDiv<-div(tags$small("Type"), chart$type) - dataDiv<-div(tags$small("Data Domain"), paste(chart$domain,collapse=" ")) + labelDiv<-div(class="name", tags$small("Chart"),chart$label) + typeDiv<-div(class="type", tags$small("Type"), chart$type) + dataDiv<-div(class="domain", tags$small("Data Domain"), paste(chart$domain,collapse=" ")) if(showLinks){ summary<-div( diff --git a/R/mod_safetyGraphicsServer.R b/R/mod_safetyGraphicsServer.R index c9a76ec2..fd0a640f 100644 --- a/R/mod_safetyGraphicsServer.R +++ b/R/mod_safetyGraphicsServer.R @@ -14,15 +14,15 @@ #' @import shiny #' @import dplyr #' @importFrom purrr map -#' @importFrom shinyjs html +#' @importFrom shinyjs html toggleClass #' #' @export safetyGraphicsServer <- function(input, output, session, meta, mapping, domainData, charts, filterDomain){ - #Initialize modules - current_mapping<-callModule(mappingTab, "mapping", meta, domainData) + # Initialize the Home tab + callModule(homeTab, "home") - # Initialize the filter tab + # Initialize the Filter tab - returns list of filtered data as a reactive filtered_data<-callModule( filterTab, "filter", @@ -30,14 +30,15 @@ safetyGraphicsServer <- function(input, output, session, meta, mapping, domainDa filterDomain=filterDomain, current_mapping=current_mapping ) - - callModule(homeTab, "home") - #Initialize Chart UI - Adds subtabs to chart menu - this initializes the chart UIs + # Initialize the Mapping tab - returns the current mapping as a reactive + current_mapping<-callModule(mappingTab, "mapping", meta, domainData) + + # Initialize Charts tab + # Initialize Chart UI - adds subtabs to chart menu and initializes the chart UIs charts %>% purrr::map(~chartsNav(.x,session$ns)) - #Initialize Chart Servers - validDomains <- tolower(names(mapping)) + # Initialize Chart Servers charts %>% purrr::map( ~callModule( module=chartsTab, @@ -48,7 +49,28 @@ safetyGraphicsServer <- function(input, output, session, meta, mapping, domainDa ) ) - #Setting tab + # Keep chart status updated + charts_status <- reactive({ + charts %>% purrr::map(function(chart){ + if(hasName(chart, 'dataSpec')){ + getChartStatus(chart,current_mapping()) + }else{ + list(chart=chart$name,status="missing") + } + }) + }) + + observeEvent(charts_status(),{ + for (check in charts_status()){ + ## code to toggle css for chart-specific tab here + shinyjs::toggleClass(selector= paste0("#sg-safetyGraphicsApp li.dropdown ul li a[data-value='", check$chart, "']"), class="valid", condition=check$status=="valid") + shinyjs::toggleClass(selector= paste0("#sg-safetyGraphicsApp li.dropdown ul li a[data-value='", check$chart, "']"), class="invalid", condition=check$status=="invalid") + shinyjs::toggleClass(selector= paste0("#sg-safetyGraphicsApp li.dropdown ul li a[data-value='", check$chart, "']"), class="missing", condition=check$status=="missing") + + } + }) + + # Initialize the Setting tab callModule(settingsTab, "settings", domains = domainData, metadata=meta, mapping=current_mapping, charts = charts) } diff --git a/inst/www/index.css b/inst/www/index.css index efdc5f3c..bec8866a 100644 --- a/inst/www/index.css +++ b/inst/www/index.css @@ -149,3 +149,19 @@ table.metatable.dataTable tr > td:last-of-type, table.metatable.trdataTable tr > } +/* chart validation formatting */ +#sg-safetyGraphicsApp li.dropdown ul li a.valid div div.name:before { + font-family: "Font Awesome 5 Free"; + font-weight: 900; + content: "\f00c"; + color: green; + padding-left: 0.3em; +} + +#sg-safetyGraphicsApp li.dropdown ul li a.invalid div div.name:before { + font-family: "Font Awesome 5 Free"; + font-weight: 900; + content: "\f00d"; + color: red; + padding-left: 0.3em; +} From 3df73c56ce1ca0023ce7e7b1ca095b268a125ad0 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Mon, 23 May 2022 15:21:16 -0400 Subject: [PATCH 03/27] Update R/getChartStatus.R Co-authored-by: Becca Krouse --- R/getChartStatus.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/getChartStatus.R b/R/getChartStatus.R index 7617c4f9..668e1b4c 100644 --- a/R/getChartStatus.R +++ b/R/getChartStatus.R @@ -63,7 +63,7 @@ getChartStatus <- function(chart, mapping){ set_names(names(colStatus)) # check to see whether all columns in all domains were valid - status <- ifelse(all(unlist(domainStatus)),"valid","invalid") + status <- ifelse(all(unlist(domainStatus)),TRUE, FALSE) return(list(chart=chart$name, columns=colStatus, domains=domainStatus, status=status)) } \ No newline at end of file From 4919803abcadb71b23ca2882766b6ffbb495ffcd Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 24 May 2022 11:20:55 -0400 Subject: [PATCH 04/27] refactor chart modules to simplify reactive flow --- R/mod_chartsNav.R | 45 ++++++++++++++++++++++++++---------- R/mod_chartsTab.R | 7 +++++- R/mod_safetyGraphicsServer.R | 27 +++------------------- R/mod_safetyGraphicsUI.R | 12 ++++++++-- R/safetyGraphicsApp.R | 9 +++++++- R/safetyGraphicsInit.R | 1 + 6 files changed, 61 insertions(+), 40 deletions(-) diff --git a/R/mod_chartsNav.R b/R/mod_chartsNav.R index 6904a81e..7a1c80d8 100644 --- a/R/mod_chartsNav.R +++ b/R/mod_chartsNav.R @@ -1,22 +1,43 @@ #' Adds a navbar tab that initializes the Chart Module UI #' +#' @param id #' @param chart chart metadata -#' @param ns namespace #' #' @export #' -chartsNav <- function(chart,ns){ - appendTab( - inputId = "safetyGraphicsApp", - menuName = "Charts", - tab = tabPanel( - title = makeChartSummary(chart, showLinks=FALSE, class="chart-nav"), - value = chart$name, - chartsTabUI( - id=ns(chart$name), - chart=chart - ) +chartsNavUI <- function(id, chart){ + ns <- NS(id) + panel<-tabPanel( + title = uiOutput(ns("tabTitle")), + value = chart$name, + chartsTabUI( + id=ns("chart"), + chart=chart ) ) + return(panel) +} + +#' Server for a navbar tab +#' +#' @param chart chart metadata +#' +#' @export +#' + +chartsNav<-function(input, output, session, chart, data, mapping){ + #status <- getChartStatus(chart,current_mapping) + + ns <- session$ns + print(paste("running chartsNav() in:", ns(''))) + output$tabTitle <- renderUI({makeChartSummary(chart, showLinks=FALSE, class="chart-nav")}) + + callModule( + module=chartsTab, + id='chart', + chart=chart, + data=data, + mapping=mapping + ) } \ No newline at end of file diff --git a/R/mod_chartsTab.R b/R/mod_chartsTab.R index 7b274b5f..a4a59f3a 100644 --- a/R/mod_chartsTab.R +++ b/R/mod_chartsTab.R @@ -10,7 +10,7 @@ chartsTabUI <- function(id, chart){ ns <- shiny::NS(id) - header<-div(class=ns("header"), makeChartSummary(chart)) + header<- uiOutput(ns("chart-header")) chartWrap<-chart$functions$ui(ns("chart-wrap")) return(list(header, chartWrap)) @@ -30,6 +30,11 @@ chartsTabUI <- function(id, chart){ chartsTab <- function(input, output, session, chart, data, mapping){ ns <- session$ns + print(paste("running chartsTab in:", ns(''))) + + # Draw the header + output$`chart-header` <- renderUI({makeChartSummary(chart)}) + # Initialize chart-specific parameters params <- reactive({ makeChartParams( diff --git a/R/mod_safetyGraphicsServer.R b/R/mod_safetyGraphicsServer.R index fd0a640f..a8b807d4 100644 --- a/R/mod_safetyGraphicsServer.R +++ b/R/mod_safetyGraphicsServer.R @@ -36,40 +36,19 @@ safetyGraphicsServer <- function(input, output, session, meta, mapping, domainDa # Initialize Charts tab # Initialize Chart UI - adds subtabs to chart menu and initializes the chart UIs - charts %>% purrr::map(~chartsNav(.x,session$ns)) + #charts %>% purrr::map(~chartsNavUI(.x$name,.x)) # Initialize Chart Servers charts %>% purrr::map( ~callModule( - module=chartsTab, + module=chartsNav, id=.x$name, chart=.x, data=filtered_data, - mapping=current_mapping + mapping=current_mapping ) ) - # Keep chart status updated - charts_status <- reactive({ - charts %>% purrr::map(function(chart){ - if(hasName(chart, 'dataSpec')){ - getChartStatus(chart,current_mapping()) - }else{ - list(chart=chart$name,status="missing") - } - }) - }) - - observeEvent(charts_status(),{ - for (check in charts_status()){ - ## code to toggle css for chart-specific tab here - shinyjs::toggleClass(selector= paste0("#sg-safetyGraphicsApp li.dropdown ul li a[data-value='", check$chart, "']"), class="valid", condition=check$status=="valid") - shinyjs::toggleClass(selector= paste0("#sg-safetyGraphicsApp li.dropdown ul li a[data-value='", check$chart, "']"), class="invalid", condition=check$status=="invalid") - shinyjs::toggleClass(selector= paste0("#sg-safetyGraphicsApp li.dropdown ul li a[data-value='", check$chart, "']"), class="missing", condition=check$status=="missing") - - } - }) - # Initialize the Setting tab callModule(settingsTab, "settings", domains = domainData, metadata=meta, mapping=current_mapping, charts = charts) } diff --git a/R/mod_safetyGraphicsUI.R b/R/mod_safetyGraphicsUI.R index 523b0a22..03e36288 100644 --- a/R/mod_safetyGraphicsUI.R +++ b/R/mod_safetyGraphicsUI.R @@ -2,6 +2,7 @@ #' #' #' @param id module ID +#' @param charts list of charts in the format produced by safetyGraphics::makeChartConfig() #' @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()} @@ -11,7 +12,7 @@ #' #' @export -safetyGraphicsUI <- function(id, meta, domainData, mapping, standards){ +safetyGraphicsUI <- function(id, meta, charts, domainData, mapping, standards){ ns<-NS(id) #read css from package @@ -37,6 +38,13 @@ safetyGraphicsUI <- function(id, meta, domainData, mapping, standards){ spinner<-NULL } + #Set up ChartNav + #trick for navbar menu: https://stackoverflow.com/questions/34846469/for-loops-lapply-navbarpage-within-in-ui-r + + chartList <- charts %>% purrr::map(~chartsNavUI(ns(.x$name),.x)) %>% unname + navParams<-c(list(title='Charts', icon=icon("chart-bar")), chartList) + chartNav <- do.call(navbarMenu, navParams) + #app UI using calls to modules ui<-tagList( shinyjs::useShinyjs(), @@ -55,7 +63,7 @@ safetyGraphicsUI <- function(id, meta, domainData, mapping, standards){ tabPanel("Home", icon=icon("home"),homeTabUI(ns("home"))), tabPanel("Mapping", icon=icon("map"), mappingTabUI(ns("mapping"), meta, domainData, mapping, standards)), tabPanel("Filtering", icon=icon("filter"), filterTabUI(ns("filter"))), - navbarMenu('Charts', icon=icon("chart-bar")), + chartNav, tabPanel('',icon=icon("cog"), settingsTabUI(ns("settings"))) ), participant_badge diff --git a/R/safetyGraphicsApp.R b/R/safetyGraphicsApp.R index 9ba1a102..33e2bdb7 100644 --- a/R/safetyGraphicsApp.R +++ b/R/safetyGraphicsApp.R @@ -32,7 +32,14 @@ safetyGraphicsApp <- function( config <- app_startup(domainData, meta, charts, mapping, autoMapping, filterDomain, chartSettingsPaths) app <- shinyApp( - ui = safetyGraphicsUI("sg",config$meta, config$domainData, config$mapping, config$standards), + ui = safetyGraphicsUI( + "sg", + config$meta, + config$charts, + config$domainData, + config$mapping, + config$standards + ), server = function(input,output,session){ callModule( safetyGraphicsServer, diff --git a/R/safetyGraphicsInit.R b/R/safetyGraphicsInit.R index 39762f63..ff7be5ea 100644 --- a/R/safetyGraphicsInit.R +++ b/R/safetyGraphicsInit.R @@ -130,6 +130,7 @@ safetyGraphicsInit <- function(charts=makeChartConfig(), delayTime=1000, maxFile safetyGraphicsUI( "sg", config$meta, + config$charts, config$domainData, config$mapping, config$standards From c68d0be76a1d681041619191a464b77f4f444c04 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 24 May 2022 12:57:00 -0400 Subject: [PATCH 05/27] add basic UI for chart status --- R/makeChartSummary.R | 17 +++++++++++++++-- R/mod_chartsNav.R | 16 ++++++++++++---- R/mod_chartsTab.R | 4 ++-- inst/www/index.css | 20 +------------------- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/R/makeChartSummary.R b/R/makeChartSummary.R index cfcb7840..68c8d290 100644 --- a/R/makeChartSummary.R +++ b/R/makeChartSummary.R @@ -7,7 +7,18 @@ #' #' @export -makeChartSummary<- function(chart, showLinks=TRUE, class="chart-header"){ +makeChartSummary<- function(chart, status=NULL, showLinks=TRUE, class="chart-header"){ + + if(!is.null(status)){ + if(status$status){ + status <- div(class="status", tags$i(class="fa fa-check-circle", style="color: green")) + }else{ + status <- div(class="status", tags$i(class="fa fa-times-circle", style="color: red")) + } + }else{ + status <- NULL + } + if(utils::hasName(chart,"links")){ links<-purrr::map2( chart$links, @@ -23,13 +34,14 @@ makeChartSummary<- function(chart, showLinks=TRUE, class="chart-header"){ }else{ links<-NULL } - + labelDiv<-div(class="name", tags$small("Chart"),chart$label) typeDiv<-div(class="type", tags$small("Type"), chart$type) dataDiv<-div(class="domain", tags$small("Data Domain"), paste(chart$domain,collapse=" ")) if(showLinks){ summary<-div( + status, labelDiv, typeDiv, dataDiv, @@ -38,6 +50,7 @@ makeChartSummary<- function(chart, showLinks=TRUE, class="chart-header"){ ) } else { summary<-div( + status, labelDiv, typeDiv, dataDiv, diff --git a/R/mod_chartsNav.R b/R/mod_chartsNav.R index 7a1c80d8..d01795b0 100644 --- a/R/mod_chartsNav.R +++ b/R/mod_chartsNav.R @@ -21,23 +21,31 @@ chartsNavUI <- function(id, chart){ #' Server for a navbar tab #' -#' @param chart chart metadata +#' @param chart chart metadata #' #' @export #' chartsNav<-function(input, output, session, chart, data, mapping){ - #status <- getChartStatus(chart,current_mapping) + chartStatus <- reactive({ + if(hasName(chart, 'dataSpec')){ + status<-getChartStatus(chart, mapping()) + }else{ + status<-NULL + } + return(status) + }) ns <- session$ns print(paste("running chartsNav() in:", ns(''))) - output$tabTitle <- renderUI({makeChartSummary(chart, showLinks=FALSE, class="chart-nav")}) + output$tabTitle <- renderUI({makeChartSummary(chart, status=chartStatus(), showLinks=FALSE, class="chart-nav")}) callModule( module=chartsTab, id='chart', chart=chart, data=data, - mapping=mapping + mapping=mapping, + status=chartStatus ) } \ No newline at end of file diff --git a/R/mod_chartsTab.R b/R/mod_chartsTab.R index a4a59f3a..ac0cc113 100644 --- a/R/mod_chartsTab.R +++ b/R/mod_chartsTab.R @@ -27,13 +27,13 @@ chartsTabUI <- function(id, chart){ #' #' @export -chartsTab <- function(input, output, session, chart, data, mapping){ +chartsTab <- function(input, output, session, chart, data, mapping, status){ ns <- session$ns print(paste("running chartsTab in:", ns(''))) # Draw the header - output$`chart-header` <- renderUI({makeChartSummary(chart)}) + output$`chart-header` <- renderUI({makeChartSummary(chart, status=status())}) # Initialize chart-specific parameters params <- reactive({ diff --git a/inst/www/index.css b/inst/www/index.css index 8bee564c..f1226335 100644 --- a/inst/www/index.css +++ b/inst/www/index.css @@ -130,7 +130,7 @@ table.metatable.dataTable tr > td:last-of-type, table.metatable.trdataTable tr > display:inline-block; } -.chart-nav div:not(:first-child){ +.chart-nav div:not(.name){ font-size:0.8em; color: #999; } @@ -151,21 +151,3 @@ table.metatable.dataTable tr > td:last-of-type, table.metatable.trdataTable tr > background-color: #d1ecf1; border:1px solid #bee5eb; } - - -/* chart validation formatting */ -#sg-safetyGraphicsApp li.dropdown ul li a.valid div div.name:before { - font-family: "Font Awesome 5 Free"; - font-weight: 900; - content: "\f00c"; - color: green; - padding-left: 0.3em; -} - -#sg-safetyGraphicsApp li.dropdown ul li a.invalid div div.name:before { - font-family: "Font Awesome 5 Free"; - font-weight: 900; - content: "\f00d"; - color: red; - padding-left: 0.3em; -} From 44bf28fee676672ca93240f95a094bacab5825c2 Mon Sep 17 00:00:00 2001 From: jwildfire Date: Tue, 24 May 2022 21:29:51 -0400 Subject: [PATCH 06/27] clear checks --- DESCRIPTION | 2 +- NAMESPACE | 2 ++ R/getChartStatus.R | 2 +- R/makeChartSummary.R | 1 + R/mod_chartsNav.R | 11 ++++++++--- R/mod_chartsTab.R | 1 + R/mod_safetyGraphicsUI.R | 3 +-- man/chartsNav.Rd | 18 +++++++++++++----- man/chartsNavUI.Rd | 16 ++++++++++++++++ man/chartsTab.Rd | 4 +++- man/getChartStatus.Rd | 2 +- man/makeChartSummary.Rd | 9 ++++++++- man/safetyGraphicsUI.Rd | 4 +++- 13 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 man/chartsNavUI.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 34ba1647..3cd5d132 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,7 @@ Depends: R (>= 4.0) License: MIT + file LICENSE Encoding: UTF-8 LazyData: true -RoxygenNote: 7.1.2 +RoxygenNote: 7.2.0 Suggests: ggplot2 (>= 3.3.0), knitr (>= 1.34), diff --git a/NAMESPACE b/NAMESPACE index a28e7476..6c11b797 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,6 +3,7 @@ export("%>%") export(app_startup) export(chartsNav) +export(chartsNavUI) export(chartsTab) export(chartsTabUI) export(detectStandard) @@ -74,6 +75,7 @@ importFrom(shinyjs,hide) importFrom(shinyjs,html) importFrom(shinyjs,removeClass) importFrom(shinyjs,show) +importFrom(shinyjs,toggleClass) importFrom(shinyjs,useShinyjs) importFrom(sortable,add_rank_list) importFrom(sortable,bucket_list) diff --git a/R/getChartStatus.R b/R/getChartStatus.R index 668e1b4c..bfceee39 100644 --- a/R/getChartStatus.R +++ b/R/getChartStatus.R @@ -27,7 +27,7 @@ #' current=c("myID","AEcol","myID","dmCol") #' ) #' -#' check <- getChartStatus(chart=ae_chart, mapping=mapping) +#' check <- safetyGraphics:::getChartStatus(chart=sample_chart, mapping=sample_mapping) #' # check$status=TRUE #' #' @importFrom purrr map_lgl set_names diff --git a/R/makeChartSummary.R b/R/makeChartSummary.R index 68c8d290..07b664fe 100644 --- a/R/makeChartSummary.R +++ b/R/makeChartSummary.R @@ -2,6 +2,7 @@ #' @description makes a nicely formatted html summary for a chart object #' #' @param chart list containing chart specifications +#' @param status (optional) chart status from `getChartStatus`. Default is NULL. #' @param showLinks boolean indicating whether to include links #' @param class character to include as class #' diff --git a/R/mod_chartsNav.R b/R/mod_chartsNav.R index d01795b0..c69c257f 100644 --- a/R/mod_chartsNav.R +++ b/R/mod_chartsNav.R @@ -1,7 +1,7 @@ #' Adds a navbar tab that initializes the Chart Module UI #' -#' @param id -#' @param chart chart metadata +#' @param id module id +#' @param chart chart metadata #' #' @export #' @@ -21,7 +21,12 @@ chartsNavUI <- function(id, chart){ #' Server for a navbar tab #' -#' @param chart chart metadata +#' @param input Input objects from module namespace +#' @param output Output objects from module namespace +#' @param session An environment that can be used to access information and functionality relating to the session +#' @param chart list containing a safetyGraphics chart object like those returned by \link{makeChartConfig}. +#' @param data named list of current data sets (Reactive). +#' @param mapping tibble capturing the current data mappings (Reactive). #' #' @export #' diff --git a/R/mod_chartsTab.R b/R/mod_chartsTab.R index ac0cc113..3ba4aa07 100644 --- a/R/mod_chartsTab.R +++ b/R/mod_chartsTab.R @@ -24,6 +24,7 @@ chartsTabUI <- function(id, chart){ #' @param chart list containing a safetyGraphics chart object like those returned by \link{makeChartConfig}. #' @param data named list of current data sets (Reactive). #' @param mapping tibble capturing the current data mappings (Reactive). +#' @param status chart status (Reactive) #' #' @export diff --git a/R/mod_safetyGraphicsUI.R b/R/mod_safetyGraphicsUI.R index 03e36288..e61f677a 100644 --- a/R/mod_safetyGraphicsUI.R +++ b/R/mod_safetyGraphicsUI.R @@ -1,6 +1,5 @@ #' UI for the core safetyGraphics app including Home, Mapping, Filter, Charts and Settings modules. #' -#' #' @param id module ID #' @param charts list of charts in the format produced by safetyGraphics::makeChartConfig() #' @param meta data frame containing the metadata for use in the app. @@ -12,7 +11,7 @@ #' #' @export -safetyGraphicsUI <- function(id, meta, charts, domainData, mapping, standards){ +safetyGraphicsUI <- function(id, charts, meta, domainData, mapping, standards){ ns<-NS(id) #read css from package diff --git a/man/chartsNav.Rd b/man/chartsNav.Rd index d0197e34..b46e9f65 100644 --- a/man/chartsNav.Rd +++ b/man/chartsNav.Rd @@ -2,15 +2,23 @@ % Please edit documentation in R/mod_chartsNav.R \name{chartsNav} \alias{chartsNav} -\title{Adds a navbar tab that initializes the Chart Module UI} +\title{Server for a navbar tab} \usage{ -chartsNav(chart, ns) +chartsNav(input, output, session, chart, data, mapping) } \arguments{ -\item{chart}{chart metadata} +\item{input}{Input objects from module namespace} -\item{ns}{namespace} +\item{output}{Output objects from module namespace} + +\item{session}{An environment that can be used to access information and functionality relating to the session} + +\item{chart}{list containing a safetyGraphics chart object like those returned by \link{makeChartConfig}.} + +\item{data}{named list of current data sets (Reactive).} + +\item{mapping}{tibble capturing the current data mappings (Reactive).} } \description{ -Adds a navbar tab that initializes the Chart Module UI +Server for a navbar tab } diff --git a/man/chartsNavUI.Rd b/man/chartsNavUI.Rd new file mode 100644 index 00000000..bc3cea1f --- /dev/null +++ b/man/chartsNavUI.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mod_chartsNav.R +\name{chartsNavUI} +\alias{chartsNavUI} +\title{Adds a navbar tab that initializes the Chart Module UI} +\usage{ +chartsNavUI(id, chart) +} +\arguments{ +\item{id}{module id} + +\item{chart}{chart metadata} +} +\description{ +Adds a navbar tab that initializes the Chart Module UI +} diff --git a/man/chartsTab.Rd b/man/chartsTab.Rd index 090efb6c..46d4985b 100644 --- a/man/chartsTab.Rd +++ b/man/chartsTab.Rd @@ -4,7 +4,7 @@ \alias{chartsTab} \title{Server for chart module, designed to be re-used for each chart generated.} \usage{ -chartsTab(input, output, session, chart, data, mapping) +chartsTab(input, output, session, chart, data, mapping, status) } \arguments{ \item{input}{Input objects from module namespace} @@ -18,6 +18,8 @@ chartsTab(input, output, session, chart, data, mapping) \item{data}{named list of current data sets (Reactive).} \item{mapping}{tibble capturing the current data mappings (Reactive).} + +\item{status}{chart status (Reactive)} } \description{ Server for chart module, designed to be re-used for each chart generated. diff --git a/man/getChartStatus.Rd b/man/getChartStatus.Rd index 2ee7d076..be1a5a86 100644 --- a/man/getChartStatus.Rd +++ b/man/getChartStatus.Rd @@ -40,7 +40,7 @@ sample_mapping <- data.frame( current=c("myID","AEcol","myID","dmCol") ) -check <- getChartStatus(chart=ae_chart, mapping=mapping) +check <- safetyGraphics:::getChartStatus(chart=sample_chart, mapping=sample_mapping) # check$status=TRUE } diff --git a/man/makeChartSummary.Rd b/man/makeChartSummary.Rd index e5e0ef9e..1bdda058 100644 --- a/man/makeChartSummary.Rd +++ b/man/makeChartSummary.Rd @@ -4,11 +4,18 @@ \alias{makeChartSummary} \title{html chart summary} \usage{ -makeChartSummary(chart, showLinks = TRUE, class = "chart-header") +makeChartSummary( + chart, + status = NULL, + showLinks = TRUE, + class = "chart-header" +) } \arguments{ \item{chart}{list containing chart specifications} +\item{status}{(optional) chart status from \code{getChartStatus}. Default is NULL.} + \item{showLinks}{boolean indicating whether to include links} \item{class}{character to include as class} diff --git a/man/safetyGraphicsUI.Rd b/man/safetyGraphicsUI.Rd index 99b312a5..bba5aeb7 100644 --- a/man/safetyGraphicsUI.Rd +++ b/man/safetyGraphicsUI.Rd @@ -4,11 +4,13 @@ \alias{safetyGraphicsUI} \title{UI for the core safetyGraphics app including Home, Mapping, Filter, Charts and Settings modules.} \usage{ -safetyGraphicsUI(id, meta, domainData, mapping, standards) +safetyGraphicsUI(id, charts, meta, domainData, mapping, standards) } \arguments{ \item{id}{module ID} +\item{charts}{list of charts in the format produced by safetyGraphics::makeChartConfig()} + \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.} From ff390838ffc4211aa894fac76341f813e67f583f Mon Sep 17 00:00:00 2001 From: jwildfire Date: Tue, 24 May 2022 21:39:12 -0400 Subject: [PATCH 07/27] server/ui params --- R/safetyGraphicsApp.R | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/R/safetyGraphicsApp.R b/R/safetyGraphicsApp.R index 33e2bdb7..f2d8dc3f 100644 --- a/R/safetyGraphicsApp.R +++ b/R/safetyGraphicsApp.R @@ -33,22 +33,22 @@ safetyGraphicsApp <- function( app <- shinyApp( ui = safetyGraphicsUI( - "sg", - config$meta, - config$charts, - config$domainData, - config$mapping, - config$standards + id="sg", + meta=config$meta, + charts=config$charts, + domainData=config$domainData, + mapping=config$mapping, + standards=config$standards ), server = function(input,output,session){ callModule( safetyGraphicsServer, - "sg", - config$meta, - config$mapping, - config$domainData, - config$charts, - config$filterDomain + id="sg", + meta=config$meta, + mapping=config$mapping, + domainData=config$domainData, + charts=config$charts, + filterDomain=config$filterDomain ) } ) From caca325c4fd13b09b4f628fb0960e3455034eea7 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Thu, 2 Jun 2022 16:09:19 -0400 Subject: [PATCH 08/27] more ui updates --- R/getChartStatus.R | 23 +++++++++++++++++++++-- R/makeChartSummary.R | 11 +++++++---- R/mod_mappingColumn.R | 2 +- inst/www/index.css | 9 ++++++++- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/R/getChartStatus.R b/R/getChartStatus.R index bfceee39..8644bec4 100644 --- a/R/getChartStatus.R +++ b/R/getChartStatus.R @@ -39,6 +39,7 @@ getChartStatus <- function(chart, mapping){ ) # check to see whether each individual column has a mapping defined + missingCols<-c() colStatus <- names(chart$dataSpec) %>% map(function(domain){ domainMapping <- generateMappingList(settingsDF=mapping, domain=domain) requiredCols <- chart$dataSpec[[domain]] @@ -51,7 +52,7 @@ getChartStatus <- function(chart, mapping){ ) } else{ status<-FALSE - } + } return(status) }) %>% set_names(requiredCols) return(colStatus) @@ -65,5 +66,23 @@ getChartStatus <- function(chart, mapping){ # check to see whether all columns in all domains were valid status <- ifelse(all(unlist(domainStatus)),TRUE, FALSE) - return(list(chart=chart$name, columns=colStatus, domains=domainStatus, status=status)) + # make a text summary + if(status){ + summary <- "All required mappings found" + }else{ + missingCols <- colStatus %>% imap(function(cols,domain){ + missingDomainCols <- cols %>% imap(function(status, col){ + if(status){ + return(NULL) + }else{ + return(paste0(domain,"$",col)) + } + }) + return(missingDomainCols) + }) + print(missingCols) + summary<- paste0("Missing Mappings: ",paste(unlist(missingCols),collapse=",")) + } + + return(list(chart=chart$name, columns=colStatus, domains=domainStatus, status=status, summary=summary)) } \ No newline at end of file diff --git a/R/makeChartSummary.R b/R/makeChartSummary.R index 07b664fe..2770983b 100644 --- a/R/makeChartSummary.R +++ b/R/makeChartSummary.R @@ -11,10 +11,11 @@ makeChartSummary<- function(chart, status=NULL, showLinks=TRUE, class="chart-header"){ if(!is.null(status)){ + print(status) if(status$status){ - status <- div(class="status", tags$i(class="fa fa-check-circle", style="color: green")) + status <- div(class="status", tags$small("Status"), tags$i(class="fa fa-check-circle", style="color: green"),title=status$summary) }else{ - status <- div(class="status", tags$i(class="fa fa-times-circle", style="color: red")) + status <- div(class="status", tags$small("Status"), tags$i(class="fa fa-times-circle", style="color: red"),title=status$summary) } }else{ status <- NULL @@ -40,21 +41,23 @@ makeChartSummary<- function(chart, status=NULL, showLinks=TRUE, class="chart-hea typeDiv<-div(class="type", tags$small("Type"), chart$type) dataDiv<-div(class="domain", tags$small("Data Domain"), paste(chart$domain,collapse=" ")) + class <- c('chart-summary',class) + if(showLinks){ summary<-div( - status, labelDiv, typeDiv, dataDiv, links, + status, class=class ) } else { summary<-div( - status, labelDiv, typeDiv, dataDiv, + status, class=class ) } diff --git a/R/mod_mappingColumn.R b/R/mod_mappingColumn.R index a08d2f29..b9b7ea25 100644 --- a/R/mod_mappingColumn.R +++ b/R/mod_mappingColumn.R @@ -33,7 +33,7 @@ mappingColumnUI <- function(id, meta, data, mapping=NULL){ col_meta <- meta %>% filter(.data$type=="column") # Exactly one column mapping provided - stopifnot(nrow(col_meta)==1) + stopifnot(msg = nrow(col_meta)==1) col_ui[[1]] <- mappingSelectUI( ns(col_meta$text_key), diff --git a/inst/www/index.css b/inst/www/index.css index f1226335..9dbe0bb9 100644 --- a/inst/www/index.css +++ b/inst/www/index.css @@ -135,7 +135,7 @@ table.metatable.dataTable tr > td:last-of-type, table.metatable.trdataTable tr > color: #999; } -.chart-nav div:last-child::before{ +.chart-nav div.domain::before{ content: "/"; } @@ -151,3 +151,10 @@ table.metatable.dataTable tr > td:last-of-type, table.metatable.trdataTable tr > background-color: #d1ecf1; border:1px solid #bee5eb; } + +/* Right align chart status */ +div.chart-header div.status{ + float:right; + cursor:help +} + From ae5a37dd2c3b3d903033ac6242724d4f876cfdfa Mon Sep 17 00:00:00 2001 From: Spencer Childress Date: Fri, 24 Jun 2022 11:07:55 -0400 Subject: [PATCH 09/27] fix #692: add app-level settings --- R/app_startup.R | 3 +- R/mod_homeTab.R | 50 ++++---------- R/mod_safetyGraphicsServer.R | 14 +++- R/mod_safetyGraphicsUI.R | 6 +- R/safetyGraphicsApp.R | 64 ++++++++++++++---- README.md | 2 +- docs/index.html | 2 +- .../noun_heart_rate_210541_ec5d57.png | Bin .../safetyGraphicsHex.png | Bin inst/resources/safetyGraphicsHomeTab.html | 24 +++++++ .../safetyHex.R | 4 +- 11 files changed, 108 insertions(+), 61 deletions(-) rename inst/{safetyGraphicsHex => resources}/noun_heart_rate_210541_ec5d57.png (100%) rename inst/{safetyGraphicsHex => resources}/safetyGraphicsHex.png (100%) create mode 100644 inst/resources/safetyGraphicsHomeTab.html rename inst/{safetyGraphicsHex => resources}/safetyHex.R (65%) diff --git a/R/app_startup.R b/R/app_startup.R index 0f23cc26..aa586860 100644 --- a/R/app_startup.R +++ b/R/app_startup.R @@ -9,7 +9,6 @@ #' @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. #' @param filterDomain domain used for the data/filter tab. Demographics ("`dm`") is used by default. Using a domain that is not one record per participant is not recommended. #' @param chartSettingsPaths path(s) where customization functions are saved relative to your working directory. All charts can have initialization (e.g. myChart_Init.R) and static charts can have charting functions (e.g. myGraphic_Chart.R). All R files in this folder are sourced and files with the correct naming convention are linked to the chart. See the Custom Charts vignette for more details. -#' #' #' @return List of elements for used to initialize the shiny app with the following parameters #' \itemize{ @@ -85,4 +84,4 @@ app_startup<-function(domainData=NULL, meta=NULL, charts=NULL, mapping=NULL, aut ) return(config) -} \ No newline at end of file +} diff --git a/R/mod_homeTab.R b/R/mod_homeTab.R index 06f83ede..d942bd4e 100644 --- a/R/mod_homeTab.R +++ b/R/mod_homeTab.R @@ -4,11 +4,11 @@ #' #' @export -homeTabUI <- function(id){ +homeTabUI <- function(id) { ns <- NS(id) fluidRow( - column(width=8, style='font-size:20px', uiOutput(outputId = ns("about"))), - column(width=4, imageOutput(outputId = ns("hex"))) + column(width=9, style='font-size:20px', uiOutput(outputId = ns("about"))), + column(width=3, imageOutput(outputId = ns("hex"))) ) } @@ -20,40 +20,20 @@ homeTabUI <- function(id){ #' #' @export -homeTab <- function(input, output, session){ +homeTab <- function(input, output, session, config) { ns <- session$ns - output$about <- renderUI({ - HTML(' -

Welcome to the Safety Graphics Shiny App

-

- The Safety Graphics Shiny app is an interactive tool for evaluating clinical trial safety using a flexible data pipeline. - This application and corresponding {safetyGraphics} R package have been developed as part of the Interactive Safety Graphics (ISG) workstream of the ASA Biopharm-DIA Safety Working Group. -

- -

Using the app

-

- Detailed instructions about using the app can be found in our vignette. - In short, the user will initialize the app with their data, adjust settings as needed, and view the interactive charts. - Finally, the user may export a self-contained, fully reproducible snapshot of the charts that can be easily shared with others. -

-

Charts

-

- The app is built to support a wide variety of chart types including static plots (e.g. from {ggplot2}), shiny modules, {htmlwidgets} and even static outputs like RTFs. - Several pre-configured charts are included in the companion {safetyCharts} R Package, and are available by default in the app. - Other charts can be added using the process descibed in this vignette. -

- -

- For more information about {safetyGraphics}, please visit our GitHub repository. - We also welcome your suggestions in our issue tracker. -

- ') + output$about <- renderUI({ + HTML(readLines(config$homeTabPath)) }) - - output$hex <- renderImage({ - list( - src = system.file("safetyGraphicsHex/safetyGraphicsHex.png", package = "safetyGraphics"), width="60%") - }, deleteFile = FALSE + + output$hex <- renderImage( + { + list( + src = config$hexPath, + width = "100%" + ) + }, + deleteFile = FALSE ) } diff --git a/R/mod_safetyGraphicsServer.R b/R/mod_safetyGraphicsServer.R index 0d7e4b85..2206fcb1 100644 --- a/R/mod_safetyGraphicsServer.R +++ b/R/mod_safetyGraphicsServer.R @@ -18,7 +18,17 @@ #' #' @export -safetyGraphicsServer <- function(input, output, session, meta, mapping, domainData, charts, filterDomain){ +safetyGraphicsServer <- function( + input, + output, + session, + meta, + mapping, + domainData, + charts, + filterDomain, + config +) { #Initialize modules current_mapping<-callModule(mappingTab, "mapping", meta, domainData) @@ -31,7 +41,7 @@ safetyGraphicsServer <- function(input, output, session, meta, mapping, domainDa current_mapping=current_mapping ) - callModule(homeTab, "home") + callModule(homeTab, "home", config) #Initialize Chart UI - Adds subtabs to chart menu - this initializes initializes chart UIs charts %>% purrr::map(~chartsNav(.x,session$ns)) diff --git a/R/mod_safetyGraphicsUI.R b/R/mod_safetyGraphicsUI.R index 523b0a22..c6f7d510 100644 --- a/R/mod_safetyGraphicsUI.R +++ b/R/mod_safetyGraphicsUI.R @@ -11,7 +11,7 @@ #' #' @export -safetyGraphicsUI <- function(id, meta, domainData, mapping, standards){ +safetyGraphicsUI <- function(id, meta, domainData, mapping, standards, config) { ns<-NS(id) #read css from package @@ -50,9 +50,9 @@ safetyGraphicsUI <- function(id, meta, domainData, mapping, standards){ ) ), navbarPage( - "safetyGraphics", + config$appName, id=ns("safetyGraphicsApp"), - tabPanel("Home", icon=icon("home"),homeTabUI(ns("home"))), + tabPanel("Home", icon=icon("home"), homeTabUI(ns("home"))), tabPanel("Mapping", icon=icon("map"), mappingTabUI(ns("mapping"), meta, domainData, mapping, standards)), tabPanel("Filtering", icon=icon("filter"), filterTabUI(ns("filter"))), navbarMenu('Charts', icon=icon("chart-bar")), diff --git a/R/safetyGraphicsApp.R b/R/safetyGraphicsApp.R index 9ba1a102..723cc7f6 100644 --- a/R/safetyGraphicsApp.R +++ b/R/safetyGraphicsApp.R @@ -15,25 +15,58 @@ #' @export safetyGraphicsApp <- function( - domainData=list( - labs=safetyData::adam_adlbc, - aes=safetyData::adam_adae, - dm=safetyData::adam_adsl + domainData = list( + labs = safetyData::adam_adlbc, + aes = safetyData::adam_adae, + dm = safetyData::adam_adsl ), meta = NULL, - charts=NULL, - mapping=NULL, - autoMapping=TRUE, - filterDomain="dm", + charts = NULL, + mapping = NULL, + autoMapping = TRUE, + filterDomain = "dm", chartSettingsPaths = NULL, - runNow = TRUE + runNow = TRUE, + appName = 'safetyGraphics', + hexPath = system.file("resources/safetyGraphicsHex.png", package = "safetyGraphics"), + homeTabPath = system.file('resources/safetyGraphicsHomeTab.html', package = 'safetyGraphics'), + launchBrowser = NULL ){ message("Initializing safetyGraphicsApp") - config <- app_startup(domainData, meta, charts, mapping, autoMapping, filterDomain, chartSettingsPaths) + + if (!is.character(appName)) + appName <- 'safetyGraphics' + + if (!is.character(hexPath) || !file.exists(hexPath)) + hexPath <- system.file("resources/safetyGraphicsHex.png", package = "safetyGraphics") + + if (!is.character(homeTabPath) || !file.exists(homeTabPath)) + homeTabPath <- system.file('resources/safetyGraphicsHomeTab.html', package = 'safetyGraphics') + + config <- app_startup( + domainData, + meta, + charts, + mapping, + autoMapping, + filterDomain, + chartSettingsPaths + ) + config$appName <- appName + config$hexPath <- hexPath + config$homeTabPath <- homeTabPath + config$launchBrowser <- launchBrowser app <- shinyApp( - ui = safetyGraphicsUI("sg",config$meta, config$domainData, config$mapping, config$standards), - server = function(input,output,session){ + ui = safetyGraphicsUI( + "sg", + config$meta, + config$domainData, + config$mapping, + config$standards, + config + ), + server = function(input, output, session) { callModule( safetyGraphicsServer, "sg", @@ -41,13 +74,14 @@ safetyGraphicsApp <- function( config$mapping, config$domainData, config$charts, - config$filterDomain + config$filterDomain, + config ) } ) - + if(runNow) - runApp(app) + runApp(app, launch.browser = launchBrowser) else app } diff --git a/README.md b/README.md index 0253c04d..fcf7db55 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![R build status](https://www.github.com/safetyGraphics/safetyGraphics/workflows/R-CMD-check-main/badge.svg)](https://github.com/SafetyGraphics/safetyGraphics/actions) -# safetyGraphics: Clinical Trial Monitoring with R +# safetyGraphics: Clinical Trial Monitoring with R The {safetyGraphics} package provides a framework for evaluating of clinical trial safety in R using a flexible data pipeline. The package includes a shiny application that allows users to explore safety data using a series of interactive graphics, including the hepatic safety explorer shown below. The package has been developed as part of the Interactive Safety Graphics (ISG) workstream of the ASA Biopharm-DIA Safety Working Group. diff --git a/docs/index.html b/docs/index.html index 99eb9706..6ca3fb60 100644 --- a/docs/index.html +++ b/docs/index.html @@ -95,7 +95,7 @@

R build status

-