---
title: "Saving and Sharing Your Tables"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Saving and Sharing Your Tables}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

```{r setup}
library(tsg)
library(dplyr)
```

Once you have a table, `tsg` can save it to a file in several formats. The steps are always the same: generate the table, optionally add a title and notes, then call the appropriate `write_*()` function.

**Which format should I use?**

| Format | Best for |
|--------|----------|
| **Excel** (`.xlsx`) | Sharing with colleagues, further editing |
| **HTML** | Embedding in a website or report |
| **PDF** | Print-ready documents |
| **Word** (`.docx`) | Inserting into a Word report or document |

Excel is the most fully-featured output and requires no additional packages beyond `tsg`. The other formats need a few extra packages — details in their sections below.

All examples use the `person_record` sample dataset included with the package.

---

## Saving to Excel

Use `write_xlsx()` to save any table to an `.xlsx` file.

### Basic save

```{r}
person_record |>
  generate_frequency(sex)
```

```{r, eval=FALSE}
person_record |>
  generate_frequency(sex) |>
  write_xlsx(path = "table-sex.xlsx")
```

```{r, echo=FALSE, out.width="80%", eval=file.exists("../man/figures/output-formats-t1.png")}
knitr::include_graphics("../man/figures/output-formats-t1.png")
```

### Add a title, subtitle, and notes

Chain `add_table_title()`, `add_table_subtitle()`, `add_source_note()`, and `add_footnote()` before saving. These appear as styled rows above and below the table in the Excel file.

```{r}
person_record |>
  generate_crosstab(marital_status, sex) |>
  add_table_title("Marital Status by Sex") |>
  add_table_subtitle("National Sample Survey, 2024") |>
  add_source_note("Source: person_record dataset.") |>
  add_footnote("Missing values are excluded from the denominator.")
```

```{r, eval=FALSE}
person_record |>
  generate_crosstab(marital_status, sex) |>
  add_table_title("Marital Status by Sex") |>
  add_table_subtitle("National Sample Survey, 2024") |>
  add_source_note("Source: person_record dataset.") |>
  add_footnote("Missing values are excluded from the denominator.") |>
  write_xlsx(path = "table-marital-sex.xlsx")
```

```{r, echo=FALSE, out.width="80%", eval=file.exists("../man/figures/output-formats-t7.png")}
knitr::include_graphics("../man/figures/output-formats-t7.png")
```

> **Shortcut:** You can also pass the title, subtitle, and notes directly as arguments to `write_xlsx()` instead of chaining the helper functions.
>
> ```r
> person_record |>
>   generate_crosstab(marital_status, sex) |>
>   write_xlsx(
>     path        = "table-marital-sex.xlsx",
>     title       = "Marital Status by Sex",
>     subtitle    = "National Sample Survey, 2024",
>     source_note = "Source: person_record dataset.",
>     footnotes   = "Missing values are excluded from the denominator."
>   )
> ```

### More table examples

#### Frequency table with running totals

```{r}
person_record |>
  generate_frequency(sex, add_cumulative = TRUE, add_cumulative_percent = TRUE)
```

```{r, eval=FALSE}
person_record |>
  generate_frequency(sex, add_cumulative = TRUE, add_cumulative_percent = TRUE) |>
  write_xlsx(path = "table-sex-cumulative.xlsx")
```

```{r, echo=FALSE, out.width="80%", eval=file.exists("../man/figures/output-formats-t2.png")}
knitr::include_graphics("../man/figures/output-formats-t2.png")
```

#### Grouped frequency table

Pipe a `group_by()` before `generate_frequency()` to stratify the output. The result is a single flat table with group labels in the category column.

```{r}
person_record |>
  group_by(sex) |>
  generate_frequency(employed)
```

```{r, eval=FALSE}
person_record |>
  group_by(sex) |>
  generate_frequency(employed) |>
  write_xlsx(path = "table-employed-by-sex.xlsx")
```

