Skip to content
/ huerd Public

A discrete color palette generator with support for fixed colors optimized for both normal and color vision deficient viewers.

License

Unknown, MIT licenses found

Licenses found

Unknown
LICENSE
MIT
LICENSE.md
Notifications You must be signed in to change notification settings

sims1253/huerd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

huerd huerd website

License R-CMD-check Tests Codecov test coverage GH-Pages Lifecycle: experimental

A discrete color palette generator with support for fixed colors, optimized for color vision deficient viewers. Features different optimization algorithms and a multi-objective optimization framework for advanced color palette generation.

Installation

You can install the development version of huerd from GitHub with:

# install.packages("pak")
pak::pak("sims1253/huerd")

Basic Example

Generate a palette with 5 colors:

library(huerd)

palette <- generate_palette(8, progress = FALSE)
print(palette)
#> 
#> -- huerd Color Palette (8 colors) --
#> Colors:
#> [ 1] #6C0000
#> [ 2] #007F77
#> [ 3] #0084FF
#> [ 4] #FF0000
#> [ 5] #E900FF
#> [ 6] #9792B2
#> [ 7] #00B1EA
#> [ 8] #00DBFF
#> 
#> -- Quality Metrics Summary --
#> * Min. Perceptual Distance (OKLAB): 0.115
#> * Optimizer Performance Ratio      : 37.0%
#> * Min. CVD-Safe Distance (OKLAB)  : 0.066
#> 
#> -- Generation Details --
#> * Optimizer Iterations: 487
#> * Optimizer Status: NLOPT_XTOL_REACHED: Optimization stopped because xtol_rel or xtol_abs (above) was reached.

Constrained Color Palettes

Include specific colors while optimizing the remaining colors:

library(huerd)

palette <- generate_palette(
  n = 8,
  include_colors = c("#4A6B8A", "#E5A04C"),
  progress = FALSE
)
print(palette)
#> 
#> -- huerd Color Palette (8 colors) --
#> Colors:
#> [ 1] #700000
#> [ 2] #114661
#> [ 3] #A73800
#> [ 4] #4A6B8A
#> [ 5] #CE673B
#> [ 6] #00AAAD
#> [ 7] #E5A04C
#> [ 8] #FFC7D8
#> 
#> -- Quality Metrics Summary --
#> * Min. Perceptual Distance (OKLAB): 0.132
#> * Optimizer Performance Ratio      : 42.7%
#> * Min. CVD-Safe Distance (OKLAB)  : 0.130
#> 
#> -- Generation Details --
#> * Optimizer Iterations: 533
#> * Optimizer Status: NLOPT_XTOL_REACHED: Optimization stopped because xtol_rel or xtol_abs (above) was reached.

Multi-Optimizer Support

Choose from 4 different optimization algorithms based on your needs:

library(huerd)

# COBYLA: Default deterministic optimizer for general use
cobyla_palette <- generate_palette(6, optimizer = "nloptr_cobyla", progress = FALSE)

# SANN: Stochastic simulated annealing for higher quality
sann_palette <- generate_palette(6, optimizer = "sann", progress = FALSE)

# DIRECT: Global optimization for reproducibility (may need tuning)
direct_palette <- generate_palette(6, optimizer = "nlopt_direct", progress = FALSE)

# Nelder-Mead: Derivative-free local optimization
# As an alternative deterministic approach
neldermead_palette <- generate_palette(6, optimizer = "nlopt_neldermead", progress = FALSE)

cat("COBYLA:", paste(cobyla_palette, collapse = ", "), "\n")
#> COBYLA: #2600BA, #970000, #0000FF, #008A00, #FF0000, #BAA69E
cat("SANN:", paste(sann_palette, collapse = ", "), "\n")
#> SANN: #300000, #6E0000, #0000D7, #00A100, #CE74FF, #00FFFF
cat("DIRECT:", paste(direct_palette, collapse = ", "), "\n")
#> DIRECT: #636363, #636363, #636363, #636363, #636363, #636363
cat("Nelder-Mead:", paste(neldermead_palette, collapse = ", "), "\n")
#> Nelder-Mead: #9D0000, #FF0000, #FF77C5, #A7C100, #FFB8A2, #00FBFF

Multi-Objective Framework

The package includes a multi-objective optimization framework:

library(huerd)

# Current: Pure distance optimization (default)
distance_palette <- generate_palette(
  n = 6,
  weights = c(distance = 1),  # Explicit distance weighting
  optimizer = "nloptr_cobyla",
  progress = FALSE
)

# Future versions will support additional objectives like:
# weights = c(distance = 0.7, aesthetics = 0.3)
# weights = c(distance = 0.8, uniformity = 0.2)

print(distance_palette)
#> 
#> -- huerd Color Palette (6 colors) --
#> Colors:
#> [ 1] #001E00
#> [ 2] #A50000
#> [ 3] #FF0000
#> [ 4] #00A5FF
#> [ 5] #00FFFF
#> [ 6] #FFF300
#> 
#> -- Quality Metrics Summary --
#> * Min. Perceptual Distance (OKLAB): 0.189
#> * Optimizer Performance Ratio      : 51.6%
#> * Min. CVD-Safe Distance (OKLAB)  : 0.136
#> 
#> -- Generation Details --
#> * Optimizer Iterations: 329
#> * Optimizer Status: NLOPT_XTOL_REACHED: Optimization stopped because xtol_rel or xtol_abs (above) was reached.

Diagnostic Dashboard

Get a quick overview of your palette properties:

library(huerd)

palette <- generate_palette(8, progress = FALSE)
plot_palette_analysis(palette, force_font_scale = 0.6)

Palette Quality Evaluation

Or look at the numerical evaluation results:

