class: center, middle, inverse, title-slide # A Bag of R Markdown Tricks ###
Yihui Xie
, RStudio ### 2020/01/29 @ Genentech --- > Good morning, #rstats friends! I mentioned in class how learning R is a lifelong process, there isn't always a "right" answer, & our community is kind & supportive of beginners. In the spirit of being vulnerable, what's one thing in R you don't yet quite understand? > --- [Jesse Mostipak (@kierisi)](https://twitter.com/kierisi/status/1070318868609019905) --- > Anything about the inner workings of rmarkdown / knitr / pandoc. I press knit, a document appears, and I believe that anything happening in between could be actual magic. > --- [Allison Horst (@allison_horst)](https://twitter.com/allison_horst/status/1070323369600442368) --- class: center ## There isn't so much magic  ??? I'll teach you some tricks here so that you can go back and make your friends believe you are able to fight a monster like Ultraman. ---  `rmarkdown::render()` = `knitr::knit()` + Pandoc (+ LaTeX for PDF output only). --- background-image: url(https://pbs.twimg.com/media/DwKpN8RUcAAcqwm.jpg) background-size: contain class: top right <https://github.com/allisonhorst/stats-illustrations> --- class: center [](https://bookdown.org/yihui/rmarkdown) --- ## R Markdown Cookbook Under development: https://bookdown.org/yihui/rmarkdown-cookbook/ The content of this talk is mostly from this book. --- ## 1. Live preview R Markdown With the **xaringan** package: ```r install.packages("xaringan") ``` Either call `xaringan::inf_mr()` in RStudio (or click the addin "Infinite Moon Reader"), or explicitly `xaringan::inf_mr('file.Rmd')` outside RStudio. If you are working on **xaringan** slides, you get [instant live preview](https://yihui.org/en/2019/02/ultimate-inf-mr/) of slides. For other output formats, you get the preview as you save the document. Note that this only works for HTML output formats. --- ## 2. [Create an animation](https://yihui.org/en/2018/08/gifski-knitr/) To create a GIF animation from all R plots in a code chunk, install the **gifski** package: ```r xfun::pkg_load2("gifski") ``` Then use the chunk option `animation.hook='gifski'`: ````md ```{r, animation.hook='gifski'} for (i in 1:2) { pie(c(i %% 2, 6), col = c('red', 'yellow'), labels = NA) } ``` ```` --- .center[] Creating a Pacman---one of the very few legitimate use cases of pie charts! --- class: inverse ## Example: `01-animation.Rmd` Play with the R packages [**animation**](https://github.com/yihui/animation) and [**gganimate**](https://github.com/thomasp85/gganimate). You can also generate a series of plots by yourself without using these packages. --- Enjoy your animations! .center[] --- ## 3. Generating PDF via LaTeX? .center[] --- - Why TinyTeX? https://yihui.org/tinytex/pain/ - They are all too big: TeX Live, MiKTeX, MacTeX (~5Gb). TinyTeX ([yihui.org/tinytex](https://yihui.org/tinytex)) is ~150Mb when installed: ```r tinytex::install_tinytex() ``` - With the R function `tinytex::latexmk()`, two common LaTeX problems are automatically solved: 1. Missing LaTeX packages are automatically installed (_doesn't require IT_). 2. The `.tex` document is compiled for the correct number of times to resolve cross-references (e.g., `pdflatex + bibtex + makeidx + pdflatex + pdflatex`). --- class: inverse ## Example: `02-tinytex.Rmd` See how missing LaTeX packages are automatically installed. --- class: center  ??? Some of you may have seen this "fun and creative" guide to draw an owl. Sometimes it feels similar when you want to create a PDF. There are too many gory details for you to take care of. --- class: center  ??? With TinyTeX and R Markdown, you just click the Knit button. Most intermediate steps are automated, and do not need your attention. --- ## 4. You don't really need LaTeX to create PDF You can create an HTML page (e.g. with the output format `html_document`), and print it to PDF in the Chrome browser, or use the [**pagedown**](https://github.com/rstudio/pagedown) package. .center[  ] --- class: inverse ## Example: `03-chrome.Rmd` You can print an Rmd document (if its output format is HTML), an HTML file, or a remote URL, e.g., ```r pagedown::chrome_print('03-chrome.Rmd') pagedown::chrome_print('03-chrome.html') pagedown::chrome_print('https://pagedown.rbind.io/html-letter') ``` If time permits, we can talk about the output formats in **pagedown** (if not, you may [watch my talk](https://resources.rstudio.com/rstudio-conf-2019/pagedown-creating-beautiful-pdfs-with-r-markdown-and-css) at rstudio::conf 2019). --- ## 5. Generate a report from an R script ```r #' Write your narratives after #'. #' Of course, you can use **Markdown**. #' Write R code in the usual way. 1 + 1 str(iris) #' Need chunk options? No problem. #' Write them after #+, e.g., #+ fig.width=5 plot(cars) ``` The script is converted to Rmd through `knitr::spin()`; then Rmd is rendered by `rmarkdown::render()`. --- class: inverse ## Example: `04-spin.R` Either click the "Notebook" button in RStudio, or run `rmarkdown::render("04-spin.R")`. --- [Some people](https://deanattali.com/2015/03/24/knitrs-best-hidden-gem-spin/) scream when they discover that an R script can play the same role as an R Markdown document... .center[   ] .footnote[images via [here](https://www.edvardmunch.org/the-scream.jsp) and [here](https://www.reddit.com/r/funny/comments/dm59b6/newsflash_the_scream_has_always_been_a_floppy/)] ??? This method is better for those who write more code than narratives. If you have a lot of narratives to write, I still recommend that you use R Markdown because otherwise you'd have to write a large amount of comments, which may feel awkward to read in an R script. --- ## 6. Cross-reference figures, tables, and sections With the **bookdown** package (even if you are not writing a book), you can cross-reference things via `\@ref(key)`. A few possible **bookdown** output formats: ```yaml output: - bookdown::html_document2 - bookdown::pdf_document2 - bookdown::word_document2 ``` --- class: inverse ## Example: `07-cross-reference.Rmd` Cross-reference sections, figures, tables, and equations, etc. --- Cross-references are dynamically generated from their IDs, so you will never mistake "Figure 3" for "Figure 4" again. .center[] --- ## 7. Inline output of a character vector ```r knitr::combine_words(c("apples", "oranges")) ## apples and oranges knitr::combine_words(LETTERS[1:5]) ## A, B, C, D, and E # why not paste()? paste(LETTERS[1:5], collapse = ", ") ## [1] "A, B, C, D, E" knitr::combine_words(c("hook", "line", "sinker")) ## hook, line, and sinker knitr::combine_words(c("the rhinos", "Washington", "Lincoln")) ## the rhinos, Washington, and Lincoln ``` --- class: inverse ## Example: `08-combine.Rmd` Try different arguments of `knitr::combine_words()`. --- ## The importance of the Oxford Comma .center[] [via](https://knowyourmeme.com/photos/946417-oxford-comma) --- ## 8. Put all code in the appendix The key: the chunk option `ref.label` to reference other code chunks. More info: https://yihui.org/en/2018/09/code-appendix/ --- class: inverse ## Example: `10-code-appendix.Rmd` Other possible applications of the `ref.label` option? (like [this one](https://twitter.com/grrrck/status/1030292012040441856), [this one](https://twitter.com/_bcullen/status/1219324079955529728), or [this one](https://twitter.com/FedeBioinfo/status/1183689617880563714)) --- You can move your code freely in an Rmd document using `ref.label`, _without cut-and-paste_. .center[] --- ## 9. Cache time-consuming code chunks Use the chunk option `cache = TRUE` if a code chunk is time-consuming and the code doesn't change often. --- class: inverse ## Example: `01-animation.Rmd` Change the code or chunk options, and watch the document recompile (in awkward silence). --- No free lunch. Simple tricks can have costs, too ([more here](https://yihui.org/en/2018/06/cache-invalidation/)). .center[] --- ## 10. Use other languages - Python, Julia, SQL, C++, shell scripts, JavaScript, CSS, ... - To know all languages supported in **knitr** (there are more than 40): ```r names(knitr::knit_engines$get()) ``` - Change the engine name from `r` to the one you want to use, e.g., ````md ```{python} x = 42 ``` ```` --- class: inverse ## Example: `14-lang.Rmd` Work with Python, Shell scripts, and so on. --- Code chunks of all different languages worked perfectly... .center[] ??? In an R Markdown document, R works, Python works, Julia works, C++ works, ... Yeah! --- ## 11. Child documents You can split your long documents into shorter ones, and include the shorter documents as child documents, e.g., ````md ```{r, child='analysis.Rmd'} ``` ```{r, child=c('one.Rmd', 'another.Rmd')} ``` ```` --- class: inverse ## Example: `15-conditional.Rmd` Choose a child document to include based on the P-value<sup>*</sup> of a regression coefficient. .footnote[\* Using the P-value as the criterion is usually bad statistical practice. This is only for the demo purpose.] --- You can let as many happy child documents as you want follow your main document... .center[] --- ## 12. R Markdown <-> Word When someone made an edit to the Word document you rendered from R Markdown... -- .center[] They are not supposed to touch the `.docx` file. All edits must be made in the source (i.e., `.Rmd`). --- - Here comes a life-saver: the **redoc** package developed by Noam Ross (https://github.com/noamross/redoc) - Caution: this package is still experimental! - Currently only on Github: ```r remotes::install_github("noamross/redoc") ``` --- class: inverse ## Example: `16-redoc.Rmd` Try the output format `redoc::redoc` and the function `redoc::dedoc()`. Learn a little bit about CriticMarkup: http://criticmarkup.com/users-guide.php --- ## We love the two-way workflow .center[] --- ## 13. Generate a plot and display it elsewhere The key is `fig.show = "hide"`, and the function `knitr::fig_chunk()`. --- class: inverse ## Example: `17-move-plot.Rmd` What if a code chunk has multiple plots? --- ## 14. Include an existing plot Plots don't have to be generated from R code. Use `knitr::include_graphics()` in a code chunk. Then most **knitr** chunk options related to figures can be applied to this plot. --- class: inverse ## Example: `18-include-graphics.Rmd` Try different chunk options such as `out.width`. You can include multiple images, too, e.g., ```r knitr::include_graphics(c('foo.pdf', 'bar.png')) ``` --- ## 15. Read external code into a code chunk You do not have to write code in code chunks. Feel free to write code in external files/scripts. --- class: inverse ## Example: `19-external.Rmd` Read a whole script into a code chunk, or read code chunks from the script. --- ## 16. Embed files in the HTML output Sometimes you may want your clients or readers to be able to download certain files that you used in the Rmd docuemnt (e.g., a CSV data file). Use the function [`xfun::embed_file()`](https://yihui.org/en/2018/07/embed-file/). This only works if the output file format is HTML (e.g., `html_document`, `ioslides_presentation`, etc.). --- class: inverse ## Example: `21-embed.Rmd` Caveat: [currently there is a 2MB file size limit in Chrome.](https://github.com/yihui/xfun/issues/23) The limit might be raised to 500MB in the future. --- ## 17. Work with a multi-file Rmd project You could write a book or a long-form report with **bookdown**, or create a website with **blogdown**. In RStudio: `File -> New Project -> New Directory`; select "Book" or "Website" projects. --- class: center .pull-left[ [](https://bookdown.org/yihui/bookdown/) ] .pull-right[ [](https://bookdown.org/yihui/blogdown/) ] --- Write a book? Create a website? Sounds scary... .center[] --- class: inverse ## More fun with R Markdown Face detection with R Markdown + Shiny: https://yihui.shinyapps.io/face-pi/ Source code: https://github.com/yihui/shiny-apps/tree/master/face-pi .center[] --- class: center, middle # Thank you! ## Slides: https://bit.ly/genen-down Examples for this talk can be downloaded at: https://rstd.io/conf20-rmd-dash (in the directory `materials/exercises/06-Recipes`)