I am trying to label my facet_wrap titles based on an aggregation of data in my data frame.
I am writing a function to plot different data sets, so I am using a function argument to select the column I want to facet by. In this case, I want to create facets for each unique class in broad
but I want the facet label to include the sum of all percBackground
values for each broad
category.
I have tried using the rlang {{}}
with little success (or understanding).
data.test <- data.frame(broad = c("A", "A", "A", "B", "B", "C", "C", "C", "C"),
detail = c("a", "b", "c", "d", "e", "f", "g", "h", "i"),
sr.Summer = c(12, 23, 32, 12, 12, 11, 14, 15, 18),
percBackground = c(1.5, 4.3, 3.4, 4.6, 3.4, 4.1, 3.9, 2.9, 1.8))
func.test <- function(data, facet.by){
aggr <- data %>% aggregate(percBackground ~ facet.by, FUN = sum) %>%
mutate(label = paste0(facet.by, " - ", round(percBackground, digits = 2), "%"))
facet_label <- aggr$label
names(facet_label) <- unique(facet_label)
ggplot(data = data, aes(x = detail)) +
geom_point(aes(y = sr.Summer)) +
facet_wrap(~facet.by, labeller = labeller(facet.by = facet_label))
}
func.test(data = data.test,
facet.by = broad)
> Error in eval(predvars, data, env) : object 'broad' not found
13. eval(predvars, data, env)
12. eval(predvars, data, env)
11. model.frame.default(formula = by, data = x)
10. stats::model.frame(formula = by, data = x)
9. eval(m, parent.frame())
8. eval(m, parent.frame())
7. aggregate.formula(x = by, data = x, FUN = FUN, ...)
6. aggregate.data.frame(., percBackground ~ facet.by, FUN = sum)
5. aggregate(., percBackground ~ facet.by, FUN = sum)
4. aggregate(., percBackground ~ facet.by, FUN = sum)
3. mutate(., label = paste0(facet.by, " - ", round(percBackground,
digits = 2), "%"))
2. data %>% aggregate(percBackground ~ facet.by, FUN = sum) %>%
mutate(label = paste0(facet.by, " - ", round(percBackground,
digits = 2), "%"))
1. func.test(data.test, broad)
One issue with using {{
is that it will not work with aggregate
, i.e. switch to dplyr::summarise
. Second, when using curly-curly {{
in facet_wrap
you have to wrap in vars()
. Third, to get the named vector of facet labels I use tibble::deframe
and finally, to pass assign the labels via labeller
I pass it to the .cols
argument (.rows
will also work fine for facet_wrap
:
library(ggplot2)
library(dplyr, warn = FALSE)
func.test <- function(data, facet.by) {
aggr <- data %>%
summarise(percBackground = sum(percBackground), .by = {{ facet.by }}) %>%
mutate(label = paste0({{ facet.by }}, " - ", round(percBackground, digits = 2), "%"))
facet_label <- aggr |>
select({{ facet.by }}, label) |>
tibble::deframe()
ggplot(data = data, aes(x = broad)) +
stat_summary(fun = "mean", geom = "point", aes(y = sr.Summer)) +
facet_wrap(vars({{ facet.by }}), labeller = labeller(.cols = facet_label))
}
func.test(
data = data.test,
facet.by = broad
)
A second option which allows to stick with standard evaluation for most of the code would be add a new column to your dataset, which you could name e.g. facet
or whatever. After doing so you use this name for the rest of your code without the of using {{
, vars()
or .rows
:
func.test <- function(data, facet.by) {
data <- data |>
mutate(facet = {{facet.by}})
aggr <- data %>%
summarise(percBackground = sum(percBackground), .by = facet) %>%
mutate(label = paste0(facet, " - ", round(percBackground, digits = 2), "%"))
facet_label <- aggr |>
select(facet, label) |>
tibble::deframe()
ggplot(data = data, aes(x = broad)) +
stat_summary(fun = "mean", geom = "point", aes(y = sr.Summer)) +
facet_wrap(~facet, labeller = labeller(facet = facet_label))
}
func.test(
data = data.test,
facet.by = broad
)