greenbooks
greenbooks

Reputation: 161

R shiny bi-directional reactive widgets

I am struggling to figure out how to get 2 R Shiny widgets to update each other. For example, a slider widget that can update a text box widget, and visa versa, where the end user can choose to use either widget.

This question is similar, but has no answer, so I am giving what is (hopefully) a simpler example. Retrieving reactive dependencies as inferred by shiny::reactive(). If this question is answered elsewhere, I have been unable to find such an answer.

I would like to know if I can move slider1 to move slider2 and slider2 to move slider1. Right now I only can do the first part (I can move slider1 to move slider2). If I can do this, I am thinking I could make widget 1 a slider, and widget 2 a numerical input, with much the same code.

The below example was modified from http://shiny.rstudio.com/gallery/update-input-demo.html and it is as minimal an example as I could make. It was also the only app I could find that came close to what I was looking for, although I realize a very different approach may needed...

Server.R Code

shinyServer(
  function(input, output, clientData, session) {

#### one way interaction between slider 1 and 2 ####
    observe({![enter image description here][1]   
      c_label <- input$control_label
      c_num <- input$control_num  # <- input$inSlider

      # Slider input =============================================
      updateSliderInput(session, "inSlider",
                        label = paste("Slider2", c_label),
                        value = c_num)
      updateSliderInput(session, "control_num",
                        label = paste("Slider1", c_label),
                        value = c_num)
    })
})

Ui.r Code

shinyUI(fluidPage(
  titlePanel("One Way Reactive Slider"),
  fluidRow(
    column(3,
           wellPanel(
             h4("Slider Inputs"),
             sliderInput("control_num",
                         "This controls values:",
                          min = 1, max = 20, value = 15),
             sliderInput("inSlider", "Slider input:",
                          min = 1, max = 20, value = 15)
    ))

  )
))

Below is a picture of the app while running. Moving slider 1 moves slider 2, but the opposite is not true (which is what I would like to do).

Upvotes: 8

Views: 3003

Answers (2)

Namaloom
Namaloom

Reputation: 11

If you enclose each input slider under a reactive observe, you can achieve your goal. This not only works for two inputs, but for several inputs as well. Let me explain by an example:

observe({
# Create a reactive relationship with slider1
input$slider1
# Update the second slider - slider2
updateTextInput(session, "slider2", NULL, input$slider1)
)}

Similarly for second input, you'd have to repeat the code, by:

observe({
# Create a reactive relationship with slider2
input$slider2
# Update the second slider - slider1
updateTextInput(session, "slider1", NULL, input$slider2)
)}

Upvotes: 0

Marat Talipov
Marat Talipov

Reputation: 13304

The trick is to create a dynamic UI. In this way, you can update a slider-drawing expression on changes in the other UI elements and rebuild a slider widget using a different default value:

server.R

shinyServer(
    function(input, output, clientData, session) {

    output$slider1 <- renderUI({
       slider2.value <- input$inSlider
       default.slider1 <- if (is.null(slider2.value)) 15 else slider2.value
       sliderInput("control_num",
                   "This controls values:",
                    min = 1, max = 20, value = default.slider1)
    })

    output$slider2 <- renderUI({
       slider1.value <- input$control_num
       default.slider2 <- if (is.null(slider1.value)) 15 else slider1.value
       sliderInput("inSlider", "Slider input:",
                    min = 1, max = 20, value = default.slider2)
    })

  })

ui.R

    shinyUI(fluidPage(
      titlePanel("One Way Reactive Slider"),
      fluidRow(
        column(3,
               wellPanel(
                 h4("Slider Inputs"),
                 uiOutput('slider1'),
                 uiOutput('slider2')
        ))

      )
    ))

Upvotes: 8

Related Questions