Version: 0.9.7
Title: Automatically Position Non-Overlapping Text Labels with 'ggplot2'
Description: Provides text and label geoms for 'ggplot2' that help to avoid overlapping text labels. Labels repel away from each other and away from the data points.
Depends: R (≥ 4.5.0), ggplot2 (≥ 3.5.2)
Imports: grid, Rcpp, rlang (≥ 1.1.6), S7, scales (≥ 1.4.0), withr (≥ 3.0.2)
Suggests: knitr, rmarkdown, testthat, svglite, vdiffr, gridExtra, ggpp, patchwork, devtools, prettydoc, ggbeeswarm, dplyr, magrittr, readr, stringr, marquee, rsvg, sf
VignetteBuilder: knitr
License: GPL-3 | file LICENSE
URL: https://ggrepel.slowkow.com/, https://github.com/slowkow/ggrepel
BugReports: https://github.com/slowkow/ggrepel/issues
RoxygenNote: 7.3.3
LinkingTo: Rcpp
Encoding: UTF-8
NeedsCompilation: yes
Packaged: 2026-02-25 01:13:15 UTC; ks38
Author: Kamil Slowikowski ORCID iD [aut, cre], Teun van den Brand ORCID iD [ctb], Alicia Schep ORCID iD [ctb], Sean Hughes ORCID iD [ctb], Trung Kien Dang ORCID iD [ctb], Saulius Lukauskas [ctb], Jean-Olivier Irisson ORCID iD [ctb], Zhian N Kamvar ORCID iD [ctb], Thompson Ryan ORCID iD [ctb], Dervieux Christophe ORCID iD [ctb], Yutani Hiroaki [ctb], Pierre Gramme [ctb], Amir Masoud Abdol [ctb], Malcolm Barrett ORCID iD [ctb], Robrecht Cannoodt ORCID iD [ctb], Michał Krassowski ORCID iD [ctb], Michael Chirico ORCID iD [ctb], Pedro Aphalo ORCID iD [ctb], Francis Barton [ctb]
Maintainer: Kamil Slowikowski <kslowikowski@gmail.com>
Repository: CRAN
Date/Publication: 2026-02-25 06:30:29 UTC

GeomLabelRepel

Description

This package contains extra geoms for ggplot2.

Details

Please see the help pages listed below:

Also see the vignette for more usage examples:

browseVignettes("ggrepel")

Please report issues and suggest improvements at Github:

https://github.com/slowkow/ggrepel

Author(s)

Maintainer: Kamil Slowikowski kslowikowski@gmail.com (ORCID)

Other contributors:

See Also

GeomLabel from the ggplot2 package.

GeomText from the ggplot2 package.

Useful links:


Repulsive text element

Description

This text element is a replacement for element_text that repulses labels.

Usage

element_text_repel(
  family = NULL,
  face = NULL,
  colour = NULL,
  size = NULL,
  hjust = NULL,
  vjust = NULL,
  angle = NULL,
  lineheight = NULL,
  color = NULL,
  margin = NULL,
  box.padding = NULL,
  force = NULL,
  force_pull = NULL,
  max.time = NULL,
  max.iter = NULL,
  max.overlaps = NULL,
  min.segment.length = NULL,
  segment.colour = NULL,
  segment.linetype = NULL,
  segment.size = NULL,
  segment.curvature = NULL,
  segment.angle = NULL,
  segment.ncp = NULL,
  segment.shape = NULL,
  segment.square = NULL,
  segment.squareShape = NULL,
  segment.inflect = NULL,
  arrow = NULL,
  seed = NA,
  position = c("bottom", "top", "left", "right"),
  inherit.blank = FALSE
)

Arguments

family

The typeface to use. The validity of this value will depend on the graphics device being used for rendering the plot. See the systemfonts vignette for guidance on the best way to access fonts installed on your computer. The values "sans", "serif", and "mono" should always be valid and will select the default typeface for the respective styles. However, what is considered default is dependant on the graphics device and the operating system.

face

Font face ("plain", "italic", "bold", "bold.italic")

colour, color

Line/border colour. Color is an alias for colour. alpha() can be used to set the transparency of the colour.

size

Font size in points.

hjust

Horizontal justification (in [0, 1])

vjust

Vertical justification (in [0, 1])

angle

Angle (in [0, 360])

lineheight

Line height

margin