library(huerd)

palette <- generate_palette(8, progress = FALSE)
evaluation <- evaluate_palette(palette)

# Access raw metrics (no subjective scoring)
cat("Minimum distance:", evaluation$distances$min, "\n")
#> Minimum distance: 0.2073131
cat("Performance ratio:", evaluation$distances$performance_ratio * 100, "%\n")
#> Performance ratio: 66.9047 %
cat("CVD worst case:", evaluation$cvd_safety$worst_case_min_distance, "\n")
#> CVD worst case: 0.08815642

Custom Parameters

Fine-tune the generation process with advanced options:

library(huerd)

palette <- generate_palette(
  n = 8,
  initialization = "harmony",              # Color harmony-based initialization
  init_lightness_bounds = c(0.3, 0.8),    # Constrain lightness range
  max_iterations = 2000,                   # Increased iterations
  optimizer = "nloptr_cobyla",             # Use COBYLA for optimization
  progress = FALSE
)
print(palette)
#> 
#> -- huerd Color Palette (8 colors) --
#> Colors:
#> [ 1] #CE4572
#> [ 2] #00AC8F
#> [ 3] #00BACF
#> [ 4] #A6AF5F
#> [ 5] #B9AFFC
#> [ 6] #D0BE8F
#> [ 7] #FFB9E7
#> [ 8] #67FFA4
#> 
#> -- Quality Metrics Summary --
#> * Min. Perceptual Distance (OKLAB): 0.093
#> * Optimizer Performance Ratio      : 29.9%
#> * Min. CVD-Safe Distance (OKLAB)  : 0.065
#> 
#> -- Generation Details --
#> * Optimizer Iterations: 573
#> * Optimizer Status: NLOPT_XTOL_REACHED: Optimization stopped because xtol_rel or xtol_abs (above) was reached.

Complete Workflow Example

library(huerd)

# 1. Generate brand palette with advanced optimization
brand_palette <- generate_palette(
  n = 8,
  include_colors = c("#1f77b4", "#ff7f0e"),  # Fixed brand colors
  fixed_aesthetic_influence = 0.9,
  initialization = "harmony",
  optimizer = "sann",
  max_iterations = 5000,
  weights = c(distance = 1),
  return_metrics = TRUE,
  progress = TRUE
)
#> Preparing for palette generation...
#> Adapting initialization from fixed colors' aesthetics...
#> Initializing 6 free colors (method: harmony)...
#> Optimizing 6 free colors using sann...
#> Finalizing palette...
#> Done.

# 2. Diagnostic analysis
plot_palette_analysis(brand_palette, force_font_scale = 0.6)

# 3. Quality evaluation
evaluation <- evaluate_palette(brand_palette)
cat("Min distance:", round(evaluation$distances$min, 3), "\n")
#> Min distance: 0.18
cat("Performance:", round(evaluation$distances$performance_ratio * 100, 1), "%\n")
#> Performance: 57.9 %

# 4. CVD accessibility check
cvd_safe <- is_cvd_safe(brand_palette)
if (cvd_safe) {
  cat("Palette is CVD-accessible\n")
} else {
  cat("Palette may challenge CVD viewers\n")
}
#> Palette is CVD-accessible

# 5. CVD simulation for verification
cvd_simulation <- simulate_palette_cvd(brand_palette, cvd_type = "all")
print(cvd_simulation)
#> 
#> -- huerd CVD Simulation Result (Multiple Types, Severity: 1.00) --
#> Palette for: original
#>   [ 1] #450000
#>   [ 2] #005800
#>   [ 3] #3100DD
#>   [ 4] #1F77B4
#>   [ 5] #FF0055
#>   [ 6] #FF7F0E
#>   [ 7] #F5B7FF
#>   [ 8] #45FF00
#> Palette for: protan
#>   [ 1] #181400
#>   [ 2] #5A4E00
#>   [ 3] #004EE2
#>   [ 4] #5A79B7
#>   [ 5] #666355
#>   [ 6] #A59100
#>   [ 7] #B0C8FF
#>   [ 8] #FFE600
#> Palette for: deutan
#>   [ 1] #292300
#>   [ 2] #52480D
#>   [ 3] #003ADA
#>   [ 4] #456CB3
#>   [ 5] #9F914E
#>   [ 6] #C4AE05
#>   [ 7] #BECFFD
#>   [ 8] #F1D83A
#> Palette for: tritan
#>   [ 1] #4D0001
#>   [ 2] #005549
#>   [ 3] #005B81
#>   [ 4] #00868D
#>   [ 5] #FF0032
#>   [ 6] #FF616D
#>   [ 7] #F7BED1
#>   [ 8] #00F7D9

# 6. Display final palette (colors are brightness-sorted)
print(brand_palette)
#> 
#> -- huerd Color Palette (8 colors) --
#> Colors:
#> [ 1] #450000
#> [ 2] #005800
#> [ 3] #3100DD
#> [ 4] #1F77B4
#> [ 5] #FF0055
#> [ 6] #FF7F0E
#> [ 7] #F5B7FF
#> [ 8] #45FF00
#> 
#> -- Quality Metrics Summary --
#> * Min. Perceptual Distance (OKLAB): 0.180
#> * Optimizer Performance Ratio      : 57.9%
#> * Min. CVD-Safe Distance (OKLAB)  : 0.093
#> 
#> -- Generation Details --
#> * Optimizer Iterations: 5000
#> * Optimizer Status: Optimization converged

About

A discrete color palette generator with support for fixed colors optimized for both normal and color vision deficient viewers.

Resources

License

Unknown, MIT licenses found

Licenses found

Unknown
LICENSE
MIT
LICENSE.md

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages