Fun with ggplot2's themes

May 7, 2020 • PD Schloss • 12 min read

If you’re like me, you’re not a big fan of ggplot2’s default plot style. Somewhere I heard that developers make these types of default themes ugly so that you have to change them. Aside from using some of the other built in themes (e.g. theme_classic, theme_dark), there are the ggthemes package with a bunch of other canned themes and the theme function. For today’s Code Club we are going to see how you can manipulate the built in themes, pick themes from ggthemes, and use the theme function to make your own modifications. Altering the styling of a figure can be helpful if you need to modify a figure to adapt something you made for a paper to something you’d like to show in a presentation. Alternatively, as we’ll see, if you have a “brand” and want to have a consistent style across figures, you can create a theme that is then used in each case.

We’ll take a different approach to previous Code Clubs in the video for this week. I’ll present a brief lesson and then turn you loose on your own to work through some lessons. Finally, I’ll come back and give you my solutions. Don’t watch the video straight through without firing up RStudio and trying the code and exercises yourself! Please be sure to see the setup instructions before you get going.


Here is a code chunk that was modified from the second exercise in the first Code Club. You’ll notice I removed the theme_classic() line from my ggplot block and that I assigned the block to the variable p.


candy_data <- read_csv("",

pluribus_data <- candy_data %>%
	filter(pluribus & (chocolate | fruity)) %>%
	pivot_longer(cols=c(chocolate, fruity), names_to="type", values_to="answer") %>%

p <- pluribus_data %>%
	ggplot(aes(x=type, y=winpercent, color=type)) +
	geom_jitter(width=0.1) +
	scale_x_discrete(breaks=c("chocolate", "fruity"), labels=c("Chocolate", "Fruity")) +
	coord_cartesian(ylim=c(0,100)) +
	labs(y="Contests won (%)",
		x="Type of candy",
		title="Bite-sized candies containing chocolate are preferred to candy without",
		subtitle="Data collected by")

That p variable holds the “value” of the plot. If you enter “p” at the R prompt it will generate the figure. This is often done so that you don’t have to repeat all the lines of code to that point and you can add additional layers to the plot. For example, this line of code applies theme_bw to our figure

p + theme_bw()

Built in themes

theme_bw is one of the themes that is built into ggplot2. Here are some of the others that you can use…

p + theme_gray() # the default
p + theme_linedraw()
p + theme_light()
p + theme_dark()
p + theme_minimal()
p + theme_classic()
p + theme_void()

Extra themes

If you want more options, you can check out the ggthemes package, which has people’s attempts at trying to recreate the themes they see from other software packages (e.g. theme_excel) and websites (e.g. theme_economist). You can find a gallery of themes in ggthemes and in other packages (e.g. the xkcd package) at allYourFigureAreBelongToUs. Be sure to install ggthemes or the package with the theme you want before attempting to use the theme


p + theme_economist() #
p + theme_excel()
p + theme_fivethirtyeight()

Passing arguments into theme_xxxxx functions

You can manipulate a lot in a figure by giving these default themes a few different arguments including base_size, base_family, base_line_size, and base_rect_size. These will change the font size, font type, thickness of the lines, and the size of border on rectangular elements.

p + theme_classic()
p + theme_classic(base_size = 20) #a number, default = 11
p + theme_classic(base_family = "mono") #a font family, default = sans (serif, mono, symbol); see extrafont package
p + theme_classic(base_line_size = 2) #a number, size for line elements, default = base_size/22

You should notice that when you change something like base_size all of the font sizes for the titles, axis titles, axis labels and axis values are scaled according to this base value. We can say that the value is inherited as we go down the cascade of related styles.

Digging into theme

These options may only get you so far. You might find that you like theme_classic, but want to change one or two things. This brings us to the theme function. This function has one of the more intimidating help pages


I’d encourage you to skip the Usage section and go to the Arguments section for an easier view of the various things you can manipulate. You’ll notice that there is generally a hierarchy to how they’re named. Unfortunately, they are mainly listed alphabetically not hierarchically

When setting the values for the theme parameters for some arguments they take a character or logical value. More frequently they take one of five functions.

You should look at the help pages for those functions to get a sense of their syntax. The arguments that these functions take can be a bit opaque

Let’s see how we can put this together to make something garish…

p +
	theme_gray() +
	theme(plot.title = element_text(color="red", family="mono", size=18),
		axis.title = element_text(color="blue"),
		axis.title.x = element_text(size = rel(2.0), family="serif"),
		legend.background = element_rect(color="black", fill=NA),
		plot.background = element_rect(fill="lightgray"),
		panel.grid.major.y = element_line(linetype=3),
		panel.background = element_rect("pink"))

Looking behind the curtain of a theme_xxxx function

One trick you can use to figure out how a theme is made is to recall that if you enter the name of a function at the prompt without any arguments or the parentheses you will often get the code for the function. Well, theme_excel is a function! For the assignments, try not to use this approach to engineer your own version of these theme_xxxx functions.


1. Without using theme_xxxxxx functions, make p look like p + theme_classic() using theme(). Hint: Within RStudio’s “Plots” panel you can use the arrow buttons to toggle between versions of plots

p + theme_classic()

p + theme(
	panel.grid = element_blank(),
	panel.background = element_blank(),
	axis.line = element_line(lineend ="round"),
	legend.key = element_blank()

2. Without using theme_xxxxxx functions, make p look like p + theme_dark() using theme().

p + theme_dark()

p + theme(
	line = element_line(size=0.25),
	panel.background = element_rect(fill="gray50"),
	panel.grid = element_line(color="gray40"),
	legend.key = element_rect(fill="gray50", color=NA)

3. Recreate the theme_fivethirtyeight theme using theme().

p + theme_fivethirtyeight()

p + theme(
	text = element_text(size=12),
	plot.title=element_text(face="bold", size=18),
	plot.margin = unit(c(1, 1, 1, 1), unit="lines"),
	plot.background = element_rect(fill="gray95", color=NA),
	panel.background = element_blank(),
	axis.title = element_blank(),
	panel.grid = element_line(color="gray80"),
	panel.grid.minor = element_blank(),
	axis.ticks = element_blank(),
	legend.position = "bottom",
	legend.background = element_blank(),
	legend.key = element_blank()