As far as I can see ggplot2
knows the dimensions of labels plotted by geom_text
. Otherwise the check_overlap
option would not work.
Where are these dimensions stored and how can I access them?
Illustrative example
library(ggplot2)
df <- data.frame(x = c(1, 2),
y = c(1, 1),
label = c("label-one-that-might-overlap-another-label",
"label-two-that-might-overlap-another-label"),
stringsAsFactors = FALSE)
With check_overlap = FALSE
(the default), the labels overplot each other.
ggplot(df, aes(x, y)) +
geom_text(aes(label = label)) +
xlim(0, 3)
With check_overlap = TRUE
, the second label is not plotted, because ggplot
finds an overlap.
ggplot(df, aes(x, y)) +
geom_text(aes(label = label), check_overlap = TRUE) +
xlim(0, 3)
How does ggplot2
know that those labels overlap? How can I access that information?
Method 1: Using geom_text() This method is used to add Text labels to data points in ggplot2 plots.
geom_text.Rd. Text geoms are useful for labeling plots. They can be used by themselves as scatterplots or in combination with other geoms, for example, for labeling points or for annotating the height of bars. geom_text() adds only text to the plot.
The default font size of geom_text() is 3.88. You can change the size using the size argument in geom_text() for a single plot.
To alter the labels on the axis, add the code +labs(y= "y axis name", x = "x axis name") to your line of basic ggplot code. Note: You can also use +labs(title = "Title") which is equivalent to ggtitle .
Text in the grid package doesn't really have a size until it is time to draw the text. Below, we'll make a helper function to measure text, but it doesn't really make any sense to do this unless you know the device and size of the plotting area in advance. (For those in the know, during the makeContent()
stage of drawing).
library(grid)
label <- c("label-one-that-might-overlap-another-label",
"label-two-that-might-overlap-another-label")
measure_size <- function(txt, gp = gpar(), to = "mm") {
if (is.grob(txt)) {
grobs <- lapply(seq_along(txt$label), function(i) {
g <- txt
# Subset grob per label
g$label <- g$label[[i]]
g$gp[] <- lapply(g$gp, function(x) {x[pmin(i, length(x))]})
g$rot <- g$rot[pmin(i, length(g$rot))]
g
})
} else {
grobs <- lapply(txt, function(t) textGrob(t, gp = gp))
}
heights <- do.call(unit.c, lapply(grobs, grobHeight))
widths <- do.call(unit.c, lapply(grobs, grobWidth))
cbind(
height = convertHeight(heights, to, valueOnly = TRUE),
weight = convertWidth(widths, to, valueOnly = TRUE)
)
}
We can now try to guess the size of the text as best as we can, but as one might expect, it depends a lot on graphical parameters of text what the actual size is. Notice for example that changing the font also changes the size of the text.
measure_size(label)
#> height weight
#> [1,] 3.175 79.13109
#> [2,] 3.175 78.65566
measure_size(label, gp = gpar(fontfamily = "Garamond"))
#> height weight
#> [1,] 2.645833 69.67223
#> [2,] 2.645833 69.69704
Now applying the same trick to ggplot2's text layer.
library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.1.1
df <- data.frame(x = c(1, 2),
y = c(1, 1),
label = label)
p <- ggplot(df, aes(x, y)) +
geom_text(aes(label = label)) +
xlim(0, 3)
textgrob <- layer_grob(p)[[1]]
measure_size(textgrob)
#> height weight
#> [1,] 2.645979 72.83233
#> [2,] 2.645979 72.39411
Created on 2021-12-13 by the reprex package (v2.0.1)
I worked a lot with text recently myself and found that the {systemfonts}/{textshaping} packages accurately return the size of the text in pixels, which is of course device/resolution dependent.
systemfonts::string_width("My label")
#> [1] 46
textshaping::text_width("My label")
#> [1] 46
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With