# Templated Workflows

# Introduction

The `officer` package is used to generate all of the underlying PowerPoint and Word documents. The purpose of `onbrand` is to provide an abstraction layer (or mapping) for the functions in `officer` in order to allow the same reporting workflow to be used with different template documents. This involves providing a consistent customizable method to interact with templates as well as a form of markdown to control the formatting of text.

If you want to use your own Office templates, we recommend you see the Custom Office Templates Vignette. This vignette focuses on how to construct workflows using templates. Here we will use the internal templates embedded in `onbrand`. If you want to copy them locally you can use the following commands:

    file.copy(system.file(package="onbrand", "templates", "report.pptx"), "report.pptx")
    file.copy(system.file(package="onbrand", "templates", "report.docx"), "report.docx")
    file.copy(system.file(package="onbrand", "templates", "report.yaml"), "report.yaml")

## PowerPoint

### Loading your presentation template

To create a new `onbrand` object for a PowerPoint document you need to use `onbrand::read_template()`. This requires that you supply the path to your PowerPoint document and the `yaml` mapping files as follows:

    obnd = read_template(
           template = file.path(system.file(package="onbrand"), "templates", "report.pptx"),
           mapping  = file.path(system.file(package="onbrand"), "templates", "report.yaml"))

### Adding content to placeholders

The mapping file (printed at the bottom of this document) uses descriptive names for slide masters and placeholders. Here is a snippet from our report `yaml`.

    rpptx:
      master: Office Theme
      templates:
        title_slide:
          title:
            ph_label:     Title 1
            content_type: text
          sub_title:
            ph_label:     Subtitle 2
            content_type: text

To add content, use `onbrand::report_add_slide()`. The following will add a slide using the templated `title_slide` layout. Provide the `elements` argument with a list of placeholder names - each containing a list of values for both `content` and `type`. For each placeholder name listed you need to specify the content and the type of content in its own list:

    obnd = report_add_slide(obnd,
      template = "title_slide",
      elements = list(
         title     = list( content = "Onbrand PowerPoint Example",
                           type    = "text"),
         sub_title = list( content = "Workflow Abstraction",
                           type    = "text")))

For a detailed description of the different types of content and the expected format see the help for the `onbrand::add_pptx_ph_content()` function. Briefly, you can specify the following content types:

- `"text"` - a string of text (only possible when the type in the mapping file is text)
- `"list"` - list of information (only possible when the type in the mapping file is list)
- `"imagefile"` - string containing the path to an image file
- `"ggplot"` - a ggplot object
- `"table"` - list containing table content and other options
- `"flextable"` - list containing flextable content and other options
- `"flextable_object"` - user-defined flextable object

#### Lists

The previous example showed how to add text content. To add a list, define a vector with paired content of the format `c("indent level", "content", "indent level", "content)`. Where `indent level` indicates a numeric value starting at 1. For example, we could define the following list content:

    bl = c("1", "This is first level bullet",
           "2", "sub-bullet",
           "3", "sub-sub-bullet",
           "3", "can't have just one sub-sub-bullet",
           "2", "same goes for sub-bullets",
           "1", "Another first level bullet")

The list `bl` can then be added to the content value of any placeholder with `list` as the type in the mapping file:

    obnd = report_add_slide(obnd,
      template = "content_list",
      elements = list(
         title        = list( content = "Adding List Content",
                              type    = "text"),
         content_body = list( content = bl,
                              type    = "list")))

#### Figures

Figures can be added in two ways:

1. as an image file (e.g. a png)
2. as a ggplot object (preferred method)

Generally, the ggplot object is preferred as it will automatically size according to the dimensions of the placeholder. First lets create some images:

    library(ggplot2)
    p = ggplot() + annotate("text", x=0, y=0, label = "picture example")
    imgfile = tempfile(pattern="image", fileext=".png")
    ggsave(filename=imgfile, plot=p, height=5.15, width=9, units="in")

Now that the object `p` contains the ggplot object and `imgfile` points to a png file containing that image, we can add the content to our `two_content_header_text` slide template:

    obnd = report_add_slide(obnd,
      template = "two_content_header_text",
      elements = list(
         title                = list(content  = "Adding Images Content",
                                     type     = "text"),
         content_left_header  = list(content  ="ggplot object",
                                     type     = "text"),
         content_left         = list(content  = p,
                                     type     = "ggplot"),
         content_right_header = list(content  ="image file",
                                     type     = "text"),
         content_right        = list(content  = imgfile,
                                     type     = "imagefile")))

