Interactively update horizontal and vertical lines in ggplot2 using dbl_click?

442 views
Skip to first unread message

Benedito Chou

unread,
Jun 26, 2015, 11:35:54 PM6/26/15
to shiny-...@googlegroups.com
Hello Shiny Friends and Experts,

I'm trying to let users set the horizontal and vertical lines in a ggplot2 scatterplot by double clicking on the graph (see my code below). When I ran this, the new graph will flash for half a second, showing where the new lines should be but then revert back to the original. Is there something I'm missing in my code I need to make the graph update permanent?

Thanks in advance for any help and suggestion.

Ben

library(shiny)
library(ggplot2)

data <- data.frame(replicate(2, rnorm(100)))

ui = fluidPage(
  plotOutput("plot", dblclick = "plot_dblclick")
    )

server = function(input,output){
    output$plot <- renderPlot({
      if(!is.null(input$plot_dblclick)) {
        xcut <- input$plot_dblclick$x
        ycut <- input$plot_dblclick$y
      } else {
        xcut <- mean(data$X1)
        ycut <- mean(data$X2)
      }
      ggplot(data, aes(x = X1, y = X2)) + geom_point() +
        geom_vline(xintercept = xcut) +
        geom_hline(yintercept = ycut)
    })
}

shinyApp(ui=ui,server=server)

Amber James

unread,
Jun 29, 2015, 12:15:01 AM6/29/15
to shiny-...@googlegroups.com
The reason you are having problems is because you are doing the main logic of the double clicking within the render function.

Essentially, the user will double click the point and shiny will redraw the entire graph. Because the data looks the same the graph will also look the same. But when you redraw the graph the plot_dblclick element changes back to null which causes the graph to change again because the if statement within the render function makes the function dependent on the changing values of the plot_dblclick statement. 

To fix this, remove the if statement and use a reactiveValue and observe event statement. 

library(shiny)
library
(ggplot2)


data
<- data.frame(replicate(2, rnorm(100)))


ui
= fluidPage(
  plotOutput
("plot", dblclick = "plot_dblclick")
)


server
= function(input,output){

  values
<- reactiveValues(
    xcut
=mean(data$X1),
    ycut
=mean(data$X2)
 
)


  observeEvent
(input$plot_dblclick, {
    values$xcut
<- input$plot_dblclick$x
    values$ycut
<- input$plot_dblclick$y
 
})


  output$plot
<- renderPlot({

    ggplot
(data, aes(x = X1, y = X2)) + geom_point() +

      geom_vline
(xintercept = values$xcut) +
      geom_hline
(yintercept = values$ycut)
 
})
}


shinyApp
(ui=ui,server=server)


Now, this code is very general. If you have a dynamic plotting application where the data changes often, you will want another observer that sets the graph cut values back to the original means. 

  observeEvent(input$data, {
    values$xcut
<- mean(data$X1)
    values$ycut
<- mean(data$X2)
 
})

The input$data in the above code would be the same as the local data frame in your original code but the observer will alter the cut values whenever the data changes. 

Hope this helps. Good Luck!

Amber

Benedito Chou

unread,
Jun 29, 2015, 10:42:44 PM6/29/15
to shiny-...@googlegroups.com
Thanks Amber,

Thank you for your lucid explanation and help. You completely answered my question and more! It makes so much sense now after you explained why my original code didn't work.

Thanks,

Ben

Amber James

unread,
Jun 29, 2015, 11:59:55 PM6/29/15
to shiny-...@googlegroups.com
Awesome! Glad to help. :)
Reply all
Reply to author
Forward
0 new messages