Transitioning from an interactive plot in R to a publication-ready plot can create a messy script file with lots of statements and use of global variables. This post outlines an approach that I have used to simplify the process and keeps code readable.
The usual way of plotting to a file is to open a plotting device (such
as pdf
or png
) run a series of commands that generate plotting
output, and then close the device with dev.off()
. However, the way
that most plots are developed is purely interactively. So you start
with:
1 2 3 4 5 6 7 8 9 |
|
Then to convert this into a figure for publication we copy and paste this between the device commands:
1 2 3 |
|
This leads to bits of code that often look like this:
1 2 3 4 5 6 7 8 9 10 11 |
|
which is all pretty ugly. On top of that, we’re often making a bunch
of variables that are global but are really only useful in the context
of the figure (in this case the fit
object that contains the trend
line). An arguably worse solution would be simply to duplicate the
plotting bits of code.
A partial solution:
The solution that I usually use is to make a function that generates the figure.
1 2 3 4 5 6 7 8 9 10 11 |
|
Then you can easily see the figure
1
|
|
or
1 2 |
|
and you can easily generate plots:
1 2 3 |
|
However, this still gets a bit unweildly when you have a large number of figures to make (especially for talks where you might make 20 or 30 figures).
1 2 3 4 5 6 7 |
|
A full solution
The solution I use here is a little function called to.pdf
:
1 2 3 4 5 6 7 |
|
Which can be used like so:
1 2 |
|
A couple of nice things about this approach:
- It becomes much easier to read and compare the parameters to the plotting device (width, height, etc).
- We’re reduced things from 6 repetitive lines to 2 that capture our intent better.
- The to.pdf function demands that you put the code for your figure in a function.
- Using functions, rather than statements in the global environment, discourages dependency on global variables. This in turn helps identify reusable chunks of code.
- Arguments are all passed to
pdf
via...
, so we don’t need to duplicatepdf
’s argument list in our function. - The
on.exit
call ensures that the device is always closed, even if the figure function fails.
For talks, I often build up figures piece-by-piece. This can be done like so (for a two-part figure)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Now – if run with as
1
|
|
just the data are plotted, and if run as
1
|
|
the trend line and legend are included. Then with the to.pdf
function, we can do:
1 2 |
|
which will generate the two figures.
The general idea can be expanded to more devices:
1 2 3 4 5 6 7 |
|
where we would do:
1 2 |
|
Note that with this to.dev
function we can rewrite the to.pdf
function more compactly:
1 2 |
|
Or write a similar function for the png
device:
1 2 |
|
(As an alternative, the dev.copy2pdf
function can be useful for
copying the current contents of an interactive plotting window to a
pdf).