ggplot2 geom_label() in R: Boxed Text Labels

The geom_label() function in ggplot2 places text labels with a COLORED BACKGROUND BOX, useful for high-contrast labels over busy plots. It is the boxed version of geom_text().

⚡ Quick Answer
ggplot(df, aes(x, y, label = name)) + geom_label()
geom_label(fill = "yellow", color = "black")
geom_label(label.padding = unit(0.5, "lines"))
geom_label(label.r = unit(0.3, "lines"))   # rounded corners
ggrepel::geom_label_repel()                 # auto-adjust

Need explanation? Read on for examples and pitfalls.

📊 Is geom_label() the right tool?
STARTneed high-contrast labelsgeom_label() (boxed)minimal labelsgeom_text() (no box)many overlapping labelsggrepel::geom_label_repel()one-off annotationsannotate("label", ...)legend-style highlightsgeom_label()

What geom_label() does in one sentence

geom_label() is geom_text() with a filled background box, providing visual contrast against busy plots. Useful when label readability matters.

Syntax

geom_label(label.padding = unit(0.25, "lines"), label.r = unit(0.15, "lines"), label.size = 0.25, ...). Box-specific arguments plus all geom_text args.

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.
RBoxed labels on scatter
library(ggplot2) library(tibble) mtcars |> tibble::rownames_to_column("car") |> head(5) |> ggplot(aes(wt, mpg, label = car)) + geom_point() + geom_label(hjust = -0.1, fill = "lightyellow")

  
Tip
geom_label is best for important annotations that must stand out. Use sparingly; many labels with boxes clutter the plot.

Five common patterns

1. Standard boxed label

RReplace text with label
ggplot(df, aes(x, y, label = name)) + geom_label()

  

2. Custom fill

RYellow boxes
ggplot(df, aes(x, y, label = name)) + geom_label(fill = "yellow")

  

3. Conditional labels

ROnly outliers
mtcars |> tibble::rownames_to_column("car") |> ggplot(aes(wt, mpg, label = ifelse(mpg > 30, car, ""))) + geom_point() + geom_label(fill = "lightblue")

  

4. ggrepel for non-overlapping

RAuto-place boxes
library(ggrepel) ggplot(mtcars, aes(wt, mpg, label = rownames(mtcars))) + geom_point() + geom_label_repel(max.overlaps = 10, size = 3)

  

5. Rounded corners

RSoft edges
ggplot(df, aes(x, y, label = name)) + geom_label(label.r = unit(0.5, "lines"), fill = "lightgreen")

  
Key Insight
Use geom_label when contrast matters; use geom_text when minimal styling is fine. geom_label adds visual weight; too many boxes clutter.

geom_label() vs geom_text() vs ggrepel

Function Box Avoid overlap
geom_label() Yes No
geom_text() No No
geom_label_repel() Yes Yes
geom_text_repel() No Yes

For many labels, prefer the repel variants.

A practical workflow

Use geom_label sparingly for "must-see" annotations.

RInteractive R
mtcars |> tibble::rownames_to_column("car") |> ggplot(aes(wt, mpg)) + geom_point() + geom_label( data = ~ filter(.x, mpg > 30), aes(label = car), fill = "lightyellow", hjust = -0.1 )

  

Only the high-mpg cars get boxed labels.

Common pitfalls

Pitfall 1: too many labels. geom_label adds visual weight; many boxes clutter the plot. Use sparingly or switch to geom_text.

Pitfall 2: positioning. Like geom_text, hjust/vjust position the box relative to (x, y).

Warning
geom_label covers underlying points and lines. If a box overlaps a point, you can't see the point. Use alpha or carefully position.

Try it yourself

Try it: Plot mpg vs wt with boxed labels for cars where mpg > 28. Save to ex_plot.

RYour turn: selective boxed labels
ex_plot <- mtcars |> tibble::rownames_to_column("car") |> # your code here

  
Click to reveal solution
RSolution
ex_plot <- mtcars |> tibble::rownames_to_column("car") |> ggplot(aes(wt, mpg)) + geom_point() + geom_label( data = ~ filter(.x, mpg > 28), aes(label = car), fill = "lightyellow", hjust = -0.1 )

  

Explanation: Filter to high-mpg cars; geom_label highlights them with yellow boxes.

After mastering geom_label, look at:

  • geom_text(): plain text
  • ggrepel::geom_label_repel(): anti-overlap boxed labels
  • annotate("label", ...): one-off labels
  • geom_text_repel(): anti-overlap plain

FAQ

What does geom_label do in ggplot2?

geom_label() places text labels with a colored background box at (x, y) coordinates.

What is the difference between geom_label and geom_text?

geom_label adds a filled box; geom_text is plain. Use label for contrast over busy backgrounds.

How do I prevent labels from overlapping?

Use ggrepel::geom_label_repel(). It auto-shifts labels to avoid collisions.

Can I customize the box appearance?

Yes. label.padding controls inside spacing; label.r controls corner rounding; fill sets background color.

Should I use geom_label or geom_text?

label for IMPORTANT must-read annotations. text for minimal styling. Many labels with boxes look cluttered; use sparingly.