I'm trying to subset data frame in Shiny app based on character input, but only after action button has been pushed. Here how this looks like in UI:
textInput("cases", "Select cases", value = ""),
actionButton("submit", "Submit", icon = icon("refresh"),
style="float:right"),
The idea is to let user choose what cases of data frame should be shown on the plot (i.e. "11,23,17,102"). In order to convert character vector into numeric, and subsequently subset data frame based on that criteria, I've tried to use next Server code:
cases <- eventReactive(input$submit, {as.numeric(unlist(strsplit(input$cases,",")))})
df <- df[cases, ]
After running application and uploading data set I get Error:invalid subscript type 'closure'
Without these lines, application works fine on whole data set. Furthermore, the same code, but with non-reactive values works fine outside Shiny environment:
cases <- "3,6,11,55,60" # example of user input
cases <- unlist(strsplit(cases,","))
cases <- as.numeric(cases)
df <- df[cases, ]
Any help on this would be appreciated.
In response to @socialscientist I am providing a wider scope of my code:
df <- read.csv(infile$datapath, header = TRUE, stringsAsFactors = FALSE)
# Subset data frame based on mode selection
mode <- input$mode
df <- df[df$Mode == mode, ]
# Take original values of wavelength as x-axis
df_x <- read.csv(infile$datapath, header = FALSE)
x_val <- as.vector(df_x[1, 11:2059])
# Remove unnecessary columns
df <- df[, 11:2059]
# Data frame cases subset based on user input
df <- eventReactive(input$submit, {
cases <- as.numeric(unlist(strsplit(input$cases,",")))
a <- df[cases(), ]
return(a)
})
# Transpose and melt data
t_df <- transpose(df)
t_df <- cbind(t(x_val), t_df)
colnames(t_df)[1] <- "wave"
final_data <- as.data.table(reshape2::melt(t_df, id='wave'))
After running this code I get an error Error in transpose: l must be a list.
I am aware that cases()
is not function anymore, and that eventReactive now is producing df()
function, but I do not know how to use it.
CodePudding user response:
I'm not certain if this is going to resolve all issues, but I'm going to infer that the code has nested observe/reactive blocks (or something else equally not-right). Here's a working example of allowing comma-separated numbers and a submit button to subset a frame.
library(shiny)
ui <- fluidPage(
textInput("cases", "Select cases", value = ""),
actionButton("submit", "Submit", icon = icon("sync")),
tableOutput("tbl")
)
server <- function(input, output, session) {
cases <- eventReactive(input$submit, {
out <- strsplit(input$cases, ",")[[1]]
out <- suppressWarnings(as.numeric(out[nzchar(out)]))
validate(
need(!anyNA(out), "Input one or more numbers separated by commas")
)
out
})
output$tbl <- renderTable({
if (length(cases())) mtcars[cases(),] else mtcars
})
}
shinyApp(ui, server)
Notes:
Error resolution: while
out[nzchar(out)]
will silently remove empty strings caused by two consecutive commas (e.g.,1,,3
) without error, the!anyNA(out)
will cause that stop cascading reactivity, instead replacing all components that usecases()
with the stringInput one or more ...
. This means that1,,3
will work without complaint, but1,a,3
will fail and be politely noisy.This example chooses to show all rows by default. If instead you want nothing shown until there is valid input in
cases
, then replace the last reactive block here with:output$tbl <- renderTable({ mtcars[cases(),] })