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.
There are two ways to apply bulid-in (or otherwise predefined) themes (e.g.
For one, they can be added as an additional layer to individual plots:
rm(list = ls()) library(gridExtra) library(ggplot2) # 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
# making the classic theme the default theme_set(theme_classic()) 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
# 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\")")
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:
- How labels and titles are displayed, is controlled by the
element_textfunction. 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_linefunction. 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
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.
- Wickham, H. (2009). ggplot2: elegant graphics for data analysis. Springer.