#### Tables

Tables can be supplied in three different ways, each providing increasing level of control over the output:

- `table` - Expects a list with the tabular data and other attributes. It uses the underlying tables in PowerPoint to make the tables.
- `flextable` - Expects a list similar to the `table` above, but instead of using the PowerPoint tables, the table is created using the `flextable` package.
- `flextable_object` - This allows you to create a flextable on your own and use it directly. The ultimate level of control.

Lets start by creating a simple data frame:

    tdf = data.frame(Parameters = c("Length", "Width", "Height"),
                     Values     = 1:3,
                     Units      = c("m", "m", "m") )

To create a PowerPoint table, use the `table` content type. Construct a named list with a single element, `table`, containing the data frame; `tab_cont = list(table = tdf)`. You can add list elements to display header information as well. See the help for `onbrand::add_pptx_ph_content()` for details.

    tab_cont = list(table = tdf)
    obnd = report_add_slide(obnd,
      template = "content_text",
      elements = list(
         title         = list( content      = "Tables",
                               type         = "text"),
         sub_title     = list( content      = "Creating PowerPoint Table",
                               type         = "text"),
         content_body  = list( content      = tab_cont,
                               type         = "table")))

Sometimes you may want to have a little more control over the tabular output. The `flextable` type allows you to supply the data and information about the flextable to be created and `onbrand` will then use them to create the flextable for you.

    tab_ft = list(table         = tdf,
                  header_format = "md",
                  header_top    = list(Parameters = "Name^2^",
                                       Values     = "*Value*",
                                       Units      = "**Units**"),
                  cwidth        = 0.8,
                  table_autofit = TRUE,
                  table_theme   = "theme_zebra")

Here we are specifying that we want the header format of the table to be rendered as markdown `"md"` and we are specifying that the top header (there can be top, middle and bottom) should be overwritten (for more on formatting with markdown see the markdown section below). Next we specify some other details like the column width. Again reference the help for `onbrand::add_pptx_ph_content()`. It covers the details of the list elements that can be supplied.

Alternatively, you can create a flextable object directly using the `flextable` package. There is an enormous amount of flexibility in the `flextable` package. Some of these can be seen in the Word examples below, but you should see the documentation for that package to get a feel for what is possible.

    tab_fto = flextable(tdf)

You can then add these (flextable list: `tab_ft`, flextable object: `tab_fto`) to any of the placeholders on a slide:

    obnd = report_add_slide(obnd,
      template = "two_content_header_text",
      elements = list(
         title                 = list( content      = "Tables",
                                       type         = "text"),
         sub_title             = list( content      = "flextables can be created in two ways",
                                       type         = "text"),
         content_left_header   = list( content      = 'using "flextable"',
                                       type         = "text"),
         content_left          = list( content      = tab_ft,
                                       type         = "flextable"),
         content_right_header  = list( content      = 'using "flextable_objecct"',
                                       type         = "text"),
         content_right         = list( content      = tab_fto,
                                       type         = "flextable_object")))

### Adding content in user-defined locations

If you want to place content in arbitrary locations on the slide you can use the `user_location` argument to `report_add_slide()`. The content and type is the same as above. You also need to supply a start and stop point. These are x-y coordinates as measured from the upper left point on the slide and they define the box where the content will be inserted. They represent fractions of the total slide width (x) and height (y):

    obnd = report_add_slide(obnd,
      template = "two_content_header_list",
      elements = list(
         title         = list( content      = "Combining elements, user defined locations, and formatting",
                               type         = "text")),
      user_location = list(
         txt_example   =
           list( content        = fpar(ftext("This is formatted text", fp_text(color="green", font.size=24))),
                 type           = "text",
                 start          = c(0,  .25),
                 stop           = c(.25,.35)),
         large_figure  =
           list( content        = p,
                 type           = "ggplot",
                 start          = c(.25,.25),
                 stop           = c(.99,.99)),
         flextable_obj  =
           list( content        = tab_fto,
                 type           = "flextable_object",
                 start          = c(0,.75),
                 stop           = c(.25,.95)),
         small_figure  =
           list( content        = p,
                 type           = "ggplot",
                 start          = c(0,  .35),
                 stop           = c(.25,.74))
      )
    )

