Mastering ggplot2 Themes

From Preset Templates to Custom Visual Branding

Author

Abdullah Al Shamim

Published

February 12, 2026

What are Themes?

In ggplot2, the geometry defines the data representation (dots, lines, bars), while the theme controls the non-data ink. This includes fonts, background colors, grid lines, and legend placement.

To customize a plot, you identify a component (e.g., axis.title) and assign it an element function: * element_text(): For titles and labels. * element_line(): For grid lines and axes. * element_rect(): For backgrounds and borders. * element_blank(): To remove a component entirely.


1. Using Preset Themes

ggplot2 comes with several built-in “all-in-one” themes. These are the quickest way to change the entire look of your plot.

Code
library(tidyverse)

# Base Plot
p <- ggplot(mtcars, aes(wt, mpg)) + 
  geom_point() + 
  ggtitle("Weight vs MPG") + 
  xlab("Weight (1000 lbs)") + 
  ylab("Miles per Gallon")

# Comparison of popular presets
# theme_bw(): White background with gray gridlines
# theme_minimal(): No borders, very clean
# theme_classic(): No gridlines, x and y axes only
Code
p + theme_bw() + ggtitle("Theme: Black & White")

Code
p + theme_classic() + ggtitle("Theme: Classic")

Code
p + theme_minimal() + ggtitle("Theme: Minimal")

Code
p + theme_void() + ggtitle("Theme: Void (Completely Empty)")


2. Customizing Specific Components

You can fine-tune every pixel using the theme() function.

Titles and Axes

Code
p + theme(
    plot.title = element_text(color = "steelblue", face = "bold", hjust = 0.5, size = rel(2)),
    axis.title = element_text(color = "red", face = "bold.italic"),
    axis.text = element_text(color = "blue", size = 12),
    axis.line = element_line(linewidth = 1, color = "black")
  )

Backgrounds and Grids

Use element_rect for backgrounds and element_line for the grid system.

Code
p + theme(
    panel.background = element_rect(fill = "lightyellow", color = "lightblue", linewidth = 2),
    plot.background = element_rect(fill = "lightgrey"),
    panel.grid.major = element_line(color = "white", linewidth = 0.5),
    panel.grid.minor = element_blank() # Remove minor grid lines
  )


3. Legend Customization

Legends are controlled via legend.* arguments. You can move them, style their background, or change their text.

Code
p_legend <- ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) + 
  geom_point() + 
  labs(title = "Weight vs MPG by Cyl", color = "Cylinders")

p_legend + theme(
    legend.position = "bottom",
    legend.background = element_rect(fill = "ivory", color = "black"),
    legend.key = element_rect(fill = "white"),
    legend.title = element_text(face = "bold")
  )


4. Facet Styling (Strips)

When using facet_wrap, the labels at the top of each box are called strips.

Code
p_facet <- ggplot(mtcars, aes(wt, mpg)) + 
  geom_point() + 
  facet_wrap(~cyl) + 
  ggtitle("Weight vs MPG by Cylinders")

p_facet + theme(
    strip.background = element_rect(fill = "steelblue", color = "black"),
    strip.text = element_text(color = "white", face = "bold"),
    panel.spacing = unit(2, "lines") # Increase space between panels
  )


5. Global Theme Setting

Instead of adding theme() to every single plot, use theme_set() at the start of your script to establish a systemic “house style.”

Code
# Set a global professional theme
theme_set(
  theme_minimal() +
  theme(
    plot.title = element_text(size = 18, face = "bold", color = "steelblue4", hjust = 0.5),
    panel.background = element_rect(fill = "white", color = NA),
    plot.background = element_rect(fill = "gray98", color = NA)
  )
)

# Any plot created now will automatically use these settings
p


Systemic Summary Toolkit

Component Element Function Common Arguments
Text (Titles, Labels) element_text() family, face, color, size, hjust
Lines (Axes, Grids) element_line() color, linewidth, linetype
Rectangles (Backgrounds) element_rect() fill, color, linewidth
To Hide/Remove element_blank() No arguments needed