0
votes

I am trying to access the data frame created in one render function into another render function.

There are two server outputs, lvi and Category, in lvi I have created Data1 data frame and Category I have created Data2 dataframe. I want to select Data2 where Data1 ID is matching.

I am following the below steps to achieve my objective but I get error "Object Data1 not found".

My UI is

ui <- fluidPage(
  # App title ----
  titlePanel("Phase1"),
  fluidPage(
    column(4,
           # Input: Select a file ----
           fileInput("file1", "Import file1")
    ) 
  ),
  fluidPage(
    column(4,
           # Input: Select a file ----
           fileInput("file2", "Import File2")
    ) 

  ),
    # Main panel for displaying outputs ----
    mainPanel( 
      # Output: Data file ----
      dataTableOutput("lvi"),
      dataTableOutput("category")
    )
  )

My server code is

server <- function(input, output) {
  output$lvi <- renderDataTable({
    req(input$file1)
    Data1 <- as.data.frame(read_excel(input$file1$datapath, sheet = "Sheet1"))    
  })

  output$category <- renderDataTable({        
    req(input$file2)        
    Data2 <- as.data.frame(read_excel(input$file2$datapath, sheet = "Sheet1"))
    Data2 <- Data2[,c(2,8)]
    Data2 <- Data2[Data1$ID == "ID001",]        
  })        
}
shinyApp(ui, server)
1

1 Answers

3
votes

Once a reactive block is done executing, all elements within it go away, like a function. The only thing that survives is what is "returned" from that block, which is typically either the last expression in the block (or, when in a real function, something in return(...)). If you think of reactive (and observe) blocks as "functions", you may realize that the only thing that something outside of the function knows of what goes on inside the function is if the function explicitly returns it somehow.

With that in mind, the way you get to a frame inside one render/reactive block is to not calculate it inside that reactive block: instead, create that frame in its own data-reactive block and use it in both the render and the other render.

Try this (untested):

server <- function(input, output) {

  Data1_rx <- eventReactive(input$file1, {
    req(input$file1, file.exists(input$file1$datapath))
    as.dataframe(read_excel(input$file1$datapath, sheet = "Sheet1"))
  })

  output$lvi <- renderDataTable({ req(Data1_rx()) })

  output$category <- renderDataTable({        
    req(input$file2, file.exists(input$file2$datapath),
        Data1_rx(), "ID" %in% names(Data1_rx()))
    Data2 <- as.data.frame(read_excel(input$file2$datapath, sheet = "Sheet1"))
    Data2 <- Data2[,c(2,8)]
    Data2 <- Data2[Data1_rx()$ID == "ID001",]        
  })        
}
shinyApp(ui, server)

But since we're already going down the road of "better design" and "best practices", let's break data2 out and the data2-filtered frame as well ... you may not be using it separately now, but it's often better to separate "loading/generate frames" from "rendering into something beautiful". That way, if you need to know something about the data you loaded, you don't have to (a) reload it elsewhere, inefficient; or (b) try to rip into the internals of the shiny DataTable object and get it manually. (Both are really bad ideas.)

So a slightly better solution might start with:

server <- function(input, output) {

  Data1_rx <- eventReactive(input$file1, {
    req(input$file1, file.exists(input$file1$datapath))
    as.dataframe(read_excel(input$file1$datapath, sheet = "Sheet1"))
  })
  Data2_rx <- eventReactive(input$file2, {
    req(input$file2, file.exists(input$file2$datapath))
    dat <- as.dataframe(read_excel(input$file2$datapath, sheet = "Sheet1"))
    dat[,c(2,8)]
  })
  Data12_rx <- reactive({
    req(Data1_rx(), Data2_rx())
    Data2_rx()[ Data1_rx()$ID == "ID001", ]
  })

  output$lvi <- renderDataTable({ req(Data1_rx()); })
  output$category <- renderDataTable({ req(Data12_rx()); })
}
shinyApp(ui, server)

While this code is a little longer, it also groups "data loading/munging" together, and "render data into something beautiful" together. And if you need to look at early data or filtered data, it's all right there.

(Side note: one performance hit you might see from this is that you now have more copies of data floating around. As long you are not dealing with "large" data, this isn't a huge deal.)