roman roman - 7 days ago 5
R Question

dynamic ggplot layers in shiny with nearPoints()

I'm familiar with the basics of shiny but struggling with something here. I would like to be able to add a ggplot layer when a point is clicked to highlight that point. I know this is possible with ggvis and there is a nice example in the gallery, but I would like to be able to use

nearPoints()
to capture the click as ui input.

I have tried something (see below) which works apart from the ggplot layer appears and then disappears. I have tried all kinds of edits to this with
reactive()
,
eventReactive()
and so on.

Any help is much appreciated...

library(shiny)
library(ggplot2)

shinyApp(
ui = shinyUI(
plotOutput("plot", click = "clicked")
),

server = shinyServer(function(input, output) {
output$plot <- renderPlot({
ggplot(mtcars, aes(x = mpg, y = wt)) +
geom_point() +
geom_point(data = nearPoints(mtcars, input$clicked), colour = "red", size = 5)
})
})
)


I think I understand conceptually why this doesn't work. The plot has a dependency on
input$clicked
which means that when
input$clicked
changes the plot re-renders but this in turn resets
input$clicked
. Bit of a catch 22 situation.

Answer

Please, try this:

library(shiny)
library(ggplot2)

# initialize global variable to record selected (clicked) rows
selected_points <- mtcars[0, ]
str(selected_points)


shinyApp(
  ui = shinyUI(
    plotOutput("plot", click = "clicked")
  ),

  server = shinyServer(function(input, output) {

    selected <- reactive({
      # add clicked
      selected_points <<- rbind(selected_points, nearPoints(mtcars, input$clicked))
      # remove _all_ duplicates if any (toggle mode) 
      # http://stackoverflow.com/a/13763299/3817004
      selected_points <<- 
        selected_points[!(duplicated(selected_points) | 
                            duplicated(selected_points, fromLast = TRUE)), ]
      str(selected_points)
      return(selected_points)
    })

    output$plot <- renderPlot({
      ggplot(mtcars, aes(x = mpg, y = wt)) +
        geom_point() +
        geom_point(data = selected(), colour = "red", size = 5)
    })
  })
)

If you click a point one time it is highlighted. If you click it a second time the highlight is turned off again (toggling).

The code uses a global variable selected_points to store the actually highlighted (selected) points and an reactive expression selected() which updates the global var whenever a point is clicked.

The str(selected_points) may help to visualize the working but can be removed.

Comments