闪亮的条件面板绕过多个相关的滑块

Posted

技术标签:

【中文标题】闪亮的条件面板绕过多个相关的滑块【英文标题】:Shiny conditionalpanel to bypass multiple dependent sliders 【发布时间】:2018-05-21 20:50:00 【问题描述】:

我正在构建一个相对复杂的应用程序,我希望用户拖动耦合滑块来设置某些计算的权重。这些总和应始终为 100%。我查看了this 和that,但我在反应性和隔离方面确实存在问题,并且updateslider 选项似乎适用于两个滑块。

因此,我转而提出了问题。我将向用户发送消息,如果他们不这样做,则权重需要总和为 100%,如果他们这样做,则显示示例 plotoutput。简单吧?嗯,不,因为条件不符合。查看this 和this 和this 后,我无法让它工作。

我在下面提供了一个可重现的示例来演示这个问题 - 我怀疑这是因为我对反应性和闪亮的观察者感到尴尬。

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

   # Application title
   titlePanel("testing 1 2 3"),

   # Sidebar with a slider input for number of bins 
   sidebarLayout(
      sidebarPanel(
      ),

      # Show a plot of the generated distribution
      mainPanel(
         fluidRow(

            column(width = 2,
                   offset = 0,
                   align = "center",
                   sliderInput(inputId = "sld_1",
                               label = "weight",
                               min = 0,
                               max = 1,
                               value = 0.25,
                               step = 0.05,
                               animate = TRUE)
                   ,
                   sliderInput(inputId = "sld_2",
                               label = "weight",
                               min = 0,
                               max = 1,
                               value = 0.25,
                               step = 0.05,
                               animate = TRUE)
                   ,
                   sliderInput(inputId = "sld_3",
                               label = "weight",
                               min = 0,
                               max = 1,
                               value = 0.25,
                               step = 0.05,
                               animate = TRUE)
                   ,
                   sliderInput(inputId = "sld_4",
                               label = "weight",
                               min = 0,
                               max = 1,
                               value = 0.25,
                               step = 0.05,
                               animate = TRUE)
            ) #slider columns
            ,
            column(width = 9,
                   offset = 0,
                   align = "center",
                   conditionalPanel(
                      condition = "output.myCondition == FALSE",
                      textOutput(outputId = "distPrint")
                   ) #conditional1
                   ,
                   conditionalPanel(
                      condition = "output.myCondition == TRUE",
                      plotOutput(outputId = "distPlot")
                   ) #conditional2
            ) #column
         )#fluidrow
      )
   )
)

# Define server logic required to draw a histogram
server <- function(input, output,session) 

   dister <-   reactive(
      if( !is.null(input$sld_1) &&
          !is.null(input$sld_2) &&
          !is.null(input$sld_3) &&
          !is.null(input$sld_4) &&
          sum(input$sld_1,input$sld_2,input$sld_3,input$sld_4)==1
      ) 
         rnorm(input$sld_1*1000)
       else c(0,1,2,3,4,5)
   )

   output.myCondition <- reactive(
      if( !is.null(input$sld_1) &&
          !is.null(input$sld_2) &&
          !is.null(input$sld_3) &&
          !is.null(input$sld_4) &&
          sum(input$sld_1,input$sld_2,input$sld_3,input$sld_4)==1
      ) 
              TRUE
       else FALSE
   )

   output$distPlot <- renderPlot(
      x<-dister()
      hist(x)
   )

   output$distPrint <- renderText(
      print("The weights must sum to 100%")
   )


# Run the application 
shinyApp(ui = ui, server = server)

【问题讨论】:

【参考方案1】:

这是一个稍微不同的方法,使用shinyjs 包:

我们创建了两个 div,一个用于绘图 (plotdiv),一个用于错误 (errordiv) 我们创建一个 reactiveVal 来保存分布 仅当我们的滑块发生变化并且它们总和为 1 时,observeEvent 才会更新 reactiveVal。在这种情况下,我们隐藏 errordiv,并显示 plotdiv。否则,我们会显示错误并隐藏绘图。

所以:

library(shiny)
library(shinyjs)

