【问题标题】:R Shiny - Isolating a reactive expression that uses req() to check preconditionsR Shiny - 隔离使用 req() 检查前置条件的反应式表达式
【发布时间】:2019-11-30 03:31:57
【问题描述】:

下面的应用程序包含一个 selectInput 和两个选项 irismtcars 以及一个显示当前选择的标题。

  • 如果用户选择iris,则在标题下方呈现相应数据集的DT。
  • 如果用户选择mtcars,则标题下方不会呈现任何内容。

这是截图:

我将选定的数据集存储在反应式表达式sel_df 中。该表达式在返回相应的数据集之前检查用户是否使用req(input$dataset=='iris') 选择了虹膜:

sel_df = reactive({

    req(input$dataset=='iris')

    iris
  })

sel_df 被传递给renderDT,它呈现数据表:

output$df = renderDT({

    sel_df()

  })

然后,我使用 h3 标头、数据表和数据表的标签呈现一些 UI 以显示 selectInput 的当前值:

  output$tbl = renderUI({

    tagList(
      h3(paste0('Selected:', input$dataset)), # Header should be visible regardless of the value of input$dataset
      tags$label(class = 'control-label', style = if(!isTruthy(isolate(sel_df()))) 'display:none;', `for` = 'df', 'Data:'), # Label should only show if input$dataset == 'iris'
      DTOutput('df')
    )

  })

我希望数据表及其标签仅在 sel_df 输出数据集时可见。但是由于应用程序的结构方式,这需要output$tbl(上面的renderUI)依赖于sel_df,以便每当input$dataset == 'mtcars' 时整个UI 块都会消失。

我想要的输出要求output$tbl 仅依赖于input$dataset,因此无论input$dataset 的值如何,h3 标头始终可见。为此,我尝试使用isolate '隔离'sel_df,但output$tbl 在每次失效时仍会调用sel_df

我不确定我哪里出错了。我想我可能错误地使用了isolate,但我不知道为什么,我想知道是否有人可以解释一下。

这是完整的应用程序:

library(shiny)
library(DT)

ui <- fluidPage(
  selectInput('dataset', 'Dataset', c('iris', 'mtcars')),
  uiOutput('tbl')
)

server <- function(input, output, session) {

  sel_df = reactive({

    req(input$dataset=='iris')

    iris
  })

  output$df = renderDT({

    sel_df()

  })

  output$tbl = renderUI({

    tagList(
      h3(paste0('Selected:', input$dataset)), # Header should be visible regardless of the value of input$dataset
      tags$label(class = 'control-label', style = if(!isTruthy(isolate(sel_df()))) 'display:none;', `for` = 'df', 'Data:'), # Label should only show if input$dataset == 'iris'
      DTOutput('df')
    )

  })

}

shinyApp(ui, server)

【问题讨论】:

  • " 但 output$tbl 在每次失效时仍会调用 sel_df。"您如何跟踪它,...使用显示模式 = 展示?
  • 我只是根据output$tblinput$dataset != "iris" 完全消失这一事实中推断出来的,这意味着output$tbl 在调用sel_df 时会停止。

标签: r shiny reactive-programming


【解决方案1】:

output$tbl 依赖于input$dataset,所以自然会在每次input$dataset 的值发生变化时调用它。 sel_df() 也依赖于 input$dataset 并在它发生变化时被调用。这就是预期的样子,我不认为你的标签被调用,因为它取决于sel_df()

但是,请注意当sel_df 为NULL 时,taglist() 调用也将返回NULL。这是因为当input$dataset != "iris" 时,您的sel_df() 调用失败,因此tagList 也会失败:

如果任何给定值不真实,则通过引发 “静默”异常(Shiny 未记录,也未显示在 Shiny 应用的 UI 中)。

试试这个:

server <- function(input, output, session) {
  sel_df = reactive({
    if(input$dataset=='iris') {
      iris 
    } else {
      NULL
    }
  })

您会发现,使用 mtcars,h3() 标签会显示,但标签会根据需要隐藏。

【讨论】:

  • 是的,我知道req 会导致sel_dfinput$dataset != 'iris' 下静默失败,但是我如何在决定是否显示标签的IF 语句中检查它?我最初使用 if/else,但发现 req 更方便,因为 sel_df 也用于其他渲染函数的调用,它使我不必在每个调用中编写 req(sel_df())
  • 另外,当我检查多个条件时,我最终使用了嵌套的 if/elses,它不像 req 那样可读。
  • 你不能一边吃蛋糕一边吃蛋糕,恐怕 ;-) req 在某种程度上相当于使用 stopifnot,这就是你应该如何对待它!如何定义另一个反应式表达式来检查是否input$dataset == 'iris' 并设置一个标志,类似于我的回复中的sel_df 定义,没有req
  • 确实如此 :) 我只是想确保没有更简单的方法。我最终使用了sel_df &lt;- reactive({ #calculate value1; if(#value1 does not meet condition1) return(NULL); #calculate value2; if(#value2 does not meet condition2) return(NULL); #more calculations}) 之类的东西。感谢您的帮助!
【解决方案2】:

如果您想在sel_df() 中使用req,您可以在renderDT 中使用trycatch,这解决了@January 提到的问题,当您不选择虹膜时tagsList 失败。

您还需要修改 if 语句以使用 is.null 而不是,因为我将其用作 trycatch 中的默认 return 值。

library(shiny)
library(DT)

ui <- fluidPage(
  selectInput('dataset', 'Dataset', c('iris', 'mtcars')),
  uiOutput('tbl')
)

server <- function(input, output, session) {

  sel_df = reactive({
    req(input$dataset=='iris')
    iris
  })

  output$df = renderDT({

    out <- tryCatch(sel_df(), error = function(e) NULL)
    return(out)

  })

  output$tbl = renderUI({

    tagList(
      tags$h3(paste0('Selected:', input$dataset)), # Header should be visible regardless of the value of input$dataset
      tags$label(class = 'control-label', style = if(is.null('df')) 'display:none;', `for` = 'df', 'Data:'), # Label should only show if input$dataset == 'iris'
      DTOutput('df')
    )

  })

}

shinyApp(ui, server)

【讨论】:

  • 谢谢@RK1,我没想到会那样使用tryCatch,我投了赞成票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-19
  • 1970-01-01
  • 1970-01-01
  • 2015-08-14
  • 2016-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多