Note that you can use both `elements` and `user_location` together.

### Saving presentations

Once you are done adding content you can save the presentation to a file:

    save_report(obnd, "vignette_presentation.pptx")

Which should look something like this:

### Accessing the PowerPoint mapping information

Sometimes it can be difficult to remember the template and placeholder names from the mapping file. You and use the `onbrand::template_details` function to show this information for the current `onbrand` object.

    details = template_details(obnd)

    Mapping:     /private/var/folders/pq/7srbf_fx3rd3k706hgxkg61r0000gp/T/Rtmp2ooQjC/Rinst12ee5e1a7332/onbrand/templates/report.yaml
    Report Type: PowerPoint
    title_slide (master/template)
      > title (text)
      > sub_title (text)
    section_slide (master/template)
      > title (text)
      > sub_title (text)
    title_only (master/template)
      > title (text)
    content_text (master/template)
      > title (text)
      > sub_title (text)
      > content_body (text)
    content_list (master/template)
      > title (text)
      > sub_title (text)
      > content_body (list)
    two_content_header_list (master/template)
      > title (text)
      > sub_title (text)
      > content_left_header (text)
      > content_left (list)
      > content_right_header (text)
      > content_right (list)
    two_content_header_text (master/template)
      > title (text)
      > sub_title (text)
      > content_left_header (text)
      > content_left (text)
      > content_right_header (text)
      > content_right (text)
    two_content_list (master/template)
      > title (text)
      > sub_title (text)
      > content_left (list)
      > content_right (list)
    two_content_text (master/template)
      > title (text)
      > sub_title (text)
      > content_left (text)
      > content_right (text)

If you do not want to use the interfaces above for creating slides but would like to use the named mapping information in a more traditional `officer` workflow you can use the function `fph`. After you’ve loaded the `onbrand` object above (`obnd`) you can then pull out the placeholder label from PowerPoint for any named placeholder in a template layout specified in the yaml mapping file. For example if we wanted the placeholder label for the `content_left_header` in the `two_content_header_text` layout we would use the following:

    ph = fph(obnd, "two_content_header_text", "content_left_header")$pl

## Word

### Loading your Word template

The `onbrand::read_template()` function is also used to create a new `onbrand` object for a Word report. Just as before, you need to supply the path to your Word template and the mapping file. This example points to files within the `onbrand` package:

    obnd = read_template(
      template = file.path(system.file(package="onbrand"), "templates", "report.docx"),
      mapping  = file.path(system.file(package="onbrand"), "templates", "report.yaml"))

### Adding content

Word report content is added using the `onbrand::report_add_doc_content()` function. This expects the user to identify the `type` of content being supplied. At a high level the following types of content can be added:

- `"break"` - page break
- `"toc"` - table of contents
- `"ph"` - text content to substitute for placeholders in the document
- `"text"` - text supplied as either character string, markdown or the result of `officer::fpar()` statements
- `"imagefile"` - string containing the path to an image file
- `"ggplot"` - a ggplot object
- `"table"` - list containing table content and other options
- `"flextable"` - list containing flextable content and other options
- `"flextable_object"` - user-defined flextable object

Similar to adding PowerPoint content, you must also supply a list containing the content and information about the content. Examples of each of these will be provided in the sections below. However you should see the help for `onbrand::report_add_doc_content()` to get a detailed explanation of the format of `content`.

### Table of contents

A table of contents, list of figures, or list of tables is added using the content type `"toc"`. You can supply a level and/or an `onbrand` style. If you supply a level, the TOC will be generated down to that header level. If you supply an `onbrand` style, the TOC will include each element with that style. So if you wish to generate separate lists of tables and figures it is important that your `onbrand` styles for those point to different Word styles.

This will add a typical TOC:

    obnd = report_add_doc_content(obnd,
      type     = "toc",
      content  = list(level=3))

While this should add the list of tables:

    obnd = report_add_doc_content(obnd,
      type     = "toc",
      content  = list(style="Table_Caption"))

And this should add a list of figures:

    obnd = report_add_doc_content(obnd,
      type     = "toc",
      content  = list(style="Figure_Caption"))

Note: If you try to update the TOCs and you get the following:

No table of contents entries found.

You may need to change the separator option in the `yaml` mapping file from: `,` to `;`.

### Text

