rggplot2plotlymouseoverggplotly

change geom_point size on mouse over with plotly


I have written the following where I have an image in the background (necessary) and some data points:

library(plotly)
library(ggplot2)
library(lorem)

df <- data.frame(
  id = 1:50,
  value = rnorm(50)
)

# background image (necessary)
image_destination <- "https://i.imgur.com/ojTcMtN.jpeg"

gg <- ggplot(df,
             aes(x = id,
                 y = value,
                 text = ipsum_words(50, collapse = F) 
             )
) +
  geom_point(color = "red", alpha = 0.5, size = 5) +
  theme_bw()


# create plot
pp <- ggplotly(gg,
               tooltip = c("text"))

# display plot
plotly::layout(pp,
               # tooltip = c("text"),
               images = list(
                 list(
                   source =  image_destination,
                   xref = "x",
                   yref = "y",
                   x = 0,
                   y = 2,
                   sizex = 100,
                   sizey = 4,
                   sizing = "stretch",
                   opacity = 1,
                   layer = "below"
                 )
               ))

Is there a way to manipulate plotly so that the size of the geom_point increases on mouse over (for example, increase from the current size of 5 to size 10)?


Solution

  • You can achieve your desired result using two custom event handlers as outlined in the docs. Using the plotly_hover event you can increase the size for the hovered points, using plotly_unhover you can set it back to the defaults. In both cases this achieved using Plotly.restyle. However, using Plotly.restyle we can only set or change the marker style for a trace. Hence, to set the marker style for one point requires that each point is treated as a single trace. To this end I map factor(id) on the color aes in ggplot(). As this will add a color legend I added showlegend = FALSE in layout as setting guide="none" is not accounted for by plotly. Finally, as the units used for sizes differs from ggplot2 getting or setting the correct sizes in plotly requires a conversion of the ggplot2 sizes which can be achieved using Size_in_mm * 96 / 25.4

    Note: As the image part is not relevant for the issue, I dropped it to make the example more minimal.

    library(plotly)
    library(ggplot2)
    library(lorem)
    
    set.seed(123)
    
    df <- data.frame(
      id = 1:50,
      value = rnorm(50),
      text = ipsum_words(50, collapse = FALSE)
    )
    
    gg <- ggplot(
      df,
      aes(
        x = id,
        y = value,
        text = text,
        color = factor(id)
      )
    ) +
      geom_point(alpha = 0.5, size = 5) +
      scale_color_manual(
        values = rep("red", nrow(df)), guide = "none"
      ) +
      theme_bw()
    
    
    # create plot
    pp <- ggplotly(gg,
      tooltip = c("text")
    )
    
    # display plot
    pp <- plotly::layout(pp,
      showlegend = FALSE
    ) 
    
    pp |>
      htmlwidgets::onRender("
        function(el) {
          el.on('plotly_hover', function(data) {
            console.log(data);
        
            var pn='',
                tn='',
                colors=[];
            
            for(var i=0; i < data.points.length; i++){
              pn = data.points[i].pointNumber;
              tn = data.points[i].curveNumber;
              colors = data.points[i].data.marker.color;
            };
            var size = 10 * 96 / 25.4;
        
            var update = {'marker':{color: colors, size: size, opacity: 1}};
            Plotly.restyle(el.id, update, [tn]);
          });
          el.on('plotly_unhover', function(data) {
            var pn='',
                tn='',
                colors=[];
            
            for(var i=0; i < data.points.length; i++){
              pn = data.points[i].pointNumber;
              tn = data.points[i].curveNumber;
              colors = data.points[i].data.marker.color;
            };
            var size = 5 * 96 / 25.4;
        
            var update = {'marker':{color: colors, size: size, opacity: .5}};
            Plotly.restyle(el.id, update, [tn]);
          });
        }
      ")
    

    enter image description here