The idea here is that I have two different kinds of variables that
want to share the same x axes, but possibly have quite different
formatting otherwise. There are basically two routes to take (I think):
one is to abuse ggplot2's model a bit and try to do this with vertical
faceting, with _post hoc_ adjustment of decorations. The second is to
make two separate plots and arrange them on the page accordingly.
The problem with the first approach, besides the fact that it abuses
ggplot2's underlying model, is that it's hard to make different vertical
facets very different. In the example below it's not too bad, but it's
not hard to come up with examples where it gets much harder to hack the
formatting of the two sets.
The problem with the second approach is that it's a great big nuisance
to tweak the plot margins to make the x axes align properly. Presumably
to make this work properly and automatically one would need to get into
the guts of the grid object and sort out the dimensions of the actual
plot region (as opposed to the entire figure region) and make these
match ...
Any ideas welcome.
thanks
Ben Bolker
=============
## make up some data with very different ranges
set.seed(1001)
z <- data.frame(x=runif(300),y=c(runif(150)*1e5,runif(150)),
f=rep(rep(LETTERS[1:3],50),2),
var=rep(letters[1:2],each=150))
library(ggplot2)
## choice 1: use faceting; use grid.text() to add separate axis labels
g1 <- ggplot(z,aes(x=x,y=y))+geom_point()+facet_grid(var~f,scale="free_y")+
opts(panel.margin=unit(0,"inches"))+ ## no gap
labs(y="")
## would like to remove vertical strips: can eliminate text with
## +opts(strip.text.y=theme_blank())
## but don't know how to get rid of them entirely (without eliminating
## background for horizontal strips?
g1
grid.text(c("first axis","second axis"),
x=unit(rep(0.02,2), "npc"),
y=unit(c(0.3,0.7),"npc"),
rot = 90,
gp=gpar(cex=1.2))
## choice 2: create two plots, then arrange using grid.arrange(),
## with painstakingly tweaked plot.margin() to get axes in synch
zz <- split(z,z$var)
g2 <- ggplot(zz[[1]],aes(x=x,y=y))+geom_point()+facet_grid(.~f)+
opts(panel.margin=unit(0,"inches"))+
labs(y="second axis")+
opts(axis.text.x=theme_blank(),axis.title.x=theme_blank())
g3 <- ggplot(zz[[2]],aes(x=x,y=y))+geom_point()+facet_grid(.~f)+
opts(panel.margin=unit(0,"inches"))+
labs(y="first axis")+
opts(strip.text.x=theme_blank(),strip.background=theme_blank())
library(gridExtra)
## By trial and error: it seems that the margins are specified in order
## Top, Right, Bottom, Left -- different from base R standard
## which is Bottom, Left, Top, Right??
grid.arrange(g2,g3+opts(plot.margin=unit(c(0,1,0,1.25),"lines")),nrow=2)
The ggExtra package has align.plots() implementing your second idea.
Quite an ugly hack, though, I'm afraid.
baptiste
library(ggExtra)
align.plots(g2, g3)
> --
> You received this message because you are subscribed to the ggplot2 mailing list.
> Please provide a reproducible example: http://gist.github.com/270442
>
> To post: email ggp...@googlegroups.com
> To unsubscribe: email ggplot2+u...@googlegroups.com
> More options: http://groups.google.com/group/ggplot2
>
This is a great start, but unfortunately grid.align() doesn't quite
align my plots. I started to poke into the guts, but couldn't see what
was wrong. Since my plotting objects are fairly complicated, I've saved
them to a file for replicability:
load(url("http://www.math.mcmaster.ca/bolker/R/misc/align-ex.RData"))
library(ggplot2)
library(ggExtra)
theme_set(theme_bw())
align.plots(g2,g1C)
## try removing legend, just in case that's the problem
align.plots(g2,g1C+opts(legend.position="none"))
There's also a fair bit of ugliness in the way the state of the device
gets left after align.plots() -- if you run exactly this code you get
left with some leftover x-axis labels from the previous plot -- but I'm
happy enough to open a new device every time if I can get this to work ...
Any further thoughts ... ? I can't see what differences there would
be between the two objects
cheers
Ben
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAk3I1AYACgkQc5UpGjwzenM3cwCeJ2KfS7ZSwLiLL2SSq7JivNe6
EBYAn1Q4OQsq3gBus9exMHmFp667vKOa
=wuiz
-----END PGP SIGNATURE-----
No need to change the device, grid.newpage() should do the trick;
that's what ggplot2 and lattice call internally so you don't usually
see the "previous mess".
>
> Any further thoughts ... ? I can't see what differences there would
> be between the two objects
I haven't looked at the details but a good candidate might be in the
fact that your plot has facets -- i only considered single-panel plots
when I wrote align.plots().
HTH,
baptiste
Thanks, Baptiste.
[Dennis: I could 'fix' the problem by making sure the y-axis labels
and title are the same width, but the whole point of this exercise is to
try to make the plots align *without* doing that ... thanks, though.]
I've managed to get a bit farther with this, but not to solve it. It
seems (?) that the problem occurs when one plot is constructed with a
legend and the other isn't -- even when the legend is removed with
opts(legend.position="none"), which implies that a difference in some
horizontal spacing element persists.
The code below is somewhat simplified (doesn't depend on my
particular complicated plots) and shows that faceting is not relevant,
but presence/absence of legends is.
Unfortunately, I don't know enough about digging into grid objects to
have been able to figure out (so far) where the difference lies and what
to do about it ...
On a side note, I was looking at
<http://groups.google.com/group/ggplot2/browse_thread/thread/753bd02a945a0e93>
and can offer the following little bit of code that seems to find
vertical strips (which could then be used, with a little bit work, to
adjust spacing properly in the cases shown in that e-mail) ...
strips <- lapply(dots, function(.g) {
cc <- .g$children$layout$children
vstrips <- cc[grepl("^strip_v",names(cc))]
## assume all strips the same width/height,
## so just use the first one?
if (length(vstrips)>0)
editGrob(vstrips[[1]],vp=NULL)
else ggplot2:::.zeroGrob
})
EXAMPLE:
========================
## make up some data with very different ranges
set.seed(1001)
z <- data.frame(x=runif(300),y=c(runif(150)*1e5,runif(150)),
f=rep(rep(LETTERS[1:3],50),2),
var=rep(letters[1:2],each=150))
library(ggplot2)
zz <- split(z,z$var)
## a variety of different combinations:
## wide y-axis, facets
g1 <- ggplot(zz[[1]],aes(x=x,y=y))+geom_point()+facet_grid(.~f)+
opts(panel.margin=unit(0,"inches"))+
labs(y=expression(log[10]("second axis")))+
opts(axis.text.x=theme_blank(),axis.title.x=theme_blank())
## narrow y-axis, facets, legend
g2 <- ggplot(zz[[2]],aes(x=x,y=y,colour=f))+geom_point()+facet_grid(.~f)+
opts(panel.margin=unit(0,"inches"))+
labs(y="first axis")+
opts(strip.text.x=theme_blank(),strip.background=theme_blank())
## narrow y-axis, facets, no legend
g3 <- ggplot(zz[[2]],aes(x=x,y=y))+geom_point(colour="red")+facet_grid(.~f)+
opts(panel.margin=unit(0,"inches"))+
labs(y="first axis")+
opts(strip.text.x=theme_blank(),strip.background=theme_blank())
## wide y-axis, no facets, no legend
g4 <- ggplot(zz[[1]],aes(x=x,y=y))+geom_point()+
labs(y=expression(log[10]("second axis")))+
opts(axis.text.x=theme_blank(),axis.title.x=theme_blank())
## narrow y-axis, no facets, no legend
g5 <- ggplot(zz[[2]],aes(x=x,y=y))+geom_point(colour="red")+
labs(y="first axis")+
opts(strip.text.x=theme_blank(),strip.background=theme_blank())
## narrow y-axis, no facets, legend
g6 <- ggplot(zz[[2]],aes(x=x,y=y,colour=f))+geom_point()+
labs(y="first axis")+
opts(strip.text.x=theme_blank(),strip.background=theme_blank())
library(gridExtra)
grid.arrange(g1,g2,g3,g4,g5,g6,ncol=3,nrow=2) ## check all plots
library(ggExtra)
theme_set(theme_bw())
grid.newpage()
## align all plots vertically.
## numbers 2 and 6 (the ones with legends, with or without
## facets) are misaligned
align.plots(g1,g2,g3,g4,g5,g6)
grid.newpage()
## this is true even if we suppress the legends
align.plots(g1,g2+opts(legend.position="none"),g3,g4,g5,
g6+opts(legend.position="none"))
## my (so far unsuccessful) attempts at tracking down the
## horizontal spacing differences between #5 and #6
gg5 <- ggplotGrob(g5)
gg6 <- ggplotGrob(g6+opts(legend.position="none"))
gl5 <- lapply(gg5$children$layout$children,grobWidth)
gl5[sapply(gl5,as.numeric)>0]
gg5$children$layout$children$`panel-3-3`$children[[3]]
gg6$children$layout$children$`panel-3-3`$children[[3]]
gl6 <- lapply(gg6$children$layout$children,grobWidth)
gl6[sapply(gl6,as.numeric)>0]