将多个sliderInput限制为闪亮,总计为100

时间:2014-01-06 14:40:09

标签: r shiny

我整天都在苦苦挣扎,我有点解决它(可怕的黑客)。然而,经验并不顺畅,并且会出现副作用。

我想要的是三个滑块,其范围为0到100约束,使得它们的总和应该始终为100.

这是Screenshot

的截图

这是server.R闪亮代码。

library(shiny)

oldState<-NULL
newState<-NULL

getState<-function(input) c(input$slider1, input$slider2, input$slider3)

# Define server logic required
shinyServer(function(input, output, session) {

  observe({
    newState<<-getState(input)
    i<-which(oldState-newState != 0)[1]
    if(!is.na(i)){
      rem <- 100-newState[i]
      a<-sum(newState[-i])
      if(a==0) newState[-i]<<-rem/length(newState[-i])
      else newState[-i]<<-rem*(newState[-i]/a)
      for(j in 1:length(newState))
        if(j!=i)
          updateSliderInput(session, paste0("slider", j), value=newState[j])
    }
    oldState<<-newState
  })

  output$restable <- renderTable({
    myvals<-getState(input)
    myvals<-c(myvals, sum(myvals))
    data.frame(Names=c("Slider 1", "Slider 2", "Slider 3", "Sum"),
               Values=myvals)
  })
})

这是ui.R闪亮代码

library(shiny)

# Define UI for application
shinyUI(pageWithSidebar(

  # Application title
  headerPanel("Sliders should sum to 100!"),

  # Sidebar with sliders whos sum should be constrained to be 100
  sidebarPanel(
    sliderInput("slider1", "Slider 1: ", min = 0, max = 100, value = 40, step=1),
    sliderInput("slider2", "Slider 2: ", min = 0, max = 100, value = 30, step=1),
    sliderInput("slider3", "Slider 3: ", min = 0, max = 100, value = 30, step=1)
  ),

  # Create table output
  mainPanel(
    tableOutput("restable")
  )
))

现在除了两件事之外,它几乎应该做的事情:

  • 感觉就像是黑客,即应该有更好的方法来做到这一点
  • 当我将滑块移动到某个位置时,它有时会跳到略低或稍高的位置。我不明白为什么。

如何解决这两个问题?

2 个答案:

答案 0 :(得分:4)

我认为使用dynamicUI可能会解决您的问题。

如果您知道需要正好3个输入总和为1,那么您可以将用户限制为仅两个滑块输入,并使第二个滑块输入在第一个输入上,如下所示。使用您的代码模板:

<强> server.R

library(shiny)

# Define server logic required
shinyServer(function(input, output) {

  output$slider2 <- renderUI {
    sliderInput("slider2", "Slider 2", min = 0,  max = 100 - input$slider1, value = 0)  
  })

  output$restable <- renderTable({
    myvals<- c(input$slider1, input$slider2, 100-input$slider1-input$slider2)
    data.frame(Names=c("Slider 1", "Slider 2", "Slider 3"),
               Values=myvals)
  })
})

此处的关键是renderUI函数,该函数会查找input$slider1值以约束slider2的值(因此slider3

<强> ui.R

library(shiny)

# Define UI for application
shinyUI(pageWithSidebar(

  # Application title
  headerPanel("Sliders should sum to 100!"),

  # Sidebar with sliders whos sum should be constrained to be 100
  sidebarPanel(
    sliderInput("slider1", "Slider 1: ", min = 0, max = 100, value = 0, step=1),
    uiOutput("slider2")
  ),

  # Create table output
  mainPanel(
    tableOutput("restable")
  )
))

如附图中所示(如果您眯着眼睛),slider2被限制为0-35,slider1被设置为65。

enter image description here

答案 1 :(得分:0)

所有这些想法都有帮助,但我的直觉是使用 tagList。算法是这样运行的,

  1. 将所有滑块保存在标签列表中
  2. 让 n 为标签列表的长度
  3. 填充标签列表中的所有滑块小部件
  4. 如果 observe {...} 下的滑块小部件更改(在服务器中),请确定是哪个小部件。
  5. 设 x 为 100 减去从标签列表 (3) 和 (4) 更改的小部件的值。
  6. 将标签列表中剩余滑块的 value 属性设置为 x/(n-1)

希望这会有所帮助。将尽快更新代码。