3

I'm looking to plot a filled contour with geom_tile and the corresponding raw trace directly below it with no space between the two. When using gridExtra or cowplot, I can get them close but not to where the top of raw trace is on the x axis of the filled contour. Here are the details:

Data

library(reshape2)
library(ggplot2)
volcano=volcano
volcano3d=melt(volcano)
names(volcano3d) <- c("x", "y", "z")

Plots

fill=ggplot(volcano3d,aes(x,y,z))+geom_tile(aes(fill=z))
raw=ggplot(volcano3d,aes(x,y))+geom_line()+theme(aspect.ratio=1/20)

My attempts

library(gridExtra)
grid.arrange(fill,raw,heights=c(5,1)

While they are pretty close, I'd like to do a few things:

  1. Move the bottom trace up so the top of the bottom trace is touching the xaxis of the contour plot.
  2. Align the two axis so 0,25,50,75 are all aligned. In cowplot you can use the align the argument so that's fine, but I can't figure out how to move them closer to each other.

Ideal Plot

This is from a different data set, but its a good example of the layout. enter image description here

thoughts?

Ted Mosby
  • 1,426
  • 1
  • 16
  • 41

2 Answers2

4

This gets you close to what you are looking for, except that the legend is inside the plotting region. I used theme(plot.margin) to adjust the top and bottom spacing around the plots and get the axes to align. The expand=0 allows the data to expand to the edges of the plot (as in your example). Creating grobs of each plot and setting the widths to equal allows you to control heights and widths in the arrangeGrob.

library(reshape2)
library(ggplot2)
library(gridExtra)
library(grid)
volcano=volcano
volcano3d=melt(volcano)
names(volcano3d) <- c("x", "y", "z")

fill=ggplot(volcano3d,aes(x,y,z))+geom_tile(aes(fill=z)) + 
theme(axis.text.x = element_blank(),
    legend.position=c(1,1), 
    legend.justification=c(1, 1), 
    axis.title.x = element_blank(),axis.ticks=element_blank(),
    plot.margin = unit(c(1,1,0,1), "cm")) +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(expand = c(0, 0)) 
raw=ggplot(volcano3d,aes(x,y))+geom_line()+
theme(aspect.ratio=1/20,
    plot.margin = unit(c(-1.2,1,1,1), "cm")) +
 scale_x_continuous(expand = c(0, 0)) 

gA <- ggplotGrob(fill)
gB <- ggplotGrob(raw)
gA$widths <- gB$widths
grid.newpage()
grid.draw(arrangeGrob(gA,gB, heights = c(4/5, 1/5)) )
Wyldsoul
  • 1,468
  • 10
  • 16
2

It is possible to keep the legend outside the plot. In the two gtables, gA has one additional column to take the legend. Therefore, add a column to gB, of the same width as the gA legend.

Also, I would drop the relevant top and bottom margin rows from the gtables.

library(reshape2)
library(ggplot2)
library(gridExtra)
library(gtable)
library(grid)
volcano=volcano
volcano3d=melt(volcano)
names(volcano3d) <- c("x", "y", "z")

fill = ggplot(volcano3d, aes(x, y, z)) +
   geom_tile(aes(fill=z)) + 
  scale_x_continuous(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0)) 

raw = ggplot(volcano3d,aes(x,y)) +
  geom_line() +
  scale_x_continuous(expand = c(0, 0)) 

gA <- ggplotGrob(fill)
gB <- ggplotGrob(raw)

ga = gA[-c(10:7), ]  # Remove bottom rows from gA
gb = gB[-c(1:5), ]   # Remove top rows from gB

# Add extra column to gB gtable
gb = gtable_add_cols(gb, ga$widths[7:8], 6)

ga$widths <- gb$widths
grid.newpage()
grid.draw(arrangeGrob(ga,gb, heights = c(4/5, 1/5)) )
Sandy Muspratt
  • 31,719
  • 12
  • 116
  • 122