6

I work with Rmarkdown and I am creating many figures composed of different ggplot2 charts, using ggarrange. The problem is that I am not able to set different sizes for figures inside a single chunk. The only way I managed to set figure size is within chunk options, like:

{r Figure1, fig.height = 4, fig.width = 7}

Is there a way of setting the plot/grid size within each ggplot() or within ggarrange() function?

Details, data & code:

All my primary plots have the same size of the grid area, but the size of the final figures changes depending on the number of primary plots they contain. In addition, for annotation purposes (e.g. with annotation_figures() function), charts in the first row must have a larger top margin (for the title), while charts in the last row must have a larger bottom margin (for captions). The extra margins, to make room for title and captions (e.g. text grobs) should not alter the plot grid size, which I want to be the same for all plots inside a figure.

One example of a dataframe called "A1" that I have:

library("pacman")
p_load(ggplot2, ggpubr, hrbrthemes, tidyverse)

year <- rep(seq(2010,2019, 1), each=3)
name <- rep(c("A", "B", "C"), times=10)
n1 <- c(0,0,1,0,2,1,1,1,1,2,0,2,0,2,1,3,2,0,1,4,2,2,9,4,8,11,8,7,9,8)
n2 <- c(7,3,1,14,1,1, 15,4,4,19,9,4,26,9,4,46,4,3,52,12,3,37,12,5,45,10,5,47,18,4)
name2 <- name
A1 <-data.frame(year,name,n1,n2,name2)

With this data frame, I build the first row of plots inside a chunk with specifications {fig.height = 4.3, fig.width = 7}. This plot row has three plots (made with facet_wrap) and a top margin of 0.3 inches to make room for title annotation in the final figure, and no bottom margin. This plot row also has its own title, which will function like a subtitle or a tag in the final figure.

AA.1 <- A1 %>%
    ggplot( aes(x=year, y=n1)) +
    geom_line( data=A1 %>% dplyr::select(-name), aes(group=name2), color="grey", size=1.0, alpha=0.6) +
    geom_line( aes(color=name), color="black", size=1.5 ) + 
    theme_ipsum() +
    theme(
      axis.text.x = element_text(size=12, angle=45),
      axis.text.y = element_text(size=12),
      legend.position="none",
      plot.title = element_text(size=16),
      panel.grid = element_blank(),
      plot.margin = unit(c(0.3, 0.2, 0, 0.2), "in")) + #Top row charts have a 0.3 top margin
    labs(title="A. TAK") +
    scale_x_continuous(name ="", 
                    limits=c(2010,2019),
                breaks=c(seq(2010,2019,2)))+
    scale_y_continuous(name ="", 
                    limits=c(0,12),
                breaks=c(seq(0,12,3)))+
    facet_wrap(~name) +
    theme(strip.text = element_text(size=13))

AA.1

Then I create the bottom row plots, inside another chunk, with a different figure height specification: {fig.height = 4.1, fig.width = 7}. This row is also made of three plots, which should be similar in all aesthetics aspects to the first row, although I am plotting a different variable, with different values (ref). This row has no top margins and a 0.1 inches bottom margin, to make room for captions.

AA.2 <- A1 %>%
    ggplot( aes(x=year, y=n2)) +
    geom_line( data=A1 %>% dplyr::select(-name), aes(group=name2), color="grey", size=1.0, alpha=0.6) +
    geom_line( aes(color=name), color="black", size=1.5 )+ 
    theme_ipsum() +
    theme(
      axis.text.x = element_text(size=12, angle=45),
      axis.text.y = element_text(size=12),
      legend.position="none",
      plot.title = element_text(size=16),
      panel.grid = element_blank(),
      plot.margin = unit(c(0, 0.2, 0.1, 0.2), "in")) + #Margins are different
    ggtitle("B. REF") +
    scale_x_continuous(name ="", 
                    limits=c(2010,2019),
                breaks=c(seq(2010,2019,2)))+
    scale_y_continuous(name ="", 
                    limits=c(0,60),
                breaks=c(seq(0,60,10)))+
    facet_wrap(~name) +
    theme(strip.text = element_text(size=13))
AA.2

Finally, I arrange both sets of plots within a figure using ggarange(), and write the final title and captions with annotate_figure(). In this chunk, I set the total fig.height to 8.4 (the sum of two previous chunks).


figureA1 <- ggarrange(AA.1, AA.2,
                   ncol=1, nrow=2,
                   heights=c(1,1))

annotate_figure(
  figureA1,
  top = text_grob("Figura A.1 - TAK & REF",
                color = "black", face = "bold", size = 18),
  bottom = text_grob("Source: My.Data (2020)", face="italic", color = "black",
                     hjust = 1, x = 1, size = 12),)

Possible solutions:

  1. I would like that each plot had a total plot grid area of 4 inches. As the first plot has a top margin of 0.3 and a bottom margin of 0, I set fig.height to 4.3. As the second plot has a top margin of 0 and a bottom margin of 0.1, I set fig.height to 0.1. However, the plot grid area does not seem to be of the same size in both plots. Any ideas on how to fix this?

  2. As the fig.height parameters are different for each plot, I need to split the code to build a figure into different chunks. I have many figures that are made in a similar fashion, and therefore, I would like to write a function to build and arrange plots within figures. However, I cannot write a function across different chunks.

I think of two possible solutions for this second problem:

  1. Some way of setting the grid plot size within ggplot function (or the total plot area); or
  2. Some way of setting each of the grid plots sizes within the ggarrange function;

Anyone has an idea of how can I do that?

Perhaps the second would be even better. I tried to set the heights of the rows in ggarrange to be the same with the same, with heights argument ("heights=c(1,1)"). Also tried to make them proportional to each fig.height ("heights=c(5.3/5.1,1)"), but the second plot row grid still looks taller than the first one.

FigureA1 - heights=c(5.3/5.1,1

LuizZ
  • 945
  • 2
  • 11
  • 23

0 Answers0