Search code examples
rggplot2ggrepel

Wrap long text in a text box


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?


Solution

  • 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).