如何在R Markdown中使用Cairo PNGs

20
使用Cairo保存R图形有许多优点(例如,请参见此处)。例如,在保存PDF时,cairo_pdf设备可以正确地嵌入自定义字体。
对于基于ggplot的图形,使用ggsave()很容易使用cairo_pdf图形设备:
library(ggplot2)

ugly_plot <- ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point() +
  labs(title = "Some data about cars") +
  theme_gray(base_family = "Papyrus")
ugly_plot

ggsave(ugly_plot, filename = "ugly_plot.pdf", 
       width = 4, height = 2.5, device = cairo_pdf)

使用 cairo_pdf 设备在 R Markdown 中与 knitr 一起使用也很容易——只需将 dev: cairo_pdf 添加到 YAML 前置内容:

---
title: "Cairo stuff"
output:
  pdf_document:
    dev: cairo_pdf
---

```{r make-ugly-plot, fig.width=4, fig.height=2.5}
library(ggplot2)

ugly_plot <- ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point() +
  labs(title = "Some data about cars") +
  theme_gray(base_family = "Papyrus")
ugly_plot
```

PDF输出

使用基于Cairo的PNG也有优势,因为Cairo可以正确处理DPI。如果您将一个通常保存的高DPI PNG放入Word或PowerPoint文件中,则图形的尺寸会被夸大且不准确。如果您将一个基于Cairo的相同高DPI PNG放入Word中,则尺寸是正确的:

奇怪的Word尺寸

使用ggsave()将ggplot输出保存为高分辨率的Cairo PNG很容易,但语法与保存为Cairo PDF略有不同。我们需要指定类型而不是设备:

ggsave(ugly_plot, filename = "ugly_plot.png", 
       width = 4, height = 2.5, dpi = 300, type = "cairo")

将该文件放入Word或PowerPoint中,一切都按高分辨率正确缩放。
当转换为HTML或Word时,这种尺寸误解会延续到R Markdown中。如果在编织时使用type = "cairo",那将是很好的,但是在R Markdown中复制dpi = 300,type = "cairo"则更加困难。Cairo库包括像Cairo :: CairoPNG()这样的设备,但是ggsave(...,type = "cairo")不使用此设备。它使用了R的标准PNG设备,但打开了Cairo支持。
通过将dpi = 300添加到块选项中,使图形具有高分辨率很容易,但我无法让knitr使用内置的PNG设备并启用type = cairo。我尝试在YAML元数据中天真地添加type:cairo,但毫不奇怪地它不起作用。knitr生成的PNG不使用Cairo,并且比预期的要大得多(在HTML和Word文档中则是巨大的)。
---
title: "Cairo stuff"
output:
  html_document: 
    self_contained: no  # to see resulting figure as a file
    dev: png
    type: cairo  # this doesn't do anything
---

```{r make-ugly-plot, fig.width=5, fig.height=3.5, dpi=300}
library(ggplot2)

ugly_plot <- ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point() +
  labs(title = "Some data about cars") +
  theme_gray(base_family = "Papyrus")
ugly_plot
```

总之,我正在寻找一种在knitr中使用与ggsave(..., filename = "blah.png", dpi = 300, type = "cairo")相同的输出的方法。有什么办法可以做到这一点吗?

---
title: "Something"
output:
  pdf_document:
    dev: cairo_pdf  # yay Cairo output
  html_document:  # What needs to go here?
    dev: png
    type: cairo
---

可能是由于dev.args而不仅仅是dev,就像我下面的回答一样吗? - rmflight
2个回答

27

使用knitr选项,而非YAML头。

可以使用knitr选项来更改特定设备的类型(是Yihui的推荐):

knitr::opts_chunk$set(dev.args = list(png = list(type = "cairo")))

或者,您可以根据输出有条件地执行它:

if (!knitr::is_latex_output()) {
  knitr::opts_chunk$set(dpi = 300, dev.args = list(type = "cairo"))
})

我现在已经在几份文档中使用了这个方法。 注意:我仅将其用于从 R 命令行执行rmarkdown::render(...)的文档。


啊!好主意!我不知道dev.args列表的事情! - Andrew
1
是的,它非常有用。我不知道/如何将其转换为yaml头中的选项。 - rmflight
3
我建议使用 dev.args = list(png = list(type = "cairo")),即只将 type = "cairo" 应用于 png 设备,而不影响其他图形设备。 - Yihui Xie
2
可以的 :) - Yihui Xie
1
我不记得最近与knitr有关图形设备的任何更改。请注意,如果capabilities('cairo') == TRUE,则type =“cairo”实际上是png()的默认设置,所以我很惊讶这个选项竟然有所帮助... - Yihui Xie
显示剩余4条评论

1
作为 @rmflight's answer 的替代方案,可以在 shell 包装器或使用可选参数 rmarkdown::render()Makefile 中实现这一点,而不是在每个文件的顶部使用一小段代码来编织 Rmarkdown 文件。
R -e 'rmarkdown::render("foo.Rmd", "pdf_document", output_file="foo.pdf", runtime = "static", output_options = list(dpi = 300, dev.args = list(type = "cairo")))'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接