Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional reactivity Shiny

Tags:

r

shiny

Reactive expressions in Shiny propagate changes where they need to go. We can suppress some of this behaviour with isolate, but can we suppress changes being propagated based on our own logical expression?

The example I give is a simple scatterplot, and we draw a crosshair with abline where the user clicks. Unfortunately, Shiny considers the result to be a new plot, and our click value is reset to NULL... which in turn is treated as an update to the value to be propagated as usual. The plot is redrawn, and NULL is passed to both arguments of abline.

My hack (commented out below) is to place a condition in the renderPlot call which updates some non-reactive variables for the plotting coordinates, only when the click values are non-NULL. This works fine for trivial plots, but it actually results in the plot being drawn twice.

What's a better way to do this? Is there a correct way?

Server file:

library(shiny)

shinyServer(function (input, output)
{
  xclick <- yclick <- NULL
  output$plot <- renderPlot({
    #if (!is.null(input$click$x)){
      xclick <<- input$click$x
      yclick <<- input$click$y
    #}
    plot(1, 1)
    abline(v = xclick, h = yclick)
  })
})

UI file:

library(shiny)

shinyUI(
  basicPage(
    plotOutput("plot", click = "click", height = "400px", width = "400px")
  )
)
like image 650
Mark O'Connell Avatar asked Jun 19 '16 13:06

Mark O'Connell


People also ask

What are reactive expressions Shiny?

A reactive expression is an R expression that uses widget input and returns a value. The reactive expression will update this value whenever the original widget changes. To create a reactive expression use the reactive function, which takes an R expression surrounded by braces (just like the render* functions).

What does the renderPlot function do in Shiny?

renderPlot is an reactive function that can take input data from the ui. R script and feed it into the server. R script. It then actively updates the information within its function.

What is reactive function?

Reactive functions are functions that can read reactive values and call other reactive functions. Whenever a reactive value changes, any reactive functions that depended on it are marked as "invalidated" and will automatically re-execute if necessary.


1 Answers

Winston calls this problem "state" accumulation - you want to display not only the current data, but something generated by the previous plot (the best place to learn about this is at https://www.rstudio.com/resources/videos/coordinated-multiple-views-linked-brushing/)

The basic idea is to create your own set of reactive values, and update them when the user clicks on the plot. They won't be invalidated until the next click, so you don't get circular behaviour.

library(shiny)

shinyApp(
  shinyUI(basicPage(plotOutput("plot", click = "click"))),
  function(input, output) {
    click <- reactiveValues(x = NULL, y = NULL)
    observeEvent(input$click, {
      click$x <- input$click$x
      click$y <- input$click$y
    })

    output$plot <- renderPlot({
      plot(1, 1)
      abline(v = click$x, h = click$y)
    })
  }
)
like image 190
hadley Avatar answered Oct 02 '22 04:10

hadley