When using R for data analysis and visualization, one may discover that the default parameter settings produce too small labels and titles for including in our articles and report. This tutorial provides a few tricks and guidelines for producing visualizations that are better readable. The tutorial is based on producing plots using R’s basic plot functions (see here for more info).
We will use as working code R Markdown’s example plot, which looks like this if we use the default values and styling and set the output size to 300 x 300 px:
plot(pressure)
Note that the axes labels and tick labels are rather small. There are
(at least) two different aspects that may change the size of the labels,
namely the size of the plot panel and the parameter cex
. We
will discuss both of these below, after illustrating how to save an R
plot to file.
All visualizations in this output file are set to a height of 300px to facilitate comparison with the original plot.
By default, the plot panel is set to 7 x 7 inches. When we would reduce the size of the plot panel but keep the font sizes constant, the labels automatically will appear larger in the resulting plot.
However, when working in R Studio we cannot change the size of the plot when we send the plot to the plot pane. Instead, we may want to have the plots appearing just after the code blocks in our R Markdown /R Notebook reports, or send the plot to a separate plot device. Both options are explained below.
Open your R Markdown or R Notebook file in R Studio and click on the wheel right to the knit symbol , and select the option “Chunk output inline” from the drop-down menu. With this option selected instead of “Chunk output in Console” the plots will appear below the code blocks in the report rather than in the R Studio plot pane.
Alternatively – for example when not working in R Studio – you could add the following lines to the header:
editor_options:
chunk_output_type: console
Now we have made sure that the plots will appear inline, following
the code blocks, we can change the size of the plots in the settings of
our code block. I prefer a default plot panel of 4 x 4 inches (instead
of 7 x 7 inches). Add fig.width=4, fig.height=4
to the
settings of the code block:
```{r myplot, fig.width=4, fig.height=4}
This result in the following plot (with `out.width=“300px” added to ensure the same size as the original plot):
plot(pressure)
One additional note: one could change the default figure size in the
setup
code block at the top, by adding the default figure
dimensions to the knitr chunk options, as illustrated here:
::opts_chunk$set(echo = TRUE, fig.width=4, fig.height=4) knitr
When you are not using R Markdown or R Notebook, or when you want to save the plots as separate files, you may want to send the plot to a separate plot device.
The following code starts a new plot device. You may want to include
the argument noRStudioGD
when working in R Studio:
dev.new(width=4, height=4, noRStudioGD = TRUE)
plot(pressure)
When working on Mac OS X, a quartz device is more convenient (but
this does not work under Windows or Linux). The quartz device can be
easily saved as png or pdf using quartz.save
function.
quartz(,4,4)
plot(pressure)
# save as png:
quartz.save("myplot.png", dpi=300)
# or as pdf:
quartz.save("myplot.pdf", type='pdf')
On all platforms it is possible to write the plots directly to an output file with specific dimensions. Here are a two examples:
# note that for png(), jpeg(), bmp(), and tiff(),
# the default units are pixels 'px'
png("myplot.png", width = 4, height = 4, units = "in", res=300)
plot(pressure)
dev.off()
# for pdf the width and height are provided in inches:
pdf("myplot.pdf", width=4, height=4)
plot(pressure)
dev.off()
In addition to changing the file size, we can also change the font
sizes of titles, axis labels, axis annotations, and subtitles using the
parameter cex
. It is also possible to set different values
for different types of labels. See help(par)
for more
information.
par(cex=1.2)
plot(pressure)
Note that changing the font sizes may require some further optimization of the plots, because some labels won’t fit anymore. We will illustrate some options in the following section.
To increase the readability of plots, it may help to reduce the
number of axis annotations. And this is also useful when the labels do
not fit anymore, because larger font sizes were used. We can specify the
axis annotations directly using the function axis()
.
# default margins:
par()$mar
## [1] 5.1 4.1 4.1 2.1
# reduce top-margin:
par(cex=1.2, mar=c(5.1,4.1,2.1,2.1))
plot(pressure,
pch=16, type='o',
axes=FALSE)
axis(1, at=c(0,100,max(pressure$temperature)), las=1)
axis(2, at=c(0,100,max(pressure$pressure)), las=1)
This can be achieved directly using the function
emptyPlot
for setting up an empty plot grid (see https://jacolienvanrij.com/Tutorials/plotfunctions.html).
library(plotfunctions)
par(cex=1.2, mar=c(5.1,4.1,2.1,2.1))
emptyPlot(max(pressure[,1]), max(pressure[,2]),
xlab="Temperature", ylab="Pressure",
xmark=c(0, 100, max(pressure[,1])),
ymark=c(0,100,max(pressure[,2])), las=1)
points(pressure, type='o', pch=16, col=1, xpd=TRUE)
Often there is not much space available for including all the figures
we would like to include. Therefore, it is useful to combine multiple
plots into one figure. The functions mfrow
and
layout
allow for combining plots:
mfrow
defines the rows and columns to evenly divide the
figure device in equally sized plot regions.layout
specifies the plot regions using a matrix,
allowing for different plot sizes.Both plots below have a height of 200px – to illustrate how one could squeeze plots into a small space. But note that the width of the two plots differs (600px and 300px respectively).
par(mfrow=c(1,3), cex=1.2)
plot(density(pressure$temperature),
main="Temperature", bty='n', lwd=2)
plot(density(pressure$pressure),
main="Pressure", bty='n', lwd=2)
plot(pressure,
main="Pressure by temperature",
bty='n', pch=16, type='o')
layout(matrix(c(3,3,1,
3,3,2), ncol=3, byrow=TRUE))
# changing the margins to optimize the space
# but making sure that the top margin aligns
# with the large panel:
par(cex=1.6, mar=c(2.1,1.1,4.1,1.1))
<- density(pressure$pressure)
d1
emptyPlot(range(d1$x), max(d1$y),
xmark=round(range(pressure$pressure),2), ymark=TRUE)
title(main="b. pressure:", adj=0)
rug(pressure$pressure, side=1)
lines(d1$x, d1$y, lwd=2, xpd=TRUE)
# changing the margins to optimize the space
# but making sure that the bottom margin
# aligns with the large panel:
par(cex=1.6, mar=c(4.1,1.1,2.1,1.1))
<- density(pressure$temperature)
d2
emptyPlot(range(d2$x), max(d2$y),
xmark=range(pressure$temperature), ymark=TRUE)
title(main="c. temperature:", adj=0)
rug(pressure$temperature, side=1)
lines(d2$x, d2$y, lwd=2, xpd=TRUE)
par(cex=1.6, mar=c(4.1,4.1,4.1,4.1))
emptyPlot(max(pressure$temperature), c(-10,10),
xmark=c(0, 100, 360),
ymark=sort(c(0,round(range(log(pressure$pressure)),2))), las=1,
xlab="Temperature", ylab="log Pressure")
mtext("a. pressure data:\nVapor Pressure of Mercury",
side=3, line=0.5, cex=1.25*par()$cex, font=2, adj=0)
lines(pressure$temperature, log(pressure$pressure),
col=alpha(1), lwd=0.5)
points(pressure$temperature, log(pressure$pressure),
pch=16, col=1)
Click on the plot to go back to the code.
For comparison we have changed
the point style and added a line to all of the plots below. This
illustrates that both changing the plot dimensions and the parameter
cex
also affect the size of the points, and the whitespace
around the plot. The plots are scaled to 200 x 200 px each.