The content type `"text"` is the most straight forward way to add content to a Word document, and the `content` is a list that has three possible elements. The only one required is the `text` element. If you just want to add text in the default format (`doc_def` in the `yaml` mapping file), then this is all you need to do:

    obnd = report_add_doc_content(obnd,
      type     = "text",
      content  = list(text="Text with no style specified will use the doc_def text format. This is a 'ph' placehoder for text: ===BODY-TEXT-EXAMPLE=== [see Placeholder text section below]"))

#### Styles

Alternatively you can specify any style defined in the `yaml` mapping file by adding a `style` element to the content list. This shows how to create multi-level headers:

    obnd = report_add_doc_content(obnd,
      type     = "text",
      content  = list(text  ="First level header",
                      style = "Heading_1"))
    obnd = report_add_doc_content(obnd,
      type     = "text",
      content  = list(text  ="Second level header",
                      style = "Heading_2"))
    obnd = report_add_doc_content(obnd,
      type     = "text",
      content  = list(text  ="Third level header",
                      style = "Heading_3"))

Note: If you want to use table and figure caption numbers that use section numbers (e.g. 1-1, 1-2, etc.) you may want/need to reset the figure counter for each major section. To do this you will need to use the `fig_start_at` and `tab_start_at` arguments to reset the counters for that section.

#### Formats

The other element you may want to control is the format of the content. In the previous examples you just needed to provide character data, but there are three possible formats you can use:

- `"text"` - character string (previous examples)
- `"md"` - character string with markdown to be rendered (see the section on markdown below)
- `"fpar"` - `officer::fpar()` object from `officer` (used with paragraph text)
- `"ftext"` - list of `officer::ftext()` objects `officer` (used with captions and notes for figures and tables)

The following provide example `"fpar"` and `"md"` formats

    library(officer)

    fpartext = fpar(
    ftext("Formatted text can be created using the ", prop=NULL),
    ftext("fpar ", prop=fp_text(color="green")),
    ftext("command from the officer package.", prop=NULL))

    obnd = report_add_doc_content(obnd,
      type     = "text",
      content  = list(text   = fpartext,
                      format = "fpar",
                      style  = "Normal"))

    mdtext = "Formatted text can be created using **<color:green>markdown</color>** formatting"
    obnd = report_add_doc_content(obnd,
      type     = "text",
      content  = list(text   = mdtext,
                      format = "md",
                      style  = "Normal"))

### Figures

Similar to the PowerPoint example above we’re going to create some figures. Both an image file (`imgfile`) and a ggplot object (`p`):

    p = ggplot() + annotate("text", x=0, y=0, label = "picture example")
    imgfile = tempfile(pattern="image", fileext=".png")
    ggsave(filename=imgfile, plot=p, height=5.15, width=9, units="in")

We can add these by specifying the appropriate content type. The content list can contain different information. Typically you would either specify the image file or ggplot object as well as a caption:

    obnd = report_add_doc_content(obnd,
      type     = "imagefile",
      content  = list(image   = imgfile,
                      caption = "This is an example of an image from a file."))

    obnd = report_add_doc_content(obnd,
      type     = "ggplot",
      content  = list(image   = p,
                      caption = "This is an example of an image from a ggplot object."))

### Tables

Tables in Word are similar to the tables in PowerPoint. The table type can be either `table`, `flextable`, or `flextable_object`. Lets look at this data frame to see how to use each of these:

    tdf =    data.frame(Parameters = c("Length", "Width", "Height"),
                        Values     = 1:3,
                        Units      = c("m", "m", "m") )

To insert a native Word table, you would use the `table` type and the content is just a list with an element named `table` that has the value of a dataframe. As with figures, the content list can have an optional caption as well.

    tab_cont = list(table   = tdf,
                    caption = "Word Table.")
    obnd = report_add_doc_content(obnd,
      type     = "table",
      content  = tab_cont)

Flextables can be used with the `flextable` type and information like headers, header formatting, etc can be passed along. `onbrand` will then construct the flextable for you.

    tab_ft = list(table         = tdf,
                  header_format = "md",
                  header_top    = list(Parameters = "Name^2^",
                                       Values     = "*Value*",
                                       Units      = "**Units**"),
                  cwidth        = 0.8,
                  table_autofit = TRUE,
                  caption       = "Flextable from onbrand abstraction",
                  table_theme   = "theme_zebra")
    obnd = report_add_doc_content(obnd,
      type     = "flextable",
      content  = tab_ft)

