# Reporting nlmixr2 Fit Results

# Introduction

The purpose of `nlmixr2rpt` is to automate reporting of `nlmixr2` analyses. This is accomplished by creating a yaml file that contains reporting options, figure and table generation code, and general content for Word and PowerPoint files.

# General workflow

First we need an `nlmixr2` fit object. We’re going to load a fit example stored in this package:

    library(nlmixr2rpt)
    library(onbrand)

    # This will create an example fit object to use in the examples below
    fit = fetch_fit_example()

Next we need to create `onbrand` report objects. This will create report objects for both PowerPoint (`obnd_pptx`) and Word (`obnd_docx`).

    obnd_pptx = read_template(
      template = system.file(package="nlmixr2rpt", "templates","nlmixr_obnd_template.pptx"),
      mapping  = system.file(package="nlmixr2rpt", "templates","nlmixr_obnd_template.yaml"))

    obnd_docx = read_template(
      template = system.file(package="nlmixr2rpt", "templates","nlmixr_obnd_template.docx"),
      mapping  = system.file(package="nlmixr2rpt", "templates","nlmixr_obnd_template.yaml"))

Next we will add the report elements to the report objects using the `report_fit()` function. This function can be used with both types of report. The contents will be different depending on the document type.

    obnd_pptx = report_fit(
      fit     = fit,
      obnd    = obnd_pptx)

    obnd_docx = report_fit(
      fit     = fit,
      obnd    = obnd_docx)

This function will append the report elements for the supplied fit object to the supplied report. If you have multiple fit objects they can added sequentially. You can also add other report content using the `onbrand` and `officer` functions. Once you’re done then you just need to save the reports:

    save_report(obnd_pptx, "report.pptx")
    save_report(obnd_docx, "report.docx")

The contents of each report type is defined in a yaml file. The commands above use the default value found in the `nlmixr2rpt` package. To customize the report elements you can make a copy of the file in your current working directory:

    file.copy(system.file(package="nlmixr2rpt", "templates", "report_fit.yaml"),
              "my_report.yaml")

Then you can edit the `my_report.yaml` file and when you call `report_fit()` provide this yaml file as the `rptyaml` argument. The following section will describe the elements of the yaml report format.

# The yaml report file structure

The core of `nlmixr2rpt` is the yaml reporting file. Below we outline each of the main sections and describe the expected elements in those sections.

## `placeholders`

You may wish create your report template with placeholders. For example if you want create a generic template for population PK analysis, it may be useful to label the figures generically. You can use this section to define placeholders that will be applied when the report is created. For example consider the yaml code here:

    placeholders:
      CMPD: Compound Name
      CUNITS: Conc Units
      OBJ: sprintf("%3g", fit$objf)

When you create the report you can label your y-axis generically such as:

`"===CMPD=== (===CUNITS===)"`

But when the report is built, it will become:

`"Compound Name (Conc Units)"`

Notice that the `OBJ` placeholder contains R Code. By default the reporting process will try to evaluate the placeholders as R Code. If that fails it will revert back to the string supplied. If you run into problems you can quote your placeholder value with both double and single quotes. For example:

      ISSTR:"'ls()'"
      ISCMD: ls()

The `ISSTR` field will just result in the string `"ls()"` while the `ISCMD` field will return a list of the objects in the environment where the string is evaluated. It is also possible to overwrite the contents of this file at runtime by providing a `placeholders` (placeholder) argument to `report_fit()`.

Note: Fields that support placeholders will be indicated by [PH] and fields with evaluable code will be indicated by [EV].

## `parameters`

For certain reporting elements it may be better to present parameters differently than the parameter names being used in the model. In `nlmixr` you can use a comment after the parameter definition to specify alternate text. The function `gen_pest_table()` will use this alternate text if it is present. In the `parameters` section you have some more flexability in how parameters are reported. You can define any parameters you want here whether they are present in the model or not. They will only be used if they are present. For tables in Word or PowerPoint you can specify the names using markdown (`md`), otherwise you can specify how they will be handled in text environments (`txt`). For example the intrinsic clearance may be called `lCLint` in the model. And you can specify it as:

    parameters:
      lCLint:
        md:  "CL~int~ (L/hr)"
        txt: "CLint (L/hr)"

It is also possible to overwrite the contents of this file at runtime by providing a `parameters` argument to `report_fit()`.

