---
title: "Definition of a gtsummary Object"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Definition of a gtsummary Object}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

This vignette is meant for those who wish to contribute to {gtsummary}, or users who wish to gain an understanding of the inner-workings of a {gtsummary} object so they may more easily modify them to suit your own needs.
If this does not describe you, please refer to the [{gtsummary} website](https://www.danieldsjoberg.com/gtsummary/) to an introduction on how to use the package's functions and tutorials on advanced use.

## Introduction

Every {gtsummary} table has a few characteristics common among all tables created with the package.
Here, we review those characteristics, and provide instructions on how to construct a {gtsummary} object.

```{r setup, message=FALSE}
library(gtsummary)

tbl_regression_ex <-
  lm(age ~ grade + marker, trial) %>%
  tbl_regression() %>%
  bold_p(t = 0.5)

tbl_summary_ex <-
  trial %>%
  select(trt, age, grade, response) %>%
  tbl_summary(by = trt)
```

## Structure of a {gtsummary} object

Every {gtsummary} object is a list comprising of, at minimum, these elements:

```r
.$table_body    .$table_styling         
```

#### table_body

The `.$table_body` object is the data frame that will ultimately be printed as the output.
The table must include columns `"label"`, `"row_type"`, and `"variable"`.
The `"label"` column is printed, and the other two are hidden from the final output.

```{r}
tbl_summary_ex$table_body
```

#### table_styling

The `.$table_styling` object is a list of data frames containing information about how `.$table_body` is printed, formatted, and styled.  
The list contains the following data frames `header`, `footnote`, `footnote_abbrev`, `fmt_fun`, `text_format`, `fmt_missing`, `cols_merge` and the following objects `source_note`, `caption`, `horizontal_line_above`.

**`header`**

The `header` table has the following columns and is one row per column found in `.$table_body`.
The table contains styling information that applies to entire column or the columns headers.

```{r, echo=FALSE}
dplyr::tribble(
  ~Column, ~Description,
  "column", "Column name from `.$table_body`",
  "hide", "Logical indicating whether the column is hidden in the output. This column is also scoped in `modify_header()` (and friends) to be used in a selecting environment",
  "align", "Specifies the alignment/justification of the column, e.g. 'center' or 'left'",
  "label", "Label that will be displayed (if column is displayed in output)",
  "interpret_label", "the {gt} function that is used to interpret the column label, `gt::md()` or `gt::html()`",
  "spanning_header", "Includes text printed above columns as spanning headers.",
  "interpret_spanning_header", "the {gt} function that is used to interpret the column spanning headers, `gt::md()` or `gt::html()`",
  "modify_stat_{*}", "any column beginning with `modify_stat_` is a statistic available to report in `modify_header()` (and others)",
  "modify_selector_{*}", "any column beginning with `modify_selector_` is a column that is scoped in `modify_header()` (and friends) to be used in a selecting environment"
) %>%
  gt::gt() %>%
  gt::fmt_markdown(columns = everything()) %>%
  gt::tab_options(
    table.font.size = "small",
    data_row.padding = gt::px(1),
    summary_row.padding = gt::px(1),
    grand_summary_row.padding = gt::px(1),
    footnotes.padding = gt::px(1),
    source_notes.padding = gt::px(1),
    row_group.padding = gt::px(1)
  )
```

**`footnote` & `footnote_abbrev`**

Each {gtsummary} table may contain a single footnote per header and cell within the table.
Footnotes and footnote abbreviations are handled separately. 
Updates/changes to footnote are appended to the bottom of the tibble.
A footnote of `NA_character_` deletes an existing footnote.

```{r, echo=FALSE}
dplyr::tribble(
  ~Column, ~Description,
  "column", "Column name from `.$table_body`",
  "rows", "expression selecting rows in `.$table_body`, `NA` indicates to add footnote to header",
  "footnote", "string containing footnote to add to column/row"
) %>%
  gt::gt() %>%
  gt::fmt_markdown(columns = everything()) %>%
  gt::tab_options(
    table.font.size = "small",
    data_row.padding = gt::px(1),
    summary_row.padding = gt::px(1),
    grand_summary_row.padding = gt::px(1),
    footnotes.padding = gt::px(1),
    source_notes.padding = gt::px(1),
    row_group.padding = gt::px(1)
  )
``` 

**`fmt_fun`**

Numeric columns/rows are styled with the functions stored in `fmt_fun`.
Updates/changes to styling functions are appended to the bottom of the tibble.


```{r, echo=FALSE}
dplyr::tribble(
  ~Column, ~Description,
  "column", "Column name from `.$table_body`",
  "rows", "expression selecting rows in `.$table_body`",
  "fmt_fun", "list of formatting/styling functions"
) %>%
  gt::gt() %>%
  gt::fmt_markdown(columns = everything()) %>%
  gt::tab_options(
    table.font.size = "small",
    data_row.padding = gt::px(1),
    summary_row.padding = gt::px(1),
    grand_summary_row.padding = gt::px(1),
    footnotes.padding = gt::px(1),
    source_notes.padding = gt::px(1),
    row_group.padding = gt::px(1)
  )
``` 

**`text_format`**

Columns/rows are styled with bold, italic, or indenting stored in `text_format`.
Updates/changes to styling functions are appended to the bottom of the tibble.


```{r, echo=FALSE}
dplyr::tribble(
  ~Column, ~Description,
  "column", "Column name from `.$table_body`",
  "rows", "expression selecting rows in `.$table_body`",
  "format_type", "one of `c('bold', 'italic', 'indent')`",
  "undo_text_format", "logical indicating where the formatting indicated should be undone/removed."
) %>%
  gt::gt() %>%
  gt::fmt_markdown(columns = everything()) %>%
  gt::tab_options(
    table.font.size = "small",
    data_row.padding = gt::px(1),
    summary_row.padding = gt::px(1),
    grand_summary_row.padding = gt::px(1),
    footnotes.padding = gt::px(1),
    source_notes.padding = gt::px(1),
    row_group.padding = gt::px(1)
  )
``` 

**`fmt_missing`**

By default, all `NA` values are shown blanks.
Missing values in columns/rows are replaced with the `symbol`.
For example, reference rows in `tbl_regression()` are shown with an em-dash.
Updates/changes to styling functions are appended to the bottom of the tibble.

```{r, echo=FALSE}
dplyr::tribble(
  ~Column, ~Description,
  "column", "Column name from `.$table_body`",
  "rows", "expression selecting rows in `.$table_body`",
  "symbol", "string to replace missing values with, e.g. an em-dash"
) %>%
  gt::gt() %>%
  gt::fmt_markdown(columns = everything()) %>%
  gt::tab_options(
    table.font.size = "small",
    data_row.padding = gt::px(1),
    summary_row.padding = gt::px(1),
    grand_summary_row.padding = gt::px(1),
    footnotes.padding = gt::px(1),
    source_notes.padding = gt::px(1),
    row_group.padding = gt::px(1)
  )
``` 

**`cols_merge`**

This object is _experimental_ and may change in the future.
This tibble gives instructions for merging columns into a single column.
The implementation in `as_gt()` will be updated after `gt::cols_label()` gains a `rows=` argument.

```{r, echo=FALSE}
dplyr::tribble(
  ~Column, ~Description,
  "column", "Column name from `.$table_body`",
  "rows", "expression selecting rows in `.$table_body`",
  "pattern", "glue pattern directing how to combine/merge columns. The merged columns will replace the column indicated in 'column'."
) %>%
  gt::gt() %>%
  gt::fmt_markdown(columns = everything()) %>%
  gt::tab_options(
    table.font.size = "small",
    data_row.padding = gt::px(1),
    summary_row.padding = gt::px(1),
    grand_summary_row.padding = gt::px(1),
    footnotes.padding = gt::px(1),
    source_notes.padding = gt::px(1),
    row_group.padding = gt::px(1)
  )
``` 

**`source_note`**

A tibble with the source notes to include.
Each source note is assigned an ID based on the order it is added to the table.

```{r, echo=FALSE}
dplyr::tribble(
  ~Column, ~Description,
  "id", "ID of the source note",
  "sounrce_note", "string containing the source note", 
  "text_interpret", "the {gt} function that is used to interpret the source note, `gt::md()` or `gt::html()`",
  "remove", "logical indicating whether the source note should be removed from the table"
) %>%
  gt::gt() %>%
  gt::fmt_markdown(columns = everything()) %>%
  gt::tab_options(
    table.font.size = "small",
    data_row.padding = gt::px(1),
    summary_row.padding = gt::px(1),
    grand_summary_row.padding = gt::px(1),
    footnotes.padding = gt::px(1),
    source_notes.padding = gt::px(1),
    row_group.padding = gt::px(1)
  )
``` 
**`caption`**

String that is made into the table caption.
The attribute `"text_interpret"` is either `c("md", "html")`.

**`horizontal_line_above`**

Expression identifying a row where a horizontal line is placed above in the table.

Example from `tbl_regression()`

```{r} 
tbl_regression_ex$table_styling
```

## Constructing a {gtsummary} object

#### table_body

When constructing a {gtsummary} object, the author will begin with the `.$table_body` object.
Recall the `.$table_body` data frame must include columns `"label"`, `"row_type"`, and `"variable"`.
Of these columns, only the `"label"` column will be printed with the final results.
The `"row_type"` column typically will control whether or not the label column is indented.
The `"variable"` column is often used in the `inline_text()` family of functions, and merging {gtsummary} tables with `tbl_merge()`.

```{r}
tbl_regression_ex %>%
  getElement("table_body") %>%
  select(variable, row_type, label)
```

The other columns in `.$table_body` are created by the user and are likely printed in the output.
Formatting and printing instructions for these columns is stored in `.$table_styling`.

### table_styling

There are a few internal {gtsummary} functions to assist in constructing and modifying a `.$table_header` data frame.

1. `.create_gtsummary_object(table_body)` After a user creates a `table_body`, pass it to this function and the skeleton of a gtsummary object is created and returned (including the full `table_styling` list of tables).

1. `.update_table_styling()` After columns are added or removed from `table_body`, run this function to update `.$table_styling` to include or remove styling instructions for the columns. FYI the default styling for each new column is to hide it.

1. `modify_table_styling()` This exported function modifies the printing instructions for a single column or groups of columns.

1. `modify_table_body()` This exported function helps users make changes to `.$table_body`. The function runs `.update_table_styling()` internally to maintain internal validity with the printing instructions.

## Printing a {gtsummary} object

All {gtsummary} objects are printed with `print.gtsummary()`.
Before a {gtsummary} object is printed, it is converted to a {gt} object using `as_gt()`.
This function takes the {gtsummary} object as its input, and uses the information in `.$table_styling` to construct a list of {gt} calls that will be executed on `.$table_body`.
After the {gtsummary} object is converted to {gt}, it is then printed as any other {gt} object.

In some cases, the package defaults to printing with other engines, such as flextable (`as_flex_table()`), huxtable (`as_hux_table()`), kableExtra (`as_kable_extra()`),  and kable (`as_kable()`).
The default print engine is set with the theme element `"pkgwide-str:print_engine"`

While the actual print function is slightly more involved, it is basically this:

```{r, eval = FALSE}
print.gtsummary <- function(x) {
  get_theme_element("pkgwide-str:print_engine") %>%
    switch(
      "gt" = as_gt(x),
      "flextable" = as_flex_table(x),
      "huxtable" = as_hux_table(x),
      "kable_extra" = as_kable_extra(x),
      "kable" = as_kable(x)
    ) %>%
    print()
}
```

## The `.$cards` object

When a gtsummary function is called that requires new statistics, these new calculations are stored in a tibble.
These tibbles are often calculated with functions from the {cards} and {cardx} packages.

These structured tibbles store labels for statistics, functions to format them, and more.
See the {cards} package documentation for details.

```{r}
tbl_summary_ex$cards[["tbl_summary"]]
```
