0

I am using the formattable package for better-looking data frames in R. Let's say my data looks as follows:

df<-data.frame(Typ=c("Winners","","Losers",""),
               Time=c("1.","2.","1.","2."),
               Value=percent(c(0.22,0.18,0.78,0.82)),
               Change=percent(c(NA,-0.04,NA,0.04)))
formattable(df, list(
  Change=formatter(
    "span",
    style = x ~ style(color = ifelse(x < 0 , "red", "green")),
    x ~ icontext(ifelse(x < 0, "arrow-down", "arrow-up"), x)))
)

In this way everything works properly (in the RStudio preview and in HTML documents), but when I try to put this table in R Sweave documents it is not rendered.

I tried to use format_table which output is a knit_kable object or knit_print but neither worked.

CL.
  • 14,577
  • 5
  • 46
  • 73
Michał
  • 273
  • 1
  • 3
  • 13

1 Answers1

2

Loosely speaking, the question is: How to use formattable (or in general: a function that generates markdown/HTML output) in a RNW document?

Background

At first, I thougt the approach I suggested in this answer could be applied. It allows to embed markdown markup in a RNW document. But as it turned out, formattable produces a mix of markdown and HTML output – in this case, that approach won't work.

About 3 weeks ago, fdetsch posted a nice answer that shows how to embed leaflet (or in general: htmlWidgets) in RNW documents. This answer builds on and extends fdetsch's solution.

The solution (raw)

  • Install the webshot library from GitHub and, if necessary, devtools and htmlwidgets.

    devtools::install_github("wch/webshot")
    
  • Save the return value of formattable in an object (I used mytable).
  • Convert mytable to an htmlWidget: as.htmlwidget(mytable)
  • Save the widget to a temporary HTML file (should be in current working directory, see below):

    tmpHTML <-  basename(tempfile(fileext = ".html"))
    saveWidget(as.htmlwidget(mytable), file = tmpHTML)
    
  • Take a "screenshot" of the HTML file. For some reason, webshot produces empty image files when passing in a path instead of a filename.

    myImage <- "image.pdf"
    webshot(tmpHTML, file = myImage, cliprect = "viewport")
    
  • Add the figure to the document:

    knitr::include_graphics(myImage)
    

Issues and improvements

  • Issue 1: The image is too large for the widget. This should be solveable by passing selector = "#htmlwidget_container" instead of cliprect = "viewport" to webshot, but this didn't work in my tests. Alternatively, plot_crop(myImage, quiet = TRUE) can be added right after webshot to use knitr's cropping mechanism.
  • Issue 2: For some reason, the produced PDF is in black and white. When saving the screenshot as PNG, color will be preserved: myImage <- "image.png". However, the fonts will be blurry and I didn't find a way to increase the resolution (the webshot argument vwidth doesn't help). Therefore, I would say it is a trade-off: You can either have non-blurry fonts (PDF), or colors (PNG).
  • Issue 3: Messy temporary files. You can add unlink(tmpHTML) if you like.

Full example

\documentclass{article}
\begin{document}
<<>>=
library(htmlwidgets)
library(webshot)
library(formattable)

# Data from the question
df <- data.frame(
  Typ = c("Winners", "", "Losers", ""),
  Time = c("1.", "2.", "1.", "2."),
  Value = percent(c(0.22, 0.18, 0.78, 0.82)),
  Change = percent(c(NA, -0.04, NA, 0.04))
  )
mytable <- formattable(df, list(Change = formatter(
  "span",
  style = x ~ style(color = ifelse(x < 0 , "red", "green")),
  x ~ icontext(ifelse(x < 0, "arrow-down", "arrow-up"), x)
  )))

tmpHTML <-  basename(tempfile(fileext = ".html"))
saveWidget(as.htmlwidget(mytable), file = tmpHTML)

myImage <- "image.pdf"
webshot(tmpHTML, file = myImage, cliprect = "viewport")

plot_crop(myImage, quiet = TRUE)
knitr::include_graphics(myImage)

unlink(tmpHTML)
@
\end{document}
Community
  • 1
  • 1
CL.
  • 14,577
  • 5
  • 46
  • 73