---
title: "Notre Dame Color Palettes"
output:
  rmarkdown::html_vignette:
    toc: true
vignette: >
  %\VignetteIndexEntry{Notre Dame Color Palettes}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.align = "center",
  fig.width = 7,
  fig.height = 4.5,
  dpi = 96,
  out.width = "100%"
)

library(NDPalette)

# This vignette is a ggplot2 demonstration. If ggplot2 is not installed,
# the figures are skipped rather than raising an error.
has_ggplot2 <- requireNamespace("ggplot2", quietly = TRUE)
if (has_ggplot2) {
  library(ggplot2)
  # Pair the brand colors with a light built-in theme throughout (see the
  # "Pairing with a light theme" section below).
  theme_set(theme_minimal(base_size = 12))
}
knitr::opts_chunk$set(eval = has_ggplot2)
```

`NDPalette` provides color palettes that approximate the University of
Notre Dame brand colors, together with `ggplot2` color and fill scales.
These colors are well suited to statistical visualization and
psychometric analysis: the white-safe ordering keeps groups legible in
plots of data, and the near-white-to-navy ramps suit continuous
quantities such as correlations and factor loadings. The colors come back
as plain hexadecimal strings, so they work anywhere that accepts a color:
a `ggplot2` scale, a base graphics call, a `plotly` chart, a table, or a
figure rendered outside R. It opens with a quick start for every workflow
(`ggplot2`, base R graphics, R Markdown, and Shiny), previews the palettes,
shows each color with its name, walks through coloring one group up to ten,
gives a gallery of common chart types in both `ggplot2` and base R, shows
how to mix in a color from outside the palette, and closes with a set of
statistical and psychometric figures. It is an independent project, not
affiliated with or endorsed by the University.

```{r load, eval = TRUE}
library(NDPalette)
```

# Quick start: every workflow, the easy way

The point of `NDPalette` is that you should not have to choose colors by
hand. In each workflow you add **one** thing and `NDPalette` applies the
colors for you. Everything after this section is only for when you want
more control: a set number of colors, a specific brand color by name, or
mixing in a color from outside the palette.

**ggplot2** --- add a scale:

```{r qs-ggplot, fig.height = 3.3}
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
  geom_point(size = 2) +
  scale_color_nd()                      # one line; the colors are chosen for you
```

**Base R graphics** --- set the palette once, then color by a grouping factor:

```{r qs-base, eval = TRUE, fig.height = 3.6}
palette(nd_palette(8))                  # base R now draws in Notre Dame colors
plot(Petal.Length ~ Sepal.Length, data = iris, col = Species, pch = 19)
palette("default")                      # restore base R's palette when done
```

**R Markdown** --- theme a whole HTML report from one line in the YAML header:

```yaml
output:
  NDPalette::html_nd_document           # navy headings, brand callouts, soft page
```

**Shiny** --- color the page chrome from the palette with a `bslib` theme (the
*Theming a Shiny app with NDPalette* vignette walks through a full app):

```r
bslib::bs_theme(primary = nd_color("navy"), secondary = nd_color("bright_gold"))
```

# The default Notre Dame palette

The default `"nd"` palette leads with the six Notre Dame brand colors
that read clearly on a white background, then extends through seven
former Notre Dame brand colors, thirteen anchors in all. `show_palette()`
previews the whole set (it defaults to the full palette):

```{r full, eval = TRUE, fig.height = 1.8, fig.width = 9}
show_palette()
```

Every color also has a readable name. The card below lists the thirteen
data colors with their names and hexadecimal values, so a color can be
matched to its label at a glance:

```{r named-card, fig.height = 5, fig.width = 6.5}
pal   <- nd_palette()                            # the thirteen data colors
named <- nd_colors[match(pal, nd_colors$hex), ]  # matched to their catalog names
named$pos <- rev(seq_len(nrow(named)))

ggplot(named, aes(x = 0, y = pos)) +
  geom_tile(aes(fill = hex), width = 0.5, height = 0.82) +
  geom_text(aes(x = 0.32, label = paste0(name, "  (", hex, ")")),
            hjust = 0, size = 3.1) +
  scale_fill_identity() +
  coord_cartesian(xlim = c(-0.3, 4), clip = "off") +
  labs(x = NULL, y = NULL) +
  theme_void()
