How to Show the Y Value on Tooltip While Hover in Ggplot2

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.

R: ggplot for hover text

We can build a text using paste0 and HTML tag <br><\br> and instructe toolttip to use text.

p <- ggplot(df, aes(x = factor(Y), y = Y, 
fill = factor(Y), text=paste('</br>A: ',A,'</br>B: ',B, '</br>1: ',1)))

ggplotly(p,tooltip = c("text"))

How to choose variable to display in tooltip when using ggplotly?

You don't need to modify the plotly object as suggested by @royr2. Just add label = name as third aesthetic

ggplot(data = d, aes(x = seq, y = value, label = name)) + geom_line() + geom_point()

and the tooltip will display name in addition to seq and value.

The ggplotly help file says about tooltip parameter:

The default, "all", means show all the aesthetic mappings (including the unofficial "text" aesthetic).

So you can use the label aesthetic as long as you don't want to use it for geom_text.

BTW: I've also tried text instead of label

ggplot(data = d, aes(x = seq, y = value, text = name)) + geom_line() + geom_point()

but then ggplot2 complained

geom_path: Each group consists of only one observation. Do you need to adjust the group aesthetic?

and plotted only points. I had to add a dummy group to geom_line to remove the issue:

ggplot(data = d, aes(x = seq, y = value, text = name)) + geom_line(group = 1) + geom_point()

(But note if you put the dummy group as fourth aesthetic inside aes() it will appear by default also in the tooltip.)

However, I find the unofficial text aesthetic can become useful alongside label if you want to have different strings plotted by geom_text and shown in the tooltip.

Edit to answer a question in comments:
The tooltip parameter to ggplotly() can be used to control the appearance. ggplotly(tooltip = NULL) will suppress tooltips at all. ggplotly(tooltip = c("label")) selects the aesthetics to include in the tooltip.

Adding markers and display the tooltip in R

Here is a first solution for your problem:

library(ggplot2)
library(plotly)

digits = 1:150
sep = iris$Sepal.Length
sepw = iris$Sepal.Width
plot_f1 <- ggplot(iris, aes(x=digits, y=sep, label=sepw)) +
geom_line(color="red") + geom_point()
plot_f1 <- ggplotly(plot_f1, tooltip=c("x","label"))
plot_f1

Sample Image

A second solution is based on the text aesthetic:

plot_f2 <-  ggplot(data=iris, aes(x=digits, y=sep, group=1, 
text=paste("Sepw =",sepw,"<br />Digits =",digits))) +
geom_line(color="red") + geom_point()
plot_f2 <- ggplotly(plot_f2, tooltip="text")
plot_f2

Sample Image

Hover tooltip in Shiny using pure ggplot2 solution

The solution is to keep the previous value of the hovered data point avoiding the invalidation. This objective can be achieved using the observeEvent() method and a reactiveVal(). The solution works like this:

  • the hovered point information is a reactive value (reactiveVal()), initialized with a zero-row tibble with the same columns as the plotted data set.
    This initial value allow a smooth visualization in a ggplot2 layer, that would not be possible initializing it to NULL.

  • the value is updated in response to an hover event, the function observeEvent() by default ignores when an event become NULL (ignoreNULL = TRUE), therefore when the input$hover is invalidated to NULL the value is not updated and remain the same as before

  • in the plot rendering, the hovered() value is initially a zero-row tibble (but still having the right columns to be compatible with the plot default data) thus not showing anything, later when an hover near a point is performed it will contain the point information.

library(tidyverse)
library(shiny)
shinyApp(
ui = fluidPage(
plotOutput("plotCars", hover="hover", width=700,height=300),
verbatimTextOutput("info")),

server = function(input, output) {
hovered <- reactiveVal(mtcars %>% filter(FALSE) %>% rownames_to_column("model"))
observeEvent(input$hover, {
hovered(nearPoints(mtcars, input$hover, maxpoints = 1) %>%
rownames_to_column("model"))
})

output$plotCars <- renderPlot({
ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point() +
geom_point(color="red",data=hovered()) +
geom_label(aes(label=model),data=hovered(),
hjust="inward",vjust="inward",
size=4,color="red",alpha=0.5)+
xlab("Weight(1000 lbs)")+ylab("Miles/gallon")
})

output$info <- renderPrint({
hovered()
})
})

Any way to display data frame information besides x and y on hover with shiny/ggplot?

You can use the following code based on the plotly package:

df <- data.frame(x=c(1,2,3,4,5), y=c(6,7,8,9,10), z=c('a','b','c','d','e'))

library(ggplot2)
# Define the content and format of the tooltip in the "text" aesthetic
p <- ggplot(df, aes(x=x, y=y,
text=paste("X=",x,"<br>Y=",y,"<br>Z=",z))) +
geom_point()

library(plotly)
p <- ggplotly(p, tooltip="text")
print(p)

Sample Image

Show tooltip on plotly based on x-axis

You can set the hovermode to "x unified":

## libraries
# library(tidyverse)
library(plotly)

## fake data
dat <- data.frame(date = seq(as.Date("1910/1/1"), as.Date("1910/1/10"), "days"),
pred = 1:10,
ci_low = seq(0, 9, 1),
ci_upper = seq(2, 11, 1))

## plot
p1 <- dat %>%
ggplot(aes(x = date, y = pred)) +
geom_line(color = "red", aes(group = 1, text = paste("date:", date, "\npred:", pred, "\nci_low:", ci_low, "\nci_upper:", ci_upper))) +
geom_ribbon(aes(x = date, ymin = ci_low, ymax = ci_upper), alpha = 0.2, linetype = 0)

## plotly-fy
ggplotly(p1, tooltip = c("text")) %>%
layout(hovermode = "x unified") %>%
style(hoverinfo = "skip", traces = 2)

result

Edit: To control the displayed hoverinfo we can use ggplotly's tooltip argument along with a custom "text" aesthetic. The hoverinfo of the geom_ribbon-trace can be hidden via style().

In the plotly book you can find some great examples regarding this.



Related Topics



Leave a reply



Submit