Run Render.ui logic only after file has been uploaded

Viewed 45

I am trying to run a shiny app with several scripted functions attached. I have a sidebar select input that accesses a variable which is only created after a file is uploaded and the "db_prep" R script is processed. The "db_prep" R script also combines elements of the "full_db" that is first loaded. I have tried to use renderUI to solve this problem but I cant identify where I am going wrong. Ideally, I would like to run the app, upload my file and then run my functions on the uploaded file and full_db to generate the output in the next boxplot tab.

Here is the ui:


#compiled db
full_db <- read.csv("./full_db.csv", header = TRUE, sep = ",", stringsAsFactors = FALSE)


 
# ui ----

ui <- fluidPage(
  theme = shinytheme("superhero"),
  titlePanel("Title"),
  tabsetPanel(type = "tabs",
              tabPanel("File Upload",
                       
                       # Sidebar layout with input and output definitions ----
                       sidebarLayout(
                         
                         # Sidebar panel for inputs ----
                         sidebarPanel(
                           
                           # Input: Select a file ----
                           fileInput("file1", "Choose CSV File",
                                     multiple = FALSE,
                                     accept = c("text/csv",
                                                "text/comma-separated-values,text/plain",
                                                ".csv")),
                           
                           # Horizontal line ----
                           tags$hr(),
                           
                           # Input: Checkbox if file has header ----
                           checkboxInput("header", "Header", TRUE),
                           
                           # Input: Select separator ----
                           radioButtons("sep", "Separator",
                                        choices = c(Comma = ",",
                                                    Semicolon = ";",
                                                    Tab = "\t"),
                                        selected = ","),
                           
                           # Input: Select quotes ----
                           radioButtons("quote", "Quote",
                                        choices = c(None = "",
                                                    "Double Quote" = '"',
                                                    "Single Quote" = "'"),
                                        selected = '"'),
                           
                           # Horizontal line ----
                           tags$hr(),
                           
                           # Input: Select number of rows to display ----
                           radioButtons("disp", "Display",
                                        choices = c(Head = "head",
                                                    All = "all"),
                                        selected = "head")
                           
                         ),
                         
                         # Main panel for displaying outputs ----
                         mainPanel(
                           
                           # Output: Data file ----
                           tableOutput("contents")
                           
                         )
                       )  
              ),
              
              uiOutput("moreControls"),
              
              
              # Main panel for displaying outputs ----
              mainPanel(
                h1("Actions"),
                plotOutput("plot", width = "100%"))
  ))



Server:

# server ----
# Define server logic to plot various variables against 
server <- function(input, output, session) {
  
  #server logic for file upload tab
  output$contents <- renderTable({
    
    # input$file1 will be NULL initially. After the user selects
    # and uploads a file, head of that data file by default,
    # or all rows if selected, will be shown.
    
    req(input$file1)
    
    # when reading semicolon separated files,
    # having a comma separator causes `read.csv` to error
    tryCatch(
      {
        df_x <- read.csv(input$file1$datapath,
                         header = input$header,
                         sep = input$sep,
                         quote = input$quote)
        if(is.null(input$file1)){
          return(NULL)
        }
      },
      error = function(e) {
        # return a safeError if a parsing error occurs
        stop(safeError(e))
      }
    )
    
    if(input$disp == "head") {
      return(head(df_x))
    }
    else {
      return(df_x)
    }
    
  })
  
  
  
  #server logic for boxplot tab
  #required scripts & functions
  source("db_prep.R")
  source("box_75_test.R")
  source("box_80_test.R")
  source("box_85_test.R")
  source("box_90_test.R")
  source("box_95_test.R")
  
  
  output$moreControls <- renderUI({
    if(is.null(input$file1())) return()
    tabPanel("Boxplot",
             sidebarPanel("output.fileUploaded", 
                          selectInput("variable", "Action:", unique(qc$Action)),
                          sliderInput("quantile", "Quantile Range:",
                                      min = 75, max = 95, value = c(85), step = 5
                          )
             ))
  })
  
  
  
  # reprex ----
  s_75 <- function(var) box_75_test(var) 
  s_80 <- function(var) box_80_test(var) 
  s_85 <- function(var) box_85_test(var) 
  s_90 <- function(var) box_90_test(var)
  s_95 <- function(var) box_95_test(var) 
  
  fn <- reactive(get(paste0("s_", input$quantile)))
  output$plot <-  renderPlot(fn()(input$variable), height = 800, width = 800)
  #    ^^^ note the reactive value goes fn()(var)
  
  
}

shinyApp(ui, server)

1 Answers

The problem I was having was due to calling the source code which was also dependent on the creation of the data frame that could only be built after a csv file was uploaded. Initially, I was only able to create a data frame as an object after the shiny session had ended but I was able to fix this by wrapping my source files and functions in an observeEvent handler like this:

  observeEvent(input$file1, {
    req(df_x)
    source("db_prep.R")
      # reprex ----
  s_75 <- function(var) box_75(var) 
  s_80 <- function(var) box_80(var) 
  s_85 <- function(var) box_85(var) 
  s_90 <- function(var) box_90(var)
  s_95 <- function(var) box_95(var) 
  
    fn <- reactive(get(paste0("s_", input$quantile)))
  output$plot <-  renderPlot(fn()(input$variable), height = 800, width = 800)

There is probably a more elegant way to achieve this but hey it works.

Related