```

`show_palette()` can also print those names on the swatches themselves, in
place of the hex values, by passing a character vector to `labels`:

```{r named-swatch, eval = TRUE, fig.height = 1.8, fig.width = 9}
show_palette(nd_palette(), labels = named$name)
```

The raw anchors are exported as `nd_palettes` for tools and for users who
want the hexadecimal values directly:

```{r anchors, eval = TRUE}
nd_palettes$nd
```

`nd_palette(n)` returns the first `n` of these. Because the colors are
taken in a fixed order, asking for five groups always yields the same
five colors, and those five are the first five of any larger request:

```{r small-requests, eval = TRUE}
nd_palette(2)
nd_palette(5)
```

# From one group to ten

As the number of groups grows, the palette adds one color at a time. The
staircase below shows exactly which colors `nd_palette(n)` returns for
`n` running from one to ten: each row is one value of `n`, read left to
right.

```{r ladder, fig.height = 5}
ladder <- do.call(rbind, lapply(1:10, function(k) {
  data.frame(n = k, position = seq_len(k), hex = nd_palette(k))
}))
ladder$n <- factor(ladder$n, levels = 10:1)

ggplot(ladder, aes(position, n, fill = hex)) +
  geom_tile(color = "white", linewidth = 1.2) +
  scale_fill_identity() +
  scale_x_continuous(breaks = 1:10, position = "top") +
  coord_equal() +
  labs(x = "color position", y = "number of groups (n)") +
  theme(panel.grid = element_blank())
```

The same progression, drawn as `ggplot2` bar charts colored with
`scale_fill_nd()`. Each panel is a plot of `n` groups, so the panels show
the palette at work for one through ten categories:

```{r facets, fig.height = 4.5}
bars <- do.call(rbind, lapply(1:10, function(k) {
  data.frame(n = k, position = seq_len(k))
}))
bars$value <- 2 + sin(bars$position)
bars$group <- factor(bars$position, levels = 1:10)
bars$panel <- factor(paste0("n = ", bars$n), levels = paste0("n = ", 1:10))

ggplot(bars, aes(group, value, fill = group)) +
  geom_col(width = 0.85) +
  facet_wrap(~ panel, nrow = 2, scales = "free_x") +
  scale_fill_nd() +
  labs(x = NULL, y = NULL) +
  theme(legend.position = "none",
        axis.text = element_blank(),
        panel.grid = element_blank())
```

The first four colors (ND Blue, Bright Gold, Green, Bright Blue) are the
most strongly separated, so two-, three-, and four-group plots read
cleanly. Past six groups the palette draws on the former Notre Dame colors,
which introduce teal, maroon, and purple to keep neighboring categories
distinct. Two of those, maroon and purple, are dark, so for a plot with
many small or thin marks (a fine line chart, a dense scatter) it is worth
checking that adjacent groups stay legible, and reaching for the
colorblind-friendly `"nd_cvd"` palette (below) when separation matters
more than leading with the brand colors.

# The scales in practice

`scale_color_nd()` and `scale_fill_nd()` drop into a `ggplot2` plot and
map the grouping levels to the Notre Dame colors automatically.
`scale_colour_nd()` is the British-spelling alias.

Two and three groups, on the color aesthetic. The data are `iris` --- sepal
and petal measurements of 150 flowers from three species:

```{r iris, fig.height = 4.5}
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
  geom_point(size = 2.5, alpha = 0.9) +
  scale_color_nd() +
  labs(title = "Three groups", x = "sepal length", y = "petal length",
       color = "species")
```

Three groups, on the fill aesthetic --- the count of the 32 `mtcars` cars by
number of cylinders:

```{r mtcars, fig.height = 4.5}
ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) +
  geom_bar(width = 0.7) +
  scale_fill_nd() +
  labs(title = "Three groups", x = "cylinders", y = "count",
       fill = "cylinders")
```

Five groups, five well-separated colors --- the count of the roughly 54,000
`diamonds` by cut quality:

```{r diamonds, fig.height = 4.5}
ggplot(diamonds, aes(cut, fill = cut)) +
  geom_bar() +
  scale_fill_nd() +
  labs(title = "Five groups", x = "cut", y = "count") +
  theme(legend.position = "none")
```

Six groups --- `InsectSprays` counts insects on field plots treated with
each of six insecticides (A--F):

```{r sprays, fig.height = 4.5}
ggplot(InsectSprays, aes(spray, count, fill = spray)) +
  geom_boxplot() +
  scale_fill_nd() +
  labs(title = "Six groups", x = "spray", y = "count") +
  theme(legend.position = "none")
```

To reverse the color order, pass `reverse = TRUE` to the scale:

```{r reverse, fig.height = 4.5}
ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) +
  geom_bar(width = 0.7) +
  scale_fill_nd(reverse = TRUE) +
  labs(x = "cylinders", y = "count", fill = "cylinders") +
  theme(legend.position = "none")
