What is “object of type ‘closure’ is not subsettable” error in Shiny?
See also this question which covers this error in a non-Shiny context.
How to fix this:
This is a very common error in shiny apps. This most typically appears when you create an object such as a list
, data.frame
or vector
using the reactive()
function – that is, your object reacts to some kind of input. If you do this, when you refer to your object afterwards, you must include parentheses.
For example, let’s say you make a reactive data.frame
like so:
MyDF<-reactive({ code that makes a data.frame with a column called “X” })
If you then wish to refer to the data.frame
and you call it MyDF
or MyDF$X
you will get the error. Instead it should be MyDF()
or MyDF()$X
You need to use this naming convention with any object you create using reactive()
.
Why this happens:
When you make a reactive object, such as a data.frame
, using reactive()
it is tempting to think of it as just like any other non-reactive data.frame
and write your code accordingly. However, what you have created is not really a data.frame.
Rather, what you have made is instructions, in the form of a function, which tell shiny how to make the data.frame
when it is needed. When you wish to actually use this function to get the data.frame
you have to use the parenthesis, just like you would any other function in R. If you forget to use the parenthesis, R thinks you are trying to use part of a function and gives you the error. Try typing:
plot$x
at the command line and you will get the same error.
You may not see this error right when your app starts. Reactive objects have what is called “lazy” evaluation. They are not evaluated until they are needed for some output. So if your data.frame
is only used to make a plot, the data.frame
will not exist until the user sees the plot for the first time. If when the app starts up the user is required to click a button or change tabs to see the plot, the code for the data.frame
will not be evaluated until that happens. Once that happens, then and only then will shiny use the current values of the inputs to run the function that constructs the data.frame
needed to make the plot. If you have forgotten to use the parentheses, this is when shiny will give you the error. Note that if the inputs change, but the user is not looking at the plot, the function that makes the data.frame
will not be re-run until the user looks at the plot again.
R shiny ERROR: object of type 'closure' is not subsettable
Expanding on @Roland 's comment: you have a namespace collision going on. There's a function data
in base R, so if R can't find an object data
in the current environment, the function data
is referenced from the global environment. In your particular case, this happens because ui.R
and server.R
are in different environments, and, moreover, the individual function bodies all have their own environments. So the data
in fluidRow(...)
doesn't reference the data
from output$table
. You need to pass around arguments and/or dynamically construct the UI using the functions for that. See for example here.
Update for the updated question:
Replacing data
with mpg
in ui.R
fixes the problem because mpg
is defined as a dataset in the global environment (this is a side effect of library(ggplot2)
). So mpg
is (almost) always accessible and has the necessary properties. For a fairer comparison, replace mpg
in ui.R
with data
, which should bring back the old problem, because data
in the global environment refers to a function and not the data frame you're trying to manipulate.
Super Update with more general solution for dynamically defining and loading selection elements for each dataset:
The server code loops through all the columns of the chosen dataframe and dynamically generates a selection box for every column that has a type other than double. (Uniqueness and equality with doubles is just asking for trouble.) This avoids the scoping issues because the UI elements are created in server.R
after a call to the reactive function that loads the data.
server.R
library(shiny)
library(ggplot2)
# Define a server for the Shiny app
shinyServer(function(input, output) {
get.data <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars,
"mpg" = mpg,
"mtcars" = mtcars,
"diamonds" = diamonds)
})
# Filter my.data based on selections
output$table <- renderDataTable({
my.data <- get.data()
for(n in names(my.data)){
# avoid too many cases ...
# unique() with double is just asking for trouble
if(typeof(my.data[,n]) != "double"){
val <- eval(parse(text=paste0("input$",n)))
print(val)
if(val != "All"){
my.data <- eval(parse(text=paste0("subset(my.data,",n,"==",val,")")))
}
}
}
my.data
})
output$dyn.ui <- renderUI({
my.data <- get.data()
sel <- NULL
for(n in names(my.data)){
# avoid too many cases ...
# unique() with double is just asking for trouble
if(typeof(my.data[,n]) != "double"){
sel <- c(sel,
selectInput(n, n, choices=c("All",unique(my.data[,n])))
)
}
}
sel
})
})
ui.R
library(shiny)
# Define the overall UI
shinyUI(fluidPage(
titlePanel("Displaying tables dynamically with renderUI() and eval()"),
sidebarLayout(
sidebarPanel(h2("Selection"),
selectInput("dataset", "Dataset", c("rock", "pressure", "cars","mtcars","diamonds")),
# Create a new Row in the UI for selectInputs
uiOutput("dyn.ui")
)
,mainPanel(h2("Data"),
dataTableOutput(outputId="table")
)
)
))
R Shiny Error: Warning: Error in $: object of type 'closure' is not subsettable
The problem is that you are using df$......
inside the UI. If you define df
inside the server
function, it is not defined in the UI. So you get this error because R recognizes df
as the function provided by the 'stats' package (an object of type "closure" is a function).
Error in $: object of type 'closure' is not subsettable in a shiny app
Change the name of the reactive
function or change the name of the dataset. They both share the same name hence, the error.
library(shiny)
library(shinydashboard)
library(ggplot2)
library(plotly)
library(tidyr)
library(hrbrthemes)
Targets<-structure(list(Week = c(1, 1, 7, 7, 16, 16, 14, 14, 20, 20, 15,
15, 7, 7, 2, 2, 10, 10, 15, 15), Type = c("Cumilative target",
"Actual target", "Cumilative target", "Actual target", "Cumilative target",
"Actual target", "Cumilative target", "Actual target", "Cumilative target",
"Actual target", "Cumilative target", "Actual target", "Cumilative target",
"Actual target", "Cumilative target", "Actual target", "Cumilative target",
"Actual target", "Cumilative target", "Actual target"), Count = c(5,
7, 123, 18, 348, 33, 298, 37, 448, 52, 323, 29, 123, 18, 13,
12, 198, 8, 323, 29)), row.names = c(NA, -20L), class = c("tbl_df",
"tbl", "data.frame"))
#The ui part contains the user interface
ui <- dashboardPage(
#Contains the title
dashboardHeader(title = "Clinics Dashboard"),
dashboardSidebar(
#Contains the sidebar with the date range input
selectInput("weeks", "Select Week(s):",
choices=unique(Targets2$Week ),selected=unique(Targets2$Week ),
multiple=T)
),
#the body contains the 2 plots
dashboardBody(
#1st plot
plotlyOutput("plot")
)
)
#the server part contains all the background code that is displayed in the ui part
server <- function(input, output) {
Targets2<-reactive({
Targets2 <- subset(Targets, Targets$Week %in% input$weeks)
})
#the code for creating the 1st plot
output$plot<-renderPlotly({
p <-
ggplot(Targets2(), aes(x = Week, y = Count, fill = Type))+
geom_area(alpha = 0.6 , size = 0.5, colour = "white", stat = "identity", orientation = "x") +
theme_ipsum() +
theme(legend.position = "bottom")
p <- p+labs(title = "Figure 1: Weekly Cumulative Projected Enrollment vs Weekly Cumulative Actual Enrollment",
subtitle = "Cum Weekly Projected Enrollment/Cum Weekly Actual Enrollment")
ggplotly(p)
})
}
shinyApp(ui, server)
object of type ‘closure’ is not subsettable in R Shiny
The reason for the error is that you call the df
as df$data
, which would be correct if it was a reactiveValues
. However, df
is a reactive which returns just one object, so you should just call it with df()
.
For your issue, you could make a reactiveVal
that holds the rows that should be removed. Please note that you should tweak this a little yourself, for example add something like observeEvent(values$data, {rows_to_remove(NULL)})
so the rows_to_remove()
object is reset to NULL when the input data changes. Another approach would be to make the entire dataframe a reactiveVal
, and use observers to update it.
Working example below, hope this helps!
library(shiny)
library(DT)
shinyApp(
ui <- fluidPage(DT::dataTableOutput("data")),
server <- function(input, output) {
values <- reactiveValues(data = NULL)
values$data <- as.data.frame(
cbind(c("a", "d", "b", "c", "e", "f"),
c(1463, 159, 54, 52, 52, 220),
c(0.7315, 0.0795, 0.027, 0.026, 0.026, 0.11)
)
)
shinyInput <- function(FUN, len, id, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))
}
inputs
}
rows_to_remove <- reactiveVal()
df <- reactive({
data = data.frame(
Delete = shinyInput(actionButton, nrow(values$data), 'button_', label = "Remove", onclick = 'Shiny.onInputChange(\"select_button\", this.id)'),
as.data.frame(values$data),
stringsAsFactors = FALSE,
row.names = 1:nrow(values$data)
)
data[!rownames(data) %in% rows_to_remove(), ]
})
output$data <- DT::renderDataTable(
df(), server = FALSE, escape = FALSE, selection = 'none'
)
observeEvent(input$select_button, {
selectedRow <- as.numeric(strsplit(input$select_button, "_")[[1]][2])
rows_to_remove(c(rows_to_remove(),selectedRow)) # update the rows to remove
})
}
)
Error in $: object of type 'closure' is not subsettable shiny R
You need to render
the datatable
. Also, your reactiveValues
need to be defined properly. Try this
library(shiny)
library(shinydashboard)
library(DT)
Create_DT <- function(dataSource){
datatable(
dataSource,
rownames = FALSE,
selection = 'none',
class = 'cell-border stripe',
extensions = 'Buttons',
options = list(
buttons = list('copy', 'print', list(extend = 'collection',buttons = c('csv', 'excel', 'pdf'),text = 'Download')),
dom = 'Bfrtip',
info = FALSE,
lengthChange = FALSE,
paging = FALSE,
searching = FALSE,
scrollX = TRUE,
columnDefs = list(list(className = 'dt-center', targets = "_all"))
)
) %>% formatStyle(colnames(dataSource),"white-space"="nowrap")
}
Create_Box <- function(description, collapsed, ui){
box(
width = 12,
title = strong(description),
color = "primary",
collapsible = TRUE,
collapsed = collapsed,
ui
)
}
Create_DTinBox <- function(description, collapsed, ui){
Create_Box(description, collapsed, ui)
}
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
uiOutput("result")
)
)
server <- function(input, output){
rv <- reactiveValues(df = iris)
output$result <- renderUI({
Create_DTinBox(
description = "test",
collapsed = TRUE,
ui = column(8, offset = 3, renderDT(Create_DT(rv$df)))
)
})
}
shinyApp(ui, server)
R shinyFiles : Warning: Error in [: object of type 'closure' is not subsettable [No stack trace available]
The famous error message "Object of type closure
is not subsettable" indicates that you are trying to subset a function. In your case the issue is that getVolumes()
returns a function which when called returns a vector of available volumes. To solve your issue change your call of shinyDirChoose
like so:
server <- shinyServer(function(input, output) {
volumes = getVolumes()
shinyDirChoose(input, 'folder', roots = volumes())
})
Related Topics
Update Subset of Values in a Dataframe Column
How to Figure Third Friday of a Month in R
How to Print a Variable Inside a for Loop to the Console in Real Time as the Loop Is Running
How to Replace Certain Values in a Specific Rows and Columns with Na in R
Rscript Could Not Find Function
"Unpacking" a Factor List from a Data.Frame
Let Ggplot2 Histogram Show Classwise Percentages on Y Axis
Remove Duplicates Column Combinations from a Dataframe in R
Match Two Columns with Two Other Columns
Accessing Y Columns with Duplicated Names in J of X[Y, J] Merges
Ggplot and R: Two Variables Over Time
Group Vector on Conditional Sum
Text Mining R Package & Regex to Handle Replace Smart Curly Quotes