Table of Contents#
- Understanding the HCL Color Model
hcl()Function Syntax and Parameters- Generating Color Vectors
- Practical Use Cases
- Best Practices and Common Pitfalls
- Conclusion
- References
Understanding the HCL Color Model#
The HCL color space decouples three perceptual attributes:
- Hue: The "color" itself (0-360° on the color wheel)
- 0° = Red, 120° = Green, 240° = Blue, 360° = Red
- Chroma: Color purity or intensity (0-100+)
- 0 = grayscale, higher values = more vivid
- Luminance: Perceived brightness (0-100)
- 0 = black, 100 = white, 50 = most vivid
Unlike RGB (which mixes light) or HSL (non-perceptually uniform), HCL's mathematical formulation ensures that:
- Luminance variations are perceptually linear
- Chroma boundaries stay within displayable gamut
- Hue differences correspond to consistent perceptual shifts

Visual representation of HCL dimensions (Source: Zeileis et al., 2009)
hcl() Function Syntax and Parameters#
The base R hcl() function has the following syntax:
hcl(h = 0, c = 35, l = 65, alpha = 1, fixup = TRUE)Parameters Explained:#
| Parameter | Type | Default | Description |
|---|---|---|---|
h | numeric | 0 | Hue (0-360) |
c | numeric | 35 | Chroma (≥0) |
l | numeric | 65 | Luminance (0-100) |
alpha | numeric | 1 | Transparency (0=transparent, 1=opaque) |
fixup | logical | TRUE | Adjust colors to valid RGB range? |
Key Characteristics:#
- All parameters are vectorized (critical for palette generation)
- Chroma and luminance values wrap/recycle to match longest vector
- For single-color output, pass scalar values to all parameters
- When
fixup = TRUE(default), colors are automatically adjusted to nearest displayable RGB values
Generating Color Vectors#
Basic Single-Color Example#
# Create a vivid red
red <- hcl(h = 0, c = 100, l = 50)
red
# [1] "#E32926"Creating Gradients#
Generate a 10-color vector from blue to yellow with constant chroma and luminance:
gradient <- hcl(
h = seq(240, 60, length.out = 10),
c = 70,
l = 65
)
Smooth perceptual gradient with constant chroma/luminance
Creating Diverging Palettes#
diverging <- hcl(
h = c(260, 0, 60), # Purple -> Gray (close to white) -> Yellow
c = c(80, 0, 80), # Chroma: vivid -> gray -> vivid
l = c(25, 95, 85), # Dark -> Light -> Medium
alpha = 0.9 # Slight transparency
)Qualitative Palettes#
Create 8 distinct colors with consistent chroma and luminance:
qualitative <- hcl(
h = seq(0, 315, length.out = 8),
c = 60,
l = 70
)Parameter Vectorization#
Match vectors manually for complex effects:
custom_vector <- hcl(
h = c(120, 240, 30, 300),
c = c(40, 80, 60, 90),
l = c(70, 60, 90, 40),
alpha = c(1, 0.7, 1, 0.5)
)Practical Use Cases#
1. Heatmap Creation#
# Generate 256-color heatmap palette
heat_colors <- hcl(
h = 0, # Red hue
c = 100, # Maximum chroma
l = seq(100, 0, length.out = 256) # Light to dark
)
filled.contour(volcano, col = heat_colors)2. Accessible Categorical Palettes#
Colorblind-friendly palette with distinct hues and balanced luminance:
accessible <- hcl(
h = c(20, 120, 260),
c = 70,
l = c(60, 65, 70)
)
pie(rep(1,3), col = accessible, labels = c("Group A", "Group B", "Group C"))3. Grayscale Conversion#
image_colors <- c("#FF5733", "#33FF57", "#3357FF")
grayscale <- hcl(
h = 0, # Hue value (arbitrary when chroma=0)
c = 0, # Zero chroma
l = 70 # Fixed luminance
)4. Coordinating Plot Elements#
plot(1:10, col = hcl(h=180, c=50, l=70), pch=16, cex=2)
lines(1:10, col = hcl(h=180, c=80, l=50), lwd=2)
title(main = "Teal Color Scheme", col.main = hcl(h=180, c=30, l=30))Best Practices and Common Pitfalls#
Do:#
- Prioritize luminance contrast - Ensure at least 30-point difference between foreground/background
- Keep chroma consistent within palettes for visual harmony
- Test palettes with
scales::show_col(your_palette) - Vectorize intentionally - Use
rep()for repeated values - Adjust for output medium - Print requires higher chroma than screens
Don't:#
- Assume gamut coverage - High chroma values may not render as expected (
fixup=TRUEhelps) - Ignore lighting conditions - Ambient light affects perceived luminance
- Overload with colors - Stick to 6-8 categorical colors maximum
- Mix HCL/RGB carelessly - Convert between spaces explicitly with
convertColor()
Common Fixes:#
# Check if colors were modified by fixup
original <- hcl(280, 150, 50, fixup = FALSE) # May be NA
adjusted <- hcl(280, 150, 50) # Adjusted to #A63BEB
# Create valid colors by constraining parameters
safe_palette <- hcl(
h = seq(0, 300, length.out = 6),
c = pmin(90, 150), # Cap chroma at 90
l = 60
)Conclusion#
The hcl() function provides a powerful, perception-based approach to color generation in R. By separating hue, chroma, and luminance, you gain intuitive control over color properties that matter most in visualization. Key advantages include:
- Creating perceptually balanced palettes with minimal effort
- Ensuring accessibility through luminance control
- Generating seamless gradients and specialized palettes
- Maintaining consistency across visualization elements
While mastering HCL requires practice, the payoff is visually compelling and statistically accurate data representation. Remember that:
- HCL complements rather than replaces other color spaces
- Always validate palettes with actual data plots
- Context (media, audience, lighting) should drive parameter choices
Experiment with the included examples and consult the references below to deepen your understanding of color theory in data visualization.
References#
- Zeileis, A., Hornik, K., & Murrell, P. (2009). Escaping RGBland: Selecting colors for statistical graphics. Computational Statistics & Data Analysis, 53(9), 3259-3270.
- Ihaka, R. (2003). Colour for Presentation Graphics. Proceedings of the 3rd International Workshop on Distributed Statistical Computing.
- R Core Team (2023). R: A Language and Environment for Statistical Computing. https://www.R-project.org/
?hcl- Official R Documentation- Stauffer, R. et al. (2015). ggthemes: Extra Themes, Scales and Geoms for ggplot2. R package version 3.4.0.
- Lumley, T. (2013). colorspace: Color Space Manipulation. R package version 1.4-1.