Styling Plots with MSUthemes

Styling Plots with base-R and ggplot2

This document introduces the MSUthemes packages and the included colour palettes by discussing the technical details of how to change the style of plots built with some of the most common types of software used to create data visualisations.

For simplicity, base R and {ggplot2} examples are provided. Often base R plots are constructed using plotting functions built into specialized packages. Though, it is common and advisable to construct plots using {ggplot2} due to its robust collection of plotting methods and the ability to design and format plots to the needed requirements.

Big Ten Dataset (1996-2023)

To demonstrate how to use the colour palettes in {MSUthemes}, a dataset of historical (1996-2023) admissions and demographics for the 18 Big Ten institutions is provided. The dataset was constructed from the April 23, 2025 version of the College Scorecard dataset.

Data related to Michigan State University (MSU) and Big Ten institutions is used to demonstrate how to use the colour palettes within {MSUthemes}.

Installing & Loading {MSUthemes}

You can install the {MSUthemes} package from CRAN using:

install.packages("MSUthemes")

You can install the development version from GitHub though it might not be as stable as the CRAN version:

devtools::install_github("emilioxavier/MSUthemes", force=TRUE)

Then load the {MSUthemes} package with:

library(MSUthemes)

R [@RTeam2021] is a programming language which is popular for statistical computing and graphics. There are many packages with R that can be used to create data visualisations, and we don’t aim to cover them all here. Instead, we address the most common methods: built-in base R graphics, and the {ggplot2} package [@Wickham2016a].

Base R

R has built-in graphics capabilities that allow users to make a wide range of data visualisations without installing any additional packages. The Styling Base R Graphics blog post from Jumping Rivers [@JR2018] provides a nice overview of how to style graphics created in base R.

Example: changing bar plot colours in base R.

If all of the bars, lines, points, etc. should have the same colour, you can set the col argument to have one of the MSU colours. The options are: msu_red, msu_blue, msu_green, msu_orange, or msu_yellow.

library(dplyr)

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
barplot(C150_4 ~ entry_term, data=filter(BigTen, name=="MSU"),
        col = msu_green,
        main = "MSU Graduation Rate (1997 - 2023)",
        xlab = "Graduation Year of Incoming Class", ylab = "6-Year Graduation Rate")

Bar plots visualising plant growth of average height for different treatments with user specified colours red, blue, and dark green.

Bar plot with bars coloured in Michigan State University (MSU) green.

If the colours in your plot are based on values in your data, you can set the default colours using the palette() function. Within {MSUthemes}, the set_msu_palette() function changes the default colours used. There are currently three palettes available in {MSUthemes}, although we hope to add more in the future. The options are msu_qual1, msu_div, or msu_seq.

set_msu_palette("msu_qual1")
plot(1:13, 1:13, col=1:13, pch=19, cex=3, xlab="", ylab="",
     main = "Example of Michigan State University (MSU) Colour Palette Plot",
     sub = "Source: Sequential Values")
abline(h=1:13, v=1:13, col = "lightgrey")

set_msu_par()
barplot(C150_4 ~ entry_term, data=filter(BigTen, name == "MSU"),
        col = set_msu_palette("msu_qual1"),
        main = "MSU Graduation Rate (1997 - 2023)",
        xlab = "Graduation Year of Incoming Class", ylab = "6-Year Graduation Rate")

Another version of the barplot showing the colours from the `msu_qual1` palette.

Another version of the barplot showing the colours from the msu_qual1 palette.

Run palette("default") to reset to original base R colours.

Example: changing the styling of base R plots.

Within the plot() function (and related base R plotting functions such as barplot(), and hist()) , there are arguments to control how the non-data elements of the plot look. For example, the family argument changes which font family is used. You can also set many of these arguments globally by calling the par() function. Within {MSUthemes}, there is a function set_msu_par() which sets some default options, including the text alignment and font for all base R plots. We also recommend adding reference lines using the abline() function.

set_msu_par()
plot(1:13, 1:13, col=1:13, pch=19, cex=3, xlab="", ylab="",
     main = "Example of Michigan State University (MSU) Colour Palette Plot",
     sub = "Source: Sequential Values")
abline(h=1:13, v=1:13, col = "lightgrey")

Scatter plot showing the base R styling implemented by the Michigan State University (MSU) par function.

Scatter plot showing the base R styling implemented by set_msu_par().

{ggplot2}

