Custom Visualisations

1 Learning Objectives

  • Explore tools for customising plot appearance in R.

2 Introduction

We have made some very basic plots so far, but we can do a lot more. Customising your graphs may, at first glance, appear reasonably trivial but the harsh reality is that many graphing packages in R have terrible defaults that contain lots of chart junk (i.e., unnecessary elements that distract the audience) as we saw in Lab 3.1. Thankfully R also provides great flexibility that facilitates customisation of almost every graph component. In fact, many major organisations actually use custom ggplot2 themes to create their stylised graphics (e.g., BBC). In this section, we will look at some of the ways we can customise our plots.

3 Start a Script

For this lab or project, begin by:

  • Starting a new R script
  • Create a good header section and table of contents
  • Save the script file with an informative name
  • set your working directory

Aim to make the script a future reference for doing things in R!

4 Data and Packages

# Load packages
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.3     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.4     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.0
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(palmerpenguins)
library(lattice)

# Load data
data(penguins)
# Simulate data for line plots
newdata <- data.frame(x = runif(24, -2, 2), # Create a variable x with 24 values between -2 and 2
                      y = rnorm(24))        # Create a variable y with 24 random normal values

5 Customising base R Plots

5.1 Histograms

Let’s start by re-creating a histogram of the flipper length of the penguins. We can use the hist() function to do this:

# Create histogram of flipper length
hist(penguins$flipper_length_mm) # Specify data

We can modify the aesthetics of the histogram using the col argument and provide context using the main and xlab arguments:

# Create histogram of flipper length  
hist(penguins$flipper_length_mm,           # Specify data
     breaks = 20,                          # Change number of bins
     col = "darkblue",                     # Change colour
     main = "Histogram of flipper length", # Add title
     xlab = "Flipper length (mm)")         # Add x-axis label

These are only some of the aesthetic options we can modify. We can also change the axis limits, axis labels, axis tick marks, and more. Let’s say we want to change the x-axis limits to 160 and 240, the x-axis label to “Flipper length (mm)”, and remove the y-axis tick marks and title. We can do this using the xlim, xlab, yaxt and ylab arguments, respectively:

# Create histogram of flipper length
hist(penguins$flipper_length_mm,           # Specify data
     breaks = 20,                          # Change number of bins
     col = "darkblue",                     # Change colour
     main = "Histogram of flipper length", # Add title
     xlab = "Flipper length (mm)",         # Add x-axis label
     xlim = c(160, 240),                   # Change x-axis limits
     yaxt = "n",                           # Remove y-axis tick marks
     ylab = "")                            # Remove y-axis label    

We can modify the plot margins using the par() function. The par() function is used to set or query graphical parameters. The mar argument is used to set the margins of the plot. The default margins are c(5, 4, 4, 2) + 0.1. The numbers in the vector are the number of lines of margin to be specified on the four sides of the plot (bottom, left, top, and right). The default unit is lines, but other units can be specified using the mar argument. For example, if we want to change the bottom margin to 10 lines, we can do the following:

# Change the bottom margin to 10 lines
par(mar = c(10, 4, 4, 2) + 0.1)

# Create histogram of flipper length
hist(penguins$flipper_length_mm,           # Specify data
     breaks = 20,                          # Change number of bins
     col = "darkblue",                     # Change colour
     main = "Histogram of flipper length", # Add title
     xlab = "Flipper length (mm)",         # Add x-axis label
     xlim = c(160, 240),                   # Change x-axis limits
     yaxt = "n",                           # Remove y-axis tick marks
     ylab = "")                            # Remove y-axis label    

We can also modify the background if we really want! We can do this using the par() function and the bg argument. The bg argument is used to set the background colour of the plot. The default background colour is white. We can change the background colour to light blue using the following code:

# Change the bottom margin back to the default
par(mar = c(5, 4, 4, 2) + 0.1)

# Change the background colour to light blue
par(bg = "lightblue")

# Create histogram of flipper length
hist(penguins$flipper_length_mm,           # Specify data
     breaks = 20,                          # Change number of bins
     col = "darkblue",                     # Change colour
     main = "Histogram of flipper length", # Add title
     xlab = "Flipper length (mm)",         # Add x-axis label
     xlim = c(160, 240),                   # Change x-axis limits
     yaxt = "n",                           # Remove y-axis tick marks
     ylab = "")                            # Remove y-axis label    

5.2 Boxplots

Let’s start by re-creating a boxplot of the flipper length of the penguins. We can use the boxplot() function to do this:

# Change the background colour back to white
par(bg = "white")

# Create boxplot of flipper length
boxplot(penguins$flipper_length_mm) # Specify data

We can modify the aesthetics of the boxplot using the col argument and provide context using the main and xlab arguments:

# Boxplot showing flipper lengths by species
boxplot(flipper_length_mm ~ species,                    # Specify data
        data = penguins,                                # Specify data frame
        main = "Boxplot of Flipper Lengths by Species", # Add title
        xlab = "Species",                               # Add x-axis label
        ylab = "Flipper Length (mm)",                   # Add y-axis label
        col = c("red", "green", "blue"))                # Change colour

Now it isn’t strictly necessary here as each penguin species is already labelled on the x-axis, but we could add a legend to the plot using the legend() function:

# Boxplot showing flipper lengths by species
boxplot(flipper_length_mm ~ species,                    # Specify data
        data = penguins,                                # Specify data frame
        main = "Boxplot of Flipper Lengths by Species", # Add title
        xlab = "Species",                               # Add x-axis label
        ylab = "Flipper Length (mm)",                   # Add y-axis label
        col = c("red", "green", "blue"))                # Change colour

# Adding legend (optional but useful)
legend("topleft",                                       # Specify location
       legend = levels(penguins$species),               # Specify legend labels
       fill = c("red", "green", "blue"))                # Specify legend colours

