GGPlot cookbook


About this document

This document is cookbook for R ggplot2 and ggplot2 add-on packages (such as cowplot) for recipes that I've developed and those I've had to repeatedly look up.

A couple notes about the code examples:

  • All examples assume the ggplot2 library has been imported
  • At the end of each example subsection, I list the versions of R, ggplot2 and all other packages used to create each example at the time of writing
  • In the code examples, p or any p* (e.g. p1, p2, pall) variable is a ggplot2 object

This document will be updated periodically.

Table of contents

Click to expand table of contents

Last updated: 2020-11-12

Create basic plot types

Create a ribbon plots (fill between between two lines)

Ribbon geom_ribbon() plots can also be used to fill between two lines or point/scatter plots

# Data must be in wider (spread) format

ggplot(plot_data, aes(xvar)) +
  # Providing 'color' automatically creates a label
  geom_line(aes(y = yvar1, color = "Label 1"), size = 0.75) +
  geom_line(aes(y = yvar2, color = "Label 2"), size = 0.75) + 

  # 'geom_ribbon' fills between a 'ymin' and 'ymax' value. Adding
  # a transparency (alpha) value makes the plot look better.
  geom_ribbon(aes(ymin = yvar1, ymax = yvar2), alpha = 0.20) +

⇧ Back to TOCR: 3.6.2 ◊ ggplot: 3.2.1

Create a correlation plot

Use ggplot2 extension GGally. Package function ggpairs can produce a variety of matrix-type plots between variables.

fpp3::us_change %>%
  GGally::ggpairs(columns = 2:6)

⇧ Back to TOCR: 4.0.2 ◊ ggplot2: 3.3.2 ◊ GGally: 2.0.0

Change plot labels, limits, and axes

Add x,y axis labels

# Using labs
p + labs(x = "x label",
         y = "y label")

# Using xlab and ylab
p + xlab("x label") + ylab("y label")

⇧ Back to TOCR: 3.6.2 ◊ ggplot2: 3.2.1

Remove x,y axis labels

Example 1: Remove labels but keep the space that the axis labels took up

p + labs(x = "",
         y = "")

Example 2: Remove labels and remove the space that the axis labels took up

p + labs(x = NULL,
         y = NULL)

⇧ Back to TOCR: 4.0.2 ◊ ggplot2: 3.3.2

Remove x,y axis tick labels

p + theme(axis.text.x = element_blank(),
          axis.text.y = element_blank())

⇧ Back to TOCR: 4.0.2 ◊ ggplot2: 3.3.2

Put an axis into scientific notation

Provide a labels function to scale_y_continuous() that converts the default labels to scientific SI notation.

The format_si() function is based on code by Ben Tupper. See