Lastly, to have the most control over the table you can construct a flextable yourself and pass that along in the content.

    tab_fto = flextable(tdf)
    obnd = report_add_doc_content(obnd,
      type     = "flextable_object",
      content  = list(ft=tab_fto,
                      caption  = "Flextable object created by the user."))

### Formatting sections

Section formatting, changing the page orientation and/or the number of columns, is controlled using the `"section"` content type. It may seem a bit counter intuitive but sections apply to the content added since the last section type specification. So now lets try the following:

- Add a landscape figure
- Add two column text
- Add more content in portrait orientation

To change formatting we need to close out the current section by inserting a portrait section type:

    obnd = report_add_doc_content(obnd,
         type     = "section",
         content  = list(section_type  ="portrait"))

Then we add the content we want in landscape mode:

    obnd = report_add_doc_content(obnd,
      type     = "ggplot",
      content  = list(image   = p,
                      height  = 2.5,
                      width   = 9,
                      caption = "This is a landscape figure."))

Now we tell the underlying report to apply landscape formatting to everything that has been added since the portrait section type:

    obnd = report_add_doc_content(obnd,
      type     = "section",
      content  = list(section_type  ="landscape",
                      height        = 8,
                      width         = 10))

Now we want to add the text for the two column format:

    obnd = report_add_doc_content(obnd,
      type     = "text",
      content  = list(text    = paste(rep("Some two column text.", 200), collapse=" ")))

Now we insert a section indicating that we want to change the section to multiple columns. The number of columns is inferred from the number of elements in the `widths` argument:

    obnd = report_add_doc_content(obnd,
      type     = "section",
      content  = list(section_type  ="columns",
                      widths        = c(3,3)))

We can now add content but don’t forget to set the insert a portrait section at the end just before you save the document.

    obnd = report_add_doc_content(obnd,
      type          = "text",
      content       = list(text    = "Back to regular portrait"))

### Placeholder text

When generating reporting workflows it can be helpful to have placeholder text in the report that is populated based on the specifics of that report. To add placeholders you can use the `"ph"` content type. This content type will not appear in the `yaml` file, it is unique to `onbrand`. A placeholder is a unique string of text surrounded on both sides by `===` (three equal signs). If the placeholder is in your template document, it may not work correctly if you type the text into Word. This is because while a string may appear to be a contiguous in Word, it may not be so in the underlying XML code. To ensure the string is contiguous you should type the placeholder text into a text editor, then copy and paste it into the Word template.

The placeholder can be in the document template itself (in the footer or header sections) or in the text you generate and add as part of your workflow. In this example, the text `===BODY-TEXT-EXAMPLE===` was added into the text content we added in the first step above. That placeholder will be replaced with the text `Swaps the placeholder with this Text`.

    obnd = report_add_doc_content(obnd,
      type     = "ph",
      content  = list(name     = "BODY-TEXT-EXAMPLE",
                      value    = "Swaps the placeholder with this Text",
                      location = "body"))

You can have the placeholders in the body as in the previous example and also in the headers and footers of the document. Again, these will not appear in the `yaml` mapping (or abstraction layer). In these examples the `===FOOTERLEFT===` and `===HEADERLEFT===` placeholders are found in the template itself. There is another placeholder `===HEADERRIGHT===` which we have not used so that you can see it in the final output.

    obnd = report_add_doc_content(obnd,
      type     = "ph",
      content  = list(name     = "FOOTERLEFT",
                      value    = "Text Swapped with Footer Placeholder",
                      location = "footer"))
    obnd = report_add_doc_content(obnd,
      type     = "ph",
      content  = list(name     = "HEADERLEFT",
                      value    = "Text Swapped with Header Placeholder",
                      location = "header"))

Headers are applied when the document is saved and can be added at any time to the `onbrand` report object.

### Formatting sections (again)

Recall up above that we were in a multi-column page format, but we wanted to return to the default portrait single column format. We added text but before we save the file we need to tell the document to apply the new section type:

    obnd = report_add_doc_content(obnd,
      type     = "section",
      content  = list(section_type  ="portrait"))

Note: that if you don’t alter the page format/layout from the document default, then you do not need to add any section content.

### Multi-page figures and tables

