Daniel V
Daniel V

Reputation: 1388

Lock aspect ratio on part of grid

I'm trying to write a function wherein our company logo is automatically added to each graph on export as part of a function, next to the title and subtitle. The dimensions of each output will depend on the needs at the time, so having a set size won't be particularly helpful unfortunately.

To do this, I've generated a series of grids to slot everything together, as per the below (using the iris dataset).

library(datasets)
library(tidyverse)
library(gridExtra)
library(grid)
library(png)

m <- readPNG("Rlogo.png") # download from: https://www.r-project.org/logo/Rlogo.png

plot <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) +
  geom_col() +
  ggtitle("Title goes here",
          subtitle = "subtitle down here")


txtTitle <- plot$labels$title
txtSubTitle <- plot$labels$subtitle

plot$labels$title <- NULL
plot$labels$subtitle <- NULL

buffer <- grobTree(rectGrob(gp = gpar(fill = "white", col = "white")))

Title <- grobTree(textGrob(label = txtTitle,  
                           hjust = 1, 
                           x = 0.98))
SubTitle <- textGrob(label = txtSubTitle, 
                     hjust = 1, 
                     x = 0.98)
Logo <- grobTree(rasterGrob(m, x = 0.02, hjust = 0))



TitlesGrid <- grid.arrange(Title, SubTitle, ncol = 1)
TopGrid <- grid.arrange(Logo, TitlesGrid, widths = c(1, 7), ncol = 2)
AllGrid <- grid.arrange(TopGrid, arrangeGrob(plot), heights = c(1,7))

This provides the following outputs at different aspect ratios.

Good spacing Bad Output

The first example has a nice gap between the title and subtitle whereas there is too much for the second one. How would I make it so that the height of TopGrid is fixed to an absolute size, but the rest fills to the size desired?

Upvotes: 3

Views: 400

Answers (1)

Claus Wilke
Claus Wilke

Reputation: 17790

Grid graphics has the concept of absolute and relative units. Absolute units (such as "cm", "in", "pt") always stay the same size, regardless of the viewport size. Relative units (called "null") expand or shrink as needed. In a regular ggplot2 object, the plot panel is specified in relative units while the various elements around the panel, such as title, axis ticks, etc. are specified in absolute units.

You specify absolute or relative units with the unit() function:

> library(grid)
> unit(1, "cm")
[1] 1cm
> unit(1, "null")
[1] 1null

In your case, the heights argument of grid.arrange can take arbitrary grid unit objects, so you just have to give the top height an absolute unit:

grid.arrange(TopGrid, arrangeGrob(plot), heights = unit(c(1, 1), c("cm", "null")))

enter image description here

enter image description here

Upvotes: 4

Related Questions