Custom Templates

Introduction

The main purpose of onbrand is to create an abstraction layer that allows for the same reporting workflow to be used with different document templates. In order to do this, the abstraction information (or mapping) needs to be provided in a yaml configuration file. The process will be detailed below, but at a high level it involves the following steps:

  1. Read in a template using the function: onbrand::view_layout()
  2. Use the resulting files to create the mapping (saved as a .yaml)
  3. Test the mapping for accuracy using the function: onbrand::preview_template()

The following sections describe this process in detail for both Word and PowerPoint documents. Before you get started, copy the provided examples into your current working directory. To do so, use the following code:

library(onbrand)
file.copy(system.file(package="onbrand","examples","example.pptx"), ".", overwrite = TRUE)
file.copy(system.file(package="onbrand","examples","example.docx"), ".", overwrite = TRUE)
file.copy(system.file(package="onbrand","examples","example.yaml"), ".", overwrite = TRUE)

This will create the following files:

Mapping and the yaml file format

Before we start discussing how to create templates we need to talk a little bit about the yaml file format (and it’s recursive nature). If you already understand this, feel free to skip ahead to the relevant section below.

onbrand utilizes the yaml file as a method for describing information in a hierarchical manner using key/value pairs. To help understand this better, consider the following example where the colors of the different parts a tree are listed in a hierarchy based on where the parts are located on the tree:

tree colors:
  roots:
    - white 
    - brown
  trunk:
    bark: brown
  crown:
    branches:
      leaves:  green
      flowers: red

This example lays out key: value pairs based on the formatting of the file. The key is followed by both a colon and a space (:) which are, in turn, followed by the value.

The main key in the example above is tree colors. This key has three values: roots, trunk, and crown. One for each section of a tree. The hierarchy comes from the indentation. Each of the main sections of a tree are indented two spaces. Each of these values (roots, trunk, and crown) are also keys themselves because they end with both a colon and a space - and are followed by still more values.

The color values associated with roots are white and brown. The root hierarchy is complete.

The trunk has value bark. But, because bark is also indented two spaces and is followed by both a colon and a space, it is also a key with value brown. Which completes the trunk hierarchy.

The value crown is indented two spaces and followed by both a colon and a space. Hence, crown is a key with value branches. Again, branches is indented and followed by both a colon and a space. Then, branches is also a key with values: leaves and flowers. Each of these are also indented and followed by by both a colon and a space. So the key leaves has value green. Similarly, key flowers has value red. This completes the crown hierarchy.

There is more that can go into a yaml file, but this should be enough to help you understand how to create mapping files for onbrand. For more details see yaml.org.

PowerPoint

This section provides a detailed walk-through for each of the three steps in the Introduction. We recommend everyone walk through this process at least once.

A quick note about terminology. A slide master is the top slide in a hierarchy of slides that stores information about the theme and slide layouts of a presentation, including the background, color, fonts, effects, placeholder sizes, and positioning. The slide master is the largest slide image at the top of the slide thumbnail list.

PowerPoint Slide Master Hierarchy.
PowerPoint Slide Master Hierarchy.

Step 1: Read the PowerPoint template

To create your custom abstraction layer for PowerPoint, you start by reading in your master template. If you don’t already have one, create a PowerPoint template master slide with slide layouts for each of the different layouts you want to use. In this example, we have the Office Theme Master Slide with two slide layouts:

  1. a title slide named: title
  2. a content slide with two columns of information named: two_col

Tip When you make slide layouts under a master, give each of them a descriptive name that will be easy to use when you are coding later. These names will be used to refer to them within scripts.

PowerPoint assigns read-only names to every placeholder within each slide layout. To reveal those read-only names, create an annotated slide deck using the onbrand::view_layout() function:

library(onbrand)
vlres = view_layout(template    = "example.pptx", 
                    output_file = "example_layout.pptx")

This will create the file example_layout.pptx. It contains a slide for each slide layout (title & two_col) under the master (Office Theme) in the input template file (example.pptx). On each slide, the names of both the slide layout and slide master will be indicated in the upper right corner. Each placeholder within the slide layout will be shown and is identified by the placeholder label (ph_label). For each placeholder within each slide layout under a slide master, onbrand::view_layout() produces three pieces of information: ph_label, type, and index. Notice, there are plenty of duplicate placeholder names.

Step 2: Create the PowerPoint mapping

Before we get to the mapping, take a moment to locate and open the example.yaml file we copied over at the start of this vignette. In the yaml file there will be a key for mapping PowerPoint templates (rows 1-39 in the file). This key is called rpptx and it will have three values (which are also keys):

  • master - Holds the name of the master slide
  • templates - Has an element for each slide layout you want to use in the template
  • md_def - Default formatting for when markdown formatting is being used