5.3 Barplots

Let’s start by re-creating a barplot of the species of penguins in the dataset. We can use the barplot() function to do this:

# Create barplot of species
barplot(table(penguins$species)) # Specify data

The barplot() function has a number of arguments that you can use to customise the barplot. We can change the aesthetics of the boxplot using the col argument and provide context using the main and xlab arguments:

# Barplot showing species
barplot(table(penguins$species),         # Specify data
        main = "Barplot of Species",     # Add title
        xlab = "Species",                # Add x-axis label
        ylab = "Count",                  # Add y-axis label
        col = c("red", "green", "blue")) # Change colour

To view your colour options you can run ?colors() in the console. If you want to change the order of the bars, you can also re-order the factor levels of the species variable to make the plot easier to interpret:

# Reorder the levels of the factor
penguins$species <- factor(penguins$species, levels = c("Chinstrap", "Gentoo", "Adelie"))

# Barplot showing species
barplot(table(rev(penguins$species)),    # Specify data
        main = "Barplot of Species",     # Add title
        xlab = "Species",                # Add x-axis label
        ylab = "Count",                  # Add y-axis label
        col = c("red", "green", "blue")) # Change colour

We can also change the y-axis limits as they currently do not fit the data range for the Adelie pengiuns:

# Barplot showing species
barplot(table(penguins$species),         # Specify data
        main = "Barplot of Species",     # Add title
        xlab = "Species",                # Add x-axis label
        ylab = "Count",                  # Add y-axis label
        col = c("red", "green", "blue"), # Change colour
        ylim = c(0, 160),                # Change y-axis limits
        yaxt = "n")                      # Remove y-axis tick marks  

# Add custom y-axis tick marks
axis(side = 2,                            # Specify side of plot
     at = seq(0, 160, by = 20),           # Specify tick mark positions
     las = 2)                             # Specify tick mark orientation - 2 = horizontal and 3 = vertical

5.4 Scatterplots

Let’s start by re-creating a scatterplot of flipper length against body mass for the penguins dataset. We can do this using the plot() function:

# Scatterplot of flipper length against body mass
plot(penguins$flipper_length_mm,                          # Specify data
     penguins$body_mass_g,                                # Specify data
     main = "Scatterplot of Flipper Length vs Body Mass", # Add title
     xlab = "Flipper Length (mm)",                        # Add x-axis label
     ylab = "Body Mass (g)")                              # Add y-axis label

We can also add some additional context by colouring the points by species:

# Scatterplot of flipper length against body mass
plot(penguins$flipper_length_mm,                          # Specify data
     penguins$body_mass_g,                                # Specify data
     main = "Scatterplot of Flipper Length vs Body Mass", # Add title
     xlab = "Flipper Length (mm)",                        # Add x-axis label
     ylab = "Body Mass (g)",                              # Add y-axis label
     col = c("red", "green", "blue")[penguins$species],  # Change colour
     pch = 16)                                            # Change point symbol

# Add legend
legend("topleft",                          # Specify position of legend
       legend = levels(penguins$species),  # Specify legend labels
       col = c("red", "green", "blue"),    # Specify legend colours
       pch = 16)                           # Specify legend symbol

If you want to view which legend symbols are available, you can use the ?points function to view the help file for the points() function. This will show you the different legend symbols that are available. You can also change the size of the legend symbols using the cex argument.

You can also add trend lines to the scatterplot using the abline() function. For example, if we want to add a linear trend line to the scatterplot, we can do the following:

# Scatterplot of flipper length against body mass
plot(penguins$flipper_length_mm,                          # Specify data
     penguins$body_mass_g,                                # Specify data
     main = "Scatterplot of Flipper Length vs Body Mass", # Add title
     xlab = "Flipper Length (mm)",                        # Add x-axis label
     ylab = "Body Mass (g)",                              # Add y-axis label
     col = c("red", "green", "blue")[penguins$species],  # Change colour
     pch = 16)                                            # Change point symbol

# Add legend
legend("topleft",                          # Specify position of legend
       legend = levels(penguins$species),  # Specify legend labels
       col = c("red", "green", "blue"),    # Specify legend colours
       pch = 16)                           # Specify legend symbol

# Add linear trend line for each species
abline(lm(penguins$body_mass_g ~ penguins$flipper_length_mm), # Specify linear model
       col = "black",                                         # Change colour
       lwd = 2)                                               # Change line width

This trend line is for all three species. If we want to add one for each species it becomes a bit more complicated as we have to fit a linear model for each species and then add the trend line for each species:

# Scatterplot of flipper length against body mass
plot(penguins$flipper_length_mm,                          # Specify data
     penguins$body_mass_g,                                # Specify data
     main = "Scatterplot of Flipper Length vs Body Mass", # Add title
     xlab = "Flipper Length (mm)",                        # Add x-axis label
     ylab = "Body Mass (g)",                              # Add y-axis label
     col = c("red", "green", "blue")[penguins$species],   # Change colour
     pch = 16)                                            # Change point symbol

# Add legend
legend("topleft",                          # Specify position of legend
       legend = levels(penguins$species),  # Specify legend labels
       col = c("red", "green", "blue"),    # Specify legend colours
       pch = 16)                           # Specify legend symbol

# Add trend lines for each species
species_levels <- levels(penguins$species)
colors <- c("red", "green", "blue")
for (i in seq_along(species_levels)) {
    species_data <- subset(penguins, species == species_levels[i])
    fit <- lm(body_mass_g ~ flipper_length_mm, data = species_data)
    abline(fit, col = colors[i], lw = 2)
}

6 Customising ggplot2 Plots

6.1 Histograms

Let’s start by re-creating the histogram of flipper length for the penguins dataset. We can do this using the geom_histogram() function:

# Create histogram of flipper length
ggplot(data = penguins, aes(x = flipper_length_mm)) + # Specify data and aesthetic mappings
  geom_histogram()                                    # Add histogram layer
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

We can see that this produces the same histogram as the base R version. These are only some of the aesthetic options we can modify. We can also change the axis limits, axis labels, axis tick marks, and more. Let’s say we want to change the x-axis limits to 160 and 240, the x-axis label to “Flipper length (mm)”, and remove the y-axis tick marks and title. We can do this by using the xlim(), xlab(), ylab(), and theme() functions:

# Create histogram of flipper length
ggplot(data = penguins, aes(x = flipper_length_mm)) + # Specify data and aesthetic mappings
  geom_histogram() +                                  # Add histogram layer
  xlim(160, 240) +                                    # Change x-axis limits
  xlab("Flipper length (mm)") +                       # Change x-axis label
  ylab(NULL) +                                        # Remove y-axis label
  theme(axis.ticks.y = element_blank(),               # Remove y-axis tick marks
        axis.title.y = element_blank(),               # Remove y-axis title
        axis.text.y = element_blank())                # Remove y-axis text
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

This produces a ggplot2 plot that closely resembles the base R plot we created earlier. However, we can do more with ggplot2. For example, we can change the colour of the bars using the fill argument:

# Create histogram of flipper length
ggplot(data = penguins, aes(x = flipper_length_mm)) +  # Specify data and aesthetic mappings
  geom_histogram(fill = "darkblue") +                  # Change colour
  xlim(160, 240) +                                     # Change x-axis limits
  xlab("Flipper length (mm)") +                        # Change x-axis label
  ylab(NULL) +                                         # Remove y-axis label
  ggtitle("Histogram of Flipper Length") +             # Add title
  theme(axis.ticks.y = element_blank(),                # Remove y-axis tick marks
        axis.title.y = element_blank(),                # Remove y-axis title
        axis.text.y = element_blank())                 # Remove y-axis text
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

You can change the size of any text on the ggplot2 plot using the size argument. For example, let’s say we want to increase the size of the title and axis labels:

# Create histogram of flipper length
ggplot(data = penguins, aes(x = flipper_length_mm)) +  # Specify data and aesthetic mappings
  geom_histogram(fill = "darkblue") +                  # Change colour
  xlim(160, 240) +                                     # Change x-axis limits
  xlab("Flipper length (mm)") +                        # Change x-axis label
  ylab(NULL) +                                         # Remove y-axis label
  ggtitle("Histogram of Flipper Length") +             # Add title
  theme(axis.ticks.y = element_blank(),                # Remove y-axis tick marks
        axis.title.y = element_blank(),                # Remove y-axis title
        axis.text.y = element_blank(),                 # Remove y-axis text
        plot.title = element_text(size = 20),          # Change title text size
        axis.title.x = element_text(size = 15))        # Change x-axis label text size
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

6.2 Boxplots

Let’s re-create the same boxplot using ggplot2:

# Create boxplot of flipper length
ggplot(data = penguins, aes(x = species, y = flipper_length_mm)) + # Specify data and aesthetic mappings
  geom_boxplot()                                                   # Add boxplot layer

We can also add the same customisations as before:

# Create boxplot of flipper length
ggplot(data = penguins, aes(x = species, y = flipper_length_mm)) + # Specify data and aesthetic mappings
  geom_boxplot(data = penguins, aes(fill = species)) +             # Add boxplot layer and change colour by species 
  labs(title = "Boxplot of flipper length",                        # Add title
       x = "Species",                                              # Add x-axis label
       y = "Flipper length (mm)")                                  # Add y-axis label

It is possible to modify the legend title and labels using the labs() function. For example, let’s say we want to change the legend title to “Species” and the legend labels to “Adelie”, “Chinstrap”, and “Gentoo”. We can also change the position:

# Create boxplot of flipper length
ggplot(data = penguins, aes(x = species, y = flipper_length_mm)) +   # Specify data and aesthetic mappings
  geom_boxplot(data = penguins, aes(fill = species)) +               # Add boxplot layer and change colour by species 
  labs(title = "Boxplot of flipper length",                          # Add title
       x = "Species",                                                # Add x-axis label
       y = "Flipper length (mm)",                                    # Add y-axis label
       fill = "Species") +                                           # Change legend title
  scale_fill_discrete(labels = c("Adelie", "Chinstrap", "Gentoo")) + # Change legend labels
  theme(legend.position = "bottom")                                  # Change legend position

6.3 Barplots

Now let’s re-create the same barplot using ggplot2:

# Create barplot of species
ggplot(data = penguins, aes(x = species)) + # Specify data and aesthetic mappings
  geom_bar()                                # Add bar plot layer

We can see that this produces the same barplot as the base R version. We can also add the same customisations as before:

# Create barplot of species
ggplot(data = penguins, aes(x = species)) +    # Specify data and aesthetic mappings
  geom_bar(fill = c("red", "green", "blue")) + # Add bar plot layer and change colour
  labs(title = "Barplot of Species",           # Add title
       x = "Species",                          # Add x-axis label
       y = "Count")                            # Add y-axis label

There is a way to modify the entire theme of the plot using the theme() function. There are several pre-defined themes available in ggplot2, such as theme_bw(), theme_classic(), and theme_minimal().

# Create barplot of species
ggplot(data = penguins, aes(x = species)) +    # Specify data and aesthetic mappings
  geom_bar(fill = c("red", "green", "blue")) + # Add bar plot layer and change colour
  labs(title = "Barplot of Species",           # Add title
       x = "Species",                          # Add x-axis label
       y = "Count") +                          # Add y-axis label
  theme_bw()                                   # Change theme

6.4 Scatterplots

Let’s start by re-creating a scatterplot of flipper length against body mass for the penguins data set using ggplot2:

# Create scatterplot of flipper length against body mass
ggplot(data = penguins, aes(x = flipper_length_mm, y = body_mass_g)) + # Specify data and aesthetic mappings
  geom_point() +                                                       # Add scatterplot layer
  labs(title = "Scatterplot of Flipper Length vs Body Mass",           # Add title
       x = "Flipper Length (mm)",                                      # Add x-axis label
       y = "Body Mass (g)")                                            # Add y-axis label

This is a nice plot, but we can add some additional context by colouring the points by species:

# Create scatterplot of flipper length against body mass
ggplot(data = penguins, aes(x = flipper_length_mm, y = body_mass_g, colour = species)) + # Specify data and aesthetic mappings
  geom_point() +                                                                         # Add scatterplot layer
  labs(title = "Scatterplot of Flipper Length vs Body Mass",                             # Add title
       x = "Flipper Length (mm)",                                                        # Add x-axis label
       y = "Body Mass (g)",                                                              # Add y-axis label
       colour = "Species") +                                                             # Add legend title    
  theme(legend.position = "bottom")                                                      # Change legend position

Adding trendlines for each species is much easier in ggplot2 than in base R. We can do this using the geom_smooth() function:

# Create scatterplot of flipper length against body mass
ggplot(data = penguins, aes(x = flipper_length_mm, y = body_mass_g, colour = species)) + # Specify data and aesthetic mappings
  geom_point() +                                                                         # Add scatterplot layer
  geom_smooth(method = "lm", se = FALSE) +                                               # Add trendline layer
  labs(title = "Scatterplot of Flipper Length vs Body Mass",                             # Add title
       x = "Flipper Length (mm)",                                                        # Add x-axis label
       y = "Body Mass (g)",                                                              # Add y-axis label
       colour = "Species") +                                                             # Add legend title    
  theme(legend.position = "bottom")                                                      # Change legend position
`geom_smooth()` using formula = 'y ~ x'

6.5 Custom Themes

There is a way to modify the entire theme of the plot using the theme() function. There are several pre-defined themes available in ggplot2, such as theme_bw(), theme_classic(), and theme_minimal().

# Create scatterplot of flipper length against body mass
ggplot(data = penguins, aes(x = flipper_length_mm, y = body_mass_g, colour = species)) + # Specify data and aesthetic mappings
  geom_point() +                                                                         # Add scatterplot layer
  geom_smooth(method = "lm", se = FALSE) +                                               # Add trendline layer
  labs(title = "Scatterplot of Flipper Length vs Body Mass",                             # Add title
       x = "Flipper Length (mm)",                                                        # Add x-axis label
       y = "Body Mass (g)",                                                              # Add y-axis label
       colour = "Species") +                                                             # Add legend title    
  theme_bw()                                                                             # Change theme
`geom_smooth()` using formula = 'y ~ x'

There are several packages that provide additional themes, some even with different default color palettes. As an example, Jeffrey Arnold has put together the library ggthemes with several custom themes imitating popular designs. For a list you can visit the ggthemes package site. Without any coding you can just adapt several styles, some of them well known for their style and aesthetics. For example, the theme_economist() function imitates the style of the Economist magazine:

# Load ggthemes package
library(ggthemes)

# Create scatterplot of flipper length against body mass
ggplot(data = penguins, aes(x = flipper_length_mm, y = body_mass_g, colour = species)) + # Specify data and aesthetic mappings
  geom_point() +                                                                         # Add scatterplot layer
  geom_smooth(method = "lm", se = FALSE) +                                               # Add trendline layer
  labs(title = "Scatterplot of Flipper Length vs Body Mass",                             # Add title
       x = "Flipper Length (mm)",                                                        # Add x-axis label
       y = "Body Mass (g)",                                                              # Add y-axis label
       colour = "Species") +                                                             # Add legend title    
  theme_economist()                                                                      # Change theme
`geom_smooth()` using formula = 'y ~ x'

If you want to change the theme for an entire session you can use theme_set as in theme_set(theme_bw()). The default is called theme_gray (or theme_grey). If you wanted to create your own custom theme, you could extract the code directly from the grey theme and modify. Note that the rel() function change the sizes relative to the base_size.

