For various functions in my cowplot package, I need to be able to convert ggplot2 plots into grobs, via the ggplotGrob()
function. A known problem in this context is that ggplotGrob()
requires an open graphics device, and depending on the graphics device currently open the call to this function creates a spurious empty plot. For examples of this problem, see ggplot2 issue #809 or most recently cowplot issue #82.
It is possible to fix the problem by opening a null pdf device. See the following example:
library(ggplot2)
# make a plot
p <- qplot(1:10, 1:10)
pdf(NULL) # open NULL pdf device to absorb empty page
grob <- ggplotGrob(p) # convert plot
dev.off()
Now here is my question: Is the sequence pdf(NULL); ggplotGrob(...); dev.off()
safe to use in an R package, or are there scenarios where I cannot assume that pdf(NULL)
will be successful/possible? If such scenarios exist, are there other graphics devices I can assume exist, and can I test when I'm in a situation where pdf(NULL)
would not be a good idea? Alternatively, what would be the best way to make the code tolerant to potential failure of the pdf(NULL)
call?
Update: See also this SO post which discusses the problem of blank pages but doesn't go into much detail of what safe methods there may be to work around the problem.
Update 2: This comment states that some R installs don't have a functioning pdf()
. So it seems that it is indeed not always possible to open a pdf NULL device. The question then is: How can I work around this problem?
I looked into this briefly when you first posted it. As "pdf" is not in capabilities()
, it "should" always work. Or so one hopes. And I tried a to construct a counter example without X11 access---and hence no font metrics---but failed.
Now, I still see two work-arounds that should always help you:
Use the virtual framebuffer device in your R call; this is eg how we run the reverse depends checks "head-less". The call becomes something like this set of lines:
xvfb-run-safe --server-args="-screen 0 1024x768x24" R CMD ...whatyouneed...
Just say no to pdf()
and use cairo()
instead which is a) known to work headlessly and b) provided by two different packages.