```

# A gallery of plot types

The same scales drop into the chart types people reach for most often.
Every example below uses a built-in R dataset, so each one runs without
any extra data.

A line chart with one series per group suits five groups. `Orange` records
the trunk circumference of five orange trees as they age:

```{r lines, fig.height = 4.5}
ggplot(Orange, aes(age, circumference, color = Tree)) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  scale_color_nd() +
  labs(title = "Five series, as lines", x = "age (days)",
       y = "trunk circumference (mm)", color = "tree")
```

Grouped (dodged) bars color a second factor with `scale_fill_nd()`.
`warpbreaks` gives the number of warp breaks on a loom by wool type (A or B)
and tension (low, medium, high):

```{r grouped-bars, fig.height = 4.5}
ggplot(warpbreaks, aes(tension, breaks, fill = wool)) +
  geom_bar(stat = "summary", fun = "mean", position = "dodge",
           width = 0.7) +
  scale_fill_nd() +
  labs(title = "Grouped bars", x = "tension", y = "mean breaks",
       fill = "wool")
```

Overlapping densities put the palette on a filled area, where a little
transparency keeps the groups readable. `ToothGrowth` is guinea-pig tooth
length at three doses of vitamin C:

```{r density, fig.height = 4.5}
ggplot(ToothGrowth, aes(len, fill = factor(dose))) +
  geom_density(alpha = 0.6) +
  scale_fill_nd() +
  labs(title = "Overlapping densities", x = "tooth length", y = "density",
       fill = "dose")
```

A scatter plot with a fitted line per group pairs `geom_smooth()` with
`scale_color_nd()`. `ChickWeight` follows the weight of chicks on four diets
over their first weeks:

```{r fitted-lines, fig.height = 4.5}
ggplot(ChickWeight, aes(Time, weight, color = Diet)) +
  geom_point(size = 1.6, alpha = 0.5) +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
  scale_color_nd() +
  labs(title = "Fitted lines by group", x = "time (days)",
       y = "weight (g)", color = "diet")
```

A stacked bar normalized to proportions (`position = "fill"`) shows how a
second factor divides each category, a common way to read composition.
Here the passenger class composition of the `Titanic` differs sharply by
sex (the crew was almost entirely male):

```{r stacked-fill, fig.height = 4.5}
titanic <- aggregate(Freq ~ Sex + Class, data = as.data.frame(Titanic),
                     FUN = sum)
ggplot(titanic, aes(Sex, Freq, fill = Class)) +
  geom_col(position = "fill") +
  scale_fill_nd() +
  labs(title = "Stacked proportions", x = NULL, y = "proportion",
       fill = "passenger class")
```

A lollipop chart --- a tidy alternative to bars --- colors the stems and heads
from the palette with `scale_color_nd()`. Here it shows the mean final weight
of chicks on each of the four `ChickWeight` diets:

```{r lollipop, fig.height = 4.5}
chick <- aggregate(weight ~ Diet, data = ChickWeight, FUN = mean)
ggplot(chick, aes(Diet, weight, color = Diet)) +
  geom_segment(aes(xend = Diet, yend = 0), linewidth = 1.5) +
  geom_point(size = 6) +
  scale_color_nd() +
  labs(title = "A lollipop chart", x = "diet", y = "mean weight (g)") +
  theme(legend.position = "none")
```

A bar chart in polar coordinates makes a radial chart, painted straight
from the palette --- again the count of `diamonds` by cut quality:

```{r polar, fig.height = 4.6, fig.width = 5}
ggplot(diamonds, aes(cut, fill = cut)) +
  geom_bar(width = 1, color = "white") +
  scale_fill_nd() +
  coord_polar() +
  labs(title = "A radial bar chart", x = NULL, y = NULL, fill = "cut") +
  theme_minimal(base_size = 12)
```

# Base R graphics

The palettes are plain hex strings, so they drop into base graphics too. The
easiest route is to set R's active palette once with `palette(nd_palette(n))`;
after that, base plots that color by a factor or integer use Notre Dame
colors automatically, with no per-call color work.

```{r base-palette, eval = TRUE, fig.height = 4}
palette(nd_palette(6))                 # base R now draws in Notre Dame colors
boxplot(count ~ spray, data = InsectSprays, col = 1:6, border = "grey30",
        main = "Six groups, base R", xlab = "spray", ylab = "count")
palette("default")                     # restore when done
```

Or pass `nd_palette()` straight to a `col` argument, without touching the
global palette:

```{r base-barplot, eval = TRUE, fig.height = 4}
barplot(table(mtcars$cyl), col = nd_palette(3), border = NA,
        main = "Three groups, base R", xlab = "cylinders", ylab = "count")
