library(tidyverse)
library(scales)
AE 08: A custom {ggplot2} theme for Cornell
Suggested answers
These are suggested answers. This document should be used as reference only, it’s not designed to be an exhaustive key.
To ensure the fonts are correctly rendered in the charts, you need to add the following code to the YAML header:
knitr:
opts_chunk:
dev: "ragg_png"
Cornell University brand identity
Organizational branding is a set of visual and verbal elements that represent an organization. It is “how your audience perceives you” and created through “many elements, including your name, logo, tagline, website, colors, collateral, messaging, positioning, graphic elements, social media, and other outreach platforms.”1
Cornell University maintains detailed guidelines for its brand identity. The design center provides explicit instructions for using the Cornell logo, color palette, and typography, as well as downloadable materials such as a PowerPoint template.
Suppose we wish to create a series of statistical charts to be used in a Cornell Bowers CIS2 presentation, but we want to ensure they are both reproducible as well as consistent with the university’s branding. We can use the {ggplot2} package to create a custom theme that adheres to the Cornell brand identity.
Basic bar chart
Let’s create a basic chart to assist us with generating an appropriate {ggplot2} theme. Here we will use graduation trends from Cornell University from College Scorecard. In this instance, we will use a bar chart to visualize the percentage of degrees awarded for three fields of study from 2018-22.
<- read_csv("data/cornell-degrees.csv")
cornell_degrees cornell_degrees
# A tibble: 135 × 3
field_of_study year pct
<chr> <dbl> <dbl>
1 Computer 1996 0.0421
2 Computer 1997 0.0497
3 Computer 1998 0.0581
4 Computer 1999 0.0716
5 Computer 2000 0.0684
6 Computer 2001 0.0859
7 Computer 2002 0.0745
8 Computer 2003 0.0463
9 Computer 2004 0.0327
10 Computer 2005 0.032
# ℹ 125 more rows
<- cornell_degrees |>
cornell_degrees_plot filter(year >= 2018) |>
# prep data for specific bar plot
mutate(
year = factor(year),
field_of_study = fct_reorder2(.f = field_of_study, .x = year, .y = pct)
|>
) ggplot(mapping = aes(x = field_of_study, y = pct, fill = year)) +
# ensure padding between dodged bar segments
geom_col(position = position_dodge2(padding = 0.2)) +
scale_x_discrete(labels = label_wrap(width = 15)) +
# format y axis labels
scale_y_continuous(labels = label_percent()) +
# optimal labels for chart
labs(
title = "Computer degrees have surpassed Engineering at Cornell",
subtitle = "Percentage of degrees awarded by field of study",
x = NULL,
y = NULL,
fill = NULL,
caption = "Source: College Scorecard"
) cornell_degrees_plot
Develop a custom Cornell theme for {ggplot2}
Based on Cornell’s brand identity, we want to ensure our theme adheres to the following requirements:
In addition, we want to
Note this final requirement is not part of the theme()
as defined by {ggplot2}, but requires us to modify the appropriate scale for the chart.
Your turn: Implement a Cornell-branded theme for {ggplot2} that meets the requirements outlined above.
In order to use the Spectral font, it needs to be installed on your system. You have two choices:
- If you are running R on your personal computer, download Spectral and install the font as you would any other font on your computer. Once installed, restart your R session and you should be able to use the font.
- Install the font for this project only using
library(systemfonts)
require_font("Spectral", dir = "fonts")
# cornell color palette - accent colors
<- c("#006699", "#6EB43F", "#F8981D", "#EF4035", "#073949")
cornell_pal
+
cornell_degrees_plot scale_fill_manual(values = cornell_pal) +
theme_minimal(
base_family = "Spectral",
base_size = 12
+
) theme(
plot.title.position = "plot",
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
legend.position = "bottom",
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.y = element_line(color = "grey", linewidth = 0.3),
panel.grid.minor.y = element_line(color = "grey", linewidth = 0.15),
axis.text = element_text(size = rel(1.2)),
legend.text = element_text(size = rel(1.0))
)
- 1
-
Use
theme_minimal()
as a starting point instead of building everything from scratch. Ensures a white background. - 2
- Align the title using the entire plot, not just the plot panel.
- 3
- Horizontally align the title and subtitle centered over the plot.
- 4
- Move the legend to the bottom of the plot.
- 5
- No grid lines on the \(x\)-axis.
- 6
- Increase visibility of grid lines on the \(y\)-axis.
- 7
- Increase font size of axis and legend labels.
- 8
- Use the Google font “Spectral” as the base font family (open-source alternative to Palantino).
- 9
-
Increase the size of all text elements of the
theme()
. - 10
- Use the Cornell color palette.
Turn into a reusable function
Demo: Convert your Cornell theme into a reusable theme_cornell()
function and test it on two different charts.
# define theme as its own function
<- function(
theme_cornell base_size = 12,
base_family = "Spectral",
base_line_size = base_size / 22,
base_rect_size = base_size / 22
) {# start with minimal theme
theme_minimal(
base_family = base_family,
base_size = base_size,
base_line_size = base_line_size,
base_rect_size = base_rect_size
+
) # customize required elements
theme(
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
plot.title.position = "plot",
legend.position = "bottom",
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.y = element_line(color = "grey", linewidth = 0.3),
panel.grid.minor.y = element_line(color = "grey", linewidth = 0.15),
axis.text = element_text(size = rel(1.2)),
legend.text = element_text(size = rel(1.0))
) }
- 1
-
Set default values based on
theme_minimal()
plus our customizations. Ensures they can always be overriden for individual plots if needed. - 2
-
Pass along function arguments to
theme_minimal()
.
# existing bar chart
+
cornell_degrees_plot scale_fill_manual(values = cornell_pal) +
theme_cornell()
# line graph
|>
cornell_degrees mutate(
field_of_study = fct_reorder2(
.f = field_of_study,
.x = year,
.y = pct
)|>
) ggplot(aes(x = year, y = pct, color = field_of_study)) +
geom_point() +
geom_line() +
scale_x_continuous(limits = c(1996, 2022), breaks = seq(1996, 2020, 4)) +
scale_color_manual(values = cornell_pal) +
scale_y_continuous(labels = label_percent()) +
labs(
x = "Graduation year",
y = "Percent of degrees awarded",
color = "Field of study",
title = "Cornell University degrees awarded from 1996-2022",
subtitle = "Only the top five fields as of 2022",
caption = "Source: Department of Education\nhttps://collegescorecard.ed.gov/"
+
) theme_cornell() +
# still makes sense to leave the legend on the right
theme(legend.position = "right")
::session_info() sessioninfo
─ Session info ───────────────────────────────────────────────────────────────
setting value
version R version 4.4.2 (2024-10-31)
os macOS Sonoma 14.6.1
system aarch64, darwin20
ui X11
language (EN)
collate en_US.UTF-8
ctype en_US.UTF-8
tz America/New_York
date 2025-02-21
pandoc 3.4 @ /usr/local/bin/ (via rmarkdown)
─ Packages ───────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
archive 1.1.9 2024-09-12 [1] CRAN (R 4.4.1)
bit 4.0.5 2022-11-15 [1] CRAN (R 4.3.0)
bit64 4.0.5 2020-08-30 [1] CRAN (R 4.3.0)
cli 3.6.3 2024-06-21 [1] CRAN (R 4.4.0)
crayon 1.5.3 2024-06-20 [1] CRAN (R 4.4.0)
dichromat 2.0-0.1 2022-05-02 [1] CRAN (R 4.3.0)
digest 0.6.37 2024-08-19 [1] CRAN (R 4.4.1)
dplyr * 1.1.4 2023-11-17 [1] CRAN (R 4.3.1)
evaluate 1.0.3 2025-01-10 [1] CRAN (R 4.4.1)
farver 2.1.2 2024-05-13 [1] CRAN (R 4.3.3)
fastmap 1.2.0 2024-05-15 [1] CRAN (R 4.4.0)
forcats * 1.0.0 2023-01-29 [1] CRAN (R 4.3.0)
generics 0.1.3 2022-07-05 [1] CRAN (R 4.3.0)
ggplot2 * 3.5.1 2024-04-23 [1] CRAN (R 4.3.1)
glue 1.8.0 2024-09-30 [1] CRAN (R 4.4.1)
gtable 0.3.6 2024-10-25 [1] CRAN (R 4.4.1)
here 1.0.1 2020-12-13 [1] CRAN (R 4.3.0)
hms 1.1.3 2023-03-21 [1] CRAN (R 4.3.0)
htmltools 0.5.8.1 2024-04-04 [1] CRAN (R 4.3.1)
htmlwidgets 1.6.4 2023-12-06 [1] CRAN (R 4.3.1)
jsonlite 1.8.9 2024-09-20 [1] CRAN (R 4.4.1)
knitr 1.49 2024-11-08 [1] CRAN (R 4.4.1)
labeling 0.4.3 2023-08-29 [1] CRAN (R 4.3.0)
lifecycle 1.0.4 2023-11-07 [1] CRAN (R 4.3.1)
lubridate * 1.9.3 2023-09-27 [1] CRAN (R 4.3.1)
magrittr 2.0.3 2022-03-30 [1] CRAN (R 4.3.0)
pillar 1.10.1 2025-01-07 [1] CRAN (R 4.4.1)
pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.3.0)
purrr * 1.0.2 2023-08-10 [1] CRAN (R 4.3.0)
R6 2.5.1 2021-08-19 [1] CRAN (R 4.3.0)
ragg 1.3.2 2024-05-15 [1] CRAN (R 4.4.0)
RColorBrewer 1.1-3 2022-04-03 [1] CRAN (R 4.3.0)
readr * 2.1.5 2024-01-10 [1] CRAN (R 4.3.1)
rlang 1.1.5 2025-01-17 [1] CRAN (R 4.4.1)
rmarkdown 2.29 2024-11-04 [1] CRAN (R 4.4.1)
rprojroot 2.0.4 2023-11-05 [1] CRAN (R 4.3.1)
scales * 1.3.0.9000 2024-11-14 [1] Github (r-lib/scales@ee03582)
sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.3.0)
stringi 1.8.4 2024-05-06 [1] CRAN (R 4.3.1)
stringr * 1.5.1 2023-11-14 [1] CRAN (R 4.3.1)
systemfonts * 1.2.0 2025-01-16 [1] CRAN (R 4.4.1)
textshaping 0.4.0 2024-05-24 [1] CRAN (R 4.4.0)
tibble * 3.2.1 2023-03-20 [1] CRAN (R 4.3.0)
tidyr * 1.3.1 2024-01-24 [1] CRAN (R 4.3.1)
tidyselect 1.2.1 2024-03-11 [1] CRAN (R 4.3.1)
tidyverse * 2.0.0 2023-02-22 [1] CRAN (R 4.3.0)
timechange 0.3.0 2024-01-18 [1] CRAN (R 4.3.1)
tzdb 0.4.0 2023-05-12 [1] CRAN (R 4.3.0)
utf8 1.2.4 2023-10-22 [1] CRAN (R 4.3.1)
vctrs 0.6.5 2023-12-01 [1] CRAN (R 4.3.1)
vroom 1.6.5 2023-12-05 [1] CRAN (R 4.3.1)
withr 3.0.2 2024-10-28 [1] CRAN (R 4.4.1)
xfun 0.50.5 2025-01-15 [1] https://yihui.r-universe.dev (R 4.4.2)
yaml 2.3.10 2024-07-26 [1] CRAN (R 4.4.0)
[1] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library
──────────────────────────────────────────────────────────────────────────────
Footnotes
According to the Cornell Bowers CIS brand guidelines, always refer to it as Cornell Bowers CIS or the more formal Cornell Ann S. Bowers College of Computing and Information Science or Cornell Bowers Computing and Information Science, never just CIS.↩︎