Some figures and tables need to span multiple pages. If you have a large `flextable` it will do that automatically. However it may be more desirable to have a caption on each page with the figure or table. To accomplish this, using a figure as an example you need to create a separate figure for each page. For each figure you will need to provide the same key value. The first figure with that key will be assigned a figure number and the other figures with that key will have the same number that references the first.

    obnd = report_add_doc_content(obnd,
      type     = "ggplot",
      content  = list(image           = p,
                      notes_format    = "text",
                      key             = "ex_fig_text",
                      notes           = "This figure shows how to use text captions _and_ notes",
                      caption_format  = "text",
                      caption         = "Multi-page figure (page 1)"))

    obnd = report_add_doc_content(obnd,
      type     = "break",
      content  = NULL)

    obnd = report_add_doc_content(obnd,
      type     = "ggplot",
      content  = list(image           = p,
                      notes_format    = "text",
                      key             = "ex_fig_text",
                      notes           = "This figure shows how to use text captions _and_ notes",
                      caption_format  = "text",
                      caption         = "Multi-page figure (page 2)"))

### Cross referencing figures and tables

When figures and tables are created above each content list has an optional key. In the example from the last section we created the key `"ex_fig_text"`. To reference in the word document you have two options. You can construct your content using onbrand markdown. Then you simply need to use the `ref` tag: `<ref:ex_fig_text>` and the figure number will be replaced when the document is built. You can also use the `officer::fpar()` function to construct content. Then you would use the officer command `officer::run_reference()` and the figure key to insert the figure number.

### Saving the Word report

Once you are done adding content you can save the report to a file with the `save_report()`` function as well:

    save_report(obnd, "vignette_report.docx")

The output from the example above should look like this:

Example Word output for workflow above.

### Accessing the Word mapping information

It can also be useful to quickly access the `onbrand` style names. You can use the same `onbrand::template_details` function to display the current styles available to you:

    details = template_details(obnd)

    Mapping:     /private/var/folders/pq/7srbf_fx3rd3k706hgxkg61r0000gp/T/Rtmp2ooQjC/Rinst12ee5e1a7332/onbrand/templates/report.yaml
    Report Type: Word
      onbrand style (word style, style type)
      --------------------------------------
      Code (Code, paragraph)
      Figure_Caption (graphic title, paragraph)
      Heading_1 (heading 1, paragraph)
      Heading_2 (heading 2, paragraph)
      Heading_3 (heading 3, paragraph)
      Normal (Normal, paragraph)
      Notes (Notes, paragraph)
      TOC (toc 1, paragraph)
      Table_Caption (table title, paragraph)
      Table (Table Grid, table)

As with the PowerPoint interface, you can also access the named Word mapping directly. This is done through the `fst` function. With the `onbrand` objected loaded (`obnd`) you can supply an `onbrand` style name and pull out the Word style name (`wsn`) and the default font format (`dff`):

    st = fst(obnd, "Heading_3")
    #Word style name
    wsn = st$wsn
    # Default font format
    dff = st$dff

## Formatting with markdown

In `officer` you can change formatting in text using `fpar` and `as_pargraph`. There are situations where this is less than ideal. For example if you want to take formatted user input from a Shiny app, it may not be practical to have them supply code this way.

To make formatting a little easier, `onbrand` provides the ability to use markdown. This can be seen above in flextable objects for PowerPoint content and with text, captions in Word. For a list of allowed markdown formatting see the help for `onbrand::md_to_officer()``.

If you want to use the markdown functionality outside of `onbrand` you can use the two functions:

- `onbrand::ft_apply_md` - This function will take a flextable object an apply markdown to the portions of the table you specify.
- `onbrand::md_to_officer` - This function will take the markdown text and convert that into strings of text containing officer commands in `fpar` and `as_paragraph` commands. You simply need to use the `eval` command to execute them.
- `onbrand::md_to_oo` - A function that wraps around `md_to_officer` and returns the `as_paragraph` result.

### Using `onbrand::ft_apply_md` to format tables

First lets start with data. Here we have dimensional data listed as a mean and variance:

    data = data.frame(property = c("**<ff:symbol>m</ff>**",   "**<ff:symbol>s</ff>**^**2**^"),
                      length     = c(200,      0.13),
                      width      = c(12,       0.05),
                      area       = c(240,      0.11),
                      volume     = c(1200,     0.32))

