library(mirage)
#> Loading required package: polish

For the purpose of this document, let’s start by laying out some vocabulary about Microsoft PowerPoint documents. - A document is made of several slides - Each slide has a particular layout, from the list of available layouts in the document’s template - A placeholder is a location on the slide for content can be added to - A layout is made of several potential placeholders - A slide can have various displays (text, images, etc …) placed either in these pre-existing placeholders, or in placeholders that are specific to the slide.

The goal of the mirage package is to help with creating and updating powerpoint documents throughout all these steps. As such, mirage can create and delete slides, or update them by adding displays to either predefined or bespoke placeholders.

This vignette should give users enough information to get started with creating powerpoint documents and add various contents to them with mirage.

Loading Powerpoint documents

You can start by using the load_pptx() to load your own Powerpoint document, or simply start with an empty document with the basic PowerPoint Template.

# pptx <- load_pptx("//where/is/your/document.pptx")
pptx <- load_pptx()

mirage uses a custom S3 class <pptx_container> that thinly wraps around the “rpptx” class from officer to add some mirage specific functionality.

pptx
#> <pptx_container> with 0 slides.
#>  Available layouts: "Title Slide", "Title and Content", "Section Header", "Two
#>   Content", "Comparison", "Title Only", and "Blank".
#>  Use `list_placeholders(index = )` or `list_placeholders(layout = )` to get
#>   information about available placeholders
#>  Use `mirage::add_slide()` or `mirage::update_slide()` to add content to new
#>   or existing slides

Adding slides

Once you have a presentation, you typically want to add slides with content. Although these two operations can be performed together, we have separated them in this document for clarity.

The add_slide() function can be used to add one slide with a given layout from the list of available layouts, it returns a modified pptx object which allows adding multiple slides by chaining calls to add_slide().

Let’s start by creating a document from the PowerPoint template with 3 slides.

pptx <- load_pptx() |> 
  add_slide("Title Slide") |> 
  add_slide("Title and Content") |> 
  add_slide("Two Content")

By default, the new slide is placed at the end of document, but add_slide() also accepts an index= argument if you’d like the new slide to be added elsewhere. This typically happens when you work on a document interactively.

pptx <- load_pptx() |> 
  add_slide("Title Slide") |>   # slide 1 at this point
  add_slide("Two Content")    # slide 2 at this point

pptx <- pptx |> 
  add_slide("Comparison", index = 2)

When you do this, you have to be mindful that this moves slides around in the document, i.e. the second slide now has the “Comparison” layout and the slide with layout “Two Content” has moved to third position.

Layouts

The list_layouts() function gives you a tibble that summarises the available layouts and some of their characteristics:

list_layouts(pptx)
#> # A tibble: 7 × 5
#>   name        filename placeholders_count placeholders_summary placeholders_data
#>   <chr>       <chr>                 <int> <chr>                <list>           
#> 1 Title Slide slideLa…                  5 Title (1), Subtitle… <tibble [5 × 11]>
#> 2 Title and … slideLa…                  5 Title (1), Content … <tibble [5 × 11]>
#> 3 Section He… slideLa…                  5 Title (1), Text Pla… <tibble [5 × 11]>
#> 4 Two Content slideLa…                  6 Title (1), Content … <tibble [6 × 11]>
#> 5 Comparison  slideLa…                  8 Title (1), Text Pla… <tibble [8 × 11]>
#> 6 Title Only  slideLa…                  4 Title (1), Date Pla… <tibble [4 × 11]>
#> 7 Blank       slideLa…                  3 Date Placeholder (1… <tibble [3 × 11]>

mirage offers various ways to choose which layout to use for a new slide.

The list_placeholders() function gives a glimpse.

list_placeholders(pptx, layout = "Title Slide")
#>   ph_label                   type     `x (in)`      `y (in)`      
#> ── From layout "Title Slide" ───────────────────────────────────────────────────
#> 1 Date Placeholder 3         dt       [0.50 - 2.83] [6.95 - 7.35] 
#> 2 Footer Placeholder 4       ftr      [3.42 - 6.58] [6.95 - 7.35] 
#> 3 Slide Number Placeholder 5 sldNum   [7.17 - 9.50] [6.95 - 7.35] 
#> 4 Subtitle 2                 subTitle [1.50 - 8.50] [4.25 - 6.17] 
#> 5 Title 1                    ctrTitle [0.75 - 9.25] [2.33 - 3.94]

and for a quick visual glance, you can use the tailored ggplot() method.

list_placeholders(pptx, layout = "Title Slide") |> 
  ggplot()

