Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Simple - Load Reporter - Inbuild (#251)
closes #81 continuation of #177 linked to insightsengineering/teal#1120 Please install this teal branch when testing the code I created a new PR from the fork as I am no longer part of the insightengineering group. My work is done as a collaboration of UCB company with Roche. insightengineering developers can edit this PR. I followed a simple design, which was evaluated positively in [the discussion](#81). DONE: - New modules `report_load_srv` and `report_load_ui`; similar direct update for Previewer. - REMOVE the `Archiver` Class as we not need it for this simplified scenario. - Improve `to_list` and `from_list` `Reporter` methods - Add `set_id` and `get_id` `Reporter` methods. Optionally add id to a Report which will be compared when it is rebuilt from a list. To test it in the teal example app please download a report and then add a new module or dataset to the app and try to load it back. The report can be loaded back to teal app only with the same datasets and modules. The id is added to the downloaded file name if exists. - Improve `to_list` and `from_list` `ReportCard` methods (linked with insightsengineering/teal#1120) - Both already existing vignette apps are updated automatically. - `warning(cond)` everywhere to be consistent. We should send the error/warning to the R console when STH fails. - Add `testServer` tests for report_load_srv/report_load_ui modules. - UI tested with all 3 bootstrap versions. Points to consider: - The JSON format Report representation seems to be enough, so an Archiver is unnecessary. The DB solution to save/load seems overcomplex for the project. - No update will be required to introduce it into teal modules. Simple reporter is updated automatically and can be customized with a new teal.reporter option. - When reloading, the Report is validated by the "report_" file name prefix later by the slot name "teal Report" and optionally by ID if it is non-empty. Example Teal App (play with bootstrap versions, simple reporter modules, and add new data/module to confirm the report can not be then reloaded): ```r library(teal.modules.general) # one of c("3", "4", "5") options("teal.bs_theme" = bslib::bs_theme(version = "4")) data <- teal_data() data <- within(data, { library(nestcolor) ADSL <- teal.modules.general::rADSL }) datanames <- c("ADSL") datanames(data) <- datanames join_keys(data) <- default_cdisc_join_keys[datanames] app <- teal::init( data = data, modules = teal::modules( teal.modules.general::tm_a_regression( label = "Regression", response = teal.transform::data_extract_spec( dataname = "ADSL", select = teal.transform::select_spec( label = "Select variable:", choices = "BMRKR1", selected = "BMRKR1", multiple = FALSE, fixed = TRUE ) ), regressor = teal.transform::data_extract_spec( dataname = "ADSL", select = teal.transform::select_spec( label = "Select variables:", choices = teal.transform::variable_choices(data[["ADSL"]], c("AGE", "SEX", "RACE")), selected = "AGE", multiple = TRUE, fixed = FALSE ) ), ggplot2_args = teal.widgets::ggplot2_args( labs = list(subtitle = "Plot generated by Regression Module") ) ) ) ) runApp(app, launch.browser = TRUE) ``` Example general shiny app (play with bootstrap versions, simple reporter modules): ```r library(shiny) library(teal.reporter) library(ggplot2) library(rtables) library(DT) library(bslib) ui <- fluidPage( # please, specify specific bootstrap version and theme theme = bs_theme(version = "4"), titlePanel(""), tabsetPanel( tabPanel( "main App", tags$br(), sidebarLayout( sidebarPanel( uiOutput("encoding") ), mainPanel( tabsetPanel( id = "tabs", tabPanel("Plot", plotOutput("dist_plot")), tabPanel("Table", verbatimTextOutput("table")), tabPanel("Table DataFrame", verbatimTextOutput("table2")), tabPanel("Table DataTable", dataTableOutput("table3")) ) ) ) ), ### REPORTER tabPanel( "Previewer", reporter_previewer_ui("prev") ) ### ) ) server <- function(input, output, session) { output$encoding <- renderUI({ tagList( ### REPORTER teal.reporter::simple_reporter_ui("simple_reporter"), ### if (input$tabs == "Plot") { sliderInput( "binwidth", "binwidth", min = 2, max = 10, value = 8 ) } else if (input$tabs %in% c("Table", "Table DataFrame", "Table DataTable")) { selectInput( "stat", label = "Statistic", choices = c("mean", "median", "sd"), "mean" ) } else { NULL } ) }) plot <- reactive({ req(input$binwidth) x <- mtcars$mpg ggplot(data = mtcars, aes(x = mpg)) + geom_histogram(binwidth = input$binwidth) }) output$dist_plot <- renderPlot(plot()) table <- reactive({ req(input$stat) lyt <- basic_table() %>% split_rows_by("Month", label_pos = "visible") %>% analyze("Ozone", afun = eval(str2expression(input$stat))) build_table(lyt, airquality) }) output$table <- renderPrint(table()) table2 <- reactive({ req(input$stat) data <- aggregate( airquality[, c("Ozone"), drop = FALSE], list(Month = airquality$Month), get(input$stat), na.rm = TRUE ) colnames(data) <- c("Month", input$stat) data }) output$table2 <- renderPrint(print.data.frame(table2())) output$table3 <- renderDataTable(table2()) ### REPORTER reporter <- Reporter$new() card_fun <- function(card = ReportCard$new(), comment) { if (input$tabs == "Plot") { card$set_name("Plot Module") card$append_text("My plot", "header2") card$append_plot(plot()) card$append_rcode( paste( c( "x <- mtcars$mpg", "ggplot2::ggplot(data = mtcars, ggplot2::aes(x = mpg)) +", paste0("ggplot2::geom_histogram(binwidth = ", input$binwidth, ")") ), collapse = "\n" ), echo = TRUE, eval = FALSE ) } else if (input$tabs == "Table") { card$set_name("Table Module rtables") card$append_text("My rtables", "header2") card$append_table(table()) card$append_rcode( paste( c( "lyt <- rtables::basic_table() %>%", 'rtables::split_rows_by("Month", label_pos = "visible") %>%', paste0('rtables::analyze("Ozone", afun = ', input$stat, ")"), "rtables::build_table(lyt, airquality)" ), collapse = "\n" ), echo = TRUE, eval = FALSE ) } else if (input$tabs %in% c("Table DataFrame", "Table DataTable")) { card$set_name("Table Module DF") card$append_text("My Table DF", "header2") card$append_table(table2()) # Here r code added as a regular verbatim text card$append_text( paste0( c( 'data <- aggregate(airquality[, c("Ozone"), drop = FALSE], list(Month = airquality$Month), ', input$stat, ", na.rm = TRUE)\n", 'colnames(data) <- c("Month", ', paste0('"', input$stat, '"'), ")\n", "data" ), collapse = "" ), "verbatim" ) } if (!comment == "") { card$append_text("Comment", "header3") card$append_text(comment) } card } teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) teal.reporter::reporter_previewer_srv("prev", reporter) ### } if (interactive()) shinyApp(ui = ui, server = server) ``` --------- Signed-off-by: Maciej Nasinski <[email protected]> Co-authored-by: Dawid Kałędkowski <[email protected]> Co-authored-by: Dawid Kałędkowski <[email protected]>
- Loading branch information