tutorial - R brillante pasando reactivo para seleccionar opciones de entrada
shiny app r tutorial (3)
servidor.R
### This will create the dynamic dropdown list ###
output$carControls <- renderUI({
selectInput("cars", "Choose cars", rownames(mtcars))
})
## End dynamic drop down list ###
## Display selected results ##
txt <- reactive({ input$cars })
output$selectedText <- renderText({ paste("you selected: ", txt() ,sep="") })
## End Display selected results ##
ui.R
uiOutput("carControls"),
br(),
textOutput("selectedText")
En una aplicación brillante (por RStudio), en el lado del servidor , tengo un reactivo que devuelve una lista de variables mediante el análisis del contenido de una entrada de texto. La lista de variables se usa luego en selectInput
y / o updateSelectInput
.
No puedo hacer que funcione. ¿Alguna sugerencia?
He hecho dos intentos. El primer enfoque es usar el outVar
reactivo directamente en selectInput
. El segundo enfoque es usar el outVar
reactivo en updateSelectInput
. Ninguno de los dos funciona
servidor.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")
)
)
Hace poco, publiqué la misma pregunta en shiny-discuss, pero ha generado poco interés, así que vuelvo a preguntar, con disculpas, https://groups.google.com/forum/#!topic/shiny-discuss/e0MgmMskfWo
Editar 1
@Ramnath ha publicado amablemente una solución que parece funcionar, denotada Edit 2 por él. Pero esa solución no soluciona el problema porque la entrada de textinput
está en el lado ui
lugar de en el lado del server
ya que está en mi problema. Si muevo la textinput
de textinput
de la segunda edición de Ramnath al lado del server
, el problema vuelve a surgir, es decir: nada se muestra y RStudio se cuelga. Descubrí que envolver input$text
en as.character
hace que el problema desaparezca.
Editar 2
En una discusión adicional, Ramnath me ha mostrado que el problema surge cuando el servidor intenta aplicar la función dinámica outVar
antes de que sus argumentos hayan sido devueltos por la textinput
de textinput
. La solución es verificar primero si is.null(input$inBody)
existe.
Verificar la existencia de argumentos es un aspecto crucial de la creación de una aplicación brillante , entonces, ¿por qué no pensé en eso? Bueno, lo hice, pero debo haber hecho algo mal. Considerando la cantidad de tiempo que gasté en el problema, es una experiencia amarga. Muestro después del código cómo verificar la existencia.
Debajo está el código de Ramnath con textinput
movido al lado del server
. Bloquea RStudio así que no lo intentes en casa. (He usado su notación)
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())
})
}
))
La forma en que suelo verificar la existencia es así:
if (is.null(input$text) || is.na(input$text)){
return()
} else {
vars <- all.vars(parse(text = input$text))
return(vars)
}
El código de Ramnath es más corto:
if (!is.null(mytext)){
mytext = input$text
vars <- all.vars(parse(text = mytext))
return(vars)
}
Ambos parecen funcionar, pero lo haré de la manera de Ramnath a partir de ahora: ¿quizás un soporte desequilibrado en mi construcción me había impedido anteriormente hacer que el cheque funcionara? El control de Ramnath es más directo.
Por último, me gustaría señalar un par de cosas sobre mis diversos intentos de depuración.
En mi búsqueda de depuración, descubrí que hay una opción para "clasificar" la prioridad de "resultados" en el lado del servidor, que exploré en un intento de resolver mi problema, pero no funcionó ya que el problema estaba en otra parte. Aún así, es interesante saber y parece no ser muy conocido en este momento:
outputOptions(output, "textbox", priority = 1)
outputOptions(output, "variables", priority = 2)
En esa búsqueda, también intenté try
:
try(vars <- all.vars(parse(text = input$text)))
Eso estuvo muy cerca, pero aun así no lo solucionó.
La primera solución con la que tropecé fue:
vars <- all.vars(parse(text = as.character(input$text)))
Supongo que sería interesante saber por qué funcionó: ¿es porque ralentiza bastante las cosas? ¿es porque as.character
"espera" que input$text
de input$text
sea no nulo?
Cualquiera que sea el caso, estoy extremadamente agradecido con Ramnath por su esfuerzo, paciencia y guía.
Por lo que puedo decir, el problema es que input$inBody
no recupera un character
aunque la función selectInput
recibe un character
como valor, es decir, value = "a+b+c"
. La solución, por lo tanto, es ajustar la input$inBody
en un carácter as.character
Los siguientes trabajos:
El enfoque de observe
con updateSelectInput
:
observe({
input$inBody
vars <- all.vars(parse(text=as.character(input$inBody)))
vars <- as.list(vars)
updateSelectInput(session = session, inputId = "inVar", choices = vars)
})
El enfoque reactive
con selectInput
:
outVar <- reactive({
vars <- all.vars(parse(text=as.character(input$inBody)))
vars <- as.list(vars)
return(vars)
})
output$inVar2 <- renderUI({
selectInput(inputId = "inVar2", label = h4("Select:"), choices = outVar())
})
Editar: he editado mi pregunta con una explicación basada en los comentarios de Ramnath. Ramnath explicó el problema y proporcionó una mejor solución, que doy como una edición de mi pregunta. Guardaré esta respuesta, pero no merece los votos.
renderUI
usar renderUI
en el lado del servidor para IU dinámicas. Aquí hay un ejemplo mínimo. Tenga en cuenta que el segundo menú desplegable es reactivo y se ajusta al conjunto de datos que elija en el primero. El código debería explicarse por sí mismo si ya has tratado con brillo antes.
runApp(list(
ui = bootstrapPage(
selectInput(''dataset'', ''Choose Dataset'', c(''mtcars'', ''iris'')),
uiOutput(''columns'')
),
server = function(input, output){
output$columns = renderUI({
mydata = get(input$dataset)
selectInput(''columns2'', ''Columns'', names(mydata))
})
}
))
EDITAR. Otra solución usando updateSelectInput
runApp(list(
ui = bootstrapPage(
selectInput(''dataset'', ''Choose Dataset'', c(''mtcars'', ''iris'')),
selectInput(''columns'', ''Columns'', "")
),
server = function(input, output, session){
outVar = reactive({
mydata = get(input$dataset)
names(mydata)
})
observe({
updateSelectInput(session, "columns",
choices = outVar()
)})
}
))
EDIT2: Ejemplo modificado usando parse
. En esta aplicación, la fórmula de texto ingresada se usa para rellenar dinámicamente el menú desplegable a continuación con la lista de variables.
library(shiny)
runApp(list(
ui = bootstrapPage(
textInput("text", "Enter Formula", "a=b+c"),
uiOutput(''variables'')
),
server = function(input, output){
outVar <- reactive({
vars <- all.vars(parse(text = input$text))
vars <- as.list(vars)
return(vars)
})
output$variables = renderUI({
selectInput(''variables2'', ''Variables'', outVar())
})
}
))