0

I have an automated report which I am creating in R markdown and knitting to Microsoft Word. At the start of the report, there is an executive summary which includes some inline code referencing calculated figures. The executive summary is displayed on a coloured background, which I achieved by creating a custom style in the reference document.

Currently, the table of contents is always printed at the beginning of the document, however I would like it to appear after the executive summary. I would still like it to include the usual contents formatting (numbered headings and page numbers) as some people may be looking at the printed document (hard copy) so hyperlinks will not always be sufficient.

I've had a look for solutions, but none of them quite seem to fit my scenario.

For example, the render_toc() function here prints the contents as a list of hyperlinks anywhere in the document, but it doesn't number headings and also doesn't print the page numbers.

I've also seen the latex \tableofcontents tag but this doesn't work for a Microsoft word output.

The only other potential solution I could find was to use the parameter include-before in my YAML header - but the only examples I can find of this show the actual text in the YAML header (for example see here), which won't work for my case as it is a complex summary that has a lot of inline code and needs to appear on the custom css style coloured background.

Does anyone have any suggestions?

Here is a small and (very) simplified example - I would expect the document title and executive summary to be on the first page, then the contents should start after the page break on page 2, then the remaining sections should be after the contents:

---
title: "My report"
toc-title: "Report contents"
output: 
  officedown::rdocx_document:
    reference_docx: "templates/wordtemplate.docx"
    toc: TRUE
    toc_depth: 3
---

```{r setup, include=FALSE, purl=FALSE}

# Set chunk options:
knitr::opts_chunk$set(echo = FALSE, 
                      message = FALSE, 
                      warning = FALSE, 
                      eval = TRUE,
                      ft.align = "left",
                      fig.width = 10,
                      out.width = "100%")

```

```{r data}

# Example data:
df <- data.frame(id = c(1,2,3), fruit = c("apple", "orange", "apple"))

```

:::{custom-style="Colour_background"}

<br>

# Executive summary

There were `r nrow(df)` people who responded to the survey.

<br>

:::

\pagebreak

# Introduction

## Objectives

Objectives of study

## Background

Background to study

# Methods

Some methods text

# Results

Some results text
Amy M
  • 967
  • 1
  • 9
  • 19
  • 1
    Have you looked at using a custom Pandoc template? I'm not sure where they are stored, but you can probably modify a standard one to get what you want. – user2554330 Jul 10 '23 at 22:21
  • See https://bookdown.org/yihui/rmarkdown-cookbook/word-template.html – user2554330 Jul 10 '23 at 22:22
  • I'm already using a custom word template, which I created basd on the guide in the link you posted above - but the default in MS Word itself is to put the contents at the beginning of the document. You can manually insert the contents after some text, but I have not yet come across anything that explains how to do this in an automated report. – Amy M Jul 10 '23 at 23:41
  • Note: if I try simply moving the contents below the summary text box in the MS word template document, this does nothing - the contents still appears at the top when the document is knitted from the .Rmd. – Amy M Jul 10 '23 at 23:48
  • I think this is a Pandoc issue -- it does the conversion, and apparently it doesn't use a template for Word output the same way it does for other formats. Maybe add "pandoc" as a tag, and get help from someone who knows it? – user2554330 Jul 11 '23 at 08:44
  • 1
    I just noticed you're using `officedown`. Maybe add that as a tag too? – user2554330 Jul 11 '23 at 08:54

1 Answers1

2

I found an answer - putting the link to the relevant S/O post here, as I was unable to find it earlier.

In case anyone else is struggling with similar issues knitting R markdown to Microsoft Word, a lot of these challenges are solved by using the officedown and officer packages together.

The first thing to do is remove any mention of the TOC in the YAML header:

---
title: "My report"
output: 
  officedown::rdocx_document:
    reference_docx: "templates/wordtemplate.docx"
---

The table of contents can then be dropped anywhere in the r markdown using the officer::block_toc() function. Note that this function does not automatically give the table of contents a title.

Note that if using the hash symbol # to style the TOC title and the number of hashes is included in the levels that you have set to be displayed in the TOC, the TOC will also include its own title. To work around this issue and supress the TOC title from itself appearing in the TOC, there are two options:

  1. Use more hashes (for example if TOC level = 3, use 4 hashes)
  2. Create a custom text style and apply that to the TOC title instead

If using option 1, you would probably want to modify the style of the level 4 header (otherwise the font will be quite small relative to the other headers). This could be done by changing the style of header level 4 in the reference_docx or alternatively by updating the style of level 4 headers with officer.

I found it cleaner not to touch the pre-styled level headers and go with option 2 to create my own custom text style. This can be done with officer::fp_text() and applied to any section headers that I don't want to include in the TOC:

```{r nontoc_headerstyle}

# Check if pacman is installed, install if not:
if (!require("pacman")) install.packages("pacman")

# Load required libraries:
pacman::p_load(officer, officedown)

# Create a style for section headers that should not appear in the TOC:
nontoc_header <- officer::fp_text(
  color = "darkblue", 
  font.size = 16, 
  bold = TRUE,
  font.family = "Calibri"
)

```

Then add the TOC title in the R markdown body text where you wish the TOC to appear (e.g. after a page break) and format it using the newly created custom text style:

\newpage

`r ftext("Report contents", prop = nontoc_header)`

Finally, use the officer::bloc_toc() function in its own code chunk (and include any modifications you want, e.g. change the toc depth):

```{r create_toc}
# Insert the table of contents:    
officer::block_toc(level = 3)
```
\newpage

Note that suppressing specific section headers from the TOC with the pandoc tags {.unlisted .unnumbered} does not work if the output is Microsoft Word, due to the way MS Word constructs TOCs (see here and here).

Amy M
  • 967
  • 1
  • 9
  • 19