```

A sequential ramp shades a heatmap or surface; `image()` is the base R
counterpart of a filled `ggplot2` raster. A ramp straight from a pale tint
to navy passes through a washed-out blue-gray in the middle, so the ramp
here runs light sky blue through Bright Blue to navy, keeping the midtones a
clear blue. `volcano` is a grid of elevations on Maungawhau, a volcano in
Auckland:

```{r base-image, eval = TRUE, fig.height = 4.2, fig.width = 5}
ramp <- grDevices::colorRampPalette(c(nd_tints[["light_sky_blue"]],
                                      nd_color("bright_blue"),
                                      nd_color("navy")))(20)
image(volcano, col = ramp, axes = FALSE, main = "Maungawhau elevation")
```

A soft tint works as a base R page background through
`par(bg = nd_informal_tints[["soft_white"]])`, the base counterpart of
setting `plot.background` in `ggplot2`; `par(bg = ...)` takes one color for
the whole page. The grid below compares the options on one plot of `mtcars`
(fuel economy versus weight for 32 cars from a 1974 issue of *Motor Trend*,
one point per car): the soft white, soft yellow, and warm soft-yellow tints
as the background, with navy or bright blue points. To use a tint for a real
page, pass it to `par(bg = ...)`; to change the point color, change the
`nd_color(...)` argument.

```{r base-bg, eval = TRUE, fig.height = 6.5, fig.width = 8}
panel <- function(bg, col, lab) {
  plot(mpg ~ wt, data = mtcars, type = "n", main = lab,
       xlab = "weight (1000 lbs)", ylab = "mpg")
  rect(par("usr")[1], par("usr")[3], par("usr")[2], par("usr")[4],
       col = bg, border = NA)                  # the tint, shown per panel
  points(mtcars$wt, mtcars$mpg, pch = 19, col = col)
  box()
}
op <- par(mfrow = c(2, 2), mar = c(4, 4, 2, 1))
panel(nd_informal_tints[["soft_white"]],       nd_color("navy"),        "soft white + navy")
panel(nd_informal_tints[["soft_yellow"]],      nd_color("navy"),        "soft yellow + navy")
panel(nd_informal_tints[["soft_yellow_warm"]], nd_color("navy"),        "soft yellow, warm (gold) + navy")
panel(nd_informal_tints[["soft_white"]],       nd_color("bright_blue"), "soft white + bright blue")
par(op)
```

# Statistical and psychometric visualization

The brand colors are built for plots of data, and they fit the figures
that recur in statistical and psychometric work. The examples that follow
are a sequential and a diverging ramp on two correlation matrices, a
two-group fill for factor loadings, and a several-color scale for item
characteristic curves.

A correlation heatmap puts the near-white-to-navy ramp on a matrix of
item intercorrelations. Here six items measure a single construct, so the
off-diagonal correlations cluster around a common value:

```{r corr-heatmap, fig.height = 4.6, fig.width = 5.4}
set.seed(113)
f     <- rnorm(250)                                    # the latent construct
load  <- 0.65                                          # common loading
items <- sapply(1:6, function(j) load * f + rnorm(250, sd = sqrt(1 - load^2)))
colnames(items) <- paste0("i", 1:6)

R <- cor(items)
dfR <- as.data.frame(as.table(R))
names(dfR) <- c("row", "col", "r")
dfR$txt <- ifelse(dfR$r > 0.5, "white", nd_color("navy"))

heat <- grDevices::colorRampPalette(
  c(nd_tints[["light_sky_blue"]], nd_palette(1)))(100)

ggplot(dfR, aes(col, row, fill = r)) +
  geom_tile(color = "white") +
  geom_text(aes(label = sprintf("%.2f", r), color = txt), size = 3) +
  scale_fill_gradientn(colors = heat, limits = c(0, 1)) +
  scale_color_identity() +
  coord_equal() +
  labs(title = "Item intercorrelations", x = NULL, y = NULL, fill = "r")
```

Because the off-diagonal correlations here are all similar (around 0.42),
the tiles read as nearly one color. When correlations are all alike, no
color scale will show much difference among them; the scale does more
visible work when the values have a wider range, including negative ones, as
in the next example.

A second matrix, the correlations among several `mtcars` variables (fuel
economy, cylinders, displacement, horsepower, rear-axle ratio, and weight),
has a wide range, including strong negative correlations --- fuel economy
falls as weight, cylinders, and displacement rise. A *diverging* ramp
anchored at the two Notre Dame primaries (navy for negative, a light tint at
zero, gold for positive) shows those differences:

```{r corr-diverging, fig.height = 4.8, fig.width = 5.8}
vars <- c("mpg", "cyl", "disp", "hp", "drat", "wt")
Rm   <- cor(mtcars[, vars])
dfm  <- as.data.frame(as.table(Rm)); names(dfm) <- c("row", "col", "r")
dfm$txt <- ifelse(dfm$r < -0.5, "white", nd_color("navy"))

