An overview of ggplot2 themes

In this post I will provide an overview of the categories of complete themes available for ggplot2, the best data visualisation package available for R, bar none. By complete themes I mean functions with the prefix theme_* available in CRAN packages used to customise your ggplot2 plot. In other words, I only consider packages available on CRAN (e.g., it is not sufficient to be available on GitHub or Bitbucket) and functions using the theme_* syntax to call the theme.

I have been going through a lot of packages that provide additional functionalities to {ggplot2}, especially when working on my GitHub repository awesome-ggplot2 over the years. A lot of these packages provide customised themes that can make it easier to obtain a beautiful ggplot2 object without having to dig into the various options available in ggplot2::theme().

In total, for this post, I have looked into 153 functions available in 56 CRAN packages. In doing this, I have identified eight categories of theme functions. These categories are not necessarily mutually exclusive, but they are – at least in my view – useful in terms of understanding the customised theme landscape for ggplot2. I will go through each of these eight categories before providing an overview of all functions I have encountered. If I have missed anything, as always, please do feel free to reach out.

Category 1: Nothing

In the beginning, there was nothing. In the ggplot2 package, you will find theme_void(), that is a completely empty theme. There are several themes available in the CRAN packages providing similar themes.

Most noteworthy is the theme function theme_nothing() that is provided in four different packages, namely {cowplot}, {ggfun}, {ggimage}, and {ggmap}. This is, alas, not the only theme function that is available across multiple packages, and I would prefer if theme functions did not overlap between different packages. In other words, if you develop your own ggplot2 theme, please make sure that the function name is not already taken by another theme in another package available on CRAN and beyond.

Of course, the themes that provide ‘nothing’ does not remove everything – only as many of the theme options as possible for there to be nothing left but the geometrics and aesthetics of the visualisation. Similar themes are available in functions such as theme_blank() in {ggnetwork}, theme_clean() in {ggiraphExtra} and theme_transparent in {ggpubr}.

Most of the ’empty’ themes are related to specific plot types. For example, when you want to visualise geospatial data, it is good to have the option to keep it simple. Accordingly, packages used to show maps have such empty themes, e.g., theme_white_f() in {ggswissmaps} and theme_mapcan in {mapcan}. Below I show an example of how theme_mapcan() removes all default features from a ggplot2 object.

There are multiple examples of such theme functions that basically do ‘nothing’, and are functionally and conceptually similar to theme_void(), including ggparliament::theme_ggparliament(), ggdag::theme_dag(), ggdendro::theme_dendro(), and ggsoccer::theme_pitch(). There is no real need to deal with all of these functions, and if all you need to do is to remove as much as possible from your ggplot2 dataviz, theme_void() will in most cases do the trick.

Category 2: Minimalist

One of my favourite default ggplot2 themes is theme_minimal(). While the theme is minimalist, there are several theme functions available for users looking for even more minimalist ggplot2 objects.

The inspiration for various minimalist themes is the work by Edward Tufte, and in particular the notion of the data-ink ratio, i.e., that we should use as little ink as possible to display our data. Specifically, we should remove as much ink (or as many non-background colour pixels) from our figures as possible and focus on what is important.

For example, consider the description of ggthemes::theme_tufte(), the ‘Tufte Maximal Data, Minimal Ink Theme‘: “Theme based on Chapter 6 ‘Data-Ink Maximization and Graphical Design’ of Edward Tufte The Visual Display of Quantitative Information. No border, no axis lines, no grids.” It is indeed easy to see how the theme removes the border, axis lines and grids when used.

The minimalist themes are popular as they remove a lot of default theme settings (such as the grey background colour) that are not needed in most cases. Accordingly, we can see a lot of themes that aim towards providing a minimalist theme in ggplot2, such as add2ggplot::theme_white(), ggfun::theme_transparent(), ggimage::theme_transparent(), and ggiraphExtra::theme_clean2().

