Search code examples
rplotlystacked-bar-chart

How can I fix the compare data on hover functionality for a plotly bar chart with stacked percents?


I have a chart that I need to display percentages of one group by another group. I have the chart exactly how I want it, but I'm having trouble getting the tooltips to function as I want.

I have the default set to hovermode = y, which basically what I want to show up when I choose "compare data on hover" in the modebar. "Closest data on hover" works fine. When I choose compare data, it is completely unhinged and chooses random values from all over the plot with seemingly no rhyme or reason (though I'm sure there must be a pattern/explanation).

I'm wanting the user to be able to switch back and forth between closest and compare, because if I simply remove compare and set the default to y, it does not let the use to return to the initial hovermode after selecting closest from the modebar.

Here is my code. Any help would be appreciated.

dat <- data.frame(group1=(rep(letters[1:4], each=5)), 
           group2=rep(LETTERS[1:5], times=4),
           pct = c(rep(.2, times=5), 
                   c(.1, .1, .1, .3, .4), 
                   c(.2, .2, .2, .3, .1),
                   c(.3, .1, .2, .2, .2))
           )
dat %>%
  plot_ly() %>%
  add_bars(x=~pct, y=~group1,  color=~group2,
           customdata = ~group2,
           hovertemplate = paste0(
             "%{y:.2f%}<br>",
             "<extra>%{customdata}</extra>"
             )
           ) %>% 
      layout(yaxis = list(title = 'Group 1', 
                          autorange='reversed', 
                          categoryorder='trace'),
             xaxis = list(title = 'Percent', tickformat = ".0%"),
             barmode = 'stack', 
             hovermode = 'y',

             legend = list(traceorder = "normal")) %>%
      config(displaylogo = FALSE
             #,modeBarButtonsToRemove = list('hoverCompareCartesian'
             )

Solution

  • With the your graph settings, the two modes in the standard modebar are closest and y (<- that's compare). However, when you select closest and subsequently select y, Plotly's changing the hovermode to x instead.

    In the call to onRender, everytime you hover, the plot hovermode is validated. If the hovermode is neither closest, nor y, it changes it back to y.

    Your plot is unchanged. This uses the library htmlwidgets.

    dat %>%
      plot_ly() %>%
      add_bars(x = ~pct, y = ~group1,  color = ~group2,
               split = ~group2, customdata = ~group2,
               hovertemplate = paste0("%{y:.2f%}<br>", "<extra>%{customdata}</extra>")) %>% 
      layout(yaxis = list(title = 'Group 1', autorange = 'reversed', categoryorder = 'trace'),
             xaxis = list(title = 'Percent', tickformat = ".0%"),
             barmode = 'stack', hovermode = 'y', legend = list(traceorder = "normal")) %>%
      config(displaylogo = FALSE) %>% 
      htmlwidgets::onRender(         # <---- I'm new!
        "function(el, x) {
          el.on('plotly_hover', function(d) {   /* when hovering, check hovermode */
            if (el.layout.hovermode !== 'closest' && el.layout.hovermode !== 'y') {
              Plotly.relayout(el.id, {hovermode: 'y'}) /* fix hovermode, if needed */
            }
          });
        }")