Create a function that insert a line break between every letter of a character variable in R

Viewed 112

What I want: to create a function to insert a line break between every letter of a character variable in R.

What I tried: but it didn't work

wrap_letters <- function(x){ 
  z <- substring(x, 1, 1) # Take the first letter of x and save it in z
  for(i in 2:stri_length(x)) { #from the second to the length of x
  w  <- substring(x, i, 1)  #take the respective letter and save it to w
  z <- paste0(z,"\n",  w) #paste z, "\n", w
  }
 z #return z
}

Reproducible example with data (using ToothGrowth that comes within R):

df <- ToothGrowth %>%
   mutate(dose = factor(dose),
          supp = case_when(
             supp=="OJ" ~ "orange juice", 
             T ~ "ascorbic acid"),
          supp_label = wrap_letters(supp))

Aplication: to vertically write labels in a facet_grid plot: I want to rotate letters to normal position (i.e. horizontal), but to place letters below each other, so they don't take too much width:

bp <- ggplot(df, aes(x=dose, y=len, group=dose)) + 
   geom_boxplot(aes(fill=dose)) +
   theme(
      strip.text.y = element_text(angle = 0)
   ) +
   facet_grid(supp_label ~ dose)
bp

Desired result:

df <- ToothGrowth %>%
   mutate(dose = factor(dose),
          supp_label = case_when(
             supp=="OJ" ~ "o\nr\na\nn\ng\ne\n \nj\nu\ni\nc\ne", 
             T ~ "a\ns\nc\no\nr\nb\ni\nc\n \na\nc\ni\nd"))

bp <- ggplot(df, aes(x=dose, y=len, group=dose)) + 
   geom_boxplot(aes(fill=dose)) +
   scale_y_continuous(position = "right") +
   facet_grid(supp_label ~ dose, switch = "y") +
   theme(
      strip.text.y.left = element_text(angle = 0, size = 12, face = "bold"), 
      strip.text.x = element_text(angle = 0, size = 12, face = "bold")
   )
bp

Note: This is a small reproducible example, I have more categories in my dataframe and I want to make everything reproducible, that is why I need a function.

enter image description here

2 Answers

wrap_letters can be written as :

wrap_letters <- function(x) {
  sapply(strsplit(x, ''), paste0, collapse = '\n')
}

You can pass a vector to it and plot.

library(dplyr)
library(ggplot2)

ToothGrowth %>%
  mutate(dose = factor(dose),
         supp = case_when(supp=="OJ" ~ "orange juice", 
                          TRUE ~ "ascorbic acid"),
         supp_label = wrap_letters(supp)) %>%
  ggplot(aes(x=dose, y=len, group=dose)) + 
  geom_boxplot(aes(fill=dose)) +
  theme(strip.text.y = element_text(angle = 0)) +
  facet_grid(supp_label ~ dose)

enter image description here

We could use a regex method to do this

library(dplyr)
library(stringr)
library(ggplot2)
wrap_letters <- function(x) {
      stringr::str_replace_all(x, "(?<=.)(?=.)", "\n")
      # or use gsub from base R
      # gsub("(?<=.)(?=.)", "\n", x)

}

Now, use the function

ToothGrowth %>%
 mutate(dose = factor(dose),
     supp = case_when(supp=="OJ" ~ "orange juice", 
                      TRUE ~ "ascorbic acid"),
     supp_label =  wrap_letters(supp)) %>%
     ggplot(aes(x=dose, y=len, group=dose)) + 
       geom_boxplot(aes(fill=dose)) +
       theme(strip.text.y = element_text(angle = 0)) +
       facet_grid(supp_label ~ dose)

-output

enter image description here

Related