Within the hierarchy of rpptx: templates: there is a value for each slide layout: title and two_col.

Remember the tip in Step 1 about names? The name you provided becomes the key value in the yaml. It’s used to reference the placeholders on the slide in your code.

Notice, the example.yaml doesn’t contain all of the placeholders for either slide in the example_layout.pptx. This is because those elements were inherited from the master slide and are not unique to either of the slide layouts.

In the yaml, each placeholder will have two value pairs below it. For example, the placeholder sub_title in slide layout title has both ph_label and content_type. The ph_label maps to the ph_label from the annotated layout (in the example_layout.pptx). The content_type should be either text or list depending on whether the placeholder contains text or list data.

The figure below shows how the annotated layout relates to the yaml mapping file.

Relationship between slide master names, placeholders, and content type and yaml mapping elements.
Relationship between slide master names, placeholders, and content type and yaml mapping elements.

Note: You only have to define mapping information for the slide layouts under a master you want to access in R. You can have as many masters defined in the template as you want and only use a subset in R.

Defining markdown defaults

Now you need to define the defaults for rendering components with markdown (see the Workflow vignette for more information on how this is used). For this you need to create elements in the following hierarchy:

rpptx:
  md_def:
    default:      
      color:                 black
      font.size:             12
      bold:                  TRUE
      italic:                FALSE
      underlined:            FALSE
      font.family:           Helvetica
      vertical.align:        baseline
      shading.color:         transparent
    Table_Labels:
      color:                 black
      font.size:             12
      bold:                  TRUE
      italic:                FALSE
      underlined:            FALSE
      font.family:           Helvetica
      vertical.align:        baseline
      shading.color:         transparent
  post_processing:           NULL

For PowerPoint templates you need to define the sections: default and Table_Labels. The default is used when rendering general markdown text. The Table_Labels is used when markdown is present in table elements like headers. For each of these you need to define the different aspects of fonts. If you’re unsure, just leave them with the defaults above.

Post-processing

rpptx:
  post_processing:           NULL

Sometimes you may wish to modify the underlying officer object. When you call save_report(), just before writing the file, the function will look for the field post_processing. Here you can define R code to modify the officer object. Within the post-processing environment the officer object rpt containing your report will be available. You should modify this object to apply any changes you want made. If the post_processing element is missing or has a value of NULL the post-processing step will be skipped.

Step 3: Testing and previewing your template

In R you can read your template by supplying the template and mapping file names:

 obnd = read_template(template = "example.pptx", 
                      mapping  = "example.yaml")

When a template is read, onbrand will check for basic errors. Look for messages in the console to help you debug any issues you may have.

After reading in the template, you can test the template using onbrand::preview_template(). Tip Save the obnd report to a file and view it to make sure the mappings are what you expect.

obnd = preview_template(obnd)
save_report(obnd, "example_preview.pptx")

That’s it. You have completed the PowerPoint example and used onbrand to create an abstraction layer for use in your own efforts. Keep in mind, this is a very straightforward example. Depending on the complexity of the template the annotated slide deck generated using onbrand::view_layout() will probably not look nearly as clean. All of the placeholders will be there; they may not be formatted as nicely. Expect to have to find the annotations you are interested in using in your mapping.

Word

This section provides a detailed walk-through for each of the three steps in the Introduction. Once again, we recommend everyone walk through this process at least once. In fact, we assume you have already worked through the PowerPoint section. If you have not and don’t feel very comfortable with abstraction layers and yaml syntax, then you might want to walk through that section first.

Another quick note about terminology. All Word documents, even a blank document, start from a template. Where PowerPoint templates are more closely tied to specific slide layouts, Word templates are files that help you design documents. They contain content and design elements (referred to as content blocks or styles) to use as a starting point when creating a document. All the formatting is complete; you simply add what you want to them.

Step 1: Read the Word document

To create your custom abstraction layer for Word, you start by reading in a Word document saved from the template you are using. This Word document should have all the styles defined and contain all the placeholders you want to use. In the example.docx there is one paragraph style and one table style.

Placeholder can be used in documents. For example, if you wanted to use this template for reports, and you wanted to have “Report NNNN”, where NNNN is the report number, in the right header. Then place a text placeholder, e.g., “Report ===RPTNUM===”, in the right header. This placeholder will be referenced in your code; the Creating Templated Office Workflows Vignette has more details.

Note: Do not type this placeholder text directly into the Word document. Cut and paste the text into the Word document from a text editor. Word is not a text editor, so while the text string may appear to be contiguous, it may not be so in the underlying XML code.

To view all of the styles in the document you can use the onbrand::view_layout() function here as well:

library(onbrand)
vlres = view_layout(template    = "example.docx", 
                    output_file = "example_layout.docx")

This will produce a word document, example_layout.docx that looks something like this: