Add gtsummary_to_reporter_clinical() with documentation, exports, and test coverage#183
Add gtsummary_to_reporter_clinical() with documentation, exports, and test coverage#183dustreturn wants to merge 1 commit intoinsightsengineering:mainfrom
Conversation
… data.frame) into clinical-style reporter outputs, generating RTF/TXT reports with support for column label and width control, spanning headers, pagination, indentation/group formatting, auto title/footnote pickup from environment variables, and optional export of processed output data plus ARD as RDS files.
|
I have read the CLA Document and I hereby sign the CLA Xiecheng Gu seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. |
| group_columns = NULL, | ||
| group_blank_after = TRUE) { | ||
|
|
||
| strip_md_bold <- function(x) { |
There was a problem hiding this comment.
helper functions should be outside the main function body and with a bit of documentation
| #' @export | ||
|
|
||
|
|
||
| gtsummary_to_reporter_clinical <- function(gts_obj, file_path = "Clinical_Report.rtf", |
There was a problem hiding this comment.
The name of this function is not very intuitive. I would change it to something more readable like export_gts_to_rtf or save or tbl_to_rtf or similar
| max_table_width = NULL, min_col_width = 0.6, | ||
| column_widths = NULL, | ||
| column_labels = NULL, | ||
| spanning_headers = NULL, |
There was a problem hiding this comment.
spanning headers can be added in gtsummary. This parameter is not needed
| gtsummary_to_reporter_clinical <- function(gts_obj, file_path = "Clinical_Report.rtf", | ||
| max_table_width = NULL, min_col_width = 0.6, | ||
| column_widths = NULL, | ||
| column_labels = NULL, |
There was a problem hiding this comment.
also column labels can be defined in gtsummary. not needed
| report_margins = NULL, | ||
| report_font_size = 9, | ||
| indent_unit = 1, | ||
| output_types = c("RTF", "TXT"), |
There was a problem hiding this comment.
the output extension should decide this
| debug_indent = FALSE, | ||
| debug_spanning = FALSE, |
There was a problem hiding this comment.
these should NOT be user-facing. There are many tools to do debugging without adding special handling
| group_columns = NULL, | ||
| group_blank_after = TRUE) { |
There was a problem hiding this comment.
difficult to understand what these do. blank rows can be added in gtsummary
There was a problem hiding this comment.
From a user’s perspective, I have a specific reason for using the reporter parameter: for instance, when multiple gtsummary objects are stacked together, manually calling add_blank_row for each one can be quite tedious. The reporter package offers an option to automatically insert blank rows based on groups without affecting the core content.
But I agree that, in principle, it might be more appropriate to handle all table-building within gtsummary itself.
| # ============================================================================= | ||
| # Script: gtsummary_to_reporter_clinical | ||
| # | ||
| # Packages referenced: | ||
| # - gtsummary: table building and styling | ||
| # - reporter: RTF/TXT report generation | ||
| # - tidyverse: dplyr/tidyr helpers used in processing | ||
| # | ||
| # Function arguments (gtsummary_to_reporter_clinical): | ||
| # - gts_obj: gtsummary object or plain data.frame to export | ||
| # - file_path: output path (extension determines RTF/TXT names) | ||
| # - max_table_width: max width (inches/cm) for all columns combined | ||
| # - min_col_width: minimum width for any column |
There was a problem hiding this comment.
This part comes from a copy-paste and should not be here
| #' Convert a `gtsummary` object (or a plain `data.frame`) into a `reporter` | ||
| #' table and write RTF and/or TXT outputs. The function is designed for | ||
| #' clinical reporting workflows and supports column labels, spanning headers, | ||
| #' pagination, indentation handling, and optional export of intermediate data. |
There was a problem hiding this comment.
The concept of reporter output is a too specific. I would keep the terminology general and bound to the output format
| #' @param gts_obj A `gtsummary` object (with `table_body`/`table_styling`) or | ||
| #' a plain `data.frame` to export. | ||
| #' @param file_path Output path. The extension is ignored and output files are | ||
| #' written according to `output_types`. | ||
| #' @param max_table_width Maximum total table width. If `NULL`, derived from | ||
| #' `report_paper_size`, `report_orientation`, `report_units`, and | ||
| #' `report_margins`. |
There was a problem hiding this comment.
wrong parameter doc formats
| } | ||
|
|
||
| # A. Extract data and styling metadata | ||
| has_table_body <- is.data.frame(gts_obj) && "table_body" %in% names(gts_obj) |
There was a problem hiding this comment.
input checks are MISSING
| footnotes_vec <- strip_md_bold(footnotes_vec) | ||
|
|
||
|
|
||
| resolve_rows <- function(row_spec, data) { |
There was a problem hiding this comment.
not very clear what this function does? I would suggest more comments and a better function flow
|
|
||
| ### Export gtsummary tables to reporter RTF/TXT | ||
|
|
There was a problem hiding this comment.
Do not repeat this here. Also, it is not the main output for everyone
Melkiades
left a comment
There was a problem hiding this comment.
Thanks for your contribution! :)
The main function has too many subfunctions added inside of it without enough comments and lacking a bit of scoping clarity. This renders everything difficult to review. Please also reformat the PR text in a clear way.
Also remember, before any coding work it is good practice to create an issue with clear goals and implementation ideas. There, for example, we could have discussed the existence of a possible better place for this PR in the {pager} package. That may be a cleaner solution to output rtf
|
@dustreturn consider also adding PRs as draft if not ready to review ;) |
|
|
||
|
|
Thank you! I will optimize the function based on your comments above. |
I originally intended to use one of them as the output method. flextable, in particular, aligns well with the required formats for clinical reports. Other options are not that good. While flextable needs to be paired with officer, there are persistent issues like pagination. I’ve previously consulted on stackoverflow https://stackoverflow.com/questions/79774759/how-to-further-fine-tune-the-rtf-output-of-gtsummary-when-pagination-is-needed. It seemed {pager} might solve this, but upon closer review, it primarily supports .docx and lacks robust support for RTF/TXT formats. In contrast, the {reporter} package covers almost all standard clinical reporting requirements (comparable to SAS PROC REPORT). From a clinical programmer's perspective, there’s hardly a better alternative. That’s why I tried to explore the possibility of integrating these two packages. |


Why this change
Clinical trial reporting requires strict table layout and output standards, especially for RTF and TXT deliverables.
This PR introduces gtsummary_to_reporter_clinical() to produce outputs that better align with clinical reporting style requirements, using reporter as the rendering engine.
reporter is a strong fit for this use case because it provides robust support for RTF/TXT generation and table-level formatting controls commonly needed in submission-oriented workflows. In practice, this workflow can serve as a near drop-in replacement for many traditional SAS PROC REPORT table delivery patterns.
What I changed
Added gtsummary_to_reporter_clinical() to convert gtsummary tables (or plain data frames) into clinical-style reporter tables.
Implemented support for:
RTF/TXT export
column label and width control
spanning headers
indentation and grouping behavior
pagination control
optional RDS export of processed output data and ARD
Added complete function documentation:
roxygen docs in R/gtsummary_to_reporter_clinical.r
manual page man/gtsummary_to_reporter_clinical.Rd
Updated examples to use real gtsummary input objects.
Exported the function in NAMESPACE.
Added reporter to Suggests in DESCRIPTION.
Added README documentation for the gtsummary -> reporter export workflow.
Added a NEWS entry for the new functionality.
Added test coverage to verify TXT export from a gtsummary object.
Why these implementation choices
Clinical style compliance: The function design focuses on formatting controls expected in clinical outputs.
Format fit: reporter natively supports high-quality RTF and TXT, making it well suited for table delivery pipelines.
Migration value: This setup helps teams move from SAS-style table production to an R-native workflow with minimal loss of reporting fidelity.
Package stability: Explicit namespace calls and documentation/test coverage improve maintainability and reproducibility.
Xiecheng Gu