Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to "clear" the brushed area of a plot in shiny?

Tags:

r

ggplot2

shiny

Plots in shiny support click and brush handlers. Is it possible to "clear"/"remove"/"delete" the brushed rectangle without having the user click elsewhere on the plot? For example, if I wanted to just store the brushed coordinates once the brush is finished and then clear the plot, this is the code I would use but I don't know how to do the clearing bit.

library(ggplot2)
library(shiny)

runApp(shinyApp(
  ui = fluidPage(
    plotOutput("plot",
               brush = brushOpts("plotBrush", delay = 5000)),
    actionButton("clear", "Clear")
  ),
  server = function(input, output, session) {
    values <- reactiveValues(brush = NULL)

    output$plot <- renderPlot({
      ggplot(cars, aes(speed, dist)) + geom_point()
    })

    brush <- reactive({
      input$plotBrush
    })

    observeEvent(input$clear, {
      cat(str(brush()))
      # clear the brushed area
    })
  }
))
like image 500
DeanAttali Avatar asked Jun 02 '15 06:06

DeanAttali


2 Answers

As of Shiny version 0.14, it is possible to use the session object to reset a plot's brush.

Below is a simple Shiny app demoing the use of session$resetBrush(<BRUSH_ID>) to clear away a brushed region. The app allows one to highlight a region of points or remove the brushed region while keeping the points highlighted or remove the brushed region and reset the color of the points.

See about halfway down at https://shiny.rstudio.com/reference/shiny/latest/session.html for the official documentation.

library(shiny)
library(ggplot2)

shinyApp(
  ui = fluidPage(
    plotOutput(
      outputId = "plot",
      brush = brushOpts(
        id = "plotBrush", 
        delay = 5000
      )
    ),
    actionButton("clearBrush", "Clear brush"),
    actionButton("resetPlot", "Reset plot")
  ),
  server = function(input, output, session) {
    output$plot <- renderPlot({
      ggplot(mtcars, aes(wt, mpg)) + 
        geom_point() +
        geom_point(
          data = brushedPoints(mtcars, brush),
          color = "#79D8CB",
          size = 2
        )
    })

    brush <- NULL
    makeReactiveBinding("brush")

    observeEvent(input$plotBrush, {
      brush <<- input$plotBrush
    })

    observeEvent(input$clearBrush, {
      session$resetBrush("plotBrush")
    })

    observeEvent(input$resetPlot, {
      session$resetBrush("plotBrush")
      brush <<- NULL
    })
  }
)
like image 79
nteetor Avatar answered Nov 17 '22 19:11

nteetor


I find myself in a similar situation where I have multiple brushes and need a button to "clear the world". I haven't found an official way to remove the brush div with R code, but it turns out there is this awesome package called shinyjs ;)

library(shiny)
library(shinyjs)

ui <- fluidPage(
  useShinyjs(),
  actionButton("clear", "Clear brush"),
  fluidRow(
    column(
      width = 6,
      plotOutput("p1", brush = brushOpts("b1"))
    ),
    column(
      width = 6,
      plotOutput("p2", brush = brushOpts("b2"))
    )
  ),
  fluidRow(
    column(
      width = 6,
      verbatimTextOutput("brush1")
    ),
    column(
      width = 6,
      verbatimTextOutput("brush2")
    )
  )
)

server <- function(input, output) {

  values <- reactiveValues(
    brush1 = NULL,
    brush2 = NULL
  )

  # update reactive values when input values change
  observe({
    values$brush1 <- input$b1
    values$brush2 <- input$b2
  })

  # display brush details
  output$brush1 <- renderPrint({
    values$brush1
  })

  output$brush2 <- renderPrint({
    values$brush2
  })

  # clear brush values and remove the div from the page
  observeEvent(input$clear, {
    values$brush1 <- NULL
    values$brush2 <- NULL
    runjs("document.getElementById('p1_brush').remove()")
    runjs("document.getElementById('p2_brush').remove()")
  })

  output$p1 <- renderPlot({
    input$clear
    m <- brushedPoints(mtcars, values$brush1, allRows = TRUE)
    qplot(data = m, wt, mpg, colour = selected_) + 
      theme(legend.position = "none")
  })

  output$p2 <- renderPlot({
    input$clear
    m <- brushedPoints(mtcars, values$brush2, allRows = TRUE)
    qplot(data = m, wt, mpg, colour = selected_) +
      theme(legend.position = "none")
  })

}

shinyApp(ui, server)

IMO, shiny should really provide something like:

clearBrush <- function(id) {
  shinyjs::runjs(sprintf("document.getElementById('%s_brush').remove()", id))
}
like image 44
Carson Avatar answered Nov 17 '22 19:11

Carson