```{r, echo=FALSE, out.width="80%", eval=file.exists("../man/figures/output-formats-t3.png")}
knitr::include_graphics("../man/figures/output-formats-t3.png")
```

#### Basic cross-tabulation

```{r}
person_record |>
  generate_crosstab(employed, sex)
```

```{r, eval=FALSE}
person_record |>
  generate_crosstab(employed, sex) |>
  write_xlsx(path = "crosstab-employed-sex.xlsx")
```

```{r, echo=FALSE, out.width="80%", eval=file.exists("../man/figures/output-formats-t4.png")}
knitr::include_graphics("../man/figures/output-formats-t4.png")
```

#### Cross-tabulation with column percentages

```{r}
person_record |>
  generate_crosstab(employed, sex, percent_by_column = TRUE)
```

```{r, eval=FALSE}
person_record |>
  generate_crosstab(employed, sex, percent_by_column = TRUE) |>
  write_xlsx(path = "crosstab-column-pct.xlsx")
```

```{r, echo=FALSE, out.width="80%", eval=file.exists("../man/figures/output-formats-t5.png")}
knitr::include_graphics("../man/figures/output-formats-t5.png")
```

### Save multiple tables to one workbook

Pass a **named list** to `write_xlsx()`. Each element becomes a separate worksheet. The name of each list element becomes the sheet name.

```{r, eval=FALSE}
tables <- list(
  "Sex"        = person_record |> generate_frequency(sex),
  "Employment" = person_record |> generate_frequency(employed),
  "Crosstab"   = person_record |> generate_crosstab(employed, sex)
)

write_xlsx(tables, path = "multi-sheet.xlsx")
```

### Save each table to its own file

Set `separate_files = TRUE` and provide a folder path instead of a file name. The folder is created if it does not exist.

```{r, eval=FALSE}
write_xlsx(tables, path = "output-dir/", separate_files = TRUE)
```

### Add an index sheet to a multi-table workbook

Set `include_table_list = TRUE` to prepend an auto-generated index sheet. This is useful for statistical reports with many tables.

```{r, eval=FALSE}
write_xlsx(tables, path = "report.xlsx", include_table_list = TRUE)
```

---

## Managing metadata for large reports

When you have many tables, it is more practical to keep all titles, subtitles, and notes in one place — a reference spreadsheet — rather than scattering them across your analysis script. `tsg` supports this with the `table_list_reference` argument.

### Step 1 — Create a template

```{r, eval=FALSE}
generate_template("table-list-template.xlsx", template = "table-list")
```

The template has one row per table with these columns:

| Column | What it contains |
|--------|-----------------|
| `table_id` | A unique identifier that must match the **name** of the list element in `write_xlsx()` |
| `table_number` | Display number shown in the index sheet |
| `table_name` | Short label shown in the index sheet |
| `title` | Full table title |
| `subtitle` | Optional subtitle |
| `footnotes` | Optional footnote text |
| `source_note` | Optional source line printed below the table |

### Step 2 — Fill in the reference data

Edit the template in Excel, or build it in R:

```{r, eval=FALSE}
table_ref <- tibble::tibble(
  table_id     = c("table_sex", "table_emp", "table_ct"),
  table_number = 1:3,
  table_name   = c("Sex", "Employment", "Employment × Sex"),
  title        = c(
    "Distribution by Sex",
    "Employment Status",
    "Employment Status by Sex"
  ),
  subtitle     = c(NA, NA, "Cross-tabulation"),
  footnotes    = NA,
  source_note  = "Source: person_record dataset."
)
```

### Step 3 — Export with the reference

The `table_id` values in your reference must match the names of your list. `write_xlsx()` looks up each table, applies its metadata, and builds the index sheet automatically.

```{r, eval=FALSE}
tables <- list(
  table_sex = person_record |> generate_frequency(sex),
  table_emp = person_record |> generate_frequency(employed),
  table_ct  = person_record |> generate_crosstab(employed, sex)
)

write_xlsx(
  tables,
  path                 = "report.xlsx",
  include_table_list   = TRUE,
  table_list_reference = table_ref
)
```

