1

Please find the working code below. Basically, there are 3 numericInputs which allows the user to change anyone at a time and the other 2 should adapt themselves resulting in 1

A + B + C = 1 However, since they are interlinked, they seems to be unstable. How can we make it stable and allow the user to change any 1 variable: A and other 2 change themselves summing to 1.

Based on the answer here, created a working code as shown below:

Connect mutually dependent shiny input values

Dependent inputs in Shiny application with R

library(shiny)
ui <- shinyUI(fluidPage(
  titlePanel("Mutually Dependent Input Values"),
  sidebarLayout(
    sidebarPanel(
      numericInput("A", "A",.333),
      numericInput("B", "B",.333),
      numericInput("C", "C",.333)
    ),
    mainPanel(
      verbatimTextOutput("result")
    )
  )
)) 
server <- shinyServer(function(input, output,session) {

  observeEvent(input$A,{
    newB <- 1 - input$A - input$C 
    updateNumericInput(session, "B", value = newB) 
    newC <- 1 - input$A - input$B 
    updateNumericInput(session, "C", value = newC) 
  })
  observeEvent(input$B,{
    newC <- 1 - input$B - input$A 
    updateNumericInput(session, "C", value = newC) 
    newA <- 1 - input$B - input$C 
    updateNumericInput(session, "A", value = newA) 
  })
  observeEvent(input$C,{
    newA <- 1 - input$C - input$B 
    updateNumericInput(session, "A", value = newA) 
    newB <- 1 - input$C - input$C 
    updateNumericInput(session, "B", value = newB) 
  })


})
shinyApp(ui,server)

Basically, user will be free to update any of the numericInput: A, B or C. Other 2 numericInput should adapt itself to sum up to 1. Currently, since they are interlinked, they seems to be unstable (please find the above code to regenerate the error)

####### Different approach with own solution

ui <- fluidPage(
  column(6, 
         tags$h2("Set parameters"),
         numericInput("valueA", "Value1", value = .333, min = 0, max = 1, step = .1),
         numericInput("valueB", "Value2", value = .333, min = 0, max = 1, step = .1),
         numericInput("valueC", "Value3", value = .333, min = 0, max = 1, step = .1)
  ),
  column(6,
         uiOutput("ui")
  )
)

server <- function(input, output, session) {
  output$ui <- renderUI( {
    tagList(
      tags$h2("Display in %"),
      numericInput("obs1", "Label1", value = 100 * (input$valueA / (input$valueA + input$valueB + input$valueC))),
      numericInput("obs2", "Label2", value = 100 * (input$valueB / (input$valueA + input$valueB + input$valueC))),
      numericInput("obs2", "Label2", value = 100 * (input$valueC / (input$valueA + input$valueB + input$valueC)))
    )
  })
}

shinyApp(ui, server)   

Abhishek
  • 407
  • 3
  • 18
  • The problem is that you're forcing all the input values to change together too many times, that is: if A is changed then B and C are changed, each of which force the other two to change and so on. – DS_UNI Apr 25 '19 at 13:35
  • True, but how can we get rid of this ? Can you pls help me – Abhishek Apr 25 '19 at 14:49

1 Answers1

0

You need to do two main things:

  • First let your initial values stable, so either their sum should be 1 (0.333, 0.333, 0.334), or maybe let the initial values be empty, which will only work if you have some type of error escaping mechanism to allow NA or empty string to be an initial value. As I thought there should be in any case some validation that the input is numeric I chose to use the second option, which works well with the validation.

  • Second one way to get rid of these infinite loops of observing and changing the input, is to change one at a time, meaning:

    • if A is changed ---> change B,
    • if B is changed ---> change C, and
    • if C is changed ---> change A

That being said, note that the order of changing the input makes a difference in this approach, this is most noticeable at the start when you give the input their first set of values.

There might be a better approach to solve this, but this is what I can think of, so here it goes.

The UI:

library(shiny)
ui <- shinyUI(fluidPage(
  titlePanel("Mutually Dependent Input Values"),
  sidebarLayout(
    sidebarPanel(
      numericInput("A", "A", NA),
      numericInput("B", "B", NA),
      numericInput("C", "C", NA)
    ),
    mainPanel(
      verbatimTextOutput("result")
    )
  )
)) 

The Server:

server <- shinyServer(function(input, output, session) {
  sum <- reactive({
    validate(
      need(is.numeric(input$A), 'A is not a number, only numbers are allowed'),
      need(is.numeric(input$B), 'B is not a number, only numbers are allowed'),
      need(is.numeric(input$C), 'C is not a number, only numbers are allowed')
    )
    input$A + input$B + input$C})

  observeEvent(input$A,{
      newB <- 1 - input$A - input$C
      updateNumericInput(session, "B", value = newB)
  })

  observeEvent(input$B,{
      newC <- 1 - input$B - input$A
      updateNumericInput(session, "C", value = newC)
  })

  observeEvent(input$C,{
      newA <- 1 - input$C - input$B
      updateNumericInput(session, "A", value = newA)
  })

  output$result <- renderPrint({
    print(sprintf("A=%.3f      B=%.3f      C=%.3f  ---->   A + B + C = %.0f", 
                  input$A, input$B, input$C, sum()))
  })
})

Run:

shinyApp(ui,server)
DS_UNI
  • 2,600
  • 2
  • 11
  • 22
  • Thanks for awesome solution. Although user has to change the inputs sequentially, it works...So I accept your answer. I have tried a different approach....(Updated in the question itself with my solution) – Abhishek Apr 27 '19 at 11:02
  • Can you please help to ensure numericInput rendered using renderUI doesnt allow user to update the value i.e Although Label1,2 and 3 are calculated based on Value1,2 and 3, User can still increase or decrease the Label values. Can we somehow disable this. So that user cannot vary the Labels ? – Abhishek Apr 27 '19 at 11:26
  • I'm not sure I understand what you mean, why use numericInput for the labels if you don't want the user to give input? – DS_UNI Apr 29 '19 at 11:03
  • Please run the code I added in the quesiton. Displaying 3 numricInput in order to display in % the weighing factors – Abhishek Apr 29 '19 at 12:18
  • I did, but what I don't understand is what you're trying to achieve with the use of numericInput, if all you want is to display the percentage then why not just renderPrint for example? – DS_UNI Apr 29 '19 at 12:26
  • Oh, Actually, the rest of the code needs the value in %. Therefore, renderPrint is not an option. – Abhishek Apr 30 '19 at 10:39
  • You mean you are trying to define new values to use in some code block not mentioned in the question? is it possible that you are trying to define [reactive values](https://riptutorial.com/shiny/example/32342/reactivevalues)? – DS_UNI Apr 30 '19 at 11:16
  • Currently, create another 3 variables as reactive for internal calculation. However was wondering if it is possible to use the same variable which are displayed in the dashboard....Because User could change the displayed numericInput (%). But since the internal calculation depends only on the weighing factors. Internal calculation is unaffected. – Abhishek Apr 30 '19 at 12:07
  • As far as I know if you don't want the user to change it, then you should not use any `...Input` function, that being said I can't say that I get 100% what you want to do without taking a look at the code and the output expect to have when run, you can if you like ask a new question, that way you can add your full code and elaborate more on what you are trying to achieve with the second `numericInput` , if you did let me know and I would gladly try to help – DS_UNI May 02 '19 at 14:53