---
title: "The write2 function"
author: "Ethan Heinzen"
output:
  rmarkdown::html_vignette:
    toc: yes
    toc_depth: 3
vignette: |
  %\VignetteIndexEntry{The write2 function}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
---

```{r include = FALSE}
knitr::opts_chunk$set(eval = FALSE, message = FALSE)
```

# Introduction

The `write2*()` functions were designed as an alternative to SAS's `ODS` procedure for useRs who want to save R Markdown tables
to separate Word, HTML, or PDF files without needing separate R Markdown programs.

There are three shortcut functions for the most common output types: HTML, PDF, and Word. Each of these three functions calls
`write2()`, an S3 function which accepts many file output types (see the help pages for `rmarkdown::render()`). Methods have been implemented for
`tableby()`, `modelsum()`, and `freqlist()`, but also `knitr::kable()`, `xtable::xtable()`, and `pander::pander_return()`.

The two most important things to recognize with `write2()` are the following:

1. Which function is being used to output the object. Sometimes the `write2` functions use `summary()`,
   while other times they will use `print()`. The details for each object specifically are described below.
   
2. How the `...` arguments are passed. To change the options for the summary-like or print-like function,
   you can pass named arguments which will in turn get passed to the appropriate function.
   Details for each object specifically are described below.
   
# A note on piping

`arsenal` is piping-compatible!

The `write2*()` functions are probably the most useful place to take advantage of
the `magrittr` package's piping framework, since commands are often nested several functions deep in the context
of `write2*()`. Piping also allows the `arsenal` package to become a part of more standard analysis pipelines;
instead of needing to write separate R Markdown programs, intermediate analysis tables and output can be easily
incorporated into piped statements.

This vignette will sprinkle the foward pipe (`%>%`) throughout as a hint at the power and flexibility of `arsenal` and piping.

# Examples Using `arsenal` Objects

```{r}
library(arsenal)
library(magrittr)
data(mockstudy)
tmpdir <- tempdir()
```

## `tableby`

For `tableby` objects, the output function in `write2()` is `summary()`.
For `summary.tableby` objects, the output function is `print()`.
For available arguments, see the help pages for `summary.tableby()`.
Don't use the option `text = TRUE` with the `write2` functions.

```{r}
mylabels <- list(sex = "SEX", age ="Age, yrs")
tab1 <- tableby(arm ~ sex + age, data=mockstudy)

write2html(
  tab1, paste0(tmpdir, "/test.tableby.html"), quiet = TRUE,
  title = "My test table",      # passed to summary.tableby
  labelTranslations = mylabels, # passed to summary.tableby
  total = FALSE                 # passed to summary.tableby
)
```

## `modelsum`

For `modelsum` objects, the output function in `write2()` is `summary()`.
For `summary.modelsum` objects, the output function is `print()`.
For available arguments, see the help pages for `summary.modelsum()`.
Don't use the option `text = TRUE` with the `write2` functions.

```{r}
tab2 <- modelsum(alk.phos ~ arm + ps + hgb, adjust= ~ age + sex, family = "gaussian", data = mockstudy)

write2pdf(
  tab2, paste0(tmpdir, "/test.modelsum.pdf"), quiet = TRUE,
  title = "My test table", # passed to summary.modelsum
  show.intercept = FALSE,  # passed to summary.modelsum
  digits = 5               # passed to summary.modelsum
)
```

## `freqlist`

For `freqlist` objects, the output function in `write2()` is `summary()`.
For `summary.freqlist` objects, the output function is `print()`.
For available arguments, see the help pages for `summary.freqlist()`.

```{r}
mockstudy[, c("arm", "sex", "mdquality.s")] %>% 
  table(useNA = "ifany") %>% 
  freqlist(groupBy = c("arm", "sex")) %>% 
  write2word(
    paste0(tmpdir, "/test.freqlist.doc"), quiet = TRUE,
    single = FALSE,         # passed to summary.freqlist
    title = "My cool title" # passed to summary.freqlist
  )
```

## `comparedf`

For `comparedf` objects, the output function in `write2()` is `summary()`.
For `summary.comparedf` objects, the output function is `print()`.

# Examples Using Other Objects

## `knitr::kable()`

For objects resulting from a call to `kable()`, the output function in `write2()` is `print()`. There aren't any arguments to the `print.knitr_kable()` function.

```{r}
mockstudy %>% 
  head() %>% 
  knitr::kable() %>% 
  write2html(paste0(tmpdir, "/test.kable.html"), quiet = TRUE)
```

## `xtable::xtable()`

