Make automatic reports

Dan Chaltiel

2021-11-27

Embed crosstables in reports

Crosstables can be inserted into automatics reports very easily.

There are two cases to consider: + You have a lot of text and a few tables? You should use Rmarkdown. + You have a lot of tables and little text? You should use officer.

Create reports with officer

The real power of crosstable comes out when used with David Gohel’s awesome package officer, which allows to automatically create MS Word documents.

Therefore, crosstable exports several helper functions to easily output a beautiful report:

library(officer)
library(ggplot2)
ct1=crosstable(iris, by=Species, test=TRUE)
ct2=crosstable(mtcars2, c(mpg,cyl,disp), by=am, effect=TRUE, total="both", showNA="always")
ct3=crosstable(esoph)
options(crosstable_units="cm")

my_plot = ggplot(data = iris ) +
  geom_point(mapping = aes(Sepal.Length, Petal.Length))

doc = read_docx() %>% #default template
  body_add_title("Dataset iris (nrow={nrow(iris)})", 1) %>%
  body_add_title("Not compacted", 2) %>%
  body_add_normal("Table \\@ref(table_autotest) is an example. However, automatic testing is bad and I should feel bad.") %>%
  body_add_crosstable(ct1) %>%
  body_add_table_legend("Automatic testing is bad", bookmark="table_autotest") %>%
  body_add_normal("Let's add a figure as well. You can see in Figure \\@ref(fig_iris) that sepal length is somehow correlated with petal length.") %>%
  body_add_figure_legend("Relation between Petal length and Sepal length", bookmark="fig_iris") %>% 
  body_add_gg2(my_plot, w=14, h=10, scale=1.5) %>% 
  body_add_title("Compacted", 2) %>%
  body_add_normal("When compacting, you might want to remove the test names.") %>%
  body_add_crosstable(ct1, compact=TRUE, show_test_name=FALSE) %>%
  body_add_break() %>%
  body_add_title("Dataset mtcars2", 1) %>%
  body_add_normal("This dataset has {nrow(ct3)} rows and {x} columns.", x=ncol(ct3)) %>%
  body_add_normal("Look, there are labels!") %>%
  body_add_crosstable(ct2, compact=TRUE)

See more useful functions at https://danchaltiel.github.io/crosstable/reference/index.html#section-officer-helpers.

Output

To see the resulting Word document, use:

write_and_open(doc)                   #save and open the docx file in a temporary file for a quick peek
write_and_open(doc, "my_report.docx") #fails if it is already open
print(doc, "my_report.docx")          #only save the docx file

You can check out the result of the example above here.

Functions

Here is a brief description of the functions used in this example:

Browse https://davidgohel.github.io/officer/ for more insight about how you can use {officer}.

Autofit macro for large tables

This is great, but large tables will unfortunately overflow your document.

This is a (known) limitation that cannot be fixed using R.

You would have to use MS Word autofit tools on each table one by one (Table Tools > Layout > AutoFit > AutoFit Window), which can be really tedious.

But fear not! You can use a MS Word macro to do the job for you. Here is how:

This process will make the macro accessible from any Word file on this computer. Note that, in the Editor, you can also drag the module to your document project to make the macro accessible only from this file. The file will have to be named with the docm extension though.

Styles

Crosstables uses Word styles to operate at full power .

Here, I used the default template of officer::read_docx() that comes with default styles. In your own custom template, you can edit all styles (for instance you can make “Normal” have a bold font of size 8) and add your own.

The best example here is body_add_list(), which is supposed to add a bullet list. Unfortunately, the default template does not come with list styles so you will have to add one to your custom template before using it:

doc = read_docx("my_template.docx) %>% #your custom template
  body_add_list(c("this is item 1", "this is item 2"), style="bullet")

#alternatively, you can define the style globally and use the ordered parameter
options(crosstable_style_list_unordered="bullet")
options(crosstable_style_list_ordered="numbered")
doc = read_docx("my_template.docx) %>%
  body_add_list(c("this is item 1", "this is item 2"), ordered=FALSE)

See ?crosstable_options for a list of all styles you can specify globally and use officer::styles_info(doc) to see which one are available in your template.

Note that you might sometimes encounter the error “Error: could not match any style named ‘xxx’” if you are not careful.

Post-production for table/figure legends

Depending on your version of {officer}, Word will ask you to update the fields

Create reports with Rmarkdown

Knitting (knitr::knit() or via RStudio) this Rmd code also creates a MS-Word file. Here, you can use the power of bookdown to generate the automatic numbering of the tables.


---
title: "Iris"
output: bookdown::word_document2
---
    
```{r setup, include=FALSE}
library(crosstable)
library(flextable)
library(dplyr) #pour le pipe %>% 
```

Table iris is given in Table \@ref(tab:irisTable).

```{r description, echo=FALSE, results='asis'}
cat("<caption> (\\#tab:irisTable) Table Iris </caption> \n\r ")
crosstable(iris, Sepal.Length, Sepal.Width, by=Species, test = TRUE, total="column") %>% as_flextable
```

You can example files here: vignette_markdown.Rmd and vignette_markdown.docx.