Search code examples
rggplot2facet-wrap

Using facet_wrap in ggplot2, how can log and linear y-axis scales be mixed (with appropriate axis text)?


I'd like to make a facet_wrap plot with both linear- and and log-scale y-axes (on different facets), but obviously that isn't easily done.

Here's an example of the kind of dataset I'm working with:

library(tidyverse)

df <- tibble(TIME = rep(1:10, 2),
             PARAM = rep(c("A", "B"), each = 10),
             VAL = c(seq.int(1, 50, length.out = 10),
                     c(1000, 100, 1, 5, 1, 10, 5, 10, 100, 1000)),
             Y_INT = rep(c(NA, 10), each = 10))

And plotted on a linear scale:

ggplot(data = df, aes(x = TIME, y = VAL)) +
  geom_line() +
  geom_hline(aes(yintercept = Y_INT), linetype = 2, color = "gray50") +
  facet_wrap(~PARAM, ncol = 1, scales = "free_y")

Example 1: A faceted plot with linear scales

One solution is to manually put data on a log scale (here, PARAM B data):

df_log <- df |>
  mutate(VAL = ifelse(PARAM == "B", log10(VAL), VAL)) |>
  mutate(Y_INT = ifelse(PARAM == "B", log10(Y_INT), Y_INT))

ggplot(data = df_log, aes(x = TIME, y = VAL)) +
  geom_line() +
  geom_hline(aes(yintercept = Y_INT), linetype = 2, color = "gray50") +
  facet_wrap(~PARAM, ncol = 1, scales = "free_y")

Example 2: A plot with the correct scale on the log-scale facet, but with axis text that isn't readily understood

However, what I would like is something like this:

Example 3: A plot with linear and log y-axes, but made using a ggarrange function

I needed to use ggpubr::ggarrange to generate that image, and I'm trying to stick with facet_wrap.

So, the final question: how can linear and log y-axis scales be used in a single facet_wrap plot with appropriate axis text, as above?


Solution

  • You can use ggh4x::scale_y_facet() to have greater control over this. Disclaimer: I'm the author of ggh4x. There's no means to do a secondary axis title though.

    library(ggplot2)
    library(scales)
    
    df <- data.frame(TIME = rep(1:10, 2),
                     PARAM = rep(c("A", "B"), each = 10),
                     VAL = c(seq.int(1, 50, length.out = 10),
                             c(1000, 100, 1, 5, 1, 10, 5, 10, 100, 1000)),
                     Y_INT = rep(c(NA, 10), each = 10))
    
    ggplot(data = df, aes(x = TIME, y = VAL)) +
      geom_line() +
      geom_hline(aes(yintercept = Y_INT), linetype = 2, color = "gray50") +
      facet_wrap(~PARAM, ncol = 1, scales = "free_y") +
      ggh4x::scale_y_facet(
        PARAM == "B",
        trans  = "log10",
        breaks = breaks_log(),
        labels = label_log()
      )
    #> Warning: Removed 10 rows containing missing values or values outside the scale range
    #> (`geom_hline()`).
    

    Created on 2023-07-31 with reprex v2.0.2