## 4.3 Customising plots

All of the plots we’ve created so far in this Chapter are more than suitable for exploring your data. If however, you’d like to make them a little prettier (for your thesis, publication or even your own amusement) you’ll need to invest some time learning how to customise your plots. The good news is that the base R graphics system allows you to change almost any aspect of your plot. There are however a couple of things to bear in mind. Firstly, although many of the approaches we introduce in this section will work with most base R plotting functions, there’s no true consistency between functions. What works with the `plot()`

function isn’t guaranteed to necessarily work with the `boxplot()`

function. This can be a little frustrating to begin with but gets easier the more experience you gain. If you crave a little more consistency take a look at Chapter 5 where we introduce the excellent `ggplot2`

package. Secondly, when you start customising plots you’re confronted with a huge number of options and arguments to try and remember. This isn’t necessarily a bad thing as this is what makes base R graphics so flexible but it’s a lot to take in. Often a quick Google or peek at the relevant help pages will jog your memory. Thirdly, learning how to customise plots in base R isn’t just about what code you need to use, it’s also about learning the process of building a plot. We often start with a basic layout of our plot and then add layers of complexity until we achieve the desired results. This requires a little experience (and trial and error), but again becomes easier with practice. Lastly, this section covers the basics of how to customise base R graphics and most (if not all) of these approaches will not work for plots created with the `lattice`

graphics system.

### 4.3.1 Customising with arguments

Let’s return to the basic plot we made previously in this Chapter. This was a simple scatterplot to examine the relationship between the `shootarea`

and `weight`

variables in the `flowers`

data frame.

Whilst this plot is adequate for data exploration it’s not going to cut the mustard if we want to share it with others. At the very least it could do with a better set of axes labels, more informative axes scales and some nicer plotting symbols.

Let’s start with the axis labels. To add labels to the x and y axes we use the corresponding `ylab =`

and `xlab =`

arguments in the `plot()`

function. Both of these arguments need character strings as values.

OK, that looks a little better but the units `(cm2)`

looks a little ugly as we should format the `2`

as a superscript. To convert to a superscript we need to use a combination of the `expression()`

and `paste()`

functions. The `expression()`

function allows us to format the superscript (and other mathematical expressions - see `?plotmath`

for more details) with the `^`

symbol and the `paste()`

function pastes together the elements `"shoot area (cm"^"2"`

and `)`

to create our axis label.

```
plot(flowers$weight, flowers$shootarea,
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")))
```

But now we have a new problem, the very top of the y axis label gets cut off. To remedy this we need to adjust the plot margins using the `par()`

function and the `mar =`

argument before we plot the graph. The `par()`

function is the main function for setting graphical parameters in base R and the `mar =`

argument sets the size of the margins that surround the plot. You can adjust the size of the margins using the notation `par(mar = c(bottom, left, top, right))`

where the arguments `bottom`

, `left`

, `top`

and `right`

are the size of the corresponding margins. By default R sets these margins as `mar = c(5.1, 4.1, 4.1, 2.1)`

with these numbers specifying the number of lines in each margin. Let’s increase the size of the left margin a little bit and decrease the size of the right margin by a smidge.

```
par(mar = c(4.1, 4.4, 4.1, 1.9))
plot(flowers$weight, flowers$shootarea,
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")))
```

That looks better. Now let’s increase the range of our axes scales so we have a bit of space above and to the right of the data points. To do this we need to supply a minimum and maximum value using the `c()`

function to the `xlim =`

and `ylim =`

arguments. We’ll set the x axis scale to run from 0 to 30 and the range of the y axis scale from 0 to 200.

```
par(mar = c(4.1, 4.4, 4.1, 1.9))
plot(flowers$weight, flowers$shootarea,
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")),
xlim = c(0, 30), ylim = c(0, 200))
```

And while we’re at it let’s remove the annoying box all the way around the plot to just leave the y and x axes using the `bty = "l"`

argument.

```
par(mar = c(4.1, 4.4, 4.1, 1.9))
plot(flowers$weight, flowers$shootarea,
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")),
xlim = c(0, 30), ylim = c(0, 200), bty = "l")
```

OK, that’s looking a lot better already after only a few adjustments. One of the things that we still don’t like is that by default the x and y axes do not intersect at the origin (0, 0) and both axes extend beyond the maximum value of the scale by a little bit. We can change this by setting the `xaxs = "i"`

and `yaxs = "i"`

arguments when we use the `par()`

function. While we’re about it let’s also rotate the y axis tick mark labels so they read horizontally using by setting the `las = 1`

argument in the `plot()`

function and make them a tad smaller with the `cex.axis =`

argument. The `cex.axis =`

argument requires a number giving the amount by which the text will be magnified (or shrunk) relative to the default value of 1. We’ll choose `0.8`

making our text 20% smaller. We can also make the tick marks just a little shorter by setting `tcl = -0.2`

. This value needs to be negative as we want the tick marks to be outside the plotting region (see what happens if you set it to `tcl = 0.2`

).