# Define UI for application that draws a histogram
ui <- fluidPage(

  # Application title
  titlePanel("testing 1 2 3"),
  shinyjs::useShinyjs(),

  # Sidebar with a slider input for number of bins 
  sidebarLayout(
    sidebarPanel(
    ),


    # Show a plot of the generated distribution
    mainPanel(
      fluidRow(

        column(width = 2,
               offset = 0,
               align = "center",
               sliderInput(inputId = "sld_1",
                           label = "weight",
                           min = 0,
                           max = 1,
                           value = 0.25,
                           step = 0.05,
                           animate = TRUE)
               ,
               sliderInput(inputId = "sld_2",
                           label = "weight",
                           min = 0,
                           max = 1,
                           value = 0.25,
                           step = 0.05,
                           animate = TRUE)
               ,
               sliderInput(inputId = "sld_3",
                           label = "weight",
                           min = 0,
                           max = 1,
                           value = 0.25,
                           step = 0.05,
                           animate = TRUE)
               ,
               sliderInput(inputId = "sld_4",
                           label = "weight",
                           min = 0,
                           max = 1,
                           value = 0.25,
                           step = 0.05,
                           animate = TRUE)
        ) #slider columns
        ,
        column(width = 9,
               offset = 0,
               align = "center",
               div(id="plotdiv",
                   plotOutput(outputId = "distPlot")
               ),               
               shinyjs::hidden(
                 div(id="errordiv",
                     p("The weights must sum to one!")
                 )
               )
        ) #column
      )#fluidrow
    )
  )
)

# Define server logic required to draw a histogram
server <- function(input, output,session) 

  dister <- reactiveVal()

  observeEvent(
    input$sld_1
    input$sld_2
    input$sld_3
    input$sld_4,
      if( !is.null(input$sld_1) &&
          !is.null(input$sld_2) &&
          !is.null(input$sld_3) &&
          !is.null(input$sld_4) &&
          sum(input$sld_1,input$sld_2,input$sld_3,input$sld_4)==1
      ) 
        dister(rnorm(input$sld_1*1000))
        shinyjs::show("plotdiv")
        shinyjs::hide("errordiv")
      
      else
      
        shinyjs::hide("plotdiv")
        shinyjs::show("errordiv")
      
    )

  output$distPlot <- renderPlot(
    x<-dister()
    hist(x)
  )



# Run the application 
shinyApp(ui = ui, server = server)

我希望这会有所帮助!

【讨论】:

【参考方案2】:

你快到了。您需要做的是在renderText 中使用您的反应式表达式output.myCondition,如下所示:

 output$distPrint <- renderText(
    if(output.myCondition())
      print("")
    else
    
      print("The weights must sum to 100%")
    

  )

[编辑]:

我似乎误解了您的问题。我知道这个问题已经得到解答,我想我会为可能在这里偶然发现的任何人提供替代解决方案。在这里,我根据output.myCondition() 的输出在renderTextrenderPlot 中添加了if else。这是更新的服务器代码。

server <- function(input, output,session) 

      dister <-   reactive(
        if( !is.null(input$sld_1) &&
            !is.null(input$sld_2) &&
            !is.null(input$sld_3) &&
            !is.null(input$sld_4) &&
            sum(input$sld_1,input$sld_2,input$sld_3,input$sld_4)==1
        ) 
          rnorm(input$sld_1*1000)
         else c(0,1,2,3,4,5)
      )

      output.myCondition <- reactive(
        if( !is.null(input$sld_1) &&
            !is.null(input$sld_2) &&
            !is.null(input$sld_3) &&
            !is.null(input$sld_4) &&
            sum(input$sld_1,input$sld_2,input$sld_3,input$sld_4)==1
        ) 
          TRUE
         else FALSE
      )

      output$distPlot <- renderPlot(
        if(output.myCondition())
        x<-dister()
        hist(x)
        else
        
         NULL
        
      )

      output$distPrint <- renderText(
        if(output.myCondition())
          print("")
        else
        
          print("The weights must sum to 100%")
        

      )
    

【讨论】:

谢谢你。然而,这并不是我所追求的。我需要显示文本或情节,这就是条件想要捕捉的内容。如果我用您提供的代码替换此代码,我仍然会得到两者。 @J.Doe。我添加了一个新答案作为上述已接受答案的替代解决方案。

以上是关于闪亮的条件面板绕过多个相关的滑块的主要内容,如果未能解决你的问题,请参考以下文章

如何在闪亮中为侧边栏面板添加滚动条?

闪亮的响应式 UI 在同一条件变量上挂起多个 uiOutput 调用

如何将条件面板设置为闪亮的选择输入?

闪亮的应用程序不更新隐藏的滑块

闪亮的滑块输入显示重复值

如何将多个输入(旋钮)添加到单个滑块?