
The R versus Python debate is a favorite among data scientists. When it comes to Data Visualization, however, yours truly has a very clear preference: ggplot2
in R all the way.
Ease of data handling and formatting aside, ggplot2
shines in its customizability. The defaults look great, albeit very distinct, but with a bit of planning you can totally transform visualizations to fit any imaginable aesthetic. In this article I’ll walk through how to create a custom ggplot2
theme that can be applied to your graphs.
First things first
Open up a new R script that will contain your customizations. You’ll run this script before building any visualizations in order to make your settings available. You can package it up into a library, too, though that’s not strictly necessary.
Make sure to load up the necessary libraries. There’s nothing surprising here, just make sure ggplot
and scales
are loaded in before you do anything else.
library("Ggplot2")
library("scales")
Fonts
New font, new you. Right? There are several options for using a custom font in your graphs.
The first option involves using the fonts that are already on your machine. To access them, load the extrafont
library and import all fonts to R. Warning: This is slow. Once you’ve run font_import()
, comment it out and leave it alone. If you’re not sure what fonts are possible, use system_fonts()
to see a list.
library("extrafont")
font_import() # only run this once then comment out. It's slow!
extrafont::loadfonts()
library("systemfonts")
system_fonts() # shows you available fonts
The second option is to add in a Google font. The showtext
library will let you import a font from the Google font page using the font_add_google()
function. In this example, I’m importing the Reenie Beanie font for a fun handwriting effect.
library("showtext")
## Loading Google fonts (https://fonts.google.com/)
graphFont = "Reenie Beanie"
font_add_google(graphFont)
Themes
Under normal circumstances you might use the theme()
argument to make small changes to the default settings. Because ggplot2
is layered, adding +theme()
to the end of a visualization will override any preceding settings.
We can take advantage of this behavior by defining a bespoke theme that can be added at the end of any visualization. This means you could even go back to old work and apply your new theme to achieve a consistent portfolio. In this example, I’ve defined a straightforward theme that makes all the text black, specifies various background fills, and sets the font. Running theme
without the parentheses in R will show you all possible theme options.
theme_custom = function(){
theme(
panel.background = element_blank(),
panel.grid = element_blank(),
axis.ticks = element_blank(),
axis.text = element_text(color = "black"),
legend.box.background = element_blank(),
legend.key = element_rect(fill = NA),
text = element_text(graphFont),
plot.title = element_text(size = 16)
)
}
Color Scales
Setting up color pre-planned color scales can be a huge time saver—say goodbye to guessing which shade of magenta you used last time. I like to use the coolors app to create color palettes, and then create a vector of hex codes.
Remember that you’ll need to set a scale for both scale_color_manual()
and scale_fill_manual()
to account for the different geoms.
pal_custom = c("#9e0a0a", "#115035", "#ff9e97", "#f6cb4c")
### Scales
custom_color_manual = function(){
scale_color_manual(values = pal_custom)
}
custom_fill_manual = function(){
scale_fill_manual(values = pal_custom)
Custom geoms
If you would like specific behavior for certain types of graphs, customizing the geoms is the way to go. The update_geom_defaults()
function does the trick. In these examples, I’ve requested that points be at least size 3, bars have white outlines, and lines are size 1.
update_geom_defaults("point", list(size = 3))
update_geom_defaults("bar", list(color = "white"))
update_geom_defaults("line", list(size = 1))
Layering Themes
As if one theme wasn’t enough, you can actually layer themes. If, for example, you are only making small changes to an existing ggplot
theme, you can run the original first, and add your changes afterward.
In this example, I used the xkcd theme by Emilio Torres-Manzanera to achieve a hand-drawn look on the axes, and then applied my custom theme at the end.
ggplot(data=iris, aes(x=Sepal.Width)) +
geom_histogram(binwidth=0.1, aes(fill=Species)) +
custom_fill_manual() +
xlab("X-axis title") +
ylab("Y-axis title") +
ggtitle("Main chart title") +
theme_xkcd() +
xkcdaxis(range(iris$Sepal.Width),range(c(0, 30))) +
theme_custom()
The Before and After
This particular theme might not be your cup of tea, but it’s certainly different from the default look:


Testing
Establishing a custom aesthetic for your visualizations will take some iteration and testing. I recommend building a few test visuals that you can run when you update your theme—this will let you preview the effects on different chart types. Having a handful of test figures will also allow you to conduct accessibility checks and ensure that your theme is user-friendly. I use the Sim Daltonism app to evaluate color palettes and the Accessibility Insights extension to check web elements.
A knitr (.Rnw
) or R Markdown (.Rmd
) script works nicely for testing because it can be easily recompiled to produce a sharable document. Something as simple as this will do the trick:
documentclass[a4paper]{article}
begin{document}
<<projections, include=FALSE, cache=FALSE>>==
source("branding.R")
opts_chunk$set(dev='cairo_pdf')
@
<<renderimage, echo = FALSE, fig.height = 3, fig.width = 5, fig.align='center'>>==
ggplot(data=iris, aes(x=Sepal.Width)) +
geom_histogram(binwidth=0.1, aes(fill=Species)) +
custom_fill_manual() +
xlab("X-axis title") +
ylab("Y-axis title") +
ggtitle("Main chart title") +
theme_xkcd() +
xkcdaxis(range(iris$Sepal.Width),range(c(0, 30))) +
theme_custom()
@
end{document}
And that’s it! I hope this gives you a few ideas on how you can create a custom theme for your own ggplot2
work. Start small, see what works, and build from there. Your graphs will be turning heads in no time.
Thinking about accessibility in data visualization? Great! Here are some ways to get started: