Kitswas
Kitswas

Reputation: 1197

Trouble with Reactive Dataframes in Shiny

Here's the minimal reproducible example:

# This is a Shiny web application. 

library(shiny)

# UI for application
ui <- fluidPage(
    
    # Application title
    titlePanel("A Problematic App - Part 2"),
    
    # Sidebar with two slider inputs
    sidebarLayout(
        sidebarPanel(
            sliderInput(
                "NoOfSamples",
                label = "Sample Size",
                value = 100,
                min = 10,
                max = 150,
                step = 10,
                width = "40%"
            ),
            sliderInput(
                "KeepSamples",
                label = "Samples to Keep",
                value = 50,
                min = 10,
                max = 150,
                step = 10,
                width = "40%"
            )
        ),
        
        # Shows the resulting table
        mainPanel(
            tableOutput("table1"),
            tableOutput("table2")
        )
    )
)

# Server logic
server <- function(input, output) {
    
    # Using the iris dataset
    datExpr <- as.data.frame(iris)
    
    n = reactive({
        input$NoOfSamples
    })
    datExpr0 <- reactive({
        datExpr[1:n(), ]
    })
    output$table1 <- renderTable({
        datExpr0()
    })
    # Displays the first table correctly if the rest is commented out
    keepSamples = reactive({
        input$KeepSamples
    })
    datExpr <- reactive({
        datExpr0()[keepSamples(),]
    })
    output$table2 <- renderTable({
        datExpr()
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

I have created live examples for demonstration.

The error is object of type 'closure' is not subsettable. While many questions (and answers) regarding this error exist, I am yet to find any explaining the behaviour demonstrated above.

Why does this happen?

The normal (script-equivalent) works as expected.

datExpr <- as.data.frame(iris)
n = 50
datExpr0 <- datExpr[1:n, ]
datExpr0
keepSamples = 10
datExpr <- datExpr0[keepSamples,]
datExpr

Is there a way to achieve what the normal script does in the shiny app?

Upvotes: 1

Views: 109

Answers (1)

stefan
stefan

Reputation: 125537

The issue is that you have both a dataframe and a reactive in your app called datExpr. Simply rename one of both (I decided for the reactive).

EDIT There is of course nothing special about that in shiny.

A simple example to illustrate the issue:

datExpr <- iris
datExpr <- function() {}
datExpr[1:2]
#> Error in datExpr[1:2]: object of type 'closure' is not subsettable

And you see that we get the famous object of type 'closure' is not subsettable error too. The general issue or lesson is that in R you can't have two different objects with the same name at the same time.

# This is a Shiny web application. 

library(shiny)

# UI for application
ui <- fluidPage(
  
  # Application title
  titlePanel("A Problematic App - Part 2"),
  
  # Sidebar with two slider inputs
  sidebarLayout(
    sidebarPanel(
      sliderInput(
        "NoOfSamples",
        label = "Sample Size",
        value = 100,
        min = 10,
        max = 150,
        step = 10,
        width = "40%"
      ),
      sliderInput(
        "KeepSamples",
        label = "Samples to Keep",
        value = 50,
        min = 10,
        max = 150,
        step = 10,
        width = "40%"
      )
    ),
    
    # Shows the resulting table
    mainPanel(
      tableOutput("table1"),
      tableOutput("table2")
    )
  )
)

# Server logic
server <- function(input, output) {
  
  # Using the iris dataset
  datExpr <- as.data.frame(iris)
  
  n = reactive({
    input$NoOfSamples
  })
  datExpr0 <- reactive({
    datExpr[1:n(), ]
  })
  output$table1 <- renderTable({
    datExpr0()
  })
  # Displays the first table correctly if the rest is commented out
  keepSamples = reactive({
    input$KeepSamples
  })
  datExpr1 <- reactive({
    datExpr0()[keepSamples(),]
  })
  output$table2 <- renderTable({
    datExpr1()
  })
}

# Run the application 
shinyApp(ui = ui, server = server)
#> 
#> Listening on http://127.0.0.1:3648

Upvotes: 4

Related Questions