feat: add brand color system, showtext fonts, and dark theme
R-CMD-check / R CMD check (push) Failing after 1m39s

- R/colors.R: civilytics_colors named vector (from --cv-* CSS vars on
  civilytics.com), three palettes (main/sequential/diverging),
  scale_color_civilytics() and scale_fill_civilytics() for ggplot2
- R/fonts.R: auto-loads Inter + Libre Franklin from Google Fonts via
  showtext in .onLoad(); exports civilytics_load_fonts() for manual retry
- R/theme.R: wires ggplot2 4.0 ink/paper/accent params into theme_grey()
  base, adds title_family + strip_color params; new theme_civilytics_dark()
  using navy_dark background and warm off-white text
- R/logo.R: make_logo_grob(variant) accepts "light"/"dark" to select the
  white logo for dark-background compositions
- DESCRIPTION: adds showtext, sysfonts; pins ggplot2 >= 4.0.0
- tests/testthat/test_theme.R: full test suite for colors, palettes,
  scales, both theme variants, and logo grob variants
This commit is contained in:
2026-05-17 10:36:59 -06:00
parent 2d70d9aecf
commit c93c469267
17 changed files with 996 additions and 206 deletions
+2
View File
@@ -27,6 +27,7 @@ Add a logo to a ggplot2 object
The resulting object needs to be drawn to the screen using grid.draw()
}
\examples{
\dontrun{
library(ggplot2); library(grid)
tmp_plot <- ggplot(mtcars) + aes(x = hp, y = disp) + geom_point() + theme_civilytics()
tmp_logo <- make_logo_grob()
@@ -34,3 +35,4 @@ plot_and_logo <- add_logo(tmp_plot, tmp_logo)
grid.draw(plot_and_logo)
dev.off()
}
}
+19
View File
@@ -0,0 +1,19 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/colors.R
\name{civilytics_colors}
\alias{civilytics_colors}
\title{Civilytics brand colors}
\format{
A named character vector of hex color codes.
}
\usage{
civilytics_colors
}
\description{
A named character vector of all Civilytics brand colors, matching the CSS
custom properties defined on www.civilytics.com (`--cv-*` variables).
}
\examples{
civilytics_colors["accent"]
civilytics_colors[c("ink", "paper")]
}
+23
View File
@@ -0,0 +1,23 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/fonts.R
\name{civilytics_load_fonts}
\alias{civilytics_load_fonts}
\title{Load Civilytics brand fonts}
\usage{
civilytics_load_fonts()
}
\value{
Invisibly returns `NULL`.
}
\description{
Downloads Inter and Libre Franklin from Google Fonts via
[sysfonts::font_add_google()], then calls [showtext::showtext_auto()] so
that all graphics devices render text with those fonts. This is called
automatically when the package loads; use this function to retry if the
initial load failed (e.g., the machine was offline at load time).
}
\examples{
\dontrun{
civilytics_load_fonts()
}
}
+29
View File
@@ -0,0 +1,29 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/colors.R
\name{civilytics_pal}
\alias{civilytics_pal}
\title{Civilytics brand color palette}
\usage{
civilytics_pal(name = "main", n = NULL)
}
\arguments{
\item{name}{Character. Palette name: `"main"`, `"sequential"`, or
`"diverging"`. Defaults to `"main"`.}
\item{n}{Integer or `NULL`. Number of colors to return. If `NULL`, returns
all colors in the palette. If `n` exceeds the number of defined stops,
colors are interpolated via [grDevices::colorRampPalette()].}
}
\value{
A character vector of hex color codes.
}
\description{
Returns a character vector of hex codes from a named Civilytics palette.
Available palettes: `"main"` (qualitative, up to 6), `"sequential"` (light
to dark navy), `"diverging"` (orange–neutral–navy).
}
\examples{
civilytics_pal() # all 6 qualitative colors
civilytics_pal("sequential", n = 3)
civilytics_pal("diverging", n = 5)
}
+12 -6
View File
@@ -4,16 +4,22 @@
\alias{make_logo_grob}
\title{Get a Civilytics Logo grob}
\usage{
make_logo_grob()
make_logo_grob(variant = c("light", "dark"))
}
\arguments{
\item{variant}{Character. `"light"` (default) uses the standard dark logo
suitable for light backgrounds. `"dark"` uses the white logo suitable for
dark backgrounds (pairs with [theme_civilytics_dark()]).}
}
\value{
a gg object which contains the logo file stored as a Grob suitable for manipulating in
grid
A ggplot object (class `"gg"`) containing the logo grob.
}
\description{
Get a Civilytics Logo grob
Returns a ggplot object containing the Civilytics logo as a rasterGrob,
ready to compose with plots via [add_logo()] or [add_logo_ga()].
}
\examples{
logo <- make_logo_grob()
class(logo) # gg
logo <- make_logo_grob() # light background
logo_dark <- make_logo_grob("dark") # dark background
class(logo) # "gg" "ggplot"
}
+36
View File
@@ -0,0 +1,36 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/colors.R
\name{scale_color_civilytics}
\alias{scale_color_civilytics}
\title{Civilytics color scale for ggplot2}
\usage{
scale_color_civilytics(palette = "main", discrete = TRUE, ...)
}
\arguments{
\item{palette}{Character. Palette name passed to [civilytics_pal()].
Defaults to `"main"`.}
\item{discrete}{Logical. `TRUE` (default) for a discrete scale; `FALSE` for
a continuous gradient via [ggplot2::scale_color_gradientn()].}
\item{...}{Additional arguments passed to the underlying ggplot2 scale
function.}
}
\value{
A ggplot2 scale object.
}
\description{
Applies a Civilytics brand palette to the `colour` aesthetic. Use
`discrete = TRUE` for categorical variables and `discrete = FALSE` for
continuous gradients.
}
\examples{
library(ggplot2)
ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point() +
scale_color_civilytics()
ggplot(mpg, aes(displ, hwy, colour = cty)) +
geom_point() +
scale_color_civilytics("sequential", discrete = FALSE)
}
+36
View File
@@ -0,0 +1,36 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/colors.R
\name{scale_fill_civilytics}
\alias{scale_fill_civilytics}
\title{Civilytics fill scale for ggplot2}
\usage{
scale_fill_civilytics(palette = "main", discrete = TRUE, ...)
}
\arguments{
\item{palette}{Character. Palette name passed to [civilytics_pal()].
Defaults to `"main"`.}
\item{discrete}{Logical. `TRUE` (default) for a discrete scale; `FALSE` for
a continuous gradient via [ggplot2::scale_fill_gradientn()].}
\item{...}{Additional arguments passed to the underlying ggplot2 scale
function.}
}
\value{
A ggplot2 scale object.
}
\description{
Applies a Civilytics brand palette to the `fill` aesthetic. Use
`discrete = TRUE` for categorical variables and `discrete = FALSE` for
continuous gradients.
}
\examples{
library(ggplot2)
ggplot(mpg, aes(class, fill = class)) +
geom_bar() +
scale_fill_civilytics()
ggplot(faithfuld, aes(waiting, eruptions, fill = density)) +
geom_tile() +
scale_fill_civilytics("sequential", discrete = FALSE)
}
+53 -11
View File
@@ -2,33 +2,75 @@
% Please edit documentation in R/theme.R
\name{theme_civilytics}
\alias{theme_civilytics}
\title{Make the Civilytics plot theme}
\title{Civilytics ggplot2 theme}
\usage{
theme_civilytics(
font_size = 14,
font_family = "",
font_family = CV_FONT_SANS,
title_family = CV_FONT_DISPLAY,
line_size = 0.5,
rel_small = 12/14,
rel_tiny = 11/14,
rel_large = 16/14
rel_large = 16/14,
ink = unname(civilytics_colors["ink"]),
paper = unname(civilytics_colors["paper"]),
accent = unname(civilytics_colors["accent"]),
strip_color = unname(civilytics_colors["paper_2"])
)
}
\arguments{
\item{font_size}{default 14, a number representing the base font for the theme}
\item{font_size}{Numeric. Base font size in points. Default `14`.}
\item{font_family}{default "", a character for the font family to use in the theme}
\item{font_family}{Character. Font family for body/axis text. Default
`"Inter"` (loaded via showtext).}
\item{line_size}{default 0.5, the line size to use for the theme}
\item{title_family}{Character. Font family for plot titles and strip labels.
Default `"Libre Franklin"` (loaded via showtext).}
\item{rel_small}{default 12/14, the scale factor to create a small font from the base font_size}
\item{line_size}{Numeric. Base line width. Default `0.5`.}
\item{rel_tiny}{default 11/14, the scale factor to create a tiny font from the base font_size}
\item{rel_small}{Numeric. Scale factor for small text relative to
`font_size`. Default `12/14`.}
\item{rel_large}{default 16/14, the scale factor to create a large font from the base font_size}
\item{rel_tiny}{Numeric. Scale factor for tiny text relative to `font_size`.
Default `11/14`.}
\item{rel_large}{Numeric. Scale factor for large text (titles) relative to
`font_size`. Default `16/14`.}
\item{ink}{Character. Hex code for foreground/text color. Defaults to
[civilytics_colors]`["ink"]` (`#0E1A2B`).}
\item{paper}{Character. Hex code for background color. Defaults to
[civilytics_colors]`["paper"]` (`#FAF7F2`).}
\item{accent}{Character. Hex code for accent/highlight color. Defaults to
[civilytics_colors]`["accent"]` (`#C25311`).}
\item{strip_color}{Character. Hex code for facet strip background. Defaults
to [civilytics_colors]`["paper_2"]` (`#F2EDE4`).}
}
\value{
a ggplot2 theme object suitable for combining with ggplot objects to theme them
A complete ggplot2 [ggplot2::theme()] object.
}
\description{
Make the Civilytics plot theme
A complete ggplot2 theme built on [ggplot2::theme_grey()] using the
Civilytics brand color palette and typography. Requires ggplot2 >= 4.0.0
for the `ink`, `paper`, and `accent` base-theme parameters.
}
\details{
Brand fonts (Inter for UI text, Libre Franklin for titles) are loaded
automatically via [showtext] when the package is attached. Call
[civilytics_load_fonts()] to reload them if needed.
}
\examples{
library(ggplot2)
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
theme_civilytics()
ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point() +
scale_color_civilytics() +
theme_civilytics()
}
+76
View File
@@ -0,0 +1,76 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/theme.R
\name{theme_civilytics_dark}
\alias{theme_civilytics_dark}
\title{Dark variant of the Civilytics ggplot2 theme}
\usage{
theme_civilytics_dark(
font_size = 14,
font_family = CV_FONT_SANS,
title_family = CV_FONT_DISPLAY,
line_size = 0.5,
rel_small = 12/14,
rel_tiny = 11/14,
rel_large = 16/14,
ink = unname(civilytics_colors["paper"]),
paper = unname(civilytics_colors["navy_dark"]),
accent = unname(civilytics_colors["accent_dark"]),
strip_color = unname(civilytics_colors["navy"])
)
}
\arguments{
\item{font_size}{Numeric. Base font size in points. Default `14`.}
\item{font_family}{Character. Font family for body/axis text. Default
`"Inter"` (loaded via showtext).}
\item{title_family}{Character. Font family for plot titles and strip labels.
Default `"Libre Franklin"` (loaded via showtext).}
\item{line_size}{Numeric. Base line width. Default `0.5`.}
\item{rel_small}{Numeric. Scale factor for small text relative to
`font_size`. Default `12/14`.}
\item{rel_tiny}{Numeric. Scale factor for tiny text relative to `font_size`.
Default `11/14`.}
\item{rel_large}{Numeric. Scale factor for large text (titles) relative to
`font_size`. Default `16/14`.}
\item{ink}{Character. Hex code for foreground/text color. Defaults to
[civilytics_colors]`["ink"]` (`#0E1A2B`).}
\item{paper}{Character. Hex code for background color. Defaults to
[civilytics_colors]`["paper"]` (`#FAF7F2`).}
\item{accent}{Character. Hex code for accent/highlight color. Defaults to
[civilytics_colors]`["accent"]` (`#C25311`).}
\item{strip_color}{Character. Hex code for facet strip background. Defaults
to [civilytics_colors]`["paper_2"]` (`#F2EDE4`).}
}
\value{
A complete ggplot2 [ggplot2::theme()] object.
}
\description{
A convenience wrapper around [theme_civilytics()] with dark-background
defaults: navy (`#1A2E4A`) background, warm off-white (`#FAF7F2`) text, and
a lighter orange accent (`#E07840`) suitable for dark backgrounds. Pair with
`make_logo_grob(variant = "dark")` to use the white logo.
}
\details{
All parameters from [theme_civilytics()] are accepted and override the dark
defaults.
}
\examples{
library(ggplot2)
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
theme_civilytics_dark()
ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point() +
scale_color_civilytics() +
theme_civilytics_dark()
}