ggplot2 scale_color_manual() in R: Custom Colors for Groups

The scale_color_manual() function in ggplot2 assigns specific colors to specific factor levels in a plot. It is the right choice when you want EXACT colors (e.g., brand colors) instead of an automatic palette.

⚡ Quick Answer
+ scale_color_manual(values = c("a" = "red", "b" = "blue"))
+ scale_color_manual(values = c("red","blue","green"))
+ scale_fill_manual(values = c(...))         # fill aesthetic
+ scale_color_brewer(palette = "Set1")        # palette alternative
+ scale_color_viridis_d()                     # perceptual uniform

Need explanation? Read on for examples and pitfalls.

📊 Is scale_color_manual() the right tool?
STARTspecific exact colors per categoryscale_color_manual()color palette by namescale_color_brewer()perceptually uniformscale_color_viridis_d()continuous gradientscale_color_gradient()fill aestheticscale_fill_manual()

What scale_color_manual() does in one sentence

scale_color_manual(values = ...) maps each factor level of the color aesthetic to a specific color you provide. Used when default palette doesn't match brand or domain conventions.

Syntax

scale_color_manual(values, name = waiver(), labels = waiver(), ...). values is a named or positional vector of colors.

Run live
Run live, no install needed. Every R block on this page runs in your browser. Click Run, edit the code, re-run instantly. No setup.
RBrand colors
library(ggplot2) ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) + geom_point(size = 3) + scale_color_manual(values = c("4" = "#1f77b4", "6" = "#ff7f0e", "8" = "#d62728"))

  
Tip
Use NAMED vectors c("level" = "color") for safety; positional c("red","blue") is fragile if levels reorder.

Five common patterns

1. Named values

RExplicit level-color mapping
+ scale_color_manual(values = c("low" = "green", "mid" = "yellow", "high" = "red"))

  

2. Positional values

ROrder matches factor levels
+ scale_color_manual(values = c("red", "blue", "green"))

  

3. fill_manual variant

RFor geom_col, geom_bar
+ scale_fill_manual(values = c("a" = "steelblue", "b" = "tomato"))

  

4. Use hex codes

RBrand colors
+ scale_color_manual(values = c("primary" = "#1F2937", "secondary" = "#3B82F6"))

  

5. Drop unused levels

Rdrop = FALSE keeps all
+ scale_color_manual(values = c(...), drop = FALSE)

  
Key Insight
Use named vector c("level"="color") for STABLE mapping across plot revisions. Positional vectors break if you reorder factor levels.

scale_color_manual() vs scale_color_brewer() vs scale_color_viridis

Function Source Best for
scale_color_manual() Custom Exact colors
scale_color_brewer() ColorBrewer palettes Named palettes
scale_color_viridis_d() Viridis Perceptually uniform
scale_color_grey() Greyscale Print-safe

A practical workflow

For team / brand consistency, define a colors vector once and reuse.

RInteractive R
team_colors <- c( "Sales" = "#1F77B4", "Marketing" = "#FF7F0E", "Engineering" = "#2CA02C" ) ggplot(df, aes(month, headcount, color = team)) + geom_line() + scale_color_manual(values = team_colors)

  

Common pitfalls

Pitfall 1: too few colors. If you have 5 levels but values has 3, ggplot recycles or errors. Provide one per level.

Pitfall 2: typos in named vector. A typo in "level" silently maps to default gray. Always check output.

Warning
scale_color_manual only sets COLOR aesthetic; for FILL, use scale_fill_manual(). They are separate scales.

Try it yourself

Try it: Color mtcars points by cyl with custom colors red, green, blue. Save to ex_plot.

RYour turn: custom colors
ex_plot <- mtcars |> ggplot(aes(wt, mpg, color = factor(cyl))) + geom_point(size = 3) + # your code here

  
Click to reveal solution
RSolution
ex_plot <- ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) + geom_point(size = 3) + scale_color_manual(values = c("4" = "red", "6" = "green", "8" = "blue"))

  

Explanation: Named vector maps each cyl value to a specific color.

After mastering scale_color_manual, look at:

  • scale_fill_manual(): same for fill aesthetic
  • scale_color_brewer(): ColorBrewer palettes
  • scale_color_viridis_d(): viridis palette
  • aes(color = ...): map color aesthetic
  • theme(): plot-wide styling

FAQ

What does scale_color_manual do in ggplot2?

scale_color_manual() assigns specific colors to factor levels for the color aesthetic. Used for custom / brand colors.

What is the difference between scale_color_manual and scale_fill_manual?

color is for line/point COLOR. fill is for area FILL (bars, polygons, ribbons). Use whichever aesthetic your geom uses.

How do I provide colors as hex codes?

Pass them in values: c("a" = "#1F77B4", "b" = "#FF7F0E").

What if I have more levels than colors?

ggplot recycles or errors. Always provide one color per level.

Should I use named or positional values?

Named for safety. Positional breaks silently if factor levels reorder.