There are existing questions asking about labeling a single geom_abline()
in ggplot2
:
- R ggplot2: Labelling a horizontal line on the y axis with a numeric value
- R ggplot2: Labeling a horizontal line without associating the label with a series
- Add label to abline ggplot2 [duplicate]
None of these get at a use-case where I wanted to add multiple reference lines to a scatter plot, with the intent of allowing easy categorization of points within slope ranges. Here is a reproducible example of the plot:
library(ggplot2)
set.seed(123)
df <- data.frame(
x = runif(100, 0, 1),
y = runif(100, 0, 1))
lines <- data.frame(
intercept = rep(0, 5),
slope = c(0.1, 0.25, 0.5, 1, 2))
p <- ggplot(df, aes(x = x, y = y)) +
geom_point() +
geom_abline(aes(intercept = intercept, slope = slope),
linetype = "dashed", data = lines)
p
As I found no way to do this programmatically via the other questions, I "scaled" the manual approach via a data frame, using trial and error to figure out reasonable label positions.
labels <- data.frame(
x = c(rep(1, 3), 0.95, 0.47),
y = c(0.12, 0.28, 0.53, 1, 1),
label = lines$slope)
p + geom_text(aes(label = label), color = "red", data = labels)
Is there a better way than trial and error? While this wasn't too bad with 5 lines, I still had to redo my tweaking further upon export, as the plot aspect ratios and spacing were not the same between prototyping in an R session vs. the generated image. Programmatic labeling would be a huge help.
For some thoughts:
- I wondered if the parameter could be along a range of
c(0, 1)
, to correspond to the position along the line - could the min/max x/y positions be extracted from the
ggplot2
object internals (which I'm not familiar with) as a "cheat" for figuring out the position? Essentially if I know the pixel location of(0, intercept)
, I already know the slope, so for this example, I just need to know the pixel position ofmax(x)
ormax(y)
, depending on where we hit the perimeter - this struck me as similar to
ggrepel
, which figures out how to label points while trying to avoid overlaps
x = Inf
ory = -Inf
, the positions are translated to the xmax and ymin positions respectively. – teunbrand