feat: bump title sizes, add font_scale to logo functions, ship SVGs
R-CMD-check / R CMD check (push) Successful in 3m36s

- Change rel_large default from 16/14 to 20/14 (~1.43x) to match the
  Civilytics editorial design system. Subtitle now renders at 1.0x base
  instead of 0.86x.
- Switch axis.text to rel() sizing so all text elements cascade from the
  root font_size, enabling uniform scaling.
- Add font_scale parameter (default 1.1) to civilytics_logo(),
  add_logo(), and add_logo_ga() — inflates text by ~10% before
  arrangeGrob composition to compensate for viewport shrinkage.
- Ship SVG logo variants (mark, wordmark, pulse) in inst/img/ for
  Quarto/HTML templates.
- Add "Maintaining brand assets" section to README documenting inst/img/
  file inventory and update workflow.
- Document full font size hierarchy in theme_civilytics() roxygen.
This commit is contained in:
2026-05-19 12:51:23 -06:00
parent 34622ccf88
commit 31d3e2886d
26 changed files with 222 additions and 26 deletions
+43 -9
View File
@@ -46,17 +46,27 @@ get_png <- function(filename) {
#' @param plot a ggplot2 grob
#' @param logo a logo grob created by make_logo_grob()
#' @param margin_param a numeric specifying what margin to add or subtract to align the logo
#' @param font_scale Numeric. Multiplicative scaling factor applied to text
#' sizes before composing the plot with the logo. Default `1.1` inflates
#' text by ~10 \% to compensate for the viewport shrinkage caused by
#' [gridExtra::arrangeGrob()]. Set to `1` to disable.
#'
#' @return a grob with a logo attached to it ready to plot
#' @importFrom ggplot2 theme
#' @importFrom gridExtra arrangeGrob
#' @export
add_logo <- function(plot, logo, margin_param = NULL) {
add_logo <- function(plot, logo, margin_param = NULL, font_scale = 1.1) {
# Inflate text sizes to compensate for arrangeGrob viewport shrinkage.
# All theme text elements use rel() sizing, so scaling the root 'text'
# element cascades to titles, axis labels, legends, captions, and strips.
if (!is.null(font_scale) && font_scale != 1) {
base_size <- plot$theme$text$size %||% 14
plot <- plot + ggplot2::theme(
text = ggplot2::element_text(size = base_size * font_scale)
)
}
if(has_caption(plot)) {
# convert the caption size to a negative number and on the "pt" scale
# p1$theme$plot.caption$size * 1.1
# Count the number of lines, which is this + 1
# For each line, we can add a certain negative space to align the logo
cap_lines <- measure_caption(plot)
if (!is.null(margin_param)) {
plot <- plot + theme(plot.margin = unit(c(7, 7, margin_param, 7), "pt"))
@@ -107,13 +117,15 @@ has_caption <- function(gg) {
any(names(gg$labels) == "caption")
}
#' Add a logo to a ggplot2 object
#' Add a logo to multiple ggplot2 objects
#'
#' @param plot_list a list containing ggplot2 objects
#' @param logo a grob containing the logo created with `make_logo_grob`
#' @param nrow an integer, default = 1, for the number of rows to align the plots in
#' @param widths an optional vector the same length as plot_list with the widths for each plot
#' @param margin_param a number giving the adjustment up or down to help manually align logo and captions
#' @param font_scale Numeric. Multiplicative scaling factor applied to text
#' sizes before composing. Default `1.1`. See [add_logo()] for details.
#'
#' @return a grid object
#' @note The resulting object needs to be drawn to the screen using grid.draw()
@@ -131,7 +143,18 @@ has_caption <- function(gg) {
#' grid.draw(plot_and_logo)
#' dev.off()
#' }
add_logo_ga <- function(plot_list, logo, nrow = 1, widths = NULL, margin_param = NULL) {
add_logo_ga <- function(plot_list, logo, nrow = 1, widths = NULL,
margin_param = NULL, font_scale = 1.1) {
# Inflate text sizes to compensate for viewport shrinkage
if (!is.null(font_scale) && font_scale != 1) {
plot_list <- lapply(plot_list, function(p) {
base_size <- p$theme$text$size %||% 14
p + ggplot2::theme(
text = ggplot2::element_text(size = base_size * font_scale)
)
})
}
# Change position of logo depending on if plot has a caption
if (!is.null(margin_param)) {
margin <- theme(plot.margin = unit(c(7, 7, margin_param, 7), "pt"))
@@ -224,6 +247,9 @@ make_logo_grob <- function(type = c("wordmark", "mark"),
#' [make_logo_grob()].
#' @param margin_param Numeric or `NULL`. Manual margin adjustment passed to
#' [add_logo()].
#' @param font_scale Numeric. Inflate text sizes by this factor to compensate
#' for viewport shrinkage when composing with [gridExtra::arrangeGrob()].
#' Default `1.1` (~10 \% inflation). Set to `1` to disable.
#'
#' @return A grob (from [gridExtra::arrangeGrob()]) ready to draw with
#' [grid::grid.draw()].
@@ -246,12 +272,20 @@ make_logo_grob <- function(type = c("wordmark", "mark"),
#' theme_civilytics_dark()) |>
#' civilytics_logo(variant = "dark", type = "mark") |>
#' grid.draw()
#'
#' # Disable font inflation
#' (ggplot(mpg, aes(displ, hwy)) +
#' geom_point() +
#' theme_civilytics()) |>
#' civilytics_logo(font_scale = 1) |>
#' grid.draw()
#' }
civilytics_logo <- function(plot,
type = c("wordmark", "mark"),
variant = c("light", "dark"),
margin_param = NULL) {
margin_param = NULL,
font_scale = 1.1) {
logo <- make_logo_grob(type = type, variant = variant)
add_logo(plot, logo, margin_param = margin_param)
add_logo(plot, logo, margin_param = margin_param, font_scale = font_scale)
}
+32 -6
View File
@@ -24,7 +24,8 @@
#' @param rel_tiny Numeric. Scale factor for tiny text relative to `font_size`.
#' Default `11/14`.
#' @param rel_large Numeric. Scale factor for large text (titles) relative to
#' `font_size`. Default `16/14`.
#' `font_size`. Default `20/14` (~1.43x), matching the Civilytics editorial
#' design system.
#' @param ink Character. Hex code for foreground/text color. Defaults to
#' [civilytics_colors]`["ink"]` (`#0E1A2B`).
#' @param paper Character. Hex code for background color. Defaults to
@@ -40,6 +41,26 @@
#' transparent background (useful for slides or overlay on colored
#' surfaces).
#'
#' @section Font size hierarchy:
#' All text sizes are derived from `font_size` using relative scale factors.
#' At the default `font_size = 14`:
#'
#' | Element | Scale factor | Default size |
#' |:--------|:-------------|:-------------|
#' | Plot title | `rel_large` (1.43x) | ~20 pt |
#' | Subtitle | 1.0x | 14 pt |
#' | Axis text (tick labels) | `rel_small` (0.86x) | ~12 pt |
#' | Axis titles | `rel_small` (0.86x) | ~12 pt |
#' | Legend text | `rel_small` (0.86x) | ~12 pt |
#' | Caption | `rel_tiny` (0.79x) | ~11 pt |
#' | Legend title | `rel_tiny` (0.79x) | ~11 pt |
#' | Strip text (facets) | `rel_small` (0.86x) | ~12 pt |
#'
#' To uniformly scale all text, change `font_size`. To adjust only the title
#' prominence, change `rel_large`. When using [civilytics_logo()] to add a
#' logo below the plot, pass `font_scale` to compensate for viewport
#' shrinkage.
#'
#' @return A complete ggplot2 [ggplot2::theme()] object.
#' @export
#'
@@ -62,6 +83,11 @@
#' ggplot(mpg, aes(displ, hwy)) +
#' geom_point() +
#' theme_civilytics(paper_bg = FALSE)
#'
#' # Larger text for poster or display
#' ggplot(mpg, aes(displ, hwy)) +
#' geom_point() +
#' theme_civilytics(font_size = 18)
#' }
theme_civilytics <- function(
font_size = 14,
@@ -70,7 +96,7 @@ theme_civilytics <- function(
line_size = 0.5,
rel_small = 12 / 14,
rel_tiny = 11 / 14,
rel_large = 16 / 14,
rel_large = 20 / 14,
ink = unname(civilytics_colors["ink"]),
paper = unname(civilytics_colors["paper"]),
accent = unname(civilytics_colors["ember_600"]),
@@ -132,7 +158,7 @@ theme_civilytics <- function(
axis.line.y = ggplot2::element_blank(),
axis.text = ggplot2::element_text(
color = ink_2,
size = small_size
size = ggplot2::rel(rel_small)
),
axis.text.x = ggplot2::element_text(
margin = ggplot2::margin(t = small_size / 4),
@@ -249,7 +275,7 @@ theme_civilytics <- function(
),
plot.title.position = "plot",
plot.subtitle = ggplot2::element_text(
size = ggplot2::rel(rel_small),
size = ggplot2::rel(1),
color = ink_2,
hjust = 0,
vjust = 1,
@@ -307,7 +333,7 @@ theme_civilytics_dark <- function(
line_size = 0.5,
rel_small = 12 / 14,
rel_tiny = 11 / 14,
rel_large = 16 / 14,
rel_large = 20 / 14,
ink = unname(civilytics_colors["paper"]),
paper = unname(civilytics_colors["navy_700"]),
accent = unname(civilytics_colors["ember_400"]),
@@ -359,7 +385,7 @@ theme_civilytics_slide <- function(
line_size = 0.5,
rel_small = 12 / 14,
rel_tiny = 11 / 14,
rel_large = 16 / 14,
rel_large = 20 / 14,
ink = unname(civilytics_colors["ink"]),
paper = unname(civilytics_colors["paper"]),
accent = unname(civilytics_colors["ember_600"]),