# Print code for theme_grey()
theme_grey()
List of 97
 $ line                      :List of 6
  ..$ colour       : chr "black"
  ..$ linewidth    : num 0.5
  ..$ linetype     : num 1
  ..$ lineend      : chr "butt"
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ rect                      :List of 5
  ..$ fill         : chr "white"
  ..$ colour       : chr "black"
  ..$ linewidth    : num 0.5
  ..$ linetype     : num 1
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ text                      :List of 11
  ..$ family       : chr ""
  ..$ face         : chr "plain"
  ..$ colour       : chr "black"
  ..$ size         : num 11
  ..$ hjust        : num 0.5
  ..$ vjust        : num 0.5
  ..$ angle        : num 0
  ..$ lineheight   : num 0.9
  ..$ margin       : 'margin' num [1:4] 0points 0points 0points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ title                     : NULL
 $ aspect.ratio              : NULL
 $ axis.title                : NULL
 $ axis.title.x              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 2.75points 0points 0points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.x.top          :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0points 0points 2.75points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.x.bottom       : NULL
 $ axis.title.y              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : num 90
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0points 2.75points 0points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.y.left         : NULL
 $ axis.title.y.right        :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : num -90
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0points 0points 0points 2.75points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text                 :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : chr "grey30"
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x               :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 2.2points 0points 0points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x.top           :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0points 0points 2.2points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x.bottom        : NULL
 $ axis.text.y               :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0points 2.2points 0points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.y.left          : NULL
 $ axis.text.y.right         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0points 0points 0points 2.2points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.ticks                :List of 6
  ..$ colour       : chr "grey20"
  ..$ linewidth    : NULL
  ..$ linetype     : NULL
  ..$ lineend      : NULL
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ axis.ticks.x              : NULL
 $ axis.ticks.x.top          : NULL
 $ axis.ticks.x.bottom       : NULL
 $ axis.ticks.y              : NULL
 $ axis.ticks.y.left         : NULL
 $ axis.ticks.y.right        : NULL
 $ axis.ticks.length         : 'simpleUnit' num 2.75points
  ..- attr(*, "unit")= int 8
 $ axis.ticks.length.x       : NULL
 $ axis.ticks.length.x.top   : NULL
 $ axis.ticks.length.x.bottom: NULL
 $ axis.ticks.length.y       : NULL
 $ axis.ticks.length.y.left  : NULL
 $ axis.ticks.length.y.right : NULL
 $ axis.line                 : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ axis.line.x               : NULL
 $ axis.line.x.top           : NULL
 $ axis.line.x.bottom        : NULL
 $ axis.line.y               : NULL
 $ axis.line.y.left          : NULL
 $ axis.line.y.right         : NULL
 $ legend.background         :List of 5
  ..$ fill         : NULL
  ..$ colour       : logi NA
  ..$ linewidth    : NULL
  ..$ linetype     : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ legend.margin             : 'margin' num [1:4] 5.5points 5.5points 5.5points 5.5points
  ..- attr(*, "unit")= int 8
 $ legend.spacing            : 'simpleUnit' num 11points
  ..- attr(*, "unit")= int 8
 $ legend.spacing.x          : NULL
 $ legend.spacing.y          : NULL
 $ legend.key                :List of 5
  ..$ fill         : chr "grey95"
  ..$ colour       : logi NA
  ..$ linewidth    : NULL
  ..$ linetype     : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ legend.key.size           : 'simpleUnit' num 1.2lines
  ..- attr(*, "unit")= int 3
 $ legend.key.height         : NULL
 $ legend.key.width          : NULL
 $ legend.text               :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ legend.text.align         : NULL
 $ legend.title              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ legend.title.align        : NULL
 $ legend.position           : chr "right"
 $ legend.direction          : NULL
 $ legend.justification      : chr "center"
 $ legend.box                : NULL
 $ legend.box.just           : NULL
 $ legend.box.margin         : 'margin' num [1:4] 0cm 0cm 0cm 0cm
  ..- attr(*, "unit")= int 1
 $ legend.box.background     : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.box.spacing        : 'simpleUnit' num 11points
  ..- attr(*, "unit")= int 8
 $ panel.background          :List of 5
  ..$ fill         : chr "grey92"
  ..$ colour       : logi NA
  ..$ linewidth    : NULL
  ..$ linetype     : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ panel.border              : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ panel.spacing             : 'simpleUnit' num 5.5points
  ..- attr(*, "unit")= int 8
 $ panel.spacing.x           : NULL
 $ panel.spacing.y           : NULL
 $ panel.grid                :List of 6
  ..$ colour       : chr "white"
  ..$ linewidth    : NULL
  ..$ linetype     : NULL
  ..$ lineend      : NULL
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ panel.grid.major          : NULL
 $ panel.grid.minor          :List of 6
  ..$ colour       : NULL
  ..$ linewidth    : 'rel' num 0.5
  ..$ linetype     : NULL
  ..$ lineend      : NULL
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ panel.grid.major.x        : NULL
 $ panel.grid.major.y        : NULL
 $ panel.grid.minor.x        : NULL
 $ panel.grid.minor.y        : NULL
 $ panel.ontop               : logi FALSE
 $ plot.background           :List of 5
  ..$ fill         : NULL
  ..$ colour       : chr "white"
  ..$ linewidth    : NULL
  ..$ linetype     : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ plot.title                :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 1.2
  ..$ hjust        : num 0
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0points 0points 5.5points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.title.position       : chr "panel"
 $ plot.subtitle             :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0points 0points 5.5points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.caption              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : num 1
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 5.5points 0points 0points 0points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.caption.position     : chr "panel"
 $ plot.tag                  :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 1.2
  ..$ hjust        : num 0.5
  ..$ vjust        : num 0.5
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.tag.position         : chr "topleft"
 $ plot.margin               : 'margin' num [1:4] 5.5points 5.5points 5.5points 5.5points
  ..- attr(*, "unit")= int 8
 $ strip.background          :List of 5
  ..$ fill         : chr "grey85"
  ..$ colour       : logi NA
  ..$ linewidth    : NULL
  ..$ linetype     : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ strip.background.x        : NULL
 $ strip.background.y        : NULL
 $ strip.clip                : chr "inherit"
 $ strip.placement           : chr "inside"
 $ strip.text                :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : chr "grey10"
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 4.4points 4.4points 4.4points 4.4points
  .. ..- attr(*, "unit")= int 8
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ strip.text.x              : NULL
 $ strip.text.x.bottom       : NULL
 $ strip.text.x.top          : NULL
 $ strip.text.y              :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : num -90
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ strip.text.y.left         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : num 90
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ strip.text.y.right        : NULL
 $ strip.switch.pad.grid     : 'simpleUnit' num 2.75points
  ..- attr(*, "unit")= int 8
 $ strip.switch.pad.wrap     : 'simpleUnit' num 2.75points
  ..- attr(*, "unit")= int 8
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi TRUE
 - attr(*, "validate")= logi TRUE

Now, let us modify the default theme function and have a look at the result:

theme_custom <- function (base_size = 12, base_family = "Roboto Condensed") {
  half_line <- base_size/2
  theme(
    line = element_line(color = "black", linewidth = .5,
                        linetype = 1, lineend = "butt"),
    rect = element_rect(fill = "white", color = "black",
                        linewidth = .5, linetype = 1),
    text = element_text(family = base_family, face = "plain",
                        color = "black", size = base_size,
                        lineheight = .9, hjust = .5, vjust = .5,
                        angle = 0, margin = margin(), debug = FALSE),
    axis.line = element_blank(),
    axis.line.x = NULL,
    axis.line.y = NULL,
    axis.text = element_text(size = base_size * 1.1, color = "gray30"),
    axis.text.x = element_text(margin = margin(t = .8 * half_line/2),
                               vjust = 1),
    axis.text.x.top = element_text(margin = margin(b = .8 * half_line/2),
                                   vjust = 0),
    axis.text.y = element_text(margin = margin(r = .8 * half_line/2),
                               hjust = 1),
    axis.text.y.right = element_text(margin = margin(l = .8 * half_line/2),
                                     hjust = 0),
    axis.ticks = element_line(color = "gray30", linewidth = .7),
    axis.ticks.length = unit(half_line / 1.5, "pt"),
    axis.ticks.length.x = NULL,
    axis.ticks.length.x.top = NULL,
    axis.ticks.length.x.bottom = NULL,
    axis.ticks.length.y = NULL,
    axis.ticks.length.y.left = NULL,
    axis.ticks.length.y.right = NULL,
    axis.title.x = element_text(margin = margin(t = half_line),
                                vjust = 1, size = base_size * 1.3,
                                face = "bold"),
    axis.title.x.top = element_text(margin = margin(b = half_line),
                                    vjust = 0),
    axis.title.y = element_text(angle = 90, vjust = 1,
                                margin = margin(r = half_line),
                                size = base_size * 1.3, face = "bold"),
    axis.title.y.right = element_text(angle = -90, vjust = 0,
                                      margin = margin(l = half_line)),
    legend.background = element_rect(color = NA),
    legend.spacing = unit(.4, "cm"),
    legend.spacing.x = NULL,
    legend.spacing.y = NULL,
    legend.margin = margin(.2, .2, .2, .2, "cm"),
    legend.key = element_rect(fill = "gray95", color = "white"),
    legend.key.size = unit(1.2, "lines"),
    legend.key.height = NULL,
    legend.key.width = NULL,
    legend.text = element_text(size = rel(.8)),
    legend.text.align = NULL,
    legend.title = element_text(hjust = 0),
    legend.title.align = NULL,
    legend.position = "right",
    legend.direction = NULL,
    legend.justification = "center",
    legend.box = NULL,
    legend.box.margin = margin(0, 0, 0, 0, "cm"),
    legend.box.background = element_blank(),
    legend.box.spacing = unit(.4, "cm"),
    panel.background = element_rect(fill = "white", color = NA),
    panel.border = element_rect(color = "gray30",
                                fill = NA, linewidth = .7),
    panel.grid.major = element_line(color = "gray90", linewidth = 1),
    panel.grid.minor = element_line(color = "gray90", linewidth = .5,
                                    linetype = "dashed"),
    panel.spacing = unit(base_size, "pt"),
    panel.spacing.x = NULL,
    panel.spacing.y = NULL,
    panel.ontop = FALSE,
    strip.background = element_rect(fill = "white", color = "gray30"),
    strip.text = element_text(color = "black", size = base_size),
    strip.text.x = element_text(margin = margin(t = half_line,
                                                b = half_line)),
    strip.text.y = element_text(angle = -90,
                                margin = margin(l = half_line,
                                                r = half_line)),
    strip.text.y.left = element_text(angle = 90),
    strip.placement = "inside",
    strip.placement.x = NULL,
    strip.placement.y = NULL,
    strip.switch.pad.grid = unit(0.1, "cm"),
    strip.switch.pad.wrap = unit(0.1, "cm"),
    plot.background = element_rect(color = NA),
    plot.title = element_text(size = base_size * 1.8, hjust = .5,
                              vjust = 1, face = "bold",
                              margin = margin(b = half_line * 1.2)),
    plot.title.position = "panel",
    plot.subtitle = element_text(size = base_size * 1.3,
                                 hjust = .5, vjust = 1,
                                 margin = margin(b = half_line * .9)),
    plot.caption = element_text(size = rel(0.9), hjust = 1, vjust = 1,
                                margin = margin(t = half_line * .9)),
    plot.caption.position = "panel",
    plot.tag = element_text(size = rel(1.2), hjust = .5, vjust = .5),
    plot.tag.position = "topleft",
    plot.margin = margin(rep(base_size, 4)),
    complete = TRUE
  )
}

Have a look on the modified aesthetics with its new look of panel and gridlines as well as axes ticks, texts and titles:

# Create scatterplot of flipper length against body mass
ggplot(data = penguins, aes(x = flipper_length_mm, y = body_mass_g, colour = species)) + # Specify data and aesthetic mappings
  geom_point() +                                                                         # Add scatterplot layer
  geom_smooth(method = "lm", se = FALSE) +                                               # Add trendline layer
  labs(title = "Scatterplot of Flipper Length vs Body Mass",                             # Add title
       x = "Flipper Length (mm)",                                                        # Add x-axis label
       y = "Body Mass (g)",                                                              # Add y-axis label
       colour = "Species") +                                                             # Add legend title    
  theme_custom()                                                                      # Change theme
`geom_smooth()` using formula = 'y ~ x'

7 Customising lattice Plots

7.1 Histograms

Let’s start by re-creating the histogram of flipper length for the penguins data set using lattice:

# Create histogram of flipper length
histogram(~ flipper_length_mm, data = penguins, # Specify formula and data
          main = "Histogram of Flipper Length", # Add title
          xlab = "Flipper Length (mm)",         # Add x-axis label
          ylab = "Count")                       # Add y-axis label

We can add some additional context by faceting the histogram by species:

# Create histogram of flipper length
histogram(~ flipper_length_mm | species, data = penguins, # Specify formula and data
          main = "Histogram of Flipper Length",           # Add title
          xlab = "Flipper Length (mm)",                   # Add x-axis label
          ylab = "Count")                                 # Add y-axis label

We can also change the histogram colour:

# Create histogram of flipper length
histogram(~ flipper_length_mm | species, data = penguins, # Specify formula and data
          main = "Histogram of Flipper Length",           # Add title
          xlab = "Flipper Length (mm)",                   # Add x-axis label
          ylab = "Count",                                 # Add y-axis label
          col = "lightblue")                              # Change colour

7.2 Boxplots

Let’s start by re-creating a boxplot of flipper length per species for the penguins data set using lattice:

# Create boxplot of flipper length per species
bwplot(flipper_length_mm ~ species, data = penguins,   # Specify formula and data
       main = "Boxplot of Flipper Length per Species", # Add title
       xlab = "Species",                               # Add x-axis label
       ylab = "Flipper Length (mm)")                   # Add y-axis label

We can also add the same customisations as before:

# Create boxplot of flipper length per species
bwplot(flipper_length_mm ~ species, data = penguins,   # Specify formula and data
       main = "Boxplot of Flipper Length per Species", # Add title
       xlab = "Species",                               # Add x-axis label
       ylab = "Flipper Length (mm)",                   # Add y-axis label
       fill = c("red", "green", "blue"))               # Change colour

7.3 Scatterplots

Let’s start by re-creating a scatterplot of flipper length against species for the penguins data set using lattice:

# Create scatterplot of flipper length against body mass
xyplot(body_mass_g ~ flipper_length_mm, data = penguins, # Specify formula and data
       main = "Scatterplot of Flipper Length vs Body Mass", # Add title
       xlab = "Flipper Length (mm)",                       # Add x-axis label
       ylab = "Body Mass (g)")                             # Add y-axis label

We can also add the same customisations as before:

# Create scatterplot of flipper length against body mass
xyplot(body_mass_g ~ flipper_length_mm, data = penguins,    # Specify formula and data
       main = "Scatterplot of Flipper Length vs Body Mass", # Add title
       xlab = "Flipper Length (mm)",                        # Add x-axis label
       ylab = "Body Mass (g)",                              # Add y-axis label
       col = c("red", "green", "blue"))                     # Change colour

We should really add a legend to facilitate reader understanding as well as some regression lines for each species. Let’s also fill the circles:

# Create scatterplot of flipper length against body mass
xyplot(body_mass_g ~ flipper_length_mm | species, data = penguins,  # Specify formula and data
       main = "Scatterplot of Flipper Length vs Body Mass",         # Add title
       xlab = "Flipper Length (mm)",                                # Add x-axis label
       ylab = "Body Mass (g)",                                      # Add y-axis label
       pch = 19,                                                    # Fill circles
       panel = function(x, y, ...) {                                # Add regression lines
         panel.xyplot(x, y, ...)
         panel.lmline(x, y, col = "black")
       })

8 Saving Plots

8.1 Saving Plots in RStudio

You can save plots in RStudio by clicking on the Export button in the Plots pane. This will open a pop-up window where you can select the file type and location to save the plot.

8.2 Saving Plots in R

You can also save plots in R using the ggsave() function. This function takes the following arguments:

  • filename: The name of the file to save the plot to.
  • plot: The plot to save.
  • device: The graphics device to use. The default is png.
  • width: The width of the plot in inches.
  • height: The height of the plot in inches.
  • units: The units to use for the width and height. The default is in.
  • dpi: The resolution of the plot in dots per inch. The default is 300.

Let’s save the scatterplot we created earlier as a png file. This will be saved to your working directory!

# Create scatterplot of flipper length against body mass
ggplot(data = penguins, aes(x = flipper_length_mm, y = body_mass_g, colour = species)) + # Specify data and aesthetic mappings
  geom_point() +                                                                         # Add scatterplot layer
  geom_smooth(method = "lm", se = FALSE) +                                               # Add trendline layer
  labs(title = "Scatterplot of Flipper Length vs Body Mass",                             # Add title
       x = "Flipper Length (mm)",                                                        # Add x-axis label
       y = "Body Mass (g)",                                                              # Add y-axis label
       colour = "Species") +                                                             # Add legend title    
  theme(legend.position = "bottom")                                                      # Change legend position

# Save plot as png file
ggsave(filename = "scatterplot.png", plot = last_plot())

9 Activities

Let’s use the diamond data from ggplot2 to practice creating different types of plots. The diamond data set contains information about 53,940 diamonds including their cut, colour, clarity, carat, and price.

9.1 Load the data

Start by loading it ggplot2 into your workspace. Then, load the data into your workspace using the data() function.

💡 Click here to view a solution
# Load the ggplot2 package
library(ggplot2)

# Load the data
data(diamonds)

9.2 Create a Histogram