Note: If you specify a parameter name here it will overwrite any alternate text specified in the model `ini()`.

## `covariates`

For figure and table generation it can be useful to have your covariates defined. You can define them here as either categorical (`cat`) or continuous (`cont`). For example to define the categorical covariates as SEX and ROUTE and the continuous covariate as WT you would do the following:

    covariates:
      cat: ["SEX", "ROUTE"]
      cont: ["WT"]

If you don’t need any covariates you can set them to `NULL`. If you want to overwrite these at runtime you can specify different values when calling `report_fit()`. These are available in the figure and table runtime environments as the objects `cat_covars` for categorical covariates and `cont_covars` for continuous covariates.

## `options`

This section allows you to control general report options. Each element here can be either an explicit value. If identified as evaluable [EV] it will first attempt to evaluate it as R code. If that fails the explicit value will be used. The following options are supported with the expected data type in parentheses:

- `output_dir`[PH,EV] - The location where figures will be generated (character)

- `resolution`[EV] - Resolution of figures being generated (numeric)

- `figenv_preamble` and `tabenv_preamble` - User-defined code evaluated before figures and tables are built (specify libraries needed, source files containing user defined code, etc.)

- `fig_stamp`[PH] - If this is set to a string it will stamp the contents of that string at the lower left portion of the figure after writing. This applies only to figures where the `p_res` object is either a vanilla `ggplot` object, a paginated `ggforce` object, or the result of `ggarrage` from the `ggpubr` package. Along with the regular placeholders, this option can also contain the `===FILE===` placeholder. This will be replaced with the full path to the figure file that is generated.

## Building `figures` & `tables`

Figures and tables are defined in terms of R code that will be evaluated. There are several objects available in the environment that can be used when creating these report elements. The following objects will be defined:

- `fid` - current figure ID (figure environment only)
- `tid` - current table ID (table environment only)
- `fit` - `nlmixr2` fit object
- `cat_covars` - character object containing the categorical covariates
- `cont_covars` - character object containing the continuous covariates
- `height` - figure height in inches (figure environment only)
- `obnd` - onbrand object of the report document
- `output_dir` - directory where figures are stored
- `resolution` - resolution of the figure (figure environment only)
- `rptdetails` - result of reading in the report yaml file
- `rpttype` - either “Word” or “PowerPoint”
- `width` - figure width in inches (figure environment only)
- `xpdb` - the default yaml file contains code in the preamble to create this object by running xpose_data_nlmixr(fit) (figure environment only)

## `figures`

The figures section consists of figure IDs. These IDs are used again when defining the Word and PowerPoint report contents. Consider this example:

    figures:
      dv_vs_pred:
        orientation:    "portrait"
        caption:        "dv_vs_pred caption"
        caption_format: "text"
        title:          "dv_vs_pred title"
        cmd: |-
          p_res <- dv_vs_pred(xpdb, caption=NULL, title=NULL) +
          xlab("Observed ===CMPD=== Concentrations (===CUNITS===)") +
          ylab("Population Predicted ===CMPD=== Concentrations (===CUNITS===)")

It creates the figure with the ID `dv_vs_pred`. It has the following elements:

- `orientation` - Orientation when used in a Word report, it can be either “portrait” or “landscape”.
- `caption`[PH] - Figure caption in Word reports.
- `caption_format` - This element is optional and can be either `"text"`(default plain text) or `"md"` (Markdown).
- `notes` - Notes about the figure.
- `notes_format` - This element is optional and can be either `"text"`(default plain text) or `"md"` (Markdown).
- `title`[PH] - Slide title when the figure is used in PowerPoint.
- `cmd`[PH] - Command to generate the figure.

Note: When the `cmd` is evaluated it needs to create an object called `p_res`. This can be either a `ggplot` object, a paginated object from `ggforce`, the result of `ggarrage` from the `ggpubr` package, a `ggmatrix` object from the `GGally` package, or a vector of file names containing image files created by the code in `cmd`. If you want to conditionally skip the reporting of a figure, you can instead set the value of `p_res` to `NA`. This will generate a message and prevent inclusion of a build error in the final document. You should also include any libraries you want in the relevant preamble section to ensure the functions are available to you.

## `tables`

Tables behave similarly to figures. In the tables section you create a table ID with the following options specified.

