class: center, middle, inverse, title-slide # The officer package ## Making PowerPoint slides from R ###
Eric Nantz
@thercast
rpodcast
r-podcast.org
###
Advanced R Markdown Workshop
rstudio::conf(2019L)
--- class: bg-main1 # A Few Disclaimers <br> <br> -- ## I am not the author of this excellent package (just a very happy user) <br> -- <br> ## I am not a fan of PowerPoint! <img src="img/looneytunes.gif" width=40%> --- class: bg-main1 # However... <blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">If you're doing <a href="https://twitter.com/hashtag/rstats?src=hash&ref_src=twsrc%5Etfw">#rstats</a> R Markdown involving knitting to MS Word/PowerPoint and you are not using <a href="https://twitter.com/DavidGohel?ref_src=twsrc%5Etfw">@DavidGohel</a>'s packages, then you are doing it wrong. The amount of functionality in `flextable` alone is mind blowing. Have you looked that, <a href="https://twitter.com/revodavid?ref_src=twsrc%5Etfw">@revodavid</a>?</p>— JD Long (@CMastication) <a href="https://twitter.com/CMastication/status/1042074521401020417?ref_src=twsrc%5Etfw">September 18, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> <blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">I've been using officer a lot this year for some projects involving <a href="https://twitter.com/hashtag/shiny?src=hash&ref_src=twsrc%5Etfw">#shiny</a> & powerpoint slides automation and I'll be attending your <a href="https://twitter.com/hashtag/rstudioconf?src=hash&ref_src=twsrc%5Etfw">#rstudioconf</a> workshop! <a href="https://twitter.com/xieyihui?ref_src=twsrc%5Etfw">@xieyihui</a> I'm happy to pitch in if you are still looking 👍</p>— The R-Podcast (Eric) (@theRcast) <a href="https://twitter.com/theRcast/status/1073441479257980928?ref_src=twsrc%5Etfw">December 14, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> --- class: split-two white .column.bg-main1[ .content[ <img src="https://www.ardata.fr/img/hexbin/officer.svg" width=85%> <br> .center[ [davidgohel.github.io/officer/](https://davidgohel.github.io/officer/) ### Authored by David Gohel ] ] ] .column.bg-main2[ .content[ ## Create Microsoft Word and PowerPoint files directly from
<br> <br> ## No dependencies on other programs/libraries ### Utilizes [Open XML format](https://support.office.com/en-us/article/open-xml-formats-and-file-name-extensions-5200d93c-3449-4380-8e11-31ef14555b18) introduced in MS Office 2007 <br> <br> ## ❌ Not part of the
Markdown ecosystem ] ] --- class: split-60 with-border .column.bg-main1[ .center[ # Motivating Example ] <img src="img/slide_example.png" width=95%> ] .column.bg-main3[ .center[ # It's Survey Time! ] ## Elicit feedback on [Megaman 2](https://megaman.fandom.com/wiki/Mega_Man_2) <br> <br> ### Which robot master was the most difficult? ### Which robot master was the easiest? ### How many attempts before defeating each robot master? <br> ## Challenge: Executives want a __very specific__ slide template used! ] --- layout: true class: split-10 with-thick-border border-gray .row.center[ .content.vmiddle[ # A workflow with `officer` ] ] .row[.content[ .split-three[ .column.bg-main1[.content[ .center[ # Configure Template ] .center[ ### Master Layout ] .img-fill.nopadding[![](img/layout_master_screenshot.png)] ] ] .column.bg-main1[.content[ .center[ # Import to
] ```r library(officer) read_pptx("megaman.pptx") %>% layout_summary() ``` .font2[ Parse slides metadata ] ```r annotate_base( "megaman.pptx", "megaman_annotated.pptx" ) ``` .font2[ Create annotated slide deck ] ] ] .column.bg-main1[.content[ .center[ # Create Slides! ] ```r my_pres %>% add_slide("title_slide", "Office Theme") %>% ph_with_text("ctrTitle", "Megaman 2 Survey") %>% add_slide("robot_master_slide", "Office Theme") %>% ph_with_text("title", "Easiest Robot Master") %>% ph_with_img("pic", "metalman.jpg") %>% ph_with_text("body", index = 3, str = "Metal Man") print(my_pres, "output.pptx") ``` ] ] ]]] --- class: gray-row2-col2 gray-row2-col3 --- class: gray-row2-col1 gray-row2-col3 count: false --- class: gray-row2-col1 gray-row2-col2 count: false --- count: false --- layout: false class: split-10 .row.bg-main1.white[.content.vmiddle[ # Importing Slides ]] .row[ .split-40[ .column.bg-main1[.content[ ```r *library(tidyverse) library(officer) *my_pres <- read_pptx("megaman.pptx) ``` ]] .column.bg-main1[.content[ ### File argument optional (`officer` ships with minimal template) ### `read_pptx` creates an R object representing a PowerPoint file <br> ### All functions for manipulating slide content take this object as __first__ parameter <br> .center[ <img src="img/magrittr.png" width=30%> <br> Pipe-friendly! ] ]]]]] --- class: split-10 .row.bg-main1.white[.content.vmiddle[ # Under the (layout) hood ]] .row[ .split-40[ .column.bg-main3[.content[ ```r library(tidyverse) library(officer) my_pres <- read_pptx("megaman.pptx") layout_summary(my_pres) ``` ``` ## # A tibble: 5 x 2 ## layout master ## <chr> <chr> ## 1 title_slide Office Theme ## 2 robot_master_slide Office Theme ## 3 graph_slide Office Theme ## 4 end_slide Office Theme ## 5 Title and Content Office Theme ``` ]] .column.bg-main4[.content[ ## Each slide layout is a template under a __Master Layout__ ### Defines placeholder formatting attributes, positions, and other static elements ### All new slides must originate from one of these layouts <br> ## How to change placeholders in a layout? ### Only through PowerPoint directly
]]]]] --- class: shuriken-reverse-100 .blade1.bg-main1[.content.vmiddle.center[ ## Open PowerPoint
View
Slide Master ]] .blade2.bg-light-blue[.content.white.vmiddle.center[ ]] .hole.bg-black[.content.center.nopadding[ <img src="img/layout_master_screenshot.png" width=80%> ]] .blade3.bg-yellow[.content.vmiddle.center.color-main1[ ## Hopefully someone else can do this for you... ]] .blade4.bg-light-blue[.content.vmiddle.white.center[ ]] --- class: split-10 .row.bg-main1.white[.content.vmiddle[ # About Placeholders ]] .row[ .split-40[ .column.bg-main3[.content[ ```r library(tidyverse) library(officer) my_pres <- read_pptx("megaman.pptx") layout_properties( my_pres, "robot_master_slide" ) ``` ``` ## # A tibble: 9 x 3 ## type id ph_label ## <chr> <chr> <chr> ## 1 body 8 Rectangle 3 ## 2 body 14 Picture 13 ## 3 body 11 robot_name ## 4 body 3 user_description ## 5 dt 4 Date Placeholder 3 ## 6 ftr 5 Footer Placeholder 4 ## 7 sldNum 6 Slide Number Placeholder 5 ## 8 title 2 slide_title ## 9 pic 9 robot_img_placeholder ``` ]] .column.bg-main4[.content[ ```r my_pres %>% add_slide("robot_master_slide", "Office Theme") %>% ph_with_text( "Metal Man", type = "body", index = 11 ) ``` ## Placeholders can be different types <br> ## Typically multiple "body" placeholders in a layout <br> ### All content functions have an `index` parameter that must be specified in these cases ## How did I know that index value
]]]]] --- class: shuriken-reverse-100 .blade1.bg-main1[.content.vmiddle.center[ ### `annotate_base("megaman.pptx", "ann.pptx")` ]] .blade2.bg-light-blue[.content.white.vmiddle.center[ ]] .hole.bg-black[.content.center.nopadding[ <img src="img/annotate_layout_example.png" width=80%> ]] .blade3.bg-blue[.content.vmiddle.center.color-main1[ ## Use the `index` values in your code! ]] .blade4.bg-light-blue[.content.vmiddle.white.center[ ]] --- class: split-10 .row.bg-main1.white[.content.vmiddle[ # Let's make some slides ]] .row[ .split-60[ .column.bg-main3[.content[ ```r my_pres <- read_pptx("megaman.pptx") my_pres <- my_pres %>% # add title slide add_slide("title_slide", "Office Theme") %>% ph_with_text(type = "ctrTitle", str = "Megaman 2 Survey") %>% ph_with_text(type = "subTitle", str = "Customer: Eric Nantz") %>% ph_with_text(type = "dt", str = format(Sys.Date())) %>% ph_with_text(type = "sldNum", str = "slide 1") print(my_pres, "result.pptx") ``` ]] .column.bg-main4[.content.center.nopadding[ <img src="img/megaman_title_slide.png" width=95%> ] ]]]]] --- class: split-10 .row.bg-main1.white[.content.vmiddle[ # Let's make some slides ]] .row[ .split-60[ .column.bg-main3[.content[ ```r # easiest robot master my_pres <- my_pres %>% add_slide("robot_master_slide", "Office Theme") %>% ph_with_text(type = "title", str = "Easiest Robot Master") %>% ph_with_img(type = "pic", src = "metalman.jpg") %>% ph_with_text(type = "body", index = 3, str = "Metal Man") %>% ph_with_text( type = "body", index = 4, str = "Metal Man's stage had fairly simple enemies to eliminate, and his attack patterns were not sophisicated") print(my_pres, "result.pptx") ``` ]] .column.bg-main4[.content.center.nopadding[ <img src="img/robot_master_easy_screenshot.png" width=95%> ] ]]]]] --- class: split-10 with-thick-border .row.bg-main1.white[.content.vmiddle[ # Another option for placeholders ]] .row[ .split-50[ .column.bg-main3[.content[ .center[ ## `ph_*()` ] ### Position, formatting defined by PowerPoint <br> ### With right index value, it is very dependable ]] .column.bg-main3[.content[ .center[ ## `ph_*_at()` ] ### Adds a __new__ placeholder at coordinates supplied in function <br> ### Ability to add formatted text via `fp_text` objects <br> ### Getting right position can be tedious ]] ] ] --- class: bg-main2 # Additional Capabilities -- ## Vector-based graphics via the [`rvg`](https://github.com/davidgohel/rvg) package <br> ### Ability to edit graph features in PowerPoint or Excel directly -- <br> ## Tables via the [`flextable`](https://davidgohel.github.io/flextable/) package <br> ### Custom definitions for cell contents and formatting using similar philosophy <br> ### Compatible with R Markdown too! --- class: bg-main4 # Additional Resources ### [`officer` package documentation](https://davidgohel.github.io/officer/index.html) <br> ### [Crafting a PowerPoint Presentation wtih R](http://lenkiefer.com/2017/09/23/crafting-a-powerpoint-presentation-with-r/) and [PURRRty PowerPoint with R](http://lenkiefer.com/2017/09/27/use-purrr/) by [Len Kiefer](https://twitter.com/@lenkiefer) <br> ### [`officer` tag](https://stackoverflow.com/questions/tagged/officer) on [StackOverflow](https://stackoverflow.com/) --- class: bg-main1 # Big thanks to: <br> ## - Advanced R Markdown [workshop team](http://arm.rbind.io/prework/#instructors) ## - David Gohel for creating `officer` and other awesome packages ## - Emi Tanaka for the [shinobi](https://emitanaka.github.io/ninja-theme/themes/kunoichi/kunoichi-theme-example.html#1) theme used in these slides ## - Open formats! --- class: split-10 with-thick-border .row.bg-main1.white[.content.hmiddle[ # Keep in touch! ]] .row[.content[ .split-three[ .column.bg-main1[.content[ .center[ #
## [@thercast](https://twitter.com/thercast) ] ] ] .column.bg-main1[.content[ .center[ #
## [github.com/rpodcast](https://github.com/rpodcast) ] ] ] .column.bg-main1[.content[ .center[ #
## [gitlab.com](https://gitlab.com/rpodcast) ] ] ] ] ] ] .row[.content[ ## Other efforts in the
community: ### - Contributor to [R Weekly](https://rweekly.org/) <br> ### - [RStudio Community](https://community.rstudio.com/) sustainer <br> ### - Member of [Rbind](https://support.rbind.io/) administrator team ]]