Home > Software engineering >  Multiple equally sized plots in an RMarkdown document
Multiple equally sized plots in an RMarkdown document

Time:12-20

I would like to align the area of several plots, each of them created by separate chunks in an RMarkdown document (preferably .html) "nicely". My problem: Because of the different lengths of the y-axis texts. The plotted area doesn't overlap perfectly (A pity because my actual x-axis is months).

Setting the fig.width= and out.width= don't help here as they consider the axis text lengths.

Dummy Data chunk:

require(ggplot2)

df = expand.grid(y = LETTERS,
                 x = paste0('A', 1:10),
                 stringsAsFactors = FALSE)
set.seed(42)
df$fill = rnorm(nrow(df))
df2 = df
df2$y = unlist(lapply(lapply(df2$y, function(x) rep(x, 10)), paste0, collapse = ''))

Plot-Chunk1:

gg1 = ggplot(df, aes(y = y, x = x, fill = fill))  
  geom_tile()
gg1

Plot-Chunk2:

gg2 = ggplot(df2, aes(y = y, x = x, fill = fill))  
  geom_tile()
gg2

The plots in the RMarkdown document should look like that (red lines highlight the desired alignment):

enter image description here

I achieved this with the patchwork package. However, like this I can only use one chunk and not multiple.

Patchwork-Plot-Chunk:

require(patchwork)

gg1 / gg2  
  plot_annotation(tag_levels = 'A')

CodePudding user response:

Edited (tidier?) solution: cowplot::align_plots

Having a bit of a play around with cowplot::align_plots, it would be possible to set a standard panel width to use across all graphs. But to do this across chunks when you're constructing each graph 'blind' to the forthcoming ones, you could create a 'template' plot with labels as wide as needed (gg_set below). Each subsequent graph would then adopt the sizing of this unused plot:

require(ggplot2)

df  <-  expand.grid(y = LETTERS,
                    x = paste0('A', 1:10),
                    stringsAsFactors = FALSE)
set.seed(42)
df$fill = rnorm(nrow(df))

df2  <-  df
df2$y  <-
  unlist(lapply(lapply(df2$y, function(x)
    rep(x, 5)), paste0, collapse = ''))


# df for setting max size needed - might need experimented with
dfset  <-  df
dfset$y  <-
  unlist(lapply(lapply(df$y, function(x)
    rep(x, 10)), paste0, collapse = ''))


# 'template' plot
gg_set <-  ggplot(dfset, aes(y = y, x = x, fill = fill))  
  geom_tile()


require(cowplot)

# Chunk 1
gg1  <-  ggplot(df, aes(y = y, x = x, fill = fill))  
  geom_tile()

ggs <- align_plots(gg_set, gg1, align = "v")

# Only extracting relevant graph.
ggdraw(ggs[[2]])


# Chunk 2
gg2  <-  ggplot(df2, aes(y = y, x = x, fill = fill))  
  geom_tile()

ggs <- align_plots(gg_set, gg2, align = "v")

ggdraw(ggs[[2]])

Created on 2021-12-17 by the reprex package (v2.0.1)

Untidy former solution

I've previously used an admittedly messy solution, which really just involves padding all labels with blank rows above and below to greater than the max length:

require(ggplot2)
#> Loading required package: ggplot2

df  <-  expand.grid(y = LETTERS,
                    x = paste0('A', 1:10),
                    stringsAsFactors = FALSE)
set.seed(42)
df$fill = rnorm(nrow(df))
df2  <-  df
df2$y  <-
  unlist(lapply(lapply(df2$y, function(x)
    rep(x, 10)), paste0, collapse = ''))


df$y <-
  paste0(paste0(rep(" ", 40), collapse = ""), "\n", df$y, "\n", paste0(rep(" ", 40)))
df2$y <-
  paste0(paste0(rep(" ", 40), collapse = ""), "\n", df2$y, "\n", paste0(rep(" ", 40)))

gg1  <-  ggplot(df, aes(y = y, x = x, fill = fill))  
  geom_tile()
gg1

gg2 <-  ggplot(df2, aes(y = y, x = x, fill = fill))  
  geom_tile()
gg2

I would hope their is a more formal solution which allows a static panel sizing, and I look forward to hearing other answers. But had used this as a quick fix!

Created on 2021-12-17 by the reprex package (v2.0.1)

CodePudding user response:

The patchwork package also includes the function align_patches() which works similar to cowplot::align_plots().

gg_l = patchwork::align_patches(gg1,
                                gg2)

Plot-Chunk1:

gg_l[[1]]

Plot-Chunk2:

gg_l[[2]]

Data from question.

  • Related