library(ggplot2)
library(gapminder)
library(dplyr)
library(wesanderson)
library(systemfonts)
# a bit of data processing
<- gapminder %>%
dat group_by(year, continent) %>%
summarise(`Life Expectancy` = mean(lifeExp),
Population = sum(as.numeric(pop)),
.groups = 'drop') %>%
rename(Year = year, Continent = continent)
ggplot2 has become one of the most powerful and flexible visualisation tools, with a large community and lots of people working on new extensions every day. A large number of ways to represent data makes it possible to create nearly anything in ggplot2
, from great data journalism to beautiful infographics and generative art. No post-processing required anymore.
The general look of a ggplot is controlled by a theme. Anyone using ggplot knows that the default grey theme is usually not what you want to show the world. Modifying themes is very flexible, but a little bit complicated. Even after using it for years, I have to google some things every single time. Creating your own theme is a way to give your plots a consistent and personal design, and will save you a lot of time and many lines of code.
The default ggplot
Let’s use the data from gapminder to see how a default plot looks like. We first load a few packages and do some data pre-processing.
Here is a default theme_grey()
scatterplot.
ggplot(dat, aes(Year, `Life Expectancy`, color = Continent)) +
geom_point()
There are a few things I change all the time:
The background, which I prefer simple plain, or only with x and y axis lines.
Grid lines: I usually keep only major grid lines (as they are connected to values) or remove them entirely.
The spacing between axis, axis-labels and axis-titles.
The font.
For themes with axis lines, like theme_classic, the line thickness.
Making your own theme
Making a new theme is quite simple. We (1) create a function which starts with a standard theme, such as theme_minimal
and (2) add all the theme aspects which we prefer for our plots. Finally (3), we add some arguments to make changing things easy which we need often, such as axis and grid lines and the text size. Below is the theme I am using, but of course you can change every other theme aspect too (see theme documentation). I’m often using the ‘Avenir Next’ font, which might not be installed on your system. Using ‘sans’ should always work.
<- function(axis_lines = TRUE,
theme_simple grid_lines = FALSE,
text_size = 12,
line_width = 0.2,
# replace with 'sans' if not working
base_family= 'Avenir Next'){
# start with theme_minimal because it is really simple.
<- ggplot2::theme_minimal(base_family = base_family,
th base_size = text_size)
# remove the grid lines
<- th + theme(panel.grid=element_blank())
th
# if we want axis lines
if (axis_lines) {
# We add axis lines and give them our preferred thickness
<- th +
th theme(axis.line = element_line(linewidth = line_width),
axis.ticks = element_line(linewidth = line_width))
} # do we want grid lines?
if (grid_lines) {
<- th +
th theme(panel.grid.major = element_line(linewidth = line_width))
}
# more space for axis text/title and plot title
<- th + theme(
th axis.text.x=element_text(margin=margin(t=5)),
axis.text.y=element_text(margin=margin(r=5)),
axis.title.x=element_text(margin=margin(t=10)),
axis.title.y=element_text(margin=margin(r=10)),
plot.title=element_text(margin=margin(b=10)))
return (th)
}
Adding theme_simple
to the plot.
Now, we can add theme_simple()
to the plot.
ggplot(dat, aes(Year, `Life Expectancy`, color = Continent)) +
geom_point() +
scale_color_manual(values = wes_palette("Darjeeling2")) +
theme_simple()
Small tweaks can sometimes make a big aesthetic difference. ggplot
comes with a few themes, like theme_classic(), which are sort of close to what I like my plots to be, but are just not quite there. If you feel the same, it’s time to make your own theme.
Lastly, you can put the code for your theme into an R script and save it, for example as theme_simple.R. The next time you make plots, just source the script to load the theme_simple()
function. To use it as the default theme, we can use theme_set like so:
source("theme_simple.R")
# set theme_simple as default theme
::theme_set(theme_simple()) ggplot2
That’s it!
If you are plotting in base R, you might say: You need a full blog post just to explain how to make ggplot look like base R with a different font! And I can only say: touché, my friend.
Appendix: Installing fonts
Fonts can really make a big difference in the visual design of plots. A lot of freely available fonts are on https://fonts.google.com/. On Mac, I just download them, double click and they are installed. Then, we have to make them available in R. The systemfonts
package magically finds all installed fonts from different directories.
# install.packages("systemfonts")
library(systemfonts)
# which fonts are installed?
# print only top 5
system_fonts()[1:5, ]
#> # A tibble: 5 × 9
#> path index name family style weight width italic monospace
#> <chr> <int> <chr> <chr> <chr> <ord> <ord> <lgl> <lgl>
#> 1 /System/Library/Assets… 0 Balo… Baloo… Regu… normal norm… FALSE FALSE
#> 2 /System/Library/Assets… 8 Nira… Niram… Light light norm… FALSE FALSE
#> 3 /System/Library/Assets… 0 Shob… Shobh… Regu… normal norm… FALSE FALSE
#> 4 /System/Library/Fonts/… 1 Telu… Telug… Bold bold norm… FALSE FALSE
#> 5 /Users/msto/Library/Fo… 0 JetB… JetBr… Semi… semib… norm… FALSE TRUE
pdf-ing
Sometimes, especially for science publications, plots need to be saved as pdfs. With non-standard fonts, this can be problematic, because they have to be embedded, but a little tweak to ggsave()
can help here.
ggsave("plot.pdf", device = cairo_pdf)