Search code examples
rggplot2shinytooltip

How can I add custom tooltips to a ggplot bar graph in a R Shiny dashboard?


I have a series of bar graphs I made for a R Shiny dashboard. When the user hovers over a bar, I want the year (x-axis) and cost amount (y-axis) to appear over the bar.

I am having trouble integrating this. I have been experimenting around with the plotly package. It seems that many of the common ways of implementing tooltips are not compatible with ggplot. I would like to continue using ggplot since most of what I have implemented on this dashboard uses it. Here is a working version of one of the plots:

  output$costs_plot <- renderPlot({
    # Subset data based on number of years to display
    data_subset <- costShortfallDf()[1:input$num_years, ]
    
    # Create a new column to store the color based on the sign of the cost
    data_subset$color <- ifelse(data_subset$cost >= 0, "#d5e8d5", "#f8cdcc")
    
    # Check if both positive and negative values exist
    show_dotted_line <- any(data_subset$cost < 0) && any(data_subset$cost > 0)
    
    ggplot(data_subset, aes(x = Year, y = cost, fill = color,  text = paste("Year:", Year, "<br>Cost:", cost))) +
      labs(title = "Financial Outlook by Year", x = "Year", y = "Revenue (Costs)") +
      scale_x_continuous(breaks = seq(min(data_subset$Year), max(data_subset$Year), by = 1)) + 
      scale_y_continuous(
        labels = function(x) paste0(ifelse(x < 0, "-$", "$"), scales::comma_format(scale = 1e-9)(abs(x)), " B")
      ) +
      theme(
        panel.background = element_blank(),
        panel.grid = element_blank(),
        legend.position = "none",
        plot.title = element_text(color = "#0D2F4F", size = 24, hjust = 0.5),
        axis.title = element_text(size = 16),
        axis.text = element_text(size = 16),
        axis.line = element_line(color = "black", linewidth = 1)
      ) +
      geom_bar(stat = "identity") +
      scale_fill_identity() +
      if (show_dotted_line) {
        geom_hline(yintercept = 0, color = "black", linetype = "dashed", alpha = 0.5)
      }
  })

The text attribute is not displaying the tooltip at all.


Solution

  • ggplot2 creates static plots (like a png/jpeg file). These do not allow user interaction or dynamic visualization. plotly has a function called ggplotly(), which transforms any ggplot into a dynamic plotly graph that maintains the ggplot optics.

    library(shiny)
    library(plotly)
    
    data <- 
      data.frame(
        cost = sample(40:400, 20),
        year = 1994:2013
      )
    
    ggplot(data, aes(year, cost)) +
      geom_bar(stat = "identity")
    
    ggplotly()
    

    enter image description here

    To use that functionality within a shiny app you can simply use plotly::renderPlotly() instead of shiny::renderPlot() and plotly::plotlyOutput() instead of shiny::plotOutput().

    library(shiny)
    library(plotly)
    
    data <- 
      data.frame(
        cost = sample(40:400, 20),
        year = 1994:2013
      )
    
    ui <- fluidPage(plotlyOutput("distPlot"))
    
    server <- function(input, output) {
        output$distPlot <- renderPlotly({
            ggplot(data, aes(year, cost)) +
            geom_bar(stat = "identity")
        })
    }
    
    shinyApp(ui = ui, server = server)