---

## Saving to HTML

> **Required package:** `gt` — install with `install.packages("gt")`

```{r, eval=FALSE}
person_record |>
  generate_frequency(sex) |>
  add_table_title("Distribution by Sex") |>
  write_html(path = "table-sex.html")
```

Cross-tabulations with grouped column headers are fully supported:

```{r, eval=FALSE}
person_record |>
  generate_crosstab(marital_status, sex) |>
  add_table_title("Marital Status by Sex") |>
  write_html(path = "crosstab.html")
```

### Multiple tables in one HTML file

When `data` is a named list, all tables are written to a single self-contained HTML file by default. Each table is wrapped in its own section. Set `include_table_list = TRUE` to add a clickable table of contents.

```{r, eval=FALSE}
tables <- list(
  "Sex"           = person_record |> generate_frequency(sex),
  "Marital Status"= person_record |> generate_frequency(marital_status),
  "Sex × Marital" = person_record |> generate_crosstab(sex, marital_status)
)

write_html(tables, path = "report.html", include_table_list = TRUE)
```

Set `separate_files = TRUE` to write each table to its own `.html` file in a folder.

```{r, eval=FALSE}
write_html(tables, path = "html-output/", separate_files = TRUE)
```

---

## Saving to PDF

> **Required packages:** `gt` and `webshot2` — install with `install.packages(c("gt", "webshot2"))`.  
> `webshot2` also requires a Chromium browser; run `webshot2::install_phantomjs()` or ensure Chrome/Chromium is available.

```{r, eval=FALSE}
person_record |>
  generate_frequency(sex) |>
  add_table_title("Distribution by Sex") |>
  write_pdf(path = "table-sex.pdf")
```

When `data` is a list, the default is one PDF file per table inside the specified folder:

```{r, eval=FALSE}
write_pdf(tables, path = "pdf-output/")
```

To combine all tables into a single PDF file, set `separate_files = FALSE` (requires the `qpdf` package):

```{r, eval=FALSE}
write_pdf(tables, path = "report.pdf", separate_files = FALSE)
```

---

## Saving to Word

> **Required packages:** `officer` and `flextable` — install with `install.packages(c("officer", "flextable"))`

```{r, eval=FALSE}
person_record |>
  generate_frequency(sex) |>
  add_table_title("Distribution by Sex") |>
  add_source_note("Source: person_record dataset") |>
  write_docx(path = "table-sex.docx")
```

Cross-tabulations are fully supported:

```{r, eval=FALSE}
person_record |>
  generate_crosstab(marital_status, sex) |>
  add_table_title("Marital Status by Sex") |>
  add_footnote("Missing values excluded from the denominator.") |>
  write_docx(path = "crosstab.docx")
```

When `data` is a named list, the default is a single `.docx` file with one table per page:

```{r, eval=FALSE}
tables <- list(
  "Sex"           = person_record |>
    generate_frequency(sex) |>
    add_table_title("Distribution by Sex"),
  "Marital Status"= person_record |>
    generate_frequency(marital_status) |>
    add_table_title("Distribution by Marital Status"),
  "Sex × Marital" = person_record |>
    generate_crosstab(sex, marital_status) |>
    add_table_title("Sex by Marital Status")
)

write_docx(tables, path = "report.docx")
```

Set `separate_files = TRUE` to write each table to its own `.docx` file:

```{r, eval=FALSE}
write_docx(tables, path = "docx-output/", separate_files = TRUE)
```

---

## Summary

| Format  | Function        | Key packages                       |
|---------|-----------------|------------------------------------|
| Excel   | `write_xlsx()`  | *(none beyond tsg)*                |
| HTML    | `write_html()`  | `gt`                               |
| PDF     | `write_pdf()`   | `gt`, `webshot2` (+ `qpdf` for combined) |
| Word    | `write_docx()`  | `officer`, `flextable`             |
