Wrap long text in a text box

2019-05-25 21:10发布

I have the following reproducible coefficient plot.

library(tidyverse)
tribble(~term, ~estimate, ~lower, ~upper, ~text,
        "a", .25, .2, .3 , "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci vel dolor luctus auctor sed non lacus. Cras malesuada, tortor ac mattis rutrum, dui erat aliquam ipsum, id.",
        "b", -.25, -.3, -.2, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci vel dolor luctus auctor sed non lacus. Cras malesuada, tortor ac mattis rutrum, dui erat aliquam ipsum, id.",
        "intercept",0, -.1, .1, NA) %>% 
  ggplot(aes(y = term, x = estimate, label = text)) +
  geom_point() +
  ggrepel::geom_text_repel(size = 2, label.size = 0.1) +
  geom_errorbarh(aes(xmin = lower, xmax = upper), height = 0) +
  geom_vline(aes(xintercept = 0), linetype = "dashed") +
  theme_classic()

enter image description here

I would like the labels to be above the points and limited to a smaller xlim aka width. Is there a way to wrap text or generate some kind of text box in ggplot2 or ggrepel to make this functionality possible?

2条回答
Lonely孤独者°
2楼-- · 2019-05-25 22:01

You can use this dummy function that replaces space with \n every 50 characters.

library(tidyverse)
data <- tribble(~term, ~estimate, ~lower, ~upper, ~text,
        "a", .25, .2, .3 , "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci vel dolor luctus auctor sed non lacus. Cras malesuada, tortor ac mattis rutrum, dui erat aliquam ipsum, id.",
        "b", -.25, -.3, -.2, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci vel dolor luctus auctor sed non lacus. Cras malesuada, tortor ac mattis rutrum, dui erat aliquam ipsum, id.",
        "intercept",0, -.1, .1, "Lorem impsum")

data$textBreaks <- sapply(strsplit(data$text, " "), function(x) {
    spacePosition <- cumsum(nchar(x))
    placeBreak <- spacePosition[which(diff(spacePosition %/% 50) == 1)] + 1
    result <- paste(x, collapse = " ")
    for(i in placeBreak) {
        substring(result, i, i) <- "\n"
    }
    result
})
ggplot(data, aes(estimate, term,label = textBreaks)) +
    geom_point() +
    ggrepel::geom_text_repel(size = 2) +
    geom_errorbarh(aes(xmin = lower, xmax = upper), height = 0) +
    geom_vline(aes(xintercept = 0), linetype = "dashed") +
    theme_classic()

enter image description here

PS.: It won't work if there's only one long word (> 50 characters).

查看更多
Bombasti
3楼-- · 2019-05-25 22:02

Here is a custom function that you might use to insert line breaks after N chars (closest spaces will be replaced by the line break):

library(stringr)

wrap_text <- function(string, n) {
  spaces <- str_locate_all(string, " ")[[1]][,1]
  chars  <- nchar(string)
  for(i in 1:floor(chars/n)) {
    s <- spaces[which.min(abs(spaces - n*i))]
    substring(string, s, s) <- "\n "
  }
  return(string)
}

tribble(~term, ~estimate, ~lower, ~upper, ~text,
        "a", .25, .2, .3 , "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci vel dolor luctus auctor sed non lacus. Cras malesuada, tortor ac mattis rutrum, dui erat aliquam ipsum, id.",
        "b", -.25, -.3, -.2, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci vel dolor luctus auctor sed non lacus. Cras malesuada, tortor ac mattis rutrum, dui erat aliquam ipsum, id.",
        "intercept",0, -.1, .1, NA) %>% 
  ggplot(aes(y = term, x = estimate, label = I(wrap_text(text, nw = 30)))) +
  geom_point() +
  ggrepel::geom_text_repel(size = 2, label.size = 0.1) +
  geom_errorbarh(aes(xmin = lower, xmax = upper), height = 0) +
  geom_vline(aes(xintercept = 0), linetype = "dashed") +
  theme_classic()
查看更多
登录 后发表回答