Simple Reporter

Simple Reporter is a shiny module for capturing app views during the session, and eventually downloading a report document. The Simple Reporter module consists of two separate modules one for each of the two buttons, Add Card and Download Report buttons modules.

The implementation should consist of 4 steps:

  1. Add modules user interface to the user interface of the app.
  2. Initialize Reporter instance.
  3. Create the Report Card function with two optional arguments: card and comment. This function must return a ReportCard object. The function should build the Card step by step and assuming it is empty at the beginning, the optional comment argument is a string provided by the user when the card is added. If the comment argument is not specified then it is added automatically at the end of the Card. If the card argument is added then the ReportCard instance is automatically created for the user otherwise the function should create the card itself. This part requires the developer to use their imagination as to what the document page should look like.
  4. Invoke the servers with the reporter instance and the function to create the report card instance.

For clarity, in the app below the code added to introduce the reporter is wrapped in the ### REPORTER code blocks.

First, load the required packages:

library(shiny)
library(teal.reporter)
library(ggplot2)
library(rtables)

Simple Reporter shiny app with separate modules for each button:

ui <- fluidPage(
  titlePanel(""),
  sidebarLayout(
    sidebarPanel(
      uiOutput("encoding")
    ),
    mainPanel(
      ### REPORTER
      shiny::tags$div(
        teal.reporter::add_card_button_ui("addReportCard"),
        teal.reporter::download_report_button_ui("downloadButton"),
        teal.reporter::reset_report_button_ui("resetButton")
      ),
      ###
      shiny::tags$br(),
      tabsetPanel(
        id = "tabs",
        tabPanel("Plot", plotOutput("dist_plot")),
        tabPanel("Table", verbatimTextOutput("table"))
      )
    )
  )
)

server <- function(input, output, session) {
  output$encoding <- renderUI({
    if (input$tabs == "Plot") {
      sliderInput(
        "binwidth",
        "binwidth",
        min = 2,
        max = 10,
        value = 8
      )
    } else {
      selectInput(
        "stat",
        label = "Statistic",
        choices = c("mean", "median", "sd"),
        "mean"
      )
    }
  })

  plot <- reactive({
    req(input$binwidth)
    x <- mtcars$mpg
    ggplot2::ggplot(data = mtcars, ggplot2::aes(x = mpg)) +
      ggplot2::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()
  })

  ### REPORTER
  reporter <- teal.reporter::Reporter$new()
  card_fun <- function(card = ReportCard$new(), comment) {
    if (input$tabs == "Plot") {
      card$append_text("My plot", "header2")
      card$append_plot(plot())
    } else if (input$tabs == "Table") {
      card$append_text("My Table", "header2")
      card$append_table(table())
    }
    if (!comment == "") {
      card$append_text("Comment", "header3")
      card$append_text(comment)
    }
    card
  }

  teal.reporter::add_card_button_srv("addReportCard", reporter = reporter, card_fun = card_fun)
  teal.reporter::download_report_button_srv("downloadButton", reporter = reporter)
  teal.reporter::reset_report_button_srv("resetButton", reporter)
  ###
}

if (interactive()) shinyApp(ui = ui, server = server)

Simple Reporter shiny app with combined buttons modules:

ui <- fluidPage(
  titlePanel(""),
  sidebarLayout(
    sidebarPanel(
      uiOutput("encoding")
    ),
    mainPanel(
      ### REPORTER
      teal.reporter::simple_reporter_ui("simpleReporter"),
      ###
      tabsetPanel(
        id = "tabs",
        tabPanel("Plot", plotOutput("dist_plot")),
        tabPanel("Table", verbatimTextOutput("table"))
      )
    )
  )
)

server <- function(input, output, session) {
  output$encoding <- renderUI({
    if (input$tabs == "Plot") {
      sliderInput(
        "binwidth",
        "binwidth",
        min = 2,
        max = 10,
        value = 8
      )
    } else {
      selectInput(
        "stat",
        label = "Statistic",
        choices = c("mean", "median", "sd"),
        "mean"
      )
    }
  })

  plot <- reactive({
    req(input$binwidth)
    x <- mtcars$mpg
    ggplot2::ggplot(data = mtcars, ggplot2::aes(x = mpg)) +
      ggplot2::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()
  })

  ### REPORTER
  reporter <- teal.reporter::Reporter$new()
  card_fun <- function(card = ReportCard$new(), comment) {
    if (input$tabs == "Plot") {
      card$append_text("My plot", "header2")
      card$append_plot(plot())
    } else if (input$tabs == "Table") {
      card$append_text("My Table", "header2")
      card$append_table(table())
    }
    if (!comment == "") {
      card$append_text("Comment", "header3")
      card$append_text(comment)
    }
    card
  }

  teal.reporter::simple_reporter_srv("simpleReporter", reporter = reporter, card_fun = card_fun)
  ###
}

if (interactive()) shinyApp(ui = ui, server = server)