2.10 HTML widgets

Although one of R’s greatest strengths is data visualization, there are a large number of JavaScript libraries for much richer data visualization. These libraries can be used to build interactive applications that can easily render in web browsers, so users do not need to install any additional software packages to view the visualizations. One way to bring these JavaScript libraries into R is through the htmlwidgets package (Vaidyanathan et al. 2020).

HTML widgets can be rendered as a standalone web page (like an R plot), or embedded in R Markdown documents and Shiny applications. They were originally designed for HTML output only, and they require the availability of JavaScript, so they will not work in non-HTML output formats, such as LaTeX/PDF. Before knitr v1.13, you will get an error when you render HTML widgets to an output format that is not HTML. Since knitr v1.13, HTML widgets will be rendered automatically as screenshots taken via the webshot package (Chang 2019). Of course, you need to install the webshot package. Additionally, you have to install PhantomJS (http://phantomjs.org), since it is what webshot uses to capture screenshots. Both webshot and PhantomJS can be installed automatically from R:

install.packages('webshot')
webshot::install_phantomjs()

The function install_phantomjs() works for Windows, OS X, and Linux. You may also choose to download and install PhantomJS by yourself, if you are familiar with modifying the system environment variable PATH.

When knitr detects an HTML widget object in a code chunk, it either renders the widget normally when the current output format is HTML, or saves the widget as an HTML page and calls webshot to capture the screen of the HTML page when the output format is not HTML. Here is an example of a table created from the DT package (Xie, Cheng, and Tan 2020):

DT::datatable(iris)

FIGURE 2.5: A table widget rendered via the DT package.

If you are reading this book as web pages now, you should see an interactive table generated from the above code chunk, e.g., you may sort the columns and search in the table. If you are reading a non-HTML version of this book, you should see a screenshot of the table. The screenshot may look a little different with the actual widget rendered in the web browser, due to the difference between a real web browser and PhantomJS’s virtual browser.

There are a number of knitr chunk options related to screen-capturing. First, if you are not satisfied with the quality of the automatic screenshots, or want a screenshot of the widget of a particular state (e.g., after you click and sort a certain column of a table), you may capture the screen manually, and provide your own screenshot via the chunk option screenshot.alt (alternative screenshots). This option takes the paths of images. If you have multiple widgets in a chunk, you can provide a vector of image paths. When this option is present, knitr will no longer call webshot to take automatic screenshots.

Second, sometimes you may want to force knitr to use static screenshots instead of rendering the actual widgets even on HTML pages. In this case, you can set the chunk option screenshot.force = TRUE, and widgets will always be rendered as static images. Note that you can still choose to use automatic or custom screenshots.

Third, webshot has some options to control the automatic screenshots, and you may specify these options via the chunk option screenshot.opts, which takes a list like list(delay = 2, cliprect = 'viewport'). See the help page ?webshot::webshot for the full list of possible options, and the package vignette vignette('intro', package = 'webshot') illustrates the effect of these options. Here the delay option can be important for widgets that take long time to render: delay specifies the number of seconds to wait before PhantomJS takes the screenshot. If you see an incomplete screenshot, you may want to specify a longer delay (the default is 0.2 seconds).

Fourth, if you feel it is slow to capture the screenshots, or do not want to do it every time the code chunk is executed, you may use the chunk option cache = TRUE to cache the chunk. Caching works for both HTML and non-HTML output formats.

Screenshots behave like normal R plots in the sense that many chunk options related to figures also apply to screenshots, including fig.width, fig.height, out.width, fig.cap, and so on. So you can specify the size of screenshots in the output document, and assign figure captions to them as well. The image format of the automatic screenshots can be specified via the chunk option dev, and possible values are pdf, png, and jpeg. The default for PDF output is pdf, and it is png for other types of output. Note that pdf may not work as faithfully as png: sometimes there are certain elements on an HTML page that fail to render to the PDF screenshot, so you may want to use dev = 'png' even for PDF output. It depends on specific cases of HTML widgets, and you can try both pdf and png (or jpeg) before deciding which format is more desirable.

References

Chang, Winston. 2019. Webshot: Take Screenshots of Web Pages. https://github.com/wch/webshot/.

Vaidyanathan, Ramnath, Yihui Xie, JJ Allaire, Joe Cheng, Carson Sievert, and Kenton Russell. 2020. Htmlwidgets: HTML Widgets for R. https://github.com/ramnathv/htmlwidgets.

Xie, Yihui, Joe Cheng, and Xianying Tan. 2020. DT: A Wrapper of the Javascript Library Datatables. https://github.com/rstudio/DT.