【问题标题】:R shiny passing reactive to selectInput choicesR闪亮将反应传递给selectInput选项
【发布时间】:2014-02-23 06:46:44
【问题描述】:

在一个闪亮的应用程序(由 RStudio)中,在 服务器 端,我有一个反应式,它通过解析 textInput 的内容返回变量列表。然后在selectInput 和/或updateSelectInput 中使用变量列表。

我无法让它工作。有什么建议吗?

我做了两次尝试。第一种方法是将反应式outVar 直接用于selectInput。第二种方法是在updateSelectInput 中使用反应式outVar。两者都不起作用。

服务器.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")
  )
)

不久前,我在shiny-discuss 上发布了同样的问题,但它引起的兴趣不大,所以我再次问,抱歉,https://groups.google.com/forum/#!topic/shiny-discuss/e0MgmMskfWo

编辑 1

@Ramnath 已经发布了一个似乎可行的解决方案,由他表示为 Edit 2。但是该解决方案不能解决问题,因为textinputui 一侧,而不是在我的问题中的server 一侧。如果我将 Ramnath 的第二次编辑的 textinput 移动到 server 一侧,问题又会出现,即:什么都没有显示并且 RStudio 崩溃。我发现将input$text 包裹在as.character 中会使问题消失。

编辑 2

在进一步的讨论中,Ramnath 向我展示了当服务器尝试在 textinput 返回其参数之前应用动态函数 outVar 时出现问题。解决方法是先检查is.null(input$inBody)是否存在。

检查参数是否存在是构建闪亮应用的关键方面,那我为什么没有想到呢?好吧,我做到了,但我一定做错了什么!考虑到我在这个问题上花费的时间,这是一次痛苦的经历。我在代码之后展示了如何检查是否存在。

下面是 Ramnath 的代码,textinput 移到了server 一侧。它会使 RStudio 崩溃,所以不要在家里尝试。 (我用过他的符号)

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())
    })
  }
))

我通常检查存在的方式是这样的:

if (is.null(input$text) || is.na(input$text)){
  return()
} else {
  vars <- all.vars(parse(text = input$text))
  return(vars)
}

Ramnath 的代码更短:

if (!is.null(mytext)){
  mytext = input$text
  vars <- all.vars(parse(text = mytext))
  return(vars)
}

两者似乎都有效,但从现在开始我将按照 Ramnath 的方式进行操作:也许我的构造中的不平衡支架早些时候阻止了我进行检查? Ramnath 的检查更直接。

最后,我想指出一些关于我的各种调试尝试的事情。

在我的调试任务中,我发现有一个选项可以在服务器端对“输出”的优先级进行“排名”,我对此进行了探索以尝试解决我的问题,但由于问题是别处。不过,知道这一点很有趣,而且目前似乎还不太为人所知:

outputOptions(output, "textbox", priority = 1)
outputOptions(output, "variables", priority = 2)

在那个任务中,我也尝试过 try:

try(vars <- all.vars(parse(text = input$text)))

这非常接近,但仍然没有解决它。

我偶然发现的第一个解决方案是:

vars <- all.vars(parse(text = as.character(input$text)))

我想知道它为什么起作用会很有趣:是因为它使事情变慢了吗?是因为as.character“等待”input$text 为非空吗?

无论情况如何,我都非常感谢 Ramnath 的努力、耐心和指导。

【问题讨论】:

  • renderUI 用于动态变化的输入元素。在您的情况下,textInput 最好放在 UI 中,因为不涉及动态元素。
  • @ Ramnath,这是一个精简的例子:我的设置中确实有动态元素 :-)
  • 在我的问题的第一行,我写在 server 端。如果您阅读我的代码,您会发现它涵盖了所有常见情况。奇怪的是,需要在 server 一侧而不是在 ui 一侧使用 as.character 包装输入。你会认为这是一个错误吗?或者这是您所期望的功能?哦!有人投了反对票,哦,好吧......
  • 这不是错误。如果在调用all.vars 之前先检查input$inBody 是否存在,它仍然有效。所以真正重要的不是as.character。这是gist 我的意思。

标签: r shiny shiny-reactivity


【解决方案1】:

您需要在服务器端使用 renderUI 来实现动态 UI。这是一个最小的例子。请注意,第二个下拉菜单是反应式的,会根据您在第一个下拉菜单中选择的数据集进行调整。如果您之前处理过闪亮,代码应该是不言自明的。

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))
    })
  }
))

编辑。另一个使用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:使用parse 的修改示例。在这个应用程序中,输入的文本公式用于使用变量列表动态填充下面的下拉菜单。

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())
    })
  }
))

【讨论】:

  • 感谢 Ramnath,我认为我的问题有点不同。我已经成功地在另一个应用程序中使用names() 完成了您在此处所做的事情。但在这里我试图将outVar() 传递给selectInput(),其中outVar() 输出一个反应列表。这可能是outVar() 的问题,但我看不出是什么,或者是事件序列中的时间问题。也许这也是一个愚蠢的错误。你在我的代码中看到什么问题吗?我需要明确说明names() 还是get()?谢谢!
  • 如果我在outVar() 的顶部写上return(list("a","b")),那么它可以工作。但是如果我保留上面给出的代码并在控制台中查看,那么str(outVar()) 返回的正是str(list("a","b")) 返回的内容(从视觉上讲),所以我认为我的问题是时间问题。 outVar() 尚未准备好 selectInput() 需要 choices,这可能是问题吗?
  • AFAIK,如果您需要动态 UI 元素,您需要使用 renderUIupdateSelectInput 方法。这克服了您所指的时间问题。
  • 感谢 Ramnath,我上面的代码有一个 updateSelectInput 方法,但它不起作用。任何想法?谢谢!
  • 我认为我遇到的问题与步骤顺序有关,我尝试设置outputOptions(output, "inBody", 1)outputOptions(output, "inVar", 2)希望updateSelectInput有耐心等待outVar()准备好,但这没有区别,所以问题可能出在其他地方。你能用parse而不是已知列表做一个例子吗?感谢您的尝试!
【解决方案2】:

据我所知,问题在于input$inBody 没有检索到character,即使selectInput 函数被赋予character 作为值,即value = "a+b+c"。因此,解决方案是将input$inBody 包装在as.character

以下作品:

observe 方法与updateSelectInput

observe({
     input$inBody
     vars <- all.vars(parse(text=as.character(input$inBody)))
     vars <- as.list(vars)
     updateSelectInput(session = session, inputId = "inVar", choices = vars)
})

reactive 方法与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())
})

编辑:我已根据 Ramnath 的反馈对我的问题进行了解释,并对其进行了编辑。 Ramnath 已经解释了这个问题并提供了一个更好的解决方案,我将其作为我的问题的编辑。我会把这个答案记录下来。

【讨论】:

    【解决方案3】:

    服务器.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")
    

    【讨论】:

      猜你喜欢
      • 2015-05-12
      • 2021-01-04
      • 2014-01-23
      • 2014-12-03
      • 2015-05-07
      • 2021-06-18
      • 2016-06-27
      • 1970-01-01
      相关资源
      最近更新 更多