Accessing data in different parts of server() in shiny

53 Views Asked by At

I am having a problem with accessing data in different parts of my server() function. The basic structure is something like this:

server <- shinyServer(function(input, output) {

  # get the data from a file obtained from a textInput in the ui
  data <- reactive({
    req(input$file)
    file <- input$file$datapath
    # process the file and return a new dataframe

  })

  output$head <- renderTable({
    mydf <- data()
    head(mydf)
  })

  output$tail <- renderTable({
    mydf <- data()
    tail(mydf)
  })

})

I would like to avoid having to call data() twice but I haven't found a way to do that.


Edit following the comment by @KentJohnson

What I am trying to achieve is for the user to select a file to open, using textInput, and after the file is opened, the app should do some processing and populate the two tables in the ui. After this, the user then chooses some other actions which also require the same data.

I wanted to avoid having to call data() twice but I haven't found a way to do that. I was assuming that each call would mean reading from the file each time. The file is very large so that is my motivation.

2

There are 2 best solutions below

2
SmokeyShakers On BEST ANSWER

As @KentJohnson points out, reactive already achieves your goal. The expression that makes up data...

req(input$file)
file <- input$file$datapath
# process the file and return a new dataframe

...only runs when input$file$datapath changes. It does not rerun each time data() is called.

6
bretauv On

Putting your two tables into an observe environment makes it possible to call data() only twice, but I don't know if it will fit with what you want to do. Notice that here, I didn't put a textInput or things like that because my point was to show the observe environment. I'll let you adapt it to your situation (since you didn't put the ui part in your post):

library(shiny)

ui <- basicPage(
  fileInput("file", 
            "Import a CSV file", 
            accept = ".csv"),
  tableOutput("head"),
  tableOutput("tail")
)

server <- shinyServer(function(input, output) {

  # get the data from a file obtained from a textInput in the ui
  data <- reactive({
    req(input$file)
    inFile <- input$file
    read.csv(inFile$datapath, header = F, sep = ";")
    # process the file and return a new dataframe

  })

  observe({
    mydf <- data()
    if (is.null(mydf)){
      output$head <- renderTable({})
      output$tail <- renderTable({})
    }
    else {
      output$head <- renderTable({
        head(mydf)
      })
      output$tail <- renderTable({
        tail(mydf)
      })
    }
  })

})

shinyApp(ui, server)

Edit: I misunderstood the OP's question, see @SmokeyShakers' answer for a more appropriate answer.