Search code examples
rshinyreactiveshiny-reactivity

Why does my Shiny app import, analyze, and display data, but not export or plot it?


I've written a shiny app to import data from a csv file, analyse it, display in a table, and then plot and export upon request.

The problem is that the app will import/analyse/display results (a df called LREdata), but when it is requested to either export or plot the results, it shows error "the LREdata doesn't exist".

The app:

ui <- fluidPage(
  titlePanel("LRE Analysis"),
  sidebarLayout(
    sidebarPanel(
      fileInput("file", "Select a file"),
    numericInput("N", "BaselineF:", 1000),
    numericInput("F", "Lowest F ratio:", 1.8)
    ),
    mainPanel(
      tabsetPanel(type = "tabs",
                  tabPanel("Data", DT::dataTableOutput("table2"),
        downloadButton("downloadData", "Download")),
tabPanel("Plot", plotOutput("plotx"))
                  
      )
       )
)
)


server <- function(input, output) {

  input_file <- reactive({
    if (is.null(input$file)) {
      return("")
    }

    read.csv(file = input$file$datapath)
  })

  output$table2 <- DT::renderDataTable({
#Analysis performs here, results in df called LREdata
   
print(LREdata)
  })

output$downloadData <- downloadHandler(
    filename = function() {
      paste(input$file, ".csv", sep = "")
    },
    content = function(file) {
      write.csv(LREdata, file, row.names = FALSE)
    }
  )

output$plotx <- renderPlot({
ggplot(LREdata, aes(x=factor(TimePeriod),y=PercentageMatches, colour = QualityMatch)) + geom_col()+ facet_grid(vars(TargetSubset), vars(Oligo))                                                     
})

}

shinyApp(ui = ui, server = server)

Solution

  • In Shiny each reactive element has its own environment, so when you generate a dataframe named LREdata in your renderDataTable() the object is not accessible to any other functions in your server side. In such cases that you want to use an object in multiple server functions you have to assign it to a reactive element. Here:

    ### Add this new reactive element after your input_file and move all your analysis from the renderDataTable here
      LREdata <- reactive({
    
      #Analysis performs here, results in df called LREdata
      LREdata
      })
    
      output$table2 <- DT::renderDataTable(LREdata())
    
    output$downloadData <- downloadHandler(
        filename = function() {
          paste(input$file, ".csv", sep = "")
        },
        content = function(file) {
          write.csv(LREdata(), file, row.names = FALSE)
        }
      )
    

    Now LREdata is defined globally and all other subsequent code can read it.