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