Written and maintained by CASRAI Editorial Board
Last updated
A ggplot2 theme controls everything on a plot that is not data: background, gridlines, axis lines, text, legend position. ggplot2 ships nine complete themes, theme() adjusts individual elements of one plot, and theme_set() changes the default for every plot you draw afterwards. The difference between those last two, and the exact difference between theme_update() and theme_replace(), is where most confusion comes from, so this guide leads with it.
What ggplot themes are used for in research
Themes make a figure fit its destination: a journal column, a slide, a poster. Because the theme is separate from the data layers, you can restyle a whole figure without touching the analysis code, and a lab can keep one theme definition so every figure looks consistent. For plotting basics see ggplots in R; this page covers only the styling layer. If a figure goes into a manuscript, pair it with a proper figure legend.
Install or access
ggplot2 is distributed through CRAN and documented at ggplot2.tidyverse.org. Install and load it from R:
install.packages("ggplot2")
library(ggplot2)
The extra theme collection ggthemes is optional. The CRAN page describes it as “Extra Themes, Scales and Geoms for ‘ggplot2′”; version 7.0.0 was published 2026-10-03 under GPL-2 and requires R (>= 4.1.0) and ggplot2 (>= 3.5.2). Install it with install.packages("ggthemes") only if the built-in themes are not enough. Cite the packages you use; see how to cite software, code and R packages.
Step-by-step: choose, tweak and set a theme
1. Pick a complete theme
Add a complete theme to a plot with +. Assuming your plot is stored as p:
p + theme_bw()
The ggplot2 reference lists these complete themes, all sharing the same arguments, theme_grey(base_size = 11, base_family = "", header_family = NULL, base_line_size = base_size/22, base_rect_size = base_size/22, ink = "black", paper = "white", accent = "#3366FF"):
| Function | What the reference says |
|---|---|
theme_grey() / theme_gray() |
The default: grey background with white gridlines, designed so the data stands out. |
theme_bw() |
Dark-on-light variation of the default; may work better for presentations displayed with a projector. |
theme_linedraw() |
Only black lines of various widths on white. Includes some very thin lines (much less than 1 pt) which some journals may refuse. |
theme_light() |
Similar to theme_linedraw() but with light grey lines and axes, directing attention to the data. |
theme_dark() |
The dark version of theme_light(); can make thin coloured lines stand out. |
theme_minimal() |
No background annotations. |
theme_classic() |
Axis lines for x and y, no gridlines. |
theme_void() |
A completely empty theme; its paper default is transparent. |
theme_test() |
For visual unit tests of ggplot2 itself; not intended for figures. |
The header_family argument sets the font family for axis titles, legend titles, the plot title and the tag; when NULL they inherit base_family. Source: ggplot2 reference, complete themes (checked 2026-10-29).
2. Tweak elements with theme()
Use theme() to change individual elements of the plot in front of you. Each element has a matching constructor: element_line() for lines, element_rect() for rectangles, element_text() for text, and element_blank() to remove an element. Examples taken from the ggplot2 reference:
p + theme(plot.title = element_text(size = rel(2)))
p + theme(plot.background = element_rect(fill = "green"))
p + theme(panel.grid.major = element_line(colour = "black"))
p + theme(legend.position = "bottom")
p + theme(strip.text.x = element_text(colour = "white", face = "bold"))
Elements inherit from more general ones. The reference’s own example: axis.title.x.bottom inherits from axis.title.x, which inherits from axis.title, which inherits from text. Likewise panel.grid inherits from line, and plot.title inherits from title and is left-aligned by default. Practical consequence: setting one high-level element such as text restyles many elements at once, while setting a specific one overrides only that element.
3. Set a theme for every plot
A plot-level + theme_bw() affects one plot. The active theme, by contrast, is applied automatically to every plot you draw. Replace it with theme_set() (also available as set_theme()), which returns the previous theme invisibly so you can restore it:
old <- theme_set(theme_bw())
p
theme_set(old)
Calling theme_set() with no argument resets the active theme to theme_grey(). Use theme_get() to inspect what is currently active.
4. Change part of the global theme
Two functions modify the active theme instead of replacing it, and they differ in an important way:
| Function | How it combines | Unspecified settings |
|---|---|---|
theme_update() |
Uses + |
Keep their existing values |
theme_replace() |
Uses %+replace% |
Become NULL |
The reference example: theme_update(panel.grid.minor = element_line(colour = "red")). Both also invisibly return the previous theme. Source: ggplot2 reference, theme_get (checked 2026-10-29).
5. Build one reusable lab theme
To keep figures consistent across a project, combine a complete theme with your tweaks in one function and add it to every plot, or pass it to theme_set() once at the top of a script:
theme_lab <- function() {
theme_bw(base_size = 12) +
theme(legend.position = "bottom")
}
p + theme_lab()
Putting the theme in a script that is kept with the analysis is also a small reproducibility gain; see computational reproducibility.
Output and how to read it
A theme never changes the data mapping, scales or statistics: if a plot looks different after adding a theme, only non-data elements moved. To confirm what a theme changed, compare the plot with and without it. For journal submission, check the journal’s figure instructions for minimum line weight before using theme_linedraw(), since the reference warns about very thin lines. theme_void() removes axes entirely, so it suits maps or diagrams but not a plot a reader must read values from. Related plot-specific guides: box plots in R, histograms in R, scatterplots in R.
Troubleshooting
My theme() changes disappeared
A complete theme replaces the whole theme, so a complete theme added after your theme() call resets those tweaks. Put the complete theme first and your theme() adjustments after it: p + theme_bw() + theme(legend.position = "bottom").
Every plot suddenly looks different
An earlier theme_set(), theme_update() or theme_replace() in the session changed the active theme. Run theme_set() with no argument to return to theme_grey(), or restore the object you saved from the earlier call.
Elements went missing after theme_replace()
Because %+replace% turns unspecified values in the element into NULL, replacing a partly specified element can drop settings you expected to keep. Use theme_update() to keep them.
Free alternatives
| Option | What it is | Source |
|---|---|---|
| ggplot2 built-in themes | The nine complete themes above; no extra package. | ggplot2 reference |
| ggthemes 7.0.0 | “Extra Themes, Scales and Geoms for ‘ggplot2′”; GPL-2; needs R (>= 4.1.0). | CRAN package page |
FAQ
What is the default ggplot theme?
theme_grey(), with a grey panel background and white gridlines.
What is the difference between theme() and theme_set()?
theme() added with + changes only that plot. theme_set() changes the active theme applied to every plot drawn afterwards.
How do I remove gridlines or a legend?
Set the element to element_blank(), for example theme(panel.grid = element_blank()), or set legend.position = "none".
Which theme is best for a journal figure?
The documentation does not name one. It notes that theme_bw() may suit projected presentations and that very thin lines in theme_linedraw() may be refused by some journals; follow the target journal’s figure guidelines.
Sources
- ggplot2 reference: complete themes, checked 2026-10-29.
- ggplot2 reference: theme(), checked 2026-10-29.
- ggplot2 reference: get and set the active theme, checked 2026-10-29.
- CRAN: ggthemes package page, checked 2026-10-29.







