Search code examples
rggplot2facet-grid

R and ggplot2: controlling scales in facet grid


I am plotting for a rowing boat the relation between cadence, speed, and going up- or down stream using facets in ggplot2:

enter image description here

library(tidyr)
library(ggplot2)

s <- function(d) ifelse(d < 500, "down", "up")

dist <- seq(1,1000)
cadence <- floor(25 + 7 * sin(dist/250))
speed <- 4+sin(dist/250)*2
stream <- s(dist)

df <- data.frame(dist,cadence,speed,stream)
g <- gather(df, variable, value, speed, cadence)

p <- ggplot(g, aes(dist, value)) +
    geom_line(aes(color=stream, group=1)) + 
    scale_x_continuous(name = "distance [m]") +
#    scale_y_continuous(sec.axis = sec_axis(~ (500/.),
#    name = "split [s/500m]",
#    breaks=c(90,95,100,105,110,115,120,125,130,140,150)),
#    limits=c(3.0,5.5),name="speed [m/s]") +
    facet_grid(variable ~ ., scales = "free_y")

I rely on scales="free_y" to get good automatic scaling of the Y axis. However, I would like to have more control and don't know how to achieve this:

  • I would like to limit each y axis individually, if possible
  • I would like to add a second y axis for the speed plot, showing a derived pace of time per 500m.

I know how to do this in individual plots but the facet grid makes sure the plots are properly aligned along the distance.


Solution

  • One option would be the ggh4x package which offers some options e.g. facetted_pos_scales to specify the scale individually for each facet and/or to add a secondary scale. Note however that we are still in the world of facets so you won't be able to set the the axis titles individually. To achieve that I would suggest to use patchwork.

    library(ggh4x)
    library(ggplot2)
    
    ggplot(g, aes(dist, value)) +
      geom_line(aes(color = stream, group = 1)) +
      scale_x_continuous(name = "distance [m]") +
      facet_grid(variable ~ ., scales = "free_y") +
      facetted_pos_scales(
        y = list(
          variable == "speed" ~ scale_y_continuous(
            limits = c(3, 5.5), name = "speed [m/s]",
            sec.axis = sec_axis(~ (500 / .), name = "split [s/500m]", breaks = c(90, 95, 100, 105, 110, 115, 120, 125, 130, 140, 150))
          )
        )
      ) +
      theme(strip.placement = "outside")
    

    enter image description here