粗略地说,问题是:如何在 RNW 文档中使用formattable(或一般而言:生成markdown/HTML 输出的函数)?
背景
起初,我认为我在this answer 中建议的方法可以应用。它允许在 RNW 文档中嵌入 markdown 标记。但事实证明,formattable 会产生 Markdown 和 HTML 输出的混合——在这种情况下,这种方法行不通。
大约 3 周前,fdetsch posted a nice answer 展示了如何在 RNW 文档中嵌入 leaflet(或一般情况下:htmlWidgets)。此答案基于并扩展了 fdetsch 的解决方案。
解决方案(原始)
-
从 GitHub 安装 webshot 库,如有必要,安装 devtools 和 htmlwidgets。
devtools::install_github("wch/webshot")
- 将
formattable的返回值保存在一个对象中(我用的是mytable)。
- 将
mytable 转换为htmlWidget:as.htmlwidget(mytable)
-
将小部件保存到临时 HTML 文件中(应该在当前工作目录中,见下文):
tmpHTML <- basename(tempfile(fileext = ".html"))
saveWidget(as.htmlwidget(mytable), file = tmpHTML)
-
对 HTML 文件进行“截图”。出于某种原因,webshot 在传入路径而不是文件名时会生成空图像文件。
myImage <- "image.pdf"
webshot(tmpHTML, file = myImage, cliprect = "viewport")
-
将图形添加到文档中:
knitr::include_graphics(myImage)
问题和改进
- 问题 1:图像对于小部件来说太大。这应该可以通过将
selector = "#htmlwidget_container" 而不是cliprect = "viewport" 传递给webshot 来解决,但这在我的测试中不起作用。或者,可以在 webshot 之后添加 plot_crop(myImage, quiet = TRUE) 以使用 knitr 的裁剪机制。
- 问题 2:由于某种原因,生成的 PDF 是黑白的。将屏幕截图保存为 PNG 时,将保留颜色:
myImage <- "image.png"。但是,字体会变得模糊,我没有找到提高分辨率的方法(webshot 参数 vwidth 没有帮助)。因此,我会说这是一种权衡:您可以使用非模糊字体 (PDF) 或颜色 (PNG)。
- 问题 3:凌乱的临时文件。喜欢的话可以加
unlink(tmpHTML)。
完整示例
\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}