## 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 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.

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 `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.

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.

- Discrete (fill) scale: `scale_fill_msu_d()`

    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`.

- Discrete (colour) scale: `scale_colour_msu_d()`

    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`.

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"`.

- Continuous (fill) scale: `scale_fill_msu_c()`

    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.

- Continuous (colour) scale: `scale_colour_msu_c()`

    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.

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

- Continuous (fill) scale: `scale_fill_msu_c()`

    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.

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.

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 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 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.↩︎