array(1) {
  array(13) {
    string(2) "en"
    string(1) "1"
    string(7) "English"
    string(1) "1"
    string(1) "1"
    string(5) "en_US"
    string(1) "0"
    string(2) "en"
    string(7) "English"
    string(69) "https://www.statworx.com/en/content-hub/blog/using-themes-in-ggplot2/"
    string(87) "https://www.statworx.com/wp-content/plugins/sitepress-multilingual-cms/res/flags/en.png"
    string(2) "en"
Content Hub
Blog Post

Using Themes in ggplot2

  • Expert Lea Waniek
  • Date 27. July 2018
  • Topic CodingData VisualizationR
  • Format Blog
  • Category Technology
Using Themes in ggplot2

As noted elsewhere, sometimes beauty matters. A plot that’s pleasing to the eye will be considered more gladly, and thus might be understood more thoroughly. Also, since we at STATWORX oftentimes need to subsume and communicate our results, we have come to appreciate how a nice plot can upgrade any presentation.

So how make a plot look good? How make it accord with given style guidelines? In ggplot2 the display of all non-data components is controlled by the theme system. Other than in some other packages, the appearance of plots is edited after all the data-related elements of the plot have been determined. The theme system of ggplot2 allows the manipulation of titles, labels, legends, grid lines and backgrounds. There are various build-in themes available that already have an all-around consistent style, pertaining to any detail of a plot.

Pre-defined themes

There are two ways to apply bulid-in (or otherwise predefined) themes (e.g. theme_grey, theme_bw, theme_linedraw, theme_light, theme_dark, theme_minimal or theme_classic).
For one, they can be added as an additional layer to individual plots:

rm(list = ls())

# generating a fictional data set containing hours of sunshine and temperature
sun_hours <- sample(seq(from = 1, to = 8, by = 0.1), size = 40, replace = TRUE)
noise <- sample(seq(from = 17, to = 24, by = 0.1), size = 40, replace = TRUE)
temperature <-  sun_hours + noise
df_sun <- data.frame(sun_hours, temperature)

# generate the plot base
base_plot <- ggplot(df_sun) +
  geom_point(aes(x = sun_hours, y = temperature, color = temperature), 
             shape = 6, size = 5, stroke = 2) +
  geom_point(aes(x = sun_hours, y = temperature, color = temperature), 
             shape = 21, size = 3.3, fill = "white", stroke = 2) +
  labs(x = "Hours of Sun", y = "Temperature") +
  scale_color_gradient(high = "firebrick", low = "#ffce00", name = " ") +
  ggtitle("Base Plot")


# adding predefined themes
p1 <- base_plot +
  theme_classic() +
  ggtitle("Plot with theme_classic()")

p2 <- base_plot +
  theme_bw() +
  ggtitle("Plot with theme_bw()")

p3 <- base_plot +
  theme_dark() +
  ggtitle("Plot with theme_dark()")

p4 <- base_plot +
  theme_light() +
  ggtitle("Plot with theme_light()")

gridExtra::grid.arrange(p1, p2, p3, p4)


Alternatively, the default theme that’s automatically added to any plot, can be set or get with the functions theme_set() or theme_get().

# making the classic theme the default

base_plot +
  ggtitle("Plot with theme_set(theme_classic())")


While predefined themes are very convenient, there’s always the option to (additionally) tweak the appearance of any non-data detail of a plot via the various arguments of theme(). This can be done for a specific plot, or the currently active default theme. The default theme can be updated or partly replaced via theme_update and theme_replace, respectively.

# changing the default theme
theme_update(legend.position = "none")

base_plot +
  ggtitle("Plot with theme_set(theme_classic()) n& theme_update(legend.position = "none")")


# changing the theme directly applied to the plot
base_plot +
  theme(legend.position = "bottom") +
  ggtitle("Plot with theme(legend.position = "bottom")")


Element functions

There’s a wide range of arguments for theme(), in fact such a wide range, that not all arguments can be discussed here. Therefore, this blog post is far from exhaustive and only deals with the general principles of the theme system and only provides some illustrative examples for a few of all the available arguments. The appearance of many elements needs to be specified via one of the four element functions: element_blank, element_text, element_line or element_rect.

  • How labels and titles are displayed, is controlled by the element_text function. For example, we can make the title of the y axis bold and increase its size.
  • Borders and backgrounds can be manipulated using element_rect. For example, we can choose the color of the plot’s background.
  • Lines can be defined via the element_line function. For example, we can change the line types of the mayor and minor grid.
  • Further, with element_blank() it is possible to remove an object completely, without having any space dedicated to the plot element.
# using element_text, element_rect, element_line, element_blank
base_plot +
  theme(axis.title.y = element_text(face = "bold", size = 16),
        plot.background = element_rect(fill = "#FED633"),
        panel.grid.major = element_line(linetype = "dashed"),
        panel.grid.minor = element_line(linetype = "dotted"),
        axis.text.y = element_blank(),
        axis.text.x = element_blank()) +
  ggtitle("Plot altered using element functions")


If we don’t want to change the display of some specific plot elements, but of all text, lines, titles or rectangular elements we can do so by specifying the arguments text, line, rect and title. Specifications passed to these arguments are inherited by all elements of the respective type. This inheritance principle also holds true for other ‘parent’ arguments. ‘Parent’ arguments oftentimes are easily identifiable, as their names are used as prefixes for all subordinate arguments.

# using overreaching arguments #1
base_plot +
  theme(line = element_line(linetype = "dashed")) +
  ggtitle("Plot with all lines altered by using line")


# using overreaching arguments #2
base_plot +
  theme(axis.title = element_text(size = 6)) + # here axis.title is the parent
  ggtitle("Plot with both axis titles altered by using axis.title")



Margins, spaces, sizes and orientations of elements are not specified with element functions but have their own sets of possible parameters. For example, the display of legends is controlled by such arguments and specific parameters.

# using parameters instead of element functions
base_plot +
  theme(legend.position = "top") 


Since ggplot2 enables to manipulate the appearance of non-data elements of plots in great detail, there is a multitude of arguments. This blog post only tries to give a first impression of the many, many possibilities to design a plot. Some additional occupation with the topic, might be advisable, but any time invested in understanding how to style plots, surely is well spent. If you want read more on making pretty plots in ggplot2, check out my other posts on coordinate stystems or customizing date and time scales. If you want more details, our Data Visualization with R workshop may interest you!



  • Wickham, H. (2009). ggplot2: elegant graphics for data analysis. Springer.

  Lea Waniek Lea Waniek

Learn more!

As one of the leading companies in the field of data science, machine learning, and AI, we guide you towards a data-driven future. Learn more about statworx and our motivation.
About us