Now lets create a flextable object with a header that shows the property being reported on one line and the units on the line below:

    header = list(property = c("",             ""),
                  length   = c("Length",       "**cm**"),
                  width    = c("Wdith",        "**cm**"),
                  area     = c("Area",         "**cm**^**2**^"),
                  volume   = c("Volume",       "**cm**^**3**^"))

    ft = flextable::flextable(data)                     |>
         flextable::delete_part(part = "header")        |>
         flextable::add_header(values =as.list(header)) |>
         flextable::theme_zebra()

That flextable currently looks like this:

| Length | Wdith | Area | Volume
--- | --- | --- | --- | ---
| **cm** | **cm** | **cm**^**2**^ | **cm**^**3**^
**<ff:symbol>m</ff>** | 200.00 | 12.00 | 240.00 | 1,200.00
**<ff:symbol>s</ff>**^**2**^ | 0.13 | 0.05 | 0.11 | 0.32

Now we want to render the markdown. We can use `ft_apply_md()` to the header and the first column:

    tab_fto = ft_apply_md(ft=ft, obnd=obnd, part = "header")
    tab_fto = ft_apply_md(ft=tab_fto, obnd=obnd, part = "body", pcols = 1)

Now the flextable object looks like this:

| Length | Wdith | Area | Volume
--- | --- | --- | --- | ---
| cm | cm | cm2 | cm3
m | 200.00 | 12.00 | 240.00 | 1,200.00
s2 | 0.13 | 0.05 | 0.11 | 0.32

Note that the Greek symbols are not rendered correctly here but will be rendered correctly in the document.

To include the newly formatted table in the `onbrand` object, you use the same method as before:

    obnd = report_add_doc_content(obnd,
      type     = "flextable_object",
      content  = list(ft=tab_fto,
                      caption  = "Flextable object with custom Markdown - created by the user."))

## Accessing the `officer` object directly

Sometimes you need more control over creating a report, and you may want to use the officer commands directly. To do this you can use the function `fetch_officer_object()` to pull out the officer object from the `onbrand` object:

Now you can use any officer command you wish on the `rpt` object. And when you’re done you can put the object back into the `onbrand` object using `set_officer_object()`:

