Faking plotly’s ‘y unified’ tooltip in ggiraph

Author

Author: Kurtis Smith

Published

November 5, 2025

Problem

A ggiraph tooltip head scratcher (and the fix!)

We settled on ggiraph as our interactive visualisation package for a new Shiny dashboard. The goal was simple: capture the Y-axis value, grouped by the X-axis to display in a tooltip when a user hovers over an element. I’ve used plotly before, and it has a handy “y unified” argument that does this perfectly (see plotly reference). The hitch? ggiraph doesn’t offer that option.

The Solution: This little snag is now sorted! I’m writing this blog post to solidify the lesson for myself and hopefully save others the headache if they run into the same problem. Let’s start with the setup.

# Load packages
library(dplyr)
library(lubridate)
library(stringr)
library(patchwork)
library(glue)
library(ggplot2)
library(ggiraph)

# Set ggplot theme and default palette
theme_set(theme_minimal())
options(ggplot2.discrete.fill="viridis")

# Promise data
data("lakers")

Solution

The below summaries the data and makes use of one of my favourite functions stringr::str_flatten_comma() to create the “y unified” tooltip alongside a few friends in glue & str_replace_all for my use case.

# Summarise data
ppp_top_3 <- lakers |> 
 filter(period != 5) |> 
 group_by(period, player) |> 
 summarise(total_points = sum(points), .groups = "drop_last") |> 
 slice_max(n = 3, order_by = total_points) |> 
 # Creating tooltip, adding <br> to neatly format tooltip
 mutate(tooltip = glue(
  "Total Points<br>", 
  str_flatten_comma(glue(" - {player} {total_points}"))
 ) |>
  str_replace_all(",", ",<br>")) |> 
 ungroup()

Plot prep

Before we can see the results let’s codes the plots. For those familiar with ggplot2 you’ll be able to spot the few differences. I think ggiraph's homepage provides a clean, short, and simple overview of the differences.

p <- ppp_top_3 |> 
 ggplot(aes(x = period, y = total_points, fill = player)) +
 geom_col_interactive(position = position_dodge2()) +
 labs(title = "Top 3 scoring Lakers players per period (2008-2009 Season)",
      subtitle = "No Tooltip",
      x = "Period", 
      y = "") +
 theme(plot.title.position = "plot", 
       legend.position = "right", 
       legend.title = element_blank())

p_tooltip <- ppp_top_3 |> 
 ggplot(aes(x = period, 
            y = total_points, 
            fill = player,
            tooltip = tooltip, 
            data_id = period)) +
 geom_col_interactive(position = position_dodge2()) +
 labs(subtitle = "With Tooltip", 
      x = "Period", 
      y = "") +
 theme(plot.title.position = "plot", 
       legend.position = "right", 
       legend.title = element_blank())

plots <- p + p_tooltip + plot_layout(ncol = 2,
                                     axes = "collect",
                                     guides = "collect")

Plot

Try it out!

girafe(
 ggobj = plots,
 options = list(
  opts_hover_inv(css = "opacity:0.2"),
  opts_toolbar(saveaspng = FALSE),
  opts_zoom(max = 1),
  opts_tooltip(
   opacity = 0.8,
   use_fill = TRUE,
   use_stroke = FALSE,
   css = "padding:5pt;color:white"
  ),
  opts_selection(type = "none", only_shiny = FALSE),
  opts_hover(css = girafe_css(
   css = glue::glue("transition: all 0.5s ease;stroke: black; stroke-width: 1px;"),
   text = glue::glue("fill-opacity:1;")
  ))
 )
)
0 200 400 600 1 2 3 4 No Tooltip Top 3 scoring Lakers players per period (2008-2009 Season) 1 2 3 4 Period With Tooltip Derek Fisher Kobe Bryant Lamar Odom Pau Gasol Trevor Ariza

Conclusion

The method of creating your tooltip in the data frame ahead of time could even work with plotly and gives you more flexibility on design.

Acknowledgements

r-bloggers.com for the reach, platform, and content

Packages and package maintainer(s):

  • dplyr | Hadley Wickham
  • lubridate | Vitalie Spinu
  • stringr | Hadley Wickham
  • patchwork | Thomas Lin Pedersen
  • glue | Jennifer Bryan
  • ggplot2 | Thomas Lin Pedersen
  • ggiraph | David Gohel