How do I show the y value on tooltip while hover in ggplot2

Unfortunately ggplot is not interactive but it can be easily “fixed” with plotly package. You only need to replace plotOutput with plotlyOutput and then render a plot on with renderPlotly.

Example 1: plotly

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

ui <- fluidPage(
    plotlyOutput("distPlot")
)

server <- function(input, output) {
   output$distPlot <- renderPlotly({
      ggplot(iris, aes(Sepal.Width, Petal.Width)) + 
       geom_line() + 
       geom_point()
   })
}

shinyApp(ui = ui, server = server)


Example 2: plotOutput(…, hoverOpts(id = “plot_hover”, delay = 50)):

We don’t have to use any special package to introduce the interactivity to our graphs though. All we need is our lovely shiny shiny! We can just play with plotOutput options as for instance click, hover or dblclick to make the plot interactive. (See more examples in shiny gallery)

In the example below we add “hovering” by the parameterhover and then customise delay, which is set by default 300ms.

plotOutput("distPlot", hover = hoverOpts(id = "plot_hover", delay = 50))

We then can access values via input$plot_hover and use a function nearPoints to show values that are near the points.

ui <- fluidPage(
  selectInput("var_y", "Y-Axis", choices = names(iris)),

# plotOutput("distPlot", hover = "plot_hover", hoverDelay = 50), # UPDATED
# plotOutput in shiny 1.7.2 doesn't have the hoverDelay argument. One needs to use hoverOpts()
plotOutput("distPlot", hover = hoverOpts(id = "plot_hover", delay = 50)),
  uiOutput("dynamic")
  
)

server <- function(input, output) {
  
  output$distPlot <- renderPlot({
    req(input$var_y)
    ggplot(iris, aes_string("Sepal.Width", input$var_y)) + 
      geom_point()
  })
  
  output$dynamic <- renderUI({
    req(input$plot_hover) 
    verbatimTextOutput("vals")
  })
  
  output$vals <- renderPrint({
    hover <- input$plot_hover 
    # print(str(hover)) # list
    y <- nearPoints(iris, input$plot_hover)[input$var_y]
    req(nrow(y) != 0)
    y
  })
  
}
shinyApp(ui = ui, server = server)

Example 3: Custom ggplot2 tooltip:

The second solution works great but yes…we want to do it better! And yes…we can do it better! (…If we use some javaScript but pssssss don’t tell anyone!).

library(shiny)
library(ggplot2)

ui <- fluidPage(
  
  tags$head(tags$style('
     #my_tooltip {
      position: absolute;
      width: 300px;
      z-index: 100;
      padding: 0;
     }
  ')),
  
  tags$script('
    $(document).ready(function() {
      // id of the plot
      $("#distPlot").mousemove(function(e) { 
        
        // ID of uiOutput
        $("#my_tooltip").show();         
        $("#my_tooltip").css({             
          top: (e.pageY + 5) + "px",             
          left: (e.pageX + 5) + "px"         
        });     
      });     
    });
  '),
  
  selectInput("var_y", "Y-Axis", choices = names(iris)),
  plotOutput("distPlot", hover = hoverOpts(id = "plot_hover", delay = 50)),
  uiOutput("my_tooltip")
  
  
)

server <- function(input, output) {

  
  output$distPlot <- renderPlot({
    req(input$var_y)
    ggplot(iris, aes_string("Sepal.Width", input$var_y)) + 
      geom_point()
  })
  
  output$my_tooltip <- renderUI({
    hover <- input$plot_hover 
    y <- nearPoints(iris, input$plot_hover)[input$var_y]
    req(nrow(y) != 0)
    verbatimTextOutput("vals")
  })
  
  output$vals <- renderPrint({
    hover <- input$plot_hover 
    y <- nearPoints(iris, input$plot_hover)[input$var_y]
    req(nrow(y) != 0)
    y
  })  
}
shinyApp(ui = ui, server = server)


Example 4: ggvis and add_tooltip:

We can also use ggvis package. This package is great, however, not enough mature yet.

Update: ggvis is currently dormant: https://github.com/rstudio/ggvis#status

library(ggvis)

ui <- fluidPage(
  ggvisOutput("plot")
)

server <- function(input, output) {
  
  iris %>%
    ggvis(~Sepal.Width, ~Petal.Width) %>%
    layer_points() %>%
    layer_lines() %>% 
    add_tooltip(function(df) { paste0("Petal.Width: ", df$Petal.Width) }) %>%
    bind_shiny("plot")
}

shinyApp(ui = ui, server = server)

EDITED


Example 5:

After this post I searched internet to see whether it could be done more nicely than example 3. I found this wonderful custom tooltip for ggplot and I believe it can hardly be done better than that.

Updated: it can happen that the shiny function p gets masked by some other function and the shiny code doesn’t work properly. In order to avoid the issue, once can run the following command before sourcing the full shiny code:

p <- shiny::p


EDITED 2


The four first examples have been updated as of 03.09.2022 such that they are working with the newest shiny version 1.7.2.

Leave a Comment