Margins around the text. See margin() for more details. When creating a theme, the margins should be placed on the side of the text facing towards the center of the plot.

box.padding

Amount of padding around bounding box, as unit or number. Defaults to 0.25. (Default unit is lines, but other units can be specified by passing unit(x, "units")).

force

Force of repulsion between overlapping text labels. Defaults to 1.

force_pull

Force of attraction between a text label and its corresponding data point. Defaults to 1.

max.time

Maximum number of seconds to try to resolve overlaps. Defaults to 0.5.

max.iter

Maximum number of iterations to try to resolve overlaps. Defaults to 10000.

max.overlaps

Exclude text labels when they overlap too many other things. For each text label, we count how many other text labels or other data points it overlaps, and exclude the text label if it has too many overlaps. Defaults to 10.

min.segment.length

Skip drawing segments shorter than this, as unit or number. Defaults to 0.5. (Default unit is lines, but other units can be specified by passing unit(x, "units")).

segment.colour, segment.linetype, segment.size

Graphical parameters for the line connecting the text to points of origin.

segment.curvature, segment.angle, segment.ncp, segment.shape, segment.square, segment.squareShape, segment.inflect

Settings for curving the connecting line. See curveGrob for descriptions of these parameters.

arrow

Arrow specification, as created by grid::arrow()

seed

Random seed passed to set.seed. Defaults to NA, which means that set.seed will not be called.

position

One of "top", "right", "bottom", "left" setting where the text labels should be relative to points of origin.

inherit.blank

Should this element inherit the existence of an element_blank among its parents? If TRUE the existence of a blank element among its parents will cause this element to be blank as well. If FALSE any blank parent element will be ignored when calculating final element state.

Value

An object of class <element_text_repel>.

Examples

# A plot with a crowded y-axis
p <- ggplot(mtcars, aes(mpg, rownames(mtcars))) +
  geom_col() +
  coord_cartesian(ylim = c(-32, 64)) +
  theme(axis.text.y = element_text_repel())

# By default there isn't enough space to draw distinctive lines
p

# The available space can be increased by setting the margin
p + theme(axis.text.y.left = element_text_repel(margin = margin(r = 20)))

# For secondary axis positions at the top and right, the `position` argument
# should be set accordingly
p + scale_y_discrete(position = "right") +
  theme(axis.text.y.right = element_text_repel(
    margin = margin(l = 20),
    position = "right"
  ))

# Using segment settings and matching tick colour
p + theme(
  axis.text.y.left = element_text_repel(
    margin = margin(r = 20),
    segment.curvature = -0.1,
    segment.inflect = TRUE,
    segment.colour = "red"
  ),
  axis.ticks.y.left = element_line(colour = "red")
)

Repulsive textual annotations.

Description

geom_text_repel adds text directly to the plot. geom_label_repel draws a rectangle underneath the text, making it easier to read. The text labels repel away from each other and away from the data points.

Usage

geom_label_repel(
  mapping = NULL,
  data = NULL,
  stat = "identity",
  position = "identity",
  parse = FALSE,
  ...,
  box.padding = 0.25,
  label.padding = 0.25,
  point.padding = 1e-06,
  label.r = 0.15,
  label.size = 0.25,
  min.segment.length = 0.5,
  arrow = NULL,
  force = 1,
  force_pull = 1,
  max.time = 0.5,
  max.iter = 10000,
  max.overlaps = getOption("ggrepel.max.overlaps", default = 10),
  nudge_x = 0,
  nudge_y = 0,
  xlim = c(NA, NA),
  ylim = c(NA, NA),
  na.rm = FALSE,
  show.legend = NA,
  direction = c("both", "y", "x"),
  seed = NA,
  verbose = getOption("verbose", default = FALSE),
  inherit.aes = TRUE
)

geom_marquee_repel(
  mapping = NULL,
  data = NULL,
  stat = "identity",
  position = "identity",
  ...,
  box.padding = 0.25,
  point.padding = 1e-06,
  min.segment.length = 0.5,
  arrow = NULL,
  force = 1,
  force_pull = 1,
  max.time = 0.5,
  max.iter = 10000,
  max.overlaps = getOption("ggrepel.max.overlaps", default = 10),
  nudge_x = 0,
  nudge_y = 0,
  xlim = c(NA, NA),
  ylim = c(NA, NA),
  na.rm = FALSE,
  show.legend = NA,
  direction = c("both", "y", "x"),
  seed = NA,
  verbose = getOption("verbose", default = FALSE),
  inherit.aes = TRUE
)

