---
title: "Table & Listing Customizations"
date: "2025-12-04"
author: "Joe Kovach and David Munoz Tord"
output:
    rmarkdown::html_document:
        theme: "spacelab"
        highlight: "kate"
        toc: true
        toc_float: true
vignette: >
  %\VignetteIndexEntry{Table & Listing Customizations}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  echo = TRUE,
  collapse = TRUE,
  comment = "#>",
  message = FALSE,
  warning = FALSE
)

options(docx.add_datetime=FALSE)

library(junco)
library(rlistings)
library(tibble)

```


```{r setup-title, include=FALSE}
#Need to set up a dummy tittle and main footer
titles <- list(title = " ",
                     subtitles = NULL,
                     main_footer = "Dummy Note: On-treatment is defined as ~{optional treatment-emergent}")
#Need tempdir
out_dir <- file.path("..", "output")
if(!dir.exists(out_dir)) {
  dir.create(out_dir)
}

NOT_CRAN <- !testthat:::on_cran()
```

## Introduction

Within clinical trial reporting, there is often the need to incorporate
custom components to the tables and listings being created. Common
custom components may include the following:

-   Page Orientation (Portrait vs. Landscape)
-   Adjusting the Font Size of a Table
-   Adding a Spanning Column Header to a Table
-   Adding a Combined Treatment Column to a Table
-   Inserting a New Line within Table & Listing Text
-   Custom Table Column Header Border Matrix
-   Addition of Superscript or Other Symbol
-   Grouping of Columns for Tables Containing Many Columns
-   Inserting Page Breaks in Tables
-   Manually Splitting Large Table & Listing Files into Multiple Smaller Files

The purpose of this vignette is to provide clear, concise examples of how to achieve each custom component.

> **Note:** The visual output shown in this HTML vignette may not exactly match what the .docx or .rtf exporters will actually produce due to differences between HTML and those formats. The HTML outputs displayed here are for demonstration purposes only. Users should run the code examples themselves to see the exact output in their preferred format (.docx or .rtf).

## Page Orientation (Portrait vs. Landscape)
Sometimes when creating a table, there are many columns that need to be presented. In this scenario, it might be beneficial for the resulting output file to have an orientation of landscape. As a result, the page is wider, allowing the information to be more readable.

### Table .rtf File
In the .rtf exporter function, `junco::tt_to_tlgrtf`, by default, the page orientation is set to portrait. If landscape orientation is required, then the orientation can be adjusted by including the `orientation` argument and specifying a value of "landscape".

```{r orientation_rtf}
library(junco)

adsl <- data.frame(TRT01A = factor(c("Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo",
                                     "Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo"),
                                   levels = c("Example Drug 5 mg",
                                              "Example Drug 10 mg",
                                              "Example Drug 20 mg",
                                              "Placebo"
                                              )
                              ),
                   USUBJID = c("1",
                               "2",
                               "3",
                               "4",
                               "5",
                               "6",
                               "7",
                               "8"),
                   RESPONSE = factor(c("Yes",
                                       "No",
                                       "Yes",
                                       "Yes",
                                       "Yes",
                                       "No",
                                       "Yes",
                                       "No"),
                                     levels = c("Yes",
                                                "No")
                              ),
                   SEX = factor(c("Male",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Male"),
                                levels = c("Male",
                                           "Female")
                           )
) |>
  var_relabel(RESPONSE = "Response")

lyt <- basic_table(
  show_colcounts = TRUE,
  colcount_format = "N=xx"
) |>
  ### first columns
  split_cols_by("TRT01A",
                show_colcounts = FALSE
  ) |>
  ### create table body row sections based on SEX
  split_rows_by("SEX",
                section_div = c(" "),
                page_by = TRUE,
                split_fun = drop_split_levels
                ) |>
  summarize_row_groups("SEX",
                       cfun =a_freq_j,
                       extra_args = list(denom = "n_df",
                                         denom_by = "SEX",
                                         riskdiff = FALSE,
                                         extrablankline = TRUE,
                                         .stats = c("count_unique")
                                         )
                       ) |>
  ### analyze height
  analyze("RESPONSE",
          var_labels = c("Response"),
          show_labels = "visible",
          afun = a_freq_j,
          extra_args = list(denom = "n_df",
                            denom_by = "SEX",
                            riskdiff = FALSE,
                            .stats = c("count_unique_fraction")
                            )
          )

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)
```

```{r orientation_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/exampleorientation"),
             orientation = "landscape")
```



###  Table .docx File

To create a .docx file with landscape orientation, the `junco::export_as_docx_j` function can be called with the `orientation` argument set to "landscape".

```{r orientation_docx_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
export_as_docx_j(result,
                tblid = "exampleorientation",
                output_dir = out_dir,
                orientation = "landscape")
```

### Visual Output (HTML Representation)
```{r orientation_rtf_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "exampleorientation", orientation = "landscape")
```



## Adjusting the Font Size of a Table or Listing
By default, the font type and size for the body of tables is Times New Roman 9-pt. If a font size of 8-pt is required for a table, then the font size can be adjusted as necessary. Other font sizes are not currently supported for tables. For listings, the default font size is 8-pt. Other font sizes are not currently supported for listings.

### Table .rtf File

To display the body of tables in Times New Roman 8-pt for .rtf files, the `junco::tt_to_tlgrtf` function can be called with the `fontspec` argument included. The `fontspec` argument will specify a `formatters::font_spec` function call.

Example of Table with Font Size of 8-pt
```{r fontsize_rtf}
library(junco)

adsl <- data.frame(TRT01A = factor(c("Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo",
                                     "Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo"),
                                   levels = c("Example Drug 5 mg",
                                              "Example Drug 10 mg",
                                              "Example Drug 20 mg",
                                              "Placebo"
                                              )
                              ),
                   USUBJID = c("1",
                               "2",
                               "3",
                               "4",
                               "5",
                               "6",
                               "7",
                               "8"),
                   RESPONSE = factor(c("Yes",
                                       "No",
                                       "Yes",
                                       "Yes",
                                       "Yes",
                                       "No",
                                       "Yes",
                                       "No"),
                                     levels = c("Yes",
                                                "No")
                              ),
                   SEX = factor(c("Male",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Male"),
                                levels = c("Male",
                                           "Female")
                           )
) |>
  var_relabel(RESPONSE = "Response")

lyt <- basic_table(
  show_colcounts = TRUE,
  colcount_format = "N=xx"
) |>
  ### first columns
  split_cols_by("TRT01A",
                show_colcounts = FALSE
  ) |>
  ### create table body row sections based on SEX
  split_rows_by("SEX",
                section_div = c(" "),
                page_by = TRUE,
                split_fun = drop_split_levels
                ) |>
  summarize_row_groups("SEX",
                       cfun =a_freq_j,
                       extra_args = list(denom = "n_df",
                                         denom_by = "SEX",
                                         riskdiff = FALSE,
                                         extrablankline = TRUE,
                                         .stats = c("count_unique")
                                         )
                       ) |>
  ### analyze height
  analyze("RESPONSE",
          var_labels = c("Response"),
          show_labels = "visible",
          afun = a_freq_j,
          extra_args = list(denom = "n_df",
                            denom_by = "SEX",
                            riskdiff = FALSE,
                            .stats = c("count_unique_fraction")
                            )
          )

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)
```

```{r fontsize_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/examplefontsize"),
             fontspec = formatters::font_spec("Times", 8, 1.2))

```
### Table .docx File

To display the body of tables in Times New Roman 8-pt for .docx files, the junco::export_as_docx_j function can be called with the theme argument included. The theme argument will specify a junco::theme_docx_default_j function call.

```{r fontsize_docx_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
export_as_docx_j(result,
                tblid = "examplefontsize",
                output_dir = out_dir,
                theme = theme_docx_default_j(font = "Times New Roman", font_size = 8L))
```

### Visual Output (HTML Representation)
```{r fontsize_rtf_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "examplefontsize", fontspec = formatters::font_spec("Times", 8, 1.2))
```



## Adding a Spanning Column Header to a Table
Sometimes, it is necessary to include a spanning header in the column header space. This is common when there is a need to group specific columns together under a common category text. A common example of this is when a spanning header such as "Active Study Agent" is to be displayed above all active treatments for a given study. To display the spanning header, a variable needs to be included in the data to represent the spanning header. Subsequently, a column header treatment map needs to be created to identify which spanning headers and columns are to be present in the resulting table output. For simple studies, the `junco::create_colspan_map` function can be leveraged to achieve the creation of the treatment map.

In the code below, the variable `colspan_trt` is being created to identify the spanning header text. In this example, the "Example Drug 5 mg", "Example Drug 10 mg", and "Example Drug 20 mg" columns are to be displayed beneath a spanning header of "Active Study Agent". Then, the treatment map is being created by calling `junco::create_colspan_map`.
```{r spanning_header_setup}
library(junco)

adsl <- data.frame(TRT01A = factor(c("Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo",
                                     "Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo"),
                                   levels = c("Example Drug 5 mg",
                                              "Example Drug 10 mg",
                                              "Example Drug 20 mg",
                                              "Placebo"
                                              )
                              ),
                   colspan_trt = factor(c("Active Study Agent",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          " ",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          " "),
                                        levels = c(
                                          "Active Study Agent",
                                          " "
                                        )
                                        ),
                   USUBJID = c("1",
                               "2",
                               "3",
                               "4",
                               "5",
                               "6",
                               "7",
                               "8"),
                   RESPONSE = factor(c("Yes",
                                       "No",
                                       "Yes",
                                       "Yes",
                                       "Yes",
                                       "No",
                                       "Yes",
                                       "No"),
                                     levels = c("Yes",
                                                "No")
                              ),
                   SEX = factor(c("Male",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Male"),
                                levels = c("Male",
                                           "Female")
                           )
) |>
  var_relabel(RESPONSE = "Response")

adsl

  colspan_trt_map <- create_colspan_map(adsl,
                                      non_active_grp = "Placebo",
                                      non_active_grp_span_lbl = " ",
                                      active_grp_span_lbl = "Active Study Agent",
                                      colspan_var = "colspan_trt",
                                      trt_var = "TRT01A")

  colspan_trt_map
```


The full code to generate the output with the spanning column header is as follows.
```{r spanning_header_full}
library(junco)

adsl <- data.frame(TRT01A = factor(c("Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo",
                                     "Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo"),
                                   levels = c("Example Drug 5 mg",
                                              "Example Drug 10 mg",
                                              "Example Drug 20 mg",
                                              "Placebo"
                                              )
                              ),
                   colspan_trt = factor(c("Active Study Agent",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          " ",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          " "),
                                        levels = c(
                                          "Active Study Agent",
                                          " "
                                        )
                                        ),
                   USUBJID = c("1",
                               "2",
                               "3",
                               "4",
                               "5",
                               "6",
                               "7",
                               "8"),
                   RESPONSE = factor(c("Yes",
                                       "No",
                                       "Yes",
                                       "Yes",
                                       "Yes",
                                       "No",
                                       "Yes",
                                       "No"),
                                     levels = c("Yes",
                                                "No")
                              ),
                   SEX = factor(c("Male",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Male"),
                                levels = c("Male",
                                           "Female")
                           )
) |>
  var_relabel(RESPONSE = "Response")

  # No combined column needed for spanning header example
  mysplit <- make_split_fun()

  colspan_trt_map <- create_colspan_map(adsl,
                                      non_active_grp = "Placebo",
                                      non_active_grp_span_lbl = " ",
                                      active_grp_span_lbl = "Active Study Agent",
                                      colspan_var = "colspan_trt",
                                      trt_var = "TRT01A")

lyt <- basic_table(
  show_colcounts = TRUE,
  colcount_format = "N=xx"
) |>
  split_cols_by("colspan_trt",
                split_fun = trim_levels_to_map(map = colspan_trt_map)
  ) |>
  split_cols_by("TRT01A",
                show_colcounts = FALSE,
                split_fun = mysplit
  ) |>
  ### create table body row sections based on SEX
  split_rows_by("SEX",
                section_div = c(" "),
                page_by = TRUE,
                split_fun = drop_split_levels
                ) |>
  summarize_row_groups("SEX",
                       cfun =a_freq_j,
                       extra_args = list(denom = "n_df",
                                         denom_by = "SEX",
                                         riskdiff = FALSE,
                                         extrablankline = TRUE,
                                         .stats = c("count_unique")
                                         )
                       ) |>
  ### analyze height
  analyze("RESPONSE",
          var_labels = c("Response"),
          show_labels = "visible",
          afun = a_freq_j,
          extra_args = list(denom = "n_df",
                            denom_by = "SEX",
                            riskdiff = FALSE,
                            .stats = c("count_unique_fraction")
                            )
          )

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)
```

```{r spanning_header_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/examplespanningheader1"),
             orientation = "landscape")
```

### Visual Output (HTML Representation)
```{r spanning_header_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "examplespanningheader1", orientation = "landscape")
```

## Adding a Combined Column to a Table
Sometimes it is necessary to add a combined column to a table, which contains aggregated data from multiple columns.

The creation of a combined column can be achieved by leveraging `rtables::add_combo_facet`. In the example below, we want to add a column named "Combined", that aggregates the data from the "Example Drug 5 mg", "Example Drug 10 mg", and "Example Drug 20 mg" columns. This can be achieved by creating an object named "add_combo", that calls `rtables::add_combo_facet`, which creates a new column from other columns in the table. A split function can then be constructed using `rtables::make_split_fun`, where the "post" argument contains the "add_combo" object, which calls `rtables::add_combo_facet`. The split function is then included in the `rtables::split_cols_by` function call for the TRT01A variable.

The snippet of code of interest is as follows.
```{r combined_column_setup}
add_combo <- add_combo_facet("Combined",
    label = "Combined",
    levels = c("Example Drug 5 mg", "Example Drug 10 mg", "Example Drug 20 mg")
  )

  mysplit <- make_split_fun(post = list(add_combo))
```

The full code to generate the output with the new "Combined" column is as follows.
```{r combined_column_full}
library(junco)

adsl <- data.frame(TRT01A = factor(c("Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo",
                                     "Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo"),
                                   levels = c("Example Drug 5 mg",
                                              "Example Drug 10 mg",
                                              "Example Drug 20 mg",
                                              "Placebo"
                                              )
                              ),
                   colspan_trt = factor(c("Active Study Agent",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          " ",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          " "),
                                        levels = c(
                                          "Active Study Agent",
                                          " "
                                        )
                                        ),
                   USUBJID = c("1",
                               "2",
                               "3",
                               "4",
                               "5",
                               "6",
                               "7",
                               "8"),
                   RESPONSE = factor(c("Yes",
                                       "No",
                                       "Yes",
                                       "Yes",
                                       "Yes",
                                       "No",
                                       "Yes",
                                       "No"),
                                     levels = c("Yes",
                                                "No")
                              ),
                   SEX = factor(c("Male",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Male"),
                                levels = c("Male",
                                           "Female")
                           )
) |>
  var_relabel(RESPONSE = "Response")

  # Set up levels and label for the required combined column
  add_combo <- add_combo_facet("Combined",
    label = "Combined",
    levels = c("Example Drug 5 mg", "Example Drug 10 mg", "Example Drug 20 mg")
  )

  mysplit <- make_split_fun(post = list(add_combo))

  colspan_trt_map <- create_colspan_map(adsl,
                                      non_active_grp = "Placebo",
                                      non_active_grp_span_lbl = " ",
                                      active_grp_span_lbl = "Active Study Agent",
                                      colspan_var = "colspan_trt",
                                      trt_var = "TRT01A")

lyt <- basic_table(
  show_colcounts = TRUE,
  colcount_format = "N=xx"
) |>
  split_cols_by("colspan_trt",
                split_fun = trim_levels_to_map(map = colspan_trt_map)
  ) |>
  split_cols_by("TRT01A",
                show_colcounts = FALSE,
                split_fun = mysplit
  ) |>
  ### create table body row sections based on SEX
  split_rows_by("SEX",
                section_div = c(" "),
                page_by = TRUE,
                split_fun = drop_split_levels
                ) |>
  summarize_row_groups("SEX",
                       cfun =a_freq_j,
                       extra_args = list(denom = "n_df",
                                         denom_by = "SEX",
                                         riskdiff = FALSE,
                                         extrablankline = TRUE,
                                         .stats = c("count_unique")
                                         )
                       ) |>
  ### analyze height
  analyze("RESPONSE",
          var_labels = c("Response"),
          show_labels = "visible",
          afun = a_freq_j,
          extra_args = list(denom = "n_df",
                            denom_by = "SEX",
                            riskdiff = FALSE,
                            .stats = c("count_unique_fraction")
                            )
          )

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)
```

```{r combined_column1_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/examplecombinedcolumn1"),
             orientation = "landscape")
```

### Visual Output (HTML Representation)
```{r combined_column_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "examplecombinedcolumn1", orientation = "landscape")
```

The code above creates the desired column, however, the issue is that the resulting output produces a "Combined" column under each spanning header, and as a result, 2 "Combined" columns are created. The "Combined" column of interest is the one appearing beneath the "Active Study Agent" spanning header. We need additional code to remove the "Combined" column that lives in the other spanning header value of " ". This can be achieved by creating an object that calls `junco::cond_rm_facets`, which removes user-specified columns from facets. A split function can then be constructed using `rtables::make_split_fun`, where the "post" argument contains the "add_combo" object, which calls `rtables::add_combo_facet`, and the "rm_combo_from_placebo" object, which calls `junco::cond_rm_facets`. Similar to above, the split function is then included in the `rtables::split_cols_by` function call for the TRT01A variable.

The additional code required for to produce the desired result is as follows.
```{r improved_combined_column_setup, eval=FALSE}
  # choose if any facets need to be removed - e.g remove the combined column for placebo
  rm_combo_from_placebo <- cond_rm_facets(
    facets = "Combined",
    ancestor_pos = NA,
    value = " ",
    split = "colspan_trt"
  )

  mysplit <- make_split_fun(post = list(add_combo, rm_combo_from_placebo))
```

The full code to generate the output with the desired "Combined" column is as follows.
```{r improved_combined_column_full}
library(junco)

adsl <- data.frame(TRT01A = factor(c("Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo",
                                     "Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo"),
                                   levels = c("Example Drug 5 mg",
                                              "Example Drug 10 mg",
                                              "Example Drug 20 mg",
                                              "Placebo"
                                              )
                              ),
                   colspan_trt = factor(c("Active Study Agent",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          " ",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          "Active Study Agent",
                                          " "),
                                        levels = c(
                                          "Active Study Agent",
                                          " "
                                        )
                                        ),
                   USUBJID = c("1",
                               "2",
                               "3",
                               "4",
                               "5",
                               "6",
                               "7",
                               "8"),
                   RESPONSE = factor(c("Yes",
                                       "No",
                                       "Yes",
                                       "Yes",
                                       "Yes",
                                       "No",
                                       "Yes",
                                       "No"),
                                     levels = c("Yes",
                                                "No")
                              ),
                   SEX = factor(c("Male",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Male"),
                                levels = c("Male",
                                           "Female")
                           )
) |>
  var_relabel(RESPONSE = "Response")

  # Set up levels and label for the required combined column
  add_combo <- add_combo_facet("Combined",
    label = "Combined",
    levels = c("Example Drug 5 mg", "Example Drug 10 mg", "Example Drug 20 mg")
  )

  # choose if any facets need to be removed - e.g remove the combined column for placebo
  rm_combo_from_placebo <- cond_rm_facets(
    facets = "Combined",
    ancestor_pos = NA,
    value = " ",
    split = "colspan_trt"
  )

  mysplit <- make_split_fun(post = list(add_combo, rm_combo_from_placebo))

  colspan_trt_map <- create_colspan_map(adsl,
                                      non_active_grp = "Placebo",
                                      non_active_grp_span_lbl = " ",
                                      active_grp_span_lbl = "Active Study Agent",
                                      colspan_var = "colspan_trt",
                                      trt_var = "TRT01A")

lyt <- basic_table(
  show_colcounts = TRUE,
  colcount_format = "N=xx"
) |>
  split_cols_by("colspan_trt",
                split_fun = trim_levels_to_map(map = colspan_trt_map)
  ) |>
  split_cols_by("TRT01A",
                show_colcounts = FALSE,
                split_fun = mysplit
  ) |>
  ### create table body row sections based on SEX
  split_rows_by("SEX",
                section_div = c(" "),
                page_by = TRUE,
                split_fun = drop_split_levels
                ) |>
  summarize_row_groups("SEX",
                       cfun =a_freq_j,
                       extra_args = list(denom = "n_df",
                                         denom_by = "SEX",
                                         riskdiff = FALSE,
                                         extrablankline = TRUE,
                                         .stats = c("count_unique")
                                         )
                       ) |>
  ### analyze height
  analyze("RESPONSE",
          var_labels = c("Response"),
          show_labels = "visible",
          afun = a_freq_j,
          extra_args = list(denom = "n_df",
                            denom_by = "SEX",
                            riskdiff = FALSE,
                            .stats = c("count_unique_fraction")
                            )
          )

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)
```

```{r combined_column2_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/examplecombinedcolumn2"),
             orientation = "landscape")
```

### Visual Output (HTML Representation)
```{r improved_combined_column_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "examplecombinedcolumn2", orientation = "landscape")
```

## Inserting a New Line within Table & Listing Text

Sometimes it is necessary to insert a new line within text so that the information is presented in the exact format provided in the table or listing specification.

In the following example data, there is a desire to insert a new line
between the drug name and the dose level for the "Example Drug" drug. In
this case, the text "Example Drug" is to appear on a different line than
the dose levels (i.e. "5 mg", "10 mg", "20 mg").

```{r newline_data}
adsl <- data.frame(TRT01A = c("Example Drug 5 mg",
                              "Example Drug 10 mg",
                              "Example Drug 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
)

adsl
```

### Table .rtf File

In order to get the dose level to appear on a new line, then the TRT01A
variable values will need to be updated to include the text "\\\\line"
between the drug name and dose level.

```{r newline_table_rtf}
library(junco)
library(rtables)

adsl <- data.frame(TRT01A = c("Example Drug\\line 5 mg",
                              "Example Drug\\line 10 mg",
                              "Example Drug\\line 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
)

lyt <- basic_table(
  show_colcounts = FALSE,
  colcount_format = "N=xx"
) |>
  ### first columns
  split_cols_by("TRT01A",,
                show_colcounts = FALSE
  ) |>
  ### analyze height
  analyze("HEIGHT", afun = list_wrap_x(summary), format = "xx.xx")

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)
```

```{r newline_table_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/newlinetable"),
             orientation = "landscape")
```

### Table .docx File

In order to get the dose level to appear on a new line, then the TRT01A
variable values will need to be updated to include the text "\\n"
between the drug name and dose level.


```{r newline_table_docx}
library(junco)
library(rtables)

adsl <- data.frame(TRT01A = c("Example Drug\n 5 mg",
                              "Example Drug\n 10 mg",
                              "Example Drug\n 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
)

lyt <- basic_table(
  show_colcounts = FALSE,
  colcount_format = "N=xx"
) |>
  ### first columns
  split_cols_by("TRT01A",,
                show_colcounts = FALSE
  ) |>
  ### analyze height
  analyze("HEIGHT", afun = list_wrap_x(summary), format = "xx.xx")

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)

```

```{r newline_table_docx_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
export_as_docx_j(result,
                tblid = "examplenewline",
                output_dir = out_dir,
                orientation = "landscape")
```

### Visual Output (HTML Representation)
```{r newline_table_rtf_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "newlinetable", orientation = "landscape")
```

### Listing .rtf File

If a .rtf file is to be created for the listing, new lines can be inserted into the column header by updating the variable label that corresponds with the column of interest.

By adding in "\\\\line" to the TRT01A variable label, a new line is inserted after "Actual Treatment".

```{r newline_listing_rtf}
library(junco)
library(rlistings)

adsl <- data.frame(TRT01A = c("Example Drug 5 mg",
                              "Example Drug 10 mg",
                              "Example Drug 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
) |>
  formatters::var_relabel(TRT01A = "Actual Treatment for\\line Period 01") |>
  formatters::var_relabel(SUBJECT = "Subject") |>
  formatters::var_relabel(HEIGHT = "Height (in)")

result <- rlistings::as_listing(
  df = adsl,
  key_cols = c("TRT01A", "SUBJECT"),
  disp_cols = "HEIGHT"
)
result <- set_titles(result, titles)
```

```{r newline_listing_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/examplelistingnewline2"),
             orientation = "landscape")
```





### Listing .docx File


If a .docx file is to be created for the listing, new lines can be inserted into the column header by updating the variable label that corresponds with the column of interest.

By adding in "\\n" to the TRT01A variable label, a new line is inserted after "Actual Treatment".

```{r newline_listing_docx}
library(junco)
library(rlistings)

adsl <- data.frame(TRT01A = c("Example Drug 5 mg",
                              "Example Drug 10 mg",
                              "Example Drug 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
) |>
  formatters::var_relabel(TRT01A = "Actual Treatment for\n Period 01") |>
  formatters::var_relabel(SUBJECT = "Subject") |>
  formatters::var_relabel(HEIGHT = "Height (in)")

result <- rlistings::as_listing(
  df = adsl,
  key_cols = c("TRT01A", "SUBJECT"),
  disp_cols = "HEIGHT"
)
result <- set_titles(result, titles)

```

```{r newline_listing_docx_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
export_as_docx_j(result,
                tblid = "examplelistingnewline2",
                output_dir = out_dir,
                orientation = "landscape")
```

### Visual Output (HTML Representation)
```{r newline_listing_rtf_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "examplelistingnewline2", orientation = "landscape")
```


## Custom Table Column Header Border Matrix

When creating a table using, there is a set of default assumptions in place that determine how the borders are crafted within the table column header space. There are times when the table specification calls for a border matrix that is not based on the default assumptions. Below is an example of how to create a border matrix that produces the user required table.

### Table .rtf File

The following is an example of a table created from `junco::tt_to_tlgrtf`.

```{r border_matrix}
library(junco)

adsl <- data.frame(span = c("Example Drug Low Dose",
                            "Example Drug Low Dose",
                            "Example Drug High Dose",
                            " "),
                   TRT01A = c("Example Drug 5 mg",
                              "Example Drug 10 mg",
                              "Example Drug 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
)

lyt <- basic_table(
  show_colcounts = FALSE,
  colcount_format = "N=xx"
) |>
  ### first level in column header
  split_cols_by("span",,
                show_colcounts = FALSE
  ) |>
  ### second level in column header
  split_cols_by("TRT01A",,
                show_colcounts = FALSE
  ) |>
  ### analyze height
  analyze("HEIGHT", afun = list_wrap_x(summary), format = "xx.xx")

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)
```

```{r border_matrix_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/bordertable"),
             orientation = "landscape")
```

### Visual Output (HTML Representation)
```{r border_matrix_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "bordertable", orientation = "landscape")
```

In the resulting output, the "Example Drug High Dose" spanning header
does not include an underline beneath the text at the bottom of the
cell. It's important for us to understand what the default border matrix
looks like. This can be achieved by calling the
`junco:::make_header_bordmat` function.

```{r default_border_matrix}
header_border <- junco:::make_header_bordmat(obj = result)
header_border
```

It can be observed that the first row, and fourth column in the border
matrix contains a value of 0. In order to have a bottom border present
under "Example Drug High Dose", a value other than 0 or 2 must be
specified. This is because "Example Drug High Dose" is expected to have it's own spanning header, and the value specified in the border matrix must be unique to the cell. The border can be updated as follows.

```{r updated_border_matrix}
header_border[1, 4] <- 4
header_border
```

Now, if the `junco::tt_to_tlgrtf` function is called with the "border_mat"
argument included, the new user-defined border matrix can be provided as the argument value to specify the desired column header borders.

```{r custom_border_matrix_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/custombordertable"),
             orientation = "landscape",
             border_mat = header_border)
```


### Table .docx File
To export a table with a custom border matrix to a .docx file, the `junco::export_as_docx_j` function can be called with the `border_mat` argument:

```{r custom_border_matrix_docx_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
export_as_docx_j(result,
                tblid = "custombordertable",
                output_dir = out_dir,
                orientation = "landscape",
                border_mat = header_border)
```

### Visual Output (HTML Representation)
> **Note:** In this HTML output the spanning line is a single line, instead of 2 lines. However, if you output the .docx or .rtf file using the same TableTree as input, it will be displayed correctly.


```{r custom_border_matrix_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "custombordertable", orientation = "landscape", border_mat = header_border)
```



## Addition of Superscript or Other Symbol
Sometimes it is necessary to insert a superscript or other symbol within text so that the information is presented according to the table or listing specification. This can be achieved by specifying a markup data frame in the export function call.

In the `junco` package, there is a default markup data frame for each exporter function, which contains common markup that translates to symbols/characters that may be desired in an output. The default markup data frame contains markup to insert superscripts, insert subscripts, and can remove optional text.

The default markup file for `junco::tt_to_tlgrtf` to produce an .rtf file is as follows.
```{r default_markup_rtf}
library(tibble)

dps_markup_df <- tibble::tribble(
  ~keyword,
  ~rtfstart,
  ~rtfend,
  "super",
  "\\super",
  "\\nosupersub",
  "sub",
  "\\sub",
  "\\nosupersub",
  "optional",
  "",
  ""
)

dps_markup_df
```
If additional markup is to be considered, then a custom markup data frame can be created and specified in the exporter function call.

In the following example data, there is a desire to insert a superscript "a" at the end the drug name for the "Example Drug" drug in reference to a footnote present at the end of the table.

```{r superscript_example_data}
adsl <- data.frame(TRT01A = c("Example Drug 5 mg",
                              "Example Drug 10 mg",
                              "Example Drug 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
)

adsl
```

Depending on the file format required (i.e. .rtf or .docx) the data will
require different updates, according to the markup that is required.

### Table .rtf File

If a .rtf file is to be created for the table, the `junco::tt_to_tlgrtf` is to be called. In this example, when calling `junco::tt_to_tlgrtf`, the "markup_df" argument has the default "dps_markup_df" object specified.

In order to get the superscript "a" to appear, the TRT01A variable values will need to be updated to include the text "~[super a]" between the drug name and dose level.

```{r superscript_table_rtf}
library(junco)

adsl <- data.frame(TRT01A = c("Example Drug~[super a] 5 mg",
                              "Example Drug~[super a] 10 mg",
                              "Example Drug~[super a] 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
)

lyt <- basic_table(
  show_colcounts = FALSE,
  colcount_format = "N=xx"
) |>
  ### first columns
  split_cols_by("TRT01A",,
                show_colcounts = FALSE
  ) |>
  ### analyze height
  analyze("HEIGHT", afun = list_wrap_x(summary), format = "xx.xx")

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)
```

```{r superscript_table_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/superscripttable"),
             orientation = "landscape",
             markup_df = dps_markup_df)
```


### Table .docx File

The default markup file for `junco::export_as_docx_j` to produce a .docx file is as follows.

```{r default_markup_docx2}
library(tibble)

docx_markup_df <- tibble::tribble(
  ~keyword,
  ~replace_by,
  "super",
  "flextable::as_sup",
  "sub",
  "flextable::as_sub",
  "optional",
  ""
)

docx_markup_df
```

If a .docx file is to be created for the table, the `junco::export_as_docx_j` is to be called. For .docx files, the markup is different from .rtf files. In this example, when calling `junco::export_as_docx_j`, the "markup_df" argument has the default "docx_markup_df" object specified.


```{r superscript_table_docx}
library(junco)

adsl <- data.frame(TRT01A = c("Example Drug~[super a] 5 mg",
                              "Example Drug~[super a] 10 mg",
                              "Example Drug~[super a] 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
)

lyt <- basic_table(
  show_colcounts = FALSE,
  colcount_format = "N=xx"
) |>
  ### first columns
  split_cols_by("TRT01A",,
                show_colcounts = FALSE
  ) |>
  ### analyze height
  analyze("HEIGHT", afun = list_wrap_x(summary), format = "xx.xx")

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)

```

```{r superscript_table_docx_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
export_as_docx_j(result,
                tblid = "superscripttable",
                output_dir = out_dir,
                orientation = "landscape",
                markup_df = docx_markup_df)
```




### Visual Output (HTML Representation)
```{r superscript_table_rtf_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "superscripttable", orientation = "landscape",  markup_df = dps_markup_df)
```

### Listing .rtf File

If a .rtf file is to be created for the listing, a superscript "a" can be
inserted into the column header by updating the variable label that
corresponds with the column of interest.

By adding in "~[super a]" to the TRT01A variable label, a superscript "a" is
added to the column label.

```{r superscript_listing_rtf}
library(junco)
library(rlistings)

adsl <- data.frame(TRT01A = c("Example Drug 5 mg",
                              "Example Drug 10 mg",
                              "Example Drug 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
) |>
  formatters::var_relabel(TRT01A = "Actual Treatment for Period 01~[super a]") |>
  formatters::var_relabel(SUBJECT = "Subject") |>
  formatters::var_relabel(HEIGHT = "Height (in)")

result <- rlistings::as_listing(
  df = adsl,
  key_cols = c("TRT01A", "SUBJECT"),
  disp_cols = "HEIGHT"
)
result <- set_titles(result, titles)
```

```{r superscript_listing_rtf_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/examplelistingsuperscript2"),
             orientation = "landscape")
```



### Listing .docx File

The default markup file for `junco::export_as_docx_j` to produce a .docx file is as follows.

```{r default_markup_docx}
library(tibble)

docx_markup_df <- tibble::tribble(
  ~keyword,
  ~replace_by,
  "super",
  "flextable::as_sup",
  "sub",
  "flextable::as_sub",
  "optional",
  ""
)

docx_markup_df
```

If a .docx file is to be created for the table, the `junco::export_as_docx_j` is to be called. For .docx files, the markup is different from .rtf files. In this example, when calling `junco::export_as_docx_j`, the "markup_df" argument has the default "docx_markup_df" object specified.

```{r superscript_listing_docx}

library(junco)
library(rlistings)

adsl <- data.frame(TRT01A = c("Example Drug 5 mg",
                              "Example Drug 10 mg",
                              "Example Drug 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
) |>
  formatters::var_relabel(TRT01A = "Actual Treatment for Period 01~[super a]") |>
  formatters::var_relabel(SUBJECT = "Subject") |>
  formatters::var_relabel(HEIGHT = "Height (in)")

result <- rlistings::as_listing(
  df = adsl,
  key_cols = c("TRT01A", "SUBJECT"),
  disp_cols = "HEIGHT"
)
result <- set_titles(result, titles)

```

```{r superscript_listing_docx_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
export_as_docx_j(result,
                tblid = "examplelistingsuperscript2",
                output_dir = out_dir,
                orientation = "landscape",
                markup_df = docx_markup_df)
```
### Visual Output (HTML Representation)
```{r superscript_listing_rtf_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result, "examplelistingsuperscript2", orientation = "landscape",  markup_df = dps_markup_df)
```


## Grouping of Columns for Tables Containing Many Columns

In some cases, there are tables that are required that contain many columns. As a result, it's possible that the table might need to be split into multiple files so that the information can be presented in a readable manner. Oftentimes, it's important to keep certain information grouped together in the same file. The following is an example of this scenario.

Data Preparation for example

```{r multiple_docs_data_prep}
library(tern)
library(dplyr)
library(rtables)
library(junco)

################################################################################
# Define script level parameters:
################################################################################

string_map <- default_str_map
trtvar <- "TRT01A"
popfl <- "SAFFL"

################################################################################
# Process Data:
################################################################################

adsl <- pharmaverseadamjnj::adsl %>%
  filter(!!rlang::sym(popfl) == "Y") %>%
  select(STUDYID, USUBJID, all_of(trtvar), all_of(popfl), RACE)

adae <- pharmaverseadamjnj::adae %>%
  filter(TRTEMFL == "Y" & AEBODSYS == "Skin and subcutaneous tissue disorders") %>%
  select(USUBJID, TRTEMFL, AEBODSYS, AEDECOD, RACE)

adsl$colspan_trt <- factor(ifelse(adsl[[trtvar]] == "Placebo", " ", "Active Study Agent"),
                           levels = c("Active Study Agent", " ")
)

colspan_trt_map <- create_colspan_map(adsl,
                                      non_active_grp = "Placebo",
                                      non_active_grp_span_lbl = " ",
                                      active_grp_span_lbl = "Active Study Agent",
                                      colspan_var = "colspan_trt",
                                      trt_var = trtvar
)

# Add total for Race - adsl
totalrace1 <- adsl %>%
  filter(RACE != "UNKNOWN" & !is.na(RACE)) %>%
  mutate(RACE = "Total")

adsl <- bind_rows(totalrace1, adsl)

adsl <- adsl %>%
  mutate(RACEcat = case_when(
    RACE == "Total" ~ "Total",
    RACE == "WHITE" ~ "White",
    RACE == "BLACK OR AFRICAN AMERICAN" ~ "Black",
    RACE == "ASIAN" ~ "Asian",
    RACE != "UNKNOWN" & !is.na(RACE) ~ "Other"
  )) %>%
  filter(RACEcat %in% c("Total", "White", "Black", "Asian", "Other")) %>%
  select(-RACE)

adsl$spanheader <- factor(ifelse(adsl$RACEcat == "Total", " ", "Race"),
                          levels = c(" ", "Race")
)

adsl$RACEcat <- factor(adsl$RACEcat, levels = c("Total", "White", "Black", "Asian", "Other"))

# Add total for Race - adae
totalrace2 <- adae %>%
  filter(RACE != "UNKNOWN" & !is.na(RACE)) %>%
  mutate(RACE = "Total")

adae <- bind_rows(totalrace2, adae)

adae <- adae %>%
  mutate(RACEcat = case_when(
    RACE == "Total" ~ "Total",
    RACE == "WHITE" ~ "White",
    RACE == "BLACK OR AFRICAN AMERICAN" ~ "Black",
    RACE == "ASIAN" ~ "Asian",
    RACE != "UNKNOWN" & !is.na(RACE) ~ "Other"
  )) %>%
  filter(RACEcat %in% c("Total", "White", "Black", "Asian", "Other")) %>%
  select(-RACE)

adae$RACEcat <- factor(adae$RACEcat, levels = c("Total", "White", "Black", "Asian", "Other"))

# join data together
ae <- left_join(adsl, adae, by = c("USUBJID", "RACEcat"))

################################################################################
# Define layout and build table:
################################################################################

extra_args_1 <- list(denom = "n_altdf",
                     .stats = c("count_unique_fraction")
)


extra_args_2 <- list(denom = "n_altdf",
                     .stats = c("count_unique")
)



lyt <- basic_table(
  top_level_section_div = " ",
  show_colcounts = FALSE
) %>%
  split_cols_by("colspan_trt", split_fun = trim_levels_to_map(map = colspan_trt_map))

lyt <- lyt %>%
  split_cols_by(trtvar)

lyt <- lyt %>%
  split_cols_by("spanheader", split_fun = trim_levels_in_group("RACEcat")) %>%
  split_cols_by("RACEcat") %>%
  analyze(popfl,
          afun = a_freq_j,
          show_labels = "hidden",
          section_div = c(" "),
          extra_args = append(extra_args_2,
                              list(
                                label = "Analysis set: Safety",
                                val = "Y",
                                section_div = c(" ")))
  ) %>%
  analyze("TRTEMFL",
          afun = a_freq_j,
          show_labels = "hidden",
          extra_args = append(extra_args_1,
                              list(label = "Subjects with >=1 AE",
                                   val = "Y",
                                   section_div = c(" ")))
  ) %>%
  split_rows_by("AEBODSYS",
                split_label = "System Organ Class",
                split_fun = trim_levels_in_group("AEDECOD"),
                label_pos = "topleft",
                section_div = c(" "),
                nested = FALSE
  ) %>%
  summarize_row_groups("AEBODSYS",
                       cfun = a_freq_j,
                       extra_args = extra_args_1
  ) %>%
  analyze("AEDECOD",
          afun = a_freq_j,
          extra_args = extra_args_1
  ) %>%
  append_topleft("  Preferred Term, n (%)")

result <- build_table(lyt, ae, alt_counts_df = adsl)
result <- set_titles(result, titles)
#########################################################################################
# Post-Processing step to sort by descending count on chosen active treatment columns.
# For this table we can use a defined colpath so it takes the appropriate sub-column ("Total")
# for the last active treatment group/combined and use this for its sort order.
# If you only have 1 active treatment arm, consider using jj_complex_scorefun(spanningheadercolvar = NA, usefirstcol = TRUE)
# See function documentation for jj_complex_scorefun should your require a different sorting behavior.
#########################################################################################

# col_paths_summary(result)

if (length(adae$TRTEMFL) != 0) {
  result <- sort_at_path(result, c("root", "AEBODSYS"),
                         scorefun = jj_complex_scorefun(colpath = c("colspan_trt", "Active Study Agent", trtvar, "Xanomeline High Dose", "spanheader", " ", "RACEcat", "Total"))
  )
  result <- sort_at_path(result, c("root", "AEBODSYS", "*", "AEDECOD"),
                         scorefun = jj_complex_scorefun(colpath = c("colspan_trt", "Active Study Agent", trtvar, "Xanomeline High Dose", "spanheader", " ", "RACEcat", "Total"))
  )
}
```

### Table .rtf File
By default, the `junco::tt_to_tlgrtf` function determines the appropriate place to break the columns so that the created files contain an appropriate number of columns that contain readable data. The default logic might not be ideal, as sometimes columns that make sense to be grouped together to appear within the same file, are not. This can be seen in the example call below, where the race information for the "Placebo" treatment group is split across files.
```{r multiple_docs_table1}
################################################################################
# Convert to tbl file and output table
################################################################################

```

```{r multiple_docs_table1_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(string_map = string_map, tt = result,
             file = paste0(out_dir, "/aetablemultipledocs1"), orientation = "landscape"
)
```

### Visual Output (HTML Representation)
```{r multiple_docs_table1_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
x <- tt_to_flextable_j(string_map = string_map, tt = result, "aetablemultipledocs1", orientation = "landscape", paginate= TRUE)
x[[1]]
knitr::asis_output("<br><br>")
x[[2]]
knitr::asis_output("<br><br>")
```

When calling the `junco::tt_to_tlgrtf` function, the `nosplitin` argument can be included, and the user can specify a variable in which the associated columns should be grouped together in the same file. Now, all the sub columns for the "Placebo" treatment group (e.g. each unique TRT01A value), are kept together within the same file.
```{r multiple_docs_table2}
################################################################################
# Convert to tbl file and output table
################################################################################

```

```{r multiple_docs_table2_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(string_map = string_map, tt = result,
             file = paste0(out_dir, "/aetablemultipledocs2"), orientation = "landscape",
             nosplitin = list(cols = c(trtvar))
)
```

### Visual Output (HTML Representation)
```{r multiple_docs_table2_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
x <- tt_to_flextable_j(string_map = string_map, tt = result, "aetablemultipledocs2", orientation = "landscape",
                  nosplitin = list(cols = c(trtvar)), paginate= TRUE)
x[[1]]
knitr::asis_output("<br><br>")
x[[2]]
knitr::asis_output("<br><br>")
x[[3]]
knitr::asis_output("<br><br>")

```

If there is a need to provide a single .rtf file that contains the multiple “part” .rtf files, then the `junco::tt_to_tlgrtf` function can be called with the "combined_rtf" argument included with a value of "TRUE". In this case, both the multiple "part" .rtf files and the single .rtf file with all "parts" appended will be created.


```{r multiple_docs_table3_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(string_map = string_map, tt = result,
             file = paste0(out_dir, "/aetablemultipledocs3"), orientation = "landscape",
             nosplitin = list(cols = c(trtvar)),
             combined_rtf = TRUE
)
```

### Visual Output (HTML Representation)
```{r multiple_docs_table3_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
x <- tt_to_flextable_j(string_map = string_map, tt = result, "aetablemultipledocs3", orientation = "landscape",
                  nosplitin = list(cols = c(trtvar)), combined_rtf = TRUE, paginate = TRUE)
x[[1]]
knitr::asis_output("<br><br>")
x[[2]]
knitr::asis_output("<br><br>")
x[[3]]
knitr::asis_output("<br><br>")
```

### Table .docx File

## Inserting Page Breaks in Tables
It is sometimes necessary to insert page breaks into tables, to indicate that a new grouping of rows is occurring. This can be achieved by including `rtables::split_rows_by within` the layout definition and specifying the `page_by` argument with a value of "TRUE". In the following example, the table is being split by the SEX variable. When specifying `page_by` = "TRUE", each new observed value of SEX (and the subsequent rows generated form the `rtables::analyze` function call) will be separated by a page break.

```{r page_break_table}
library(junco)

adsl <- data.frame(TRT01A = factor(c("Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo",
                                     "Example Drug 5 mg",
                                     "Example Drug 10 mg",
                                     "Example Drug 20 mg",
                                     "Placebo"),
                                   levels = c("Example Drug 5 mg",
                                              "Example Drug 10 mg",
                                              "Example Drug 20 mg",
                                              "Placebo"
                                              )
                              ),
                   USUBJID = c("1",
                               "2",
                               "3",
                               "4",
                               "5",
                               "6",
                               "7",
                               "8"),
                   RESPONSE = factor(c("Yes",
                                       "No",
                                       "Yes",
                                       "Yes",
                                       "Yes",
                                       "No",
                                       "Yes",
                                       "No"),
                                     levels = c("Yes",
                                                "No")
                              ),
                   SEX = factor(c("Male",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Female",
                                  "Male",
                                  "Female",
                                  "Male"),
                                levels = c("Male",
                                           "Female")
                           )
) |>
  var_relabel(RESPONSE = "Response")

lyt <- basic_table(
  show_colcounts = TRUE,
  colcount_format = "N=xx"
) |>
  ### first columns
  split_cols_by("TRT01A",
                show_colcounts = FALSE
  ) |>
  ### create table body row sections based on SEX
  split_rows_by("SEX",
                section_div = c(" "),
                page_by = TRUE,
                split_fun = drop_split_levels
                ) |>
  summarize_row_groups("SEX",
                       cfun =a_freq_j,
                       extra_args = list(denom = "n_df",
                                         denom_by = "SEX",
                                         riskdiff = FALSE,
                                         extrablankline = TRUE,
                                         .stats = c("count_unique")
                                         )
                       ) |>
  ### analyze height
  analyze("RESPONSE",
          var_labels = c("Response"),
          show_labels = "visible",
          afun = a_freq_j,
          extra_args = list(denom = "n_df",
                            denom_by = "SEX",
                            riskdiff = FALSE,
                            .stats = c("count_unique_fraction")
                            )
          )

result <- build_table(lyt, adsl)
result <- set_titles(result, titles)
```

```{r page_break_table_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result,
             file = paste0(out_dir, "/examplepagebreak"))
```

### Visual Output (HTML Representation)
> **Note:** HTML output notoriously does not handle well page break, so here it is represented in two parts to show the point.
```{r page_break_table_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
male <- result[1:5, keep_titles = TRUE, keep_footers = FALSE]
tt_to_flextable_j(male, "examplepagebreak")
knitr::asis_output("<br><br>")
```


```{r page_break_table_display_part2, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}

female <- result[6:10, keep_titles = TRUE, keep_footers = TRUE]
tt_to_flextable_j(female, "examplepagebreak")
```

## Manually Splitting Large Listing Files into Multiple Smaller Files
In rare cases, the listing files produced are large in size (e.g. >20 MB). There can be multiple reasons why this occurs, but a common example is that there is a need to present longitudinal data for a large trial. In this scenario, it might be beneficial to create multiple smaller files instead of a single large file. This can be achieved by subsetting the data and then calling the necessary exporter function multiple times.

### Listing .rtf File
The `junco::tt_to_tlgrtf` function can be called multiple times to produce multiple .rtf files.
```{r split_listing_part1}
library(junco)
library(rlistings)

adsl <- data.frame(TRT01A = c("Example Drug 5 mg",
                              "Example Drug 10 mg",
                              "Example Drug 20 mg",
                              "Placebo"),
                   SUBJECT = c("1",
                               "2",
                               "3",
                               "4"),
                   HEIGHT = c(70,
                              74,
                              60,
                              64
                   )
) |>
  formatters::var_relabel(TRT01A = "Actual Treatment for Period 01~[super a]") |>
  formatters::var_relabel(SUBJECT = "Subject") |>
  formatters::var_relabel(HEIGHT = "Height (in)")

result <- rlistings::as_listing(
  df = adsl,
  key_cols = c("TRT01A", "SUBJECT"),
  disp_cols = "HEIGHT"
)
result <- set_titles(result, titles)
keep <- result$TRT01A %in% c("Example Drug 5 mg", "Example Drug 10 mg")

result1 <- result[keep, ]
```

```{r split_listing_part1_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result1,
  file = paste0(out_dir, "/examplelistingmultiplefilesPART1OF2"),
  orientation = "landscape"
)
```


### Listing .docx File
The `junco::export_as_docx_j` function can be called multiple times to produce multiple .docx files, similar to the approach used for .rtf files:

```{r split_listing_docx_part1_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}

export_as_docx_j(result1,
  tblid = "examplelistingmultiplefilesPART1OF2",
  output_dir = out_dir,
  orientation = "landscape"
)
```

### Visual Output (HTML Representation)
```{r split_listing_part1_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result1, "examplelistingmultiplefilesPART1OF2",
  orientation = "landscape")
```

### Listing .rtf File 2

```{r split_listing_part2}

keep <- result$TRT01A %in% c("Example Drug 20 mg", "Placebo")

result2 <- result[keep, ]
```

```{r split_listing_part2_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}
tt_to_tlgrtf(result2,
  file = paste0(out_dir, "/examplelistingmultiplefilesPART2OF2"),
  orientation = "landscape"
)
```


### Listing .docx File 2
```{r split_listing_docx_part2_export, eval=NOT_CRAN, message=FALSE, warning=FALSE}

export_as_docx_j(result2,
  tblid = "examplelistingmultiplefilesPART2OF2",
  output_dir = out_dir,
  orientation = "landscape"
)
```

### Visual Output (HTML Representation)
```{r split_listing_part2_display, echo=FALSE, fig.align="center", out.width="100%", out.height="200px"}
tt_to_flextable_j(result2, "examplelistingmultiplefilesPART2OF2",
  orientation = "landscape")
```
