Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving ggplot graph to PDF with fonts embedded in r

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.

like image 408
hmhensen Avatar asked Sep 01 '17 21:09

hmhensen


People also ask

How do I embed fonts in a PDF in R?

Solution in R: Use cairo_pdf() Produce vector graphics not via pdf() but via cairo_pdf() . This will embed the fonts automatically, and LaTeX will subsequently embed these fonts, too. This is the workflow that I recommend.

How do I export a ggplot graph?

You can either print directly a ggplot into PNG/PDF files or use the convenient function ggsave() for saving a ggplot. The default of ggsave() is to export the last plot that you displayed, using the size of the current graphics device.

What font does r use in ggplot?

R and ggplot can create fantastic graphs, but the default Arial/Helvetica font is too boring and standard. You can change the font used in a plot fairly easily three different ways: All of the built-in ggplot themes have a base_family argument for setting the overall font family for the plot.

Can you change ggplot font?

ggplot allows you to change the font of each part of the figure: you just need to know the correct option to modify in the theme. (For a full list of customizable components of the theme, see this documentation.)


3 Answers

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)

plot

# 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.

like image 140
mnm Avatar answered Sep 24 '22 13:09

mnm


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

Calibrified

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")
like image 37
Andrew Avatar answered Sep 24 '22 13:09

Andrew


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.

like image 29
Konrad Rudolph Avatar answered Sep 25 '22 13:09

Konrad Rudolph