geom_text_repel(
  mapping = NULL,
  data = NULL,
  stat = "identity",
  position = "identity",
  parse = FALSE,
  ...,
  box.padding = 0.25,
  point.padding = 1e-06,
  min.segment.length = 0.5,
  arrow = NULL,
  force = 1,
  force_pull = 1,
  max.time = 0.5,
  max.iter = 10000,
  max.overlaps = getOption("ggrepel.max.overlaps", default = 10),
  nudge_x = 0,
  nudge_y = 0,
  xlim = c(NA, NA),
  ylim = c(NA, NA),
  na.rm = FALSE,
  show.legend = NA,
  direction = c("both", "y", "x"),
  seed = NA,
  verbose = getOption("verbose", default = FALSE),
  inherit.aes = TRUE
)

Arguments

mapping

Set of aesthetic mappings created by aes or aes_. If specified and inherit.aes = TRUE (the default), is combined with the default mapping at the top level of the plot. You only need to supply mapping if there isn't a mapping defined for the plot.

data

A data frame. If specified, overrides the default data frame defined at the top level of the plot.

stat

The statistical transformation to use on the data for this layer, as a string.

position

Position adjustment, either as a string, or the result of a call to a position adjustment function.

parse

If TRUE, the labels will be parsed into expressions and displayed as described in ?plotmath

...

other arguments passed on to layer. There are three types of arguments you can use here:

  • Aesthetics: to set an aesthetic to a fixed value, like colour = "red" or size = 3.

  • Other arguments to the layer, for example you override the default stat associated with the layer.

  • Other arguments passed on to the stat.

box.padding

Amount of padding around bounding box, as unit or number. Defaults to 0.25. (Default unit is lines, but other units can be specified by passing unit(x, "units")).

label.padding

Amount of padding around label, as unit or number. Defaults to 0.25. (Default unit is lines, but other units can be specified by passing unit(x, "units")).

point.padding

Amount of padding around labeled point, as unit or number. Defaults to 0. (Default unit is lines, but other units can be specified by passing unit(x, "units")).

label.r

Radius of rounded corners, as unit or number. Defaults to 0.15. (Default unit is lines, but other units can be specified by passing unit(x, "units")).

label.size

Size of label border, in mm.

min.segment.length

Skip drawing segments shorter than this, as unit or number. Defaults to 0.5. (Default unit is lines, but other units can be specified by passing unit(x, "units")).

arrow

specification for arrow heads, as created by arrow

force

Force of repulsion between overlapping text labels. Defaults to 1.

force_pull

Force of attraction between a text label and its corresponding data point. Defaults to 1.

max.time

Maximum number of seconds to try to resolve overlaps. Defaults to 0.5.

max.iter

Maximum number of iterations to try to resolve overlaps. Defaults to 10000.

max.overlaps

Exclude text labels when they overlap too many other things. For each text label, we count how many other text labels or other data points it overlaps, and exclude the text label if it has too many overlaps. Defaults to 10.

nudge_x, nudge_y

Horizontal and vertical adjustments to nudge the starting position of each text label. The units for nudge_x and nudge_y are the same as for the data units on the x-axis and y-axis.

xlim, ylim

Limits for the x and y axes. Text labels will be constrained to these limits. By default, text labels are constrained to the entire plot area.

na.rm

If FALSE (the default), removes missing values with a warning. If TRUE silently removes missing values.

show.legend

logical. Should this layer be included in the legends? NA, the default, includes if any aesthetics are mapped. FALSE never includes, and TRUE always includes.

direction

"both", "x", or "y" – direction in which to adjust position of labels

seed

Random seed passed to set.seed. Defaults to NA, which means that set.seed will not be called.

verbose

If TRUE, some diagnostics of the repel algorithm are printed

inherit.aes

If FALSE, overrides the default aesthetics, rather than combining with them. This is most useful for helper functions that define both data and aesthetics and shouldn't inherit behaviour from the default plot specification, e.g. borders.

Details

These geoms are based on geom_text and geom_label. See the documentation for those functions for more details. Differences from those functions are noted here.

Text labels have height and width, but they are physical units, not data units. The amount of space they occupy on that plot is not constant in data units: when you resize a plot, labels stay the same size, but the size of the axes changes. The text labels are repositioned after resizing a plot.