## Mapping file

    rpptx:
      master: Office Theme
      templates:
        title_slide:
          title:
            ph_label:     Title 1
            content_type: text
          sub_title:
            ph_label:     Subtitle 2
            content_type: text
        section_slide:
          title:
            ph_label:     Title 1
            content_type: text
          sub_title:
            ph_label:     Subtitle 2
            content_type: text
        title_only:
          title:
            ph_label:     Title 1
            content_type: text
        content_text:
          title:
            ph_label:     Title 1
            content_type: text
          sub_title:
            ph_label:     Subtitle 2
            content_type: text
          content_body:
            ph_label:     Content Placeholder 2
            content_type: text
        content_list:
          title:
            ph_label:     Title 1
            content_type: text
          sub_title:
            ph_label:     Subtitle 2
            content_type: text
          content_body:
            ph_label:     Content Placeholder 2
            content_type: list
        two_content_header_list:
          title:
            ph_label:     Title 1
            content_type: text
          sub_title:
            ph_label:     Subtitle 2
            content_type: text
          content_left_header:
            ph_label:     Text Placeholder 2
            content_type: text
          content_left:
            ph_label:     Content Placeholder 3
            content_type: list
          content_right_header:
            ph_label:     Text Placeholder 4
            content_type: text
          content_right:
            ph_label:     Content Placeholder 5
            content_type: list
        two_content_header_text:
          title:
            ph_label:     Title 1
            content_type: text
          sub_title:
            ph_label:     Subtitle 2
            content_type: text
          content_left_header:
            ph_label:     Text Placeholder 2
            content_type: text
          content_left:
            ph_label:     Content Placeholder 3
            content_type: text
          content_right_header:
            ph_label:     Text Placeholder 4
            content_type: text
          content_right:
            ph_label:     Content Placeholder 5
            content_type: text
        two_content_list:
          title:
            ph_label:     Title 1
            content_type: text
          sub_title:
            ph_label:     Subtitle 2
            content_type: text
          content_left:
            ph_label:     Content Placeholder 2
            content_type: list
          content_right:
            ph_label:     Content Placeholder 3
            content_type: list
        two_content_text:
          title:
            ph_label:     Title 1
            content_type: text
          sub_title:
            ph_label:     Subtitle 2
            content_type: text
          content_left:
            ph_label:     Content Placeholder 2
            content_type: text
          content_right:
            ph_label:     Content Placeholder 3
            content_type: text
      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
    rdocx:
      styles:
        Normal:                    Normal
        Notes:                     Notes
        Code:                      Code
        TOC:                       toc 1
        Heading_1:                 heading 1
        Heading_2:                 heading 2
        Heading_3:                 heading 3
        Table:                     Table Grid
        Table_Caption:             table title
        Figure_Caption:            graphic title
      doc_def:
        Text:                      Normal
        Table:                     Table
        Table_Caption:             Table_Caption
        Figure_Caption:            Figure_Caption
        Notes:                     Notes
      formatting:
        separator:                 ","
        Table_Order:
          - table
          - notes
          - caption
        Table_Caption_Label_Pre:   "Table "
        Table_Caption_Label_Post:  ". "
        Figure_Order:
          - figure
          - notes
          - caption
        Figure_Caption_Label_Pre:  "Figure "
        Figure_Caption_Label_Post: ". "
        Figure_Width:              6.0
        Figure_Height:             5.0
        Figure_Seq_Id:             "Figure"
        Figure_Number: |-
          list(officer::run_autonum(pre_label  = "",
                                    seq_id     = Caption_Seq_Id,
                                    post_label = "",
                                    start_at   = Caption_Start_At))
        Table_Seq_Id:              "Table"
        Table_Number: |-
          list(officer::run_autonum(pre_label  = "",
                                    seq_id     = Caption_Seq_Id,
                                    post_label = "",
                                    start_at   = Caption_Start_At))
      md_def:
        # For each style above you need a default specification here. You will
        # also need the 'default' specification, generally just a copy of Normal
        default:
          color:                  black
          font.size:              12
          bold:                   FALSE
          italic:                 FALSE
          underlined:             FALSE
          font.family:            Cambria (Body)
          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
        Notes:
          color:                  black
          font.size:              10
          bold:                   FALSE
          italic:                 FALSE
          underlined:             FALSE
          font.family:            Cambria (Body)
          vertical.align:         baseline
          shading.color:          transparent
        Normal:
          color:                  black
          font.size:              12
          bold:                   FALSE
          italic:                 FALSE
          underlined:             FALSE
          font.family:            Cambria (Body)
          vertical.align:         baseline
          shading.color:          transparent
        Code:
          color:                  black
          font.size:              12
          bold:                   FALSE
          italic:                 FALSE
          underlined:             FALSE
          font.family:            Courier
          vertical.align:         baseline
          shading.color:          transparent
        TOC:
          color:                  black
          font.size:              12
          bold:                   FALSE
          italic:                 FALSE
          underlined:             FALSE
          font.family:            Courier
          vertical.align:         baseline
          shading.color:          transparent
        Heading_1:
          color:                  black
          font.size:              16
          bold:                   TRUE
          italic:                 FALSE
          underlined:             FALSE
          font.family:            Calibri (Headings)
          vertical.align:         baseline
          shading.color:          transparent
        Heading_2:
          color:                  black
          font.size:              13
          bold:                   TRUE
          italic:                 FALSE
          underlined:             FALSE
          font.family:            Calibri (Headings)
          vertical.align:         baseline
          shading.color:          transparent
        Heading_3:
          color:                  black
          font.size:              12
          bold:                   TRUE
          italic:                 FALSE
          underlined:             FALSE
          font.family:            Calibri (Headings)
          vertical.align:         baseline
          shading.color:          transparent
        Table:
          color:                 black
          font.size:             12
          bold:                  FALSE
          italic:                FALSE
          underlined:            FALSE
          font.family:           Helvetica
          vertical.align:        baseline
          shading.color:         transparent
        Table_Caption:
          color:                 black
          font.size:             12
          bold:                  TRUE
          italic:                TRUE
          underlined:            FALSE
          font.family:           Cambria (Body)
          vertical.align:        baseline
          shading.color:         transparent
        Figure_Caption:
          color:                 black
          font.size:             12
          bold:                  TRUE
          italic:                TRUE
          underlined:            FALSE
          font.family:           Cambria (Body)
          vertical.align:        baseline
          shading.color:         transparent
      post_processing:           NULL