class: center, middle, inverse, title-slide # R Markdown Recipes ###
Yihui Xie
, RStudio ### 2020/01/28 @ rstudio::conf --- class: center, middle # Slides: [bit.ly/down-recipes](https://bit.ly/down-recipes) ### To work on exercises, use either RStudio Cloud project "06-Recipes" at https://rstd.io/RMAID or download the repo https://github.com/rstudio-conf-2020/rmarkdown-dashboard and go to the local dir "materials/exercises/06-Recipes/" ### You may write down your questions here https://community.rstudio.com/t/49101 during the lecture. I'll try to answer them at the end. --- ## Workshop policies - Identify the exits closest to you in case of emergency - Please review the rstudio::conf code of conduct that applies to all workshops. Issues can be addressed three ways: - In person: contact any rstudio::conf staff member or the conference registration desk - By email: send a message to conf@rstudio.com - By phone: call 844-448-1212 - Please do not photograph people wearing red lanyards - A chill-out room is available for neurologically diverse attendees on the 4th floor of tower 1 --- ## Teaching staff Instructors: Carl Howe, Yihui Xie TAs: Hadrien, Melanie, Jiena, Adi --- > 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 ![:image 70%, How Ultraman was made](gif/ultraman.gif) ??? 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. --- ![How Rmd is converted through knitr and Pandoc](https://bookdown.org/yihui/rmarkdown-cookbook/images/workflow.png) `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 [![:image 41%, R Markdown definitive guide](https://bookdown.org/yihui/rmarkdown/images/cover.png)](https://bookdown.org/yihui/rmarkdown) --- ## R Markdown Cookbook Under development: https://bookdown.org/yihui/rmarkdown-cookbook/ This session of the workshop is based on this book. --- ## 0. A lesser-known way to 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. ??? As we try **xaringan**, how can we not mention `xaringan:::karl`? :) --- ## 1. [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[![Pacman](https://user-images.githubusercontent.com/163582/44246516-30c93000-a1a4-11e8-8aa5-8876e51a227f.gif)] Creating a Pacman---one of the very few legitimate use cases of pie charts! --- class: inverse ## Exercise: `01-animation.Rmd` Play with the R packages [**animation**](https://yihui.org/animation/examples/) and [**gganimate**](https://github.com/thomasp85/gganimate). --- Enjoy your animations! .center[![Pixar](gif/pixar.gif)] --- ## 2. Generating PDF via LaTeX? .center[![TinyTeX logo](https://yihui.org/images/logo-tinytex.png)] --- - 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 ## Exercise: `02-tinytex.Rmd` See how missing LaTeX packages are automatically installed. --- class: center ![How to draw an owl](gif/draw-an-owl.jpg) ??? 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 ![How to create a PDF](https://user-images.githubusercontent.com/163582/68422075-18f11980-0165-11ea-8589-24e168a3f246.jpg) ??? With TinyTeX and R Markdown, you just click the Knit button. Most intermediate steps are automated, and do not need your attention. --- ## 3. 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** package. .center[ ![pagedown](https://user-images.githubusercontent.com/163582/51942716-66be4180-23dd-11e9-8dbc-fdb4f465d1c2.png) https://github.com/rstudio/pagedown ] --- class: inverse ## Exercise: `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) from last year). --- ## 4. 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 ## Exercise: `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[ ![:image 31.8%, "The Scream"](https://www.edvardmunch.org/images/paintings/the-scream.jpg) ![:image 30%, "The Scream"](https://i.redd.it/294ep87hpcu31.jpg) ] .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. --- ## 5. Convert Rmd to R script Call `knitr::purl()` on the Rmd file. --- class: inverse ## Exercise: `05-purl.Rmd` ```r knitr::purl("05-purl.Rmd") # output: 05-purl.R # no documentation, pure code knitr::purl("05-purl.Rmd", documentation = 0) # full documentation in #' comments knitr::purl("05-purl.Rmd", documentation = 2) ``` Caveat: there is a caching mechanism behind `knitr::purl()`. That is, if the Rmd file is not changed, the R script won't be regenerated. --- You just realized that all Rmd documents are actually R scripts wearing text masks. .center[![Ducks wearing dog masks](gif/duck-dog-mask.gif)] --- ## 6. Add citations BibTeX databases: ```r knitr::write_bib("base") ``` ``` @Manual{R-base, title = {R: A Language and Environment for Statistical Computing}, author = {{R Core Team}}, organization = {R Foundation for Statistical Computing}, address = {Vienna, Austria}, year = {2019}, url = {https://www.R-project.org/}, } ``` --- - Write citation entries to a file, e.g., ```r pkgs <- c("rmarkdown", "pagedown", "gifski") knitr::write_bib(pkgs, file = "packages.bib") ``` - Add a `bibliography` field to the YAML metadata, e.g., ```yaml title: "Add citations in R Markdown" bibliography: "packages.bib" # you can use multiple bib files, e.g. # bibliography: ["foo.bib", "bar.bib"] ``` - Use `@key` to cite an entry (or `[@key]` if you need brackets, or cite multiple entries via `[@key-1; @key-2]`). --- class: inverse ## Exercise: `06-citation.Rmd` You can cite any publications (not limited to R packages). Try to find some BibTeX entries from https://scholar.google.com. --- ## Please acknowledge your helpers e.g., cite R packages that helped you .center[![:image 50%, "A dog helper"](gif/dog-help.gif)] --- ## 7. 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 ## Exercise: `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[![Kicking the wrong ball](gif/kick-head.gif)] --- ## 8. 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()`. Try other R code in the inline R expressions (not necessarily using `combine_words`). --- ## The importance of the Oxford Comma .center[![Oxford Comma](https://i.kym-cdn.com/photos/images/newsfeed/000/946/417/c2e.jpg)] [via](https://knowyourmeme.com/photos/946417-oxford-comma) --- ## 9. Line breaks (not paragraphs) This may sound like a simple question, but I guess most people don't know the answer: how to break a line in the output? In LaTeX, you use `\\`; in HTML, you use `<br/>`. In Markdown, what do you use? By default, simply a line break in source won't work (it will be ignored). -- The answer is add _two trailing spaces_ before you break a line in the source. --- class: inverse ## Exercise: `09-quote.Rmd` Use the **blogdown** addin "Quote Poem" in RStudio to add these trailing spaces when you quote a large amount of text and want to preserve the line breaks (such as in poems or lyrics). .footnote[If you don't see the **blogdown** addin, install **blogdown**: `install.packages('blogdown')`] --- Sometimes a simple task can drive you crazy... .center[![How to drink the water?](gif/wrong-usage.gif)] When in doubt, read the manual: https://pandoc.org/MANUAL.html (e.g. search for "landscape" on this page for how to create landscape PDFs, or learn how to end a list before another list) --- ## 10. 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 ## Exercise: `10-code-appendix.Rmd` Can you think of 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[![The magic of moving the table cloth](gif/table-cloth.gif)] --- ## 11. 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 ## Exercise: `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[![How to easily lose 10kg](images/lose-weight.jpg)] --- ## 12. Add logos to your R plots The key: the chunk option `fig.process` can be a function to post-process your plots. ````md ```{r, fig.process=function(x, options) { x }} # plot ``` ```` --- class: inverse ## Exercise: `12-magick.Rmd` Give a chunk option a `TRUE`/`FALSE` value and you feed it for a day. Give a chunk option a function and you feed it for a lifetime. --- class: center ## `fig.process` == Strong force ![:image 50%, Feel the force](gif/git-push-force.gif) Be creative. Use your imagination. --- ## 13. Add real LaTeX math expressions to R plots - You may know `?plotmath`, but these tricks in base R graphics do not produce real LaTeX math expressions ```r plot(cars, main = expression(hat(beta) == (X^t * X)^{-1} * X^t * y)) ``` - The (perhaps only) R package that allows you to write LaTeX expressions in R plots is **tikzDevice**. - How to use **tikzDevice** in R Markdown? Short answer: use the chunk option `dev = "tikz"`. But it only makes sense to LaTeX output... --- class: inverse ## Exercise: `13-tikz.Rmd` How to generate R graphics through **tikzDevice** for both LaTeX and HTML output? The `tikz` device only generates PDF output. We need to convert PDF to other image formats for non-LaTeX output formats. --- You definitely need skills to create beautiful math expressions in R plots... ![:image 100%, "You need some skills to write beautiful LaTeX math"](gif/cool-car.gif) --- ## 14. 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 ## Exercise: `14-lang.Rmd` Work with Python, Shell scripts, and so on. --- Code chunks of all different languages worked perfectly... .center[![:image 70%, "Celebration"](gif/duiyou-3.gif)] ??? In an R Markdown document, R works, Python works, Julia works, C++ works, ... Yeah! --- ## 15. 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 ## Exercise: `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 have as many happy child documents as you want... .center[![:image 70%, "Happy child"](gif/pony.gif)] --- ## 16. Roundtrip between R Markdown and Word When someone made a small edit to the Word document you rendered from R Markdown... -- .center[![Falling apart](gif/encontro.gif)] They are not supposed to touch the `.docx` file. All edits must be made in the source (i.e., `.Rmd`). --- - 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 if (!xfun::pkg_load('redoc')) remotes::install_github("noamross/redoc") ``` --- class: inverse ## Exercise: `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[![:image 50%, Water flowing back and forth](gif/pythagorean.gif)] --- ## 17. Generate a plot and display it elsewhere The key is `fig.show = "hide"`, and the function `knitr::fig_chunk()`. --- class: inverse ## Exercise: `17-move-plot.Rmd` What if a code chunk has multiple plots? --- ## 18. 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 ## Exercise: `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')) ``` --- ## 19. 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 ## Exercise: `19-external.Rmd` Read a whole script into a code chunk, or read code chunks from the script. --- ## 20. Truncate text output Output hooks in **knitr** allow you to customize any types of output from a code chunk or an inline R expression: https://yihui.org/knitr/hooks/#output-hooks An output hook is a function that takes a piece of output and a list of current chunk options as the input, and returns the possibly revised output. ```r knitr::knit_hooks$set(HOOK_TYPE = function(x, options) { # do whatever you want with x, and then return(x) }) ``` --- class: inverse ## Exercise: `20-truncate.Rmd` Several types of output hooks are available in **knitr**. See this page https://yihui.org/knitr/hooks/#output-hooks for the full list. Now we use the `output` hook to truncate long text output. --- ## 21. 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 ## Exercise: `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. --- ## 22. 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[ [![:image 82%, the bookdown book](https://bookdown.org/yihui/bookdown/images/cover.jpg)](https://bookdown.org/yihui/bookdown/) ] .pull-right[ [![:image 87%, the blogdown book](https://bookdown.org/yihui/blogdown/images/cover.png)](https://bookdown.org/yihui/blogdown/) ] --- class: inverse ## Exercise .center[![:image 35%, Change stuff and see what happens](https://pbs.twimg.com/media/Cf7eHZ1W4AEeZJA.jpg)] --- Write a book? Create a website? Sounds scary... .center[![:image 70%, "Scared cat"](gif/drag-cat.gif)] --- 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[![Dog face](gif/dog-wat.gif)] --- class: center, middle # Thank you! ## Slides: https://bit.ly/down-recipes Examples for this session can be downloaded at: https://rstd.io/conf20-rmd-dash (in the directory `materials/exercises/06-Recipes`) --- class: center # We want to hear your feedback and please help us complete a survey at https://rstd.io/ws-survey. # Thank you!