format_si <- function(...) {

  function(x) {
    limits <- c(1e-24, 1e-21, 1e-18, 1e-15, 1e-12,
                1e-9,  1e-6,  1e-3,  1e0,   1e3,
                1e6,   1e9,   1e12,  1e15,  1e18,
                1e21,  1e24,  1e27,  1e30,  1e33)
    prefix <- c("y",   "z",   "a",   "f",   "p",
                "n",   "µ",   "m",   " ",   "k",
                "M",   "G",   "T",   "P",   "E",
                "Z",   "Y",   "kY",  "MY",  "GY")

    # Vector with array indices according to position in intervals
    i <- findInterval(abs(x), limits)

    # Set prefix to " " for very small values < 1e-24
    i <- ifelse(i==0, which(limits == 1e0), i)

    paste(format(round(x/limits[i], 1),
                 trim=TRUE, scientific=FALSE, ...),

p + scale_y_continuous(labels = format_si())

⇧ Back to TOCR: 3.6.2 ◊ ggplot: 3.2.1

Put y axis into percentage format

p + scale_y_continuous(labels = scales::percent)

⇧ Back to TOCR: 3.6.2 ◊ ggplot2: 3.2.1

Make y-axis origin start at zero

p + scale_y_continuous(expand = c(0, 0), limits = c(0, NA))

The same logic applies to the x-axis using scale_x_continuous

⇧ Back to TOCR: 4.0.2 ◊ ggplot2: 3.3.2

Add, remove, and modify a legends

Add a legend to a single plot

Legend are automatically created if color (also spelled as colour) is assigned to the categorical or group variable. This requires data to be in the longer (gathered) format.

ggplot(mydataset, aes(xvar,yvar,color=groupvar)) +

Alternatively, if the data is in wider (spread) format, color can be assigned within each individual aesthetic with the legend label of choice.

# Data must be in wider (spread) format.
# Manually assign labels through the 'color' variable.

ggplot(mydataset, aes(x = xvar))+
  geom_line(aes(y = yvar1, color = "Label 1")) +
  geom_line(aes(y = yvar2, color = "Label 2"))

⇧ Back to TOCR: 3.6.2 ◊ ggplot: 3.2.1

Add a common legend to multiple plots (cowplot)

Recipe assumes that all plots share the same legend


  1. Create individual plots without legends (removed using theme(legend.position = "none"))
  2. Create a common legend by taking the legend details from one of the plots. Each individual plot should have the same legend therefore it doesn't matter which one we grab. Change the parameters to make it visible and put in the shape desired (e.g. single row for plot bottom)
  3. Create a cowplot::plot_grid for just the plots
  4. Create a new cowplot::plot_grid with the first plot grid and the legend
# Create the individual plots without legends
p1 <- p1 + theme(legend.position = "none")
p2 <- p2 + theme(legend.position = "none")
p3 <- p3 + theme(legend.position = "none")
p4 <- p4 + theme(legend.position = "none")

# Create the common legend
legend <- get_legend(
  p1 + 
    # Make the legend visible. Bottom alignment.
    theme(legend.position = "bottom") +
    guides(color = guide_legend(nrow = 1))

# Plot grid of just the plots
pall <- cowplot::plot_grid(p1, p2, p3, p4)

# Plot grid of the the plot grid defined above and the legend 
plot_grid(prow, legend_b, ncol = 1, rel_heights = c(1, .1))

⇧ Back to TOCR: 4.0.2 ◊ ggplot2: 3.3.2 ◊ cowplot: 1.0.0

Overwrite or change automatic legend labels

Overwrite the labels. The labels must be provided in the same alphabetical order as the default legend.

Method 1: Use scale_color_discrete()

p + scale_color_discrete(labels = c("label1", "label2", "label3"))

Method 2 (for point or line plot): Use scale_color_manual()

p + scale_color_manual(labels = c("label1", "label2", "label3"))

Method 2 is required when we also need to also change the color palette, e.g.

p + scale_color_manual(labels = c("label1", "label2", "label3"),
                       values = cbPalette)

We can't use both scale_color_discrete() and scale_color_manual() The two methods compete with eachother.

Method 3 (for fill-type plots): Use scale_color_manual()

As Method 2, but for fill-type plots.

p + scale_color_manual(labels = c("label1", "label2", "label3"))

# Or if we also need to specify a color palette
p + scale_color_manual(labels = c("label1", "label2", "label3"),
                       values = cbPalette)

⇧ Back to TOCR: 4.0.1 ◊ ggplot2: 3.3.2

Move a legend to different location

Legend position is set through the parameter legend.position within theme(). The variable accepts words, e.g. "top", "bottom", "left", "right", or relative x,y coordinates such as c(0.8,0.8).

The new legend will be automatically reshaped for its new location, e.g. a legend.position of "right" (default) will create a column-like legend, a legend.position of "bottom" will create a horizontal-like legend.

# Example 1
p + theme(legend.position = "top")

# Example 2
p + theme(legend.position = c(0.8,0.8))

⇧ Back to TOCR: 3.6.2 ◊ ggplot2: 3.2.1

Remove entire legend

p + theme(legend.position = "none")

⇧ Back to TOCR: 3.6.2 ◊ ggplot: 3.2.1

Remove legend title

p + theme(legend.title = element_blank())

⇧ Back to TOCR: 3.6.2 ◊ ggplot: 3.2.1

Change legend title

Example 1: For point- or line-like plots

# For geom_line, either
p + labs(color="New Legend Title")
# or
p + labs(color=guide_legend(title="New Legend Title"))

Example 2: For fill-like plots

# For geom_boxplot, either 
p + labs(fill="New Legend Title")
# or 
p + labs(fill=guide_legend(title="New Legend Title"))

⇧ Back to TOCR: 3.6.2 ◊ ggplot2: 3.2.1

Change legend shape

Method 1: Specifying number of rows (e.g. put everything in a single row)

# set 'nrow = 1' for a single row (everything arranged horizontally)
p + guides(color = guide_legend(nrow = 2))

Method 2: Specify the box shape

p + theme( = "horizontal")

⇧ Back to TOCR: 3.6.2 ◊ ggplot2: 3.2.1

Make legend background transparent

Useful when positioning a legend inside a plot. The default legend background is a white rectangle and it will overlay and hide plot elements like grid lines or plot borders.

p + theme(legend.background = element_rect(fill = 'transparent', color=NA))

⇧ Back to TOCR: 3.6.2 ◊ ggplot2: 3.2.1

Add or modify plot text

Put a portion of a title or subtitle in italics or bold font

Using library ggtext. Its theme element element_markdown() understands basic markup characters like * and **.


ggplot(iris, aes(Sepal.Length, Sepal.Width)) + 
geom_point() + 
    title = "Sepal length and sepal width of various *Iris* species",
    x = "Sepal length (cm)",
    y = "Sepal width (cm)"
  ) +
# Use ggtext::element_markdown() theme element(instead of element_text(). It
# understands basic markup characters like `*` (italics), and `**` (bold)
theme(plot.title = ggtext::element_markdown())

⇧ Back to TOCR: 4.0.2 ◊ ggplot2:3.3.2 &loz ggtext: 0.1.0

Change plot aesthetics

Change the default color palette (e.g. to a colorblind palette)

Automatic ggplot color choices can be overwritten by providing a color palette. For example, two color-blind palettes:

# Color blinds pallettes. Both palettes are identical except for the first
# color which is either grey or black.

# Colorblind palette with grey
cbPalette <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442",
                "#0072B2", "#D55E00", "#CC79A7")

# Colorblind palette with black
cbbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442",
                 "#0072B2", "#D55E00", "#CC79A7")

Example 1: For line and point colors use scale_color_manual()

p + scale_color_manual(values = cbPalette)

Example 2: For fills use scale_fill_manual

p + scale_fill_manual(values = cbPalette)

⇧ Back to TOCR: 4.0.2 ◊ ggplot2:3.3.2

Increase line thickness

Use the size parameter

p + geom_line(size=1.0)

⇧ Back to TOCR: 3.6.2 ◊ ggplot: 3.2.1

Combine multiple plots

Using 'grid' library

Package 'grid': from


# 'p1','p2' are ggplot objects
grid.draw(rbind(ggplotGrob(p1), ggplotGrob(p2), size = "last"))

This can be modified to write a PDF of the plot to disk


grid.draw(rbind(ggplotGrob(p1), ggplotGrob(p2), size = "last"))

⇧ Back to TOCR: 4.0.2 ◊ ggplot: 3.3.2 ◊ grid: 4.0.2

Using 'cowplot' library


# plot1, plot2, etc. are ggplot objects. Any number of these can be supplied as
# arguments.
cowplot::plot_grid(p1, p2, p3, p4, ncol = 2)

# Save plot to disk
cowplot::save_plot("myplot.png", p_allforecasts)

⇧ Back to TOCR: 4.0.2 ◊ ggplot: 3.3.2 ◊ cowplot: 1.0.0

Saving a plot

Save a plot as a png image

Function ggsave() will save the last rendered plot.

# By default ggsaves the last rendered plot
ggsave("myplot.png", width = 6, height = 4.25, units = "in")

⇧ Back to TOCR: 3.6.2 ◊ ggplot 3.2.1


Pass a variable name as a string

See ggplot reference: defining aesthetic mappings progromatically

Quick answer: use aes_string() instead of aes() to define the aethetic..

The passed variable string can be an expression. For example, assuming we had the variables INCOMING and OUTGOING in our dataset we could could pass yvar = "INCOMING - OUTGOING" to our function plotVariable()

# Example assumes we've already loaded a data.frame with the name 'dframe' into
# memory. 'xvar', 'yvar', and 'groupvar' are strings.
plotVariable <- function(xvar, yvar, groupvar){

  p <- ggplot(dframe, aes_string(xvar, yvar, color = groupvar) +


⇧ Back to TOCR: 3.6.2 ◊ ggplot: 3.2.1