diverging <- grDevices::colorRampPalette(
  c(nd_color("navy"), nd_tints[["light_warm_white"]], nd_color("bright_gold")))(100)

ggplot(dfm, aes(col, row, fill = r)) +
  geom_tile(color = "white") +
  geom_text(aes(label = sprintf("%.2f", r), color = txt), size = 3) +
  scale_fill_gradientn(colors = diverging, limits = c(-1, 1)) +
  scale_color_identity() +
  coord_equal() +
  labs(title = "mtcars correlations (diverging ramp)", x = NULL, y = NULL,
       fill = "r")
```

Standardized factor loadings are a natural two-group fill: one bar per
item for each of two factors, colored ND Blue and Bright Gold. The first
four items load on the first factor, the last four on the second:

```{r factor-loadings, fig.height = 4.4, fig.width = 7}
loadings <- rbind(
  data.frame(item = paste0("Item ", 1:8), factor = "Verbal",
             loading = c(.74, .69, .78, .81, .22, .15, .09, .25)),
  data.frame(item = paste0("Item ", 1:8), factor = "Quantitative",
             loading = c(.18, .12, .24, .07, .71, .79, .66, .80)))
loadings$item <- factor(loadings$item, levels = paste0("Item ", 8:1))

ggplot(loadings, aes(loading, item, fill = factor)) +
  geom_col(position = "dodge", width = 0.7) +
  scale_fill_nd() +
  labs(title = "Standardized factor loadings", x = "loading", y = NULL,
       fill = "factor")
```

Item characteristic curves from a two-parameter logistic model give each
item one of the well-separated brand colors. Five items, five colors:

```{r item-curves, fig.height = 4.4, fig.width = 7}
theta <- seq(-4, 4, length.out = 200)
pars  <- data.frame(item = paste0("Item ", 1:5),
                    a = c(1.2, 0.8, 1.6, 1.0, 1.9),     # discriminations
                    b = c(-1.5, -0.6, 0.1, 0.8, 1.7))   # difficulties
icc <- do.call(rbind, lapply(seq_len(nrow(pars)), function(i) {
  data.frame(theta = theta, item = pars$item[i],
             p = plogis(pars$a[i] * (theta - pars$b[i])))
}))

ggplot(icc, aes(theta, p, color = item)) +
  geom_line(linewidth = 1) +
  scale_color_nd() +
  labs(title = "Item characteristic curves (2PL)",
       x = expression(theta), y = "probability of a correct response",
       color = "item")
```

# Finding a color by name and role

The palettes above cover most plotting needs, but sometimes you want one
specific brand color, or you want to see the whole set at once with a
note on what each color is. `nd_colors` is that catalog: one row per
color, labeled with its brand (University or Athletics) and its role
(primary, secondary, former, tint, or neutral).

```{r colors-table, eval = TRUE}
nd_colors
```

`nd_color()` pulls hex values out of that table by name or by role, which
is easier than going through a palette name when you only want a color or
two:

```{r color-by-name, eval = TRUE}
nd_color("navy", "green")        # two colors by name
nd_color(role = "former")        # a whole role group
```

Because the result is a plain character vector of hexadecimal strings, it
drops straight into a manual scale, a base graphics call, or anywhere
else a color is expected:

```{r color-manual, fig.height = 4.5}
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
  geom_point(size = 2.5, alpha = 0.9) +
  scale_color_manual(values = nd_color("navy", "bright_gold", "green")) +
  labs(title = "Picked by name", x = "sepal length", y = "petal length",
       color = "species")
