Saving ggplot graph to PDF with fonts embedded in r

北战南征 提交于 2020-01-01 05:44:06

问题


I've been following advice I've found online for saving a ggplot graph to PDF but I can't quite get it to work. I'm using the extrafont package to produce charts with text in Calibri, but my charts are printing out with no text. I don't know what I'm missing. I can't find any mistakes in my process. Hopefully, someone else can help.

Here's the code and process I used:

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

I installed GhostScript at this time. Then ran the following to set the GhostScript location.

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

I then produced a chart using ggplot called "chart". The chart looked perfect in RStudio, but not in PDF.

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

Here I get warnings showing stuff like this:

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

Apparently, these warnings are supposed to happen? Then I run...

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

Unfortunately, after all this, the final "embed" chart looks no different than the original chart produced, neither of which have any text.

In case it helps, here's the code to produce the chart:

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"))

I've been pulling my hair out trying to figure this out. Or maybe it's not the code but something else? Either way, thanks for any assistance.


回答1:


There are a couple issues at play here: (1) loading fonts into R and (2) using a PDF-writing library that works correctly with custom embedded fonts.

First, as others have mentioned, on Windows you generally need to run extrafont::font_import() to register many of your system fonts with R, but it can take a while and can miss TTF and other types of fonts. One way around this is to load fonts into R on the fly, without loading the full database, using windowsFonts(name_of_font_inside_r = windowsFont("Name of actual font")), like so:

windowsFonts(Calibri = windowsFont("Calibri"))

This makes just that one font accessible in R. You can check with windowsFonts(). You have to run this line each time the script is run—the font loading doesn't persist across sessions. Once the font has been loaded, you can use it normally:

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

Second, R's built-in PDF-writing device on both Windows and macOS doesn't handle font embedding very well. However, R now includes the Cairo graphics library, which can embed fonts just fine. You can specify the Cairo device in ggsave() to use it, which is easier than dealing with GhostScript:

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



回答2:


I’ve found it safer to explicitly register fonts using pdfFonts (and/or postscriptFonts).

The documentation contains an example but also take a look at my fonts module. With this, registering a new font is as easy as writing

fonts$register_font('Calibri')

Internally, this creates a font specification using Type1Font, ensures that names are set correctly, and invokes pdfFonts.

It also ensures that the complete set of font metrics to exist (which is done using extrafont::ttf_import).

This way is considerably faster than generating font metrics for all fonts using font_import, and it gives you more control.




回答3:


I think you missed the initialization step font_import(). Be forewarned, executing this command can take a bit longer time.

First, you can see what fonts you have available with the command windowsFonts(). The current fonts in my graphing device are;

$serif
[1] "TT Times New Roman"

$sans
[1] "TT Arial"

$mono
[1] "TT Courier New"

Thereafter, you can import the extrafont library and the loadfonts(device = "win"). I also recommend to execute these commands in the R console and not in RStudio. I suggest this because when you are importing the fonts using font_import() in RStudio, it may not show the y/n prompt.

Below I provide a minimum reproducible example;

    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")

Note

Its only the ArialMT font that seems to work with ggsave(). See this 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 for ggsave and has not been answered since 2013.



来源:https://stackoverflow.com/questions/46008304/saving-ggplot-graph-to-pdf-with-fonts-embedded-in-r

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!