Base-R provides the ability to quickly and simply construct initial plots to understand the data and results of interest. More in-depth plots displaying the desired and refined information of interest are best constructed using {ggplot2}.1 The following examples demonstrate how to use the MSU and Big Ten colour palettes using historical institutional data. The ggplot2 documentation illustrates how to create various types of plots. Within the ggplot2: Elegant Graphics for Data Analysis (3e) book, information on changing the colours and refinement of {ggplot2} visualisations, is provided by Hadley Wickham, Danielle Navarro, & Thomas Lin Pedersen[@Wickham2016a].2 Recipe-focused examples are available in Cookbook for R by Winston Chang or R Cookbook, 2nd Edition by James (JD) Long & Paul Teetor3.

Let’s set up a basic MSU and Big Ten datasets to make plots with {ggplot2}.

library(ggplot2)
library(dplyr)

set_msu_par()  ## reset graphics par(ameters)

MSU_df <- filter(BigTen, name == "MSU")

MSU Color Palettes in {ggplot2}

Example: changing the non-mapped colours in {ggplot2}.

In {ggplot2}, the colour (or color) argument changes the colour outlining an element, and fill changes the colour filling the element. If all of the, e.g., bars, lines, or points should have the same colour, you can set either the fill or colour arguments to have one of the MSU colours. The options are: msu_red, msu_blue, msu_green, msu_orange, or msu_yellow.

ggplot(data = MSU_df,
       mapping = aes(x = entry_term, y = UGDS)) +
  geom_col(fill = msu_yellow)

Bar plot with bars coloured yellow

Bar plot with bars coloured yellow.

Example: using a discrete colour scale in {ggplot2}.

For working with qualitative (discrete) data, the best palette to use is "msu_qual1". This palette currently only contains four colours.

ggplot(data = slice(MSU_df, 1:13),
       mapping = aes(x = entry_term, y = UGDS, fill = factor(entry_term))) +
  geom_col() +
  scale_fill_msu_d(palette = "msu_qual1")

Bar plot with colours from msu_qual1

Bar plot with colours from msu_qual1.
ggplot(data = slice(MSU_df, 1:4),
       mapping = aes(x = entry_term, y = UGDS, colour = factor(entry_term))) +
  geom_point(size = 6) +
  scale_colour_msu_d(palette = "msu_qual2")

Scatter plot with colours from msu_qual2

Scatter plot with colours from msu_qual2.

Example: using a continuous colour scale in {ggplot2}.

Continuous colour scales may be sequential or diverging. For working with sequential (continuous) data, the best palette to use is "msu_seq".

ggplot(data = slice(MSU_df, 1:13),
       mapping = aes(x = entry_term, y = UGDS, fill = UGDS)) +
  geom_col() +
  scale_fill_msu_c(palette = "msu_seq")

Bar plot showing sequential green colour palette

Bar plot showing sequential green colour palette.
ggplot(data = MSU_df,
       mapping = aes(x = entry_term, y = UGDS, colour = UGDS)) +
  geom_point(size = 6) +
  scale_colour_msu_c(palette = "msu_seq")

Scatter plot showing sequential green colour palette

Scatter plot showing sequential green colour palette.

For working with diverging (continuous) data, the best palette to use is "msu_div".

ggplot(data = MSU_df,
       mapping = aes(x = entry_term, y = UGDS, fill = UGDS)) +
  geom_col() +
  scale_fill_msu_c(palette = "msu_div")

Bar plot showing diverging red to blue palette

Bar plot showing diverging red to blue palette.

If you want to centre the diverging scale around a different value, you can alternatively pass the pre-defined colours from {MSUthemes} into scale_fill_gradient2() in {ggplot2}:

ggplot(data = MSU_df,
       mapping = aes(x = entry_term, y = UGDS, fill = UGDS)) +
  geom_col() +
  scale_fill_gradient2(low = msu_orange,
                       high = msu_purple,
                       midpoint = median(MSU_df$UGDS, na.rm = TRUE))

Bar plot showing diverging orange to purple palette centred at the median undergraduate population for Big Ten institutions

Bar plot showing diverging orange to purple palette centred at the median undergraduate population for Big Ten institutions.

Example: changing the theme in {ggplot2}.

Within {ggplot2}, themes allow you to control the appearance of the non-data elements of your plot. The default theme is theme_grey() which has a darker background. We recommend using a white or transparent background, such as those created with theme_minimal() or theme_bw().

You can also use theme_MSU() from {MSUthemes} which additionally sets the plot font to Metropolis (used in MSU branding). Check that you have already run library(MSUthemes) to ensure the fonts load correctly.

BigTen_2023 <- filter(BigTen, entry_term == 2023)