```

The table also carries the Notre Dame Athletics colors for reference.
Athletics is a separate brand system: it shares ND Blue with the
University, pairs it with a warmer Standard Dome Gold and a metallic gold
that has no sanctioned digital value (so its hex is `NA`), and uses an
Irish Green a single Pantone step from the University green. These
Athletics colors are reference only and never enter `nd_palette()` or the
scales.

```{r colors-athletics, eval = TRUE}
nd_colors[nd_colors$brand == "athletics", c("name", "hex", "pms")]
```

# Mixing in a color from outside the palette

Sometimes one category should be a specific color that is not a Notre Dame
color at all --- a rival's color, another institution's, or a flag. Because
`nd_palette()` and `nd_color()` return plain hex strings, you can append your
own color and hand the combined vector to `scale_color_manual()` (in
`ggplot2`) or to a `col` argument (in base R): keep the Notre Dame colors for
the brand-relevant groups and let the outside color stand apart.

The three below are **not** Notre Dame colors; they are defined here only for
the example:

```{r non-nd-defs, eval = TRUE}
st_louis_blues <- "#2c5196"   # St. Louis Blues blue
irish_flag     <- "#009900"   # Irish flag green
dark_goldenrod <- "#b8860b"   # darkgoldenrod
```

In `ggplot2`, build the value vector from `nd_color()` plus the outside color
and pass it to `scale_color_manual()`:

```{r non-nd-ggplot, fig.height = 4.2}
values <- c("setosa"     = nd_color("navy"),
            "versicolor" = nd_color("bright_gold"),
            "virginica"  = st_louis_blues)        # the non-ND color
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
  geom_point(size = 2.5) +
  scale_color_manual(values = values) +
  labs(title = "Two Notre Dame colors plus one from outside the palette",
       x = "sepal length", y = "petal length", color = "species")
```

The same idea in base R --- the first groups take Notre Dame colors and the
last takes the outside color:

```{r non-nd-base, eval = TRUE, fig.height = 4}
cols <- c(nd_palette(2), irish_flag)              # navy, bright gold, Irish green
barplot(c(8, 6, 9), col = cols, border = NA, names.arg = c("A", "B", "C"),
        main = "Notre Dame palette plus one outside color")
```

# Other palettes

## Former Notre Dame colors

The seven colors past the six leading brand colors are former Notre Dame
colors: a historical, legacy set no longer in the current brand guide. In
the former brand taxonomy six were *secondary* colors and purple was the
lone *tertiary* color. They are approximate, legacy colors, included here
only to extend the categorical palette past six, and are not part of the
current Notre Dame brand. A color such as purple appearing in this set
should not be read as a current, primary, or signature Notre Dame color.
Because a key like `maroon` does not reveal its tier, the `description`
column of `nd_colors` gives each one's tier and hue (teal, for instance, is
a former secondary color):

```{r former-desc, eval = TRUE}
nd_colors[nd_colors$role == "former", c("name", "hex", "description")]
```

They round out the default palette beyond six, and they are also available
on their own:

```{r former-swatch, eval = TRUE, fig.height = 1.6, fig.width = 8}
nd_palette(palette = "former")
show_palette(nd_palette(palette = "former"))
```

Selectable palettes other than `"nd"` are not wired into the
`scale_*_nd()` functions; reach them through `scale_fill_manual()` or
`scale_color_manual()`:

```{r former-plot, fig.height = 4.5}
ggplot(InsectSprays, aes(spray, count, fill = spray)) +
  geom_boxplot() +
  scale_fill_manual(values = nd_palette(palette = "former")) +
  labs(title = "Former Notre Dame palette", x = "spray", y = "count") +
  theme(legend.position = "none")
```

## Colorblind-friendly Notre Dame colors

When categorical separation or colorblind safety matters more than leading
with the brand colors, the `"nd_cvd"` palette reorders the
*actual* Notre Dame colors (current and former) so that they stay
distinguishable under the common forms of color vision deficiency, rather
than borrowing a palette from another source. The order was derived by a
greedy search that, at each step, adds the Notre Dame color that keeps the
worst-case minimum CIE-Lab Delta-E as large as possible across normal
vision and simulated deuteranopia, protanopia, and tritanopia. The ten
anchors stay distinguishable for two through ten categories and lead with
ND Blue and Bright Gold, the Notre Dame pair furthest apart under simulation.

```{r cvd-swatch, eval = TRUE, fig.height = 1.6, fig.width = 8}
show_palette(nd_palette(palette = "nd_cvd"))
```

The `scale_*_nd()` scales take it through their `palette` argument, so it
drops into a plot the same way as the default:

```{r cvd-plot, fig.height = 4.5}
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
  geom_point(size = 2.5) +
  scale_color_nd(palette = "nd_cvd") +
  labs(title = "Colorblind-friendly Notre Dame colors", x = "sepal length",
       y = "petal length", color = "species")