For `xtable` objects, the output function in `write2()` is `print()`. For available arguments, see the help pages for `print.xtable()`.

```{r}
mockstudy %>% 
  head() %>% 
  xtable::xtable(caption = "My xtable") %>% 
  write2pdf(
    paste0(tmpdir, "/test.xtable.pdf"), quiet = TRUE,
    comment = FALSE, # passed to print.xtable to turn off the default message about xtable version
    include.rownames = FALSE, # passed to print.xtable
    caption.placement = "top" # passed to print.xtable
  )
```

To make an HTML document, use the `print.xtable()` option `type = "html"`.

```{r}
mockstudy %>% 
  head() %>% 
  xtable::xtable(caption = "My xtable") %>% 
  write2html(
    paste0(tmpdir, "/test.xtable.html"), quiet = TRUE,
    type = "html",            # passed to print.xtable
    comment = FALSE, # passed to print.xtable to turn off the default message about xtable version
    include.rownames = FALSE, # passed to print.xtable
    caption.placement = "top" # passed to print.xtable
  )
```

User beware! `xtable()` is not compatible with `write2word()`.

## `pander::pander_return()`

Pander is a little bit more tricky. Since `pander::pander()` doesn't return an object, the useR should instead use
`pander::pander_return()`. For this (and for all character vectors), the the output function in `write2()` is `cat(sep = '\n')`.

```{r}
write2word(pander::pander_return(head(mockstudy)), file = paste0(tmpdir, "/test.pander.doc"), quiet = TRUE)
```

# Output Multiple Tables to One Document

To output multiple tables into a document, simply make a list of them and call the same function as before.

```{r}
mylist <- list(
  tableby(sex ~ age, data = mockstudy),
  freqlist(table(mockstudy[, c("sex", "arm")])),
  knitr::kable(head(mockstudy))
)

write2pdf(mylist, paste0(tmpdir, "/test.mylist.pdf"), quiet = TRUE)

```

One neat side-effect of this function is that you can output text and headers, etc. The possibilities are endless!

```{r}
mylist2 <- list(
  "# Header 1",
  "This is a small paragraph introducing tableby.",
  tableby(sex ~ age, data = mockstudy),
  "<hr>",
  "# Header 2",
  "<font color='red'>I can change color of my text!</font>"
)
write2html(mylist2, paste0(tmpdir, "/test.mylist2.html"), quiet = TRUE)
```

In fact, you can even recurse on the lists!

```{r}
write2pdf(list(mylist2, mylist), paste0(tmpdir, "/test.mylists.pdf"), quiet = TRUE)
```

# Output Other Objects Monospaced (as if in a terminal)

It may be useful at times to write output that would normally be copied from the terminal. The default method for `write2()`
does this automatically. To output the results of `summary.lm()`, for example:

```{r}
lm(age ~ sex, data = mockstudy) %>% 
  summary() %>% 
  write2pdf(paste0(tmpdir, "/test.lm.pdf"), quiet = TRUE)
```

The `verbatim()` function is another option to explicitly alert `write2()` to do this. This
becomes particularly helpful to overrule existing S3 methods.

For example, suppose you wanted to just print a tableby object (as if it were to print in the terminal):

```{r}
tab4 <- tableby(arm ~ sex + age, data=mockstudy)
write2html(verbatim(tab4), paste0(tmpdir, "/test.print.tableby.html"), quiet = TRUE)
```

Or suppose you wanted to print a character vector (as if it were to print in the terminal):

```{r}
chr <- paste0("MyVector", 1:10)
write2pdf(verbatim(chr), paste0(tmpdir, "/test.character.pdf"), quiet = TRUE)
```

Note that you can combine multiple objects in one call:

```{r}
write2pdf(verbatim(tab4, chr), paste0(tmpdir, "/test.verbatim.pdf"), quiet = TRUE)
```

# Add a YAML Header to the Output

You can add a YAML header to `write2()` output using the `yaml()` function.

```{r}
mylist3 <- list(
  yaml(title = "Test YAML Title", author = "My cool author name"),
  "# Header 1",
  "This is a small paragraph introducing tableby.",
  tableby(sex ~ age, data = mockstudy)
)
write2html(mylist3, paste0(tmpdir, "/test.yaml.html"), quiet = TRUE)
```

In fact, all detected YAML pieces will be moved as the first output, so that the above code chunk
gives the same output as this one:

