class: title-slide, right, middle background-image: url("images/vintage_valentine.jpg") background-position: left background-size: contain .pull-right[ # Made with YAML, strings, and glue ## An R Markdown valentine for you ### Alison Hill ### 2021-02-16 ] --- class: middle, center, inverse ## .big-text[Hello.] ??? So hello- I'm so happy to be invited to join you all today. --- name: hello class: middle, center, inverse ### Alison Hill <img style="border-radius: 50%;" src="https://alison.rbind.io/authors/alison/avatar.jpg" width="150px"/> ### Product Manager, Data Science Communication ### @RStudio [
@apreshill](https://github.com/apreshill) [
@apreshill](https://twitter.com/apreshill) [
alison.rbind.io](https://alison.rbind.io) --- class: middle .left-column[ ![](images/bakeoff.png) ] .right-column[ # On your marks...get set... ```r remotes::install_github("apreshill/bakeoff") ``` https://bakeoff.netlify.app/ ] --- class: middle, left, pink background-image: url(images/cat.png) background-position: right bottom background-size: 50% # Let's knit some valentines 💌 https://github.com/apreshill/baker-valentines --- background-image: url(images/rmarkdown_hedgehog_wide.png) background-size: contain class: bottom Artwork by [Allison Horst](https://www.allisonhorst.com/) --- name: glue class: middle .left-column[ ![](images/glue.png) ] --- template: glue .right-column[ # Let's start with glue ```r library(glue) ``` https://glue.tidyverse.org/index.html ] --- template: glue .right-column[ # Use glue in chunks .panelset[ .panel[.panel-name[What you code] ```` ```{r results='asis', echo=FALSE} bakers %>% count(series) %>% glue_data("- Series {series} had {n} bakers") %>% glue_collapse(sep = " \ \n") ``` ```` ] .panel[.panel-name[What you see] - Series 1 had 10 bakers - Series 2 had 12 bakers - Series 3 had 12 bakers - Series 4 had 13 bakers - Series 5 had 12 bakers - Series 6 had 12 bakers - Series 7 had 12 bakers - Series 8 had 12 bakers - Series 9 had 12 bakers - Series 10 had 13 bakers ] ] ] --- template: glue .right-column[ # Use glue inline .panelset[ .panel[.panel-name[What you code] The show has aired on `` `r glue::glue_collapse(unique(series$channel), sep = ", ", last = ", and ")` ``. ] .panel[.panel-name[What you see] The show has aired on BBC Two, BBC One, and Channel 4. ] ] ] --- name: epoxy class: middle .left-column[ ![](images/epoxy.jpg) ] --- template: epoxy .right-column[ # Let's level up: epoxy ```r # install.packages("remotes") remotes::install_github("gadenbuie/epoxy") ``` ```r library(epoxy) ``` Epoxy gives `knitr` a new **engine**. ### Why? This helps us meld our data and text in a whole new way. ] --- template: epoxy .right-column[ # Fire up the glue engine .panelset[ .panel[.panel-name[What you code] ````markdown ```{glue} There are {nrow(bakeoff::series)} series of *The Great British Bake-Off* (or, **GBBO**). ``` ```` ] .panel[.panel-name[What you see] There are 10 series of *The Great British Bake-Off* (or, **GBBO**). ] ] ] --- template: epoxy .right-column[ # Add data .panelset[ .panel[.panel-name[What you code] ````markdown ```{glue data = series, .transformer = epoxy_style_collapse()} The show has aired on {unique(channel)&}. ``` ```` Choose how vectors are collapsed by adding `*`, `&` or `|` to the end of the expression. ] .panel[.panel-name[What you see] The show has aired on BBC Two, BBC One and Channel 4. ] ] ] --- template: epoxy .right-column[ # The oxford comma way .panelset[ .panel[.panel-name[What you code] ````markdown ```{glue data = series, .transformer = epoxy_style_collapse(last_and = ", and ")} The show has aired on {unique(channel)&}. ``` ```` Use `.transformer` to change. ] .panel[.panel-name[What you see] The show has aired on BBC Two, BBC One, and Channel 4. ] ] ] --- template: epoxy .right-column[ # Epoxy is *vectorized* .panelset[ .panel[.panel-name[Data] ```r bakers %>% count(series) ## # A tibble: 10 x 2 ## series n ## * <fct> <int> ## 1 1 10 ## 2 2 12 ## 3 3 12 ## 4 4 13 ## 5 5 12 ## 6 6 12 ## 7 7 12 ## 8 8 12 ## 9 9 12 ## 10 10 13 ``` ] .panel[.panel-name[What you code] ````markdown ```{glue data = bakers %>% count(series)} - **Series {series}**: {n} bakers ``` ```` ] .panel[.panel-name[What you see] - **Series 1**: 10 bakers - **Series 2**: 12 bakers - **Series 3**: 12 bakers - **Series 4**: 13 bakers - **Series 5**: 12 bakers - **Series 6**: 12 bakers - **Series 7**: 12 bakers - **Series 8**: 12 bakers - **Series 9**: 12 bakers - **Series 10**: 13 bakers ] ] ] --- background-image: url("images/kitten-box.png") background-position: right background-size: contain class: middle, center, inverse .pull-left[ # What about parameters? ] --- name: parameters # The parameters two-step .pull-left[ 1\. Setup in YAML with `params:` ``` --- params: date: February 14 send_to: value: first: Annetha last: Mills sent_from: value: first: Alison last: Hill --- ``` ] --- template: parameters -- .pull-right[ ```r params$date ## [1] "February 14" params$send_to ## $first ## [1] "Annetha" ## ## $last ## [1] "Mills" params$sent_from ## $first ## [1] "Alison" ## ## $last ## [1] "Hill" ``` ] --- template: parameters -- .pull-right[ 2\. Use in code with `params$field_name` Valentine's Day is `` `r params$date`` ` ```r baker_results %>% filter(baker_first == params$send_to$first & baker_last == params$send_to$last) ``` ] --- template: parameters -- .pull-right[ 2\. Use in code with epoxy! ### To (sent February 14): Annetha Mills ### From: Alison Hill ] --- template: parameters .pull-right[ 2\. Use in code with epoxy! ````markdown ```{glue data = params} ### To (sent {date}): ``` ```` ````markdown ```{glue data = params$send_to} {first} {last} ``` ```` ````markdown ```{glue data = params$sent_from} ### From: {first} {last} ``` ```` ] --- class: middle # Two main flavors of parameterized reports -- .pull-left[ + .emphasis[Scoped:] a report made with a single source, but with different variants scoped for different audiences. + .emphasis[Change:] code; .emphasis[Keep:] data → `conf.html` → `lnl.html` ] -- .pull-right[ + .emphasis[Filtered:] a report made with a single source but the dataset is filtered to focus on a specific subsample or time period. + .emphasis[Change:] data; .emphasis[Keep:] code → `nw-covid-august.html` → `se-covid-july.html` ] --- class: middle # Two main modes for rendering parameterized reports -- .pull-left[ + .emphasis[Single:] you just want to render one-at-a-time. You can use vanilla knit button, a Shiny interactive interface, or command line. ] -- .pull-right[ + .emphasis[Batch:] you want to render many reports, iterating across all values of a parameter. You can use command line, or customize your 🧶 button. ] --- background-image: url("images/kitten-theater.png") background-position: right background-size: contain class: middle, center, inverse .pull-left[ # The grand params finale ] --- class: inverse, middle, center .pull-left[ ## ⬇️ So, we know parameters flow .emphasis[down] by affecting code/text in the body of your document. ] -- .pull-right[ ## ⬆️ But parameters can also flow .emphasis[up] to our YAML, our file output names, and our document's metadata. ] --- # Use params inside YAML fields ``` --- title: A valentine for `r params$send_to$first` subtitle: Yours truly, `r params$sent_from$first` params: date: February 14 send_to: value: first: Annetha last: Mills sent_from: value: first: Alison last: Hill --- ``` --- # Use params inside `rmarkdown::render` .panelset[ .panel[.panel-name[Script] Here, I'm overriding the name of the `output_file` and the `theme`. ```r purrr::walk( .x = list(send_to = list(first = "Sophie", last = "Faldo")), ~ rmarkdown::render( input = "index.Rmd", * output_file = glue::glue("valentine-for-{.x$first}.html"), * output_options = list(theme = "journal") ) ) ``` ] .panel[.panel-name[Args] You can replace anything that is an argument to [`rmarkdown::render()`](https://rmarkdown.rstudio.com/docs//reference/render.html) .emphasis[But]...this won't actually change the valentine itself! ] ] --- # Use params to replace param values Now, I'm actually making a valentine for Sophie! ```r purrr::walk( .x = list(send_to = list(first = "Sophie", last = "Faldo")), ~ rmarkdown::render( input = "index.Rmd", output_file = glue::glue("valentine-for-{.x$first}.html"), output_options = list(theme = "journal"), * params = list(send_to = {.x}) ) ) ``` --- # Use params to replace param values You can *also* .emphasis[replace anything that is a parameter...] [`_render_single.R`](https://github.com/apreshill/baker-valentines/blob/master/_render_single.R) ```r purrr::walk( .x = list(send_to = list(first = "Sophie", last = "Faldo")), ~ rmarkdown::render( input = "index.Rmd", output_file = glue::glue("valentine-for-{.x$first}.html"), output_options = list(theme = "journal"), params = list(send_to = {.x}, * sent_from = list(first = "Paul", last = "Hollywood")) ) ) ``` --- # Use params to replace YAML fields [`_render_single.R`](https://github.com/apreshill/baker-valentines/blob/master/_render_single.R) -- .panelset[ .panel[.panel-name[Step 1] ``` --- title: '`r params$my_valentine`' params: my_valentine: Nothing matters --- ``` ] .panel[.panel-name[Step 2] ```r purrr::walk( .x = list(send_to = list(first = "Sophie", last = "Faldo")), ~ rmarkdown::render( input = "index.Rmd", output_file = glue::glue("valentine-for-{.x$first}.html"), output_options = list(theme = "journal"), params = list(send_to = {.x}, sent_from = list(first = "Paul", last = "Hollywood"), * my_valentine = "My funny valentine") ) ) ``` ] ] --- # Use params to replace YAML fields [`_render_single.R`](https://github.com/apreshill/baker-valentines/blob/master/_render_single.R) -- .panelset[ .panel[.panel-name[Step 1] ``` --- title: '`r params$my_valentine`' params: my_valentine: Nothing matters --- ``` ] .panel[.panel-name[Step 2] ```r purrr::walk( .x = list(send_to = list(first = "Sophie", last = "Faldo")), ~ rmarkdown::render( input = input, output_file = glue::glue("valentine-for-{.x$first}.html"), output_options = list(theme = "journal"), params = list(send_to = {.x}, sent_from = list(first = "Paul", last = "Hollywood"), * my_valentine = glue::glue("My funny valentine, {.x$first}")) ) ) ``` ] ] --- class: middle, left, pink background-image: url(images/cat.png) background-position: right bottom background-size: 50% # Using YAML with strings and glue -- Use params inside YAML fields → dynamic YAML -- Use params inside `rmarkdown::render` → dynamic render -- Use params to replace param values → dynamic params -- Use params to replace YAML fields → dynamic metadata --- # Batch render [`_render_batch.R`](https://github.com/apreshill/baker-valentines/blob/master/_render_batch.R) .panelset[ .panel[.panel-name[The setup] ```r library(dplyr) bnames <- readr::read_csv("data/bakers.csv") %>% mutate(send_to = purrr::map2(.x = baker_first, .y = baker_last, ~list(first = .x, last = .y))) ``` ] .panel[.panel-name[The data] ```r bnames %>% tidyr::unnest_wider(send_to) ## # A tibble: 6 x 2 ## first last ## <chr> <chr> ## 1 Annetha Mills ## 2 David Chambers ## 3 Edward Kimber ## 4 Jasminder Randhawa ## 5 Jonathan Shepherd ## 6 Lea Harris ``` ] .panel[.panel-name[The play] ```r purrr::walk( * .x = bnames$send_to, ~ rmarkdown::render( input = "index.Rmd", output_file = glue::glue("valentine-for-{.x$first}.html"), output_options = list(theme = "journal"), params = list(send_to = {.x}, sent_from = list(first = "Paul", last = "Hollywood"), my_valentine = glue::glue("My funny valentine, {.x$first}")) ) ) ``` ] ] --- class: middle # Change what the knit button does .pull-left[ ### Add your R script Recommended: name it `_render.R`, and it .emphasis[must] be of the form: ```r function(input, ...) { ... rmarkdown::render( * input = input ) } ``` ] -- .pull-right[ ### Add to YAML with `knit:` key `source` your script, and you .emphasis[must] end this with `$value` ``` --- knit: source('_render.R')$value --- ``` ] --- name: goodbye class: pink, bottom .pull-left[ ### Sincere thanks to my RStudio colleagues: + Jim Hester, + Christophe Dervieux, + Garrick Aden-Buie, and + Tom Mock. ] .pull-right[ .right[ <img style="border-radius: 50%;" src="https://github.com/apreshill.png" width="150px"/> # Thank you! ### Find me at... [
@apreshill](http://twitter.com/apreshill) [
@apreshill](http://github.com/apreshill) [
alison.rbind.io](https://alison.rbind.io) ] ]