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

  • A+
Category:Languages

Edit

It seems as the faulty behaviour of sec_axis in ggplot2 3.1.0 is a bug. This has been recognized by the devs and they are working on a fix (see thread on GitHub).


Goal

I have a graphic where the y-axis ranges from 0 to 1. I'd like to add a secondary y-axis that ranges from 0 to 0.5 (so exactly half the values of the primary y-axis). So far no problem.

What complicates the matter is that I have a custom transformation for the y-axis where part of the y-axis is displayed linearly and the rest logarithmically (see code below for an example). For reference, see this post or this one.

Problem

This worked beautifully using ggplot2 version 3.0.0 but doesn't work anymore using the newest version (3.1.0). See example below. I don't know how to fix it in the newest version.

From the changelog:

sec_axis() and dup_axis() now return appropriate breaks for the secondary axis when applied to log transformed scales

This new functionality seems to break in the case of mixed-transformed y-axes.

Reproducible example

Here is an example using the newest version (3.1.0) of ggplot2:

library(ggplot2) library(scales)  #------------------------------------------------------------------------------------------------------- # Custom y-axis #-------------------------------------------------------------------------------------------------------  magnify_trans_log <- function(interval_low = 0.05, interval_high = 1,  reducer = 0.05, reducer2 = 8) {    trans <- Vectorize(function(x, i_low = interval_low, i_high = interval_high, r = reducer, r2 = reducer2) {     if(is.na(x) || (x >= i_low & x <= i_high)) {       x     } else if(x < i_low & !is.na(x)) {       (log10(x / r)/r2 + i_low)     } else {       log10((x - i_high) / r + i_high)/r2     }   })    inv <- Vectorize(function(x, i_low = interval_low, i_high = interval_high, r = reducer, r2 = reducer2) {     if(is.na(x) || (x >= i_low & x <= i_high)) {       x     } else if(x < i_low & !is.na(x)) {       10^(-(i_low - x)*r2)*r     } else {       i_high + 10^(x*r2)*r - i_high*r     }   })    trans_new(name = 'customlog', transform = trans, inverse = inv, domain = c(1e-16, Inf)) }  #------------------------------------------------------------------------------------------------------- # Create data #-------------------------------------------------------------------------------------------------------  x <- seq(-1, 1, length.out = 1000) y <- c(x[x<0] + 1, -x[x>0] + 1)  dat <- data.frame(   x = x   , y = y )  #------------------------------------------------------------------------------------------------------- # Plot using ggplot2 #-------------------------------------------------------------------------------------------------------  theme_set(theme_bw()) ggplot(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 = ~.*(1/2)       , breaks = c(0.001, 0.01, 0.1, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5)     )   ) + theme(     axis.text.y=element_text(colour = "black", size=15)   ) 

This produces the following plot:

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

The labelling of the secondary y-axis is correct for the logarithmic part of the axis (below 0.5) but wrong for the linear part of the axis.

If I install ggplot2 3.0.0 using

require(devtools) install_version("ggplot2", version = "3.0.0", repos = "http://cran.us.r-project.org") 

and run the same code as above, I get the following graph, which is what I want:

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

Questions

  1. Is there a way to fix this issue in the newest version of ggplot2 (3.1.0)? Ideally, I would like to refrain from using an older version of ggplot2 (i.e. 3.0.0).
  2. Are there alternatives to sec_axis that would work in this case?

 


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) 

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

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: