rms-wordr-markdownofficerofficedown

Switch page layout conditionally for MS Word documents generated from Rmarkdown code


I create MS Word documents using Rmarkdown and officer/officedown packages. My output is officdown::rdocx_document. I have code like this in my Rmarkdown file:

library(flextable)
library(officer)

tables <- list(
  flextable(iris),
  flextable(mtcars)
  # and potentially more tables, the list is dynamic
)

I want to toggle portrait/landscape layout depending on the number of columns of each table. For example, if the number of columns is greater than 5 the page orientation should be landscape, otherwise portrait.

I know that officer package provides block_section function, but I don't know how to use it dynamically. Please notice that I don't know how many tables will be there, the list is dynamic.

I tried this, according to the help page of block_section function:

orients <- calculate_page_orient(tables)  # a helper that will determine the orientation based on the number of columns in a table
for (i in seq_len(lenght(tables))) {
  block_section(prop_section(type = "continuous")
  tables[[i]]
  block_section(prop_section(page_size = page_size(orient = orients[i])))
}

But it doesn't work. How I can dynamically set the page layout using officer package?


Solution

  • Here is one possible implementation which instead of using block_section uses !---BLOCK_LANDSCAPE_START/END---> to set the page layout to landscape and which uses chunk option results='asis' to dynamically render your tables within a for loop. Also note that I loop directly over the datasets and do the conversion to a flextable inside the loop.

    ---
    output: officedown::rdocx_document
    ---
    
    ```{r setup, include=FALSE}
    knitr::opts_chunk$set(echo = FALSE, fig.cap = TRUE)
    library(officedown)
    library(officer)
    library(flextable)
    ```
    
    ```{r}
    tables <- list(
      iris,
      mtcars
    ) |> 
      lapply(head)
    ```
    
    ```{r}
    calculate_page_orient <- function(x) {
      if (ncol(x) > 5) "landscape" else "portrait"
    }
    ```
    
    ```{r results='asis'}
    for (tbl in tables) {
      orient <- calculate_page_orient(tbl)
      if (orient == "landscape") cat("\n\n<!---BLOCK_LANDSCAPE_START--->\n\n")
      ft <- flextable(tbl)
      ft <- autofit(ft)
      flextable_to_rmd(ft)
      if (orient == "landscape") cat("\n\n<!---BLOCK_LANDSCAPE_STOP--->\n")
      cat("\\newpage\n\n")
    }
    ```
    

    enter image description here