使用嵌入在 r 中的字体将 ggplot 图保存为 PDF

Saving ggplot graph to PDF with fonts embedded in r

我一直在遵循我在网上找到的关于将 ggplot 图保存为 PDF 的建议,但我不能完全让它工作。我正在使用 extrafont 包在 Calibri 中生成带有文本的图表,但我的图表打印出来时没有文本。我不知道我错过了什么。我在我的过程中找不到任何错误。希望其他人可以提供帮助。

这是我使用的代码和过程:

library(extrafont)
font_import(pattern="[C/c]alibri")
loadfonts(device="win")

我这时候安装了GhostScript。然后运行下面设置GhostScript位置。

Sys.setenv(R_GSCMD = "C:\Program Files\gs\gs9.21\bin\gswin64c.exe")

然后我使用 ggplot 制作了一个名为 "chart" 的图表。该图表在 RStudio 中看起来很完美,但在 PDF 中却不是。

ggsave("chart.pdf", plot = chart, width = 6, height = 4)

我在这里收到警告,显示如下内容:

In grid.Call(C_textBounds, as.graphicsAnnot(x$label), ... : font family 'Calibri' not found in PostScript font database

显然,这些警告应该发生?然后我运行...

embed_fonts("chart.pdf", outfile="chart_embed.pdf")

不幸的是,经过这一切,最终的 "embed" 图表看起来与生成的原始图表没有什么不同,两者都没有任何文本。

如果有帮助,这里是生成图表的代码:

a <- ggplot(data=stats, aes(x=Date))
Chart <- a + geom_point(aes(y=NevadaTotalNonfarmAllEmployees)) + 
      xlab("Date") + 
      ylab("Nonfarm Jobs") + 
      ggtitle("Nevada Total Jobs") + 
      theme(axis.title.x = element_text(size=15, family = "Calibri"),
            axis.title.y = element_text(size=15, family = "Calibri"),
            axis.text.x = element_text(size=10, family = "Calibri"),
            axis.text.y = element_text(size=10, family = "Calibri"),
            plot.title = element_text(hjust=0.5, size=20, family = "Calibri"))

我一直在绞尽脑汁想弄明白这个问题。或者可能不是代码而是其他东西?无论哪种方式,感谢您的帮助。

我想你错过了初始化步骤 font_import()。请注意,执行此命令可能需要更长的时间。

首先,您可以使用命令 windowsFonts() 查看您可以使用的字体。我的图形设备中的当前字体是;

$serif
[1] "TT Times New Roman"

$sans
[1] "TT Arial"

$mono
[1] "TT Courier New"

此后,您可以导入 extrafont 库和 loadfonts(device = "win")。我还建议在 R 控制台而不是 RStudio 中执行这些命令。我建议这样做是因为当您在 RStudio 中使用 font_import() 导入字体时,它可能不会显示 y/n 提示符。

下面我提供了一个最小的可重现示例;

    library(ggplot2)
    library(extrafont)
    font_import()
    # tell where ghostscript is located. This is required for saving the font in pdf
    Sys.setenv(R_GSCMD = "C:\Program Files\gs\gs9.21\bin\gswin64c.exe") # I have installed 64-bit version of GhostScript. This is why I've used gswin64c.exe. If you have installed 32-bit version of GhostScript, use gswin32c.exe. Failure to specify the correct installed GhostScript will yield error message, "GhostScript not found"
    # create a plot object
p <- ggplot(mtcars, aes(x=wt, y=mpg)) + 
  geom_point()+
  ggtitle("Fuel Efficiency of 32 Cars")+
  xlab("Weight (x1000 lb)") + ylab("Miles per Gallon") +
  theme_bw()+
  theme(text=element_text(family="ArialMT", size=14))
# show the plot
print(p)

# save the plot as pdf  
ggsave("figures//ggplot_arialmt.pdf", p, width=20, height=20, 
   device = "pdf", units = "cm")

备注

只有 ArialMT 字体似乎适用于 ggsave()。请参阅此 SO post. Using any other font for saving to pdf, renders the figure with characters on top of another. This is also an open issue ggsave 并且自 2013 年以来一直没有得到答复。

我发现使用 pdfFonts (and/or postscriptFonts) 显式注册字体更安全。

该文档包含一个示例,但也可以查看我的 fonts module。有了这个,注册一个新字体就像写

一样简单
fonts$register_font('Calibri')

在内部,这会使用 Type1Font 创建字体规范,确保名称设置正确,并调用 pdfFonts.

它还确保存在完整的字体规格集(使用 extrafont::ttf_import 完成)。

这种方式比使用 font_import 为所有字体生成字体规格要快得多,而且它给了您更多的控制权。

这里有几个问题:(1) 将字体加载到 R 中,以及 (2) 使用可以正确处理自定义嵌入字体的 PDF 编写库。

首先, 正如其他人提到的,在 Windows 上,您通常需要 运行 extrafont::font_import() 来注册许多系统字体R,但它可能需要一段时间,并且可能会错过 TTF 和其他类型的字体。解决此问题的一种方法是使用 windowsFonts(name_of_font_inside_r = windowsFont("Name of actual font")) 将字体动态加载到 R 中,而不加载完整的数据库,如下所示:

windowsFonts(Calibri = windowsFont("Calibri"))

这使得 R 中只能访问一种字体。您可以查看 windowsFonts()。每次脚本 运行 时,您都必须 运行 这一行——字体加载不会跨会话持续。字体加载完成后就可以正常使用了:

library(tidyverse)
df <- data_frame(x = 1:10, y = 2:11)

p <- ggplot(df, aes(x = x, y = y)) +
  geom_point() +
  labs(title = "Yay Calibri") +
  theme_light(base_family = "Calibri")
p

其次,R 在Windows 和 macOS 上的内置 PDF 写入设备不能很好地处理字体嵌入。然而,R 现在包括 Cairo 图形库,它可以很好地嵌入字体。你可以在ggsave()中指定Cairo设备来使用它,这比处理GhostScript更容易:

ggsave(p, filename = "whatever.pdf", device = cairo_pdf, 
       width = 4, height = 3, units = "in")