```

To see why the ordering is safe, the rows below show the first eight
`"nd_cvd"` colors as they appear to normal vision and as simulated for the
three dichromacies with the `colorspace` package. The colors stay
separated across all four rows:

```{r cvd-sim, eval = requireNamespace("colorspace", quietly = TRUE), fig.height = 3.2, fig.width = 8}
cvd8 <- nd_palette(8, palette = "nd_cvd")
rows <- list("normal vision" = cvd8,
             deuteranopia     = colorspace::deutan(cvd8),
             protanopia       = colorspace::protan(cvd8),
             tritanopia       = colorspace::tritan(cvd8))
op <- par(mfrow = c(4, 1), mar = c(0.3, 6.5, 0.3, 0.3))
for (nm in names(rows)) {
  plot(NA, xlim = c(0, 8), ylim = c(0, 1), axes = FALSE, xlab = "", ylab = "",
       xaxs = "i", yaxs = "i")
  rect(0:7, 0, 1:8, 1, col = rows[[nm]], border = "white")
  mtext(nm, side = 2, las = 1, line = 0.5, cex = 0.85)
}
par(op)
```

# Brand tints, backgrounds, and sequential ramps

Four Notre Dame brand tints are too light to read as data on a white
background, so `nd_palette()` never returns them. They remain useful away
from the data layer and are exported as `nd_tints`:

```{r tints, eval = TRUE}
nd_tints
```

A tint makes a panel background behind a single brand color:

```{r tint-bg, fig.height = 4.5}
ggplot(mtcars, aes(wt, mpg)) +
  geom_point(color = nd_palette(1), size = 2.5) +
  labs(title = "A tint as a panel background", x = "weight", y = "mpg") +
  theme(panel.background = element_rect(fill = nd_tints[["light_sky_blue"]],
                                        color = NA))
```

Warm White (`#efe9d9`) is the warm counterpart: a cream that works as a
full-page background behind dark brand colors. Set it on both
`panel.background` and `plot.background`:

```{r warm-white-bg, fig.height = 4.5}
ggplot(mtcars, aes(wt, mpg)) +
  geom_point(color = nd_palette(1), size = 2.5) +
  labs(title = "Warm White as a full background", x = "weight", y = "mpg") +
  theme(
    panel.background = element_rect(fill = nd_tints[["warm_white"]],
                                    color = NA),
    plot.background  = element_rect(fill = nd_tints[["warm_white"]],
                                    color = NA)
  )
```

Six informal soft backgrounds are also provided, as `nd_informal_tints`,
running from a very light warm white to a warmer soft yellow. The two
`faint_*` tints sit just off pure white (CIE L\* about 99) for the lightest
touch, where you want only a hint of warmth rather than plain white. These
are **not** Notre Dame brand colors; they are alternatives to a white
background for HTML reports, vignettes, and Shiny apps, offered alongside
the official Warm Whites:

```{r informal-tints, eval = TRUE}
nd_informal_tints
```

```{r informal-swatch, eval = TRUE, fig.height = 1.5, fig.width = 9}
show_palette(nd_informal_tints, labels = names(nd_informal_tints),
             border = "grey80")
```

Set one on both `panel.background` and `plot.background` for a soft page
behind a plot --- here the new, even softer `soft_white`:

```{r soft-bg, fig.height = 4.5}
ggplot(mtcars, aes(wt, mpg)) +
  geom_point(color = nd_palette(1), size = 2.5) +
  labs(title = "An informal soft-white background", x = "weight", y = "mpg") +
  theme(
    panel.background = element_rect(fill = nd_informal_tints[["soft_white"]],
                                    color = NA),
    plot.background  = element_rect(fill = nd_informal_tints[["soft_white"]],
                                    color = NA)
  )
```

A tint also makes a natural light end for a sequential ramp running to a
dark brand color, for a continuous (rather than categorical) fill. Putting
Bright Blue between the pale tint and navy keeps the midtones a clear blue
instead of a washed-out gray:

```{r ramp, eval = TRUE, fig.height = 1.6, fig.width = 8}
ramp <- grDevices::colorRampPalette(
  c(nd_tints[["light_sky_blue"]], nd_color("bright_blue"), nd_color("navy")))(7)
show_palette(ramp)
```

Applied to `faithfuld`, a smoothed density of Old Faithful eruptions over
eruption length and waiting time:

```{r ramp-plot, fig.height = 4.5}
ggplot(faithfuld, aes(waiting, eruptions, fill = density)) +
  geom_raster() +
  scale_fill_gradientn(colors = ramp) +
  labs(title = "Old Faithful eruption density", x = "waiting", y = "eruptions")
```

For a **diverging** quantity --- a correlation that runs from negative to
positive, say --- a ramp anchored at the two Notre Dame primaries (navy and
gold) with a light tint in the middle covers both directions:

