Handle ggplot2 axis text face programmatically


#1

x-posted to Stack Overflow

Hi folks,

I'm wondering if it's possible to change the axis text in ggplot2 programatically or if there is some native way to do this in ggplot2. In this reprex, the idea is that I want to bold the axis text of a variable y that has an absolute value of x over 1.5. I can add it in manually via theme(), and that works fine.

library(ggplot2)
library(dplyr)
library(forcats)

set.seed(2939)
df <- data.frame(x = rnorm(15), y = paste0("y", 1:15), group = rep(1:3, 5))

df <- mutate(df, big_number = abs(x) > 1.5, 
                          face = ifelse(big_number, "bold", "plain"))

p <- ggplot(df, aes(x = x, y = fct_inorder(y), col = big_number)) + 
          geom_point() + 
          theme(axis.text.y = element_text(face = df$face))

p

But if I facet it by group, y gets reordered and ggplot2 has no idea how face is connected to df and thus y, so it just bolds in the same order as the first plot.

p + facet_grid(group ~ .)

And it's worse if I use a different scale for each.

p + facet_grid(group ~ ., scales = "free")

What do you think? Is there a general way to handle this that would work consistently here?

Thanks!
Malcolm


#2

Based on an answer from Stack Overflow user PoGibas:

bold_labels <- function(breaks) {
  big_nums <- filter(df, y %in% breaks) %>% pull(big_number)
  labels <- purrr::map2(breaks, big_nums, 
    ~if (.y)  bquote(bold(.(.x))) else bquote(plain(.(.x))))
  parse(text = labels)
}

ggplot(df, aes(x, fct_inorder(y), col = big_number)) + geom_point() + scale_y_discrete(labels = bold_labels) + 
  facet_grid(group ~ ., scales = "free")

I'm going to mark this as the solution for now because I think this might be as close as I can get to it being dynamic, but definitely open to a more robust solution!