3

This is a followup question on one of the solutions provided by @ClausWilke (see post) to insert gap between main panel & marginal plots. How does one decide the (scale_x_continuous) limits? Also, what’ll happen if we used “NA” as the upper limit?

# Example with limits set to: (-2,4.5)
require(ggplot2)
require(cowplot)

pmain <- ggplot(data = mpg, aes(x = cty, y = hwy)) + 
  geom_point() + 
  xlab("City driving (miles/gallon)") +
  ylab("Highway driving (miles/gallon)") + 
  theme_grey()

xbox2 <- axis_canvas(pmain, axis = "x", coord_flip = TRUE) + 
  geom_boxplot(data = mpg, aes(y = cty, x = 1))  + 
  scale_x_continuous(limits = c(-2, 4.5)) + coord_flip()

ybox2 <- axis_canvas(pmain, axis = "y") + 
  geom_boxplot(data = mpg, aes(y = hwy, x = 1)) + 
  scale_x_continuous(limits = c(-2, 4.5))

p1 <- insert_xaxis_grob(pmain, xbox2, grid::unit(0.8, "in"), position = "top")
p2 <- insert_yaxis_grob(p1, ybox2, grid::unit(0.8, "in"), position = "right")

ggdraw(p2)
Vikrant
  • 125
  • 8

2 Answers2

3

With a continuous x-axis scale, you can use expand_limits to add some empty space between the main plot and the marginal plots.

For example, your ybox2 is a single box plot with a continuous x-axis scale. By default, the x-range for this plot is roughly 0.6 to 1.4 (you can see this by running ggplot(mpg, aes(y=hwy, x=1)) + geom_boxplot()). The following code sets the lower x-axis limit to 0.2 instead, meaning that about 0.4/(0.8+0.4) = 33% of the x-axis range will be the margin between the main plot and the marginal plot. We do the same for xbox2.

ybox2 <- axis_canvas(pmain, axis = "y") + 
  geom_boxplot(data = mpg, aes(y = hwy, x = 1)) +
  expand_limits(x = 0.2)

xbox2 <- axis_canvas(pmain, axis = "x", coord_flip = TRUE) + 
  geom_boxplot(data = mpg, aes(y = cty, x = 1))  + 
  coord_flip() +
  expand_limits(x = 0.2)

p1 <- insert_xaxis_grob(pmain, xbox2, grid::unit(0.4, "in"), position = "top")
p2 <- insert_yaxis_grob(p1, ybox2, grid::unit(0.4, "in"), position = "right")

ggdraw(p2)

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285
  • Was reviewing this problem once again. Your solution of expand_limits() is an extremely simple, generalizable and useful one. Avoids getting into scale limits, which could vary by type of marginal plot. Great solution! Thanks a lot. – Vikrant Dec 09 '17 at 02:19
2

The accepted answer is correct. To provide some additional information:

First, you can use the layer_scales() function to figure out exactly what the scales limits of a plot are. For example:

ybox2 <- axis_canvas(pmain, axis = "y") +  
    geom_boxplot(data = mpg, aes(y = hwy, x = 1))
layer_scales(ybox2)
#$x
#<ScaleContinuousPosition>
# Range:  0.625 -- 1.38
# Limits: 0.625 -- 1.38
#
#$y
#<ScaleContinuousPosition>
# Range:    12 --   44
# Limits: 10.4 -- 45.6

Second, it can be helpful to look at the marginal plots in a theme that shows the axes, like so:

ybox2 + theme_bw()

enter image description here

We see that the boxplot completely fills the entire x range of the plot, hence there are no margins. If we expand the axis, as suggested in the other answer, we get:

ybox2 + expand_limits(x = 0.2) + theme_bw()

enter image description here

In the original figure I had made, with four boxplots, using these methods you can see that the boxplots are at positions 1, 2, 3, 4, therefore it made sense to set the axis range from -2 to 4.5. However, the upper limit of 4.5 wasn't chosen perfectly, and created some additional gap on the other side of the boxplots. The expand_limits() approach is probably better.

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104
  • As always, thank you for providing a 360 on the problem (adding to the solution by @eipi10)! Until now, I was only using ggplot_build() to understand some nuances of created plots. Henceforth I will use layer_scales() too. Perhaps, a good way to use layer_scales() + expand_limits::: find the scale range using layer_scales(). Use expand_limits(x =c(lower_limit_x, upper_limit_x), y = c(lower_limit_y, upper_limit_y)) as required. To maintain symmetry, if required, use range +/- axis_limit – Vikrant Nov 30 '17 at 06:55