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)
=crosstable(iris, by=Species, test=TRUE)
ct1=crosstable(mtcars2, c(mpg,cyl,disp), by=am, effect=TRUE, total="both", showNA="always")
ct2=crosstable(esoph)
ct3options(crosstable_units="cm")
= ggplot(data = iris ) +
my_plot geom_point(mapping = aes(Sepal.Length, Petal.Length))
= read_docx() %>% #default template
doc 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)
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.
Here is a brief description of the functions used in this example:
officer::read_docx()
: creates a bare MS Word documentbody_add_title()
: adds a title paragraph of any levelbody_add_normal()
: adds a normal style paragraph. You can also incorporate variables using the syntax {nrow(ct3)}
and references using the syntax \\@ref(my_bookmark)
.body_add_crosstable()
: adds a crosstablebody_add_figure_legend()
and body_add_table_legend()
: adds a figure/table legend. The bookmark
is the key that can be added elsewhere in body_add_normal()
.body_add_gg2()
: adds a ggplot. Unlike officer::body_add_gg()
, you can change the unit using the units
argument or the options options(crosstable_units="cm")
.Browse https://davidgohel.github.io/officer/ for more insight about how you can use {officer}
.
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:
= read_docx("my_template.docx) %>% #your custom template
doc 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.
Depending on your version of {officer}
, Word will ask you to update the fields
During the opening of the document, MS Word might ask you to “update the fields”, to which you should answer “Yes”. If it does not ask or if you answer “No”, the legends added with body_add_table_legend()
or body_add_figure_legend()
might have no actual numbers displayed.
In this case, you have to manually update the references inside MS Word: select all (+), then update (), sometimes twice. You might even need to do this several times. See ?body_add_legend
for more insight.
Large tables can sometimes overflow the MS Word document width. In this case (for instance for mtcars2
in the previous example), you have to manually go to Table Tools > Layout > AutoFit > AutoFit Window
in the ribbon to correct the width. This is a limitation that comes with officer
(link). You can also use generate_autofit_macro()
to generate a .bas
file that, once imported in Word, unlocks the possibility to autofit every table of the document at once. See ?generate_autofit_macro
for more details.
Be aware that you unfortunately cannot reference a bookmark more than once using this method. Writing: body_add_normal("Table \\@ref(iris_col1) is about flowers. I like this Table \\@ref(iris_col1).")
will prevent all the numbering from applying.
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.