- `orientation` - Orientation when used in a Word report, it can be either “portrait” or “landscape”.
- `caption`[PH] - Table caption in Word reports.
- `caption_format` - This element is optional and can be either `"text"`(default plain text) or `"md"` (Markdown).
- `notes_format` - This element is optional and can be either `"text"`(default plain text) or `"md"` (Markdown).
- `title`[PH] - Slide title when the table is used in PowerPoint.
- `cmd`[PH] - Command to generate the table.

This example will create a table of the parameter estimates.

    tables:
      pest_table:
        orientation:    "portrait"
        caption:        "Parameter Estimates"
        caption_format: "text"
        title:          "Parameter Estimates"
        cmd: |-
          t_res <- gen_pest_table(
          fit        = fit,
          obnd       = obnd,
          rptdetails = rptdetails)

Note: When the `cmd` is evaluated it needs to create a variable called `t_res`. This a list which can contain the following elements:

- `df` - List of data frames containing the tabular information.
- `ft` - List of flextables containing the tabular information
- `notes` - Optional list of table notes.

If you only supply the data frames list element, they will be converted into flextables internally. Flextables will span multiple pages automatically. If you prefer to have a caption on each page you can split the tables manually into multiple data frames/flextables (see `span_table()` from the `onbrand` package). The reporting functionality is written to support table spanning multiple pages. If you define a separate table for each page you need to add those as sequential list elements to the `df` and `ft` elements. For example:

    t_res$df = list()
    t_res$df[[1]] = data.frame()
    t_res$df[[2]] = data.frame()
    etc

or

    t_res$ft = list()
    t_res$ft[[1]] = flextable::flextable()
    t_res$ft[[2]] = flextable::flextable()
    etc

If you only have a single table or if you want it to span multiple pages automatically you simply specify the first element listed above (e.g. `t_res$df[[1]]`).

If you want to conditionally skip the generation of a table, simply set `t_res` to `NA`. Like with figures above, this will signal to the reporting functions that you do not want to generate this table for the current fit object. It will also prevent the generation of a build error.

## `pptx`

This section defines general aspects of PowerPoint reports and also the contents of the report relating to the fitting results. Both the `figures` and `tables` sections contain the `onbrand` slide master names (`"content_text"`) to be used to hold these objects. The slides will be created with a title specified in figure and table IDs. The placeholder name for the title (`"title"`) must be specified as well as the placeholder name for the content (`"content_body"`). Figures for PowerPoint reports must be generated in the dimensions of the placeholder, so it is important that the `width` and `height` elements are specified in inches.

    pptx:
      figures:
        master:
          name:       "content_text"
          title_ph:   "title"
          content_ph: "content_body"
        width:  9.5
        height: 5.0
      tables:
        master:
          name:       "content_text"
          title_ph:   "title"
          content_ph: "content_body"

The actual content is specified in the `content` section. This is a list of keywords followed by a value. The `table` keyword should be followed by a table ID defined in the `tables` section. Similarly the `figure` keyworld should be followed by a figure ID defined in the `figures` section:

      content:
        - table: pest_table
        - figure: ind_plots
        - figure: dv_vs_pred
        - figure: dv_vs_ipred
        - figure: res_vs_pred
        - figure: res_vs_idv
        - figure: prm_vs_iteration
        - figure: absval_res_vs_pred

## `docx`

This section starts with general information about word documents. The `figures` section defines the height and width of figures for both `landscape` and `portrait` orientations. Again the units here are inches.

    docx:
      figures:
        landscape:
          width:  8.0
          height: 4.2
        portrait:
          width:  6.5
          height: 6.0

Just like with PowerPoint the content is defined in the `content` section. This can be defined as a `figure` or a `table` the same as in PowerPoint. Content can also include text elements as well. Just specify the `onbrand` style to control general formatting.

      content:
        - text:
            text:  "Figures"
            style: Heading_1
        - figure: dv_vs_pred
        - figure: ind_plots
        - figure: dv_vs_ipred
        - figure: res_vs_pred
        - figure: res_vs_idv
        - figure: prm_vs_iteration
        - figure: absval_res_vs_pred
        - text:
            text:  "Tables"
            style: Heading_1
        - table: pest_table

# Customizing reports for your organization

