Search code examples
rplotly

fixing the position of hover box in plotly for r


I have a plotly generated widget which I need to embed into a webpage. The small space where I must embed it leads to the text being offset from the hover box (see pic)

enter image description here

Increasing the space for the plot on the web page is not an option and decreasing the font size of the hover info is also not an option, it'll get unreadable.

Question: How can I anchor the hover box to always display at the bottom of the plot, such that the hover info remains inside the box?

I did search the internet a bit, but wasn't successful. Is it even possible to set the position of the box?

Edit: Here is a sample code which shows how the plot widget gets created. Note however, that you have to resize your browser window and make it smaller, so that the hover box behaves in this wierd fashion.

library(data.table)
library(ggplot2)
library(plotly)

dt.plot.data    <- data.table(value=90)

ggp <- ggplot(dt.plot.data, aes(1, y=value, fill="dummy", text="Info 1: foo<br>Info2: bar<br>date:<br>2018-05-30")) + 
        geom_bar(stat="identity") + ggtitle("Performance") + labs(y="%") + theme_bw() +
        scale_fill_manual(values=c("#EE68FD")) +
        theme(  
                plot.title=element_text(hjust=0.5), legend.position="none",
                axis.title.x=element_blank(), axis.line.y=element_line(color="black"),
                axis.text.x=element_blank(),
                panel.grid.major.x=element_blank(), panel.grid.minor.x=element_blank(),
                #panel.grid.major.y=element_line(linetype="dashed"), panel.grid.minor.y=element_line(linetype="dashed"),
                panel.border=element_blank(), axis.ticks.x=element_blank()
        )
#ggp

ply.yaxis       <- list(autorange=FALSE, range=c(0, 100))
ply.title       <- list(font=list(size=11), bordercolor="black", bgcolor="grey")
ply.hoverlabel  <- list(bordercolor="white", font=list(color="white", size=11))

ply <- ggplotly(ggp, dynamicTicks=TRUE, tooltip=c("y", "text")) %>% 
        layout(hoverlabel=ply.hoverlabel, yaxis=ply.yaxis) %>%
        config(displayModeBar=FALSE)
ply$sizingPolicy$padding <- 0
ply

Solution

  • This will center the tooltip in the plot, I'm not sure if it's enough to solve your problem.

    I don't have everything going on in the background with your plot (e.g., the actual data, the Shiny code, etc.), so if there is an issue with this working, let me know what you're seeing. I probably just need more information.

    What happens in this code:

    • Hovering:
      • Plotly makes a tool tip
      • The tip location is modified based on what was hovered on
      • The tool tip is copied (stolen)
      • Plotly tool tips are turned off and the stolen deep copy is in its place
    • Unhovering:
      • Plotly tool tips are turned back on

    I've tried to put comments as to what's happening where, but if you have any questions, let me know.

    This uses the library htmlwidgets.

    ply %>% 
      htmlwidgets::onRender(
        "function(el, x) {   /* replace tool tip if there is one, otherwise, ya, no */
          el.on('plotly_hover', function(d) {
            dd = document.querySelector('g.hoverlayer'); /* get hover house */
                                          /* find the mid, top of the house */
            newx = d.points[0].bbox.x0 + 1/2 * (d.points[0].bbox.x1 - d.points[0].bbox.x0);
            newy = d.points[0].bbox.y0;
            ht = document.querySelector('g.hovertext');      /* find tooltip */
                                                           /* center tooltip */
            ht.setAttribute('transform', 'translate(' + newx + ',' + newy + ')');
            hto = JSON.stringify(ht.outerHTML);            /* deep copy HTML */
            Plotly.restyle(el.id, {hoverinfo: 'none'});/* turn off Plotly TTs*/
            dd.innerHTML = JSON.parse(hto);   /* recreate TT w/o Plotly ctrl */
          });
          el.on('plotly_unhover', function() { /* turn on using y + text from plot */
            Plotly.restyle(el.id, {hoverinfo: 'y+text'}); /* turn Plotly TTs on */
          });
      }")
    

    enter image description here

    If you wanted to try moving the tooltip to the right side, you could change the line that begins with newx, instead of all of what's there you could use newx = d.points[0].bbox.x1;.