```
par(mar = c(4.1, 4.4, 4.1, 1.9), xaxs = "i", yaxs = "i")
plot(flowers$weight, flowers$shootarea,
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")),
xlim = c(0, 30), ylim = c(0, 200), bty = "l",
las = 1, cex.axis = 0.8, tcl = -0.2)
```

We can also change the type of plotting symbol, the colour of the symbol and the size of the symbol using the `pch =`

, `col =`

and `cex =`

arguments respectively. The `pch =`

argument takes an integer value between 0 and 25 to define the type of plotting symbol. Symbols 0 to 14 are open symbols, 15 to 20 are filled symbols and 21 to 25 are symbols where you can specify a different fill colour and outside line colour. Here’s a summary table displaying the value and corresponding symbol type.

The `col =`

argument changes the colour of the plotting symbols. This argument can either take an integer value to specify the colour or a character string giving the colour name. For example, `col = "red"`

changes the plotting symbol to red. To see a list of all 657 preset colours available in base R use the `colours()`

function (you can also use `colors()`

) or perhaps even easier see this link. More colour options are available with other packages (see the excellent `RColorBrewer`

package) or you can even ‘mix’ your own colours using the `colorRamp()`

function (see `?colorRamp`

for more details).

The `cex =`

argument allow you to change the size of the plotting symbol. This argument works in the same way as the other `cex`

arguments we’ ve already seen (i.e. `cex.axis`

) and requires a numeric value to indicate the proportional increase or decrease in size relative to the default value of 1.

Let’s change the plotting symbol to a filled circle (16), the colour of the symbol to “dodgerblue1” and decrease the size of the symbol by 10%.

```
par(mar = c(4.1, 4.4, 4.1, 1.9), xaxs = "i", yaxs = "i")
plot(flowers$weight, flowers$shootarea,
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")),
xlim = c(0, 30), ylim = c(0, 200), bty = "l",
las = 1, cex.axis = 0.8, tcl = -0.2,
pch = 16, col = "dodgerblue1", cex = 0.9)
```

The last thing we’ll do is add a text label to the plot so we can identify it. Perhaps this plot will be one of a series of plots we want to include in the same figure (see the section on plotting multiple graphs to see how to do this) so it would be nice to be able to refer to it in our figure title. To do this we’ll use the `text()`

function to add a capital ‘A’ to the top right of the plot. The `text()`

function needs an `x =`

and a `y =`

coordinate to position the text, a `label =`

for the text and we can use the `cex =`

argument again to change the size of the text.

```
par(mar = c(4.1, 4.4, 4.1, 1.9), xaxs = "i", yaxs = "i")
plot(flowers$weight, flowers$shootarea,
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")),
xlim = c(0, 30), ylim = c(0, 200), bty = "l",
las = 1, cex.axis = 0.8, tcl = -0.2,
pch = 16, col = "dodgerblue1", cex = 0.9)
text(x = 28, y = 190, label = "A", cex = 2)
```

We think our plot now looks pretty good so we’ll stop here! There are, however, a multitude of other arguments which you can play around with to change the look of your plots. The best place to quickly look for more information is the help page associated with the `par()`

function (`?par`

) or just do a quick Google search. Here’s a table of the more commonly used arguments.

Argument | Description |
---|---|

`adj` |
controls justification of the text (0 left justified, 0.5 centered, 1 right justified) |

`bg` |
specifies the background colour of the plot (i.e. : `bg = "red"` , `bg = "blue"` ) |

`bty` |
controls the type of box drawn around the plot, values include: `"o"` , `"l"` , `"7"` , `"c"` , `"u"` , `"]"` (the box looks like the corresponding character); if `bty = "n"` the box is not drawn |

`cex` |
controls the size of text and symbols in the plotting area with respect to the default value of 1. Similar commands include: `cex.axis` controls the numbers on the axes, `cex.lab` numbers on the axis labels, `cex.main` the title and `cex.sub` the sub-title |

`col` |
controls the colour of symbols; additional argument include: `col.axis` , `col.lab` , `col.main` , `col.sub` |

`font` |
an integer controlling the style of text (1: normal, 2: bold, 3: italics, 4: bold italics); other argument include `font.axis` , `font.lab` , `font.main` , `font.sub` |

`las` |
an integer which controls the orientation of the axis labels (0: parallel to the axes, 1: horizontal, 2: perpendicular to the axes, 3: vertical) |

`lty` |
controls the line style, can be an integer (1: solid, 2: dashed, 3: dotted, 4: dotdash, 5: longdash, 6: twodash) |

`lwd` |
a numeric which controls the width of lines. Works as per `cex` |

`pch` |
controls the type of symbol, either an integer between 0 and 25, or any single character within quotes `" "` |

`ps` |
an integer which controls the size in points of texts and symbols |

`pty` |
a character which specifies the type of the plotting region, “s”: square, “m”: maximal |

`tck` |
a value which specifies the length of tick marks on the axes as a fraction of the width or height of the plot; if `tck = 1` a grid is drawn |

`tcl` |
a value which specifies the length of tick marks on the axes as a fraction of the height of a line of text (by default `tcl = -0.5` ) |

### 4.3.2 Building plots

For even more control over how your plot looks we can build our plot up in layers, customising each step as we go along. For example, perhaps we want to create a plot of `shootarea`

