ggplot2 2.1.0 broke my code? Secondary transformed axis now appears incorrectly

前端 未结 3 518
情歌与酒
情歌与酒 2020-12-17 02:29

Some time ago, I inquired about adding a secondary transformed x-axis in ggplot, and Nate Pope provided the excellent solution described at ggplot2: Adding secondary transfo

相关标签:
3条回答
  • 2020-12-17 02:51

    Updated to ggplot2 v 2.2.1, but it is easier to use sec.axis - see here

    Original

    Moving axes in ggplot2 became more complex from version 2.1.0. This solution draws on code from older solutions and from code in the cowplot package.

    With respect to your second issue, it was easier to construct a separate text grob for the "Stuff" title (rather than dealing with ggtitle with its margins).

    library(ggplot2) #v 2.2.1
    library(gtable)  #v 0.2.0
    library(grid)
    
    LakeLevels <- data.frame(Day = c(1:365), Elevation = sin(seq(0, 2*pi, 2 * pi/364)) * 10 + 100)
    
    ## 'base' plot
    p1 <- ggplot(data = LakeLevels) + 
      geom_path(aes(x = Elevation, y = Day)) + 
      scale_x_continuous(name = "Elevation (m)", limits = c(75, 125)) + 
      theme_bw() 
    
    ## plot with "transformed" axis
    p2 <- ggplot(data = LakeLevels) +
      geom_path(aes(x = Elevation, y = Day))+
      scale_x_continuous(name = "Elevation (ft)", limits = c(75, 125),
                         breaks = c(80, 90, 100, 110, 120),
                         labels = round(c(80, 90, 100, 110, 120) * 3.28084)) +   ## labels convert to feet
    theme_bw()
    
    ## Get gtable
    g1 <- ggplotGrob(p1)    
    g2 <- ggplotGrob(p2)
    
    ## Get the position of the plot panel in g1
    pp <- c(subset(g1$layout, name == "panel", se = t:r))
    
    # Title grobs have margins. 
    # The margins need to be swapped.
    # Function to swap margins - 
    # taken from the cowplot package:
    # https://github.com/wilkelab/cowplot/blob/master/R/switch_axis.R
    vinvert_title_grob <- function(grob) {
      heights <- grob$heights
      grob$heights[1] <- heights[3]
      grob$heights[3] <- heights[1]
      grob$vp[[1]]$layout$heights[1] <- heights[3]
      grob$vp[[1]]$layout$heights[3] <- heights[1]
    
      grob$children[[1]]$hjust <- 1 - grob$children[[1]]$hjust 
      grob$children[[1]]$vjust <- 1 - grob$children[[1]]$vjust 
      grob$children[[1]]$y <- unit(1, "npc") - grob$children[[1]]$y
      grob
    }
    
    # Copy "Elevation (ft)" xlab from g2 and swap margins
    index <- which(g2$layout$name == "xlab-b")
    xlab <- g2$grobs[[index]]
    xlab <- vinvert_title_grob(xlab)
    
    # Put xlab at the top of g1
    g1 <- gtable_add_rows(g1, g2$heights[g2$layout[index, ]$t], pp$t-1)
    g1 <- gtable_add_grob(g1, xlab, pp$t, pp$l, pp$t, pp$r, clip = "off", name="topxlab")
    
    # Get "feet" axis (axis line, tick marks and tick mark labels) from g2
    index <- which(g2$layout$name == "axis-b")
    xaxis <- g2$grobs[[index]]
    
    # Move the axis line to the bottom (Not needed in your example)
    xaxis$children[[1]]$y <- unit.c(unit(0, "npc"), unit(0, "npc"))
    
    # Swap axis ticks and tick mark labels
    ticks <- xaxis$children[[2]]
    ticks$heights <- rev(ticks$heights)
    ticks$grobs <- rev(ticks$grobs)
    
    # Move tick marks
    ticks$grobs[[2]]$y <- ticks$grobs[[2]]$y - unit(1, "npc") + unit(3, "pt")
    
    # Sswap tick mark labels' margins
    ticks$grobs[[1]] <- vinvert_title_grob(ticks$grobs[[1]])
    
    # Put ticks and tick mark labels back into xaxis
    xaxis$children[[2]] <- ticks
    
    # Add axis to top of g1
    g1 <- gtable_add_rows(g1, g2$heights[g2$layout[index, ]$t], pp$t)
    g1 <- gtable_add_grob(g1, xaxis, pp$t+1, pp$l, pp$t+1, pp$r, clip = "off", name = "axis-t")
    
    # Add "Stuff" title
    titleGrob = textGrob("Stuff", x = 0.9, y = 0.95, gp = gpar(cex = 1.5, fontface = "bold"))
    g1 <- gtable_add_grob(g1, titleGrob, pp$t+2, pp$l, pp$t+2, pp$r, name = "Title")
    
    # Draw it
    grid.newpage()
    grid.draw(g1)
    

    0 讨论(0)
  • 2020-12-17 02:55

    After some thought, I've confirmed that issue #1 originates from changes to recent versions of ggplot2, and I've also come up with a temporary workaround - installing an old version of ggplot2.

    Following Installing older version of R package to install ggplot2 1.0.0, I installed ggplot2 1.0.0 using

    packageurl <- "http://cran.r-project.org/src/contrib/Archive/ggplot2/ggplot2_1.0.0.tar.gz"
    install.packages(packageurl, repos=NULL, type="source")
    

    which I verified with

    packageDescription("ggplot2")$Version
    

    Then, re-running the exact code posted above, I was able to produce a plot with the added x-axis correctly displayed:

    This is obviously not a very satisfying answer, but it at least works until someone smarter than I can explain why this approach doesn't work in recent versions of ggplot2. :)

    So issue #1 from above has been resolved. I'm still haven't resolved issue #2 from above, so would appreciate any insight on that.

    0 讨论(0)
  • 2020-12-17 02:58

    As suggested above, you can use sec_axis or dup_axis.

    library(ggplot2)
    
    LakeLevels <- data.frame(Day = c(1:365), 
                             Elevation = sin(seq(0, 2*pi, 2 * pi/364)) * 10 + 100)
    
    ggplot(data = LakeLevels) + 
      geom_path(aes(x = Elevation, y = Day)) + 
      scale_x_continuous(name = "Elevation (m)", limits = c(75, 125),
                         sec.axis = sec_axis(trans = ~ . * 3.28084, name = "Elevation (ft)"))
    

    ggplot2 version 3.1.1

    0 讨论(0)
提交回复
热议问题