geom_label_repel

Currently geom_label_repel does not support the rot argument and is considerably slower than geom_text_repel. The fill aesthetic controls the background colour of the label.

Alignment with hjust or vjust

The arguments hjust and vjust are supported, but they only control the initial positioning, so repulsive forces may disrupt alignment. Alignment with hjust will be preserved if labels only move up and down by using direction="y". For vjust, use direction="x".

Examples


p <- ggplot(mtcars,
  aes(wt, mpg, label = rownames(mtcars), colour = factor(cyl))) +
  geom_point()

# Avoid overlaps by repelling text labels
p + geom_text_repel()
# Labels with background
p + geom_label_repel()

## Not run: 
p + geom_text_repel(family = "Times New Roman",
  box.padding = 0.5)

# Add aesthetic mappings
p + geom_text_repel(aes(alpha=wt, size=mpg))
p + geom_label_repel(aes(fill=factor(cyl)), colour="white", segment.colour="black")

# Draw all line segments
p + geom_text_repel(min.segment.length = 0)

# Omit short line segments (default behavior)
p + geom_text_repel(min.segment.length = 0.5)

# Omit all line segments
p + geom_text_repel(segment.colour = NA)

# Repel just the labels and totally ignore the data points
p + geom_text_repel(point.size = NA)

# Hide some of the labels, but repel from all data points
mtcars$label <- rownames(mtcars)
mtcars$label[1:15] <- ""
p + geom_text_repel(data = mtcars, aes(wt, mpg, label = label))

# Nudge the starting positions
p + geom_text_repel(nudge_x = ifelse(mtcars$cyl == 6, 1, 0),
                    nudge_y = ifelse(mtcars$cyl == 6, 8, 0))

# Change the text size
p + geom_text_repel(aes(size = wt))
# Scale height of text, rather than sqrt(height)
p + geom_text_repel(aes(size = wt)) + scale_radius(range = c(3,6))

# You can display expressions by setting parse = TRUE.  The
# details of the display are described in ?plotmath, but note that
# geom_text_repel uses strings, not expressions.
p + geom_text_repel(aes(label = paste(wt, "^(", cyl, ")", sep = "")),
  parse = TRUE)

# Add a text annotation
p +
  geom_text_repel() +
  annotate(
    "text", label = "plot mpg vs. wt",
    x = 2, y = 15, size = 8, colour = "red"
  )

# Add arrows
p +
  geom_point(colour = "red") +
  geom_text_repel(
    arrow = arrow(length = unit(0.02, "npc")),
    box.padding = 1
  )


## End(Not run)

Nudge labels a fixed distance from points

Description

position_nudge_repel is useful for adjusting the starting position of text labels before they are repelled from data points.

Usage

position_nudge_repel(x = 0, y = 0)

Arguments

x, y

Amount of horizontal and vertical distance to move. Same units as the data on the x and y axes.

Examples


df <- data.frame(
  x = c(1,3,2,5),
  y = c("a","c","d","c")
)

ggplot(df, aes(x, y)) +
  geom_point() +
  geom_text_repel(aes(label = y))

ggplot(df, aes(x, y)) +
  geom_point() +
  geom_text_repel(
    aes(label = y),
    min.segment.length = 0,
    position = position_nudge_repel(x = 0.1, y = 0.15)
  )

# The values for x and y can be vectors
ggplot(df, aes(x, y)) +
  geom_point() +
  geom_text_repel(
    aes(label = y),
    min.segment.length = 0,
    position = position_nudge_repel(
      x = c(0.1, 0, -0.1, 0),
      y = c(0.1, 0.2, -0.1, -0.2)
    )
  )

# We can also use geom_text_repel() with arguments nudge_x, nudge_y
ggplot(df, aes(x, y)) +
  geom_point() +
  geom_text_repel(
    aes(label = y),
    min.segment.length = 0,
    nudge_x = 0.1,
    nudge_y = 0.15
  )

# The arguments nudge_x, nudge_y also accept vectors
ggplot(df, aes(x, y)) +
  geom_point() +
  geom_text_repel(
    aes(label = y),
    min.segment.length = 0,
    nudge_x = c(0.1, 0, -0.1, 0),
    nudge_y = c(0.1, 0.2, -0.1, -0.2)
  )