Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I wrap facet labels in ggplot while retaining the variable name?

I am plotting a graph in ggplot with multiple facets. I want to wrap the facet labels and I know I can do this with the label_wrap_gen function, but this obscures the variable name and only shows the value. How can I wrap the label while still retaining the facet variable?

library(ggplot2)

# Create example data
df <- data.frame(x = rnorm(100), y = rnorm(100), 
     a = sample(c("Group 1", "Group 2"), 50, replace = TRUE),
     b = sample(c("Group 1", "Group 2"), 50, replace = TRUE))

label_wrap_gen wraps the labels:

# Create plot with facet wrap and custom labeller
ggplot(df, aes(x, y)) +
  geom_point() +
  facet_grid(a~b, labeller = label_wrap_gen(10))

label_both retains the variable names:

# Create plot with facet wrap and custom labeller
ggplot(df, aes(x, y)) +
  geom_point() +
  facet_grid(a~b, labeller = label_both)

Is there a solution that accomplishes both?

like image 877
jonnyf Avatar asked Sep 02 '25 14:09

jonnyf


2 Answers

I think there are two easy options: modify the labels so that they include the variable name; or craft a new function that combines the utility of label_both and label_wrap_gen.

I'll change the width= from 10 to 6 so that we see the effects.

Unchanged:

ggplot(df, aes(x, y)) +
  geom_point() +
  facet_grid(a~b, labeller = label_both)

ggplot2 original, both but not wrapped

Option 1: change the faceting variables

This is perhaps the simplest:

transform(df, a = paste("a:", a), b = paste("b:", b)) |>
  ggplot(aes(x, y)) +
  geom_point() +
  facet_grid(a~b, labeller = label_wrap_gen(6))

ggplot2, wrapped labels with both name and value

I used transform, one can use $<- or dplyr::mutate or one of several other ways to do it. This can be generalized so that it can be done programmatically, if needed. When doing something like this, I really prefer to do it inline as above, and not changing the data at-rest in df; doing the latter risks me applying them twice and/or having them present in post-plot renders (more plots, tables) where the combination is not desired. Doing this inline is a little "safer" in that regard.

Option 2: custom function

label_wrap_gen_both <- function(width = 25, multi_line = TRUE, sep = ": ") {
  fun <- function(labels) {
    value <- label_value(labels, multi_line = multi_line)
    variable <- ggplot2:::label_variable(labels, multi_line = multi_line)
    if (multi_line) {
        out <- vector("list", length(value))
        for (i in seq_along(out)) {
            out[[i]] <- paste(variable[[i]], value[[i]], sep = sep)
        }
    }
    else {
        value <- inject(paste(!!!value, sep = ", "))
        variable <- inject(paste(!!!variable, sep = ", "))
        out <- Map(paste, variable, value, sep = sep)
        out <- list(unname(unlist(out)))
    }
    lapply(out, function(st)
      vapply(strwrap(st, width = width, simplify = FALSE), paste, character(1), collapse = "\n"))
  }
  structure(fun, class = "labeller")
}

ggplot(df, aes(x, y)) +
  geom_point() +
  facet_grid(a~b, labeller = label_wrap_gen_both(6))

(same plot as above)

like image 137
r2evans Avatar answered Sep 05 '25 12:09

r2evans


Option3: via named character vector

# Set New facet label names for a variable
a.labs <- c("lab_a1", "lab_a2")
names(a.labs) <- c("Group 1", "Group 2")

# Set New facet label names for b variable
b.labs <- c("lab_1B!", "lab_2B!")
names(b.labs) <- c("Group 1", "Group 2")

ggplot(df, aes(x, y)) +
  geom_point() +
  facet_grid(a~b, labeller = labeller(a = a.labs, b = b.labs))

enter image description here

like image 35
Wael Avatar answered Sep 05 '25 13:09

Wael