The reporting here is done using the `onbrand` package. This provides an abstraction layer to the `officer` package. The benefit here is that you can use your own organization Word and PowerPoint templates. Simply create them with the appropriate masters for PowerPoint or styles for Word, then create an on brand mapping file. When you initialize your report objects you can just provide the your organizational template and mapping files. For more details on how to create the templates and mapping files, see the vignette in the `onbrand` package.

## PowerPoint

To create an `onbrand` PowerPoint template for your organization you will need the following master slide names define with the corresponding elements.

Master/Template | onbrand | Content
--- | --- | ---
Name | Placeholder | Type
title_slide | title | text
sub_title | text
section_slide | title | text
sub_title | text
title_only | title | text
content_text | title | text
sub_title | text
content_body | text
content_list | title | text
sub_title | text
content_body | list
two_content_header_list | title | text
sub_title | text
content_left_header | text
content_left | list
content_right_header | text
content_right | list
two_content_header_text | title | text
sub_title | text
content_left_header | text
content_left | text
content_right_header | text
content_right | text
two_content_list | title | text
sub_title | text
content_left | list
content_right | list
two_content_text | title | text
sub_title | text
content_left | text
content_right | text

## Word

Similarly, to create an `onbrand` Word template you will need to the following `onbrand` styles defined.

onbrand | Word | Style
--- | --- | ---
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

# Report configuration file `report_fit.yaml`

    placeholders:
      CMPD: Compound Name
      CUNITS: Conc Units
      TUNITS: Time Units
      RUN: RUNN
      OBJ: sprintf("%3g", fit$objf)
    parameters:
      lVp:
        md:  "V~p~"
        txt: "Vp"
      add_err:
        md:  "Add Err"
        txt: "Add Err"
      prop_err:
        md:  "Prop Err"
        txt: "Prop Err"
    covariates:
      cat:  NULL
      cont: NULL
    options:
      output_dir:   "file.path(getwd(), '===RUN===')"
      resolution:   300
      fig_stamp:    "source: ===FILE==="
      figenv_preamble: |-
        library("ggplot2")
        library("xpose")
        library("ggforce")
        if(system.file(package="ggPMX") != ""){
          library("ggPMX")
        }
        xpdb = xpose.nlmixr2::xpose_data_nlmixr(fit)
      tabenv_preamble: NULL
    figures:
      dv_vs_pred_ipred:
        orientation: "portrait"
        caption:     "Observed vs Predicted"
        title:       "Observed vs Predicted"
        cmd: |-
          p_pred <- dv_vs_pred(xpdb, caption=NULL, title=NULL, subtitle=NULL) +
          ggtitle("===CMPD=== (===CUNITS===)") +
          coord_fixed()+
          ylab("Observed") +
          xlab("Population Predicted") +
          theme_light()
          yrange = layer_scales(p_pred)$y$range$range
          xrange = layer_scales(p_pred)$x$range$range
          lb = min(c(yrange,xrange))
          ub = max(c(yrange,xrange))
          p_pred = p_pred + xlim(c(lb, ub)) + ylim(c(lb,ub))

          p_ipred <- dv_vs_ipred(xpdb, caption=NULL, title=NULL, subtitle=NULL) +
          ggtitle("===CMPD=== (===CUNITS===)") +
          coord_fixed()+
          ylab("Observed") +
          xlab("Individual Predicted") +
          theme_light()
          yrange = layer_scales(p_ipred)$y$range$range
          xrange = layer_scales(p_ipred)$x$range$range
          lb = min(c(yrange,xrange))
          ub = max(c(yrange,xrange))
          p_ipred = p_ipred + xlim(c(lb, ub)) + ylim(c(lb,ub))
          p_res <- ggpubr::ggarrange(p_pred, p_ipred, ncol=2, nrow=1 )
      res_vs_pred_idv:
        orientation: "portrait"
        caption:     "CWRES vs Pred and Time"
        title:       "CWRES vs Pred and Time"
        cmd: |-
          if("CWRES" %in% names(fit)){
            p_pred <- res_vs_pred(xpdb, caption=NULL, title=NULL, res="CWRES") +
            ggtitle("===CMPD=== (===CUNITS===)") +
            ylab("CWRES") +
            xlab("Population Predicted") +
            theme_light()

            p_idv  <- res_vs_idv(xpdb, caption=NULL, title=NULL, res="CWRES") +
            ggtitle("Time (===CUNITS===)") +
            ylab("CWRES") +
            xlab("Time (===TUNITS===)") +
            theme_light()

            p_res <- ggpubr::ggarrange(p_pred, p_idv, ncol=2, nrow=1 )
          } else {
            p_res <- NA
          }
      eta_cat:
        orientation: "landscape"
        caption:     "Effect of categorical covariates"
        title:       "Effect of categorical covariates"
        cmd: |-
          if(!is.null(cat_covars)){
            if(system.file(package="ggPMX") != ""){
              ctr = ggPMX::pmx_nlmixr(fit,
                      vpc = FALSE,
                      conts = cont_covars,
                      cats  = cat_covars)
              p_res <- ggPMX::pmx_plot_eta_cats(ctr) +
                theme_light()
            } else {
              p_res <- mk_error_fig("ggPMX is not installed")
            }
          } else {
            p_res <- NA
          }
      eta_cont:
        orientation: "landscape"
        caption:     "Effect of continuous covariates"
        title:       "Effect of continuous covariates"
        cmd: |-
          if(!is.null(cont_covars)){
            if(system.file(package="ggPMX") != ""){
              ctr = ggPMX::pmx_nlmixr(fit,
                      vpc = FALSE,
                      conts = cont_covars,
                      cats  = cat_covars)
              p_res <- ggPMX::pmx_plot_eta_conts(ctr) +
                theme_light()
            } else {
              p_res = mk_error_fig("ggPMX is not installed")
            }
          } else {
            p_res <- NA
          }
      prm_vs_iteration:
        orientation: "landscape"
        caption:     "SAEM Stabilization"
        title:       "SAEM Stabilization"
        cmd: |-
          p_res <- prm_vs_iteration(xpdb, caption=NULL, title=NULL) +
            theme_light()
      ind_plots:
        orientation: "landscape"
        caption:     "Individual and population prediction overlay"
        title:       "Individual and population prediction overlay"
        cmd: |-
          p_res <- ind_plots(xpdb, nrow=3, ncol=4, caption=NULL, title=NULL)  +
          ylab(" ===CMPD=== (===CUNITS===)") +
          xlab("Time (===TUNITS===)")  +
          theme_light()
      eta_matrix:
        orientation: "landscape"
        caption:     "Correlation between IIV terms and parameters"
        title:       "IIV Correlation"
        cmd: |-
          if(system.file(package="ggPMX") != ""){
            ctr = ggPMX::pmx_nlmixr(fit,
                    vpc = FALSE,
                    conts = cont_covars,
                    cats  = cat_covars)
            p_res <- ggPMX::pmx_plot_eta_matrix(ctr) +
              theme_light()
          }
      skip_figure:
        orientation: "landscape"
        caption:     "ind_plots caption"
        title:       "ind_plots title"
        cmd: |-
          p_res <- NA
    tables:
      skip_table:
        orientation: "portrait"
        caption:     "Parameter Estimates"
        title:       "Parameter Estimates"
        cmd: |-
          t_res <- NA
      pest_table:
        orientation: "portrait"
        caption:     "Parameter Estimates"
        title:       "Parameter Estimates"
        cmd: |-
          t_res <- gen_pest_table(
          fit        = fit,
          obnd       = obnd,
          rptdetails = rptdetails)
    pptx:
      figures:
        master:
          name:       "content_text"
          title_ph:   "title"
          content_ph: "content_body"
        width:  9.5
        height: 5.0
      tables:
        master:
          name:       "content_text"
          title_ph:   "title"
          content_ph: "content_body"
      content:
        - table: pest_table
        - table: skip_table
        - figure: ind_plots
        - figure: dv_vs_pred_ipred
        - figure: res_vs_pred_idv
        - figure: prm_vs_iteration
        - figure: eta_cont
        - figure: eta_cat
        - figure: skip_figure
    docx:
      figures:
        landscape:
          width:  8.0
          height: 4.2
        portrait:
          width:  6.5
          height: 6.0
      content:
        - text:
            text:  "Tables"
            style: Heading_1
        - table: pest_table
        - text:
            text:  "Figures"
            style: Heading_1
        - figure: ind_plots
        - figure: dv_vs_pred_ipred
        - figure: res_vs_pred_idv
        - figure: prm_vs_iteration
        - figure: skip_figure
        - figure: eta_cont
        - figure: eta_cat