Adding content

Once we’ve added slides, we can add displays with the update_slide() function, it takes the document and the slide index as mandatory first arguments, and then a variable number of display specifications, as calls to the content() function.

Let’s illustrate with a simple example that updates the first slide with two simple strings displays.

pptx <- pptx |> 
  update_slide(index = 1, 
    content("My slide title"                        , ph = ph_title()), 
    content("Some more information in the sub title", ph = ph_subtitle())
  )
#> → mirage to add 2 contents at slide 1.
#>  Successfully added content to placeholder "Title 1".
#>  Successfully added content to placeholder "Subtitle 2".

update_slide() also returns the modified pptx object, so multiple calls can be chained.

Adding displays amounts to making a number of calls to the content() function to encapsulate: - what to add, with the value= argument - where to add it, via the ph= argument

Displays

The content(value=) argument accepts anything that can be polished by the polish::polish_content_pptx() function, which is extensible to allow third party packages to implement it. The content(...=) arguments are also passed down to polish_content_pptx() in addition to value= to fine tune how each value may be polished.

For example, content(value=) handles the plot1 and tbl1 objects created below.

library(ggplot2)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(flextable)

plot1 <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
tbl1  <- mtcars |> select(mpg, disp) |> slice(1:5) |> flextable()

Placeholders

The second part of what content() needs is information about where to inject the display. mirage offers ways to precisely specify the placeholder depending on if you intend to target a placeholder from the layout or create one from scratch. This is described in the dedicated vignette.

But for the purpose of this document, we only cover the set of predefined placeholders for the most common cases which generally are good enough: - ph_title(), ph_subtitle() to target Title or SubTitle - ph_body(), ph_body_left() and ph_body_right() to target body placeholders, or more specifically left-most or right-most - ph_footer(), ph_footer_left() and ph_footer_right() for footer placeholders

These templated placeholders have carefully selected defaults to first prioritize existing placeholders in the slide or the slide layout, and if no match is found use the predefined settings to create a new placeholder.

Saving the document

As we’ve loaded the document with load_pptx(), we can save it with save_pptx().

save_pptx(pptx, path = "updated_deck.pptx")

Wrapping it all together

Now that we’ve covered how to create a powerpoint presentation from a template, add slides, add displays to them, and save the document back to the file system, we can put it all together as a simple script that creates a simple presentation.

library(mirage)
library(ggplot2)
library(dplyr)
library(flextable)

plot1 <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
tbl1  <- mtcars |> select(mpg, disp) |> slice(1:5) |> flextable()

pptx <- load_pptx() |> 
  add_slide("Title Slide") |> 
  add_slide("Comparison")

pptx <- pptx |> 
  update_slide(index = 1, 
    content("Title",     ph = ph_title()), 
    content("Sub title", ph = ph_subtitle())
  ) |> 
  update_slide(index = 2, 
    content(plot1, ph = ph_body_left()), 
    content(tbl1,  ph = ph_body_right())
  )
#> → mirage to add 2 contents at slide 1.
#>  Successfully added content to placeholder "Title 1".
#>  Successfully added content to placeholder "Subtitle 2".
#> → mirage to add 2 contents at slide 2.
#>  Successfully added content to placeholder "Content Placeholder 3".
#>  Successfully added content to placeholder "Content Placeholder 5".

# save_pptx(pptx, "//somewhere/over/the/rainbow.pptx")

Alternatively, we can also take advantage of the fact that add_slide() can directly handle the content() calls, which has the side benefits of: - visually having the layout closer to the displays - avoid having to mentally map which slide is which.

The script can then be rewritten in a more concise and expressive form:

library(mirage)
library(ggplot2)
library(dplyr)
library(flextable)

plot1 <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
tbl1  <- mtcars |> select(mpg, disp) |> slice(1:5) |> flextable()

pptx <- load_pptx() |> 
  add_slide("Title Slide", 
    content("Title",     ph = ph_title()), 
    content("Sub title", ph = ph_subtitle())        
  ) |> 
  add_slide("Comparison", 
    content(plot1, ph = ph_body_left()), 
    content(tbl1,  ph = ph_body_right())       
  )
#> → mirage to add 2 contents at slide 1.
#>  Successfully added content to placeholder "Title 1".
#>  Successfully added content to placeholder "Subtitle 2".
#> → mirage to add 2 contents at slide 2.
#>  Successfully added content to placeholder "Content Placeholder 3".
#>  Successfully added content to placeholder "Content Placeholder 5".
# save_pptx(pptx, "//somewhere/over/the/rainbow.pptx")