1
votes

I apologize if this question has a trivial answer and my limited knowledge of Shiny has led me down the wrong path during my extensive search for an answer.

I am trying to solve the following issue. I have an output that depends on two sliderInputs to create a plot. The sliders in turn are dependent on each other in the sense that the state of second slider should be reset each time the value for the first slider changes. My current attempt on implementing this looks as follows:

library(shiny)
library(plotly)
library(ggplot2)    

ui <- fluidPage(

  titlePanel("Test"),
  sidebarLayout(
    sidebarPanel(
      sliderInput("slider1", "Slider1:", min = 0, max = 100, value = 0, step= 0.1),
      sliderInput("slider2", "Slider2:", min = 0, max = 100, value = 0, step= 0.1)
    ),
    mainPanel(
      plotlyOutput('plot', height = 600)
    )
  )
)


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

  #temporary state storage.
  slider1.state <- reactiveVal(-1)
  counter <- reactiveVal(0)

  output$plot <- renderPlotly({

    print(paste("Function Call Number ", isolate(counter()) )) 
    counter(isolate(counter())+1)

    #Only reset Slider2 if Slider1 has been changed
    if (isolate(slider1.state()) != input$slider1) {

      #this triggers a redraw
      updateSliderInput(session, "slider2", value=0 )

    }
    ylim_max = input$slider2

    #set the new values of the sliders
    slider1.state(input$slider1)

    ggplot(data.frame()) + geom_point() + xlim(0, input$slider1) + ylim(0, ylim_max)

  })

}

shinyApp(ui, server)

I am using reactive values to store the state of slider1, and resetting slider2 using updateSliderInput only when slider1 has changed. The problem that I am facing however this that the call to updateSliderInput triggers the renderPlotly function a second time, hence unnecessarily computing and redrawing the plot of a second time.

I have tried to find a solution that would allow me to somehow update the sliderInput without triggering an event, but to no avail. Is there an elegant way of obtaining this behavior? Ideally, I am looking for a solution that could be applied to arbitrary inputs.

Any help in this matter would be greatly appreciated. Thank you!

1
I'd suggest using an actionButton() to trigger the plot building and separating the updateSliderInput logic into it's own eventReactive(input$slider1, {...}). - Nate

1 Answers

0
votes

You could use debounce() to avoid unnecessary updates:

library(shiny)
library(plotly)
library(ggplot2)    

ui <- fluidPage(

  titlePanel("Test"),
  sidebarLayout(
    sidebarPanel(
      sliderInput("slider1", "Slider1:", min = 0, max = 100, value = 0, step= 0.1),
      sliderInput("slider2", "Slider2:", min = 0, max = 100, value = 0, step= 0.1)
    ),
    mainPanel(
      plotlyOutput('plot', height = 600)
    )
  )
)


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

  observeEvent(input$slider1, {
    updateSliderInput(session, "slider2", value=0 )
  })

  plot_limits <- reactive({
    list(xlim_max = input$slider1, ylim_max = input$slider2)
  })

  plot_limits_d <- plot_limits %>% debounce(500)

  counter <- reactiveVal(0)

  output$plot <- renderPlotly({
    print(paste("Function Call Number ", isolate(counter()) )) 
    counter(isolate(counter())+1)
    ggplot(data.frame()) + geom_point() + xlim(0, plot_limits_d()$xlim_max) + ylim(0, plot_limits_d()$ylim_max)
  })

}

shinyApp(ui, server)