Custom y-axis scale and secondary y-axis labels in ggplot2 3.1.0

Here is a solution that works with ggplot2 version 3.1.0 using sec_axis(), and which only requires creating a single plot. We still use sec_axis() as before, but rather than scaling the transform by 1/2 for the secondary axis, we inverse scale the breaks on the secondary axis instead.

In this particular case we have it fairly easy, as we simply have to multiply the desired breakpoint positions by 2. The resulting breakpoints are then correctly positioned for both the logarithmic and linear portions of your graph. After that, all we have to do is to relabel the breaks with their desired values. This sidesteps the problem of ggplot2 getting confused by the break placement when it has to scale a mixed transform, as we do the scaling ourselves. Crude, but effective.

Unfortunately, at the present moment there don't appear to be any other alternatives to sec_axis() (other than dup_axis() which will be of little help here). I'd be happy to be corrected on this point, however! Good luck, and I hope this solution proves helpful for you!

Here's the code:

# Vector of desired breakpoints for secondary axis
sec_breaks <- c(0.001, 0.01, 0.1, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5)
# Vector of scaled breakpoints that we will actually add to the plot
scaled_breaks <- 2 * sec_breaks

ggplot(data = dat, aes(x = x, y = y)) +
  geom_line(size = 1) +
  scale_y_continuous(trans = magnify_trans_log(interval_low = 0.5,
                                               interval_high = 1,
                                               reducer = 0.5,
                                               reducer2 = 8),
                     breaks = c(0.001, 0.01, 0.1, 0.5, 0.6, 0.7, 0.8, 0.9, 1),
                     sec.axis = sec_axis(trans = ~.,
                                         breaks = scaled_breaks,
                                         labels = sprintf("%.3f", sec_breaks))) +
  theme_bw() +
  theme(axis.text.y=element_text(colour = "black", size=15))

And the resulting plot:

enter image description here


Can you create two separate plots for the different y-axis ranges, & stack them together? The following works for me, on ggplot2 3.1.0:

library(cowplot)

theme_set(theme_bw())

p.bottom <- ggplot(dat, aes(x = x, y = y)) +
  geom_line(size = 1) +
  scale_y_log10(breaks = c(0.001, 0.01, 0.1, 0.5),
                expand = c(0, 0),
                sec.axis = sec_axis(trans = ~ . * (1/2),
                                    breaks = c(0.001, 0.01, 0.1, 0.25))) +
  coord_cartesian(ylim = c(0.001, 0.5)) + # limit y-axis range
  theme(axis.text.y=element_text(colour = "black", size=15),
        axis.title.y = element_blank(),
        axis.ticks.length = unit(0, "pt"),
        plot.margin = unit(c(0, 5.5, 5.5, 5.5), "pt")) #remove any space above plot panel

p.top <- ggplot(dat, aes(x = x, y = y)) +
  geom_line(size = 1) +
  scale_y_continuous(breaks = c(0.6, 0.7, 0.8, 0.9, 1),
                     labels = function(y) sprintf("%.3f", y), #ensure same label format as p.bottom
                expand = c(0, 0),
                sec.axis = sec_axis(trans = ~ . * (1/2),
                                    breaks = c(0.3, 0.35, 0.4, 0.45, 0.5),
                                    labels = function(y) sprintf("%.3f", y))) +
  coord_cartesian(ylim = c(0.5, 1)) + # limit y-axis range
  theme(axis.text.y=element_text(colour = "black", size=15),
        axis.text.x = element_blank(),       # remove x-axis labels / ticks / title &
        axis.ticks.x = element_blank(),      # any space below the plot panel
        axis.title.x = element_blank(),
        axis.ticks.length = unit(0, "pt"),
        plot.margin = unit(c(5.5, 5.5, 0, 5.5), "pt"))

plot_grid(p.top, p.bottom, 
          align = "v", ncol = 1)

plot