Color Palette Management

Overview

The palette module provides nine functions covering four areas:

Area Functions
Querying palettes get_palette(), list_palettes()
Visualization preview_palette(), palette_gallery()
Managing palettes create_palette(), remove_palette(), compile_palettes()
Color conversion hex2rgb(), rgb2hex()
library(evanverse)

Note: All code examples in this vignette are static (eval = FALSE). Output is hand-written to reflect the current implementation. If you modify the palette functions, re-verify the examples manually or switch chunks to eval = TRUE.

Palettes are stored as JSON files organized under three subdirectories — sequential/, diverging/, and qualitative/ — and compiled into the palettes package dataset via compile_palettes().


1 Querying Palettes

get_palette() — Retrieve a palette by name

Returns a character vector of HEX color codes. If type is omitted, the palette type is auto-detected. Use n to take the first N colors from a larger palette.

# Auto-detect type
get_palette("qual_vivid")
#> [1] "#E64B35" "#4DBBD5" "#00A087" "#3C5488" "#F39B7F" "#8491B4"

# Specify type explicitly
get_palette("qual_vivid", type = "qualitative")
#> [1] "#E64B35" "#4DBBD5" "#00A087" "#3C5488" "#F39B7F" "#8491B4"

# Take only the first 3 colors
get_palette("seq_blues", type = "sequential", n = 3)
#> [1] "#deebf7" "#9ecae1" "#3182bd"

When type is wrong, the error message tells you where the palette actually lives:

get_palette("qual_vivid", type = "sequential")
#> Error in `get_palette()`:
#> ! Palette "qual_vivid" not found under "sequential", but exists under "qualitative".
#> Try: get_palette("qual_vivid", type = "qualitative")

Requesting more colors than the palette contains raises an informative error rather than silently recycling:

get_palette("qual_softtrio", type = "qualitative", n = 10)
#> Error in `get_palette()`:
#> ! Palette "qual_softtrio" only has 3 colors, but requested 10.

list_palettes() — Browse available palettes

Returns a data frame with columns name, type, n_color, and colors. Filter by one or more types with the type argument.

list_palettes()
#>              name       type n_color                                   colors
#> 1    div_contrast  diverging       5  #2166ac, #92c5de, #f7f7f7, ...
#> 2    div_fireice   diverging       7  #4575b4, #91bfdb, #e0f3f8, ...
#> ...
#> 12   qual_vivid   qualitative       6  #E64B35, #4DBBD5, #00A087, ...
#> ...
# Single type
list_palettes(type = "qualitative")

# Multiple types
list_palettes(type = c("sequential", "diverging"))

Results are sorted by type, n_color, and name by default. Set sort = FALSE to keep the original file order.


2 Visualization

preview_palette() — Visualize a single palette

Plots a single palette using one of five styles: "bar" (default), "pie", "point", "rect", or "circle". Returns NULL invisibly — called for the plotting side effect.

preview_palette("seq_blues", type = "sequential")
preview_palette("div_fireice", plot_type = "pie")
preview_palette("qual_vivid", n = 4, plot_type = "circle")

Supply title to override the default title (which is the palette name):

preview_palette("qual_vivid", title = "My favourite palette")

3 Managing Palettes

create_palette() — Save a custom palette

Writes a named palette as a JSON file under color_dir/<type>/<name>.json. The directory is created automatically if it does not exist.

temp_dir <- file.path(tempdir(), "palettes")

create_palette("blues", "sequential", c("#deebf7", "#9ecae1", "#3182bd"),
               color_dir = temp_dir)
#> v Palette saved: /tmp/.../palettes/sequential/blues.json

create_palette("qual_vivid", "qualitative",
               c("#E64B35", "#4DBBD5", "#00A087"),
               color_dir = temp_dir)
#> v Palette saved: /tmp/.../palettes/qualitative/qual_vivid.json

By default, saving over an existing name raises an error. Pass overwrite = TRUE to replace it:

create_palette("blues", "sequential", c("#c6dbef", "#6baed6", "#2171b5"),
               color_dir = temp_dir, overwrite = TRUE)
#> i Overwriting existing palette: "blues"
#> v Palette saved: /tmp/.../palettes/sequential/blues.json
# Without overwrite = TRUE
create_palette("blues", "sequential", c("#deebf7", "#9ecae1", "#3182bd"),
               color_dir = temp_dir)
#> Error in `create_palette()`:
#> ! Palette "blues" already exists. Use `overwrite = TRUE` to replace.

The function invisibly returns a list with path and info so the result can be captured when needed.


remove_palette() — Delete a palette JSON

Removes a palette JSON file by name. If type is omitted, all three type directories are searched in order.

remove_palette("blues", color_dir = temp_dir)
#> v Removed "blues" from sequential

# Specify type to skip the search
remove_palette("qual_vivid", type = "qualitative", color_dir = temp_dir)
#> v Removed "qual_vivid" from qualitative

If the palette is not found in any directory, a warning is issued and the function returns FALSE invisibly:

remove_palette("nonexistent", color_dir = temp_dir)
#> ! Palette "nonexistent" not found in any type.

