2

(x-posted to community.rstudio.com)

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

Plot 1 with no facets Plot 1 with no facets

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

Plot 2 with facets Plot 2 with facets

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

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

Plot 3 with facets and different scales Plot 3 with facets and different scales

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

pogibas
  • 27,303
  • 19
  • 84
  • 117
  • Related: [ggplot2: Coloring axis text on a faceted plot](https://stackoverflow.com/questions/45843759/ggplot2-coloring-axis-text-on-a-faceted-plot) – pogibas Apr 07 '18 at 01:23

2 Answers2

1

Idea: Don't change theme, change y-axis labels. Create a call for every y with if/else condition and parse it with parse.

Not the most elegant solution (using for loop), but works (need loop as bquote doesn't work with ifelse). I always get confused when trying to work with multiple expressions (more on that here).

Code:

# Create data
library(tidyverse)
set.seed(2939)
df <- data.frame(x = rnorm(15), y = paste0("y", 1:15), group = rep(1:3, 5)) %>%
    mutate(yF = fct_inorder(y),
           big_number = abs(x) > 1.5)

# Expressions for y-axis
# ifelse doesn't work
# ifelse(df$big_number, bquote(bold(1)), bquote(plain(2)))
yExp <- c() # Ignore terrible way of concatenating 
for(i in 1:nrow(df)) {
    if (df$big_number[i]) {
        yExp <- c(yExp, bquote(bold(.(as.character(df$yF[i])))))
    } else {
        yExp <- c(yExp, bquote(plain(.(as.character(df$yF[i])))))
    }
}

# Plot with facets
ggplot(df, aes(x, yF, col = big_number)) + 
    geom_point() +
    scale_y_discrete(breaks = levels(df$yF), 
                     labels = parse(text = yExp)) +
    facet_grid(group ~ ., scales = "free")

Result:

enter image description here

pogibas
  • 27,303
  • 19
  • 84
  • 117
  • Interesting! I tried a similar approach where I used a function in labels to process it. I think using scale labels might be as close as this can get. – Malcolm Barrett Apr 07 '18 at 17:02
0

Inspired by @PoGibas, I also used a function in scale_y_discrete(), which works, too.

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")