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.

Changing the size of the 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.

… when using R Markdown / R Notebook

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:

knitr::opts_chunk$set(echo = TRUE, fig.width=4, fig.height=4)

… using other plot devices

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()

Changing the font sizes

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.

Further optimization

Reducing axis annotations

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)

Combining multiple plots in one figure

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))

d1 <- density(pressure$pressure)

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))

d2 <- density(pressure$temperature)

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)

Comparison of results

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.