dual y axis together with facet_wrap

回眸只為那壹抹淺笑 提交于 2019-12-10 15:58:34

问题


At How can I put a transformed scale on the right side of a ggplot2? it was shown how to add two y-axis in the same plot by manipulation and merging ggplot2 objects with gtable. From the example there I managed to extend it to work with facet_wrap. See the example below.

There are however three things that are not perfect.

  1. The scale is always put on the far right. It would be better if it connected with the plot in the last row
  2. It doesn't work if there is y-axis on all plots separately (i.e. you put scales="free_y" in facet_wrap)
  3. If I leave the grid-lines in (the line that is commented out) The grid-lines from the second plots appear in front of the first plot.

Any ideas if there is a smart way to fix these admittedly small issues?

library(ggplot2)
library(gtable)
library(grid)

p1 <- ggplot(diamonds, aes(y=carat,x=price))
p1 <- p1 + geom_point(color="red")
p1 <- p1 + facet_wrap(~ color)
p1 <- p1 + theme_bw()  %+replace%  theme(panel.background = element_rect(fill = NA)) # use white theme and set bg to transparent so they can merge nice
#p1 <- p1 + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) # remove gridlines
p1


p2 <- ggplot(diamonds, aes(x=price))
p2 <- p2 + geom_histogram( binwidth = 1000)
p2 <- p2 +  facet_wrap(~ color)
p2 <- p2 + theme_bw()  %+replace%  theme(panel.background = element_rect(fill = NA))
#p2 <- p2 + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())

p2



## Putting plots together ##################
# extract gtable
g1 <- ggplot_gtable(ggplot_build(p1))
g2 <- ggplot_gtable(ggplot_build(p2))

# overlap the panel of 2nd plot on that of 1st plot
pp <- c(subset(g1$layout, grepl("panel",name) , se = t:r))
g <- gtable_add_grob(g1, g2$grobs[grep("panel",g2$layout$name)], pp$t, 
                     pp$l, pp$b, pp$l)



# axis tweaks
ia <- which(grepl("axis_l",g2$layout$name) |  grepl("axis-l",g2$layout$name)     )
ga <- g2$grobs[ia]


axis_idx <- as.numeric(which(sapply(ga,function(x) !is.null(x$children$axis))))

for(i in 1:length(axis_idx)){
  ax <- ga[[axis_idx[i]]]$children$axis
  ax$widths <- rev(ax$widths)
  ax$grobs <- rev(ax$grobs)
  ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
  g <- gtable_add_cols(g, g2$widths[g2$layout[ia[axis_idx[i]], ]$l], length(g$widths) - 1)
  g <- gtable_add_grob(g, ax, pp$t[axis_idx[i]], length(g$widths) - i, pp$b[axis_idx[i]])
}



# Plot!
grid.newpage()
grid.draw(g)


回答1:


Here is a tweak that you should be able to tweak further to your satisfaction. Working out something more precise and general would take me more time than I have left at this instant. But I think you'll have no difficulty in taking it the extra step.

The first few steps are unchanged.

Here I copy your procedure for the top 2 row-panels, not adding back the tweaked axes at the bottom:

# do not add back the bottom lhs axis
for(i in 1:(length(axis_idx)-1)) {
    ax <- ga[[axis_idx[i]]]$children$axis
    ax$widths <- rev(ax$widths)
    ax$grobs <- rev(ax$grobs)
    ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
    g <- gtable_add_cols(g, 
        g2$widths[g2$layout[ia[axis_idx[i]], ]$l], length(g$widths) - 1)
    g <- gtable_add_grob(g, 
        ax, pp$t[axis_idx[i]], length(g$widths) - i, pp$b[axis_idx[i]])
}

Here I treat the bottom row separately. This is the bit where I have not generalized. You'll need to tweak the distances between the ticks and the vertical axis a bit. You'll also need to generalize the indexing for cases where there is only one plot at the bottom, 2 plots, etc..

# Here I fix the index ``i`` to 3, to cater for your example.
i <- length(axis_idx)
    ax <- ga[[axis_idx[i]]]$children$axis
    ax$widths <- rev(ax$widths)
    ax$grobs <- rev(ax$grobs)
    ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
    g <- gtable_add_cols(g, g2$widths[3], 12)
    g <- gtable_add_grob(g, ax, pp$t[axis_idx[i]], length(g$widths) - 9, pp$b[axis_idx[i]])

The bits that need to be generalized are the numbers 12 and 9. The bit that probably needs to be tweaked is the line with unit(0.15, "cm") to get more space than there appears to be at the moment.

To begin with your g object has width 12, which is the 3 by 3 panel plus 3 vertical axes. Then you add a column to cater for the second axis, and you obtain a width of 15. The number 12 is chosen to be on the rhs of the bottom plot. The number 9 is chosen to place the second axis there. I think.



来源:https://stackoverflow.com/questions/30103408/dual-y-axis-together-with-facet-wrap

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!