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.
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.
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.
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.
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.)
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.
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")
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With