3

I am a newbie using ggplot2 and I'm trying to plot a scatter plot above a heatmap. Both plots have the same discrete x-axis.

This is the code I'm trying:

library(ggplot2) library(grid) library(reshape2) #data for the scatterplot df = data.frame(id1 = letters[1:10], C = abs(rnorm(10))) #scatter plot p1 <- ggplot(df, aes(x= id1, y = C)) + geom_point(pch = 19) + theme_bw() + scale_x_discrete(expand = c(0, 0), breaks = letters[1:10]) + theme(legend.position = "none") + theme(axis.title.y = element_blank()) + theme(axis.title.x = element_blank()) #data for the heatmap X = data.frame(matrix(rnorm(100), nrow = 10)) names(X) = month.name[1:10] X = melt(cbind(id1 = letters[1:10], X)) #heatmap p2 <- ggplot(X, aes(x = id1, y = variable, fill = value)) p2 <- p2 + geom_tile() p2 <- p2 + scale_fill_gradientn(colours = c("blue", "white" , "red")) p2 <- p2 + theme(legend.position = "none") + theme(axis.title.y = element_blank()) + theme(axis.title.x = element_blank()) p2 <- p2 + scale_x_discrete(expand = c(0, 0), breaks = letters[1:10]) p2 <- p2 + scale_y_discrete(expand = c(0, 0)) layt <- grid.layout(nrow=2,ncol=1,heights=c(2/8,6/8),default.units=c('null','null')) vplayout <- function(x,y) {viewport(layout.pos.row = x, layout.pos.col = y)} grid.newpage() pushViewport(viewport(layout=layt)) print(p1,vp=vplayout(1,1)) print(p2,vp = vplayout(2,1)) 

The problem is that the axis are not situated one above the other.

https://mail.google.com/mail/u/0/?ui=2&ik=81975edabc&view=att&th=13ece12a06a3cea2&attid=0.1&disp=emb&realattid=ii_13ece128398baede&zw&atsh=1

Is there any solution? It is possible to reshape the data and make something like facets?

1
  • I'd try the grid.extra package, but aligning axes like this is always difficult. You may want to consider different visualizations (i.e. include the legend in your heatmap so you can avoid the need for a scatter plot). Commented May 22, 2013 at 21:36

2 Answers 2

2

Another option:

grid.draw(gtable:::rbind.gtable(ggplotGrob(p1), ggplotGrob(p2), size='last')) 

(ideally one would want size=max, but it has a bug preventing it to work).

Sign up to request clarification or add additional context in comments.

4 Comments

Definitely more elegant method to align the plots - I'll use it a lot! I think what makes this question different though is the alignment within the plots (because of the different geom in each), even if the left is aligned, the points will still not match the heatmap clearly.
the two alignment methods are virtually equivalent; only by working out the width manually you can use unit.pmax, which currently gtable:::rbind fails to do properly (you therefore need to guess which plot takes more space, hoping it's the same one across all viewports...)
Thank you very much, baptiste... Just a last question, I forgot to mention that I need that the heatmap uses more than the lower half of the plot (maybe 2/5, 3/5). I don't want to steal more of your time, but where I can find information to know how to do it?? And thank you again...
in my opinion you should rather accept @alexwhan answer as it is currently better, if slightly less compact. Using grid.arrange at the end, you can use heights = c(2,3) and that should work.
1

There are a couple of tricks here. The first is that the tick marks get treated differently, even though you have the same discrete axis. When you do expand = c(0,0), on the scatterplot the tick is now aligned with the y axis, while on the heatmap it is in the centre of the category. My method of getting around that is to manually assign the expand value for the scatterplot so that there is a gap of of 1/2 a categorical value. Because there are 10 categorical values, in this case it is 0.05 ((1/10)/2). The points will now align with the centre of each category.

The other side of the problem is because the y labels are different sizes they throw out the rest of the alignment. The solution comes from this question, using ggplot_gtable and grid.arrange from the gridExtra package.

library(gridExtra) #data for the scatterplot df = data.frame(id1 = letters[1:10], C = abs(rnorm(10))) #scatter plot p1 <- ggplot(df, aes(x= id1, y = C)) + geom_point(pch = 19) + theme_bw() + # Change the expand values scale_x_discrete(expand = c(0.05, 0.05), breaks = letters[1:10]) + #scale_y_discrete(breaks = NULL) + theme(legend.position = "none") + theme(axis.title.y = element_blank()) + theme(axis.title.x = element_blank()) p1 #data for the heatmap X = data.frame(matrix(rnorm(100), nrow = 10)) names(X) = month.name[1:10] X = melt(cbind(id1 = letters[1:10], X)) #heatmap p2 <- ggplot(X, aes(x = id1, y = variable, fill = value)) p2 <- p2 + geom_tile() p2 <- p2 + scale_fill_gradientn(colours = c("blue", "white" , "red")) p2 <- p2 + theme(legend.position = "none") + theme(axis.title.y = element_blank()) + theme(axis.title.x = element_blank()) p2 <- p2 + scale_x_discrete(expand = c(0, 0), breaks = letters[1:10]) p2 <- p2 + scale_y_discrete(expand = c(0, 0)) #Here's the gtable magic gp1<- ggplot_gtable(ggplot_build(p1)) gp2<- ggplot_gtable(ggplot_build(p2)) #This identifies the maximum width maxWidth = unit.pmax(gp1$widths[2:3], gp2$widths[2:3]) #Set each to the maximum width gp1$widths[2:3] <- maxWidth gp2$widths[2:3] <- maxWidth #Put them together grid.arrange(gp1, gp2) 

EDIT - See @baptiste's answer for a more elegant method of alignment of the y axis

enter image description here

2 Comments

you could use ggplotGrob instead of ggplot_gtable(ggplot_build())
Thank you, alexwhan for taking the time to answer me.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.