2.10 HTML 小组件

尽管 R 的最大优势之一是数据可视化,但仍然有大量 JavaScript 库可用于更丰富的数据可视化。这些库可以被用来构建能够在 Web 浏览器中轻松呈现的可交互式应用,因此用户不必安装其它任何软件包就能够查看可视化效果。将这些 JavaScript 库引入 R 的一种方法是通过 htmlwidgets 软件包 (Vaidyanathan et al. 2023)

HTML 小组件能够呈现为独立的网页(就像 R plot 一样),或者嵌入 R Markdown 文档和 Shiny 应用中。它们最初仅被设计用于 HTML 输出,并且需要使用 JavaScript,因此它们不能用于非 HTML 输出格式,例如 LaTeX/PDF。在 knitr v1.13 之前,如果你试图在非 HTML 输出格式中呈现 HTML 小组件,你将会收到错误消息。从 knitr v1.13 开始,HTML 小组件将会自动被呈现为通过 webshot 软件包 (Chang 2023) 截取的屏幕截图。当然,你需要安装有 webshot 软件包。另外,你必须安装 PhantomJS (http://phantomjs.org),因为 webshot 使用它来捕捉屏幕截图。webshot 和 PhantomJS 都能够在 R 中自动安装:

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

函数 install_phantomjs() 适用于 Windows、OS X 和 Linux。如果你熟悉修改系统环境变量 PATH,也可以选择自己下载和安装 PhantomJS。

knitr 在代码块中检测到 HTML 小组件对象时,它要么在当前输出格式为 HTML 时正常呈现小组件,要么在输出格式不是 HTML 时将小组件保存为 HTML 页面,并调用 webshot 来捕获 HTML 页面的屏幕图像。下面是从 DT 软件包 (Xie, Cheng, and Tan 2023) 创建的表格的示例:

DT::datatable(iris)

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

如果你现在以网页的形式阅读本书,应该能看到由上述代码块生成的交互式表格:你可以对列进行排序并在表格中进行搜索。如果你正在阅读本书的非 HTML 版本,应该能看到这个表格的屏幕截图。由于真实的 Web 浏览器和 PhantomJS 的虚拟浏览器之间的差异,屏幕截图可能与 Web 浏览器中呈现的实际小组件略有不同。

有许多与屏幕捕获相关的 knitr 区块选项。第一,如果你对自动截图的质量不满意,或者想要一个特定状态的小组件的屏幕截图(例如在你单击并排序表的某一列之后),可以手动捕获屏幕图像,并通过区块选项 screenshot.alt(备选屏幕截图 (alternative screenshots))提供自己的屏幕截图。该选项使用图像的路径获得图片。如果一个区块中有多个小组件,则可以提供一个图像路径的向量。当该选项存在时,knitr 将不再调用 webshot 自动截图。

第二,有时你可能希望强制 knitr 使用静态屏幕截图,而不是在 HTML 页面上呈现实际的小组件。在这种情况下,你可以设置区块选项 screenshot.force = TRUE。小组件将始终呈现为静态图像。请注意,你仍然可以选择使用自动或自定义的屏幕截图。

第三,webshot 有一些控制自动屏幕截图的选项,你可以通过区块选项 screenshot.opts 来进行设置,该选项接收一个类似 list(delay = 2, cliprect = 'viewport') 的列表。有关可用选项的完整列表,请查阅帮助页面 ?webshot::webshot,而其中一些选项的效果说明请见软件包介绍。这里的 delay 选项对于需要很长时间进行渲染的小组件来说很重要:delay 指定了 PhantomJS 在截图前等待的秒数。如果看到不完整的屏幕截图,可能需要指定更长的延迟时间(默认值为 0.2 秒)。

第四,如果你觉得捕获屏幕截图很慢,或者不想每次执行代码块时都这样做,可以使用区块选项 cache = TRUE 来缓存区块。缓存对于 HTML 和非 HTML 输出格式都适用。

屏幕截图的表现类似于普通的 R plot,因为许多与图形相关的区块选项也适用于屏幕截图,包括 fig.widthfig.heightout.widthfig.cap 等。因此你可以在输出文档中指定屏幕截图的大小,并为其指定图片标题。可以通过区块选项 dev 指定自动截图的图片格式,可能的值为 pdfpngjpeg。PDF 输出的默认值为 pdf,其他类型输出的默认值为 png。请注意,pdf 可能不如 png 那样可靠:有时 HTML 页面上的某些元素无法呈现到 PDF 屏幕截图中,因此你甚至可能希望在 PDF 输出中使用 dev = 'png'。不过能否正常使用取决于 HTML 小部件的具体情况,在确定哪种格式更加合适之前,你可以对 pdfpng(或 jpeg)都加以尝试。

参考文献

Chang, Winston. 2023. Webshot: Take Screenshots of Web Pages. https://wch.github.io/webshot/.
Vaidyanathan, Ramnath, Yihui Xie, JJ Allaire, Joe Cheng, Carson Sievert, and Kenton Russell. 2023. Htmlwidgets: HTML Widgets for r. https://github.com/ramnathv/htmlwidgets.
Xie, Yihui, Joe Cheng, and Xianying Tan. 2023. DT: A Wrapper of the JavaScript Library DataTables. https://github.com/rstudio/DT.