Some text labels overlap each other in plots created with geom_text:
library(ggplot2)
ggplot(mtcars) +
geom_point(aes(wt, mpg), color = 'red') +
geom_text(aes(wt, mpg, label = rownames(mtcars))) +
theme_classic(base_size = 16)
ggrepel
implements functions to repel overlapping text labels away from each other and away from the data points that they label. The algorithm works as follows:
We can repel the text labels away from each other by loading ggrepel
and using geom_text_repel
instead:
library(ggrepel)
set.seed(42)
ggplot(mtcars) +
geom_point(aes(wt, mpg), color = 'red') +
geom_text_repel(aes(wt, mpg, label = rownames(mtcars))) +
theme_classic(base_size = 16)
geom_label_repel
is based on geom_label.
set.seed(42)
ggplot(mtcars) +
geom_point(aes(wt, mpg), size = 5, color = 'grey') +
geom_label_repel(
aes(wt, mpg, fill = factor(cyl), label = rownames(mtcars)),
fontface = 'bold', color = 'white',
box.padding = 0.35, point.padding = 0.5,
segment.color = 'grey50'
) +
theme_classic(base_size = 16)
All options available for geom_text such as size
, angle
, family
, fontface
are also available for geom_text_repel
.
However, the following parameters are not supported:
hjust
vjust
position
check_overlap
ggrepel
provides additional parameters for geom_text_repel
and geom_label_repel
:
segment.color
is the line segment colorsegment.size
is the line segment thicknesssegment.alpha
is the line segment transparencybox.padding
is the padding surrounding the text bounding boxpoint.padding
is the padding around the labeled pointarrow
is the specification for arrow heads created by grid::arrow
force
is the force of repulsion between overlapping text labelsmax.iter
is the maximum number of iterations to attempt to resolve overlapsnudge_x
is how much to shift the starting position of the text label along the x axisnudge_y
is how much to shift the starting position of the text label along the y axisdirection
is what direction to allow movement of the label, either “both” (default), “x”, or “y”Here is an example that uses most of these options:
set.seed(42)
ggplot(mtcars) +
geom_point(aes(wt, mpg, color = factor(cyl)), size = 3) +
geom_text_repel(
aes(
wt, mpg,
color = factor(cyl),
label = rownames(mtcars),
# Cars with 4 cylinders are rotated 90 degrees.
angle = ifelse(mtcars$cyl == 4, 90, 0)
),
size = 4,
family = 'Times',
fontface = 'bold',
# Add extra padding around each text label.
box.padding = 0.5,
# Add extra padding around each data point.
point.padding = 1.6,
# Color of the line segments.
segment.color = '#cccccc',
# Width of the line segments.
segment.size = 0.5,
# Draw an arrow from the label to the data point.
arrow = arrow(length = unit(0.01, 'npc')),
# Strength of the repulsion force.
force = 1,
# Maximum iterations of the naive repulsion algorithm O(n^2).
max.iter = 3e3,
# Cars with 6 cylinders are nudged up and to the right.
nudge_x = ifelse(mtcars$cyl == 6, 2, 0),
nudge_y = ifelse(mtcars$cyl == 6, 9, 0)
) +
scale_color_discrete(name = 'cyl') +
scale_x_continuous(expand = c(0.5, 0)) +
scale_y_continuous(expand = c(0.25, 0)) +
theme_classic(base_size = 16)
Set point.padding = NA
to exclude all data points from repulsion calculations.
set.seed(42)
mtcars$label <- rownames(mtcars)
ggplot(mtcars, aes(wt, mpg, label = label)) +
geom_point(color = "red") +
geom_text_repel(point.padding = NA) +
theme_bw(base_size = 16)
Set some labels to the empty string ""
to hide them. All data points will still repel the remaining labels.
set.seed(42)
mtcars$label <- rownames(mtcars)
mtcars$label[1:15] <- ""
ggplot(mtcars, aes(wt, mpg)) +
geom_point(aes(color = factor(cyl)), size = 2) +
geom_text_repel(
aes(
color = factor(cyl),
size = hp,
label = label
),
point.padding = 0.25,
box.padding = 0.25,
nudge_y = 0.1
) +
theme_bw(base_size = 16)
Use xlim
and ylim
to constrain the labels to a specific area. Limits are specified in data coordinates. Use NA
when there is no lower or upper bound in a particular direction.
set.seed(42)
data <- mtcars
mu <- mean(data$wt)
left <- data[data$wt < mu,]
right <- data[data$wt >= mu,]
ggplot() +
geom_vline(xintercept = mu) +
geom_point(
data = data,
mapping = aes(wt, mpg)
) +
geom_text_repel(
data = left,
mapping = aes(wt, mpg, label = rownames(left), colour = 'Left half'),
# Limit labels to the left of the vertical x=mu line
xlim = c(NA, mu)
) +
geom_text_repel(
data = right,
mapping = aes(wt, mpg, label = rownames(right), colour = 'Right half'),
# Limit labels to the right of the vertical x=mu line
xlim = c(mu, NA)
) +
theme_classic(base_size = 16)
Use direction
to limit label movement to the x-axis (left and right) or y-axis (up and down). The options are “both” (default), “x”, or “y”.
set.seed(42)
ggplot(mtcars) +
geom_point(aes(wt, mpg), color = 'red') +
geom_text_repel(aes(wt, mpg, label = rownames(mtcars)), direction = "x") +
theme_classic(base_size = 16) + xlim(1,6)
Setting direction
to “y”:
set.seed(42)
ggplot(mtcars) +
geom_point(aes(wt, mpg), color = 'red') +
geom_text_repel(aes(wt, mpg, label = rownames(mtcars)), direction = "y") +
theme_classic(base_size = 16)
set.seed(42)
ggplot(Orange, aes(age, circumference, color = Tree)) +
geom_line() +
coord_cartesian(xlim = c(min(Orange$age), max(Orange$age) + 90)) +
geom_text_repel(
data = subset(Orange, age == max(age)),
aes(label = paste("Tree", Tree)),
size = 6,
nudge_x = 45,
segment.color = NA
) +
theme_classic(base_size = 16) +
theme(legend.position = "none") +
labs(title = "Orange Trees", x = "Age (days)", y = "Circumference (mm)")
set.seed(42)
# Read Stephen Turner's data
genes <- read.table("genes.txt.bz2", header = TRUE)
genes$Significant <- ifelse(genes$padj < 0.05, "FDR < 0.05", "Not Sig")
ggplot(genes, aes(x = log2FoldChange, y = -log10(pvalue))) +
geom_point(aes(color = Significant)) +
scale_color_manual(values = c("red", "grey")) +
theme_bw(base_size = 16) +
geom_text_repel(
data = subset(genes, padj < 0.05),
aes(label = Gene),
size = 5,
box.padding = 0.25,
point.padding = 0.3
)
ggsave("figures/ggrepel/volcano-1.png", width = 12, height = 8, dpi = 84)
set.seed(42)
mtcars$label <- rownames(mtcars)
mtcars$label[mtcars$mpg < 25] <- ""
ggplot(mtcars, aes(x = wt, y = mpg, label = label)) +
coord_polar(theta = "x") +
geom_point(aes(color = factor(cyl)), size = 2) +
geom_text_repel(
aes(
color = factor(cyl)
),
point.padding = 0.25,
box.padding = 0.25,
nudge_y = 0.1
) +
theme_bw(base_size = 16)
library(gridExtra)
set.seed(0)
d <- data.frame(
x = runif(30),
y = runif(30),
Parameter = c(
"prod(plain(P)(X == x), x)",
"integral(f(x) * dx, a, b)",
"lim(f(x), x %->% 0)",
rep("", 27)
)
)
p1 <- ggplot(d, aes(x, y, label = Parameter)) +
geom_point() +
geom_text_repel(
parse = TRUE, size = 8,
min.segment.length = 0,
point.padding = 0.5,
box.padding = 0.5
) +
theme_classic(base_size = 20)
p2 <- ggplot(d, aes(x, y, label = Parameter)) +
geom_point() +
geom_label_repel(parse = TRUE, size = 8, alpha = 0.5) +
theme_classic(base_size = 20)
grid.arrange(p1, p2, ncol = 2)
# This chunk of code will take a minute or two to run.
library(ggrepel)
library(animation)
plot_frame <- function(n) {
set.seed(42)
p <- ggplot(mtcars) +
geom_point(aes(wt, mpg), color = 'red') +
geom_text_repel(
aes(wt, mpg, label = rownames(mtcars)),
size = 5, force = 3, max.iter = n
) +
theme_classic(base_size = 16)
print(p)
}
saveGIF(
lapply(ceiling(1.75^(1:12)), function(i) {
plot_frame(i)
}),
interval = 0.20,
ani.width = 800,
ani.heigth = 600,
movie.name = 'animated.gif'
)
devtools::session_info()
## setting value
## version R version 3.4.0 (2017-04-21)
## system x86_64, darwin15.6.0
## ui X11
## language (EN)
## collate en_US.UTF-8
## tz America/New_York
## date 2017-09-28
##
## package * version date source
## base * 3.4.0 2017-04-21 local
## codetools 0.2-15 2016-10-05 CRAN (R 3.4.0)
## colorspace 1.3-2 2016-12-14 CRAN (R 3.4.0)
## compiler 3.4.0 2017-04-21 local
## datasets * 3.4.0 2017-04-21 local
## devtools 1.13.0 2017-05-08 CRAN (R 3.4.0)
## digest 0.6.12 2017-01-27 CRAN (R 3.4.0)
## evaluate 0.10 2016-10-11 CRAN (R 3.4.0)
## ggplot2 * 2.2.1 2016-12-30 CRAN (R 3.4.0)
## ggrepel * 0.7.0 2017-09-28 local
## graphics * 3.4.0 2017-04-21 local
## grDevices * 3.4.0 2017-04-21 local
## grid 3.4.0 2017-04-21 local
## gridExtra * 2.2.1 2016-02-29 CRAN (R 3.4.0)
## gtable 0.2.0 2016-02-26 CRAN (R 3.4.0)
## highr 0.6 2016-05-09 CRAN (R 3.4.0)
## knitr * 1.15.1 2016-11-22 CRAN (R 3.4.0)
## labeling 0.3 2014-08-23 CRAN (R 3.4.0)
## lazyeval 0.2.0 2016-06-12 CRAN (R 3.4.0)
## magrittr 1.5 2014-11-22 CRAN (R 3.4.0)
## memoise 1.1.0 2017-04-21 CRAN (R 3.4.0)
## methods * 3.4.0 2017-04-21 local
## munsell 0.4.3 2016-02-13 CRAN (R 3.4.0)
## plyr 1.8.4 2016-06-08 CRAN (R 3.4.0)
## Rcpp 0.12.12 2017-07-15 CRAN (R 3.4.1)
## scales 0.4.1 2016-11-09 CRAN (R 3.4.0)
## stats * 3.4.0 2017-04-21 local
## stringi 1.1.5 2017-04-07 CRAN (R 3.4.0)
## stringr 1.2.0 2017-02-18 CRAN (R 3.4.0)
## tibble 1.3.0 2017-04-01 CRAN (R 3.4.0)
## tools 3.4.0 2017-04-21 local
## utils * 3.4.0 2017-04-21 local
## withr 1.0.2 2016-06-20 CRAN (R 3.4.0)