and `weight`

as we did before but this time we want to change the symbol colours of our data points depending on what level of `nitrogen`

the plants were exposed to. The general approach is to use the high level plotting function `plot()`

to create the general plot (axes, axes labels etc) but without the data points by including the `type = "n"`

argument. We then use the low level function `points()`

to add the plotting symbols for each `nitrogen`

level separately choosing a different colour for each set of points. Let’s go through this approach a step at a time. First we’ll make the plot but suppress plotting the data using the `type = "n"`

argument in the `plot()`

function.

```
par(mar = c(4.1, 4.4, 4.1, 1.9), xaxs = "i", yaxs = "i")
plot(flowers$weight, flowers$shootarea,
type = "n",
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")),
xlim = c(0, 30), ylim = c(0, 200), bty = "l",
las = 1, cex.axis = 0.8, tcl = -0.2)
```

We can now use the `points()`

function in combination with our square bracket `[ ]`

skills to only select those data from the `low`

level of `nitrogen`

. Whilst using the `points()`

function we can also set the symbol type and the symbol colour using the `pch =`

and `col =`

arguments.

```
par(mar = c(4.1, 4.4, 4.1, 1.9), xaxs = "i", yaxs = "i")
plot(flowers$weight, flowers$shootarea,
type = "n",
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")),
xlim = c(0, 30), ylim = c(0, 200), bty = "l",
las = 1, cex.axis = 0.8, tcl = -0.2)
points(x = flowers$weight[flowers$nitrogen == "low"],
y = flowers$shootarea[flowers$nitrogen == "low"],
pch = 16, col = "deepskyblue")
```

We can now use the `points()`

function again to plot data for the `medium`

level of nitrogen and change the symbol colour to something different. Notice that we do not reuse the `plot()`

function here as we are just using the low level function `points()`

to add data points to the existing plot.

```
points(x = flowers$weight[flowers$nitrogen == "medium"],
y = flowers$shootarea[flowers$nitrogen == "medium"],
pch = 16, col = "yellowgreen")
```

And finally to add the `high`

level of `nitrogen`

data points to the plot and add our text label (‘A’) to the plot as before.

```
points(x = flowers$weight[flowers$nitrogen == "high"],
y = flowers$shootarea[flowers$nitrogen == "high"],
pch = 16, col = "deeppink3")
text(x = 28, y = 190, label = "A", cex = 2)
```

The only thing left to do is to add a legend to the plot to let your reader know what `nitrogen`

level each colour corresponds to. We’ll use another low level function,`legend()`

to do this. The `legend()`

function requires us to provide the x and y coordinates to specify the position of the top left of the legend in the plot, a vector of colours, symbol types and labels to use in the legend. The `bty = "n"`

argument stops a border being drawn around the legend and the `title =`

argument gives the legend a title.

```
leg_cols <- c("deepskyblue", "yellowgreen", "deeppink3")
leg_sym <- c(16, 16, 16)
leg_lab <- c("low", "medium", "high")
legend(x = 1, y = 200, col = leg_cols, pch = leg_sym,
legend = leg_lab, bty = "n",
title = "Nitrogen level")
```

If you want to see all the code together.

```
par(mar = c(4.1, 4.4, 4.1, 1.9), xaxs="i", yaxs="i")
plot(flowers$weight, flowers$shootarea,
type = "n",
xlab = "weight (g)",
ylab = expression(paste("shoot area (cm"^"2",")")),
xlim = c(0, 30), ylim = c(0, 200), bty = "l",
las = 1, cex.axis = 0.8, tcl = -0.2)
points(x = flowers$weight[flowers$nitrogen == "low"],
y = flowers$shootarea[flowers$nitrogen == "low"],
pch = 16, col = "deepskyblue")
points(x = flowers$weight[flowers$nitrogen == "medium"],
y = flowers$shootarea[flowers$nitrogen == "medium"],
pch = 16, col = "yellowgreen")
points(x = flowers$weight[flowers$nitrogen == "high"],
y = flowers$shootarea[flowers$nitrogen == "high"],
pch = 16, col = "deeppink3")
text(x = 28, y = 190, label = "A", cex = 2)
leg_cols <- c("deepskyblue", "yellowgreen", "deeppink3")
leg_sym <- c(16, 16, 16)
leg_lab <- c("low", "medium", "high")
legend(x = 1, y = 200, col = leg_cols, pch = leg_sym,
legend = leg_lab, bty = "n",
title = "Nitrogen level")
```

The table below highlights some of the low level potting functions you might find useful.

Function | Description |
---|---|

`lines()` |
add connected lines to a plot |

`curve()` |
draws a curve corresponding to a function |

`arrows()` |
draws arrows between 2 points |

`text()` |
adds text to a plot |

`mtext()` |
adds text to one of the 4 plot margins |

`axis()` |
adds an axis to the current plot |

`rect()` |
draws a rectangle |

`legend()` |
adds a legend to the plot |

`points()` |
adds points to the plot |

`abline()` |
adds a straight line to a plot |

`grid()` |
adds a rectangular grid to the current plot |

`polygon()` |
draws a polygon |