What we see with a minimalist theme is mostly about what we do not see. A good minimalist theme will have strong defaults that remove everything that is not needed to convey the signal in the visualisation, but nothing more. In other words, we can see the minimalist theme as a continuation of the ‘nothing’ themes, but with the addition of the core information required to understand and interpret the information (most often labels and axes information).

Category 3: Dark mode

While I do most of my R work in dark mode in my IDE, I rarely save figures with a dark theme. However, there are several dark themes available for ggplot2, in addition to ggplot2::theme_dark().

Some of these theme functions are shown in the figure below – i.e., ggseg::theme_darkbrain(), lcars::theme_lcars_dark(), hrbrthemes::theme_ft_rc(), and hrbrthemes::theme_modern_rc(). The themes differ in the colours and whatnot, but they are all very much dark.

Other noteworthy dark themes are theme_abyss(), theme_blackboard(), and theme_radar_dark() (all available in the package {see}). There is also a question about how dark a theme should be before it is a dark theme. I would not add, for example, add2ggplot::theme_grey_and_red() to the list of dark themes, but it is close.

I should also mention the package {ggdark} which I am not including here due to the syntax. That is, the package uses dark_* to provide dark variations of ggplot2 themes, e.g., dark_theme_bw(). However, if you are interested in dark themes to ggplot2, I can definitely recommend checking out the package.

Category 4: Popular culture

This is my least favourite category of ggplot2 themes. They tend to get a lot of attention on social media, most likely due to the juxtaposition of statistical programming and people’s favourite TV shows and movies. I am not against these themes per se, but they often require a lot more work to be useful, and even then, it is not always clear what the actual use case is.