ggplot(data = BigTen_2023, aes(x = reorder(name, UGDS), y = UGDS, fill = ADM_RATE)) +
  geom_col() +
  scale_fill_msu_c(palette = "msu_div") +
  scale_y_continuous(labels = scales::comma) +
  labs(x = NULL,
       y = "Undergraduate Enrollment",
       title = "Big Ten Enrollment (2023)",
       subtitle = "Bars Shaded by Admission Rate",
       fill = "Admission Rate") +
  theme_MSU() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Bar plot showing Big Ten enrollment with MSU theme

Bar plot styled with theme_MSU().

Using Big Ten Institutional Colors

The {MSUthemes} package includes comprehensive color support for all Big Ten institutions, making it easy to create multi-institutional comparisons with consistent, recognizable branding.

Example: comparing Big Ten institutions with institutional colors.

BigTen_2023 <- filter(BigTen, entry_term == 2023)

ggplot(data = BigTen_2023,
       aes(x = ADM_RATE, y = C150_4, size = UGDS, colour = name, label = name)) +
  geom_point(alpha = 0.7) +
  ggrepel::geom_text_repel(size = 3,
                           colour = "black",
                           show.legend = FALSE, max.overlaps = 20) +
  scale_x_continuous(labels = scales::percent) +
  scale_y_continuous(labels = scales::percent) +
  scale_colour_manual(values = bigten_colors_primary) +
  scale_size_continuous(labels = scales::comma, range = c(3, 12)) +
  guides(size = guide_legend(title = "Undergraduate\nEnrollment"),
         colour = "none") +
  labs(x = "Admission Rate",
       y = "6-Year Graduation Rate",
       title = "Big Ten Institutional Comparison (2023)",
       subtitle = "Each institution shown in its official primary color") +
  theme_MSU()

Scatter plot showing Big Ten institutions with official institutional colors

Scatter plot comparing Big Ten institutions using official colors.

If you find a bug in the {MSUthemes} package, or something that isn’t working quite as you expected, please submit a GitHub issue.

Exporting images from R

Given the wide ranging places you might be including your plots (including but not limited to slide decks documents, or websites), the desired dimensions (height and width), pixel density (commonly resolution or DPI), and file type (EPS, PDF, JPEG, JPG, PNG, TIFF, or SVG to name a few) will vary and can impact the final appearance of your plot.[FOOTNOTE: EPS, PDF, and SVG file types allow the easy resizing of your images.] Thus, using a standard file writing method you understand and are comfortable using while provides the high quality images should be the reason for selecting the method.

While there are several ways to export plots from R, ggplot2::ggsave() (or its derivative cowplot::ggsave2()) offer robust interfaces to create the desired file types. We strongly discourage using the Export button on the Plots pane in RStudio or Visual Studio Code, as these methods do not result in images with the required publication resolution of at least 300 dpi.

The minimum image resolution for images published in print is 300 dpi. If you use ggsave() from {ggplot2}, 300 dpi is the default resolution. We recommend saving images in PDF or EPS file format as this makes it easier for them to be resized.

Example: exporting with base R graphics

pdf(file = "MSU-feature-plot.pdf",  # name of file
    width = 7,                      # width in inches
    height = 5                      # height in inches
    )
barplot(C150_4 ~ entry_term, data = filter(BigTen, name == "MSU"),
        col = msu_green,
        main = "MSU Graduation Rate (1997 - 2023)",
        xlab = "Graduation Year of Incoming Class",
        ylab = "6-Year Graduation Rate")
dev.off()

Example: exporting with {ggplot2} using ggsave()

# Create a plot
p <- ggplot(data = MSU_df, aes(x = entry_term, y = UGDS, fill = UGDS)) +
  geom_col() +
  scale_fill_msu_c(palette = "msu_seq") +
  labs(title = "MSU Undergraduate Enrollment",
       x = "Entry Term",
       y = "Undergraduate Enrollment") +
  theme_MSU()

# Save the plot
ggsave(filename = "MSU-enrollment.pdf",
       plot = p,
       width = 8,
       height = 6,
       dpi = 300)

# For PNG format
ggsave(filename = "MSU-enrollment.png",
       plot = p,
       width = 8,
       height = 6,
       dpi = 300)

  1. Yes, base-R can make amazing data visualisations. Unfortunately, base-R is not as flexible as {ggplot2}. Please, don’t @ me.↩︎

  2. The linked webpages are a work in progress and might not be very helpful in their current forms.↩︎

  3. Please see the Graphics chapter.↩︎