Create a histogram of the price variable using either Base R or ggplot2. Use a bindwith of 1000 and colour the bars by cut if using ggplot2 (this won’t easily work for `Base R). Add a title and axis labels.

💡 Click here to view a Base R solution
# Create histogram using base R
hist(diamonds$price,                      # Specify data
     breaks = seq(0, 20000, 1000),        # Specify breaks
     main = "Histogram of Price",         # Add title
     xlab = "Price",                      # Add x-axis label
     ylab = "Count")                      # Add y-axis label
💡 Click here to view a ggplot2 solution
# Create histogram using ggplot2
ggplot(data = diamonds, aes(x = price, fill = cut)) + # Specify data and aesthetic mappings
  geom_histogram(binwidth = 1000) +                   # Add histogram layer
  labs(title = "Histogram of Price",                  # Add title
       x = "Price",                                   # Add x-axis label
       y = "Count",                                   # Add y-axis label
       fill = "Cut") +                                # Add legend title
  theme(legend.position = "bottom")                   # Change legend position

9.3 Create a Boxplot

Create a boxplot of the price variable by cut using either ggplot2 or lattice. Add a title and axis labels.

💡 Click here to view a ggplot2 solution
# Create boxplot using ggplot2
ggplot(data = diamonds, aes(x = cut, y = price)) + # Specify data and aesthetic mappings
  geom_boxplot() +                                 # Add boxplot layer
  labs(title = "Boxplot of Price by Cut",          # Add title
       x = "Cut",                                  # Add x-axis label
       y = "Price") +                              # Add y-axis label
  theme(legend.position = "bottom")                # Change legend position
💡 Click here to view a lattice solution
# Create boxplot using lattice
bwplot(price ~ cut, data = diamonds, # Specify data and variables
       main = "Boxplot of Price by Cut", # Add title
       xlab = "Cut", ylab = "Price")     # Add axis labels

9.4 Create a scatterplot

Create a scatterplot of price vs. carat using either Base R or ggplot2. Add a title and axis labels. Colour the points by cut. Describe the relationship between price and carat.

💡 Click here to view a Base R solution
# Define a colour for each cut
cut_colours <- setNames(rainbow(length(levels(diamonds$cut))), 
                        levels(diamonds$cut))

# Create scatterplot using base R
plot(diamonds$carat, diamonds$price,            # Specify data
     main = "Price vs. Carat",                  # Add title
     xlab = "Carat", ylab = "Price",            # Add axis labels
     col = cut_colours[diamonds$cut],           # Add colours
     pch = 16)                                  # Add solid points

There are too many points on this plot. Let’s try to reduce the number of points by sampling 1000 points from each cut.

# Sample 1000 points from each cut
diamonds_sample <- diamonds %>% # Specify data
  group_by(cut) %>%             # Group by cut
  sample_n(1000)                # Sample 1000 points from each cut

# Create scatterplot using base R
plot(diamonds_sample$carat, diamonds_sample$price,  # Specify data
     main = "Price vs. Carat",                      # Add title
     xlab = "Carat", ylab = "Price",                # Add axis labels
     col = cut_colours[diamonds_sample$cut],        # Add colours
     pch = 16)                                      # Add solid points

The relationship between price and carat is positive and linear. As carat increases, price increases.

💡 Click here to view a ggplot2 solution
# Create scatterplot using ggplot2
ggplot(data = diamonds, aes(x = carat, y = price, colour = cut)) + # Specify data and aesthetic mappings
  geom_point() +                                                    # Add scatterplot layer
  labs(title = "Price vs. Carat",                                   # Add title
       x = "Carat", y = "Price",                                     # Add axis labels
       colour = "Cut") +                                             # Add legend title
  theme(legend.position = "bottom")                                  # Change legend position

There are too many points on this plot. Let’s try to reduce the number of points by sampling 1000 points from each cut.

# Sample 1000 points from each cut
diamonds_sample <- diamonds %>% # Specify data
  group_by(cut) %>%             # Group by cut
  sample_n(1000)                # Sample 1000 points from each cut

# Create scatterplot using ggplot2
ggplot(data = diamonds_sample, aes(x = carat, y = price, colour = cut)) + # Specify data and aesthetic mappings
  geom_point() +                                                         # Add scatterplot layer
  labs(title = "Price vs. Carat",                                        # Add title
       x = "Carat", y = "Price",                                          # Add axis labels
       colour = "Cut") +                                                  # Add legend title
  theme(legend.position = "bottom")                                       # Change legend position

9.5 Create a theme

Modify the theme_grey() theme to change the text colour to red. You can also change the gridlines to black. Now apply this theme to the ggplot2 scatterplot you created in the previous exercise.

💡 Click here to view a solution
# Create a theme
my_theme <- theme_grey() + # Start with theme_grey()
  theme(text = element_text(colour = "red"), # Change text colour to red
        panel.grid.major = element_line(colour = "black")) # Change gridlines to black

# Create scatterplot using ggplot2
ggplot(data = diamonds_sample, aes(x = carat, y = price, colour = cut)) + # Specify data and aesthetic mappings
  geom_point() +                                                         # Add scatterplot layer
  labs(title = "Price vs. Carat",                                        # Add title
       x = "Carat", y = "Price",                                          # Add axis labels
       colour = "Cut") +                                                  # Add legend title
  my_theme                                                                # Apply theme

It’s not the most aesthetically pleasing plot, but it’s a start! Make some more changes to the theme to make it look better.

9.6 Which framework is easier to customise?

Which framework do you prefer for creating plots? Why? Write a short paragraph describing your thoughts.

9.7 Make your own plot

Create a plot of your choice using either Base R, ggplot2 or lattice and the diamond data. Be creative!

10 Recap

  • Data visualisations can be customised to make them more informative and aesthetically pleasing;
  • There are three main frameworks for creating data visualisations in R: Base R, ggplot2 and lattice;
  • Base R plots are built up using a series of functions;
  • Base R plots can be customised using arguments;
  • ggplot2 is a popular framework for creating data visualisations;
  • ggplot2 plots are built up in layers;
  • ggplot2 plots can be customised using themes;
  • lattice plots are built up using a series of functions;
  • lattice plots can be customised using arguments.