In the figure below we look at four themes from the {tvthemes} package, namely theme_brooklyn99() (for Brooklyn Nine-Nine), theme_simpsons() (for The Simpsons), theme_rickAndMorty() (for Rick and Morty), and theme_parksAndRec() (for Parks and Recreation. Again, in these figures I only show the application of the theme function and not any other functions that be required to make the figures reflect the visual style of the respective TV series (in particular the font and various colours).

While I personally am not a great fan of these themes, I do believe they showcase how much flexibility there is in ggplot2 to customise figures. A customised ggplot2 theme is not only about changing a few grid lines but potentially about shaping the whole identity of a figure. That being said, it also shows how much work is often required to make a good visualisation beyond what can be obtained with a theme_* function. Try, for example, to make a ggplot2 object look like an xkcd comic with the {xkcd}. It is more difficult than it looks.

For another R package that introduces a lot of themes related to popular culture, do also check out the {ThemePark} package. It is not on CRAN yet so I have not included it here. However, from what I can understand, it should be on the way to a CRAN near you soon.

Category 5: Media outlets

Media outlets often have their own unique visual style, and there are of course themes available to reproduce these visual styles when working with ggplot2 objects. In the figure below I show four examples of such themes, namely ggthemes::theme_economist() (for The Economist), ggthemes::theme_fivethirtyeight() (for FiveThirtyEight), ggthemes::theme_wsj() (for Wall Street Journal), and wsjplot::theme_wsj() (also for Wall Street Journal).

There is no guarantee that using these themes will reflect the (current) theme defaults used by the respective media outlets. For example, The Economist recently changed their style and it is not reflected in the theme above. In addition, consider how the two examples of theme_wsj() from different packages are very different.

In addition, do keep in mind that none of these themes are ‘official’ in the sense that they are associated with any of the specific media outlets. The only exception I am familiar with is the {bbplot} package (for BBC), but this package never made its way to CRAN (and I doubt it ever will).

Category 6: Software

If you do not want it to look like your figure was made with R, but instead, say, Stata, look no further. In the figure below you will find some examples of themes that reflect the theme defaults from other software, i.e., ggthemes::theme_excel_new(), ggthemes::theme_stata(), jmvcore::theme_spss(), and ggnuplot::theme_gnuplot().

Some of these themes look good, but it is never clear to me why you would want your figures to look more like Excel than R. If anything, Excel should make it easier to make it look like your figure was made in R.

Noteworthy, the theme defaults were changed in Stata 18, so the above-mentioned Stata theme is for the now old Stata defaults. Unironically, I do like the new Stata defaults better than ggplot2 defaults. That being said, in general, I am not in favour of making it look like a figure was made in a different software.

Category 7: Statistical models

Several themes are related to the visualisation of specific statistical models. When an R package provides functions to work with specific statistical models, they often provide additional functions to help visualise the output from these models. This is similar to the packages mentioned above working with geospatial data providing theme functions removing grid lines and labels.

To better understand the usefulness of these functions, it makes sense to check out the functions in their natural habitat, i.e., when being used to visualise the output they are made to visualise. Below I show examples of such functions in the form of ggsurvfit::theme_ggsurvfit_default(), ggsurvfit::theme_ggsurvfit_KMunicate(), survminer::theme_survminer(), and ggdist::theme_tidybayes().

Interestingly, these themes are more than fine for most plot types. If you are looking for inspiration on how best to visualise the results from specific models, it is worth checking out the various themes available within the ggplot2-verse.

Category 8: Border, axis lines, and grid preferences

This is the catch-all category for all the themes that changes the borders, axes, grid lines, etc., but cannot fit into any of the categories mentioned so far. To just illustrate a few, here are four examples in the form of cowplot::theme_minimal_hgrid(), ezplot::theme_ez(), tinythemes::theme_ipsum_rc(), and ggfun::theme_noxaxis().

These are all – conditional upon the focus of the visualisation – great themes, and I prefer most of these themes over the default ggplot2 theme. That being said, after having gone through a lot of themes, I will still stick to the good old theme_minimal() and theme_bw().

The overview I have presented here should not be seen as a fully comprehensive overview of all themes (especially as a lot of themes are not available on CRAN), but it hopefully serves as an introduction to some of the key differences between the different themes.

Overview of packages

If there is one thing we are not running short of today, it is customised themes for ggplot2 available in various CRAN packages. In the table below, I provide an overview of all the ggplot2 themes using the theme_* syntax I have been able to locate on CRAN with information on the packages they are in and the most recent version of the package (I have sorted the packages by how popular they are – with {ggplot2} itself being the most popular).

Package Version Theme functions
ggplot2 3.5.1 theme_void, theme_dark, theme_set, theme_classic, theme_test, theme_linedraw, theme_minimal, theme_update, theme_light, theme_replace, theme_grey, theme_get, theme_bw, theme_gray
ggmap 4.0.0 theme_inset, theme_nothing
ggpubr 0.6.0 theme_pubclean, theme_cleveland, theme_classic2, theme_pubr, theme_transparent
cowplot 1.1.3 theme_half_open, theme_cowplot, theme_minimal_vgrid, theme_nothing, theme_minimal_hgrid, theme_minimal_grid, theme_map
ggforce 0.4.2 theme_no_axes
ggridges 0.5.6 theme_ridges
ggthemes 5.1.0 theme_solid, theme_tufte, theme_fivethirtyeight, theme_hc, theme_igray, theme_economist_white, theme_excel_new, theme_solarized_2, theme_base, theme_few, theme_excel, theme_foundation, theme_clean, theme_economist, theme_gdocs, theme_wsj, theme_stata, theme_pander, theme_calc, theme_map, theme_solarized, theme_par
survminer 0.4.9 theme_cleantable, theme_survminer
ggdist 3.3.2 theme_tidybayes, theme_ggdist
ggfun 0.1.4 theme_nothing, theme_noaxis, theme_noxaxis, theme_fp, theme_stamp, theme_transparent, theme_no_margin, theme_blinds, theme_noyaxis
hrbrthemes 0.8.7 theme_ipsum_rc, theme_ft_rc, theme_ipsum_es, theme_ipsum, theme_ipsum_pub, theme_modern_rc, theme_ipsum_ps, theme_ipsum_gs, theme_ipsum_inter
see 0.8.4 theme_radar, theme_lucid, theme_radar_dark, theme_modern, theme_abyss, theme_blackboard
ggdendro 0.2.0 theme_dendro
ggimage 0.3.3 theme_nothing, theme_transparent
ggstatsplot 0.12.3 theme_ggstatsplot
ggrastr 1.0.2 theme_pdf
egg 0.4.5 theme_presentation, theme_article
ggsurvfit 1.1.0 theme_risktable_default, theme_ggsurvfit_default, theme_risktable_boxed, theme_ggsurvfit_KMunicate
ggnetwork 0.5.13 theme_facet, theme_blank
ggmosaic 0.3.3 theme_mosaic
ggdag 0.2.12 theme_dag_grid, theme_dag_blank, theme_dag_gray_grid, theme_dag_grey, theme_dag_grey_grid, theme_dag, theme_dag_gray
ggiraphExtra 0.3.0 theme_clean2, theme_clean
jmvcore 2.4.7 theme_spss, theme_min, theme_default, theme_hadley
gggenes 0.5.1 theme_genes_flipped, theme_genes
ggupset 0.3.0 theme_combmatrix
ggseqlogo 0.2 theme_logo
ggOceanMaps 2.2.0 theme_map
jcolors 0.0.5 theme_dark_bg, theme_light_bg
tvthemes 1.3.3 theme_brooklyn99, theme_theLastAirbender, theme_parksAndRecLight, theme_hildaDusk, theme_simpsons, theme_parksAndRec, theme_hildaDay, theme_parksAndRec_light, theme_rickAndMorty, theme_spongeBob, theme_hildaNight, theme_avatar
onsvplot 0.3.2 theme_onsv
ggjoy 0.4.1 theme_joy
ggsoccer 0.1.7 theme_pitch
ggseg 1.6.5 theme_custombrain, theme_darkbrain, theme_brain2, theme_brain
aRtsy 0.2.4 theme_canvas
ezplot 0.7.13 theme_ez
ggcorset 0.5.0 theme_ggcorset
nestcolor 0.1.2 theme_nest
xkcd 0.0.6 theme_xkcd
ggDoE 0.8 theme_bw_nogrid
mlbplotR 1.1.0 theme_y_mlb, theme_x_mlb
add2ggplot 0.3.0 theme_grey_and_red, theme_classic2, theme_white, theme_ilo, theme_du_bois
utile.visuals 0.3.3 theme_risk, theme_basic
ipeaplot 0.3.1 theme_ipea
unhcrthemes 0.6.2 theme_unhcr
ggDoubleHeat 0.1.2 theme_heat
ggswissmaps 0.1.1 theme_white_f
ggpcp 0.2.0 theme_pcp
tgamtheme 0.1.0 theme_tgam
lcars 0.3.8 theme_lcars_light, theme_lcars_dark
mapcan 0.0.1 theme_mapcan
ggFishPlots 0.2.2 theme_fishplots
ggredist 0.0.2 theme_map
gglgbtq 0.1.1 theme_lgbtq
r2spss 0.3.2 theme_SPSS
tinythemes 0.0.2 theme_ipsum_rc
ggtea 0.1.1 theme_apricot, theme_matcha
ggthemeUL 0.1.3 theme_ul
stevethemes 0.1.0 theme_steve
profiplots 0.2.3 theme_profinit
ggnuplot 0.1.0 theme_gnuplot
wsjplot 0.1.0 theme_wsj

As a note of caution, some of these packages have not been updated for years, and since we see updates to the theme settings in {ggplot2}, it is always a good idea to look into whether the theme you set out to use is actively maintained (including potential dependencies).

In most cases, you should be able to make great ggplot2 figures simply by using the themes provided by ggplot2 itself. However, it is worth checking out these theme functions, and in particular how they change the ggplot2 theme in order to better understand the options you have within ggplot2::theme(). In other words, come for the various theme_* functions, stay for ggplot2::theme().

I plan to look further into the packages related to ggplot2 at some point in the future. First, by expanding the analysis of the themes, e.g., by looking further “inside” the theme functions (what and how many options they use, how much flexibility they provide, etc.). Second, by also looking into other functions beyond theme_*, such as geom_*, scale_*, and stat_*. Until then, enjoy the various customised ggplot2 themes.