compile_palettes() — Build the palette dataset

Reads all JSON files under palettes_dir/sequential/, palettes_dir/diverging/, and palettes_dir/qualitative/, validates them, and returns a structured list. This is the function used in data-raw/palettes.R to rebuild the palettes package dataset via usethis::use_data().

compiled <- compile_palettes(
  palettes_dir = system.file("extdata", "palettes", package = "evanverse")
)
#> v Compiled 30 palettes: Sequential=8, Diverging=6, Qualitative=16

The return value is a named list with three elements — sequential, diverging, and qualitative — each of which is a named list of HEX vectors:

compiled$qualitative[["qual_vivid"]]
#> [1] "#E64B35" "#4DBBD5" "#00A087" "#3C5488" "#F39B7F" "#8491B4"

Duplicate palette names within the same type emit a warning and the last file read wins. JSON files with missing or invalid fields are skipped with a warning rather than aborting the whole compile.


4 Color Conversion

hex2rgb() — HEX to RGB data frame

Converts a character vector of HEX codes to a data frame with columns hex, r, g, b. Both 6-digit (#RRGGBB) and 8-digit (#RRGGBBAA) codes are accepted; the alpha channel is silently ignored.

hex2rgb("#FF8000")
#>       hex   r   g b
#> 1 #FF8000 255 128 0

hex2rgb(c("#FF8000", "#00FF00", "#3182bdB2"))
#>          hex   r   g   b
#> 1    #FF8000 255 128   0
#> 2    #00FF00   0 255   0
#> 3 #3182bdB2  49 130 189

The # prefix is required; codes that fail the pattern and NA values are both reported as invalid:

# Missing '#' prefix
hex2rgb("FF8000")
#> Error in `hex2rgb()`:
#> ! `hex` contains invalid HEX codes: "FF8000".

# NA is treated as an invalid code
hex2rgb(c("#FF8000", NA))
#> Error in `hex2rgb()`:
#> ! `hex` contains invalid HEX codes: NA.

rgb2hex() — RGB to HEX color codes

The symmetric counterpart to hex2rgb(). Accepts either a numeric vector of length 3 or the data frame returned by hex2rgb(). Non-integer values are rounded before conversion.

# Single color as a length-3 vector
rgb2hex(c(255, 128, 0))
#> [1] "#FF8000"
# Round-trip: HEX -> RGB -> HEX
rgb2hex(hex2rgb(c("#FF8000", "#00FF00")))
#> [1] "#FF8000" "#00FF00"
# Non-integer values are rounded
rgb2hex(c(254.7, 128.2, 0.4))
#> [1] "#FF8000"

Typical failure cases for the vector form:

# Wrong length
rgb2hex(c(255, 128))
#> Error in `rgb2hex()`:
#> ! `rgb` must be a numeric vector of length 3.

# Value out of range
rgb2hex(c(255, 128, 300))
#> Error in `rgb2hex()`:
#> ! `rgb` values must be in [0, 255].

And for the data frame form:

# Missing column
rgb2hex(data.frame(r = 255, g = 128))
#> Error in `rgb2hex()`:
#> ! `rgb` must have columns {"r", "g", "b"}. Missing: {"b"}.

# Column value out of range
rgb2hex(data.frame(r = 255, g = 128, b = 300))
#> Error in `rgb2hex()`:
#> ! Column "b" in `rgb` must be numeric with values in [0, 255].

5 A Combined Workflow

The palette and conversion functions compose naturally. The example below picks a qualitative palette, converts its colors to RGB for downstream processing, then rounds-trips back to HEX to verify no information was lost.

library(evanverse)

# 1. Retrieve a qualitative palette
colors <- get_palette("qual_vivid", type = "qualitative", n = 4)
colors
#> [1] "#E64B35" "#4DBBD5" "#00A087" "#3C5488"

# 2. Convert to RGB for numeric manipulation
rgb_df <- hex2rgb(colors)
rgb_df
#>       hex   r   g   b
#> 1 #E64B35 230  75  53
#> 2 #4DBBD5  77 187 213
#> 3 #00A087   0 160 135
#> 4 #3C5488  60  84 136

# 3. Lighten each color by blending 50% toward white (255)
rgb_light <- rgb_df
rgb_light$r <- (rgb_light$r + 255) / 2
rgb_light$g <- (rgb_light$g + 255) / 2
rgb_light$b <- (rgb_light$b + 255) / 2

# 4. Convert back to HEX and preview
light_hex <- rgb2hex(rgb_light)
light_hex
#> [1] "#F2A59A" "#A6DDEA" "#80CFC7" "#9EAAC4"

# 5. Save the new derived palette for reuse
temp_dir <- file.path(tempdir(), "palettes")
create_palette("qual_vivid_light", "qualitative", light_hex,
               color_dir = temp_dir)
#> v Palette saved: /tmp/.../palettes/qualitative/qual_vivid_light.json

# 6. Verify the new palette is retrievable
"qual_vivid_light" %in% list_palettes(type = "qualitative")$name
#> [1] TRUE

# 7. Clean up
unlink(temp_dir, recursive = TRUE)

Getting Help