Tuesday, October 31, 2017

Flexdashboard/plotly interaction results in odd scroll bar behavior

Leave a Comment

I have a bizarre and very frustrating problem. When I build plotly graphs within storyboards (from the flexdashboard package), I get a very annoying and totally unnecessary scroll bar in my legend. When someone tries to click one of the dots on or off, the scroll bar twitches and its practically impossible to click the thing. This scroll bar only appears when the tab with the plotly graph is not immediately visible during the load of the page - i.e. if the page loads with some other tab selected.

I can make the same graph outside of the storyboard, with no problems either in RStudio, or saving it as an htmlwidget and loading it in Chrome. But when I load my storyboard, either in RStudio or in Chrome, I get this annoying scrollbar. The scrollbar exists whether it's a vertical or horizontal legend.

ggplotly objects do not have this problem.

Here's an example of the unnecessary scroll bar. The ggplotly graph is fine, and the plotly one has the scrollbar.

--- title: "Untitled" output:    flexdashboard::flex_dashboard:     storyboard: true ---  ```{r setup, include=FALSE} library(flexdashboard) ```  ### ggplot  ```{r}  library(plotly)  carggplot <- ggplot(mtcars, aes(hp, mpg, fill = as.factor(carb))) +     geom_point() +     theme_bw()  ggplotly(carggplot) ```   ### plotly  ```{r} carsplot <- plot_ly(     data = mtcars,     x = ~hp,     y = ~mpg,     color = ~as.factor(carb),     type = "scatter",     mode = "markers"     )  carsplot ``` 

I have been unable to find any documentation on this issue, although I found a similar problem posted by someone using the python interface to plotly.

I'm looking for a way to either turn off the scroll bar completely (while keeping the legend), or some explanation of the scroll bar's twitchy behavior.

flexdashboard is 0.5, plotly is 4.7.1, R is 64 bit 3.4.1, Windows 7.

1 Answers

Answers 1

There are quite a lot of moving parts going on to answer your question. I won't cover each in detail but touch on them only briefly.

Background

  1. The plotly.js chart is behaving as designed when the length of the legend gets longer, it automatically inserts the scrollbar.

  2. This is not happening with the ggplotly chart because all the visual styling is coming from the ggplot object.

  3. flexdashboard is the culprit in this case because of how it is dynamically fitting the available space and informing plotly.js on how to render. It is worth noting this appears as SVG in the source html.

  4. The solution is then to manipulate the DOM in order to hide/remove/alter the problematic element.

Potential Solution

The solution I offer below is therefore a bit of a hack. A more permanent solution may be to lodge an issue with the good people at RStudio to see if any change could be made to the package, which addresses your problem.

If you add runtime: shiny to your YAML header, you can then make use of the excellent shinyjs package by Dean Attali. While I'm not an expert in this space, I've added a few lines to your MRE that remove <rect> elements from the SVG of class=scrollbar. Important to note you may need to alter the javascript I offer to be more specific and not remove elements you may wish to retain.

Update to MRE

Here is the Rmd code with comments where I've made changes.

--- title: "Untitled" output:    flexdashboard::flex_dashboard:     storyboard: true   runtime: shiny ---  ```{r setup, include=FALSE} library(shinyjs)        # add package, note runtime option above in YAML useShinyjs(rmd = TRUE)  # function needs to initialise js  library(flexdashboard) library(plotly) ```  ### ggplot  ```{r}  library(plotly)  carggplot <- ggplot(mtcars, aes(hp, mpg, fill = as.factor(carb))) +     geom_point() +     theme_bw()  ggplotly(carggplot) ```   ### plotly  ```{r} carsplot <- plot_ly(     data = mtcars,     x = ~hp,     y = ~mpg,     color = ~as.factor(carb),     type = "scatter",     mode = "markers"     )  carsplot  runjs("$svg.selectAll('rect[class=scrollbar]').remove();") # run plain js to remove elements ``` 

N.B. As I post this, I have had unreliable results and will dig in further.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment