--- 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` |