In a shiny app (by RStudio), on the server side, I have a reactive that returns a list of variables by parsing the content of a textInput
. The list of variables is then used in selectInput
and/or updateSelectInput
.
I can't make it work. Any suggestions?
I have made two attempts. The first approach is to use the reactive outVar
directly into selectInput
. The second approach is to use the reactive outVar
in updateSelectInput
. Neither works.
server.R
shinyServer(
function(input, output, session) {
outVar <- reactive({
vars <- all.vars(parse(text=input$inBody))
vars <- as.list(vars)
return(vars)
})
output$inBody <- renderUI({
textInput(inputId = "inBody", label = h4("Enter a function:"), value = "a+b+c")
})
output$inVar <- renderUI({ ## works but the choices are non-reactive
selectInput(inputId = "inVar", label = h4("Select variables:"), choices = list("a","b"))
})
observe({ ## doesn't work
choices <- outVar()
updateSelectInput(session = session, inputId = "inVar", choices = choices)
})
})
ui.R
shinyUI(
basicPage(
uiOutput("inBody"),
uiOutput("inVar")
)
)
A short while ago, I posted the same question at shiny-discuss, but it has generated little interest, so I'm asking again, with apologies, https://groups.google.com/forum/#!topic/shiny-discuss/e0MgmMskfWo
Edit 1
@Ramnath has kindly posted a solution that appears to work, denoted Edit 2 by him. But that solution does not address the problem because the textinput
is on the ui
side instead of on the server
side as it is in my problem. If I move the textinput
of Ramnath's second edit to the server
side, the problem crops up again, namely: nothing shows and RStudio crashes. I found that wrapping input$text
in as.character
makes the problem disappear.
Edit 2
In further discussion, Ramnath has shown me that the problem arises when the server attempts to apply the dynamic function outVar
before its arguments have been returned by textinput
. The solution is to first check whether is.null(input$inBody)
exists.
Checking for existence of arguments is a crucial aspect of building a shiny app, so why did I not think of it? Well, I did, but I must have done something wrong! Considering the amount of time I spent on the problem, it's a bitter experience. I show after the code how to check for existence.
Below is Ramnath's code with textinput
moved to the server
side. It crashes RStudio so don't try it at home. (I have used his notation)
library(shiny)
runApp(list(
ui = bootstrapPage(
uiOutput('textbox'), ## moving Ramnath's textinput to the server side
uiOutput('variables')
),
server = function(input, output){
outVar <- reactive({
vars <- all.vars(parse(text = input$text)) ## existence check needed here to prevent a crash
vars <- as.list(vars)
return(vars)
})
output$textbox = renderUI({
textInput("text", "Enter Formula", "a=b+c")
})
output$variables = renderUI({
selectInput('variables2', 'Variables', outVar())
})
}
))
The way I usually check for existence is like this:
if (is.null(input$text) || is.na(input$text)){
return()
} else {
vars <- all.vars(parse(text = input$text))
return(vars)
}
Ramnath's code is shorter:
if (!is.null(mytext)){
mytext = input$text
vars <- all.vars(parse(text = mytext))
return(vars)
}
Both seem to work, but I'll be doing it Ramnath's way from now on: maybe an unbalanced bracket in my construct had earlier prevented me to make the check work? Ramnath's check is more direct.
Lastly, I'd like to note a couple of things about my various attempts to debug.
In my debugging quest, I discovered that there is an option to "rank" the priority of "outputs" on the server side, which I explored in an attempt to solve my problem, but didn't work since the problem was elsewhere. Still, it's interesting to know and seems not very well known at this time:
outputOptions(output, "textbox", priority = 1)
outputOptions(output, "variables", priority = 2)
In that quest, I also tried try
:
try(vars <- all.vars(parse(text = input$text)))
That was pretty close, but still did not fix it.
The first solution I stumbled upon was:
vars <- all.vars(parse(text = as.character(input$text)))
I suppose it would be interesting to know why it worked: is it because it slows things down enough? is it because as.character
"waits" for input$text
to be non-null?
Whatever the case may be, I am extremely grateful to Ramnath for his effort, patience and guidance.
Question&Answers:
os