R: How to wrap character columns to print to 2 lines in ggplot, but they're NOT titles?

78 Views Asked by At

There are myriad similar questions for splitting character strings to 2 lines with \n and cat (e.g.), paste (e.g.), strwrap (e.g.), and writeLines (e.g.). But all of these either anticipate the output being explicitly printed immediately thereafter, or printing will happen automatically by plot/ggplot; in the latter case, examples typically relate to (axis) titles.

I've created an alluvial plot which creates the following plot:

Alluvial

From the following post-processed table of data:

table

I'm trying to force certain cells in "FnGpRealm" and "Effect Type" columns to wrap to two lines. An example of the various similar approached I've tried (relevant code chunk only):

dplyr::mutate(FnGpRealm = stringr::str_replace_all(string = FnGpRealm,
                                                            pattern = "Ma: Inshore/Shelf",
                                                            replacement = paste0("Ma:", "\n", "Inshore/Shelf"))

I've also tried "Ma:\nInshore/Shelf" as the replacement, used "/n" as the collapse in a paste, wrapped writeLines around the whole str_replace_all block... all to no avail. If I try to print / writeLines the column onto itself after adding the /n, it kills the column completely:

tmp$FnGpRealm

1 "Ma:\nInshore/Shelf"

tmp$FnGpRealm <- writeLines(tmp$FnGpRealm)

tmp$FnGpRealm

NULL. Warning message: Unknown or uninitialised column: FnGpRealm.

Based on the extent to which I understand how \n works in all of this, it seems character strings with regex special characters like \n get autochecked by some functions (cat, paste, writeLines), probably also within (gg)plot calls, which then wrap them to multiple lines when detected. But since ggalluvial populates its elements using character cells which evidently aren't autochecked the same way... is there a way to wrap those strings within the column natively? So when ggalluvial prints them, they're already wrapped? Or is this not a thing?

My fallback is just to rename stuff shorter like I already did with macro/mesopredator to Ma/Me. But that kinda sucks.

Thanks in advance!

edit: dput(head(df)) output:

structure(list(Effect Type = structure(c(1L, 1L, 2L, 2L, 2L, 3L), levels = c("Top-down: Direct Predation", "Top-down: Risk Effects", "Top-down: Trophic Cascade", "Competition", "BU:NVS:SAF", "BU:NVS:EAE" ), class = c("ordered", "factor")), Effect Size = structure(c(1L, 2L, 1L, 2L, 3L, 1L), levels = c("3", "2", "1"), class = c("ordered", "factor")), Count = c(16L, 8L, 32L, 11L, 2L, 17L)), class = c("grouped_df", "tbl_df", "tbl", "data.frame"), row.names = c(NA, -6L), groups = structure(list( Effect Type = structure(1:3, levels = c("Top-down: Direct Predation", "Top-down: Risk Effects", "Top-down: Trophic Cascade", "Competition", "BU:NVS:SAF", "BU:NVS:EAE"), class = c("ordered", "factor" )), .rows = structure(list(1:2, 3:5, 6L), ptype = integer(0), class = c("vctrs_list_of", "vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame" ), row.names = c(NA, -3L), .drop = TRUE))

2

There are 2 best solutions below

0
On BEST ANSWER

I think stringr::str_wrap directly inside aes when specifying the label aesthetic should be fine:

library(ggalluvial)

ggplot(data = data,
       aes(axis1 = FnGpRealm, axis2 = EffectType, y = Count)) +
  geom_alluvium(aes(fill = factor(EffectSize)), alpha = 0.7) +
  geom_stratum(fill = 'white') +
  geom_text(stat = "stratum",
            aes(label = stringr::str_wrap(after_stat(stratum), 12))) +
  scale_x_discrete(expand = c(0.15, 0.05)) +
  scale_fill_manual('Effect\nSize',
                    values = c('3' = '#55b69a', '2' = '#9894c6', 
                               '1' = '#e38642')) +
  theme(axis.line.y = element_line(),
        panel.background = element_blank(),
        legend.position = c(0.2, 0.8))

enter image description here


Data OCR'd from table in OP

data <- structure(list(FnGpRealm = c("Ma: Inshore/Shelf", "Ma: Inshore/Shelf", 
"Ma: Inshore/Shelf", "Ma: Inshore/Shelf", "Ma: Inshore/Shelf", 
"Ma: Inshore/Shelf", "Ma: Inshore/Shelf", "Ma: Inshore/Shelf", 
"Ma: Inshore/Shelf", "Ma: Inshore/Shelf", "Ma: Inshore/Shelf", 
"Ma: Inshore/Shelf", "Ma: Pelagic", "Ma: Pelagic", "Me: Inshore/Shelf", 
"Me: Inshore/Shelf", "Me: Inshore/Shelf", "Me: Inshore/Shelf", 
"Me: Inshore/Shelf", "Me: Inshore/Shelf", "Me: Inshore/Shelf", 
"Me: Inshore/Shelf", "Me: Inshore/Shelf", "Me: Inshore/Shelf", 
"Me: Inshore/Shelf", "Me: Inshore/Shelf", "Me: Inshore/Shelf", 
"Me: Inshore/Shelf", "Me: Inshore/Shelf", "Me: Inshore/Shelf", 
"Me: Pelagic", "Me: Pelagic", "Me: Pelagic", "Me: Pelagic"), 
    EffectType = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 3L, 3L, 
    4L, 5L, 5L, 6L, 1L, 3L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 
    4L, 4L, 4L, 5L, 5L, 6L, 1L, 1L, 3L, 4L, 4L), .Label = c("Top-down: Direct Predation", 
    "Top-down: Risk Effects", "Top-down: Trophic Cascade", "Competition", 
    "BU:NVS:SAF", "BU:NVS:EAE"), class = "factor"), EffectSize = c(3L, 
    2L, 3L, 1L, 3L, 2L, 1L, 1L, 3L, 2L, 1L, 3L, 3L, 3L, 3L, 2L, 
    1L, 3L, 2L, 1L, 3L, 2L, 1L, 3L, 1L, 1L, 1L, 1L, 3L, 3L, 2L, 
    3L, 3L, 2L), Count = c(16L, 8L, 32L, 11L, 2L, 17L, 4L, 4L, 
    1L, 1L, 2L, 1L, 1L, 4L, 2L, 3L, 6L, 4L, 1L, 1L, 4L, 2L, 1L, 
    1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 1L)), row.names = c(NA, 
-34L), class = "data.frame")
2
On

In your question you refer to "/n" - is this a typo? The newline character is "\n" (back slash, not forward slash) - is this what's causing the issue?

Also, I tried but wasn't able to reproduce this problem on my system:

library(tidyverse)
library(palmerpenguins)
library(ggalluvial)

penguins %>%
  na.omit() %>%
  mutate(species = if_else(species == "Adelie", "Some other\nlong name\nfor 'Adelie'", species)) %>%
  pivot_wider(id_cols = c(species, island, year),
              names_from = sex,
              values_from = body_mass_g,
              values_fn = sum) %>%
  ggplot(aes(axis1 = species,
             axis2 = island,
             y = female)) +
  geom_alluvium(aes(fill = factor(year))) +
  geom_stratum() +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)))

Created on 2023-11-30 with reprex v2.0.2