```{r}
mylist4 <- list(
  "# Header 1",
  "This is a small paragraph introducing tableby.",
  yaml(title = "Test YAML Title"),
  tableby(sex ~ age, data = mockstudy),
  yaml(author = "My cool author name")
)
write2html(mylist4, paste0(tmpdir, "/test.yaml2.html"), quiet = TRUE)
```

# Add a Code Chunk to the Output

It is now possible to add code chunks to the output `.Rmd`:

```{r}
mylist5 <- list(
  "# What is 1 + 2?",
  code.chunk(a <- 1, b <- 2),
  code.chunk(a + b, chunk.opts = "r echo=FALSE, eval=TRUE")
)
write2html(mylist5, paste0(tmpdir, "/test.code.chunk.html"), quiet = TRUE)
```

This allow flexibility to create objects on-the-fly, to read in saved objects to the temporary `.Rmd`, etc. The possibilities are endless!

# FAQs

## How do I suppress the note about my document getting rendered?

This is easily accomplished by using the argument `quiet = TRUE` (passed to the `rmarkdown::render()` function).

```{r}
write2html(
  knitr::kable(head(mockstudy)), paste0(tmpdir, "/test.kable.quiet.html"),
  quiet = TRUE # passed to rmarkdown::render
)
```

## How do I look at the temporary `.Rmd` file?

This is easily accomplished by using the option `keep.rmd = TRUE`.

```{r}
write2html(
  knitr::kable(head(mockstudy)), paste0(tmpdir, "/test.kable.keep.rmd.html"),
  quiet = TRUE, # passed to rmarkdown::render
  keep.rmd = TRUE
)
```


## How do I prevent my document from being rendered?

This is easily accomplished by using the option `render. = FALSE`. Note that this will then default to `keep.rmd = TRUE`.

```{r}
write2html(
  knitr::kable(head(mockstudy)), paste0(tmpdir, "/test.kable.dont.render.html"),
  render. = FALSE
)
```

## How do I output headers, raw HTML/LaTeX, paragraphs, etc.?

One can simply abuse the list S3 method for `write2()`!

```{r}
mylist2 <- list(
  "# Header 1",
  "This is a small paragraph introducing tableby.",
  tableby(sex ~ age, data = mockstudy),
  "<hr>",
  "# Header 2",
  "<font color='red'>I can change color of my text!</font>"
)
write2html(mylist2, paste0(tmpdir, "/test.mylist2.html"), quiet = TRUE)
```

## How do I tweak the default format from `write2word()`, `write2html()`, or `write2pdf()`?

You can pass arguments to the format functions used behind the scenes.

```{r}
write2html(
  knitr::kable(head(mockstudy)), paste0(tmpdir, "/test.kable.theme.html"),
  quiet = TRUE,  # passed to rmarkdown::render
  theme = "yeti" # passed to rmarkdown::html_document
)
```

See the help pages for `rmarkdown::word_document()`, `rmarkdown::html_document()`, and `rmarkdown::pdf_document()`.

## How do I output to a file format other than word, HTML, and PDF?

This can be done using the generic `write2()` function. The last argument in the function can be another format specification.
For details on the acceptable inputs, see the help page for `write2()`.

```{r}
write2(
  knitr::kable(head(mockstudy[, 1:4])), paste0(tmpdir, "/test.kable.rtf"),
  quiet = TRUE,  # passed to rmarkdown::render
  output_format = rmarkdown::rtf_document
)
```

## How do I avoid prefixes on my table captions in PDF?

You can do this pretty easily with the `yaml()` function:

```{r}
mylist5 <- list(
  yaml("header-includes" = list("\\usepackage[labelformat=empty]{caption}")),
  "# Header 1",
  "This is a small paragraph introducing tableby.",
  tableby(sex ~ age, data = mockstudy)
)
write2pdf(mylist5, paste0(tmpdir, "/test.noprefixes.pdf"), title = "My tableby")
```

## How do I output multiple tables with different titles?

There are now `write2()` methods for the summary objects of `arsenal` functions. This allows you to
specify a title for each table:

```{r}
mylist6 <- list(
  summary(tableby(sex ~ age, data = mockstudy), title = "A Title for tableby"),
  summary(modelsum(age ~ sex, data = mockstudy), title = "A Title for modelsum"),
  summary(freqlist(~ sex, data = mockstudy), title = "A Title for freqlist")
)
write2pdf(mylist6, paste0(tmpdir, "/test.multiple.titles.pdf"))
```

## Why is `write2()` not working in R Markdown/R Studio?

It's possible that a global option in R Studio is preventing the tables from rendering. Consider turning off (i.e., unchecking) the option
Tools > Global Options > R Markdown > Show output inline for all R Markdown documents.
