Plotly to static image for pdf or word

How to embed a interactive plotly vis in pdf/word output

I recently used plotly to produce interactive visualisations in html output. However, knitting the RMarkdown into pdf (or Word) resulted in an error. Moreover, my idea is to have one Rmd and toggle between the outputs to save on coding.

The solution entails

  • installation of webshot package and phantomjs
  • using a deprecated plotly function
  • using a htmlWidget & webshot based solution

Prep - install webshot and phantomjs

That should be a no-brainer. install.packages(...) is your friend here.

If you run R/RStudio on a Windows machine with no admin rights (like I do at work), download phantomjs. Then locate phantomjs.exe. This should sit somewhere in Users/username/App/Roaming/PhantomJS on your computer. Move the exe to a folder you have write/exe rights over. Edit your environmental PATH variable to point to the folder you added phantomjs.exe.

You can check whether your R/RStudio instance sees phantomjs.exe by using webshot::is_phantomjs_installed(). Troubleshoot the location and path definition until the call delivers a TRUE!

plotly::export()

Plotly had a handy function. At the time of writing (February 2021) the call to plotly::export() just throws a warning. However, it is anticipated that this will no longer work one day.

htmlWidgets & webshot()

This power-duo can be used to

  • save the interactive plot as an html page
  • make a snapshot of this html and integrate a static (here png file)

utility function

plotly::export()

plotly_to_static <- function(.plot = last_plot(), .debug = FALSE){
  # turn object variable name into character
  plot_name <- deparse(substitute(.plot))
  # create a folder for figures
  if(!dir.exists("./figures")){dir.create("./figures")}
  # export is deprecated, need to find other solution
  if(.debug == TRUE){
    plotly::export(.plot, file = paste0("./figures/", plot_name, ".png") )
  }else{
    suppressWarnings(
      plotly::export(.plot, file = paste0("./figures/", plot_name, ".png") )
                     )
  }
}

webshots

# save plot as a html widget
htmlwidgets::saveWidget(widget = piechart, file = "hc.html")
# call webshot to make a snapshot and embed the graph
webshot::webshot(url = "hc.html", file = "hc.png", delay = 1, zoom = 4, vheight = 500)

Final Words

I use this approach to toggle between html and pdf output without having to code another graphic for the static output.

  • first create the plotly plot (there is a handy wrapper for ggplots: ggplotly(your-ggplot))
  • use the eval chunk option to detect whether the output is html or non-html (e.g. pdf): `{r pdf_output_here, eval=!knitr::is_html_output()} and use aforementioned function.
  • then create a code-chunk for the html output with eval=knitr::is_html_output and just call the element (e.g. plotly graph, DT)

Feel free to do so too. If you can think of a more elegant way to do this, please let me know. Thanks!

Avatar
Rainer Koelle
Head Operational ANS Performance

I am a pilot, air traffic controller, and engineer, and work for EUROCONTROL, Performance Review Unit. My research interests revolve around operational air navigation and/or air transportation system performance applying a mix of data science and system analytics. In a side role I am also interested in time-critical decision making applied in aviation security and critical infrastructure protection.

Related

Next
Previous