'Using long figures in markdown

I'm displaying long figures in a markdown report.

These are long because they use ggplot2::facet_wrap so their height depend on the data, which is not constant.

I can set the figure.height parameter of the chunk but then it's fixed and my report looks bad. Is their a way around this ?

Example :

---
title: "title"
author: "author"
date: '`r Sys.Date()`'
output: html_document
---

```{r, figure.height=40}
library(dplyr)
library(ggplot2)
iris %>%
  mutate_at("Sepal.Length",cut, 5) %>%
  mutate_at("Sepal.Width",cut,2) %>%
  group_by_at(c(1,2,5)) %>%
  summarize_at("Petal.Length",mean) %>%
  ggplot(aes(Species, Petal.Length)) +
  geom_col() +
  facet_wrap(Sepal.Length ~ Sepal.Width,ncol=2)
```


Solution 1:[1]

To go along with the n * single_height idea: you can use the chunk option eval.after so that the fig.width and fig.height options will be evaluated after the rest of the chunk is evaluated and then use the ggplot_build to pull apart a ggplot object and determine the number of rows and columns used in the facets.

For example:

---
author: "author"
date: '`r Sys.Date()`'
output: html_document
---

```{r setup}
library(dplyr)
library(ggplot2) 
library(knitr)

FACET_HEIGHT = 3.4
FACET_WIDTH  = 5

opts_chunk$set(out.width = "80%",
               out.height = "80%",
               eval.after = c("fig.height", "fig.width"))
```

For the example we'll have one basic plot to which we will set different facets.
```{r}
g <- 
  iris %>%
  mutate_at("Sepal.Length",cut, 5) %>%
  mutate_at("Sepal.Width",cut,2) %>%
  group_by_at(c(1,2,5)) %>%
  summarize_at("Petal.Length",mean) %>%
  ggplot(aes(Species, Petal.Length)) +
  geom_col()
```

A graphic with two columns
```{r fig1, fig.height = FACET_HEIGHT * max(ggplot_build(g1)$layout$layout$ROW), fig.width = FACET_WIDTH * max(ggplot_build(g1)$layout$layout$COL)}
g1 <- g + facet_wrap(Sepal.Length ~ Sepal.Width, ncol = 2)
g1
```


A graphic with two rows
```{r fig2, fig.height = FACET_HEIGHT * max(ggplot_build(g2)$layout$layout$ROW), fig.width = FACET_WIDTH * max(ggplot_build(g2)$layout$layout$COL)}
g2 <- g + facet_wrap(Sepal.Length ~ Sepal.Width, nrow = 2)
g2
```

A screenshot of the resulting html is:

enter image description here

Some fine tuning of the image width and height will be needed, but this should be a good starting point.

Solution 2:[2]

I had a similar issue and was not able to get Peter's solution to work. From what I'm able to gather, eval.after does not work with fig.height.

But thanks to Peter's example, I was able to find a work-around:

---
author: "author"
date: '`r Sys.Date()`'
output: html_document
---

```{r setup}
library(dplyr)
library(ggplot2) 
library(knitr)

FACET_HEIGHT <- 3.4
```

In chunk 1:  First, create the ggplot.
Then, use `ggplot_build` to create a new variable called `adaptive_figure_height`.
Finally, use knitr::opts_chunk$set to update the chunk option `fig.height` to better suit your ggplot.
```{r}
g <- 
  iris %>%
  mutate_at("Sepal.Length",cut, 5) %>%
  mutate_at("Sepal.Width",cut,2) %>%
  group_by_at(c(1,2,5)) %>%
  summarize_at("Petal.Length",mean) %>%
  ggplot(aes(Species, Petal.Length)) +
  geom_col() +
  facet_wrap(Sepal.Length ~ Sepal.Width, ncol = 2)

adaptive_fig_height <- FACET_HEIGHT * max(ggplot_build(g)$layout$layout$ROW)
 
opts_chunk$set( fig.height = adaptive_fig_height )
```

In chunk 2: Plot the ggplot. 
If needed, you can revert `fig.height` back to a default value.
```{r }
g
opts_chunk$set( fig.height = 7 )
```
 
Repeat the setup in chunk 1 and 2 if you have multiple long plots with differing heights.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter
Solution 2