Consider a plot with a segment/line and a text/label. I'd like the text to overlay the segment such that the text does not overlap the segment.
I tried using geom_label
but I still want the background to be the same, just the other objects to be removed around the text. I also tried with geomtextpath
but couldn't get the text to be horizontal. Any ideas?
seg <- data.frame(x = 1, xend = 1, y = 2, yend = 3)
plot1 <- ggplot(seg)
aes(x = x, xend = xend, y = y, yend = yend)
geom_segment()
geom_text(aes(y = (y yend) / 2), label = "Hello", size = 10)
labs(title = "geom_text",
subtitle = "The text is horizontal but the segment should\nbe cut around the text.")
library(geomtextpath)
plot2 <- ggplot(seg)
aes(x = x, xend = xend, y = y, yend = yend)
geom_textsegment(label = "Hello", size = 10)
labs(title = "geomtextpath",
subtitle = "The segment is correctly overlaid but\nI need the text to be horizontal")
seg2 <- data.frame(x = c(1, 1), xend = c(1, 1), y = c(2, 2.55), yend = c(2.45, 3))
plot3 <- ggplot(seg2)
aes(x = x, xend = xend, y = y, yend = yend)
geom_segment()
geom_text(aes(y = 2.5), label = "Hello", size = 10)
labs(title = "manual geom_segment",
subtitle = "This is the expected output, but it is done\nmanually. I need a scalable solution.")
library(patchwork)
plot1 plot2 plot3
CodePudding user response:
I wouldn't say the following is 'easy', but you can use the {ggfx} package to put an inverted mask on the segment that corresponds with a textbox.
library(ggplot2)
library(ggfx)
seg <- data.frame(x = 1, xend = 1, y = 2, yend = 3)
ggplot(seg)
aes(x = x, xend = xend, y = y, yend = yend)
# Adding a label-textbox as mask ensures appropriate window-agnostic size
# Just make sure the aesthetics are the same as the geom_text later
as_reference(
geom_label(aes(y = (y yend) / 2), label = "Hello", size = 10),
id = "textbox"
)
# Plot the masked bit
with_mask(
geom_segment(),
mask = ch_alpha("textbox"), invert = TRUE
)
# On top of the mask
geom_text(aes(y = (y yend) / 2), label = "Hello", size = 10)
Created on 2022-10-14 by the reprex package (v2.0.1)
CodePudding user response:
An option could be using ggplot_build
to modify the distance of your geom_segment
by creating two separate segments like this:
seg <- data.frame(x = 1, xend = 1, y = 2, yend = 3)
library(ggplot2)
library(dplyr)
p <- ggplot(seg)
aes(x = x, xend = xend, y = y, yend = yend)
geom_segment()
geom_text(aes(y = (y yend) / 2), label = "Hello", size = 10)
q <- ggplot_build(p)
q$data[[1]] <- q$data[[1]] %>%
bind_rows(q$data[[1]]) %>%
mutate(y = c(2, 2.55),
yend = c(2.45, 3))
q <- ggplot_gtable(q)
plot(q)
Created on 2022-10-15 with reprex v2.0.2