3
votes

I need to create a multi-panel figure where the tick labels for the y-axis (factor) are italicized for some panels and plain text for other panels.

Here is a reproducible example, using made up data, of one thing I've tried:

library(ggplot2)
## Example data
df <- data.frame(var = c("Grass cover", "River depth", "Canis familiaris", "Canis lupus", "Canis latrans"), 
                 coef = c(0.6, 0.4, 0.8, 0.1, 0.5),
                 se = c(0.3, 0.4, 0.4, 0.05, 0.2),
                 panel = c(rep("Environment", 2), rep("Canid abundance", 3)))
## multi-panel plot
ggplot(df, aes(y = var, x = coef, xmin = coef - se, xmax = coef + se)) + 
  geom_pointrange() +
  facet_wrap(~ panel, scales = "free_y", ncol = 1) +
  labs(y = NULL) +
  theme(axis.text.y = element_text(face = c(rep("plain", 2), rep("italic", 3))))

multi-panel plot

Notice that only "Canis lupus" is italicized in the top panel. The desired figure would have all scientific names (y-axis labels) in the first panel be italics but labels in the bottom panel should be plain. In the real data, I have 4 panels, 2 of which need italics.

It appears that a vectorized face argument in element_text() is recycled between panels. I've also tried axis.text.y = element_text(face = rep("italic", 3), c(rep("plain", 2))) which results in all 5 y-axis labels being italicized.

If possible, I'd prefer not to use multiple ggplot objects (i.e., grid_arrange() or cowplot()). Though, I'm open to any solution that allows me to tweak all visual formatting elements.


I think there must be a solution using expression(), but I haven't been able to work it out.

2
If you're unable to find something native to ggplot2, you might consider the ggtree (github) package, which supports markdown in labels and such.r2evans

2 Answers

3
votes

Here is another option.

library(tidyverse)

df <- tibble(var = c("Grass cover", "River depth", "Canis familiaris", "Canis lupus", "Canis latrans"),
             coef = c(0.6, 0.4, 0.8, 0.1, 0.5),
             se = c(0.3, 0.4, 0.4, 0.05, 0.2),
             panel = c(rep("Environment", 2), rep("Canid abundance", 3)))

df %>%
  mutate(lab = map2_chr(var, panel, 
                        ~ifelse(.y == "Canid abundance", 
                                paste0('italic("', .x,'")'), 
                                paste0('"', .x,'"')))) %>%
  ggplot(aes(y = lab, x = coef, xmin = coef - se, xmax = coef + se)) + 
  geom_pointrange() +
  facet_wrap(~ panel, scales = "free_y", ncol = 1) +
  labs(y = NULL) +
  scale_y_discrete(label = function(x) parse(text = x))

2
votes

One option to achieve your desired result would be to make use of the ggtext package which allows for using markdown syntax and/or HTML/CSS to style labels and theme elements.

  1. Making use of theme(axis.text.y = ggtext::element_markdown()) the y axis labels will be parsed as markdown code.
  2. Wrap the labels to be shown in italic inside * ... *.
library(ggplot2)
library(ggtext)

df <- data.frame(var = c("Grass cover", "River depth", "Canis familiaris", "Canis lupus", "Canis latrans"), 
                 coef = c(0.6, 0.4, 0.8, 0.1, 0.5),
                 se = c(0.3, 0.4, 0.4, 0.05, 0.2),
                 panel = c(rep("Environment", 2), rep("Canid abundance", 3)))
df$var <- ifelse(df$panel %in% "Canid abundance", paste0("*", df$var, "*"), df$var)

## multi-panel plot
ggplot(df, aes(y = var, x = coef, xmin = coef - se, xmax = coef + se)) + 
  geom_pointrange() +
  facet_wrap(~ panel, scales = "free_y", ncol = 1) +
  labs(y = NULL) +
  theme(axis.text.y = ggtext::element_markdown())