```{r diverging-ramp, eval = TRUE, fig.height = 1.6, fig.width = 9}
diverging <- grDevices::colorRampPalette(
  c(nd_color("navy"), nd_tints[["light_warm_white"]], nd_color("bright_gold")))(11)
show_palette(diverging)
```

The *Statistical and psychometric visualization* section above puts this
ramp on a correlation matrix.

# Theming R Markdown reports

The package's stylesheet themes an HTML report in the same colors its figures
use, so the prose and the plots match. The simplest route is the
`html_nd_document` output format, which wires the stylesheet in for you:

```yaml
output: NDPalette::html_nd_document
```

To add it to an existing `html_document` instead, point the `css` field at the
shipped stylesheet:

```yaml
output:
  html_document:
    css: !expr NDPalette::nd_css_path()
```

Either way you get navy headings, a bright-gold accent rule, navy table
headers, brand-tinted callout boxes (`.note`, `.important`, `.tip`), and the
soft Warm White page background; `nd_css()` also returns the stylesheet as a
string if you would rather inline it or edit a copy. The same stylesheet
drops into Shiny via `shiny::includeCSS(nd_css_path())`, and the *Theming a
Shiny app with NDPalette* vignette walks through a complete app.

By default the stylesheet uses a system sans-serif font and loads nothing
from the network. To pull two open-source fonts close in feel to the brand
typefaces --- Montserrat for body text, Zilla Slab for headings --- generate
the stylesheet with `web_fonts = TRUE`, which adds a Google Fonts import:

```yaml
output:
  html_document:
    css: !expr NDPalette::nd_css(tempfile(fileext = ".css"), web_fonts = TRUE)
```

These are independent open-source typefaces, not the licensed Notre Dame
brand fonts.

# Pairing with a light theme

`NDPalette` is a color system, not a full visual theme: it does not ship
a `theme_nd()`. The brand colors pair best with a light built-in
`ggplot2` theme, which keeps the figure background white or near-white so
the colors carry the meaning. This vignette sets `theme_minimal()` once at
the top with `theme_set(theme_minimal(base_size = 12))`, and every figure
above inherits it.

`theme_light()` and `theme_bw()` are good light alternatives:

```{r theme-light, fig.height = 4.5}
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
  geom_point(size = 2.5) +
  scale_color_nd() +
  labs(x = "sepal length", y = "petal length", color = "species") +
  theme_light(base_size = 12)
```

# A note on fonts

Notre Dame's brand typefaces are licensed, so `NDPalette` ships colors
only, not fonts. You can pair the colors with free, openly licensed fonts
that have a similar feel through `ggplot2`'s `base_family` argument.
Montserrat is a geometric sans close to the brand sans, and Zilla Slab or
Roboto Slab is a slab serif close to the brand display face. These are
independent open-source typefaces, not the Notre Dame fonts. For an HTML
report, `nd_css(web_fonts = TRUE)` pulls the same two open-source fonts
from Google Fonts and applies them to the page (see *Theming R Markdown
reports* above).

The recipe below uses the `showtext` and `sysfonts` packages to pull two
free fonts from Google Fonts and render them. It is shown for reference
and is not run when this vignette is built (it would require those two
packages and a network connection).

```{r fonts, eval = FALSE}
# install.packages(c("showtext", "sysfonts"))
library(showtext)
sysfonts::font_add_google("Montserrat", "nd_sans")  # geometric sans
sysfonts::font_add_google("Zilla Slab", "nd_slab")  # slab serif
showtext_auto()

ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
  geom_point(size = 2.5) +
  scale_color_nd() +
  labs(title = "Notre Dame colors with a free, ND-evoking font",
       x = "sepal length", y = "petal length", color = "species") +
  theme_minimal(base_family = "nd_sans") +
  theme(plot.title = element_text(family = "nd_slab", face = "bold"))
```

If you already have a free font installed on your system, the
`systemfonts` package can register it by name without a download, and the
same `base_family` argument then applies it.

# Related color tools

`NDPalette` is a small, single-purpose package: one institution's colors,
curated and ordered for statistical visualization and psychometric
analysis. For general color-palette machinery (palette classes, format
conversion, interpolation, and a large catalog of palettes from across R),
see Emil Hvitfeldt's
[palettes](https://cran.r-project.org/package=palettes) package and the
companion [r-color-palettes](https://github.com/EmilHvitfeldt/r-color-palettes)
gallery. The `NDPalette` anchors are exported as `nd_palettes` precisely
so they can be registered with general tools such as
[paletteer](https://emilhvitfeldt.github.io/paletteer/) when that broader
machinery is what you need.
