In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
-
Our Standards
+
Our Standards
+
Examples of behavior that contributes to creating a positive environment include:
-
Using welcoming and inclusive language
+
+
Using welcoming and inclusive language
Being respectful of differing viewpoints and experiences
Gracefully accepting constructive criticism
Focusing on what is best for the community
Showing empathy towards other community members
-
Examples of unacceptable behavior by participants include:
-
The use of sexualized language or imagery and unwelcome sexual attention or advances
+
+
Examples of unacceptable behavior by participants include:
+
+
The use of sexualized language or imagery and unwelcome sexual attention or advances
Trolling, insulting/derogatory comments, and personal or political attacks
Public or private harassment
Publishing others’ private information, such as a physical or electronic address, without explicit permission
Other conduct which could reasonably be considered inappropriate in a professional setting
-
+
+
-
Our Responsibilities
+
Our Responsibilities
+
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
-
Scope
+
Scope
+
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
-
Enforcement
+
Enforcement
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at support@github.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.
We welcome contributions big and small to the ongoing development of the {rtables} package. For most, the best way to contribute to the package is by filing issues for feature requests or bugs that you have encountered. For those who are interested in contributing code to the package, contributions can be made by working on current issues and opening pull requests with code changes. Any help that you are able to provide is greatly appreciated!
Contributions to this project are released to the public under the project’s open source license.
-
-
Filing Issues
+
+
+
Filing Issues
+
Issues are used to establish a prioritized timeline and track development progress within the package. If there is a new feature that you feel would be enhance the experience of package users, please open a Feature Request issue. If you notice a bug in the existing code, please file a Bug Fix issue with a description of the bug and a reprex (reproducible example). Other types of issues (questions, typos you’ve noticed, improvements to documentation, etc.) can be filed as well. Click here to file a new issue, and here to see the list of current issues. Please utilize labels wherever possible when creating issues for organization purposes and to narrow down the scope of the work required.
-
+
+
-
Creating Pull Requests
+
Creating Pull Requests
+
Development of the {rtables} package relies on an Issue → Branch → PR → Code Review → Merge pipeline facilitated through GitHub. If you are a more experienced programmer interested in contributing to the package code, please begin by filing an issue describing the changes you would like to make. It may be the case that your idea has already been implemented in some way, and the package maintainers can help to determine whether the feature is necessary before you begin development. Whether you are opening an issue or a pull request, the more detailed your description, the easier it will be for package maintainers to help you! To make code changes in the package, please follow the following process.
-
Pull Request Process
+
Pull Request Process
+
The {rtables} package is part of the NEST project and utilizes staged.dependencies to ensure to simplify the development process and track upstream and downstream package dependencies. We highly recommend installing and using this package when developing within {rtables}.
-
1. Create a branch
+
1. Create a branch
+
In order to work on a new pull request, please first create a branch off of main upon which you can work and commit changes. To comply with staged.dependencies standards, {rtables} uses the following branch naming convention:
issue#_description_of_issue@target_merge_branch
For example, 443_refactor_splits@main. In most cases, the target merge branch is the base (main) branch.
Work within the {rtables} package to apply your code changes. Avoid combining issues on a single branch - ideally, each branch should be associated with a single issue and be prefixed by the issue number.
For information on the basics of the {rtables} package, please read the package vignettes, which are available here.
For advanced development work within {rtables}, consider reading through the {rtables} Developer Guide. The Developer Guide can be accessed from the {rtables} site navigation bar, and is listed here for your convenience:
The {rtables} package follows the tidyverse style guide so please adhere to these guidelines in your submitted code. After making changes to a file within the package, you can apply the package styler automatically and check for lint by running the following two lines of code while within the file:
styler:::style_active_file()lintr:::addin_lint()
-
Documentation
+
Documentation
+
Package documentation uses roxygen2. If your contribution requires updates to documentation, ensure that the roxygen comments are updated within the source code file. After updating roxygen documentation, run devtools::document() to update the accompanying .Rd files (do not update these files by hand!).
-
Tests
+
Tests
+
To ensure high code coverage, we create tests using the testthat package. In most cases, changes to package code necessitate the addition of one or more tests to ensure that any added features are working as expected and no existing features were broken.
-
NEWS
+
NEWS
+
After making updates to the package, please add a descriptive entry to the NEWS file that reflects your changes. See the tidyverse style guide for guidelines on creating a NEWS entry.
-
3. Make a Pull Request
+
3. Make a Pull Request
+
Once the previous two steps are complete, you can create a pull request. Indicate in the description which issue is addressed in the pull request, and again utilize labels to help reviewers identify the category of the changes contained within the pull request.
Once your pull request has been created, a series of checks will be automatically triggered, including R CMD check, tests/code coverage, auto-documentation, and more. All checks must be passing in order to eventually merge your pull request, and further changes may be required in order to resolve the status of these checks. All pull requests must also be reviewed and approved by at least one of the package maintainers before they can be merged. A review will be automatically requested from several {rtables} maintainers upon creating your pull request. When a maintainer reviews your pull request, please try to address the comments in short order - the {rtables} package is updated on a regular basis and leaving a pull request open too long is likely to result in merge conflicts which create more work for the developer.
-
Code of Conduct
+
Code of Conduct
+
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
Please briefly describe your problem and, when relevant, the output you expect. Please also provide the output of utils::sessionInfo() or devtools::session_info() at the end of your post.
If at all possible, please include a minimal, reproducible example. The rtables team will be much more likely to resolve your issue if they are able to reproduce it themselves locally.
Please delete this preamble after you have read it.
Experimental pagination is now possible in tt_as_flextable() and export_as_docx().
+
New Features
+
+
+
Experimental pagination is now possible in tt_as_flextable() and export_as_docx().
Added handling of widths in tt_as_flextable(). Now it is possible to change column widths for .docx exports.
Initialized vignette about quality control outputs of as_result_df().
Completed parameter make_ard output for single-line statistical outputs.
Added stat_names to rcell() to be used by as_result_df(make_ard = TRUE).
-
+
+
-
Miscellaneous
-
Split docx document generation to the new package rtables.officer.
+
Miscellaneous
+
+
+
Split docx document generation to the new package rtables.officer.
Refactored as_result_df() parameters as_strings and as_viewer into data_format = c("full_precision", "strings", "numeric") following the same outputs.
Refactored as_result_df() to have a standard behavior, with all the relevant parameters, and a possibility to add personalized spec.
Removed result_df_specs(), because as_result_df() was a too shallow wrapper.
Merged behavior of as_result_df() parameters as_is and simplify parameters to remove structural information.
-
+
+
-
Bug Fixes
-
Fixed bug that was keeping indentation space characters in top left information when making a flextable from a TableTree object.
+
Bug Fixes
+
+
+
Fixed bug that was keeping indentation space characters in top left information when making a flextable from a TableTree object.
Fixed bug in analyze that was causing an error when passing a single NA value to the var_labels parameter.
Fixed bugs for multiple analyze calls in as_result_df.
-
+
+
-
rtables 0.6.10
CRAN release: 2024-09-20
+
rtables 0.6.10
+
+
CRAN release: 2024-09-20
-
New Features
-
Added top left information handling (now bold and bottom aligned).
+
New Features
+
+
+
Added top left information handling (now bold and bottom aligned).
Added section_properties_default() function to define standard portrait properties for tables.
Added default theme for .html outputs.
Added parameter bold_titles to tt_to_flextable() to bold titles.
Now users can add more than one theme to tt_to_flextable(), and/or extend themes.
-
+
+
-
Enhancements
-
Modified reorder_split_levels() to cover more edge cases and be more stringent in the allowed inputs.
+
Enhancements
+
+
+
Modified reorder_split_levels() to cover more edge cases and be more stringent in the allowed inputs.
Removed table tree tt input from theme_docx_default() and added code to handle row classes and number of columns internally.
Reworked padding and spacing in default theme theme_docx_default().
Added parameter bold_titles to tt_to_flextable() to bold titles.
-
+
+
-
Bug Fixes
-
Fixed "\n" newline issues in as_html by relying onto output devices for newline handling. Added expand_newlines = FALSE default to allow previous behavior.
+
Bug Fixes
+
+
+
Fixed "\n" newline issues in as_html by relying onto output devices for newline handling. Added expand_newlines = FALSE default to allow previous behavior.
keep_split_levels() throws now an error if the user requests to keep levels that are not present in data.
Fixed issue with removal of horizontal lines in tt_as_flextable() header when title was added.
Fixed multiple counts in header issue when exporting to flextable.
Fixed issue with empty cells "" having larger imposed margins than filled cell. They are transformed into " " before rendering.
Fixed issue with borders appearing in theme_docx_default() when only one line of column names is present, but top left information is on multiple lines.
-
+
+
-
Miscellaneous
-
Added option to change sep = "\t" and set other parameters via ... parameter propagation in export_as_tsv.
+
Miscellaneous
+
+
+
Added option to change sep = "\t" and set other parameters via ... parameter propagation in export_as_tsv.
Added developer’s guide vignette. New materials are focused on printing methods, specifically matrix_form and toString.
Grouped split functions documentation into one page with precise descriptions of each function and relative examples.
Moved simple_analysis into utils file.
Added examples to theme_docx_default() showing how to extend the default theme.
Added the possibility to remove internal borders from label rows in theme_html_default().
Split export functions into separate source files. Similarly for test files.
-
+
+
-
rtables 0.6.9
CRAN release: 2024-06-27
+
rtables 0.6.9
+
+
CRAN release: 2024-06-27
-
Miscellaneous
-
Update col_counts vignette wording, as CRAN macOS check failed. Raised the issue with the R-core team already.
-
+
Miscellaneous
+
+
+
Update col_counts vignette wording, as CRAN macOS check failed. Raised the issue with the R-core team already.
+
+
-
rtables 0.6.8
CRAN release: 2024-06-20
+
rtables 0.6.8
+
+
CRAN release: 2024-06-20
-
New Features
-
Add support for truetype fonts based on formatters version >= 0.5.8. Nearly all functions related to pagination or export now accept fontspec argument and pass it around accordingly, by @gmbecker.
+
New Features
+
+
+
Add support for truetype fonts based on formatters version >= 0.5.8. Nearly all functions related to pagination or export now accept fontspec argument and pass it around accordingly, by @gmbecker.
Core splitting machinery can now be overridden in column space via make_split_fun provided that core_split associates the generated facets with subsetting expressions. Subsetting expressions remain unnecessary for splits in row space. By @gmbecker.
ValueWrapper objects now carry around subsetting expressions for use during tabulation, by @gmbecker.
New facet_colcounts_visible setter to conveniently set the column count visibility of a set of sibling facets in column space
New rm_all_colcounts convenience function for turning off visibility all column counts throughout the column structure @gmbecker.
-
+
+
-
Bug Fixes
-
Fixed bug in as_html preventing indentation from being applied in Viewer output.
+
Bug Fixes
+
+
+
Fixed bug in as_html preventing indentation from being applied in Viewer output.
col_counts<- and col_total<- methods now explicitly convert value to integer, by @gmbecker.
col_gap is now respected in nlines row methods, and thus by make_row_df, by @gmbecker.
-
+
+
-
Miscellaneous
-
Added lifecycle badge files for deprecated documentation.
+
Miscellaneous
+
+
+
Added lifecycle badge files for deprecated documentation.
Deprecated the gap and check_headers arguments to rbindl_rtables using lifecycle.
-
+
+
-
rtables 0.6.7
CRAN release: 2024-04-15
+
rtables 0.6.7
+
+
CRAN release: 2024-04-15
-
New Features
-
Added top_level_section_div for basic_table to set section dividers for top level rows.
+
New Features
+
+
+
Added top_level_section_div for basic_table to set section dividers for top level rows.
Added keep_label_rows to as_result_df to have these lines visible.
sort_at_path now gives informative error messages when the given path does not exist.
-
+
+
-
Bug Fixes
-
Fixed rlistings decoration (e.g. titles and footers) expansion when there are new lines. Moved relevant handling from rtables’ matrix_form function to formatters’ dedicated mform_handle_newlines function.
+
Bug Fixes
+
+
+
Fixed rlistings decoration (e.g. titles and footers) expansion when there are new lines. Moved relevant handling from rtables’ matrix_form function to formatters’ dedicated mform_handle_newlines function.
Fixed issue with rtables_root not being removed when using as_result_df.
Fixed edge case bug in as_result_df where rows of the table have only "root" as path index.
Fixed sort_at_path pathing to ignore leading "root" element (regardless of actual root element name) to match current tt_at_path behavior.
Removed deprecated functions add_analyzed_var and trim_zero_rows.
-
+
Miscellaneous
+
+
+
Removed deprecated functions add_analyzed_var and trim_zero_rows.
+
+
-
rtables 0.6.6
CRAN release: 2023-12-08
+
rtables 0.6.6
+
+
CRAN release: 2023-12-08
-
New Features
-
Removed ref_group reordering in column splits so not to change the order.
+
New Features
+
+
+
Removed ref_group reordering in column splits so not to change the order.
Added bold argument to as_html to bold specified elements, and header_sep_line argument to print a horizontal line under the table header in rendered HTML output.
Duplicate referential footnotes are consolidated when tables are rendered.
Added support for white spaces in all labels and text by redesigning of wrapping functions in formatters.
+
New Features
+
+
+
Added support for white spaces in all labels and text by redesigning of wrapping functions in formatters.
Added support for new line characters across rtables (titles, column names, row names, footers, and na_str).
Modified top left information vertical alignment to stay at the bottom of the header.
-
+
+
-
Bug Fixes
-
Fixed a bug causing Viewer and as_html to fail when new line characters were added.
-
+
Bug Fixes
+
+
+
Fixed a bug causing Viewer and as_html to fail when new line characters were added.
+
+
-
Miscellaneous
-
Added slide decks for advanced training as internal files.
-
+
Miscellaneous
+
+
+
Added slide decks for advanced training as internal files.
+
+
-
rtables 0.6.4
+
rtables 0.6.4
+
-
New Features
-
Added support for .docx exports with export_as_docx().
+
New Features
+
+
+
Added support for .docx exports with export_as_docx().
Expanded support for flextable customization with theme function specific for word documents (theme_docx_default()).
-
+
+
-
Bug Fixes
-
Fixed bug causing all-NA rows to be included in every .df_row split.
-
+
Bug Fixes
+
+
+
Fixed bug causing all-NA rows to be included in every .df_row split.
+
+
-
Miscellaneous
-
Specified minimal version of package dependencies.
-
+
Miscellaneous
+
+
+
Specified minimal version of package dependencies.
+
+
-
rtables 0.6.3
CRAN release: 2023-08-30
+
rtables 0.6.3
+
+
CRAN release: 2023-08-30
-
New Features
-
Analysis functions (cfun/afun) can use new parameters to extend analysis calculations: .alt_df_row and .alt_df give access to alt_counts_df across columns, while .all_col_exprs and .all_col_counts contains global information about all columns.
+
New Features
+
+
+
Analysis functions (cfun/afun) can use new parameters to extend analysis calculations: .alt_df_row and .alt_df give access to alt_counts_df across columns, while .all_col_exprs and .all_col_counts contains global information about all columns.
Binding objects via rbind will retain titles/footer information if identical in all objects or only present in the first object being bound.
-
+
+
-
Enhancements
-
Analysis functions (cfun/afun) have more information about current column split; .spl_context has access to cur_col_id, cur_col_expr, cur_col_split, and cur_col_split_val.
+
Enhancements
+
+
+
Analysis functions (cfun/afun) have more information about current column split; .spl_context has access to cur_col_id, cur_col_expr, cur_col_split, and cur_col_split_val.
Added vignette on exploratory analysis with qtable.
Extracted qtable_layout from qtable.
-
+
+
-
Bug Fixes
-
Page-by splits which generate zero facets (and thus tables which would have zero pages when rendered) now throw an informative error at table build time.
+
Bug Fixes
+
+
+
Page-by splits which generate zero facets (and thus tables which would have zero pages when rendered) now throw an informative error at table build time.
Fixed major regressions for page_by machinery caused by migration to formatters 0.5.1 pagination framework.
+
rtables 0.6.2
+
+
+
Fixed major regressions for page_by machinery caused by migration to formatters 0.5.1 pagination framework.
Fixed page_by labels become missing when only one level exist in the split_rows_by.
Fixed a bug when dropping var levels but not lblvar levels.
Added checks to catch bad labels (with {}) and throw informative error.
Added qtable function to create a table with a single top-level structure in both row and column dimensions involving faceting by 0 or more variables in each.
Added as_result_df function to flatten a table into a dataframe.
Added sanitize_table_struct, validate_table_struct, find_degen_struct to support degenerative table rendering.
-
+
+
-
rtables 0.6.1
CRAN release: 2023-05-25
-
Improved resilience of pagination machinery (paginate_table) by generalizing parameters’ defaults (cpp, lpp, and font_size).
+
rtables 0.6.1
+
+
CRAN release: 2023-05-25
+
+
Improved resilience of pagination machinery (paginate_table) by generalizing parameters’ defaults (cpp, lpp, and font_size).
Moved export_as_txt to formatters. Added to reexports.
Migrated export_as_rtf to formatters. Not re-exported.
formatable dependency renamed to formatters for suitability of release to CRAN
Update versioned dependency of formatters (previously formatable) to >=0.2.0
-
+
+
-
rtables 0.4.1.0004
-
Fix bug when function format combined with NULL cfun caused error (#307)
+
rtables 0.4.1.0004
+
+
+
Fix bug when function format combined with NULL cfun caused error (#307)
Fix bug in path_enriched_df (which powers tsv export), related to (#308)
-
+
+
-
rtables 0.4.1.0002
-
added table_shell to display shell of table with formats
-
+
rtables 0.4.1.0002
+
+
+
added table_shell to display shell of table with formats
+
+
-
rtables 0.4.1.0001
-
added linesep argument to toString to specify a character to create the line separator. Previously we used the en dash as the line separator character, now we changed the default to the em dash reducing the gap between the dash line elements.
-
+
rtables 0.4.1.0001
+
+
+
added linesep argument to toString to specify a character to create the line separator. Previously we used the en dash as the line separator character, now we changed the default to the em dash reducing the gap between the dash line elements.
+
+
-
rtables 0.4.0
CRAN release: 2021-10-06
-
Initializing layouts with NULL is now deprecated
+
rtables 0.4.0
+
+
CRAN release: 2021-10-06
+
+
Initializing layouts with NULL is now deprecated
insert_rrow is deprecated in favor of new insert_row_at_path and label_at_path<- functions
split and analysis/content functions can now depend on values of splits they are nested inside by accepting and using the new .spl_context optional argument
new trim_levels_to_map split function based on [@wwojciech](https://github.com/wwojciech)’s work in #203
+
rtables 0.3.8.9001
+
+
+
new trim_levels_to_map split function based on [@wwojciech](https://github.com/wwojciech)’s work in #203
support for column referential footnotes
support for adding footnotes to existing table via fnotes_at_path<- function
@@ -511,13 +713,18 @@
rtables
value_at and cell_values now work for tablerow objects
Fixed as_html bug in multivar split columns case
Fixed pagination off-by-one error
-
+
+
-
rtables 0.3.8.9000
+
rtables 0.3.8.9000
+
-
rtables 0.3.8
CRAN release: 2021-07-13
-
Add experimental support for newlines in column names, row labels, and cell values (not supported in top-left annotations)
+
rtables 0.3.8
+
+
CRAN release: 2021-07-13
+
+
Add experimental support for newlines in column names, row labels, and cell values (not supported in top-left annotations)
as_html refactored to support newlines while respecting table structure
self_extent column of df returned by make_row_df now reflects extent in lines, thus will return larger values if the row-label or any cell values contain newlines.
Documentation revisions as requested by CRAN. No change to package code.
-
rtables 0.3.5
+
rtables 0.3.5
+
Documentation-text only changes to introduction vignette to pass CRAN’s URL checks. All package, example, test, and vignette code fully identical to that in tagged GitHub release 0.3.4
-
rtables 0.3.4
+
rtables 0.3.4
+
Minor changes to the 0.3.3 version in order to submit rtables to CRAN.
-
rtables 0.3.3
+
rtables 0.3.3
+
This version completely refactors the rtables package. We do provide a backwards compatibility layer with the rtable, rcell, rrow, rheader, and rtabulate family of functions. However the table data structure and main tabulation framework have changed. We provide extensive documentation in the manuals help(package = "rtables") and vignettes vignette(package = "rtables") of the package.
The changes to rtables have been undertaken to better meet the requirements of creating and analyzing & reporting tables in the context of clinical trials.
-
rtables 0.3.2.17.9046
-
+
rtables 0.3.2.17.9046
+
+
+
make_afun now force()s all customization arguments immediately, which prevents problems when called within loop/lapply constructs.
-
+
+
-
rtables 0.3.2.17.9045
-
Tabulation machinery no longer removes NAs mandatorily in some cases, including multivar column splits
+
rtables 0.3.2.17.9045
+
+
+
Tabulation machinery no longer removes NAs mandatorily in some cases, including multivar column splits
analyze_colvars’s inclNAs argument now respected.
-
+
+
-
rtables 0.3.2.17.9044
-
Fix indent modifier propagation during tabulation
+
rtables 0.3.2.17.9044
+
+
+
Fix indent modifier propagation during tabulation
Fix indent calculation in make_pagdf
Add significant testing to ensure make_pagdf indent calculation remains correct
-
+
+
-
rtables 0.3.2.17.9043
-
Rework how reference columns are handled so analyses which use .in_ref_col and .ref_group work correctly when custom splitting is used (including the provided combination-levels mechanism)
-
+
rtables 0.3.2.17.9043
+
+
+
Rework how reference columns are handled so analyses which use .in_ref_col and .ref_group work correctly when custom splitting is used (including the provided combination-levels mechanism)
+
+
-
rtables 0.3.2.17.9042
-
Fix naming/pathing for columns in multivar case (split itself now has default name "multivars")
+
rtables 0.3.2.17.9042
+
+
+
Fix naming/pathing for columns in multivar case (split itself now has default name "multivars")
Fix labeling bug when same variable appears multiple times in MultiVarSplit with different associated levels
-
+
+
-
rtables 0.3.2.17.9041
-
Allow single variable to be used within split_cols_by_multivar
+
rtables 0.3.2.17.9041
+
+
+
Allow single variable to be used within split_cols_by_multivar
Various removal of defunct
-
+
+
-
rtables 0.3.2.17.9040
-
Fix regression caused by 0.3.2.17.9039 where column split values were displayed by name rather than label.
-
+
rtables 0.3.2.17.9040
+
+
+
Fix regression caused by 0.3.2.17.9039 where column split values were displayed by name rather than label.
+
+
-
rtables 0.3.2.17.9039
-
Fix bug in display of column information when column structure is not symmetric, as with recursive cbinds.
-
+
rtables 0.3.2.17.9039
+
+
+
Fix bug in display of column information when column structure is not symmetric, as with recursive cbinds.
+
+
-
rtables 0.3.2.17.9036
-
Fixed bug in row subsetting when table has only content rows.
+
rtables 0.3.2.17.9036
+
+
+
Fixed bug in row subsetting when table has only content rows.
Basic compare_rtables function now works as in previous versions, no awareness of row or column structure.
-
+
+
-
rtables 0.3.2.17.9036
-
+
rtables 0.3.2.17.9036
+
+
+
summarize_row_groups can now accept a list of functions for the cfun argument as analyze_colvars does.
-
+
+
-
rtables 0.3.2.17.9035
-
Fix bug unearthed by change in 0.3.2.17.9034 where cell formats not retained during column subsetting
-
+
rtables 0.3.2.17.9035
+
+
+
Fix bug unearthed by change in 0.3.2.17.9034 where cell formats not retained during column subsetting
+
+
-
rtables 0.3.2.17.9034
-
Fix internal value_formats accessor so it operates on CellValues rather than the raw contained values (thus always returning NULL)
+
rtables 0.3.2.17.9034
+
+
+
Fix internal value_formats accessor so it operates on CellValues rather than the raw contained values (thus always returning NULL)
rrow constructor no longer interprets cell formats a row format when they are the same across all cells. Fixes bug in “correct way” code discussed in #112
-
+
+
-
rtables 0.3.2.17.9033
-
Interpret .formats in in_rows as cell formats rather than row formats.
-
+
rtables 0.3.2.17.9033
+
+
+
Interpret .formats in in_rows as cell formats rather than row formats.
+
+
-
rtables 0.3.2.17.9031
-
+
rtables 0.3.2.17.9031
+
+
+
cbind_rtables can now take more than 2 tables.
-
+
+
-
rtables 0.3.2.17.9029
-
Fix issue underlying spurious length-mismatch warning in some cases when using analyze_colvars
+
rtables 0.3.2.17.9029
+
+
+
Fix issue underlying spurious length-mismatch warning in some cases when using analyze_colvars
-
+
+
-
rtables 0.3.2.17.9028
-
+
rtables 0.3.2.17.9028
+
+
+
analyze_colvars now takes and adheres to inclNAs argument
-
+
+
-
rtables 0.3.2.17.9027
-
issues with no news:
-
+
rtables 0.3.2.17.9027
+
+
+
issues with no news:
+
+
-
rtables 0.1.7
-
added format xx.xx (xx.xx - xx.xx) and x.xxxx | (<0.0001)
+
rtables 0.1.7
+
+
+
added format xx.xx (xx.xx - xx.xx) and x.xxxx | (<0.0001)
-
+
+
-
rtables 0.1.6
-
Minor changes.
-
+
rtables 0.1.6
+
+
+
Minor changes.
+
+
-
rtables 0.1.5
-
Changed testing approach to fit internal pipelines.
-
+
rtables 0.1.5
+
+
+
Changed testing approach to fit internal pipelines.
+
+
-
rtables 0.1.4
-
Replaced dots to underscore in class checking functions.
-
+
rtables 0.1.4
+
+
+
Replaced dots to underscore in class checking functions.
rbind.rtable now supports binding rtables with rows, e.g. rbind(tbl1, rrow(), tbl2) or rbind(tbl1, rrow("row name"), tbl2).
rbindl_rtables supports NULL objects in the list (except for the first element).
Add indent function.
header_add_N deals gracefully with NULL objects.
-
+
+
-
rtables 0.1.1
-
+
rtables 0.1.1
+
+
+
rtablulate family of functions do not support the row_*_data_args arguments anymore. Instead, the col_wise_args argument is introduced.
Functions order_rrows, sort_rrows, order_rtables, and sort_rtables are introduced.
Prevent rtables from being unlisted with unlist.rtables.
-
+
+
-
rtables 0.1.0.6
-
+
rtables 0.1.0.6
+
+
+
Viewer now also accepts objects of class shiny.tag (defined in package htmltools).
as.html accepts class.table, class.tr, class.th, and class.td as an argument.
-
+
+
-
rtables 0.1.0.5
-
Added sprintf_format for formatting rcells (thanks to Doug Kelkhoff for the suggestion).
+
rtables 0.1.0.5
+
+
+
Added sprintf_format for formatting rcells (thanks to Doug Kelkhoff for the suggestion).
Added "(N=xx)" and ">999.9" format labels.
rtabulate has now an argument col_N and the function col_N().
-
+
+
-
rtables 0.1.0
-
Version 0.1.0 is a major re-design with lots of internal refactoring and the following API changes:
-
Redesign: rtable has now header argument instead of col.names. A header can be created with rheader and is a collection of rrows. If header is set to c("A", "B") then rtable will create the rheader with a single rrow and by setting row.name to NULL.
+
rtables 0.1.0
+
+
+
Version 0.1.0 is a major re-design with lots of internal refactoring and the following API changes:
+
+
Redesign: rtable has now header argument instead of col.names. A header can be created with rheader and is a collection of rrows. If header is set to c("A", "B") then rtable will create the rheader with a single rrow and by setting row.name to NULL.
header and header<- function added.
Renamed get_rcell_formats to list_rcell_format_labels.
(ANY) value in the cell exactly as it should be passed to a formatter or returned when extracted.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
colspan
+
colspan
+
(integer(1)) column span value.
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
footnotes
+
footnotes
+
(list or NULL) referential footnote messages for the cell.
-
align
+
align
+
(string or NULL) alignment the value should be rendered with. Defaults to "center" if
NULL is used. See formatters::list_valid_aligns() for all currently supported alignments.
-
format_na_str
+
format_na_str
+
(string) string which should be displayed when formatted if this cell's value(s)
are all NA.
-
stat_names
+
stat_names
+
(character or NA) names for the statistics in the cell. It can be a vector of strings.
If NA, statistic names are not specified.
-
+
+
-
Value
+
Value
+
An object representing the value within a single cell within a populated table. The underlying structure
of this object is an implementation detail and should not be relied upon beyond calling accessors for the class.
(character) levels of the split (i.e. the children of the manual split).
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
name
+
name
+
(string) name of the split/table/row being created. Defaults to the value of the
corresponding label, but is not required to be.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
cindent_mod
+
cindent_mod
+
(numeric(1)) the indent modifier for the content tables generated by this split.
-
cvar
+
cvar
+
(string) the variable, if any, that the content function should accept. Defaults to NA.
-
cextra_args
+
cextra_args
+
(list) extra arguments to be passed to the content function when tabulating row group
summaries.
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
page_prefix
+
page_prefix
+
(string) prefix to be appended with the split value when forcing pagination between
the children of a split/table.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
+
+
-
Value
+
Value
+
A ManualSplit object.
-
Author
+
Author
+
Gabriel Becker
+
+
-
+
+
-
+
+
diff --git a/main/reference/MultiVarSplit.html b/main/reference/MultiVarSplit.html
index 6e0287ca6..a4b3180bf 100644
--- a/main/reference/MultiVarSplit.html
+++ b/main/reference/MultiVarSplit.html
@@ -1,5 +1,28 @@
-
-Split between two or more different variables — MultiVarSplit • rtables
+
+
+
+
+
+
+Split between two or more different variables — MultiVarSplit • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -15,11 +38,13 @@
(string) label to be associated with the table generated by the split. Not to be confused
with labels assigned to each child (which are based on the data and type of split during tabulation).
-
varlabels
+
varlabels
+
(character) vector of labels for vars.
-
varnames
+
varnames
+
(character) vector of names for vars which will appear in pathing. When vars are all
unique this will be the variable names. If not, these will be variable names with suffixes as necessary to enforce
uniqueness.
-
cfun
+
cfun
+
(list, function, or NULL) tabulation function(s) for creating content rows. Must accept x
or df as first parameter. Must accept labelstr as the second argument. Can optionally accept all optional
arguments accepted by analysis functions. See analyze().
-
cformat
+
cformat
+
(string, function, or list) format for content rows.
-
cna_str
+
cna_str
+
(character) NA string for use with cformat for content table.
-
split_format
+
split_format
+
(string, function, or list) default format associated with the split being created.
-
split_na_str
+
split_na_str
+
(character) NA string vector for use with split_format.
-
split_name
+
split_name
+
(string) name associated with the split (for pathing, etc.).
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
cindent_mod
+
cindent_mod
+
(numeric(1)) the indent modifier for the content tables generated by this split.
-
cvar
+
cvar
+
(string) the variable, if any, that the content function should accept. Defaults to NA.
-
cextra_args
+
cextra_args
+
(list) extra arguments to be passed to the content function when tabulating row group
summaries.
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
split_fun
+
split_fun
+
(function or NULL) custom splitting function. See custom_split_funs.
-
page_prefix
+
page_prefix
+
(string) prefix to be appended with the split value when forcing pagination between
the children of a split/table.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
show_colcounts
+
show_colcounts
+
(logical(1)) should column counts be displayed at the level
facets created by this split. Defaults to FALSE.
-
colcount_format
+
colcount_format
+
(character(1)) if show_colcounts is TRUE, the
format which should be used to display column counts for facets generated by
this split. Defaults to "(N=xx)".
-
+
+
-
Value
+
Value
+
A MultiVarSplit object.
-
Author
+
Author
+
Gabriel Becker
+
+
-
+
+
-
+
+
diff --git a/main/reference/VarLevelSplit.html b/main/reference/VarLevelSplit.html
index 31c75dae6..9f54b4073 100644
--- a/main/reference/VarLevelSplit.html
+++ b/main/reference/VarLevelSplit.html
@@ -1,5 +1,28 @@
-
-Split on levels within a variable — VarLevelSplit-class • rtables
+
+
+
+
+
+
+Split on levels within a variable — VarLevelSplit-class • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -15,11 +38,13 @@
(string) label to be associated with the table generated by the split. Not to be confused
with labels assigned to each child (which are based on the data and type of split during tabulation).
-
labels_var
+
labels_var
+
(string) name of variable containing labels to be displayed for the values of var.
-
cfun
+
cfun
+
(list, function, or NULL) tabulation function(s) for creating content rows. Must accept x
or df as first parameter. Must accept labelstr as the second argument. Can optionally accept all optional
arguments accepted by analysis functions. See analyze().
-
cformat
+
cformat
+
(string, function, or list) format for content rows.
-
cna_str
+
cna_str
+
(character) NA string for use with cformat for content table.
-
split_fun
+
split_fun
+
(function or NULL) custom splitting function. See custom_split_funs.
-
split_format
+
split_format
+
(string, function, or list) default format associated with the split being created.
-
split_na_str
+
split_na_str
+
(character) NA string vector for use with split_format.
-
valorder
+
valorder
+
(character) the order that the split children should appear in resulting table.
-
split_name
+
split_name
+
(string) name associated with the split (for pathing, etc.).
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
cindent_mod
+
cindent_mod
+
(numeric(1)) the indent modifier for the content tables generated by this split.
-
cvar
+
cvar
+
(string) the variable, if any, that the content function should accept. Defaults to NA.
-
cextra_args
+
cextra_args
+
(list) extra arguments to be passed to the content function when tabulating row group
summaries.
-
page_prefix
+
page_prefix
+
(string) prefix to be appended with the split value when forcing pagination between
the children of a split/table.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
show_colcounts
+
show_colcounts
+
(logical(1)) should column counts be displayed at the level
facets created by this split. Defaults to FALSE.
-
colcount_format
+
colcount_format
+
(character(1)) if show_colcounts is TRUE, the
format which should be used to display column counts for facets generated by
this split. Defaults to "(N=xx)".
-
ref_group
+
ref_group
+
(character) value of var to be taken as the ref_group/control to be compared against.
-
label_fstr
+
label_fstr
+
(string) a sprintf style format string. For non-comparison splits, it can contain up to
one "\%s" which takes the current split value and generates the row/column label. For comparison-based splits
it can contain up to two "\%s".
-
+
+
-
Value
+
Value
+
a VarLevelSplit object.
-
Author
+
Author
+
Gabriel Becker
+
+
-
+
+
-
+
+
diff --git a/main/reference/Viewer.html b/main/reference/Viewer.html
index 25e2dea53..01b0a2e0c 100644
--- a/main/reference/Viewer.html
+++ b/main/reference/Viewer.html
@@ -1,5 +1,28 @@
-
-Display an rtable object in the Viewer pane in RStudio or in a browser — Viewer • rtables
+
+
+
+
+
+
+Display an rtable object in the Viewer pane in RStudio or in a browser — Viewer • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -15,11 +38,13 @@
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
-
Details
+
Details
+
It is often the case that the the column counts derived from the
input data to build_table() is not representative of the population counts.
For example, if events are counted in the table and the header should
display the number of subjects and not the total number of events.
add_combo_facet(name, label =name, levels, extra =list())add_overall_facet(name, label, extra =list())
-
Arguments
+
Arguments
+
-
name
+
+
name
+
(string) name for the resulting facet (for use in pathing, etc.).
-
label
+
label
+
(string) label for the resulting facet.
-
levels
+
levels
+
(character) vector of levels to combine within the resulting facet.
-
extra
+
extra
+
(list) extra arguments to be passed to analysis functions applied within the resulting facet.
-
+
+
-
Value
+
Value
+
A function which can be used within the post argument in make_split_fun().
-
Details
+
Details
+
For add_combo_facet, the data associated with the resulting facet will be the data associated with the facets for
each level in levels, row-bound together. In particular, this means that if those levels are overlapping, data
that appears in both will be duplicated.
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
tt
+
tt
+
(TableTree or related class) a TableTree object representing a populated table.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
(string) value to be assigned to the implicit all-observations split level. Defaults to
"Overall".
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
first
+
first
+
(flag) whether the implicit level should appear first (TRUE) or last (FALSE). Defaults
to TRUE.
-
trim
+
trim
+
(flag) whether splits corresponding with 0 observations should be kept when tabulating.
-
combosdf
+
combosdf
+
(data.frame or tbl_df) a data frame with columns valname, label, levelcombo, and
exargs. levelcombo and exargs should be list columns. Passing the select_all_levels object as a value in
comblevels column indicates that an overall/all-observations level should be created.
-
keep_levels
+
keep_levels
+
(character or NULL) if non-NULL, the levels to retain across both combination and
individual levels.
-
+
+
-
Value
+
Value
+
A splitting function (splfun) that adds or changes the levels of a split.
-
Note
+
Note
+
Analysis or summary functions for which the order matters should never be used within the tabulation framework.
If any of these formals is specified incorrectly or not present in the tabulation machinery, it will be
treated as if missing. For example, .ref_group will be missing if no baseline is previously defined during
data splitting (via ref_group parameters in, e.g., split_rows_by()). Similarly, if no alt_counts_df is
@@ -140,17 +197,19 @@
Note
+
+
-
+
+
-
+
+
diff --git a/main/reference/analyze.html b/main/reference/analyze.html
index 82d677462..7d69eaa8d 100644
--- a/main/reference/analyze.html
+++ b/main/reference/analyze.html
@@ -1,9 +1,32 @@
-
-Generate rows analyzing variables across columns — analyze • rtables
+
+
+
+
+
+Generate rows analyzing variables across columns — analyze • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+the tabulation will occur at the current/next level of nesting by default.">
+
+
+
+
+
Skip to contents
@@ -19,11 +42,13 @@
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
vars
+
vars
+
(character) vector of variable names.
-
afun
+
afun
+
(function) analysis function. Must accept x or df as its first parameter. Can optionally take
other parameters which will be populated by the tabulation framework. See Details in analyze().
-
var_labels
+
var_labels
+
(character) vector of labels for one or more variables.
-
table_names
+
table_names
+
(character) names for the tables representing each atomic analysis. Defaults to var.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
nested
+
nested
+
(logical) whether this layout instruction should be applied within the existing layout structure
if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split
underneath analyses, which is not allowed.
-
inclNAs
+
inclNAs
+
(logical) whether NA observations in the var variable(s) should be included when performing
the analysis. Defaults to FALSE.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
show_labels
+
show_labels
+
(string) whether the variable labels corresponding to the variable(s) in vars
should be visible in the resulting table.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
-
Details
+
Details
+
When non-NULL, format is used to specify formats for all generated rows, and can be a character vector, a
function, or a list of functions. It will be repped out to the number of rows once this is calculated during the
tabulation process, but will be overridden by formats specified within rcell calls in afun.
The analysis function (afun) should take as its first parameter either x or df. Whichever of these the
-function accepts will change the behavior when tabulation is performed as follows:
If afun's first parameter is x, it will receive the corresponding subset vector of data from the relevant
+function accepts will change the behavior when tabulation is performed as follows:
+
+
If afun's first parameter is x, it will receive the corresponding subset vector of data from the relevant
column (from var here) of the raw data being used to build the table.
If afun's first parameter is df, it will receive the corresponding subset data frame (i.e. all columns) of
the raw data being tabulated.
-
In addition to differentiation on the first argument, the analysis function can optionally accept a number of
+
+
In addition to differentiation on the first argument, the analysis function can optionally accept a number of
other parameters which, if and only if present in the formals, will be passed to the function by the tabulation
machinery. These are listed and described in additional_fun_params.
-
Note
+
Note
+
None of the arguments described in the Details section can be overridden via extra_args or when calling
make_afun(). .N_col and .N_total can be overridden via the col_counts argument to build_table().
Alternative values for the others must be calculated within afun based on a combination of extra arguments and
the unmodified values provided by the tabulation framework.
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
afun
+
afun
+
(function or list) function(s) to be used to calculate the values in each column. The list
will be repped out as needed and matched by position with the columns during tabulation. This functions
accepts the same parameters as analyze() like afun and format. For further information see
additional_fun_params.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
nested
+
nested
+
(logical) whether this layout instruction should be applied within the existing layout structure
if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split
underneath analyses, which is not allowed.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
inclNAs
+
inclNAs
+
(logical) whether NA observations in the var variable(s) should be included when performing
the analysis. Defaults to FALSE.
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
newlines
+
newlines
+
(character) the new line(s) to be added to the materials.
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
-
Details
+
Details
+
Adds newlines to the set of strings representing the 'top-left' materials declared in the layout (the content
displayed to the left of the column labels when the resulting tables are printed).
Top-left material strings are stored and then displayed exactly as is, no structure or indenting is applied to
them either when they are added or when they are displayed.
-
Note
+
Note
+
Currently, where in the construction of the layout this is called makes no difference, as it is independent of
the actual splitting keywords. This may change in the future.
This function is experimental, its name and the details of its behavior are subject to change in future versions.
(character) a string to indicate the desired width of the table. Common input formats include a
percentage of the viewer window width (e.g. "100%") or a distance value (e.g. "300px"). Defaults to NULL.
-
class_table
+
class_table
+
(character) class for table tag.
-
class_tr
+
class_tr
+
(character) class for tr tag.
-
class_th
+
class_th
+
(character) class for th tag.
-
link_label
+
link_label
+
(character) link anchor label (not including tab: prefix) for the table.
-
bold
+
bold
+
(character) elements in table output that should be bold. Options are "main_title",
"subtitles", "header", "row_names", "label_rows", and "content_rows" (which includes any non-label
rows). Defaults to "header".
-
header_sep_line
+
header_sep_line
+
(flag) whether a black line should be printed to under the table header. Defaults
to TRUE.
-
no_spaces_between_cells
+
no_spaces_between_cells
+
(flag) whether spaces between table cells should be collapsed. Defaults
to FALSE.
-
expand_newlines
+
expand_newlines
+
(flag) Defaults to FALSE, relying on html output to solve newline characters (\n).
Doing this keeps the structure of the cells but may depend on the output device.
-
+
+
-
Value
+
Value
+
A shiny.tag object representing x in HTML.
-
Examples
+
Examples
+
tbl<-rtable( header =LETTERS[1:3], format ="xx",
@@ -272,17 +341,19 @@
(string) label to be associated with the table generated by the split. Not to be confused
with labels assigned to each child (which are based on the data and type of split during tabulation).
-
afun
+
afun
+
(function) analysis function. Must accept x or df as its first parameter. Can optionally take
other parameters which will be populated by the tabulation framework. See Details in analyze().
-
defrowlab
+
defrowlab
+
(character) default row labels, if not specified by the return value of afun.
-
cfun
+
cfun
+
(list, function, or NULL) tabulation function(s) for creating content rows. Must accept x
or df as first parameter. Must accept labelstr as the second argument. Can optionally accept all optional
arguments accepted by analysis functions. See analyze().
-
cformat
+
cformat
+
(string, function, or list) format for content rows.
-
split_format
+
split_format
+
(string, function, or list) default format associated with the split being created.
-
split_na_str
+
split_na_str
+
(character) NA string vector for use with split_format.
-
inclNAs
+
inclNAs
+
(logical) whether NA observations in the var variable(s) should be included when performing
the analysis. Defaults to FALSE.
-
split_name
+
split_name
+
(string) name associated with the split (for pathing, etc.).
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
cvar
+
cvar
+
(string) the variable, if any, that the content function should accept. Defaults to NA.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
.payload
+
.payload
+
(list) used internally, not intended to be set by end users.
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
child_names
+
child_names
+
(character) names to be given to the subsplits contained by a compound split (typically
an AnalyzeMultiVars split object).
-
+
+
-
Value
+
Value
+
An AnalyzeVarSplit object.
An AnalyzeMultiVars split object.
-
Author
+
Author
+
Gabriel Becker
+
+
-
+
+
-
+
+
diff --git a/main/reference/basic_table.html b/main/reference/basic_table.html
index d7da01208..93daf0a35 100644
--- a/main/reference/basic_table.html
+++ b/main/reference/basic_table.html
@@ -1,5 +1,28 @@
-
-Layout with 1 column and zero rows — basic_table • rtables
+
+
+
+
+
+
+Layout with 1 column and zero rows — basic_table • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -15,11 +38,13 @@
(character) a vector of strings to use as subtitles (formatters::subtitles()), where every
element is printed on a separate line. Ignored for subtables.
-
main_footer
+
main_footer
+
(character) a vector of strings to use as main global (non-referential) footer materials
(formatters::main_footer()), where every element is printed on a separate line.
-
prov_footer
+
prov_footer
+
(character) a vector of strings to use as provenance-related global footer materials
(formatters::prov_footer()), where every element is printed on a separate line.
-
show_colcounts
+
show_colcounts
+
(logical(1)) Indicates whether the lowest level of
applied to data. NA, the default, indicates that the show_colcounts
argument(s) passed to the relevant calls to split_cols_by*
@@ -117,35 +178,42 @@
(string) format for use when displaying the column counts. Must be 1d, or 2d
where one component is a percent. This will also apply to any displayed higher
level column counts where an explicit format was not specified. Defaults to "(N=xx)". See Details below.
-
header_section_div
+
header_section_div
+
(string) string which will be used to divide the header from the table. See
header_section_div() for the associated getter and setter. Please consider changing last element of
section_div() when concatenating tables that require a divider between them.
-
top_level_section_div
+
top_level_section_div
+
(character(1)) if assigned a single character, the first (top level) split
or division of the table will be highlighted by a line made of that character. See section_div for more
information.
-
inset
+
inset
+
(numeric(1)) number of spaces to inset the table header, table body, referential footnotes, and
main_footer, as compared to alignment of title, subtitle, and provenance footer. Defaults to 0 (no inset).
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
-
Details
+
Details
+
colcount_format is ignored if show_colcounts is FALSE (the default). When show_colcounts is TRUE,
and colcount_format is 2-dimensional with a percent component, the value component for the percent is always
populated with 1 (i.e. 100%). 1d formats are used to render the counts exactly as they normally would be,
@@ -154,18 +222,22 @@
Because percent components in colcount_format are always populated with the value 1, we can get arguably
+
+
Because percent components in colcount_format are always populated with the value 1, we can get arguably
strange results, such as that individual arm columns and a combined "all patients" column all list "100%" as
their percentage, even though the individual arm columns represent strict subsets of the "all patients" column.
# S4 method for class 'VTableTree,ANY,ANY,list'x[i, j, ...]<-value
@@ -80,23 +135,32 @@
Usage
-
Arguments
+
Arguments
+
-
x
+
+
x
+
(TableTree) a TableTree object.
-
i
+
i
+
(numeric(1)) index.
-
j
+
j
+
(numeric(1)) index.
-
...
-
additional arguments. Includes:
keep_topleft
+
...
+
+
+
additional arguments. Includes:
+
+
keep_topleft
(flag) ([ only) whether the top-left material for the table should be retained after
subsetting. Defaults to TRUE if all rows are included (i.e. subsetting was by column), and drops it
otherwise.
(flag) whether the value in the cell should be returned if one cell is selected by the
combination of i and j. It is not possible to return a vector of values. To do so please consider using
cell_values(). Defaults to FALSE.
-
+
+
-
Value
+
Value
+
A TableTree (or ElementaryTable) object, unless a single cell was selected with drop = TRUE, in which
case the (possibly multi-valued) fully stripped raw value of the selected cell.
-
Details
+
Details
+
By default, subsetting drops the information about title, subtitle, main footer, provenance footer, and topleft.
If only a column is selected and all rows are kept, the topleft information remains as default. Any referential
footnote is kept whenever the subset table contains the referenced element.
-
Note
+
Note
+
Subsetting always preserve the original order, even if provided indexes do not preserve it. If sorting is needed,
please consider using sort_at_path(). Also note that character indices are treated as paths, not vectors of
names in both [ and [<-.
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
df
+
df
+
(data.frame or tibble) dataset.
-
alt_counts_df
+
alt_counts_df
+
(data.frame or tibble) alternative full dataset the rtables framework will use
only when calculating column counts.
-
col_counts
+
col_counts
+
(numeric or NULL) if non-NULL, column counts
for leaf-columns only which override those calculated automatically during tabulation. Must specify
"counts" for all leaf-columns if non-NULL. NA elements will be replaced with the automatically
calculated counts. Turns on display of leaf-column counts when non-NULL.
-
col_total
+
col_total
+
(integer(1)) the total observations across all columns. Defaults to nrow(df).
-
topleft
+
topleft
+
(character) override values for the "top left" material to be displayed during printing.
-
hsep
+
hsep
+
(string) set of characters to be repeated as the separator between the header and body of
the table when rendered as text. Defaults to a connected horizontal line (unicode 2014) in locals that use a UTF
charset, and to - elsewhere (with a once per session warning). See formatters::set_default_hsep() for further
information.
-
...
+
...
+
ignored.
-
+
+
-
Value
+
Value
+
A TableTree or ElementaryTable object representing the table created by performing the tabulations
declared in lyt to the data df.
-
Details
+
Details
+
When alt_counts_df is specified, column counts are calculated by applying the exact column subsetting
expressions determined when applying column splitting to the main data (df) to alt_counts_df and
counting the observations in each resulting subset.
When overriding the column counts or totals care must be taken that, e.g., length() or nrow() are not called
within tabulation functions, because those will NOT give the overridden counts. Writing/using tabulation
functions which accept .N_col and .N_total or do not rely on column counts at all (even implicitly) is the
only way to ensure overridden counts are fully respected.
one or more further objects of the same class as x.
-
sync_count_vis
+
sync_count_vis
+
(logical(1)) should column count
visibility be synced across the new and existing columns.
Currently defaults to TRUE for backwards compatibility but
this may change in future releases.
(TableTree or related class) a TableTree object representing a populated table.
-
rowpath
+
rowpath
+
(character) path in row-split space to the desired row(s). Can include "@content".
-
colpath
+
colpath
+
(character) path in column-split space to the desired column(s). Can include "*".
-
omit_labrows
+
omit_labrows
+
(flag) whether label rows underneath rowpath should be omitted (TRUE, the default),
or return empty lists of cell "values" (FALSE).
-
+
+
-
Value
+
Value
+
-
cell_values returns a list (regardless of the type of value the cells hold). If rowpath defines a path to
+
+
cell_values returns a list (regardless of the type of value the cells hold). If rowpath defines a path to
a single row, cell_values returns the list of cell values for that row, otherwise a list of such lists, one for
each row captured underneath rowpath. This occurs after subsetting to colpath has occurred.
value_at returns the "unwrapped" value of a single cell, or an error, if the combination of rowpath and
colpath do not define the location of a single cell in tt.
-
+
+
-
Note
+
Note
+
cell_values will return a single cell's value wrapped in a list. Use value_at to receive the "bare" cell
value.
clayout(obj)# S4 method for class 'VTableNodeInfo'
@@ -211,68 +265,83 @@
Usage
-
Arguments
+
Arguments
+
-
obj
+
+
obj
+
(ANY) the object for the accessor to access or modify.
-
object
+
object
+
(ANY) the object to modify in place.
-
value
+
value
+
(ANY) the new value.
-
df
+
df
+
(data.frame or NULL) data to use if the column information is being
generated from a pre-data layout object.
-
rtpos
+
rtpos
+
(TreePos) root position.
-
alt_counts_df
+
alt_counts_df
+
(data.frame or tibble) alternative full dataset the rtables framework will use
only when calculating column counts.
-
ccount_format
+
ccount_format
+
(FormatSpec) The format to be used by default for column
counts throughout this column tree (i.e. if not overridden by a more specific format
specification).
-
path
+
path
+
(character or NULL) col_counts accessor and setter only.
Path (in column structure).
-
+
+
-
Value
+
Value
+
A LayoutColTree object.
Returns various information about columns, depending on the accessor used.
colcount_visible(obj, path)# S4 method for class 'VTableTree'
@@ -96,24 +150,31 @@
Usage
-
Arguments
+
Arguments
+
-
obj
+
+
obj
+
(ANY) the object for the accessor to access or modify.
-
path
+
path
+
(character) a vector path for a position within the structure of a TableTree. Each element
represents a subsequent choice amongst the children of the previous choice.
-
value
+
value
+
(ANY) the new value.
-
+
+
-
Value
+
Value
+
for colcount_visible a logical scalar
indicating whether the specified position in
the column hierarchy is set to display its column count;
@@ -121,7 +182,8 @@
Value
-
Note
+
Note
+
Users generally should not call colcount_visible
directly, as setting sibling facets to have differing
column count visibility will result in an error when
@@ -129,17 +191,19 @@
(flag) whether to compare cell formats. Other attributes are
silently ignored.
-
structure
+
structure
+
(flag) whether structures (in the form of column and row
paths to cells) should be compared. Currently defaults to FALSE, but this is
subject to change in future versions.
-
+
+
-
Value
+
Value
+
A matrix of class rtables_diff representing the differences
between object and expected as described above.
-
Note
+
Note
+
In its current form, compare_rtables does not take structure into
account, only row and cell position.
compat_args(.lst, row.name, format, indent, label, inset)
-
Arguments
+
Arguments
+
-
.lst
+
+
.lst
+
(list) an already-collected list of arguments to be used instead of the elements of ....
Arguments passed via ... will be ignored if this is specified.
-
row.name
+
row.name
+
(string or NULL) row name. If NULL, an empty string is used as row.name of the
rrow().
-
format
+
format
+
(string, function, or list) the format label (string) or formatter function to apply to the
cell values passed via .... See formatters::list_valid_format_labels() for currently supported format labels.
-
indent
+
indent
+
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
inset
+
inset
+
(integer(1)) the table inset for the row or table being constructed. See
formatters::table_inset() for details.
(integer(1)) nesting level (roughly, indentation level in practical terms).
-
iscontent
+
iscontent
+
(flag) whether the TableTree/ElementaryTable is being constructed as the content
table for another TableTree.
-
cinfo
+
cinfo
+
(InstantiatedColumnInfo or NULL) column structure for the object being created.
-
labelrow
+
labelrow
+
(LabelRow) the LabelRow object to assign to the table. Constructed from label by default
if not specified.
-
vals
+
vals
+
(list) cell values for the row.
-
cspan
+
cspan
+
(integer) column span. 1 indicates no spanning.
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
cindent_mod
+
cindent_mod
+
(numeric(1)) the indent modifier for the content tables generated by this split.
-
cvar
+
cvar
+
(string) the variable, if any, that the content function should accept. Defaults to NA.
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
cextra_args
+
cextra_args
+
(list) extra arguments to be passed to the content function when tabulating row group
summaries.
-
child_names
+
child_names
+
(character) names to be given to the subsplits contained by a compound split (typically
an AnalyzeMultiVars split object).
(character) a vector of strings to use as subtitles (formatters::subtitles()), where every
element is printed on a separate line. Ignored for subtables.
-
main_footer
+
main_footer
+
(character) a vector of strings to use as main global (non-referential) footer materials
(formatters::main_footer()), where every element is printed on a separate line.
-
prov_footer
+
prov_footer
+
(character) a vector of strings to use as provenance-related global footer materials
(formatters::prov_footer()), where every element is printed on a separate line.
-
footnotes
+
footnotes
+
(list or NULL) referential footnotes to be applied at current level. In post-processing,
this can be achieved with fnotes_at_path<-.
-
page_title
+
page_title
+
(character) page-specific title(s).
-
page_prefix
+
page_prefix
+
(string) prefix to be appended with the split value when forcing pagination between
the children of a split/table.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
trailing_section_div
+
trailing_section_div
+
(string) string which will be used as a section divider after the printing
of the last row contained in this (sub)table, unless that row is also the last table row to be printed overall,
or NA_character_ for none (the default). When generated via layouting, this would correspond to the
section_div of the split under which this table represents a single facet.
-
split_na_str
+
split_na_str
+
(character) NA string vector for use with split_format.
-
cna_str
+
cna_str
+
(character) NA string for use with cformat for content table.
-
inset
+
inset
+
(numeric(1)) number of spaces to inset the table header, table body, referential footnotes, and
main_footer, as compared to alignment of title, subtitle, and provenance footer. Defaults to 0 (no inset).
-
table_inset
+
table_inset
+
(numeric(1)) number of spaces to inset the table header, table body, referential footnotes,
and main footer, as compared to alignment of title, subtitles, and provenance footer. Defaults to 0 (no inset).
-
header_section_div
+
header_section_div
+
(string) string which will be used to divide the header from the table. See
header_section_div() for the associated getter and setter. Please consider changing last element of
section_div() when concatenating tables that require a divider between them.
User-defined custom split functions can perform any type of computation on the incoming data provided that they
meet the requirements for generating "splits" of the incoming data based on the split object.
One way to generate custom splitting functions is to wrap existing split functions and modify either the incoming
+
+
One way to generate custom splitting functions is to wrap existing split functions and modify either the incoming
data before they are called or their outputs.
-
See also
+
See also
+
make_split_fun() for the API for creating custom split functions, and split_funcs for a variety of
pre-defined split functions.
-
Examples
+
Examples
+
# Example of a picky split function. The number of values in the column variable# var decrees if we are going to print also the column with all observation# or not.
@@ -176,17 +237,19 @@
Examples
+
+
-
+
+
-
+
+
diff --git a/main/reference/cutsplits.html b/main/reference/cutsplits.html
index a0059cb65..879bc5f41 100644
--- a/main/reference/cutsplits.html
+++ b/main/reference/cutsplits.html
@@ -1,7 +1,30 @@
-
-Splits for cutting by values of a numeric variable — VarStaticCutSplit-class • rtables
+
+
+
+
+
+
+Splits for cutting by values of a numeric variable — VarStaticCutSplit-class • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -17,11 +40,13 @@
(string) label to be associated with the table generated by the split. Not to be confused
with labels assigned to each child (which are based on the data and type of split during tabulation).
-
cuts
+
cuts
+
(numeric) cuts to use.
-
cutlabels
+
cutlabels
+
(character or NULL) labels for the cuts.
-
cfun
+
cfun
+
(list, function, or NULL) tabulation function(s) for creating content rows. Must accept x
or df as first parameter. Must accept labelstr as the second argument. Can optionally accept all optional
arguments accepted by analysis functions. See analyze().
-
cformat
+
cformat
+
(string, function, or list) format for content rows.
-
cna_str
+
cna_str
+
(character) NA string for use with cformat for content table.
-
split_format
+
split_format
+
(string, function, or list) default format associated with the split being created.
-
split_na_str
+
split_na_str
+
(character) NA string vector for use with split_format.
-
split_name
+
split_name
+
(string) name associated with the split (for pathing, etc.).
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
cindent_mod
+
cindent_mod
+
(numeric(1)) the indent modifier for the content tables generated by this split.
-
cvar
+
cvar
+
(string) the variable, if any, that the content function should accept. Defaults to NA.
-
cextra_args
+
cextra_args
+
(list) extra arguments to be passed to the content function when tabulating row group
summaries.
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
cumulative
+
cumulative
+
(flag) whether the cuts should be treated as cumulative. Defaults to FALSE.
-
page_prefix
+
page_prefix
+
(string) prefix to be appended with the split value when forcing pagination between
the children of a split/table.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
show_colcounts
+
show_colcounts
+
(logical(1)) should column counts be displayed at the level
facets created by this split. Defaults to FALSE.
-
colcount_format
+
colcount_format
+
(character(1)) if show_colcounts is TRUE, the
format which should be used to display column counts for facets generated by
this split. Defaults to "(N=xx)".
-
cutfun
+
cutfun
+
(function) function which accepts the full vector of var values and returns cut points to be
used (via cut) when splitting data during tabulation.
-
cutlabelfun
+
cutlabelfun
+
(function) function which returns either labels for the cuts or NULL when passed the
return value of cutfun.
-
+
+
-
Value
+
Value
+
A VarStaticCutSplit, CumulativeCutSplit object for make_static_cut_split, or a VarDynCutSplit
object for VarDynCutSplit().
+
+
-
+
+
-
+
+
diff --git a/main/reference/data.frame_export.html b/main/reference/data.frame_export.html
index a99502f28..010ff472c 100644
--- a/main/reference/data.frame_export.html
+++ b/main/reference/data.frame_export.html
@@ -1,5 +1,28 @@
-
-Generate a result data frame — data.frame_export • rtables
+
+
+
+
+
+
+Generate a result data frame — data.frame_export • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -15,11 +38,13 @@
(TableTree or related class) a TableTree object representing a populated table.
-
spec
+
spec
+
(function) function that generates the result data frame from a table (TableTree).
It defaults to NULL, for standard processing.
-
data_format
+
data_format
+
(string) the format of the data in the result data frame. It can be one value
between "full_precision" (default), "strings", and "numeric". The last two values show the numeric
data with the visible precision.
-
make_ard
+
make_ard
+
(flag) when TRUE, the result data frame will have only one statistic per row.
-
expand_colnames
+
expand_colnames
+
(flag) when TRUE, the result data frame will have expanded column
names above the usual output. This is useful when the result data frame is used for further processing.
-
keep_label_rows
+
keep_label_rows
+
(flag) when TRUE, the result data frame will have all labels
as they appear in the final table.
-
simplify
+
simplify
+
(flag) when TRUE, the result data frame will have only visible labels and
result columns. Consider showing also label rows with keep_label_rows = TRUE. This output can be
used again to create a TableTree object with df_to_tt().
-
...
+
...
+
additional arguments passed to spec-specific result data frame function (spec).
-
path_fun
+
path_fun
+
(function) function to transform paths into single-string row/column names.
-
value_fun
+
value_fun
+
(function) function to transform cell values into cells of a data.frame. Defaults to
collapse_values, which creates strings where multi-valued cells are collapsed together, separated by |.
-
+
+
-
Value
-
-
as_result_df returns a result data.frame.
-
path_enriched_df() returns a data.frame of tt's cell values (processed by value_fun, with columns named by
+
Value
+
+
+
+
as_result_df returns a result data.frame.
+
+
+
path_enriched_df() returns a data.frame of tt's cell values (processed by value_fun, with columns named by
the full column paths (processed by path_fun and an additional row_path column with the row paths (processed
by path_fun).
-
+
+
-
Functions
+
Functions
+
-
path_enriched_df(): Transform a TableTree object to a path-enriched data.frame.
-
+
+
path_enriched_df(): Transform a TableTree object to a path-enriched data.frame.
If row names are not defined in df (or they are simple numbers), then the row names are taken from the column
label_name, if it exists. If label_name exists, then it is also removed from the original data. This behavior
is compatible with as_result_df(), when as_is = TRUE and the row names are not unique.
facet_colcount(obj, path)# S4 method for class 'LayoutColTree'
@@ -102,33 +156,41 @@
Usage
-
Arguments
+
Arguments
+
-
obj
+
+
obj
+
(ANY) the object for the accessor to access or modify.
-
path
+
path
+
character. This path must end on a
split value, e.g., the level of a categorical variable
that was split on in column space, but it need not
be the path to an individual column.
-
value
+
value
+
(ANY) the new value.
-
+
+
-
Value
+
Value
+
for facet_colcount the current count associated
with that facet in column space, for facet_colcount<-,
obj modified with the new column count for the specified
facet.
-
Note
+
Note
+
Updating a lower-level (more specific)
column count manually will not update the
counts for its parent facets. This cannot be made
@@ -140,12 +202,14 @@
# S4 method for class 'VNodeInfo'obj_name(obj)
@@ -254,90 +308,114 @@
Usage
-
Arguments
+
Arguments
+
-
obj
+
+
obj
+
(ANY) the object for the accessor to access or modify.
-
value
+
value
+
(ANY) the new value.
-
x
+
x
+
(ANY) an object.
-
colwidths
+
colwidths
+
(numeric) a vector of column widths for use in vertical pagination.
-
max_width
+
max_width
+
(numeric(1)) width that strings should be wrapped to when
determining how many lines they require.
-
fontspec
+
fontspec
+
(font_spec) a font_spec object specifying the font information to use for
calculating string widths and heights, as returned by font_spec().
-
col_gap
+
col_gap
+
(numeric(1)) width of gap between columns in number of spaces.
Only used by methods which must calculate span widths after wrapping.
-
tt
+
tt
+
(TableTree or related class) a TableTree object representing a populated table.
-
visible_only
+
visible_only
+
(flag) should only visible aspects of the table structure be reflected
in this summary. Defaults to TRUE. May not be supported by all methods.
-
rownum
+
rownum
+
(numeric(1)) internal detail, do not set manually.
-
indent
+
indent
+
(integer(1)) internal detail, do not set manually.
-
path
+
path
+
(character) a vector path for a position within the structure of a TableTree. Each element
represents a subsequent choice amongst the children of the previous choice.
-
incontent
+
incontent
+
(flag) internal detail, do not set manually.
-
repr_ext
+
repr_ext
+
(integer(1)) internal detail, do not set manually.
-
repr_inds
+
repr_inds
+
(integer) internal detail, do not set manually.
-
sibpos
+
sibpos
+
(integer(1)) internal detail, do not set manually.
-
nsibs
+
nsibs
+
(integer(1)) internal detail, do not set manually.
-
+
+
-
Value
+
Value
+
-
Accessor functions return the current value of the component being accessed of obj
+
+
Accessor functions return the current value of the component being accessed of obj
Setter functions return a modified copy of obj with the new value.
-
+
+
-
Details
+
Details
+
When visible_only is TRUE (the default), methods should return a data.frame with exactly one
row per visible row in the table-like object. This is useful when reasoning about how a table will
print, but does not reflect the full pathing space of the structure (though the paths which are given
@@ -349,31 +427,35 @@
The technically present root tree node is excluded from the summary returned by
both make_row_df and make_col_df (see relevant functions inrtables), as it is the
row/column structure of tt and thus not useful for pathing or pagination.
-
Examples
+
Examples
+
# Expected error with matrix_form. For real case examples consult {rtables} documentationmf<-basic_matrix_form(iris)# make_row_df(mf) # Use table obj instead
(data.frame or tibble) alternative full dataset the rtables framework will use
only when calculating column counts.
-
spl
+
spl
+
(Split) a Split object defining a partitioning or analysis/tabulation of the data.
-
pos
+
pos
+
(numeric) which top-level set of nested splits should the new layout feature be added to. Defaults
to the current split.
-
tt
+
tt
+
(TableTree or related class) a TableTree object representing a populated table.
-
tr
+
tr
+
(TableRow or related class) a TableRow object representing a single row within a populated table.
-
verbose
+
verbose
+
(flag) whether additional information should be displayed to the user. Defaults to FALSE.
-
colwidths
+
colwidths
+
(numeric) a vector of column widths for use in vertical pagination.
-
obj
+
obj
+
(ANY) the object for the accessor to access or modify.
-
x
+
x
+
(ANY) an object.
-
value
+
value
+
(ANY) the new value.
-
object
+
object
+
(ANY) the object to modify in place.
-
path
+
path
+
(character) a vector path for a position within the structure of a TableTree. Each element
represents a subsequent choice amongst the children of the previous choice.
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
cvar
+
cvar
+
(string) the variable, if any, that the content function should accept. Defaults to NA.
-
topleft
+
topleft
+
(character) override values for the "top left" material to be displayed during printing.
-
page_prefix
+
page_prefix
+
(string) prefix to be appended with the split value when forcing pagination between
the children of a split/table.
-
hsep
+
hsep
+
(string) set of characters to be repeated as the separator between the header and body of
the table when rendered as text. Defaults to a connected horizontal line (unicode 2014) in locals that use a UTF
charset, and to - elsewhere (with a once per session warning). See formatters::set_default_hsep() for further
information.
-
indent_size
+
indent_size
+
(numeric(1)) number of spaces to use per indent level. Defaults to 2.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
inset
+
inset
+
(numeric(1)) number of spaces to inset the table header, table body, referential footnotes, and
main_footer, as compared to alignment of title, subtitle, and provenance footer. Defaults to 0 (no inset).
-
table_inset
+
table_inset
+
(numeric(1)) number of spaces to inset the table header, table body, referential footnotes,
and main footer, as compared to alignment of title, subtitles, and provenance footer. Defaults to 0 (no inset).
-
...
+
...
+
additional parameters passed to methods or tabulation functions.
head(x, ...)# S4 method for class 'VTableTree'
@@ -100,18 +154,23 @@
Usage
-
Arguments
+
Arguments
+
-
x
+
+
x
+
an object
-
...
+
...
+
arguments to be passed to or from other methods.
-
n
+
n
+
an integer vector of length up to dim(x) (or 1,
for non-dimensioned objects). A logical is silently coerced to
integer. Values specify the indices to be
@@ -124,39 +183,46 @@
insert_row_at_path(tt, path, value, after =FALSE)# S4 method for class 'VTableTree,DataRow'
@@ -85,34 +139,43 @@
Usage
-
Arguments
+
Arguments
+
-
tt
+
+
tt
+
(TableTree or related class) a TableTree object representing a populated table.
-
path
+
path
+
(character) a vector path for a position within the structure of a TableTree. Each element
represents a subsequent choice amongst the children of the previous choice.
-
value
+
value
+
(ANY) the new value.
-
after
+
after
+
(flag) whether value should be added as a row directly before (FALSE, the default) or after
(TRUE) the row specified by path.
Label rows (i.e. a row with no data values, only a row.name) can only be inserted at positions which do
not already contain a label row when there is a non-trivial nested row structure in tbl.
# S4 method for class 'SplitVector'c(x, ...)
@@ -1153,195 +1207,240 @@
Usage
-
Arguments
+
Arguments
+
-
x
+
+
x
+
(ANY) the object.
-
...
+
...
+
splits or SplitVector objects.
-
lyt
+
lyt
+
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
spl
+
spl
+
(Split) the split.
-
pos
+
pos
+
(numeric(1)) intended for internal use.
-
cmpnd_fun
+
cmpnd_fun
+
(function) intended for internal use.
-
constructor
+
constructor
+
(function) constructor function.
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
cfun
+
cfun
+
(list, function, or NULL) tabulation function(s) for creating content rows. Must accept x
or df as first parameter. Must accept labelstr as the second argument. Can optionally accept all optional
arguments accepted by analysis functions. See analyze().
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
cformat
+
cformat
+
(string, function, or list) format for content rows.
-
cna_str
+
cna_str
+
(character) NA string for use with cformat for content table.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
cvar
+
cvar
+
(string) the variable, if any, that the content function should accept. Defaults to NA.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
df
+
df
+
(data.frame or tibble) dataset.
-
obj
+
obj
+
(ANY) the object.
-
depth
+
depth
+
(numeric(1)) depth in tree.
-
indent
+
indent
+
(numeric(1)) indent.
-
print_indent
+
print_indent
+
(numeric(1)) indent for printing.
-
object
+
object
+
(VTableTree) a table object.
-
max.level
+
max.level
+
(numeric(1)) passed to utils::str. Defaults to 3 for the VTableTree method, unlike
the underlying default of NA. NA is not appropriate for VTableTree objects.
-
value
+
value
+
(ANY) the new value.
-
nested
+
nested
+
(logical) whether this layout instruction should be applied within the existing layout structure
if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split
underneath analyses, which is not allowed.
-
for_analyze
+
for_analyze
+
(flag) whether split is an analyze split.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
override
+
override
+
(flag) whether to override attribute.
-
tt
+
tt
+
(TableTree or related class) a TableTree object representing a populated table.
-
incl.cont
+
incl.cont
+
(flag) whether to include rows from content tables within the tree. Defaults to TRUE.
-
add.labrows
+
add.labrows
+
(flag) whether to include label rows. Defaults to FALSE.
-
path
+
path
+
(character) a vector path for a position within the structure of a TableTree. Each element
represents a subsequent choice amongst the children of the previous choice.
(character or NULL) path within row structure. NULL indicates the footnote should
go on the column rather than cell.
-
colpath
+
colpath
+
(character or NULL) path within column structure. NULL indicates footnote should go
on the row rather than cell.
-
reset_idx
+
reset_idx
+
(flag) whether the numbering for referential footnotes should be immediately
recalculated. Defaults to TRUE.
-
y
+
y
+
(ANY) second element to be row-bound via rbind2.
-
i
+
i
+
(numeric(1)) index.
-
j
+
j
+
(numeric(1)) index.
-
drop
+
drop
+
(flag) whether the value in the cell should be returned if one cell is selected by the
combination of i and j. It is not possible to return a vector of values. To do so please consider using
cell_values(). Defaults to FALSE.
-
+
+
-
Value
+
Value
+
Various, but should be considered implementation details.
(TableTree or related class) a TableTree object representing a populated table.
-
path
+
path
+
(character) a vector path for a position within the structure of a TableTree. Each element
represents a subsequent choice amongst the children of the previous choice.
-
value
+
value
+
(ANY) the new value.
-
+
+
-
Details
+
Details
+
If path resolves to a single row, the label for that row is retrieved or set. If, instead, path resolves to a
subtable, the text for the row-label associated with that path is retrieved or set. In the subtable case, if the
label text is set to a non-NA value, the labelrow will be set to visible, even if it was not before. Similarly,
@@ -103,14 +164,16 @@
When changing the row labels for content rows, it is important to path all the way to the row. Paths
ending in "@content" will not exhibit the behavior you want, and are thus an error. See row_paths() for help
determining the full paths to content rows.
+
+
-
+
+
-
+
+
diff --git a/main/reference/list_wrap.html b/main/reference/list_wrap.html
index 3054d0d4f..49276a3f7 100644
--- a/main/reference/list_wrap.html
+++ b/main/reference/list_wrap.html
@@ -1,5 +1,28 @@
-
-Returns a function that coerces the return values of a function to a list — list_wrap_x • rtables
+
+
+
+
+
+
+Returns a function that coerces the return values of a function to a list — list_wrap_x • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -15,11 +38,13 @@
A function that returns a list of CellValue objects.
-
Details
+
Details
+
list_wrap_x generates a wrapper which takes x as its first argument, while list_wrap_df generates an
otherwise identical wrapper function whose first argument is named df.
We provide both because when using the functions as tabulation in analyze(), functions which take df as
@@ -98,12 +158,14 @@
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
var
+
var
+
(string) variable name.
-
vars
+
vars
+
(character) vector of variable names.
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
labels_var
+
labels_var
+
(string) name of variable containing labels to be displayed for the values of var.
-
varlabels
+
varlabels
+
(character) vector of labels for vars.
-
varnames
+
varnames
+
(character) vector of names for vars which will appear in pathing. When vars are all
unique this will be the variable names. If not, these will be variable names with suffixes as necessary to enforce
uniqueness.
-
split_format
+
split_format
+
(string, function, or list) default format associated with the split being created.
-
split_na_str
+
split_na_str
+
(character) NA string vector for use with split_format.
-
nested
+
nested
+
(logical) whether this layout instruction should be applied within the existing layout structure
if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split
underneath analyses, which is not allowed.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
cfun
+
cfun
+
(list, function, or NULL) tabulation function(s) for creating content rows. Must accept x
or df as first parameter. Must accept labelstr as the second argument. Can optionally accept all optional
arguments accepted by analysis functions. See analyze().
-
cformat
+
cformat
+
(string, function, or list) format for content rows.
-
cna_str
+
cna_str
+
(character) NA string for use with cformat for content table.
-
split_fun
+
split_fun
+
(function or NULL) custom splitting function. See custom_split_funs.
-
split_name
+
split_name
+
(string) name associated with the split (for pathing, etc.).
-
split_label
+
split_label
+
(string) label to be associated with the table generated by the split. Not to be confused
with labels assigned to each child (which are based on the data and type of split during tabulation).
-
afun
+
afun
+
(function) analysis function. Must accept x or df as its first parameter. Can optionally take
other parameters which will be populated by the tabulation framework. See Details in analyze().
-
inclNAs
+
inclNAs
+
(logical) whether NA observations in the var variable(s) should be included when performing
the analysis. Defaults to FALSE.
-
valorder
+
valorder
+
(character) the order that the split children should appear in resulting table.
-
ref_group
+
ref_group
+
(character) value of var to be taken as the ref_group/control to be compared against.
-
compfun
+
compfun
+
(function or string) the comparison function which accepts the analysis function outputs for
two different partitions and returns a single value. Defaults to subtraction. If a string, taken as the name of a
function.
-
label_fstr
+
label_fstr
+
(string) a sprintf style format string. For non-comparison splits, it can contain up to
one "\%s" which takes the current split value and generates the row/column label. For comparison-based splits
it can contain up to two "\%s".
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
name
+
name
+
(string) name of the split/table/row being created. Defaults to the value of the
corresponding label, but is not required to be.
-
cuts
+
cuts
+
(numeric) cuts to use.
-
cutlabels
+
cutlabels
+
(character or NULL) labels for the cuts.
-
cutfun
+
cutfun
+
(function) function which accepts the full vector of var values and returns cut points to be
used (via cut) when splitting data during tabulation.
-
cutlabelfun
+
cutlabelfun
+
(function) function which returns either labels for the cuts or NULL when passed the
return value of cutfun.
-
cumulative
+
cumulative
+
(flag) whether the cuts should be treated as cumulative. Defaults to FALSE.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
show_labels
+
show_labels
+
(string) whether the variable labels corresponding to the variable(s) in vars
should be visible in the resulting table.
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
var_labels
+
var_labels
+
(character) vector of labels for one or more variables.
-
cvar
+
cvar
+
(string) the variable, if any, that the content function should accept. Defaults to NA.
-
table_names
+
table_names
+
(character) names for the tables representing each atomic analysis. Defaults to var.
-
topleft
+
topleft
+
(character) override values for the "top left" material to be displayed during printing.
-
align
+
align
+
(string or NULL) alignment the value should be rendered with. Defaults to "center" if
NULL is used. See formatters::list_valid_aligns() for all currently supported alignments.
-
page_by
+
page_by
+
(flag) whether pagination should be forced between different children resulting from this
split. An error will occur if the selected split does not contain at least one value that is not NA.
-
page_prefix
+
page_prefix
+
(string) prefix to be appended with the split value when forcing pagination between
the children of a split/table.
-
format_na_str
+
format_na_str
+
(string) string which should be displayed when formatted if this cell's value(s)
are all NA.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
show_colcounts
+
show_colcounts
+
(logical(1)) should column counts be displayed at the level
facets created by this split. Defaults to FALSE.
-
colcount_format
+
colcount_format
+
(character(1)) if show_colcounts is TRUE, the
format which should be used to display column counts for facets generated by
this split. Defaults to "(N=xx)".
(function) the function to be wrapped in a new customized analysis function.
fun should return a named list.
-
.stats
+
.stats
+
(character) names of elements to keep from fun's full output.
-
.formats
+
.formats
+
(ANY) vector or list of formats to override any defaults applied by fun.
-
.labels
+
.labels
+
(character) vector of labels to override defaults returned by fun.
-
.indent_mods
+
.indent_mods
+
(integer) named vector of indent modifiers for the generated rows.
-
.ungroup_stats
+
.ungroup_stats
+
(character) vector of names, which must match elements of .stats.
-
.format_na_strs
+
.format_na_strs
+
(ANY) vector/list of NA strings to override any defaults applied by fun.
-
...
+
...
+
additional arguments to fun which effectively become new defaults. These can still be
overridden by extra_args within a split.
-
.null_ref_cells
+
.null_ref_cells
+
(flag) whether cells for the reference column should be NULL-ed by the
returned analysis function. Defaults to TRUE if fun accepts .in_ref_col as a formal argument. Note
this argument occurs after ... so it must be fully specified by name when set.
-
+
+
-
Value
+
Value
+
A function suitable for use in analyze() with element selection, reformatting, and relabeling
performed automatically.
-
Note
+
Note
+
Setting .ungroup_stats to non-NULL changes the structure of the value(s) returned by fun, rather than
just labeling (.labels), formatting (.formats), and selecting amongst (.stats) them. This means that
subsequent make_afun calls to customize the output further both can and must operate on the new structure,
not the original structure returned by fun. See the final pair of examples below.
make_split_fun(pre =list(), core_split =NULL, post =list())
-
Arguments
+
Arguments
+
-
pre
+
+
pre
+
(list) zero or more functions which operate on the incoming data and return a new data frame that
should split via core_split. They will be called on the data in the order they appear in the list.
-
core_split
+
core_split
+
(function or NULL) if non-NULL, a function which accepts the same arguments that
do_base_split does, and returns the same type of named list. Custom functions which override this behavior
cannot be used in column splits.
-
post
+
post
+
(list) zero or more functions which should be called on the list output by splitting.
-
+
+
-
Value
+
Value
+
A custom function that can be used as a split function.
-
Details
-
Custom split functions can be thought of as (up to) 3 different types of manipulations of the splitting process:
Pre-processing of the incoming data to be split.
+
Details
+
+
Custom split functions can be thought of as (up to) 3 different types of manipulations of the splitting process:
+
+
Pre-processing of the incoming data to be split.
(Row-splitting only) Customization of the core mapping of incoming data to facets.
Post-processing operations on the set of facets (groups) generated by the split.
-
This function provides an interface to create custom split functions by implementing and specifying sets of
+
+
This function provides an interface to create custom split functions by implementing and specifying sets of
operations in each of those classes of customization independently.
Pre-processing functions (1), must accept: df, spl, vals, and labels, and can optionally accept
.spl_context. They then manipulate df (the incoming data for the split) and return a modified data frame.
@@ -128,17 +193,21 @@
(character or list(SplitValue)) the values associated with each facet.
-
datasplit
+
datasplit
+
(list(data.frame)) the facet data for each facet generated in the split.
-
labels
+
labels
+
(character) the labels associated with each facet.
-
extras
+
extras
+
(list or NULL) extra values associated with each of the facets which will be passed to
analysis functions applied within the facet.
-
subset_exprs
+
subset_exprs
+
(list) A list of subsetting expressions (e.g.,
created with quote()) to be used during column subsetting.
-
splres
+
splres
+
(list) a list representing the result of splitting.
-
+
+
-
Value
+
Value
+
A named list representing the facets generated by the split with elements values, datasplit, and
labels, which are the same length and correspond to each other element-wise.
-
Details
+
Details
+
These functions performs various housekeeping tasks to ensure that the split result list is as the rtables
internals expect it, most of which are not relevant to end users.
one or more vectors of levels to appear in the column space. If more than one set of levels is given,
the values of the second are nested within each value of the first, and so on.
-
.lst
+
.lst
+
(list) a list of sets of levels, by default populated via list(...).
-
ccount_format
+
ccount_format
+
(FormatSpec) the format to use when counts are displayed.
-
+
+
-
Value
+
Value
+
An InstantiatedColumnInfo object, suitable for declaring the column structure for a manually constructed
table.
-
Author
+
Author
+
Gabriel Becker
-
Examples
+
Examples
+
# simple one level column spacerows<-lapply(1:5, function(i){DataRow(rep(i, times =3))
@@ -135,17 +198,19 @@
Examples
+
+
-
+
+
-
+
+
diff --git a/main/reference/matrix_form-VTableTree-method.html b/main/reference/matrix_form-VTableTree-method.html
index e949e0b85..740e737de 100644
--- a/main/reference/matrix_form-VTableTree-method.html
+++ b/main/reference/matrix_form-VTableTree-method.html
@@ -1,7 +1,30 @@
-
-Transform an rtable to a list of matrices which can be used for outputting — matrix_form,VTableTree-method • rtables
+
+
+
+
+
+
+Transform an rtable to a list of matrices which can be used for outputting — matrix_form,VTableTree-method • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -17,11 +40,13 @@
# S4 method for class 'VTableTree'matrix_form(obj,
@@ -87,42 +141,54 @@
Usage
-
Arguments
+
Arguments
+
-
obj
+
+
obj
+
(ANY) the object for the accessor to access or modify.
-
indent_rownames
+
indent_rownames
+
(flag) if TRUE, the column with the row names in the strings matrix of the output
has indented row names (strings pre-fixed).
-
expand_newlines
+
expand_newlines
+
(flag) whether the matrix form generated should expand rows whose values contain
newlines into multiple 'physical' rows (as they will appear when rendered into ASCII). Defaults to TRUE.
-
indent_size
+
indent_size
+
(numeric(1)) number of spaces to use per indent level. Defaults to 2.
-
fontspec
+
fontspec
+
(font_spec) The font that should be used by default when
rendering this MatrixPrintForm object, or NULL (the default).
-
col_gap
+
col_gap
+
(numeric(1))] The number of spaces (in the font specified
by fontspec) that should be placed between columns when the table
is rendered directly to text (e.g., by toString or export_as_txt). Defaults
to 3.
-
+
+
-
Value
-
A list with the following elements:
strings
+
Value
+
+
A list with the following elements:
+
+
strings
The content, as it should be printed, of the top-left material, column headers, row labels,
and cell values of tt.
@@ -139,17 +205,20 @@
Value
The data.frame generated by make_row_df.
-
With an additional nrow_header attribute indicating the number of pseudo "rows" that the column structure defines.
+
+
With an additional nrow_header attribute indicating the number of pseudo "rows" that the column structure defines.
-
Details
+
Details
+
The strings in the return object are defined as follows: row labels are those determined by make_row_df and cell
values are determined using get_formatted_cells. (Column labels are calculated using a non-exported internal
function.
# S4 method for class 'VTableNodeInfo'names(x)
@@ -86,35 +141,43 @@
Usage
-
Arguments
+
Arguments
+
-
x
+
+
x
+
(TableTree) the object.
-
+
+
-
Value
+
Value
+
The column names of x, as defined in the details above.
-
Details
+
Details
+
For TableTrees with more than one level of splitting in columns, the names are defined to be the top-level
split values repped out across the columns that they span.
+
+
-
+
+
-
+
+
diff --git a/main/reference/no_info.html b/main/reference/no_info.html
index b65c1cc73..daef64520 100644
--- a/main/reference/no_info.html
+++ b/main/reference/no_info.html
@@ -1,5 +1,28 @@
-
-Exported for use in tern — no_colinfo • rtables
+
+
+
+
+
+
+Exported for use in tern — no_colinfo • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -15,11 +38,13 @@
(TableTree or related class) a TableTree object representing a populated table.
-
lpp
+
lpp
+
(numeric(1)) maximum lines per page including (re)printed header and context rows.
-
min_siblings
+
min_siblings
+
(numeric(1)) minimum sibling rows which must appear on either side of pagination row for a
mid-subtable split to be valid. Defaults to 2.
-
nosplitin
+
nosplitin
+
(character) names of sub-tables where page-breaks are not allowed, regardless of other
considerations. Defaults to none.
-
colwidths
+
colwidths
+
(numeric) a vector of column widths for use in vertical pagination.
-
max_width
+
max_width
+
(integer(1), string or NULL) width that title and footer (including
footnotes) materials should be word-wrapped to. If NULL, it is set to the current print width of the
session (getOption("width")). If set to "auto", the width of the table (plus any table inset) is
used. Parameter is ignored if tf_wrap = FALSE.
-
fontspec
+
fontspec
+
(font_spec) a font_spec object specifying the font information to use for
calculating string widths and heights, as returned by font_spec().
-
col_gap
+
col_gap
+
(numeric(1)) space (in characters) between columns.
-
verbose
+
verbose
+
(flag) whether additional information should be displayed to the user. Defaults to FALSE.
-
page_type
+
page_type
+
(string) name of a page type. See page_types. Ignored
when pg_width and pg_height are set directly.
-
font_family
+
font_family
+
(string) name of a font family. An error will be thrown
if the family named is not monospaced. Defaults to "Courier".
-
font_size
+
font_size
+
(numeric(1)) font size. Defaults to 12.
-
lineheight
+
lineheight
+
(numeric(1)) line height. Defaults to 1.
-
landscape
+
landscape
+
(flag) whether the dimensions of page_type should be
inverted for landscape orientation. Defaults to FALSE, ignored when pg_width and
pg_height are set directly.
-
pg_width
+
pg_width
+
(numeric(1)) page width in inches.
-
pg_height
+
pg_height
+
(numeric(1)) page height in inches.
-
margins
+
margins
+
(numeric(4)) named numeric vector containing "bottom", "left",
"top", and "right" margins in inches. Defaults to .5 inches for both vertical
margins and .75 for both horizontal margins.
-
cpp
+
cpp
+
(numeric(1) or NULL) width (in characters) of the pages for horizontal pagination.
NA (the default) indicates cpp should be inferred from the page size; NULL indicates no horizontal
pagination should be done regardless of page size.
-
tf_wrap
+
tf_wrap
+
(flag) whether the text for title, subtitles, and footnotes should be wrapped.
-
+
+
-
Value
+
Value
+
-
pag_tt_indices returns a list of paginated-groups of row-indices of tt.
+
+
pag_tt_indices returns a list of paginated-groups of row-indices of tt.
paginate_table returns the subtables defined by subsetting by the indices defined by pag_tt_indices.
-
+
+
-
Details
+
Details
+
rtables pagination is context aware, meaning that label rows and row-group summaries (content rows) are repeated
after (vertical) pagination, as appropriate. This allows the reader to immediately understand where they are in the
table after turning to a new page, but does also mean that a rendered, paginated table will take up more lines of
@@ -219,56 +300,82 @@
Pagination is performed independently in the vertical and horizontal
directions based solely on a pagination data frame, which includes the
-following information for each row/column:
Number of lines/characters rendering the row will take after
+following information for each row/column:
+
+
Number of lines/characters rendering the row will take after
word-wrapping (self_extent)
The indices (reprint_inds) and number of lines (par_extent)
of the rows which act as context for the row
The row's number of siblings and position within its siblings
-
Given lpp (cpp) is already adjusted for rendered elements which
+
+
Given lpp (cpp) is already adjusted for rendered elements which
are not rows/columns and a data frame of pagination information,
pagination is performed via the following algorithm with start = 1.
-
Core Pagination Algorithm:
Initial guess for pagination position is start + lpp (start + cpp)
-
While the guess is not a valid pagination position, and guess > start,
-decrement guess and repeat.
An error is thrown if all possible pagination positions between
+
Core Pagination Algorithm:
+
+
Initial guess for pagination position is start + lpp (start + cpp)
+
+
While the guess is not a valid pagination position, and guess > start,
+decrement guess and repeat.
+
+
An error is thrown if all possible pagination positions between
start and start + lpp (start + cpp) would be < start
after decrementing
-
+
+
Retain pagination index
If pagination point was less than NROW(tt) (ncol(tt)), set
start to pos + 1, and repeat steps (1) - (4).
-
Validating Pagination Position:
-
Given an (already adjusted) lpp or cpp value, a pagination is invalid if:
The rows/columns on the page would take more than (adjusted) lpp lines/cpp
-characters to render including:
word-wrapping
+
+
Validating Pagination Position:
+
Given an (already adjusted) lpp or cpp value, a pagination is invalid if:
+
+
+
The rows/columns on the page would take more than (adjusted) lpp lines/cpp
+characters to render including:
+
+
word-wrapping
(vertical only) context repetition
-
+
+
(vertical only) footnote messages and/or section divider lines
take up too many lines after rendering rows
(vertical only) row is a label or content (row-group summary) row
(vertical only) row at the pagination point has siblings, and
it has less than min_siblings preceding or following siblings
pagination would occur within a sub-table listed in nosplitin
(character) the names of variables to be used in row facetting.
-
col_vars
+
col_vars
+
(character) the names of variables to be used in column facetting.
-
avar
+
avar
+
(string) the variable to be analyzed. Defaults to the first variable in data.
-
row_labels
+
row_labels
+
(character or NULL) row label(s) which should be applied to the analysis rows. Length must
match the number of rows generated by afun.
-
afun
+
afun
+
(function) the function to generate the analysis row cell values. This can be a proper analysis
function, or a function which returns a vector or list. Vectors are taken as multi-valued single cells, whereas
lists are interpreted as multiple cells.
-
summarize_groups
+
summarize_groups
+
(flag) whether each level of nesting should include marginal summary rows. Defaults to
FALSE.
(character) a vector of strings to use as subtitles (formatters::subtitles()), where every
element is printed on a separate line. Ignored for subtables.
-
main_footer
+
main_footer
+
(character) a vector of strings to use as main global (non-referential) footer materials
(formatters::main_footer()), where every element is printed on a separate line.
-
prov_footer
+
prov_footer
+
(character) a vector of strings to use as provenance-related global footer materials
(formatters::prov_footer()), where every element is printed on a separate line.
-
show_colcounts
+
show_colcounts
+
(logical(1)) Indicates whether the lowest level of
applied to data. NA, the default, indicates that the show_colcounts
argument(s) passed to the relevant calls to split_cols_by*
@@ -178,28 +246,36 @@
(flag) whether unobserved factor levels should be dropped during facetting. Defaults to
TRUE.
-
...
+
...
+
additional arguments passed to afun.
-
.default_rlabel
+
.default_rlabel
+
(string) this is an implementation detail that should not be set by end users.
-
+
+
-
Value
+
Value
+
-
qtable returns a built TableTree object representing the desired table
+
+
qtable returns a built TableTree object representing the desired table
qtable_layout returns a PreDataTableLayouts object declaring the structure of the desired table, suitable for
passing to build_table().
-
+
+
-
Details
+
Details
+
This function creates a table with a single top-level structure in both row and column dimensions involving faceting
by 0 or more variables in each dimension.
The display of the table depends on certain details of the tabulation. In the case of an afun which returns a
@@ -214,7 +290,8 @@
Details
-
Examples
+
Examples
+
qtable(ex_adsl)#> all obs#> (N=400)
@@ -365,17 +442,19 @@
rbindl_rtables(x, gap =lifecycle::deprecated(),
@@ -86,39 +140,50 @@
Usage
-
Arguments
+
Arguments
+
-
x
+
+
x
+
(VTableNodeInfo) TableTree, ElementaryTable, or TableRow object.
-
gap
+
gap
+
ignored.
-
check_headers
+
check_headers
+
ignored.
-
...
+
...
+
(ANY) elements to be stacked.
-
deparse.level
+
deparse.level
+
(numeric(1)) currently ignored.
-
y
+
y
+
(VTableNodeInfo) TableTree, ElementaryTable, or TableRow object.
-
+
+
-
Value
+
Value
+
A formal table object.
-
Note
+
Note
+
When objects are row-bound, titles and footer information is retained from the first object (if any exists) if all
other objects have no titles/footers or have identical titles/footers. Otherwise, all titles/footers are removed
and must be set for the bound table via the formatters::main_title(), formatters::subtitles(),
@@ -126,7 +191,8 @@
(string or function) the format label (string) or formatters function to apply to x.
See formatters::list_valid_format_labels() for currently supported format labels.
-
colspan
+
colspan
+
(integer(1)) column span value.
-
label
+
label
+
(string or NULL) label. If non-NULL, it will be looked at when determining row labels.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
footnotes
+
footnotes
+
(list or NULL) referential footnote messages for the cell.
-
align
+
align
+
(string or NULL) alignment the value should be rendered with. Defaults to "center" if
NULL is used. See formatters::list_valid_aligns() for all currently supported alignments.
-
format_na_str
+
format_na_str
+
(string) string which should be displayed when formatted if this cell's value(s)
are all NA.
-
stat_names
+
stat_names
+
(character or NA) names for the statistics in the cell. It can be a vector of strings.
If NA, statistic names are not specified.
-
is_ref
+
is_ref
+
(flag) whether function is being used in the reference column (i.e. .in_ref_col should be
passed to this argument).
-
refval
+
refval
+
(ANY) value to use when in the reference column. Defaults to NULL.
-
+
+
-
Value
+
Value
+
An object representing the value within a single cell within a populated table. The underlying structure
of this object is an implementation detail and should not be relied upon beyond calling accessors for the class.
-
Details
+
Details
+
non_ref_rcell provides the common blank for cells in the reference column, this value otherwise, and should
be passed the value of .in_ref_col when it is used.
-
Note
+
Note
+
Currently column spanning is only supported for defining header structure.
-
Examples
+
Examples
+
rcell(1, format ="xx.x")#> rcell: 1.0 rcell(c(1, 2), format =c("xx - xx"))
@@ -179,17 +251,19 @@
row specifications, either as character vectors or the output from rrow(), DataRow(),
LabelRow(), etc.
-
format
+
format
+
(string, function, or list) the format label (string) or formatter function to apply to the
cell values passed via .... See formatters::list_valid_format_labels() for currently supported format labels.
-
.lst
+
.lst
+
(list) an already-collected list of arguments to be used instead of the elements of ....
Arguments passed via ... will be ignored if this is specified.
-
+
+
-
Value
+
Value
+
A InstantiatedColumnInfo object.
-
See also
+
See also
+
Other compatibility:
rrow(),
rrowl(),
@@ -107,7 +169,8 @@
LabelRow( lev =1L, label ="",
@@ -109,104 +163,127 @@
Usage
-
Arguments
+
Arguments
+
-
lev
+
+
lev
+
(integer(1)) nesting level (roughly, indentation level in practical terms).
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
name
+
name
+
(string) name of the split/table/row being created. Defaults to the value of the
corresponding label, but is not required to be.
-
vis
+
vis
+
(flag) whether the row should be visible (LabelRow only).
-
cinfo
+
cinfo
+
(InstantiatedColumnInfo or NULL) column structure for the object being created.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
table_inset
+
table_inset
+
(numeric(1)) number of spaces to inset the table header, table body, referential footnotes,
and main footer, as compared to alignment of title, subtitles, and provenance footer. Defaults to 0 (no inset).
-
trailing_section_div
+
trailing_section_div
+
(string) string which will be used as a section divider after the printing
of the last row contained in this (sub)table, unless that row is also the last table row to be printed overall,
or NA_character_ for none (the default). When generated via layouting, this would correspond to the
section_div of the split under which this table represents a single facet.
-
vals
+
vals
+
(list) cell values for the row.
-
cspan
+
cspan
+
(integer) column span. 1 indicates no spanning.
-
var
+
var
+
(string) variable name.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
klass
+
klass
+
(character) internal detail.
-
footnotes
+
footnotes
+
(list or NULL) referential footnotes to be applied at current level. In post-processing,
this can be achieved with fnotes_at_path<-.
-
...
+
...
+
additional parameters passed to shared constructor (.tablerow).
-
+
+
-
Value
+
Value
+
A formal object representing a table row of the constructed type.
rrow(row.name ="", ..., format =NULL, indent =0, inset =0L)
-
Arguments
+
Arguments
+
-
row.name
+
+
row.name
+
(string or NULL) row name. If NULL, an empty string is used as row.name of the
rrow().
-
...
+
...
+
cell values.
-
format
+
format
+
(string, function, or list) the format label (string) or formatter function to apply to the
cell values passed via .... See formatters::list_valid_format_labels() for currently supported format labels.
-
indent
+
indent
+
-
inset
+
inset
+
(integer(1)) the table inset for the row or table being constructed. See
formatters::table_inset() for details.
-
+
+
-
Value
+
Value
+
A row object of the context-appropriate type (label or data).
-
See also
+
See also
+
Other compatibility:
rheader(),
rrowl(),
@@ -115,7 +179,8 @@
rrowl(row.name, ..., format =NULL, indent =0, inset =0L)
-
Arguments
+
Arguments
+
-
row.name
+
+
row.name
+
(string or NULL) row name. If NULL, an empty string is used as row.name of the
rrow().
-
...
+
...
+
values in vector/list form.
-
format
+
format
+
(string, function, or list) the format label (string) or formatter function to apply to the
cell values passed via .... See formatters::list_valid_format_labels() for currently supported format labels.
-
indent
+
indent
+
-
inset
+
inset
+
(integer(1)) the table inset for the row or table being constructed. See
formatters::table_inset() for details.
-
+
+
-
Value
+
Value
+
A row object of the context-appropriate type (label or data).
-
See also
+
See also
+
Other compatibility:
rheader(),
rrow(),
@@ -115,7 +179,8 @@
rtable(header, ..., format =NULL, hsep =default_hsep(), inset =0L)rtablel(header, ..., format =NULL, hsep =default_hsep(), inset =0L)
-
Arguments
+
Arguments
+
-
header
+
+
header
+
(TableRow, character, or InstantiatedColumnInfo) information defining the header
(column structure) of the table. This can be as row objects (legacy), character vectors, or an
InstantiatedColumnInfo object.
-
...
+
...
+
rows to place in the table.
-
format
+
format
+
(string, function, or list) the format label (string) or formatter function to apply to the
cell values passed via .... See formatters::list_valid_format_labels() for currently supported format labels.
-
hsep
+
hsep
+
(string) set of characters to be repeated as the separator between the header and body of
the table when rendered as text. Defaults to a connected horizontal line (unicode 2014) in locals that use a UTF
charset, and to - elsewhere (with a once per session warning). See formatters::set_default_hsep() for further
information.
-
inset
+
inset
+
(integer(1)) the table inset for the row or table being constructed. See
formatters::table_inset() for details.
-
+
+
-
Value
+
Value
+
A formal table object of the appropriate type (ElementaryTable or TableTree).
-
See also
+
See also
+
Other compatibility:
rheader(),
rrow(),
@@ -121,7 +185,8 @@
sanitize_table_struct(tt, empty_msg ="-- This Section Contains No Data --")
-
Arguments
+
Arguments
+
-
tt
+
+
tt
+
(TableTree) a TableTree object.
-
empty_msg
+
empty_msg
+
(string) the string which should be spanned across the inserted empty rows.
-
+
+
-
Value
+
Value
+
If tt is already valid, it is returned unmodified. If tt is degenerate, a modified, non-degenerate
version of the table is returned.
-
Details
+
Details
+
This function locates degenerate portions of the table (including the table overall in the case of a table with no
data rows) and inserts a row which spans all columns with the message empty_msg at each one, generating a table
guaranteed to be non-degenerate.
section_div(obj)# S4 method for class 'VTableTree'
@@ -140,36 +194,44 @@
Usage
-
Arguments
+
Arguments
+
-
obj
+
+
obj
+
(VTableTree) table object. This can be of any class that inherits from VTableTree
or TableRow/LabelRow.
-
only_sep_sections
+
only_sep_sections
+
(flag) defaults to FALSE for section_div<-. Allows
you to set the section divider only for sections that are splits or analyses if the number of
values is less than the number of rows in the table. If TRUE, the section divider will
be set for all rows of the table.
-
value
+
value
+
(character) vector of single characters to use as section dividers. Each character
is repeated such that all section dividers span the width of the table. Each character that is
not NA_character_ will produce a trailing separator for each row of the table. value length
should reflect the number of rows, or be between 1 and the number of splits/levels.
See the Details section below for more information.
-
+
+
-
Value
+
Value
+
The section divider string. Each line that does not have a trailing separator
will have NA_character_ as section divider.
-
Details
+
Details
+
Assigned value to section divider must be a character vector. If any value is NA_character_
the section divider will be absent for that row or section. When you want to only affect sections
or splits, please use only_sep_sections or provide a shorter vector than the number of rows.
@@ -183,13 +245,15 @@
(TableTree or related class) a TableTree object representing a populated table.
-
path
+
path
+
(character) a vector path for a position within the structure of a TableTree. Each element
represents a subsequent choice amongst the children of the previous choice.
-
scorefun
+
scorefun
+
(function) scoring function. Should accept the type of children directly under the position
at path (either VTableTree, VTableRow, or VTableNodeInfo, which covers both) and return a numeric value
to be sorted.
-
decreasing
+
decreasing
+
(flag) whether the scores generated by scorefun should be sorted in decreasing order. If
unset (the default of NA), it is set to TRUE if the generated scores are numeric and FALSE if they are
characters.
-
na.pos
+
na.pos
+
(string) what should be done with children (sub-trees/rows) with NA scores. Defaults to
"omit", which removes them. Other allowed values are "last" and "first", which indicate where NA scores
should be placed in the order.
-
.prev_path
+
.prev_path
+
(character) internal detail, do not set manually.
-
+
+
-
Value
+
Value
+
A TableTree with the same structure as tt with the exception that the requested sorting has been done
at path.
-
Details
+
Details
+
sort_at_path, given a path, locates the (sub)table(s) described by the path (see below for handling of the "*"
wildcard). For each such subtable, it then calls scorefun on each direct child of the table, using the resulting
scores to determine their sorted order. tt is then modified to reflect each of these one or more sorting
@@ -147,7 +212,9 @@
Built-in score functions are cont_n_allcols() and cont_n_onecol(). They are both working with content rows
(coming from summarize_row_groups()) while a custom score function needs to be used on DataRows. Here, some
-useful descriptor and accessor functions (coming from related vignette):
cell_values() - Retrieves a named list of a TableRow or TableTree object's values.
+useful descriptor and accessor functions (coming from related vignette):
+
+
cell_values() - Retrieves a named list of a TableRow or TableTree object's values.
formatters::obj_name() - Retrieves the name of an object. Note this can differ from the label that is
displayed (if any is) when printing.
formatters::obj_label() - Retrieves the display label of an object. Note this can differ from the name that
@@ -155,18 +222,23 @@
Details
content_table() - Retrieves a TableTree object's content table (which contains its summary rows).
tree_children() - Retrieves a TableTree object's direct children (either subtables, rows or possibly a mix
thereof, though that should not happen in practice).
The .spl_contextdata.frame gives information about the subsets of data corresponding to the splits within
which the current analyze action is nested. Taken together, these correspond to the path that the resulting (set
of) rows the analysis function is creating, although the information is in a slightly different form. Each split
(which correspond to groups of rows in the resulting table), as well as the initial 'root' "split", is represented
via the following columns:
-
split
+
+
split
The name of the split (often the variable being split).
Within analysis functions that accept .spl_context, the all_cols_n and cur_col_n columns of the data frame
will contain the 'true' observation counts corresponding to the row-group and row-group x column subsets of the
data. These numbers will not, and currently cannot, reflect alternate column observation counts provided by the
@@ -134,17 +191,19 @@
Note
+
+
-
+
+
-
+
+
diff --git a/main/reference/spl_context_to_disp_path.html b/main/reference/spl_context_to_disp_path.html
index 9e62e6334..3dfb4b5b4 100644
--- a/main/reference/spl_context_to_disp_path.html
+++ b/main/reference/spl_context_to_disp_path.html
@@ -1,5 +1,28 @@
-
-Translate spl_context to a path to display in error messages — spl_context_to_disp_path • rtables
+
+
+
+
+
+
+Translate spl_context to a path to display in error messages — spl_context_to_disp_path • rtables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Skip to contents
@@ -15,11 +38,13 @@
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
var
+
var
+
(string) variable name.
-
labels_var
+
labels_var
+
(string) name of variable containing labels to be displayed for the values of var.
-
split_label
+
split_label
+
(string) label to be associated with the table generated by the split. Not to be confused
with labels assigned to each child (which are based on the data and type of split during tabulation).
-
split_fun
+
split_fun
+
(function or NULL) custom splitting function. See custom_split_funs.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
nested
+
nested
+
(logical) whether this layout instruction should be applied within the existing layout structure
if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split
underneath analyses, which is not allowed.
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
ref_group
+
ref_group
+
(string or NULL) level of var that should be considered ref_group/reference.
-
show_colcounts
+
show_colcounts
+
(logical(1)) should column counts be displayed at the level
facets created by this split. Defaults to FALSE.
-
colcount_format
+
colcount_format
+
(character(1)) if show_colcounts is TRUE, the
format which should be used to display column counts for facets generated by
this split. Defaults to "(N=xx)".
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
-
Custom Splitting Function Details
+
Custom Splitting Function Details
+
User-defined custom split functions can perform any type of computation on the incoming data provided that they
meet the requirements for generating "splits" of the incoming data based on the split object.
One way to generate custom splitting functions is to wrap existing split functions and modify either the incoming
+
+
One way to generate custom splitting functions is to wrap existing split functions and modify either the incoming
data before they are called or their outputs.
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
vars
+
vars
+
(character) vector of variable names.
-
split_fun
+
split_fun
+
(function or NULL) custom splitting function. See custom_split_funs.
-
varlabels
+
varlabels
+
(character) vector of labels for vars.
-
varnames
+
varnames
+
(character) vector of names for vars which will appear in pathing. When vars are all
unique this will be the variable names. If not, these will be variable names with suffixes as necessary to enforce
uniqueness.
-
nested
+
nested
+
(logical) whether this layout instruction should be applied within the existing layout structure
if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split
underneath analyses, which is not allowed.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
show_colcounts
+
show_colcounts
+
(logical(1)) should column counts be displayed at the level
facets created by this split. Defaults to FALSE.
-
colcount_format
+
colcount_format
+
(character(1)) if show_colcounts is TRUE, the
format which should be used to display column counts for facets generated by
this split. Defaults to "(N=xx)".
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
(character) levels to retain (all others will be dropped). If none of the levels is present
an empty table is returned.
-
reorder
+
reorder
+
(flag) whether the order of only should be used as the order of the children of the
split. Defaults to TRUE.
-
excl
+
excl
+
(character) levels to be excluded (they will not be reflected in the resulting table structure
regardless of presence in the data).
-
df
+
df
+
(data.frame or tibble) dataset.
-
spl
+
spl
+
(Split) a Split object defining a partitioning or analysis/tabulation of the data.
-
vals
+
vals
+
(ANY) for internal use only.
-
labels
+
labels
+
(character) labels to use for the remaining levels instead of the existing ones.
-
trim
+
trim
+
(flag) whether splits corresponding with 0 observations should be kept when tabulating.
-
neworder
+
neworder
+
(character) new order of factor levels. All need to be present in the data.
To add empty levels, rely on pre-processing or create your custom_split_funs.
-
newlabels
+
newlabels
+
(character) labels for (new order of) factor levels. If named, the levels are matched.
Otherwise, the order of neworder is used.
-
drlevels
+
drlevels
+
(flag) whether levels that are not in neworder should be dropped.
Default is TRUE. Note: drlevels = TRUE does not drop levels that are not originally in the data.
Rely on pre-processing or use a combination of split functions with make_split_fun() to also drop
unused levels.
-
innervar
+
innervar
+
(string) variable whose factor levels should be trimmed (e.g. empty levels dropped)
separately within each grouping defined at this point in the structure.
-
drop_outlevs
+
drop_outlevs
+
(flag) whether empty levels in the variable being split on (i.e. the "outer"
variable, not innervar) should be dropped. Defaults to TRUE.
-
+
+
-
Value
+
Value
+
A function that can be used to split the data accordingly. The actual function signature
is similar to the one you can define when creating a fully custom one. For more details see custom_split_funs.
-
Functions
+
Functions
+
-
keep_split_levels(): keeps only specified levels (only) in the split variable. If any of the specified
+
+
keep_split_levels(): keeps only specified levels (only) in the split variable. If any of the specified
levels is not present, an error is returned. reorder = TRUE (the default) orders the split levels
according to the order of only.
remove_split_levels(): Removes specified levels (excl) from the split variable. Nothing done if not in data.
The following parameters are also documented here but they are only the default
signature of a split function: df (data to be split), spl (split object), and vals = NULL,
labels = NULL, trim = FALSE (last three only for internal use). See custom_split_funs for more details
and make_split_fun() for a more advanced API.
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
var
+
var
+
(string) variable name.
-
labels_var
+
labels_var
+
(string) name of variable containing labels to be displayed for the values of var.
-
split_label
+
split_label
+
(string) label to be associated with the table generated by the split. Not to be confused
with labels assigned to each child (which are based on the data and type of split during tabulation).
-
split_fun
+
split_fun
+
(function or NULL) custom splitting function. See custom_split_funs.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
nested
+
nested
+
(logical) whether this layout instruction should be applied within the existing layout structure
if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split
underneath analyses, which is not allowed.
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
page_by
+
page_by
+
(flag) whether pagination should be forced between different children resulting from this
split. An error will occur if the selected split does not contain at least one value that is not NA.
-
page_prefix
+
page_prefix
+
(string) prefix to be appended with the split value when forcing pagination between
the children of a split/table.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
-
Note
+
Note
+
If var is a factor with empty unobserved levels and labels_var is specified, it must also be a factor
with the same number of levels as var. Currently the error that occurs when this is not the case is not very
informative, but that will change in the future.
-
Custom Splitting Function Details
+
Custom Splitting Function Details
+
User-defined custom split functions can perform any type of computation on the incoming data provided that they
meet the requirements for generating "splits" of the incoming data based on the split object.
One way to generate custom splitting functions is to wrap existing split functions and modify either the incoming
+
+
One way to generate custom splitting functions is to wrap existing split functions and modify either the incoming
data before they are called or their outputs.
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
vars
+
vars
+
(character) vector of variable names.
-
split_fun
+
split_fun
+
(function or NULL) custom splitting function. See custom_split_funs.
-
split_label
+
split_label
+
(string) label to be associated with the table generated by the split. Not to be confused
with labels assigned to each child (which are based on the data and type of split during tabulation).
-
varlabels
+
varlabels
+
(character) vector of labels for vars.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
nested
+
nested
+
(logical) whether this layout instruction should be applied within the existing layout structure
if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split
underneath analyses, which is not allowed.
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
summarize_row_groups(lyt, var ="",
@@ -85,57 +139,70 @@
Usage
-
Arguments
+
Arguments
+
-
lyt
+
+
lyt
+
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
var
+
var
+
(string) variable name.
-
label_fstr
+
label_fstr
+
(string) a sprintf style format string. For non-comparison splits, it can contain up to
one "\%s" which takes the current split value and generates the row/column label. For comparison-based splits
it can contain up to two "\%s".
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
cfun
+
cfun
+
(list, function, or NULL) tabulation function(s) for creating content rows. Must accept x
or df as first parameter. Must accept labelstr as the second argument. Can optionally accept all optional
arguments accepted by analysis functions. See analyze().
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
-
Details
+
Details
+
If format expects 1 value (i.e. it is specified as a format string and xx appears for two values
(i.e. xx appears twice in the format string) or is specified as a function, then both raw and percent of
column total counts are calculated. If format is a format string where xx appears only one time, only
@@ -148,12 +215,14 @@
ElementaryTable( kids =list(), name ="",
@@ -127,137 +182,166 @@
Usage
-
Arguments
+
Arguments
+
-
kids
+
+
kids
+
(list) list of direct children.
-
name
+
name
+
(string) name of the split/table/row being created. Defaults to the value of the
corresponding label, but is not required to be.
-
lev
+
lev
+
(integer(1)) nesting level (roughly, indentation level in practical terms).
-
label
+
label
+
(string) a label (not to be confused with the name) for the object/structure.
-
labelrow
+
labelrow
+
(LabelRow) the LabelRow object to assign to the table. Constructed from label by default
if not specified.
-
rspans
+
rspans
+
(data.frame) currently stored but otherwise ignored.
-
cinfo
+
cinfo
+
(InstantiatedColumnInfo or NULL) column structure for the object being created.
-
iscontent
+
iscontent
+
(flag) whether the TableTree/ElementaryTable is being constructed as the content
table for another TableTree.
-
var
+
var
+
(string) variable name.
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
(character) a vector of strings to use as subtitles (formatters::subtitles()), where every
element is printed on a separate line. Ignored for subtables.
-
main_footer
+
main_footer
+
(character) a vector of strings to use as main global (non-referential) footer materials
(formatters::main_footer()), where every element is printed on a separate line.
-
prov_footer
+
prov_footer
+
(character) a vector of strings to use as provenance-related global footer materials
(formatters::prov_footer()), where every element is printed on a separate line.
-
header_section_div
+
header_section_div
+
(string) string which will be used to divide the header from the table. See
header_section_div() for the associated getter and setter. Please consider changing last element of
section_div() when concatenating tables that require a divider between them.
-
hsep
+
hsep
+
(string) set of characters to be repeated as the separator between the header and body of
the table when rendered as text. Defaults to a connected horizontal line (unicode 2014) in locals that use a UTF
charset, and to - elsewhere (with a once per session warning). See formatters::set_default_hsep() for further
information.
-
trailing_section_div
+
trailing_section_div
+
(string) string which will be used as a section divider after the printing
of the last row contained in this (sub)table, unless that row is also the last table row to be printed overall,
or NA_character_ for none (the default). When generated via layouting, this would correspond to the
section_div of the split under which this table represents a single facet.
-
inset
+
inset
+
(numeric(1)) number of spaces to inset the table header, table body, referential footnotes, and
main_footer, as compared to alignment of title, subtitle, and provenance footer. Defaults to 0 (no inset).
(TableTree or related class) a TableTree object representing a populated table.
-
widths
+
widths
+
(numeric or NULL) Proposed widths for the columns of x. The expected
length of this numeric vector can be retrieved with ncol(x) + 1 as the column of row names
must also be considered.
-
col_gap
+
col_gap
+
(numeric(1)) space (in characters) between columns.
-
hsep
+
hsep
+
(string) character to repeat to create header/body separator line. If
NULL, the object value will be used. If " ", an empty separator will be printed. See
default_hsep() for more information.
-
tf_wrap
+
tf_wrap
+
(flag) whether the text for title, subtitles, and footnotes should be wrapped.
-
max_width
+
max_width
+
(integer(1), string or NULL) width that title and footer (including
footnotes) materials should be word-wrapped to. If NULL, it is set to the current print width of the
session (getOption("width")). If set to "auto", the width of the table (plus any table inset) is
used. Parameter is ignored if tf_wrap = FALSE.
-
+
+
-
Value
+
Value
+
-
table_shell returns NULL, as the function is called for the side effect of printing the shell to the console.
+
+
table_shell returns NULL, as the function is called for the side effect of printing the shell to the console.
table_shell_str returns the string representing the table shell.
-
+
+
-
See also
+
See also
+
value_formats() for a matrix of formats for each cell in a table.
# S4 method for class 'VTableTree'toString(x,
@@ -102,72 +156,88 @@
Usage
-
Arguments
+
Arguments
+
-
x
+
+
x
+
(ANY) object to be prepared for rendering.
-
widths
+
widths
+
(numeric or NULL) Proposed widths for the columns of x. The expected
length of this numeric vector can be retrieved with ncol(x) + 1 as the column of row names
must also be considered.
-
col_gap
+
col_gap
+
(numeric(1)) space (in characters) between columns.
-
hsep
+
hsep
+
(string) character to repeat to create header/body separator line. If
NULL, the object value will be used. If " ", an empty separator will be printed. See
default_hsep() for more information.
-
indent_size
+
indent_size
+
(numeric(1)) number of spaces to use per indent level. Defaults to 2.
-
tf_wrap
+
tf_wrap
+
(flag) whether the text for title, subtitles, and footnotes should be wrapped.
-
max_width
+
max_width
+
(integer(1), string or NULL) width that title and footer (including
footnotes) materials should be word-wrapped to. If NULL, it is set to the current print width of the
session (getOption("width")). If set to "auto", the width of the table (plus any table inset) is
used. Parameter is ignored if tf_wrap = FALSE.
-
fontspec
+
fontspec
+
(font_spec) a font_spec object specifying the font information to use for
calculating string widths and heights, as returned by font_spec().
-
ttype_ok
+
ttype_ok
+
(logical(1)) should truetype (non-monospace) fonts be
allowed via fontspec. Defaults to FALSE. This parameter is primarily
for internal testing and generally should not be set by end users.
-
+
+
-
Value
+
Value
+
A string representation of x as it appears when printed.
-
Details
+
Details
+
Manual insertion of newlines is not supported when tf_wrap = TRUE and will result in a warning and
undefined wrapping behavior. Passing vectors of already split strings remains supported, however in this
case each string is word-wrapped separately with the behavior described above.
data.frame. A data.frame defining allowed combinations of
variables. Any combination at the level of this split not present in the
map will be removed from the data, both for the variable being split and
those present in the data but not associated with this split or any parents
of it.
-
+
+
-
Value
+
Value
+
A function that can be used as a split function.
-
Details
+
Details
+
When splitting occurs, the map is subset to the values of all previously performed splits. The levels of the
variable being split are then pruned to only those still present within this subset of the map representing the
current hierarchical splitting context.
(TableRow or related class) a TableRow object representing a single row within a populated table.
-
tt
+
tt
+
(TableTree or related class) a TableTree object representing a populated table.
-
criteria
+
criteria
+
(function) function which takes a TableRow object and returns TRUE if that row
should be removed. Defaults to all_zero_or_na().
-
min
+
min
+
(numeric(1)) (used by low_obs_pruner only). Minimum aggregate count value.
Subtables whose combined/average count are below this threshold will be pruned.
-
type
+
type
+
(string) how count values should be aggregated. Must be "sum" (the default) or "mean".
-
+
+
-
Value
+
Value
+
A logical value indicating whether tr should be included (TRUE) or pruned (FALSE) during pruning.
-
Details
+
Details
+
all_zero_or_na returns TRUE (and thus indicates trimming/pruning) for any non-LabelRowTableRow which contain only any mix of NA (including NaN), 0, Inf and -Inf values.
all_zero returns TRUE for any non-LabelRow which contains only (non-missing) zero values.
-
content_all_zeros_nas prunes a subtable if both of the following are true:
It has a content table with exactly one row in it.
+
content_all_zeros_nas prunes a subtable if both of the following are true:
+
+
It has a content table with exactly one row in it.
all_zero_or_na returns TRUE for that single content row. In practice, when the default summary/content
function is used, this represents pruning any subtable which corresponds to an empty set of the input data
(e.g. because a factor variable was used in split_rows_by() but not all levels were present in the data).
-
prune_empty_level combines all_zero_or_na behavior for TableRow objects, content_all_zeros_nas on
+
+
prune_empty_level combines all_zero_or_na behavior for TableRow objects, content_all_zeros_nas on
content_table(tt) for TableTree objects, and an additional check that returns TRUE if the tt has no
children.
prune_zeros_only behaves as prune_empty_level does, except that like all_zero it prunes
@@ -134,12 +201,14 @@
(TableTree or related class) a TableTree object representing a populated table.
-
criteria
+
criteria
+
(function) function which takes a TableRow object and returns TRUE if that row
should be removed. Defaults to all_zero_or_na().
-
+
+
-
Value
+
Value
+
The table with rows that have only NA or 0 cell values removed.
-
Details
+
Details
+
This function will be deprecated in the future in favor of the more elegant and versatile prune_table()
function which can perform the same function as trim_rows() but is more powerful as it takes table structure
into account.
-
Note
+
Note
+
Visible LabelRows are including in this trimming, which can lead to either all label rows being trimmed or
label rows remaining when all data rows have been trimmed, depending on what criteria returns when called on
a LabelRow object. To avoid this, use the structurally-aware prune_table() machinery instead.
(TableTree or related class) a TableTree object representing a populated table.
-
file
+
file
+
(string) the path of the file to written to or read from.
-
path_fun
+
path_fun
+
(function) function to transform paths into single-string row/column names.
-
value_fun
+
value_fun
+
(function) function to transform cell values into cells of a data.frame. Defaults to
collapse_values, which creates strings where multi-valued cells are collapsed together, separated by |.
import_from_tsv returns a data.frame with re-constituted list values.
-
+
+
-
Details
+
Details
+
By default (i.e. when value_func is not specified, list columns where at least one value has length > 1 are
collapsed to character vectors by collapsing the list element with "|".
-
Note
+
Note
+
There is currently no round-trip capability for this type of export. You can read values exported this way back in
via import_from_tsv but you will receive only the data.frame version back, NOT a TableTree.
(TableTree or related class) a TableTree object representing a populated table.
-
path
+
path
+
(character) a vector path for a position within the structure of a TableTree. Each element
represents a subsequent choice amongst the children of the previous choice.
-
...
+
...
+
unused.
-
value
+
value
+
(ANY) the new value.
-
+
+
-
Note
+
Note
+
Setting NULL at a defined path removes the corresponding sub-table.
(TableTree or related class) a TableTree object representing a populated table.
-
+
+
-
Details
+
Details
+
After adding or removing referential footnotes manually, or after subsetting a table, the reference indexes
(i.e. the number associated with specific footnotes) may be incorrect. This function recalculates these based
on the full table.
-
Note
+
Note
+
In the future this should not generally need to be called manually.
A TableTree (rtables-built table) is considered degenerate if:
It contains no subtables or data rows (content rows do not count).
+
A TableTree (rtables-built table) is considered degenerate if:
+
+
It contains no subtables or data rows (content rows do not count).
It contains a subtable which is degenerate by the criterion above.
-
validate_table_struct assesses whether tt has a valid (non-degenerate) structure.
+
+
validate_table_struct assesses whether tt has a valid (non-degenerate) structure.
assert_valid_table asserts a table must have a valid structure, and throws an informative error (the default) or
warning (if warn_only is TRUE) if the table is degenerate (has invalid structure or contains one or more
invalid substructures.
value_formats(obj, default =obj_format(obj))# S4 method for class 'ANY'
@@ -88,29 +142,37 @@
Usage
-
Arguments
+
Arguments
+
-
obj
+
+
obj
+
(VTableTree or TableRow) a table or row object.
-
default
+
default
+
(string, function, or list) default format.
-
+
+
-
Value
+
Value
+
Matrix (storage mode list) containing the effective format for each cell position in the table
(including 'virtual' cells implied by label rows, whose formats are always NULL).
(PreDataTableLayouts) layout object pre-data used for tabulation.
-
var
+
var
+
(string) variable name.
-
cuts
+
cuts
+
(numeric) cuts to use.
-
cutlabels
+
cutlabels
+
(character or NULL) labels for the cuts.
-
split_label
+
split_label
+
(string) label to be associated with the table generated by the split. Not to be confused
with labels assigned to each child (which are based on the data and type of split during tabulation).
-
nested
+
nested
+
(logical) whether this layout instruction should be applied within the existing layout structure
if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split
underneath analyses, which is not allowed.
-
cumulative
+
cumulative
+
(flag) whether the cuts should be treated as cumulative. Defaults to FALSE.
-
show_colcounts
+
show_colcounts
+
(logical(1)) should column counts be displayed at the level
facets created by this split. Defaults to FALSE.
-
colcount_format
+
colcount_format
+
(character(1)) if show_colcounts is TRUE, the
format which should be used to display column counts for facets generated by
this split. Defaults to "(N=xx)".
-
format
+
format
+
(string, function, or list) format associated with this split. Formats can be declared via
strings ("xx.x") or function. In cases such as analyze calls, they can be character vectors or lists of
functions. See formatters::list_valid_format_labels() for a list of all available format strings.
-
na_str
+
na_str
+
(string) string that should be displayed when the value of x is missing. Defaults to "NA".
-
label_pos
+
label_pos
+
(string) location where the variable label should be displayed. Accepts "hidden"
(default for non-analyze row splits), "visible", "topleft", and "default" (for analyze splits only). For
analyze calls, "default" indicates that the variable should be visible if and only if multiple variables are
analyzed at the same level of nesting.
-
section_div
+
section_div
+
(string) string which should be repeated as a section divider after each group defined
by this split instruction, or NA_character_ (the default) for no section divider.
-
cutfun
+
cutfun
+
(function) function which accepts the full vector of var values and returns cut points to be
used (via cut) when splitting data during tabulation.
-
cutlabelfun
+
cutlabelfun
+
(function) function which returns either labels for the cuts or NULL when passed the
return value of cutfun.
-
extra_args
+
extra_args
+
(list) extra arguments to be passed to the tabulation function. Element position in the list
corresponds to the children of this split. Named elements in the child-specific lists are ignored if they do
not match a formal argument of the tabulation function.
-
child_labels
+
child_labels
+
(string) the display behavior for the labels (i.e. label rows) of the children of this
split. Accepts "default", "visible", and "hidden". Defaults to "default" which flags the label row as
visible only if the child has 0 content rows.
-
indent_mod
+
indent_mod
+
(numeric) modifier for the default indent position for the structure created by this
function (subtable, content table, or row) and all of that structure's children. Defaults to 0, which
corresponds to the unmodified default behavior.
-
+
+
-
Value
+
Value
+
A PreDataTableLayouts object suitable for passing to further layouting functions, and to build_table().
-
Details
+
Details
+
For dynamic cuts, the cut is transformed into a static cut by build_table()based on the full dataset,
before proceeding. Thus even when nested within another split in column/row space, the resulting split will reflect
the overall values (e.g., quartiles) in the dataset, NOT the values for subset it is nested under.
vars_in_layout(lyt)# S4 method for class 'PreDataTableLayouts'
@@ -94,35 +148,48 @@
Usage
-
Arguments
+
Arguments
+
-
lyt
+
+
lyt
+
(PreDataTableLayouts) the layout (or a component thereof).
-
+
+
-
Value
+
Value
+
A character vector containing the unique variables explicitly used in the layout (see the notes below).
-
Details
+
Details
+
This will walk the layout declaration and return a vector of the names of the unique variables that are used
-in any of the following ways:
Variable being split on (directly or via cuts)
+in any of the following ways:
+
+
Variable being split on (directly or via cuts)
Element of a Multi-variable column split
Content variable
Value-label variable
-
+
+
-
Note
+
Note
+
-
This function will not detect dependencies implicit in analysis or summary functions which accept x
+
+
This function will not detect dependencies implicit in analysis or summary functions which accept x
or df and then rely on the existence of particular variables not being split on/analyzed.
The order these variable names appear within the return vector is undefined and should not be relied upon.
-
+
+
-
+
+
diff --git a/main/search.json b/main/search.json
index 064c0338e..b0a46413b 100644
--- a/main/search.json
+++ b/main/search.json
@@ -1 +1 @@
-[{"path":[]},{"path":"https://insightsengineering.github.io/rtables/CODE_OF_CONDUCT.html","id":"our-pledge","dir":"","previous_headings":"","what":"Our Pledge","title":"Contributor Covenant Code of Conduct","text":"interest fostering open welcoming environment, contributors maintainers pledge making participation project community harassment-free experience everyone, regardless age, body size, disability, ethnicity, sex characteristics, gender identity expression, level experience, education, socio-economic status, nationality, personal appearance, race, religion, sexual identity orientation.","code":""},{"path":"https://insightsengineering.github.io/rtables/CODE_OF_CONDUCT.html","id":"our-standards","dir":"","previous_headings":"","what":"Our Standards","title":"Contributor Covenant Code of Conduct","text":"Examples behavior contributes creating positive environment include: Using welcoming inclusive language respectful differing viewpoints experiences Gracefully accepting constructive criticism Focusing best community Showing empathy towards community members Examples unacceptable behavior participants include: use sexualized language imagery unwelcome sexual attention advances Trolling, insulting/derogatory comments, personal political attacks Public private harassment Publishing others’ private information, physical electronic address, without explicit permission conduct reasonably considered inappropriate professional setting","code":""},{"path":"https://insightsengineering.github.io/rtables/CODE_OF_CONDUCT.html","id":"our-responsibilities","dir":"","previous_headings":"","what":"Our Responsibilities","title":"Contributor Covenant Code of Conduct","text":"Project maintainers responsible clarifying standards acceptable behavior expected take appropriate fair corrective action response instances unacceptable behavior. Project maintainers right responsibility remove, edit, reject comments, commits, code, wiki edits, issues, contributions aligned Code Conduct, ban temporarily permanently contributor behaviors deem inappropriate, threatening, offensive, harmful.","code":""},{"path":"https://insightsengineering.github.io/rtables/CODE_OF_CONDUCT.html","id":"scope","dir":"","previous_headings":"","what":"Scope","title":"Contributor Covenant Code of Conduct","text":"Code Conduct applies within project spaces public spaces individual representing project community. Examples representing project community include using official project e-mail address, posting via official social media account, acting appointed representative online offline event. Representation project may defined clarified project maintainers.","code":""},{"path":"https://insightsengineering.github.io/rtables/CODE_OF_CONDUCT.html","id":"enforcement","dir":"","previous_headings":"","what":"Enforcement","title":"Contributor Covenant Code of Conduct","text":"Instances abusive, harassing, otherwise unacceptable behavior may reported contacting project team support@github.com. complaints reviewed investigated result response deemed necessary appropriate circumstances. project team obligated maintain confidentiality regard reporter incident. details specific enforcement policies may posted separately. Project maintainers follow enforce Code Conduct good faith may face temporary permanent repercussions determined members project’s leadership.","code":""},{"path":"https://insightsengineering.github.io/rtables/CODE_OF_CONDUCT.html","id":"attribution","dir":"","previous_headings":"","what":"Attribution","title":"Contributor Covenant Code of Conduct","text":"Code Conduct adapted Contributor Covenant, version 1.4, available https://www.contributor-covenant.org/version/1/4/code--conduct.html answers common questions code conduct, see https://www.contributor-covenant.org/faq","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":null,"dir":"","previous_headings":"","what":"Contributing to {rtables}","title":"Contributing to {rtables}","text":"welcome contributions big small ongoing development {rtables} package. , best way contribute package filing issues feature requests bugs encountered. interested contributing code package, contributions can made working current issues opening pull requests code changes. help able provide greatly appreciated! Contributions project released public project’s open source license.","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"filing-issues","dir":"","previous_headings":"","what":"Filing Issues","title":"Contributing to {rtables}","text":"Issues used establish prioritized timeline track development progress within package. new feature feel enhance experience package users, please open Feature Request issue. notice bug existing code, please file Bug Fix issue description bug reprex (reproducible example). types issues (questions, typos ’ve noticed, improvements documentation, etc.) can filed well. Click file new issue, see list current issues. Please utilize labels wherever possible creating issues organization purposes narrow scope work required.","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"creating-pull-requests","dir":"","previous_headings":"","what":"Creating Pull Requests","title":"Contributing to {rtables}","text":"Development {rtables} package relies Issue → Branch → PR → Code Review → Merge pipeline facilitated GitHub. experienced programmer interested contributing package code, please begin filing issue describing changes like make. may case idea already implemented way, package maintainers can help determine whether feature necessary begin development. Whether opening issue pull request, detailed description, easier package maintainers help ! make code changes package, please follow following process.","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"pull-request-process","dir":"","previous_headings":"Creating Pull Requests","what":"Pull Request Process","title":"Contributing to {rtables}","text":"{rtables} package part NEST project utilizes staged.dependencies ensure simplify development process track upstream downstream package dependencies. highly recommend installing using package developing within {rtables}.","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"id_1-create-a-branch","dir":"","previous_headings":"Creating Pull Requests > Pull Request Process","what":"1. Create a branch","title":"Contributing to {rtables}","text":"order work new pull request, please first create branch main upon can work commit changes. comply staged.dependencies standards, {rtables} uses following branch naming convention: issue#_description_of_issue@target_merge_branch example, 443_refactor_splits@main. cases, target merge branch base (main) branch. cases, change {rtables} may first require upstream changes {formatters} package. Suppose branch 100_update_fmts@main {formatters} containing required upstream changes. branch created {rtables} named follows example: 443_refactor_splits@100_update_fmts@main. ensures correct branches checked running tests, etc. details staged.dependencies branch naming conventions, click .","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"id_2-code","dir":"","previous_headings":"Creating Pull Requests > Pull Request Process","what":"2. Code","title":"Contributing to {rtables}","text":"Work within {rtables} package apply code changes. Avoid combining issues single branch - ideally, branch associated single issue prefixed issue number. information basics {rtables} package, please read package vignettes, available . advanced development work within {rtables}, consider reading {rtables} Developer Guide. Developer Guide can accessed {rtables} site navigation bar, listed convenience: Developer Guide: Split Machinery Developer Guide: Tabulation Developer Guide: Debugging {rtables} Beyond Developer Guide: Sparse Notes {rtables} Internals","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"code-style","dir":"","previous_headings":"Creating Pull Requests > Pull Request Process > 2. Code","what":"Code style","title":"Contributing to {rtables}","text":"{rtables} package follows tidyverse style guide please adhere guidelines submitted code. making changes file within package, can apply package styler automatically check lint running following two lines code within file:","code":"styler:::style_active_file() lintr:::addin_lint()"},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"documentation","dir":"","previous_headings":"Creating Pull Requests > Pull Request Process > 2. Code","what":"Documentation","title":"Contributing to {rtables}","text":"Package documentation uses roxygen2. contribution requires updates documentation, ensure roxygen comments updated within source code file. updating roxygen documentation, run devtools::document() update accompanying .Rd files (update files hand!).","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"tests","dir":"","previous_headings":"Creating Pull Requests > Pull Request Process > 2. Code","what":"Tests","title":"Contributing to {rtables}","text":"ensure high code coverage, create tests using testthat package. cases, changes package code necessitate addition one tests ensure added features working expected existing features broken.","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"news","dir":"","previous_headings":"Creating Pull Requests > Pull Request Process > 2. Code","what":"NEWS","title":"Contributing to {rtables}","text":"making updates package, please add descriptive entry NEWS file reflects changes. See tidyverse style guide guidelines creating NEWS entry.","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"id_3-make-a-pull-request","dir":"","previous_headings":"Creating Pull Requests > Pull Request Process","what":"3. Make a Pull Request","title":"Contributing to {rtables}","text":"previous two steps complete, can create pull request. Indicate description issue addressed pull request, utilize labels help reviewers identify category changes contained within pull request. pull request created, series checks automatically triggered, including R CMD check, tests/code coverage, auto-documentation, . checks must passing order eventually merge pull request, changes may required order resolve status checks. pull requests must also reviewed approved least one package maintainers can merged. review automatically requested several {rtables} maintainers upon creating pull request. maintainer reviews pull request, please try address comments short order - {rtables} package updated regular basis leaving pull request open long likely result merge conflicts create work developer.","code":""},{"path":"https://insightsengineering.github.io/rtables/CONTRIBUTING.html","id":"code-of-conduct","dir":"","previous_headings":"","what":"Code of Conduct","title":"Contributing to {rtables}","text":"Please note project released Contributor Code Conduct. participating project agree abide terms.","code":""},{"path":"https://insightsengineering.github.io/rtables/ISSUE_TEMPLATE.html","id":null,"dir":"","previous_headings":"","what":"Reporting an Issue with rtables","title":"Reporting an Issue with rtables","text":"use form ask question, ask assistance. Instead, ask Stackoverflow using nest-rtables tag. Questions function’s use closed without response. Please briefly describe problem , relevant, output expect. Please also provide output utils::sessionInfo() devtools::session_info() end post. possible, please include minimal, reproducible example. rtables team much likely resolve issue able reproduce locally. Please delete preamble read . brief description problem","code":"library(rtables) # your reproducible example here"},{"path":"https://insightsengineering.github.io/rtables/articles/advanced_usage.html","id":"note","dir":"Articles","previous_headings":"","what":"NOTE","title":"{rtables} Advanced Usage","text":"vignette currently development. code prose appears version vignette main branch repository work/correct, likely final form. Initialization","code":"library(rtables)"},{"path":"https://insightsengineering.github.io/rtables/articles/advanced_usage.html","id":"control-splitting-with-provided-function-limited-customization","dir":"Articles","previous_headings":"","what":"Control splitting with provided function (limited customization)","title":"{rtables} Advanced Usage","text":"rtables provides array functions control splitting logic without creating entirely new split functions. default split_*_by facets data based categorical variable. continuous variables, split_*_by_cutfun can leveraged create categories corresponding faceting, break points dependent data. Alternatively, split_*_by_cuts can used breakpoints predefined split_*_by_quartiles data faceted quantile.","code":"d1 <- subset(ex_adsl, AGE < 25) d1$AGE <- as.factor(d1$AGE) lyt1 <- basic_table() %>% split_cols_by(\"AGE\") %>% analyze(\"SEX\") build_table(lyt1, d1) ## 20 21 23 24 ## ———————————————————————————————————— ## F 0 2 4 5 ## M 1 1 2 3 ## U 0 0 0 0 ## UNDIFFERENTIATED 0 0 0 0 sd_cutfun <- function(x) { cutpoints <- c( min(x), mean(x) - sd(x), mean(x) + sd(x), max(x) ) names(cutpoints) <- c(\"\", \"Low\", \"Medium\", \"High\") cutpoints } lyt1 <- basic_table() %>% split_cols_by_cutfun(\"AGE\", cutfun = sd_cutfun) %>% analyze(\"SEX\") build_table(lyt1, ex_adsl) ## Low Medium High ## —————————————————————————————————————— ## F 36 165 21 ## M 21 115 30 ## U 1 8 0 ## UNDIFFERENTIATED 0 1 2 lyt1 <- basic_table() %>% split_cols_by_cuts( \"AGE\", cuts = c(0, 30, 60, 100), cutlabels = c(\"0-30 y.o.\", \"30-60 y.o.\", \"60-100 y.o.\") ) %>% analyze(\"SEX\") build_table(lyt1, ex_adsl) ## 0-30 y.o. 30-60 y.o. 60-100 y.o. ## ——————————————————————————————————————————————————————— ## F 71 150 1 ## M 48 116 2 ## U 2 7 0 ## UNDIFFERENTIATED 1 2 0"},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/articles/advanced_usage.html","id":"adding-an-overall-column-only-when-the-split-would-already-define-2-facets","dir":"Articles","previous_headings":"Custom Split Functions","what":"Adding an Overall Column Only When The Split Would Already Define 2+ Facets","title":"{rtables} Advanced Usage","text":"custom split functions can anything, including conditionally applying one existing custom split functions. define function constructor accepts variable name want check, return custom split function behavior want using functions provided rtables cases: gives us desired behavior one column corner case: standard multi-column case: Notice use add_overall_level function constructor, immediately call constructed function --one-columns case.","code":"picky_splitter <- function(var) { function(df, spl, vals, labels, trim) { orig_vals <- vals if (is.null(vals)) { vec <- df[[var]] vals <- if (is.factor(vec)) levels(vec) else unique(vec) } if (length(vals) == 1) { do_base_split(spl = spl, df = df, vals = vals, labels = labels, trim = trim) } else { add_overall_level( \"Overall\", label = \"All Obs\", first = FALSE )(df = df, spl = spl, vals = orig_vals, trim = trim) } } } d1 <- subset(ex_adsl, ARM == \"A: Drug X\") d1$ARM <- factor(d1$ARM) lyt1 <- basic_table() %>% split_cols_by(\"ARM\", split_fun = picky_splitter(\"ARM\")) %>% analyze(\"AGE\") build_table(lyt1, d1) ## A: Drug X ## ———————————————— ## Mean 33.77 build_table(lyt1, ex_adsl) ## A: Drug X B: Placebo C: Combination All Obs ## ———————————————————————————————————————————————————————— ## Mean 33.77 35.43 35.43 34.88"},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/articles/advanced_usage.html","id":"what-is--spl_context","dir":"Articles","previous_headings":"Leveraging .spl_context","what":"What Is .spl_context?","title":"{rtables} Advanced Usage","text":".spl_context (see ?spl_context) mechanism rtables tabulation machinery gives custom split, analysis content (row-group summary) functions information overarching facet-structure splits cells generate reside . particular .spl_context ensures functions know (thus computations based ) following types information:","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/advanced_usage.html","id":"different-formats-for-different-values-within-a-row-split","dir":"Articles","previous_headings":"Leveraging .spl_context","what":"Different Formats For Different Values Within A Row-Split","title":"{rtables} Advanced Usage","text":"","code":"dta_test <- data.frame( USUBJID = rep(1:6, each = 3), PARAMCD = rep(\"lab\", 6 * 3), AVISIT = rep(paste0(\"V\", 1:3), 6), ARM = rep(LETTERS[1:3], rep(6, 3)), AVAL = c(9:1, rep(NA, 9)), CHG = c(1:9, rep(NA, 9)) ) my_afun <- function(x, .spl_context) { n <- sum(!is.na(x)) meanval <- mean(x, na.rm = TRUE) sdval <- sd(x, na.rm = TRUE) ## get the split value of the most recent parent ## (row) split above this analyze val <- .spl_context[nrow(.spl_context), \"value\"] ## do a silly thing to decide the different format precisiosn ## your real logic would go here valnum <- min(2L, as.integer(gsub(\"[^[:digit:]]*\", \"\", val))) fstringpt <- paste0(\"xx.\", strrep(\"x\", valnum)) fmt_mnsd <- sprintf(\"%s (%s)\", fstringpt, fstringpt) in_rows( n = n, \"Mean, SD\" = c(meanval, sdval), .formats = c(n = \"xx\", \"Mean, SD\" = fmt_mnsd) ) } lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"AVISIT\") %>% split_cols_by_multivar(vars = c(\"AVAL\", \"CHG\")) %>% analyze_colvars(my_afun) build_table(lyt, dta_test) ## A B C ## AVAL CHG AVAL CHG AVAL CHG ## ——————————————————————————————————————————————————————————————————————————— ## V1 ## n 2 2 1 1 0 0 ## Mean, SD 7.5 (2.1) 2.5 (2.1) 3.0 (NA) 7.0 (NA) NA NA ## V2 ## n 2 2 1 1 0 0 ## Mean, SD 6.50 (2.12) 3.50 (2.12) 2.00 (NA) 8.00 (NA) NA NA ## V3 ## n 2 2 1 1 0 0 ## Mean, SD 5.50 (2.12) 4.50 (2.12) 1.00 (NA) 9.00 (NA) NA NA"},{"path":"https://insightsengineering.github.io/rtables/articles/advanced_usage.html","id":"simulating-baseline-comparison-in-row-space","dir":"Articles","previous_headings":"Leveraging .spl_context","what":"Simulating ‘Baseline Comparison’ In Row Space","title":"{rtables} Advanced Usage","text":"can simulate formal modeling reference row(s) using extra_args machinery","code":"my_afun <- function(x, .var, .spl_context) { n <- sum(!is.na(x)) meanval <- mean(x, na.rm = TRUE) sdval <- sd(x, na.rm = TRUE) ## get the split value of the most recent parent ## (row) split above this analyze val <- .spl_context[nrow(.spl_context), \"value\"] ## we show it if its not a CHG within V1 show_it <- val != \"V1\" || .var != \"CHG\" ## do a silly thing to decide the different format precisiosn ## your real logic would go here valnum <- min(2L, as.integer(gsub(\"[^[:digit:]]*\", \"\", val))) fstringpt <- paste0(\"xx.\", strrep(\"x\", valnum)) fmt_mnsd <- if (show_it) sprintf(\"%s (%s)\", fstringpt, fstringpt) else \"xx\" in_rows( n = if (show_it) n, ## NULL otherwise \"Mean, SD\" = if (show_it) c(meanval, sdval), ## NULL otherwise .formats = c(n = \"xx\", \"Mean, SD\" = fmt_mnsd) ) } lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"AVISIT\") %>% split_cols_by_multivar(vars = c(\"AVAL\", \"CHG\")) %>% analyze_colvars(my_afun) build_table(lyt, dta_test) ## A B C ## AVAL CHG AVAL CHG AVAL CHG ## ——————————————————————————————————————————————————————————————————————————— ## V1 ## n 2 1 0 ## Mean, SD 7.5 (2.1) 3.0 (NA) NA ## V2 ## n 2 2 1 1 0 0 ## Mean, SD 6.50 (2.12) 3.50 (2.12) 2.00 (NA) 8.00 (NA) NA NA ## V3 ## n 2 2 1 1 0 0 ## Mean, SD 5.50 (2.12) 4.50 (2.12) 1.00 (NA) 9.00 (NA) NA NA my_afun <- function(x, .var, ref_rowgroup, .spl_context) { n <- sum(!is.na(x)) meanval <- mean(x, na.rm = TRUE) sdval <- sd(x, na.rm = TRUE) ## get the split value of the most recent parent ## (row) split above this analyze val <- .spl_context[nrow(.spl_context), \"value\"] ## we show it if its not a CHG within V1 show_it <- val != ref_rowgroup || .var != \"CHG\" fmt_mnsd <- if (show_it) \"xx.x (xx.x)\" else \"xx\" in_rows( n = if (show_it) n, ## NULL otherwise \"Mean, SD\" = if (show_it) c(meanval, sdval), ## NULL otherwise .formats = c(n = \"xx\", \"Mean, SD\" = fmt_mnsd) ) } lyt2 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"AVISIT\") %>% split_cols_by_multivar(vars = c(\"AVAL\", \"CHG\")) %>% analyze_colvars(my_afun, extra_args = list(ref_rowgroup = \"V1\")) build_table(lyt2, dta_test) ## A B C ## AVAL CHG AVAL CHG AVAL CHG ## ————————————————————————————————————————————————————————————————————— ## V1 ## n 2 1 0 ## Mean, SD 7.5 (2.1) 3.0 (NA) NA ## V2 ## n 2 2 1 1 0 0 ## Mean, SD 6.5 (2.1) 3.5 (2.1) 2.0 (NA) 8.0 (NA) NA NA ## V3 ## n 2 2 1 1 0 0 ## Mean, SD 5.5 (2.1) 4.5 (2.1) 1.0 (NA) 9.0 (NA) NA NA"},{"path":"https://insightsengineering.github.io/rtables/articles/ard_how_to.html","id":"disclaimer","dir":"Articles","previous_headings":"","what":"Disclaimer","title":"Generating QC-Ready Result Data Frames (ARDs) from Tables","text":"vignette work progress subject change.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/ard_how_to.html","id":"creating-an-example-table","dir":"Articles","previous_headings":"Disclaimer","what":"Creating an Example Table","title":"Generating QC-Ready Result Data Frames (ARDs) from Tables","text":"order generate ARD (Analysis Results Dataset), first need create table necessary information retrieved. borrow simple table vignette clinical trials.","code":"library(rtables) # Loading required package: formatters # # Attaching package: 'formatters' # The following object is masked from 'package:base': # # %||% # Loading required package: magrittr # # Attaching package: 'rtables' # The following object is masked from 'package:utils': # # str ADSL <- ex_adsl # Example ADSL dataset # Very simple table lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(c(\"AGE\", \"SEX\")) tbl <- build_table(lyt, ADSL) tbl # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————— # AGE # Mean 33.77 35.43 35.43 # SEX # F 79 77 66 # M 51 55 60 # U 3 2 4 # UNDIFFERENTIATED 1 0 2"},{"path":"https://insightsengineering.github.io/rtables/articles/ard_how_to.html","id":"converting-the-table-to-a-result-data-frame-ard","dir":"Articles","previous_headings":"Disclaimer","what":"Converting the Table to a Result Data Frame (ARD)","title":"Generating QC-Ready Result Data Frames (ARDs) from Tables","text":"as_result_df() function used convert table result data frame. result data frame data frame contains result summary table ready used quality control purposes. may customized according different standards. Let’s see can produce different result data.frames. following outputs can returned setting different parameters as_results_df() function, results can transformed back table using df_to_tt() function. Now let’s generate final ARD output, ready used quality control purposes.","code":"as_result_df(tbl) # group1 group1_level avar_name row_name # 1 ma_AGE_SEX AGE Mean # 2 ma_AGE_SEX SEX F # 3 ma_AGE_SEX SEX M # 4 ma_AGE_SEX SEX U # 5 ma_AGE_SEX SEX UNDIFFERENTIATED # label_name row_num is_group_summary node_class A: Drug X B: Placebo # 1 Mean 2 FALSE DataRow 33.76866 35.43284 # 2 F 4 FALSE DataRow 79 77 # 3 M 5 FALSE DataRow 51 55 # 4 U 6 FALSE DataRow 3 2 # 5 UNDIFFERENTIATED 7 FALSE DataRow 1 0 # C: Combination # 1 35.43182 # 2 66 # 3 60 # 4 4 # 5 2 as_result_df(tbl, data_format = \"strings\") # group1 group1_level avar_name row_name # 1 ma_AGE_SEX AGE Mean # 2 ma_AGE_SEX SEX F # 3 ma_AGE_SEX SEX M # 4 ma_AGE_SEX SEX U # 5 ma_AGE_SEX SEX UNDIFFERENTIATED # label_name row_num is_group_summary node_class A: Drug X B: Placebo # 1 Mean 2 FALSE DataRow 33.77 35.43 # 2 F 4 FALSE DataRow 79 77 # 3 M 5 FALSE DataRow 51 55 # 4 U 6 FALSE DataRow 3 2 # 5 UNDIFFERENTIATED 7 FALSE DataRow 1 0 # C: Combination # 1 35.43 # 2 66 # 3 60 # 4 4 # 5 2 as_result_df(tbl, simplify = TRUE) # label_name A: Drug X B: Placebo C: Combination # 1 Mean 33.76866 35.43284 35.43182 # 2 F 79 77 66 # 3 M 51 55 60 # 4 U 3 2 4 # 5 UNDIFFERENTIATED 1 0 2 as_result_df(tbl, simplify = TRUE, keep_label_rows = TRUE) # label_name A: Drug X B: Placebo C: Combination # 1 AGE NA NA NA # 2 Mean 33.76866 35.43284 35.43182 # 3 SEX NA NA NA # 4 F 79 77 66 # 5 M 51 55 60 # 6 U 3 2 4 # 7 UNDIFFERENTIATED 1 0 2 as_result_df(tbl, simplify = TRUE, keep_label_rows = TRUE, expand_colnames = TRUE) # label_name A: Drug X B: Placebo C: Combination # 1 A: Drug X B: Placebo C: Combination # 2 AGE NA NA NA # 3 Mean 33.76866 35.43284 35.43182 # 4 SEX NA NA NA # 5 F 79 77 66 # 6 M 51 55 60 # 7 U 3 2 4 # 8 UNDIFFERENTIATED 1 0 2 as_result_df(tbl, make_ard = TRUE) # group1 group1_level group2 group2_level variable # 1 ma_AGE_SEX ARM A: Drug X AGE # 2 ma_AGE_SEX ARM A: Drug X SEX # 3 ma_AGE_SEX ARM A: Drug X SEX # 4 ma_AGE_SEX ARM A: Drug X SEX # 5 ma_AGE_SEX ARM A: Drug X SEX # 6 ma_AGE_SEX ARM B: Placebo AGE # 7 ma_AGE_SEX ARM B: Placebo SEX # 8 ma_AGE_SEX ARM B: Placebo SEX # 9 ma_AGE_SEX ARM B: Placebo SEX # 10 ma_AGE_SEX ARM B: Placebo SEX # 11 ma_AGE_SEX ARM C: Combination AGE # 12 ma_AGE_SEX ARM C: Combination SEX # 13 ma_AGE_SEX ARM C: Combination SEX # 14 ma_AGE_SEX ARM C: Combination SEX # 15 ma_AGE_SEX ARM C: Combination SEX # variable_level variable_label stat_name stat # 1 Mean Mean mean 33.76866 # 2 F F n 79.00000 # 3 M M n 51.00000 # 4 U U n 3.00000 # 5 UNDIFFERENTIATED UNDIFFERENTIATED n 1.00000 # 6 Mean Mean mean 35.43284 # 7 F F n 77.00000 # 8 M M n 55.00000 # 9 U U n 2.00000 # 10 UNDIFFERENTIATED UNDIFFERENTIATED n 0.00000 # 11 Mean Mean mean 35.43182 # 12 F F n 66.00000 # 13 M M n 60.00000 # 14 U U n 4.00000 # 15 UNDIFFERENTIATED UNDIFFERENTIATED n 2.00000"},{"path":"https://insightsengineering.github.io/rtables/articles/ard_how_to.html","id":"customizing-the-output","dir":"Articles","previous_headings":"Disclaimer","what":"Customizing the Output","title":"Generating QC-Ready Result Data Frames (ARDs) from Tables","text":"as_result_df() ARDs depend content table, possible modify table customize output. example, can add user-defined statistics custom names: Let’s put practice:","code":"# rcell and in_rows are the core of any analysis function rc <- rcell(c(1, 2), stat_names = c(\"Rand1\", \"Rand2\")) print(obj_stat_names(rc)) # c(\"Rand1\", \"Rand2\") # [1] \"Rand1\" \"Rand2\" rc_row <- in_rows( .list = list(a = c(NA, 1), b = c(1, NA)), .formats = c(\"xx - xx\", \"xx.x - xx.x\"), .format_na_strs = list(c(\"asda\", \"lkjklj\")), .stat_names = list(c(\"A\", \"B\"), c(\"B\", \"C\")) ) # Only a getter for this object print(obj_stat_names(rc_row)) # list(a = c(\"A\", \"B\"), b = c(\"B\", \"C\")) # $a # [1] \"A\" \"B\" # # $b # [1] \"B\" \"C\" # if c(\"A\", \"B\"), one for each row # if single list, duplicated rc_row <- in_rows( .list = list(a = c(NA, 1), b = c(1, NA)), .formats = c(\"xx - xx\", \"xx.x - xx.x\"), .format_na_strs = list(c(\"asda\", \"lkjklj\")), .stat_names = c(\"A\", \"B\") ) print(obj_stat_names(rc_row)) # c(\"A\", \"B\") # one for each row # $a # [1] \"A\" # # $b # [1] \"B\" print(lapply(rc_row, obj_stat_names)) # identical to above + row names # $a # [1] \"A\" # # $b # [1] \"B\" rc_row <- in_rows( .list = list(a = c(NA, 1), b = c(1, NA)), .formats = c(\"xx - xx\", \"xx.x - xx.x\"), .format_na_strs = list(c(\"asda\", \"lkjklj\")), .stat_names = list(c(\"A\", \"B\")) # It is duplicated, check it yourself! ) mean_sd_custom <- function(x) { mean <- mean(x, na.rm = FALSE) sd <- sd(x, na.rm = FALSE) rcell(c(mean, sd), label = \"Mean (SD)\", format = \"xx.x (xx.x)\" # , # stat_names = c(\"Mean\", \"SD\") ) } counts_percentage_custom <- function(x) { cnts <- table(x) out <- lapply(cnts, function(x) { perc <- x / sum(cnts) rcell(c(x, perc), format = \"xx. (xx.%)\") }) in_rows( .list = as.list(out), .labels = names(cnts), .stat_names = list(c(\"Count\", \"Percentage\")) ) } lyt <- basic_table(show_colcounts = TRUE, colcount_format = \"N=xx\") %>% split_cols_by(\"ARM\", split_fun = keep_split_levels(c(\"A: Drug X\", \"B: Placebo\"))) %>% analyze(vars = \"AGE\", afun = mean_sd_custom) %>% analyze(vars = \"SEX\", afun = counts_percentage_custom) tbl <- build_table(lyt, ex_adsl) as_result_df(tbl, make_ard = TRUE) # group1 group1_level group2 group2_level variable # 1 ma_AGE_SEX ARM A: Drug X AGE # 2 ma_AGE_SEX ARM A: Drug X AGE # 3 ma_AGE_SEX ARM A: Drug X SEX # 4 ma_AGE_SEX ARM A: Drug X SEX # 5 ma_AGE_SEX ARM A: Drug X SEX # 6 ma_AGE_SEX ARM A: Drug X SEX # 7 ma_AGE_SEX ARM A: Drug X SEX # 8 ma_AGE_SEX ARM A: Drug X SEX # 9 ma_AGE_SEX ARM A: Drug X SEX # 10 ma_AGE_SEX ARM A: Drug X SEX # 11 ma_AGE_SEX ARM B: Placebo AGE # 12 ma_AGE_SEX ARM B: Placebo AGE # 13 ma_AGE_SEX ARM B: Placebo SEX # 14 ma_AGE_SEX ARM B: Placebo SEX # 15 ma_AGE_SEX ARM B: Placebo SEX # 16 ma_AGE_SEX ARM B: Placebo SEX # 17 ma_AGE_SEX ARM B: Placebo SEX # 18 ma_AGE_SEX ARM B: Placebo SEX # 19 ma_AGE_SEX ARM B: Placebo SEX # 20 ma_AGE_SEX ARM B: Placebo SEX # variable_level variable_label stat_name stat # 1 Mean (SD) Mean (SD) 33.768656716 # 2 Mean (SD) Mean (SD) 6.553325712 # 3 F F Count 79.000000000 # 4 F F Percentage 0.589552239 # 5 M M Count 51.000000000 # 6 M M Percentage 0.380597015 # 7 U U Count 3.000000000 # 8 U U Percentage 0.022388060 # 9 UNDIFFERENTIATED UNDIFFERENTIATED Count 1.000000000 # 10 UNDIFFERENTIATED UNDIFFERENTIATED Percentage 0.007462687 # 11 Mean (SD) Mean (SD) 35.432835821 # 12 Mean (SD) Mean (SD) 7.895413879 # 13 F F Count 77.000000000 # 14 F F Percentage 0.574626866 # 15 M M Count 55.000000000 # 16 M M Percentage 0.410447761 # 17 U U Count 2.000000000 # 18 U U Percentage 0.014925373 # 19 UNDIFFERENTIATED UNDIFFERENTIATED Count 0.000000000 # 20 UNDIFFERENTIATED UNDIFFERENTIATED Percentage 0.000000000"},{"path":"https://insightsengineering.github.io/rtables/articles/ard_how_to.html","id":"more-complex-outputs","dir":"Articles","previous_headings":"","what":"More Complex Outputs","title":"Generating QC-Ready Result Data Frames (ARDs) from Tables","text":"Let’s add hierarchical row column splits:","code":"lyt <- basic_table() %>% split_rows_by(\"STRATA2\") %>% summarize_row_groups() %>% split_cols_by(\"ARM\") %>% split_cols_by(\"STRATA1\") %>% analyze(c(\"AGE\", \"SEX\")) tbl <- build_table(lyt, ex_adsl) as_result_df(tbl, make_ard = TRUE) # group1 group1_level group2 group2_level group3 group3_level variable # 1 STRATA2 S1 ARM A: Drug X STRATA1 A STRATA2 # 2 STRATA2 S1 ARM A: Drug X STRATA1 A STRATA2 # 3 STRATA2 S1 ARM A: Drug X STRATA1 A AGE # 4 STRATA2 S1 ARM A: Drug X STRATA1 A SEX # 5 STRATA2 S1 ARM A: Drug X STRATA1 A SEX # 6 STRATA2 S1 ARM A: Drug X STRATA1 A SEX # 7 STRATA2 S1 ARM A: Drug X STRATA1 A SEX # 8 STRATA2 S2 ARM A: Drug X STRATA1 A STRATA2 # 9 STRATA2 S2 ARM A: Drug X STRATA1 A STRATA2 # 10 STRATA2 S2 ARM A: Drug X STRATA1 A AGE # 11 STRATA2 S2 ARM A: Drug X STRATA1 A SEX # 12 STRATA2 S2 ARM A: Drug X STRATA1 A SEX # 13 STRATA2 S2 ARM A: Drug X STRATA1 A SEX # 14 STRATA2 S2 ARM A: Drug X STRATA1 A SEX # 15 STRATA2 S1 ARM A: Drug X STRATA1 B STRATA2 # 16 STRATA2 S1 ARM A: Drug X STRATA1 B STRATA2 # 17 STRATA2 S1 ARM A: Drug X STRATA1 B AGE # 18 STRATA2 S1 ARM A: Drug X STRATA1 B SEX # 19 STRATA2 S1 ARM A: Drug X STRATA1 B SEX # 20 STRATA2 S1 ARM A: Drug X STRATA1 B SEX # 21 STRATA2 S1 ARM A: Drug X STRATA1 B SEX # 22 STRATA2 S2 ARM A: Drug X STRATA1 B STRATA2 # 23 STRATA2 S2 ARM A: Drug X STRATA1 B STRATA2 # 24 STRATA2 S2 ARM A: Drug X STRATA1 B AGE # 25 STRATA2 S2 ARM A: Drug X STRATA1 B SEX # 26 STRATA2 S2 ARM A: Drug X STRATA1 B SEX # 27 STRATA2 S2 ARM A: Drug X STRATA1 B SEX # 28 STRATA2 S2 ARM A: Drug X STRATA1 B SEX # 29 STRATA2 S1 ARM A: Drug X STRATA1 C STRATA2 # 30 STRATA2 S1 ARM A: Drug X STRATA1 C STRATA2 # 31 STRATA2 S1 ARM A: Drug X STRATA1 C AGE # 32 STRATA2 S1 ARM A: Drug X STRATA1 C SEX # 33 STRATA2 S1 ARM A: Drug X STRATA1 C SEX # 34 STRATA2 S1 ARM A: Drug X STRATA1 C SEX # 35 STRATA2 S1 ARM A: Drug X STRATA1 C SEX # 36 STRATA2 S2 ARM A: Drug X STRATA1 C STRATA2 # 37 STRATA2 S2 ARM A: Drug X STRATA1 C STRATA2 # 38 STRATA2 S2 ARM A: Drug X STRATA1 C AGE # 39 STRATA2 S2 ARM A: Drug X STRATA1 C SEX # 40 STRATA2 S2 ARM A: Drug X STRATA1 C SEX # 41 STRATA2 S2 ARM A: Drug X STRATA1 C SEX # 42 STRATA2 S2 ARM A: Drug X STRATA1 C SEX # 43 STRATA2 S1 ARM B: Placebo STRATA1 A STRATA2 # 44 STRATA2 S1 ARM B: Placebo STRATA1 A STRATA2 # 45 STRATA2 S1 ARM B: Placebo STRATA1 A AGE # 46 STRATA2 S1 ARM B: Placebo STRATA1 A SEX # 47 STRATA2 S1 ARM B: Placebo STRATA1 A SEX # 48 STRATA2 S1 ARM B: Placebo STRATA1 A SEX # 49 STRATA2 S1 ARM B: Placebo STRATA1 A SEX # 50 STRATA2 S2 ARM B: Placebo STRATA1 A STRATA2 # 51 STRATA2 S2 ARM B: Placebo STRATA1 A STRATA2 # 52 STRATA2 S2 ARM B: Placebo STRATA1 A AGE # 53 STRATA2 S2 ARM B: Placebo STRATA1 A SEX # 54 STRATA2 S2 ARM B: Placebo STRATA1 A SEX # 55 STRATA2 S2 ARM B: Placebo STRATA1 A SEX # 56 STRATA2 S2 ARM B: Placebo STRATA1 A SEX # 57 STRATA2 S1 ARM B: Placebo STRATA1 B STRATA2 # 58 STRATA2 S1 ARM B: Placebo STRATA1 B STRATA2 # 59 STRATA2 S1 ARM B: Placebo STRATA1 B AGE # 60 STRATA2 S1 ARM B: Placebo STRATA1 B SEX # 61 STRATA2 S1 ARM B: Placebo STRATA1 B SEX # 62 STRATA2 S1 ARM B: Placebo STRATA1 B SEX # 63 STRATA2 S1 ARM B: Placebo STRATA1 B SEX # 64 STRATA2 S2 ARM B: Placebo STRATA1 B STRATA2 # 65 STRATA2 S2 ARM B: Placebo STRATA1 B STRATA2 # 66 STRATA2 S2 ARM B: Placebo STRATA1 B AGE # 67 STRATA2 S2 ARM B: Placebo STRATA1 B SEX # 68 STRATA2 S2 ARM B: Placebo STRATA1 B SEX # 69 STRATA2 S2 ARM B: Placebo STRATA1 B SEX # 70 STRATA2 S2 ARM B: Placebo STRATA1 B SEX # 71 STRATA2 S1 ARM B: Placebo STRATA1 C STRATA2 # 72 STRATA2 S1 ARM B: Placebo STRATA1 C STRATA2 # 73 STRATA2 S1 ARM B: Placebo STRATA1 C AGE # 74 STRATA2 S1 ARM B: Placebo STRATA1 C SEX # 75 STRATA2 S1 ARM B: Placebo STRATA1 C SEX # 76 STRATA2 S1 ARM B: Placebo STRATA1 C SEX # 77 STRATA2 S1 ARM B: Placebo STRATA1 C SEX # 78 STRATA2 S2 ARM B: Placebo STRATA1 C STRATA2 # 79 STRATA2 S2 ARM B: Placebo STRATA1 C STRATA2 # 80 STRATA2 S2 ARM B: Placebo STRATA1 C AGE # 81 STRATA2 S2 ARM B: Placebo STRATA1 C SEX # 82 STRATA2 S2 ARM B: Placebo STRATA1 C SEX # 83 STRATA2 S2 ARM B: Placebo STRATA1 C SEX # 84 STRATA2 S2 ARM B: Placebo STRATA1 C SEX # 85 STRATA2 S1 ARM C: Combination STRATA1 A STRATA2 # 86 STRATA2 S1 ARM C: Combination STRATA1 A STRATA2 # 87 STRATA2 S1 ARM C: Combination STRATA1 A AGE # 88 STRATA2 S1 ARM C: Combination STRATA1 A SEX # 89 STRATA2 S1 ARM C: Combination STRATA1 A SEX # 90 STRATA2 S1 ARM C: Combination STRATA1 A SEX # 91 STRATA2 S1 ARM C: Combination STRATA1 A SEX # 92 STRATA2 S2 ARM C: Combination STRATA1 A STRATA2 # 93 STRATA2 S2 ARM C: Combination STRATA1 A STRATA2 # 94 STRATA2 S2 ARM C: Combination STRATA1 A AGE # 95 STRATA2 S2 ARM C: Combination STRATA1 A SEX # 96 STRATA2 S2 ARM C: Combination STRATA1 A SEX # 97 STRATA2 S2 ARM C: Combination STRATA1 A SEX # 98 STRATA2 S2 ARM C: Combination STRATA1 A SEX # 99 STRATA2 S1 ARM C: Combination STRATA1 B STRATA2 # 100 STRATA2 S1 ARM C: Combination STRATA1 B STRATA2 # 101 STRATA2 S1 ARM C: Combination STRATA1 B AGE # 102 STRATA2 S1 ARM C: Combination STRATA1 B SEX # 103 STRATA2 S1 ARM C: Combination STRATA1 B SEX # 104 STRATA2 S1 ARM C: Combination STRATA1 B SEX # 105 STRATA2 S1 ARM C: Combination STRATA1 B SEX # 106 STRATA2 S2 ARM C: Combination STRATA1 B STRATA2 # 107 STRATA2 S2 ARM C: Combination STRATA1 B STRATA2 # 108 STRATA2 S2 ARM C: Combination STRATA1 B AGE # 109 STRATA2 S2 ARM C: Combination STRATA1 B SEX # 110 STRATA2 S2 ARM C: Combination STRATA1 B SEX # 111 STRATA2 S2 ARM C: Combination STRATA1 B SEX # 112 STRATA2 S2 ARM C: Combination STRATA1 B SEX # 113 STRATA2 S1 ARM C: Combination STRATA1 C STRATA2 # 114 STRATA2 S1 ARM C: Combination STRATA1 C STRATA2 # 115 STRATA2 S1 ARM C: Combination STRATA1 C AGE # 116 STRATA2 S1 ARM C: Combination STRATA1 C SEX # 117 STRATA2 S1 ARM C: Combination STRATA1 C SEX # 118 STRATA2 S1 ARM C: Combination STRATA1 C SEX # 119 STRATA2 S1 ARM C: Combination STRATA1 C SEX # 120 STRATA2 S2 ARM C: Combination STRATA1 C STRATA2 # 121 STRATA2 S2 ARM C: Combination STRATA1 C STRATA2 # 122 STRATA2 S2 ARM C: Combination STRATA1 C AGE # 123 STRATA2 S2 ARM C: Combination STRATA1 C SEX # 124 STRATA2 S2 ARM C: Combination STRATA1 C SEX # 125 STRATA2 S2 ARM C: Combination STRATA1 C SEX # 126 STRATA2 S2 ARM C: Combination STRATA1 C SEX # variable_level variable_label stat_name stat # 1 S1 S1 n 18.0000000 # 2 S1 S1 p 0.4736842 # 3 Mean Mean mean 31.6111111 # 4 F F n 12.0000000 # 5 M M n 5.0000000 # 6 U U n 1.0000000 # 7 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 8 S2 S2 n 20.0000000 # 9 S2 S2 p 0.5263158 # 10 Mean Mean mean 34.4000000 # 11 F F n 9.0000000 # 12 M M n 11.0000000 # 13 U U n 0.0000000 # 14 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 15 S1 S1 n 28.0000000 # 16 S1 S1 p 0.5957447 # 17 Mean Mean mean 34.5714286 # 18 F F n 14.0000000 # 19 M M n 13.0000000 # 20 U U n 1.0000000 # 21 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 22 S2 S2 n 19.0000000 # 23 S2 S2 p 0.4042553 # 24 Mean Mean mean 32.7894737 # 25 F F n 11.0000000 # 26 M M n 8.0000000 # 27 U U n 0.0000000 # 28 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 29 S1 S1 n 27.0000000 # 30 S1 S1 p 0.5510204 # 31 Mean Mean mean 35.2592593 # 32 F F n 17.0000000 # 33 M M n 8.0000000 # 34 U U n 1.0000000 # 35 UNDIFFERENTIATED UNDIFFERENTIATED n 1.0000000 # 36 S2 S2 n 22.0000000 # 37 S2 S2 p 0.4489796 # 38 Mean Mean mean 32.9545455 # 39 F F n 16.0000000 # 40 M M n 6.0000000 # 41 U U n 0.0000000 # 42 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 43 S1 S1 n 22.0000000 # 44 S1 S1 p 0.5000000 # 45 Mean Mean mean 36.6818182 # 46 F F n 11.0000000 # 47 M M n 10.0000000 # 48 U U n 1.0000000 # 49 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 50 S2 S2 n 22.0000000 # 51 S2 S2 p 0.5000000 # 52 Mean Mean mean 33.5454545 # 53 F F n 13.0000000 # 54 M M n 9.0000000 # 55 U U n 0.0000000 # 56 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 57 S1 S1 n 19.0000000 # 58 S1 S1 p 0.4222222 # 59 Mean Mean mean 37.6842105 # 60 F F n 12.0000000 # 61 M M n 7.0000000 # 62 U U n 0.0000000 # 63 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 64 S2 S2 n 26.0000000 # 65 S2 S2 p 0.5777778 # 66 Mean Mean mean 34.7692308 # 67 F F n 15.0000000 # 68 M M n 10.0000000 # 69 U U n 1.0000000 # 70 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 71 S1 S1 n 26.0000000 # 72 S1 S1 p 0.5777778 # 73 Mean Mean mean 35.3846154 # 74 F F n 13.0000000 # 75 M M n 13.0000000 # 76 U U n 0.0000000 # 77 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 78 S2 S2 n 19.0000000 # 79 S2 S2 p 0.4222222 # 80 Mean Mean mean 34.8947368 # 81 F F n 13.0000000 # 82 M M n 6.0000000 # 83 U U n 0.0000000 # 84 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 85 S1 S1 n 14.0000000 # 86 S1 S1 p 0.3500000 # 87 Mean Mean mean 34.0000000 # 88 F F n 7.0000000 # 89 M M n 6.0000000 # 90 U U n 1.0000000 # 91 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 92 S2 S2 n 26.0000000 # 93 S2 S2 p 0.6500000 # 94 Mean Mean mean 34.3461538 # 95 F F n 11.0000000 # 96 M M n 14.0000000 # 97 U U n 0.0000000 # 98 UNDIFFERENTIATED UNDIFFERENTIATED n 1.0000000 # 99 S1 S1 n 18.0000000 # 100 S1 S1 p 0.4186047 # 101 Mean Mean mean 35.8333333 # 102 F F n 9.0000000 # 103 M M n 9.0000000 # 104 U U n 0.0000000 # 105 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 106 S2 S2 n 25.0000000 # 107 S2 S2 p 0.5813953 # 108 Mean Mean mean 36.6800000 # 109 F F n 12.0000000 # 110 M M n 12.0000000 # 111 U U n 1.0000000 # 112 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000 # 113 S1 S1 n 24.0000000 # 114 S1 S1 p 0.4897959 # 115 Mean Mean mean 36.5833333 # 116 F F n 14.0000000 # 117 M M n 8.0000000 # 118 U U n 1.0000000 # 119 UNDIFFERENTIATED UNDIFFERENTIATED n 1.0000000 # 120 S2 S2 n 25.0000000 # 121 S2 S2 p 0.5102041 # 122 Mean Mean mean 34.7200000 # 123 F F n 13.0000000 # 124 M M n 11.0000000 # 125 U U n 1.0000000 # 126 UNDIFFERENTIATED UNDIFFERENTIATED n 0.0000000"},{"path":"https://insightsengineering.github.io/rtables/articles/baseline.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Comparing Against Baselines or Control","text":"Often data one column considered reference/baseline/comparison group compared data columns. example, lets calculate average age: difference average AGE placebo arm arms: Note column order changed reference group displayed first column. cases want cells blank reference column, (e.g., “B: Placebo”) use non_ref_rcell() instead rcell(), pass .in_ref_col second argument: can see arguments available afun manual analyze().","code":"library(rtables) lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(\"AGE\") tbl <- build_table(lyt, DM) tbl # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————— # Mean 34.91 33.02 34.57 lyt2 <- basic_table() %>% split_cols_by(\"ARM\", ref_group = \"B: Placebo\") %>% analyze(\"AGE\", afun = function(x, .ref_group) { in_rows( \"Difference of Averages\" = rcell(mean(x) - mean(.ref_group), format = \"xx.xx\") ) }) tbl2 <- build_table(lyt2, DM) tbl2 # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————————— # Difference of Averages 1.89 0.00 1.55 lyt3 <- basic_table() %>% split_cols_by(\"ARM\", ref_group = \"B: Placebo\") %>% analyze( \"AGE\", afun = function(x, .ref_group, .in_ref_col) { in_rows( \"Difference of Averages\" = non_ref_rcell(mean(x) - mean(.ref_group), is_ref = .in_ref_col, format = \"xx.xx\") ) } ) tbl3 <- build_table(lyt3, DM) tbl3 # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————————— # Difference of Averages 1.89 1.55 lyt4 <- basic_table() %>% split_cols_by(\"ARM\", ref_group = \"B: Placebo\") %>% analyze( \"AGE\", afun = function(x, .ref_group, .in_ref_col) { in_rows( \"Difference of Averages\" = non_ref_rcell(mean(x) - mean(.ref_group), is_ref = .in_ref_col, format = \"xx.xx\"), \"another row\" = non_ref_rcell(\"aaa\", .in_ref_col) ) } ) tbl4 <- build_table(lyt4, DM) tbl4 # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————————— # Difference of Averages 1.89 1.55 # another row aaa aaa"},{"path":"https://insightsengineering.github.io/rtables/articles/baseline.html","id":"row-splitting","dir":"Articles","previous_headings":"","what":"Row Splitting","title":"Comparing Against Baselines or Control","text":"adding row-splitting reference data may represented column without row splitting. example: data assigned .ref_full full data reference column whereas data assigned .ref_group respects subsetting defined row-splitting hence subset argument x df afun.","code":"lyt5 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\", ref_group = \"B: Placebo\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels) %>% analyze(\"AGE\", afun = function(x, .ref_group, .ref_full, .in_ref_col) { in_rows( \"is reference (.in_ref_col)\" = rcell(.in_ref_col), \"ref cell N (.ref_group)\" = rcell(length(.ref_group)), \"ref column N (.ref_full)\" = rcell(length(.ref_full)) ) }) tbl5 <- build_table(lyt5, subset(DM, SEX %in% c(\"M\", \"F\"))) tbl5 # A: Drug X B: Placebo C: Combination # (N=121) (N=106) (N=129) # —————————————————————————————————————————————————————————————————————— # F # is reference (.in_ref_col) FALSE TRUE FALSE # ref cell N (.ref_group) 56 56 56 # ref column N (.ref_full) 106 106 106 # M # is reference (.in_ref_col) FALSE TRUE FALSE # ref cell N (.ref_group) 50 50 50 # ref column N (.ref_full) 106 106 106"},{"path":"https://insightsengineering.github.io/rtables/articles/clinical_trials.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Example Clinical Trials Tables","text":"vignette create demographic table adverse event table response table time--event analysis table using rtables layout facility. , demonstrate layout based tabulation framework can specify structure relations commonly found analyzing clinical trials data. Note data created using random number generators. ex_* data currently attached rtables package provided formatters package created using publicly available random.cdisc.data R package. packages used vignette :","code":"library(rtables) library(tibble) library(dplyr)"},{"path":"https://insightsengineering.github.io/rtables/articles/clinical_trials.html","id":"demographic-table","dir":"Articles","previous_headings":"","what":"Demographic Table","title":"Example Clinical Trials Tables","text":"Demographic tables summarize variables content different population subsets (encoded columns). One feature analyze() introduced previous vignette analysis function afun can specify multiple rows in_rows() function: Multiple variables can analyzed one analyze() call: Hence, afun can process different data vector types (.e. variables selected data) fairly close standard demographic table. function either creates count table number summary argument x factor numeric, respectively: Note use rcell wrap results order add formatting instructions rtables. can use s_summary outside context tabulation: can now create commonly used variant demographic table: Note analyze() can also called multiple times sequence: leads table identical summary_tbl: clinical trials analyses number patients per column often referred N (rather overall population outside clinical trials commonly referred N). Column Ns added setting show_colcounts argument basic_table() TRUE:","code":"ADSL <- ex_adsl # Example ADSL dataset lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(vars = \"AGE\", afun = function(x) { in_rows( \"Mean (sd)\" = rcell(c(mean(x), sd(x)), format = \"xx.xx (xx.xx)\"), \"Range\" = rcell(range(x), format = \"xx.xx - xx.xx\") ) }) tbl <- build_table(lyt, ADSL) tbl # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————— # Mean (sd) 33.77 (6.55) 35.43 (7.90) 35.43 (7.72) # Range 21.00 - 50.00 21.00 - 62.00 20.00 - 69.00 lyt2 <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(vars = c(\"AGE\", \"BMRKR1\"), afun = function(x) { in_rows( \"Mean (sd)\" = rcell(c(mean(x), sd(x)), format = \"xx.xx (xx.xx)\"), \"Range\" = rcell(range(x), format = \"xx.xx - xx.xx\") ) }) tbl2 <- build_table(lyt2, ADSL) tbl2 # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————— # AGE # Mean (sd) 33.77 (6.55) 35.43 (7.90) 35.43 (7.72) # Range 21.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # BMRKR1 # Mean (sd) 5.97 (3.55) 5.70 (3.31) 5.62 (3.49) # Range 0.41 - 17.67 0.65 - 14.24 0.17 - 21.39 s_summary <- function(x) { if (is.numeric(x)) { in_rows( \"n\" = rcell(sum(!is.na(x)), format = \"xx\"), \"Mean (sd)\" = rcell(c(mean(x, na.rm = TRUE), sd(x, na.rm = TRUE)), format = \"xx.xx (xx.xx)\"), \"IQR\" = rcell(IQR(x, na.rm = TRUE), format = \"xx.xx\"), \"min - max\" = rcell(range(x, na.rm = TRUE), format = \"xx.xx - xx.xx\") ) } else if (is.factor(x)) { vs <- as.list(table(x)) do.call(in_rows, lapply(vs, rcell, format = \"xx\")) } else { stop(\"type not supported\") } } s_summary(ADSL$AGE) # RowsVerticalSection (in_rows) object print method: # ---------------------------- # row_name formatted_cell indent_mod row_label # 1 n 400 0 n # 2 Mean (sd) 34.88 (7.44) 0 Mean (sd) # 3 IQR 10.00 0 IQR # 4 min - max 20.00 - 69.00 0 min - max s_summary(ADSL$SEX) # RowsVerticalSection (in_rows) object print method: # ---------------------------- # row_name formatted_cell indent_mod row_label # 1 F 222 0 F # 2 M 166 0 M # 3 U 9 0 U # 4 UNDIFFERENTIATED 3 0 UNDIFFERENTIATED summary_lyt <- basic_table() %>% split_cols_by(var = \"ARM\") %>% analyze(c(\"AGE\", \"SEX\"), afun = s_summary) summary_tbl <- build_table(summary_lyt, ADSL) summary_tbl # A: Drug X B: Placebo C: Combination # ——————————————————————————————————————————————————————————————————— # AGE # n 134 134 132 # Mean (sd) 33.77 (6.55) 35.43 (7.90) 35.43 (7.72) # IQR 11.00 10.00 10.00 # min - max 21.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # SEX # F 79 77 66 # M 51 55 60 # U 3 2 4 # UNDIFFERENTIATED 1 0 2 summary_lyt2 <- basic_table() %>% split_cols_by(var = \"ARM\") %>% analyze(\"AGE\", s_summary) %>% analyze(\"SEX\", s_summary) summary_tbl2 <- build_table(summary_lyt2, ADSL) summary_tbl2 # A: Drug X B: Placebo C: Combination # ——————————————————————————————————————————————————————————————————— # AGE # n 134 134 132 # Mean (sd) 33.77 (6.55) 35.43 (7.90) 35.43 (7.72) # IQR 11.00 10.00 10.00 # min - max 21.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # SEX # F 79 77 66 # M 51 55 60 # U 3 2 4 # UNDIFFERENTIATED 1 0 2 identical(summary_tbl, summary_tbl2) # [1] TRUE summary_lyt3 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARMCD\") %>% analyze(c(\"AGE\", \"SEX\"), s_summary) summary_tbl3 <- build_table(summary_lyt3, ADSL) summary_tbl3 # ARM A ARM B ARM C # (N=134) (N=134) (N=132) # —————————————————————————————————————————————————————————————————— # AGE # n 134 134 132 # Mean (sd) 33.77 (6.55) 35.43 (7.90) 35.43 (7.72) # IQR 11.00 10.00 10.00 # min - max 21.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # SEX # F 79 77 66 # M 51 55 60 # U 3 2 4 # UNDIFFERENTIATED 1 0 2"},{"path":"https://insightsengineering.github.io/rtables/articles/clinical_trials.html","id":"variations-on-the-demographic-table","dir":"Articles","previous_headings":"Demographic Table","what":"Variations on the Demographic Table","title":"Example Clinical Trials Tables","text":"now show couple variations demographic table developed . variations structure analysis, hence don’t require modification s_summary function. start standard table analyzing variables AGE BMRKR2 variables: Assume like analysis carried per gender encoded row space: now subset ADSL include males females analysis order reduce number rows table: Note UNDIFFERENTIATED U levels still show table. tabulation respects factor levels level order, exactly split table function . empty levels dropped rtables needs know splitting time via split_fun argument split_rows_by(). number predefined functions. example drop_split_levels() required drop empty levels splitting time. Splitting big topic eventually addressed specific package vignette. table labels M F descriptive. can add full labels follows: next table variation stratify gender AGE analysis. nested argument set FALSE analyze() call: split rows groups (Male Female ) one might want summarize groups: usually showing count column percentages. especially important missing data. example, create table add missing data AGE variable: easy see many females males arm n represents number non-missing data elements variables. Groups within rows defined splitting can summarized summarize_row_groups(), example: couple things note : Group summaries produce “content” rows. Visually, ’s impossible distinguish data rows content rows. difference justified (’s important design decision) paginate tables content rows default repeated group gets divided via pagination. Conceptually content rows summarize patient population analyzed hence often count & group percentages (default behavior summarize_row_groups()). can recreate default behavior (count percentage) defining cfun illustrative purposes results table : Note cfun, like afun (used analyze()), can operate either variables, passed via x argument, data.frames tibbles, passed via df argument (afun can optionally request df ). Unlike afun, cfun must accept labelstr second argument gives default group label (factor level splitting) hence modified:","code":"lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% analyze(c(\"AGE\", \"BMRKR2\"), s_summary) tbl <- build_table(lyt, ADSL) tbl # A: Drug X B: Placebo C: Combination # (N=134) (N=134) (N=132) # ———————————————————————————————————————————————————————————— # AGE # n 134 134 132 # Mean (sd) 33.77 (6.55) 35.43 (7.90) 35.43 (7.72) # IQR 11.00 10.00 10.00 # min - max 21.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # BMRKR2 # LOW 50 45 40 # MEDIUM 37 56 42 # HIGH 47 33 50 lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(c(\"AGE\", \"BMRKR2\"), s_summary) tbl <- build_table(lyt, ADSL) tbl # A: Drug X B: Placebo C: Combination # (N=134) (N=134) (N=132) # ————————————————————————————————————————————————————————————————— # F # AGE # n 79 77 66 # Mean (sd) 32.76 (6.09) 34.12 (7.06) 35.20 (7.43) # IQR 9.00 8.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 64.00 # BMRKR2 # LOW 26 21 26 # MEDIUM 21 38 17 # HIGH 32 18 23 # M # AGE # n 51 55 60 # Mean (sd) 35.57 (7.08) 37.44 (8.69) 35.38 (8.24) # IQR 11.00 9.00 11.00 # min - max 23.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # BMRKR2 # LOW 21 23 11 # MEDIUM 15 18 23 # HIGH 15 14 26 # U # AGE # n 3 2 4 # Mean (sd) 31.67 (3.21) 31.00 (5.66) 35.25 (3.10) # IQR 3.00 4.00 3.25 # min - max 28.00 - 34.00 27.00 - 35.00 31.00 - 38.00 # BMRKR2 # LOW 2 1 1 # MEDIUM 1 0 2 # HIGH 0 1 1 # UNDIFFERENTIATED # AGE # n 1 0 2 # Mean (sd) 28.00 (NA) NA 45.00 (1.41) # IQR 0.00 NA 1.00 # min - max 28.00 - 28.00 Inf - -Inf 44.00 - 46.00 # BMRKR2 # LOW 1 0 2 # MEDIUM 0 0 0 # HIGH 0 0 0 ADSL_M_F <- filter(ADSL, SEX %in% c(\"M\", \"F\")) lyt2 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(c(\"AGE\", \"BMRKR2\"), s_summary) tbl2 <- build_table(lyt2, ADSL_M_F) tbl2 # A: Drug X B: Placebo C: Combination # (N=130) (N=132) (N=126) # ————————————————————————————————————————————————————————————————— # F # AGE # n 79 77 66 # Mean (sd) 32.76 (6.09) 34.12 (7.06) 35.20 (7.43) # IQR 9.00 8.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 64.00 # BMRKR2 # LOW 26 21 26 # MEDIUM 21 38 17 # HIGH 32 18 23 # M # AGE # n 51 55 60 # Mean (sd) 35.57 (7.08) 37.44 (8.69) 35.38 (8.24) # IQR 11.00 9.00 11.00 # min - max 23.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # BMRKR2 # LOW 21 23 11 # MEDIUM 15 18 23 # HIGH 15 14 26 # U # AGE # n 0 0 0 # Mean (sd) NA NA NA # IQR NA NA NA # min - max Inf - -Inf Inf - -Inf Inf - -Inf # BMRKR2 # LOW 0 0 0 # MEDIUM 0 0 0 # HIGH 0 0 0 # UNDIFFERENTIATED # AGE # n 0 0 0 # Mean (sd) NA NA NA # IQR NA NA NA # min - max Inf - -Inf Inf - -Inf Inf - -Inf # BMRKR2 # LOW 0 0 0 # MEDIUM 0 0 0 # HIGH 0 0 0 lyt3 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels, child_labels = \"visible\") %>% analyze(c(\"AGE\", \"BMRKR2\"), s_summary) tbl3 <- build_table(lyt3, ADSL_M_F) tbl3 # A: Drug X B: Placebo C: Combination # (N=130) (N=132) (N=126) # —————————————————————————————————————————————————————————————— # F # AGE # n 79 77 66 # Mean (sd) 32.76 (6.09) 34.12 (7.06) 35.20 (7.43) # IQR 9.00 8.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 64.00 # BMRKR2 # LOW 26 21 26 # MEDIUM 21 38 17 # HIGH 32 18 23 # M # AGE # n 51 55 60 # Mean (sd) 35.57 (7.08) 37.44 (8.69) 35.38 (8.24) # IQR 11.00 9.00 11.00 # min - max 23.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # BMRKR2 # LOW 21 23 11 # MEDIUM 15 18 23 # HIGH 15 14 26 ADSL_M_F_l <- ADSL_M_F %>% mutate(lbl_sex = case_when( SEX == \"M\" ~ \"Male\", SEX == \"F\" ~ \"Female\", SEX == \"U\" ~ \"Unknown\", SEX == \"UNDIFFERENTIATED\" ~ \"Undifferentiated\" )) lyt4 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\", labels_var = \"lbl_sex\", split_fun = drop_split_levels, child_labels = \"visible\") %>% analyze(c(\"AGE\", \"BMRKR2\"), s_summary) tbl4 <- build_table(lyt4, ADSL_M_F_l) tbl4 # A: Drug X B: Placebo C: Combination # (N=130) (N=132) (N=126) # —————————————————————————————————————————————————————————————— # Female # AGE # n 79 77 66 # Mean (sd) 32.76 (6.09) 34.12 (7.06) 35.20 (7.43) # IQR 9.00 8.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 64.00 # BMRKR2 # LOW 26 21 26 # MEDIUM 21 38 17 # HIGH 32 18 23 # Male # AGE # n 51 55 60 # Mean (sd) 35.57 (7.08) 37.44 (8.69) 35.38 (8.24) # IQR 11.00 9.00 11.00 # min - max 23.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # BMRKR2 # LOW 21 23 11 # MEDIUM 15 18 23 # HIGH 15 14 26 lyt5 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\", labels_var = \"lbl_sex\", split_fun = drop_split_levels, child_labels = \"visible\") %>% analyze(\"AGE\", s_summary, show_labels = \"visible\") %>% analyze(\"BMRKR2\", s_summary, nested = FALSE, show_labels = \"visible\") tbl5 <- build_table(lyt5, ADSL_M_F_l) tbl5 # A: Drug X B: Placebo C: Combination # (N=130) (N=132) (N=126) # —————————————————————————————————————————————————————————————— # Female # AGE # n 79 77 66 # Mean (sd) 32.76 (6.09) 34.12 (7.06) 35.20 (7.43) # IQR 9.00 8.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 64.00 # Male # AGE # n 51 55 60 # Mean (sd) 35.57 (7.08) 37.44 (8.69) 35.38 (8.24) # IQR 11.00 9.00 11.00 # min - max 23.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # BMRKR2 # LOW 47 44 37 # MEDIUM 36 56 40 # HIGH 47 32 49 insert_NAs <- function(x) { x[sample(c(TRUE, FALSE), length(x), TRUE, prob = c(0.2, 0.8))] <- NA x } set.seed(1) ADSL_NA <- ADSL_M_F_l %>% mutate(AGE = insert_NAs(AGE)) lyt6 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by( \"SEX\", labels_var = \"lbl_sex\", split_fun = drop_split_levels, child_labels = \"visible\" ) %>% analyze(\"AGE\", s_summary) %>% analyze(\"BMRKR2\", s_summary, nested = FALSE, show_labels = \"visible\") tbl6 <- build_table(lyt6, filter(ADSL_NA, SEX %in% c(\"M\", \"F\"))) tbl6 # A: Drug X B: Placebo C: Combination # (N=130) (N=132) (N=126) # ———————————————————————————————————————————————————————————— # Female # n 65 61 54 # Mean (sd) 32.71 (6.07) 34.33 (7.31) 34.61 (6.78) # IQR 9.00 10.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 54.00 # Male # n 44 44 50 # Mean (sd) 35.66 (6.78) 36.93 (8.18) 35.64 (8.42) # IQR 10.50 8.25 10.75 # min - max 24.00 - 48.00 21.00 - 58.00 20.00 - 69.00 # BMRKR2 # LOW 47 44 37 # MEDIUM 36 56 40 # HIGH 47 32 49 lyt7 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\", labels_var = \"lbl_sex\", split_fun = drop_split_levels) %>% summarize_row_groups() %>% analyze(\"AGE\", s_summary) %>% analyze(\"BMRKR2\", afun = s_summary, nested = FALSE, show_labels = \"visible\") tbl7 <- build_table(lyt7, filter(ADSL_NA, SEX %in% c(\"M\", \"F\"))) tbl7 # A: Drug X B: Placebo C: Combination # (N=130) (N=132) (N=126) # ———————————————————————————————————————————————————————————— # Female 79 (60.8%) 77 (58.3%) 66 (52.4%) # n 65 61 54 # Mean (sd) 32.71 (6.07) 34.33 (7.31) 34.61 (6.78) # IQR 9.00 10.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 54.00 # Male 51 (39.2%) 55 (41.7%) 60 (47.6%) # n 44 44 50 # Mean (sd) 35.66 (6.78) 36.93 (8.18) 35.64 (8.42) # IQR 10.50 8.25 10.75 # min - max 24.00 - 48.00 21.00 - 58.00 20.00 - 69.00 # BMRKR2 # LOW 47 44 37 # MEDIUM 36 56 40 # HIGH 47 32 49 lyt8 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\", labels_var = \"lbl_sex\", split_fun = drop_split_levels) %>% summarize_row_groups(cfun = function(df, labelstr, .N_col, ...) { in_rows( rcell(nrow(df) * c(1, 1 / .N_col), format = \"xx (xx.xx%)\"), .labels = labelstr ) }) %>% analyze(\"AGE\", s_summary) %>% analyze(\"BEP01FL\", afun = s_summary, nested = FALSE, show_labels = \"visible\") tbl8 <- build_table(lyt8, filter(ADSL_NA, SEX %in% c(\"M\", \"F\"))) tbl8 # A: Drug X B: Placebo C: Combination # (N=130) (N=132) (N=126) # ———————————————————————————————————————————————————————————— # Female 79 (60.77%) 77 (58.33%) 66 (52.38%) # n 65 61 54 # Mean (sd) 32.71 (6.07) 34.33 (7.31) 34.61 (6.78) # IQR 9.00 10.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 54.00 # Male 51 (39.23%) 55 (41.67%) 60 (47.62%) # n 44 44 50 # Mean (sd) 35.66 (6.78) 36.93 (8.18) 35.64 (8.42) # IQR 10.50 8.25 10.75 # min - max 24.00 - 48.00 21.00 - 58.00 20.00 - 69.00 # BEP01FL # Y 67 63 65 # N 63 69 61 lyt9 <- basic_table() %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\", labels_var = \"lbl_sex\", split_fun = drop_split_levels, child_labels = \"hidden\") %>% summarize_row_groups(cfun = function(df, labelstr, .N_col, ...) { in_rows( rcell(nrow(df) * c(1, 1 / .N_col), format = \"xx (xx.xx%)\"), .labels = paste0(labelstr, \": count (perc.)\") ) }) %>% analyze(\"AGE\", s_summary) %>% analyze(\"BEP01FL\", s_summary, nested = FALSE, show_labels = \"visible\") tbl9 <- build_table(lyt9, filter(ADSL_NA, SEX %in% c(\"M\", \"F\"))) tbl9 # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————————————————— # Female: count (perc.) 79 (60.77%) 77 (58.33%) 66 (52.38%) # n 65 61 54 # Mean (sd) 32.71 (6.07) 34.33 (7.31) 34.61 (6.78) # IQR 9.00 10.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 54.00 # Male: count (perc.) 51 (39.23%) 55 (41.67%) 60 (47.62%) # n 44 44 50 # Mean (sd) 35.66 (6.78) 36.93 (8.18) 35.64 (8.42) # IQR 10.50 8.25 10.75 # min - max 24.00 - 48.00 21.00 - 58.00 20.00 - 69.00 # BEP01FL # Y 67 63 65 # N 63 69 61"},{"path":"https://insightsengineering.github.io/rtables/articles/clinical_trials.html","id":"using-layouts","dir":"Articles","previous_headings":"Demographic Table","what":"Using Layouts","title":"Example Clinical Trials Tables","text":"Layouts couple advantages tabulating tables directly: .e. separate analyses description actual data referencing variable names happens via strings (non-standard evaluation (NSE) needed, though arguably either feature shortcoming) layouts can reused example demonstrates reusability layouts: can now build table ADSL patients older 18:","code":"adsl_lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\") %>% analyze(c(\"AGE\", \"SEX\"), afun = s_summary) adsl_lyt # A Pre-data Table Layout # # Column-Split Structure: # ARM (lvls) # # Row-Split Structure: # AGE:SEX (** multivar analysis **) adsl_tbl <- build_table(adsl_lyt, ADSL) adsl_tbl # A: Drug X B: Placebo C: Combination # (N=134) (N=134) (N=132) # ——————————————————————————————————————————————————————————————————— # AGE # n 134 134 132 # Mean (sd) 33.77 (6.55) 35.43 (7.90) 35.43 (7.72) # IQR 11.00 10.00 10.00 # min - max 21.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # SEX # F 79 77 66 # M 51 55 60 # U 3 2 4 # UNDIFFERENTIATED 1 0 2 adsl_f_tbl <- build_table(lyt, ADSL %>% filter(AGE > 18)) # Warning in min(x): no non-missing arguments to min; returning Inf # Warning in max(x): no non-missing arguments to max; returning -Inf adsl_f_tbl # A: Drug X B: Placebo C: Combination # (N=134) (N=134) (N=132) # ————————————————————————————————————————————————————————————————— # F # AGE # n 79 77 66 # Mean (sd) 32.76 (6.09) 34.12 (7.06) 35.20 (7.43) # IQR 9.00 8.00 6.75 # min - max 21.00 - 47.00 23.00 - 58.00 21.00 - 64.00 # BMRKR2 # LOW 26 21 26 # MEDIUM 21 38 17 # HIGH 32 18 23 # M # AGE # n 51 55 60 # Mean (sd) 35.57 (7.08) 37.44 (8.69) 35.38 (8.24) # IQR 11.00 9.00 11.00 # min - max 23.00 - 50.00 21.00 - 62.00 20.00 - 69.00 # BMRKR2 # LOW 21 23 11 # MEDIUM 15 18 23 # HIGH 15 14 26 # U # AGE # n 3 2 4 # Mean (sd) 31.67 (3.21) 31.00 (5.66) 35.25 (3.10) # IQR 3.00 4.00 3.25 # min - max 28.00 - 34.00 27.00 - 35.00 31.00 - 38.00 # BMRKR2 # LOW 2 1 1 # MEDIUM 1 0 2 # HIGH 0 1 1 # UNDIFFERENTIATED # AGE # n 1 0 2 # Mean (sd) 28.00 (NA) NA 45.00 (1.41) # IQR 0.00 NA 1.00 # min - max 28.00 - 28.00 Inf - -Inf 44.00 - 46.00 # BMRKR2 # LOW 1 0 2 # MEDIUM 0 0 0 # HIGH 0 0 0"},{"path":"https://insightsengineering.github.io/rtables/articles/clinical_trials.html","id":"adverse-events","dir":"Articles","previous_headings":"","what":"Adverse Events","title":"Example Clinical Trials Tables","text":"number different adverse event tables. now present two tables show adverse events ID grade ID. time won’t use ADAE dataset random.cdisc.data rather generate dataset fly (see Adrian’s 2016 Phuse paper):","code":"set.seed(1) lookup <- tribble( ~AEDECOD, ~AEBODSYS, ~AETOXGR, \"HEADACHE\", \"NERVOUS SYSTEM DISORDERS\", \"5\", \"BACK PAIN\", \"MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS\", \"2\", \"GINGIVAL BLEEDING\", \"GASTROINTESTINAL DISORDERS\", \"1\", \"HYPOTENSION\", \"VASCULAR DISORDERS\", \"3\", \"FAECES SOFT\", \"GASTROINTESTINAL DISORDERS\", \"2\", \"ABDOMINAL DISCOMFORT\", \"GASTROINTESTINAL DISORDERS\", \"1\", \"DIARRHEA\", \"GASTROINTESTINAL DISORDERS\", \"1\", \"ABDOMINAL FULLNESS DUE TO GAS\", \"GASTROINTESTINAL DISORDERS\", \"1\", \"NAUSEA (INTERMITTENT)\", \"GASTROINTESTINAL DISORDERS\", \"2\", \"WEAKNESS\", \"MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS\", \"3\", \"ORTHOSTATIC HYPOTENSION\", \"VASCULAR DISORDERS\", \"4\" ) normalize <- function(x) x / sum(x) weightsA <- normalize(c(0.1, dlnorm(seq(0, 5, length.out = 25), meanlog = 3))) weightsB <- normalize(c(0.2, dlnorm(seq(0, 5, length.out = 25)))) N_pop <- 300 ADSL2 <- data.frame( USUBJID = seq(1, N_pop, by = 1), ARM = sample(c(\"ARM A\", \"ARM B\"), N_pop, TRUE), SEX = sample(c(\"F\", \"M\"), N_pop, TRUE), AGE = 20 + rbinom(N_pop, size = 40, prob = 0.7) ) l.adae <- mapply( ADSL2$USUBJID, ADSL2$ARM, ADSL2$SEX, ADSL2$AGE, FUN = function(id, arm, sex, age) { n_ae <- sample(0:25, 1, prob = if (arm == \"ARM A\") weightsA else weightsB) i <- sample(seq_len(nrow(lookup)), size = n_ae, replace = TRUE, prob = c(6, rep(1, 10)) / 16) lookup[i, ] %>% mutate( AESEQ = seq_len(n()), USUBJID = id, ARM = arm, SEX = sex, AGE = age ) }, SIMPLIFY = FALSE ) ADAE2 <- do.call(rbind, l.adae) ADAE2 <- ADAE2 %>% mutate( ARM = factor(ARM, levels = c(\"ARM A\", \"ARM B\")), AEDECOD = as.factor(AEDECOD), AEBODSYS = as.factor(AEBODSYS), AETOXGR = factor(AETOXGR, levels = as.character(1:5)) ) %>% select(USUBJID, ARM, AGE, SEX, AESEQ, AEDECOD, AEBODSYS, AETOXGR) ADAE2 # # A tibble: 3,118 × 8 # USUBJID ARM AGE SEX AESEQ AEDECOD AEBODSYS AETOXGR # # 1 1 ARM A 45 F 1 NAUSEA (INTERMITTENT) GASTROINTESTIN… 2 # 2 1 ARM A 45 F 2 HEADACHE NERVOUS SYSTEM… 5 # 3 1 ARM A 45 F 3 HEADACHE NERVOUS SYSTEM… 5 # 4 1 ARM A 45 F 4 HEADACHE NERVOUS SYSTEM… 5 # 5 1 ARM A 45 F 5 HEADACHE NERVOUS SYSTEM… 5 # 6 1 ARM A 45 F 6 HEADACHE NERVOUS SYSTEM… 5 # 7 1 ARM A 45 F 7 HEADACHE NERVOUS SYSTEM… 5 # 8 1 ARM A 45 F 8 HEADACHE NERVOUS SYSTEM… 5 # 9 1 ARM A 45 F 9 HEADACHE NERVOUS SYSTEM… 5 # 10 1 ARM A 45 F 10 FAECES SOFT GASTROINTESTIN… 2 # # ℹ 3,108 more rows"},{"path":"https://insightsengineering.github.io/rtables/articles/clinical_trials.html","id":"adverse-events-by-id","dir":"Articles","previous_headings":"Adverse Events","what":"Adverse Events By ID","title":"Example Clinical Trials Tables","text":"start defining events summary function: , population 5 patients one patient 2 AEs one patient 1 AE three patients AEs get following summary: .N_col argument special keyword argument build_table() passes population size respective column. list keyword arguments functions passed afun analyze(), refer documentation ?analyze. now use s_events_patients summary function tabulation: Note column Ns wrong default set number rows per group (.e. number AEs per arm ). also affects percentages. table interested number patients per column/arm usually taken ADSL (var ADSL2 ). rtables handles allowing us override column counts computed. can specify alt_counts_df build_table(). , rtables calculates column counts applying column faceting alt_counts_df primary data tabulation: Alternatively, desired column counts already calculated, can specified directly via col_counts argument build_table(), though specifying alt_counts_df preferred mechanism (number rows used, duplicate checking!!!). next calculate information per system organ class: now add count table AEDECOD AEBODSYS. default analyze() behavior factor create count table per level (using rtab_inner): indent_mod argument enables relative indenting changes tree structure table result desired indentation default. table far however usual adverse event table counts total number events number subjects one events particular term. get correct table need write custom analysis function: desired AE table : Note missing overall summary first two rows. can added initial analyze() call. Finally, wanted prune 0 count rows can trim_rows() function: Pruning larger topic separate rtables package vignette.","code":"s_events_patients <- function(x, labelstr, .N_col) { in_rows( \"Total number of patients with at least one event\" = rcell(length(unique(x)) * c(1, 1 / .N_col), format = \"xx (xx.xx%)\"), \"Total number of events\" = rcell(length(x), format = \"xx\") ) } s_events_patients(x = c(\"id 1\", \"id 1\", \"id 2\"), .N_col = 5) # RowsVerticalSection (in_rows) object print method: # ---------------------------- # row_name formatted_cell indent_mod # 1 Total number of patients with at least one event 2 (40.00%) 0 # 2 Total number of events 3 0 # row_label # 1 Total number of patients with at least one event # 2 Total number of events adae_lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\") %>% analyze(\"USUBJID\", s_events_patients) adae_tbl <- build_table(adae_lyt, ADAE2) adae_tbl # ARM A ARM B # (N=2060) (N=1058) # ————————————————————————————————————————————————————————————————————————————— # Total number of patients with at least one event 114 (5.53%) 150 (14.18%) # Total number of events 2060 1058 adae_adsl_tbl <- build_table(adae_lyt, ADAE2, alt_counts_df = ADSL2) adae_adsl_tbl # ARM A ARM B # (N=146) (N=154) # —————————————————————————————————————————————————————————————————————————————— # Total number of patients with at least one event 114 (78.08%) 150 (97.40%) # Total number of events 2060 1058 adae_soc_lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\") %>% analyze(\"USUBJID\", s_events_patients) %>% split_rows_by(\"AEBODSYS\", child_labels = \"visible\", nested = FALSE) %>% summarize_row_groups(\"USUBJID\", cfun = s_events_patients) adae_soc_tbl <- build_table(adae_soc_lyt, ADAE2, alt_counts_df = ADSL2) adae_soc_tbl # ARM A ARM B # (N=146) (N=154) # ———————————————————————————————————————————————————————————————————————————————— # Total number of patients with at least one event 114 (78.08%) 150 (97.40%) # Total number of events 2060 1058 # GASTROINTESTINAL DISORDERS # Total number of patients with at least one event 114 (78.08%) 130 (84.42%) # Total number of events 760 374 # MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS # Total number of patients with at least one event 98 (67.12%) 81 (52.60%) # Total number of events 273 142 # NERVOUS SYSTEM DISORDERS # Total number of patients with at least one event 113 (77.40%) 133 (86.36%) # Total number of events 787 420 # VASCULAR DISORDERS # Total number of patients with at least one event 93 (63.70%) 75 (48.70%) # Total number of events 240 122 adae_soc_lyt2 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"AEBODSYS\", child_labels = \"visible\", indent_mod = 1) %>% summarize_row_groups(\"USUBJID\", cfun = s_events_patients) %>% analyze(\"AEDECOD\", indent_mod = -1) adae_soc_tbl2 <- build_table(adae_soc_lyt2, ADAE2, alt_counts_df = ADSL2) adae_soc_tbl2 # ARM A ARM B # (N=146) (N=154) # —————————————————————————————————————————————————————————————————————————————————— # GASTROINTESTINAL DISORDERS # Total number of patients with at least one event 114 (78.08%) 130 (84.42%) # Total number of events 760 374 # ABDOMINAL DISCOMFORT 113 65 # ABDOMINAL FULLNESS DUE TO GAS 119 65 # BACK PAIN 0 0 # DIARRHEA 107 53 # FAECES SOFT 122 58 # GINGIVAL BLEEDING 147 71 # HEADACHE 0 0 # HYPOTENSION 0 0 # NAUSEA (INTERMITTENT) 152 62 # ORTHOSTATIC HYPOTENSION 0 0 # WEAKNESS 0 0 # MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS # Total number of patients with at least one event 98 (67.12%) 81 (52.60%) # Total number of events 273 142 # ABDOMINAL DISCOMFORT 0 0 # ABDOMINAL FULLNESS DUE TO GAS 0 0 # BACK PAIN 135 75 # DIARRHEA 0 0 # FAECES SOFT 0 0 # GINGIVAL BLEEDING 0 0 # HEADACHE 0 0 # HYPOTENSION 0 0 # NAUSEA (INTERMITTENT) 0 0 # ORTHOSTATIC HYPOTENSION 0 0 # WEAKNESS 138 67 # NERVOUS SYSTEM DISORDERS # Total number of patients with at least one event 113 (77.40%) 133 (86.36%) # Total number of events 787 420 # ABDOMINAL DISCOMFORT 0 0 # ABDOMINAL FULLNESS DUE TO GAS 0 0 # BACK PAIN 0 0 # DIARRHEA 0 0 # FAECES SOFT 0 0 # GINGIVAL BLEEDING 0 0 # HEADACHE 787 420 # HYPOTENSION 0 0 # NAUSEA (INTERMITTENT) 0 0 # ORTHOSTATIC HYPOTENSION 0 0 # WEAKNESS 0 0 # VASCULAR DISORDERS # Total number of patients with at least one event 93 (63.70%) 75 (48.70%) # Total number of events 240 122 # ABDOMINAL DISCOMFORT 0 0 # ABDOMINAL FULLNESS DUE TO GAS 0 0 # BACK PAIN 0 0 # DIARRHEA 0 0 # FAECES SOFT 0 0 # GINGIVAL BLEEDING 0 0 # HEADACHE 0 0 # HYPOTENSION 104 58 # NAUSEA (INTERMITTENT) 0 0 # ORTHOSTATIC HYPOTENSION 136 64 # WEAKNESS 0 0 table_count_once_per_id <- function(df, termvar = \"AEDECOD\", idvar = \"USUBJID\") { x <- df[[termvar]] id <- df[[idvar]] counts <- table(x[!duplicated(id)]) in_rows( .list = as.vector(counts), .labels = names(counts) ) } table_count_once_per_id(ADAE2) # RowsVerticalSection (in_rows) object print method: # ---------------------------- # row_name formatted_cell indent_mod # 1 ABDOMINAL DISCOMFORT 23 0 # 2 ABDOMINAL FULLNESS DUE TO GAS 21 0 # 3 BACK PAIN 20 0 # 4 DIARRHEA 7 0 # 5 FAECES SOFT 11 0 # 6 GINGIVAL BLEEDING 15 0 # 7 HEADACHE 100 0 # 8 HYPOTENSION 16 0 # 9 NAUSEA (INTERMITTENT) 21 0 # 10 ORTHOSTATIC HYPOTENSION 14 0 # 11 WEAKNESS 16 0 # row_label # 1 ABDOMINAL DISCOMFORT # 2 ABDOMINAL FULLNESS DUE TO GAS # 3 BACK PAIN # 4 DIARRHEA # 5 FAECES SOFT # 6 GINGIVAL BLEEDING # 7 HEADACHE # 8 HYPOTENSION # 9 NAUSEA (INTERMITTENT) # 10 ORTHOSTATIC HYPOTENSION # 11 WEAKNESS adae_soc_lyt3 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"AEBODSYS\", child_labels = \"visible\", indent_mod = 1) %>% summarize_row_groups(\"USUBJID\", cfun = s_events_patients) %>% analyze(\"AEDECOD\", afun = table_count_once_per_id, show_labels = \"hidden\", indent_mod = -1) adae_soc_tbl3 <- build_table(adae_soc_lyt3, ADAE2, alt_counts_df = ADSL2) adae_soc_tbl3 # ARM A ARM B # (N=146) (N=154) # —————————————————————————————————————————————————————————————————————————————————— # GASTROINTESTINAL DISORDERS # Total number of patients with at least one event 114 (78.08%) 130 (84.42%) # Total number of events 760 374 # ABDOMINAL DISCOMFORT 24 28 # ABDOMINAL FULLNESS DUE TO GAS 18 26 # BACK PAIN 0 0 # DIARRHEA 17 17 # FAECES SOFT 17 14 # GINGIVAL BLEEDING 18 25 # HEADACHE 0 0 # HYPOTENSION 0 0 # NAUSEA (INTERMITTENT) 20 20 # ORTHOSTATIC HYPOTENSION 0 0 # WEAKNESS 0 0 # MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS # Total number of patients with at least one event 98 (67.12%) 81 (52.60%) # Total number of events 273 142 # ABDOMINAL DISCOMFORT 0 0 # ABDOMINAL FULLNESS DUE TO GAS 0 0 # BACK PAIN 58 45 # DIARRHEA 0 0 # FAECES SOFT 0 0 # GINGIVAL BLEEDING 0 0 # HEADACHE 0 0 # HYPOTENSION 0 0 # NAUSEA (INTERMITTENT) 0 0 # ORTHOSTATIC HYPOTENSION 0 0 # WEAKNESS 40 36 # NERVOUS SYSTEM DISORDERS # Total number of patients with at least one event 113 (77.40%) 133 (86.36%) # Total number of events 787 420 # ABDOMINAL DISCOMFORT 0 0 # ABDOMINAL FULLNESS DUE TO GAS 0 0 # BACK PAIN 0 0 # DIARRHEA 0 0 # FAECES SOFT 0 0 # GINGIVAL BLEEDING 0 0 # HEADACHE 113 133 # HYPOTENSION 0 0 # NAUSEA (INTERMITTENT) 0 0 # ORTHOSTATIC HYPOTENSION 0 0 # WEAKNESS 0 0 # VASCULAR DISORDERS # Total number of patients with at least one event 93 (63.70%) 75 (48.70%) # Total number of events 240 122 # ABDOMINAL DISCOMFORT 0 0 # ABDOMINAL FULLNESS DUE TO GAS 0 0 # BACK PAIN 0 0 # DIARRHEA 0 0 # FAECES SOFT 0 0 # GINGIVAL BLEEDING 0 0 # HEADACHE 0 0 # HYPOTENSION 44 31 # NAUSEA (INTERMITTENT) 0 0 # ORTHOSTATIC HYPOTENSION 49 44 # WEAKNESS 0 0 adae_soc_lyt4 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\") %>% analyze(\"USUBJID\", afun = s_events_patients) %>% split_rows_by(\"AEBODSYS\", child_labels = \"visible\", indent_mod = 1, section_div = \"\") %>% summarize_row_groups(\"USUBJID\", cfun = s_events_patients) %>% analyze(\"AEDECOD\", table_count_once_per_id, show_labels = \"hidden\", indent_mod = -1) adae_soc_tbl4 <- build_table(adae_soc_lyt4, ADAE2, alt_counts_df = ADSL2) adae_soc_tbl4 # ARM A ARM B # (N=146) (N=154) # —————————————————————————————————————————————————————————————————————————————————— # Total number of patients with at least one event 114 (78.08%) 150 (97.40%) # Total number of events 2060 1058 # GASTROINTESTINAL DISORDERS # Total number of patients with at least one event 114 (78.08%) 130 (84.42%) # Total number of events 760 374 # ABDOMINAL DISCOMFORT 24 28 # ABDOMINAL FULLNESS DUE TO GAS 18 26 # BACK PAIN 0 0 # DIARRHEA 17 17 # FAECES SOFT 17 14 # GINGIVAL BLEEDING 18 25 # HEADACHE 0 0 # HYPOTENSION 0 0 # NAUSEA (INTERMITTENT) 20 20 # ORTHOSTATIC HYPOTENSION 0 0 # WEAKNESS 0 0 # # MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS # Total number of patients with at least one event 98 (67.12%) 81 (52.60%) # Total number of events 273 142 # ABDOMINAL DISCOMFORT 0 0 # ABDOMINAL FULLNESS DUE TO GAS 0 0 # BACK PAIN 58 45 # DIARRHEA 0 0 # FAECES SOFT 0 0 # GINGIVAL BLEEDING 0 0 # HEADACHE 0 0 # HYPOTENSION 0 0 # NAUSEA (INTERMITTENT) 0 0 # ORTHOSTATIC HYPOTENSION 0 0 # WEAKNESS 40 36 # # NERVOUS SYSTEM DISORDERS # Total number of patients with at least one event 113 (77.40%) 133 (86.36%) # Total number of events 787 420 # ABDOMINAL DISCOMFORT 0 0 # ABDOMINAL FULLNESS DUE TO GAS 0 0 # BACK PAIN 0 0 # DIARRHEA 0 0 # FAECES SOFT 0 0 # GINGIVAL BLEEDING 0 0 # HEADACHE 113 133 # HYPOTENSION 0 0 # NAUSEA (INTERMITTENT) 0 0 # ORTHOSTATIC HYPOTENSION 0 0 # WEAKNESS 0 0 # # VASCULAR DISORDERS # Total number of patients with at least one event 93 (63.70%) 75 (48.70%) # Total number of events 240 122 # ABDOMINAL DISCOMFORT 0 0 # ABDOMINAL FULLNESS DUE TO GAS 0 0 # BACK PAIN 0 0 # DIARRHEA 0 0 # FAECES SOFT 0 0 # GINGIVAL BLEEDING 0 0 # HEADACHE 0 0 # HYPOTENSION 44 31 # NAUSEA (INTERMITTENT) 0 0 # ORTHOSTATIC HYPOTENSION 49 44 # WEAKNESS 0 0 trim_rows(adae_soc_tbl4) # ARM A ARM B # (N=146) (N=154) # —————————————————————————————————————————————————————————————————————————————————— # Total number of patients with at least one event 114 (78.08%) 150 (97.40%) # Total number of events 2060 1058 # GASTROINTESTINAL DISORDERS # Total number of patients with at least one event 114 (78.08%) 130 (84.42%) # Total number of events 760 374 # ABDOMINAL DISCOMFORT 24 28 # ABDOMINAL FULLNESS DUE TO GAS 18 26 # DIARRHEA 17 17 # FAECES SOFT 17 14 # GINGIVAL BLEEDING 18 25 # NAUSEA (INTERMITTENT) 20 20 # # MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS # Total number of patients with at least one event 98 (67.12%) 81 (52.60%) # Total number of events 273 142 # BACK PAIN 58 45 # WEAKNESS 40 36 # # NERVOUS SYSTEM DISORDERS # Total number of patients with at least one event 113 (77.40%) 133 (86.36%) # Total number of events 787 420 # HEADACHE 113 133 # # VASCULAR DISORDERS # Total number of patients with at least one event 93 (63.70%) 75 (48.70%) # Total number of events 240 122 # HYPOTENSION 44 31 # ORTHOSTATIC HYPOTENSION 49 44"},{"path":"https://insightsengineering.github.io/rtables/articles/clinical_trials.html","id":"adverse-events-by-id-and-by-grade","dir":"Articles","previous_headings":"Adverse Events","what":"Adverse Events By ID and By Grade","title":"Example Clinical Trials Tables","text":"adverse events table ID grade shows many patients least one adverse event per grade different subsets data (e.g. defined system organ class). table show zero count grades. Note add “overall” groups custom split function. layouting concepts needed create table already introduced far:","code":"table_count_grade_once_per_id <- function(df, labelstr = \"\", gradevar = \"AETOXGR\", idvar = \"USUBJID\", grade_levels = NULL) { id <- df[[idvar]] grade <- df[[gradevar]] if (!is.null(grade_levels)) { stopifnot(all(grade %in% grade_levels)) grade <- factor(grade, levels = grade_levels) } id_sel <- !duplicated(id) in_rows( \"--Any Grade--\" = sum(id_sel), .list = as.list(table(grade[id_sel])) ) } table_count_grade_once_per_id(ex_adae, grade_levels = 1:5) # RowsVerticalSection (in_rows) object print method: # ---------------------------- # row_name formatted_cell indent_mod row_label # 1 --Any Grade-- 365 0 --Any Grade-- # 2 1 131 0 1 # 3 2 70 0 2 # 4 3 74 0 3 # 5 4 25 0 4 # 6 5 65 0 5 adae_grade_lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\") %>% analyze( \"AETOXGR\", afun = table_count_grade_once_per_id, extra_args = list(grade_levels = 1:5), var_labels = \"- Any adverse events -\", show_labels = \"visible\" ) %>% split_rows_by(\"AEBODSYS\", child_labels = \"visible\", indent_mod = 1) %>% summarize_row_groups(cfun = table_count_grade_once_per_id, format = \"xx\", indent_mod = 1) %>% split_rows_by(\"AEDECOD\", child_labels = \"visible\", indent_mod = -2) %>% analyze( \"AETOXGR\", afun = table_count_grade_once_per_id, extra_args = list(grade_levels = 1:5), show_labels = \"hidden\" ) adae_grade_tbl <- build_table(adae_grade_lyt, ADAE2, alt_counts_df = ADSL2) adae_grade_tbl # ARM A ARM B # (N=146) (N=154) # ————————————————————————————————————————————————————————————————————— # - Any adverse events - # --Any Grade-- 114 150 # 1 32 34 # 2 22 30 # 3 11 21 # 4 8 6 # 5 41 59 # GASTROINTESTINAL DISORDERS # --Any Grade-- 114 130 # 1 77 96 # 2 37 34 # 3 0 0 # 4 0 0 # 5 0 0 # ABDOMINAL DISCOMFORT # --Any Grade-- 68 49 # 1 68 49 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # ABDOMINAL FULLNESS DUE TO GAS # --Any Grade-- 73 51 # 1 73 51 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # BACK PAIN # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # DIARRHEA # --Any Grade-- 68 40 # 1 68 40 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # FAECES SOFT # --Any Grade-- 76 44 # 1 0 0 # 2 76 44 # 3 0 0 # 4 0 0 # 5 0 0 # GINGIVAL BLEEDING # --Any Grade-- 80 52 # 1 80 52 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # HEADACHE # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # HYPOTENSION # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # NAUSEA (INTERMITTENT) # --Any Grade-- 83 50 # 1 0 0 # 2 83 50 # 3 0 0 # 4 0 0 # 5 0 0 # ORTHOSTATIC HYPOTENSION # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # WEAKNESS # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS # --Any Grade-- 98 81 # 1 0 0 # 2 58 45 # 3 40 36 # 4 0 0 # 5 0 0 # ABDOMINAL DISCOMFORT # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # ABDOMINAL FULLNESS DUE TO GAS # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # BACK PAIN # --Any Grade-- 79 62 # 1 0 0 # 2 79 62 # 3 0 0 # 4 0 0 # 5 0 0 # DIARRHEA # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # FAECES SOFT # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # GINGIVAL BLEEDING # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # HEADACHE # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # HYPOTENSION # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # NAUSEA (INTERMITTENT) # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # ORTHOSTATIC HYPOTENSION # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # WEAKNESS # --Any Grade-- 73 43 # 1 0 0 # 2 0 0 # 3 73 43 # 4 0 0 # 5 0 0 # NERVOUS SYSTEM DISORDERS # --Any Grade-- 113 133 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 113 133 # ABDOMINAL DISCOMFORT # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # ABDOMINAL FULLNESS DUE TO GAS # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # BACK PAIN # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # DIARRHEA # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # FAECES SOFT # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # GINGIVAL BLEEDING # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # HEADACHE # --Any Grade-- 113 133 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 113 133 # HYPOTENSION # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # NAUSEA (INTERMITTENT) # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # ORTHOSTATIC HYPOTENSION # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # WEAKNESS # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # VASCULAR DISORDERS # --Any Grade-- 93 75 # 1 0 0 # 2 0 0 # 3 44 31 # 4 49 44 # 5 0 0 # ABDOMINAL DISCOMFORT # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # ABDOMINAL FULLNESS DUE TO GAS # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # BACK PAIN # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # DIARRHEA # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # FAECES SOFT # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # GINGIVAL BLEEDING # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # HEADACHE # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # HYPOTENSION # --Any Grade-- 66 43 # 1 0 0 # 2 0 0 # 3 66 43 # 4 0 0 # 5 0 0 # NAUSEA (INTERMITTENT) # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0 # ORTHOSTATIC HYPOTENSION # --Any Grade-- 70 54 # 1 0 0 # 2 0 0 # 3 0 0 # 4 70 54 # 5 0 0 # WEAKNESS # --Any Grade-- 0 0 # 1 0 0 # 2 0 0 # 3 0 0 # 4 0 0 # 5 0 0"},{"path":"https://insightsengineering.github.io/rtables/articles/clinical_trials.html","id":"response-table","dir":"Articles","previous_headings":"","what":"Response Table","title":"Example Clinical Trials Tables","text":"response table create composed 3 parts: Binary response table Unstratified analysis comparison vs. control group Multinomial response table Let’s start first part fairly simple derive: Note set ref_group argument split_cols_by() current table effect use cell data responder non-responder counts. ref_group argument needed part 2 3 table. now look implementation part 2: unstratified analysis comparison vs. control group. Let’s start analysis function: Hence can now add next vignette table: Next add part 3: multinomial response table. , adding row-split response level, thing binary response table . can now create final response table three parts: case wanted rename levels AVALC remove CI NE follows: Note table missing rows gaps make readable. row spacing feature rtables roadmap implemented future.","code":"ADRS_BESRSPI <- ex_adrs %>% filter(PARAMCD == \"BESRSPI\") %>% mutate( rsp = factor(AVALC %in% c(\"CR\", \"PR\"), levels = c(TRUE, FALSE), labels = c(\"Responders\", \"Non-Responders\")), is_rsp = (rsp == \"Responders\") ) s_proportion <- function(x, .N_col) { in_rows( .list = lapply( as.list(table(x)), function(xi) rcell(xi * c(1, 1 / .N_col), format = \"xx.xx (xx.xx%)\") ) ) } rsp_lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARMCD\", ref_group = \"ARM A\") %>% analyze(\"rsp\", s_proportion, show_labels = \"hidden\") rsp_tbl <- build_table(rsp_lyt, ADRS_BESRSPI) rsp_tbl # ARM A ARM B ARM C # (N=134) (N=134) (N=132) # ——————————————————————————————————————————————————————————————————— # Responders 114.00 (85.07%) 90.00 (67.16%) 120.00 (90.91%) # Non-Responders 20.00 (14.93%) 44.00 (32.84%) 12.00 (9.09%) s_unstrat_resp <- function(x, .ref_group, .in_ref_col) { if (.in_ref_col) { return(in_rows( \"Difference in Response Rates (%)\" = rcell(numeric(0)), \"95% CI (Wald, with correction)\" = rcell(numeric(0)), \"p-value (Chi-Squared Test)\" = rcell(numeric(0)), \"Odds Ratio (95% CI)\" = rcell(numeric(0)) )) } fit <- stats::prop.test( x = c(sum(x), sum(.ref_group)), n = c(length(x), length(.ref_group)), correct = FALSE ) fit_glm <- stats::glm( formula = rsp ~ group, data = data.frame( rsp = c(.ref_group, x), group = factor(rep(c(\"ref\", \"x\"), times = c(length(.ref_group), length(x))), levels = c(\"ref\", \"x\")) ), family = binomial(link = \"logit\") ) in_rows( \"Difference in Response Rates (%)\" = non_ref_rcell( (mean(x) - mean(.ref_group)) * 100, .in_ref_col, format = \"xx.xx\" ), \"95% CI (Wald, with correction)\" = non_ref_rcell( fit$conf.int * 100, .in_ref_col, format = \"(xx.xx, xx.xx)\" ), \"p-value (Chi-Squared Test)\" = non_ref_rcell( fit$p.value, .in_ref_col, format = \"x.xxxx | (<0.0001)\" ), \"Odds Ratio (95% CI)\" = non_ref_rcell( c( exp(stats::coef(fit_glm)[-1]), exp(stats::confint.default(fit_glm, level = .95)[-1, , drop = FALSE]) ), .in_ref_col, format = \"xx.xx (xx.xx - xx.xx)\" ) ) } s_unstrat_resp( x = ADRS_BESRSPI %>% filter(ARM == \"A: Drug X\") %>% pull(is_rsp), .ref_group = ADRS_BESRSPI %>% filter(ARM == \"B: Placebo\") %>% pull(is_rsp), .in_ref_col = FALSE ) # RowsVerticalSection (in_rows) object print method: # ---------------------------- # row_name formatted_cell indent_mod # 1 Difference in Response Rates (%) 17.91 0 # 2 95% CI (Wald, with correction) (7.93, 27.89) 0 # 3 p-value (Chi-Squared Test) 0.0006 0 # 4 Odds Ratio (95% CI) 2.79 (1.53 - 5.06) 0 # row_label # 1 Difference in Response Rates (%) # 2 95% CI (Wald, with correction) # 3 p-value (Chi-Squared Test) # 4 Odds Ratio (95% CI) rsp_lyt2 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARMCD\", ref_group = \"ARM A\") %>% analyze(\"rsp\", s_proportion, show_labels = \"hidden\") %>% analyze( \"is_rsp\", s_unstrat_resp, show_labels = \"visible\", var_labels = \"Unstratified Response Analysis\" ) rsp_tbl2 <- build_table(rsp_lyt2, ADRS_BESRSPI) rsp_tbl2 # ARM A ARM B ARM C # (N=134) (N=134) (N=132) # —————————————————————————————————————————————————————————————————————————————————————————————— # Responders 114.00 (85.07%) 90.00 (67.16%) 120.00 (90.91%) # Non-Responders 20.00 (14.93%) 44.00 (32.84%) 12.00 (9.09%) # Unstratified Response Analysis # Difference in Response Rates (%) -17.91 5.83 # 95% CI (Wald, with correction) (-27.89, -7.93) (-1.94, 13.61) # p-value (Chi-Squared Test) 0.0006 0.1436 # Odds Ratio (95% CI) 0.36 (0.20 - 0.65) 1.75 (0.82 - 3.75) s_prop <- function(df, .N_col) { in_rows( \"95% CI (Wald, with correction)\" = rcell(binom.test(nrow(df), .N_col)$conf.int * 100, format = \"(xx.xx, xx.xx)\") ) } s_prop( df = ADRS_BESRSPI %>% filter(ARM == \"A: Drug X\", AVALC == \"CR\"), .N_col = sum(ADRS_BESRSPI$ARM == \"A: Drug X\") ) # RowsVerticalSection (in_rows) object print method: # ---------------------------- # row_name formatted_cell indent_mod # 1 95% CI (Wald, with correction) (49.38, 66.67) 0 # row_label # 1 95% CI (Wald, with correction) rsp_lyt3 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARMCD\", ref_group = \"ARM A\") %>% analyze(\"rsp\", s_proportion, show_labels = \"hidden\") %>% analyze( \"is_rsp\", s_unstrat_resp, show_labels = \"visible\", var_labels = \"Unstratified Response Analysis\" ) %>% split_rows_by( var = \"AVALC\", split_fun = reorder_split_levels(neworder = c(\"CR\", \"PR\", \"SD\", \"PD\", \"NE\"), drlevels = TRUE), nested = FALSE ) %>% summarize_row_groups() %>% analyze(\"AVALC\", afun = s_prop) rsp_tbl3 <- build_table(rsp_lyt3, ADRS_BESRSPI) rsp_tbl3 # ARM A ARM B ARM C # (N=134) (N=134) (N=132) # —————————————————————————————————————————————————————————————————————————————————————————————— # Responders 114.00 (85.07%) 90.00 (67.16%) 120.00 (90.91%) # Non-Responders 20.00 (14.93%) 44.00 (32.84%) 12.00 (9.09%) # Unstratified Response Analysis # Difference in Response Rates (%) -17.91 5.83 # 95% CI (Wald, with correction) (-27.89, -7.93) (-1.94, 13.61) # p-value (Chi-Squared Test) 0.0006 0.1436 # Odds Ratio (95% CI) 0.36 (0.20 - 0.65) 1.75 (0.82 - 3.75) # CR 78 (58.2%) 55 (41.0%) 97 (73.5%) # 95% CI (Wald, with correction) (49.38, 66.67) (32.63, 49.87) (65.10, 80.79) # PR 36 (26.9%) 35 (26.1%) 23 (17.4%) # 95% CI (Wald, with correction) (19.58, 35.20) (18.92, 34.41) (11.38, 24.99) # SD 20 (14.9%) 44 (32.8%) 12 (9.1%) # 95% CI (Wald, with correction) (9.36, 22.11) (24.97, 41.47) (4.79, 15.34) # PD 0 (0.0%) 0 (0.0%) 0 (0.0%) # 95% CI (Wald, with correction) (0.00, 2.72) (0.00, 2.72) (0.00, 2.76) # NE 0 (0.0%) 0 (0.0%) 0 (0.0%) # 95% CI (Wald, with correction) (0.00, 2.72) (0.00, 2.72) (0.00, 2.76) rsp_label <- function(x) { rsp_full_label <- c( CR = \"Complete Response (CR)\", PR = \"Partial Response (PR)\", SD = \"Stable Disease (SD)\", `NON CR/PD` = \"Non-CR or Non-PD (NON CR/PD)\", PD = \"Progressive Disease (PD)\", NE = \"Not Evaluable (NE)\", Missing = \"Missing\", `NE/Missing` = \"Missing or unevaluable\" ) stopifnot(all(x %in% names(rsp_full_label))) rsp_full_label[x] } rsp_lyt4 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARMCD\", ref_group = \"ARM A\") %>% analyze(\"rsp\", s_proportion, show_labels = \"hidden\") %>% analyze( \"is_rsp\", s_unstrat_resp, show_labels = \"visible\", var_labels = \"Unstratified Response Analysis\" ) %>% split_rows_by( var = \"AVALC\", split_fun = keep_split_levels(c(\"CR\", \"PR\", \"SD\", \"PD\"), reorder = TRUE), nested = FALSE ) %>% summarize_row_groups(cfun = function(df, labelstr, .N_col) { in_rows(nrow(df) * c(1, 1 / .N_col), .formats = \"xx (xx.xx%)\", .labels = rsp_label(labelstr)) }) %>% analyze(\"AVALC\", afun = s_prop) %>% analyze(\"AVALC\", afun = function(x, .N_col) { in_rows(rcell(sum(x == \"NE\") * c(1, 1 / .N_col), format = \"xx.xx (xx.xx%)\"), .labels = rsp_label(\"NE\")) }, nested = FALSE) rsp_tbl4 <- build_table(rsp_lyt4, ADRS_BESRSPI) rsp_tbl4 # ARM A ARM B ARM C # (N=134) (N=134) (N=132) # —————————————————————————————————————————————————————————————————————————————————————————————— # Responders 114.00 (85.07%) 90.00 (67.16%) 120.00 (90.91%) # Non-Responders 20.00 (14.93%) 44.00 (32.84%) 12.00 (9.09%) # Unstratified Response Analysis # Difference in Response Rates (%) -17.91 5.83 # 95% CI (Wald, with correction) (-27.89, -7.93) (-1.94, 13.61) # p-value (Chi-Squared Test) 0.0006 0.1436 # Odds Ratio (95% CI) 0.36 (0.20 - 0.65) 1.75 (0.82 - 3.75) # Complete Response (CR) 78 (58.21%) 55 (41.04%) 97 (73.48%) # 95% CI (Wald, with correction) (49.38, 66.67) (32.63, 49.87) (65.10, 80.79) # Partial Response (PR) 36 (26.87%) 35 (26.12%) 23 (17.42%) # 95% CI (Wald, with correction) (19.58, 35.20) (18.92, 34.41) (11.38, 24.99) # Stable Disease (SD) 20 (14.93%) 44 (32.84%) 12 (9.09%) # 95% CI (Wald, with correction) (9.36, 22.11) (24.97, 41.47) (4.79, 15.34) # Progressive Disease (PD) 0 (0.00%) 0 (0.00%) 0 (0.00%) # 95% CI (Wald, with correction) (0.00, 2.72) (0.00, 2.72) (0.00, 2.76) # Not Evaluable (NE) 0.00 (0.00%) 0.00 (0.00%) 0.00 (0.00%)"},{"path":"https://insightsengineering.github.io/rtables/articles/clinical_trials.html","id":"time-to-event-analysis-table","dir":"Articles","previous_headings":"","what":"Time to Event Analysis Table","title":"Example Clinical Trials Tables","text":"time event analysis table constructed consists four parts: Overall subject counts Censored subjects summary Cox proportional-hazards analysis Time--event analysis table constructed sequential use analyze() function, four custom analysis functions corresponding four parts listed . addition table includes referential footnotes relevant table contents. table faceted column-wise arm. First start loading necessary packages preparing data used construction table. adtte dataset used preparing models adtte2 dataset handles missing values “Censor Date Description” column used produce final table. add censoring data example purposes. Next create basic analysis function, a_count_subjs prints overall unique subject counts percentages within data. analysis function created generate counts censored subjects level factor variable dataset. case cnsr_counter function applied CNSDTDSC variable contains censor date description censored subject. function generates counts fractions unique subjects corresponding factor level, excluding missing values (uncensored patients). Cox proportional-hazards (Cox P-H) analysis generated next third custom analysis function, a_cph. Prior creating analysis function, Cox P-H model fit data using coxph() Surv() functions survival package. model used input a_cph analysis function returns hazard ratios, 95% confidence intervals, p-values comparing reference group - case leftmost column. fourth final analysis function, a_tte, generates time first adverse event table three rows corresponding Median, 95% Confidence Interval, Min Max respectively. First survival table constructed summary table survival model using survfit() Surv() functions survival package. table given input a_tte produces table time first adverse event consisting previously mentioned summary statistics. Additionally, a_tte function creates referential footnote within table indicate censoring occurred data. Now able use four analysis functions build time event analysis table. set show_colcounts argument basic_table() TRUE first print total subject counts column. Next use split_cols_by() split table three columns corresponding three different levels ARM, specify first arm, \": Drug X\" act reference group compared - reference group used Cox P-H analysis. call analyze() sequentially using four custom analysis functions argument afun specifying additional arguments necessary. use build_table() construct rtable using adtte2 dataset. Finally, annotate table using fnotes_at_path() function specify product-limit estimates used calculate statistics listed “Time first adverse event” heading within table. referential footnote created earlier time--event analysis function (a_tte) also displayed.","code":"library(survival) adtte <- ex_adaette %>% dplyr::filter(PARAMCD == \"AETTE2\", SAFFL == \"Y\") # Add censoring to data for example adtte[adtte$AVAL > 1.0, ] <- adtte[adtte$AVAL > 1.0, ] %>% mutate(AVAL = 1.0, CNSR = 1) adtte2 <- adtte %>% mutate(CNSDTDSC = ifelse(CNSDTDSC == \"\", \"__none__\", CNSDTDSC)) a_count_subjs <- function(x, .N_col) { in_rows( \"Subjects with Adverse Events n (%)\" = rcell(length(unique(x)) * c(1, 1 / .N_col), format = \"xx (xx.xx%)\") ) } cnsr_counter <- function(df, .var, .N_col) { x <- df[!duplicated(df$USUBJID), .var] x <- x[x != \"__none__\"] lapply(table(x), function(xi) rcell(xi * c(1, 1 / .N_col), format = \"xx (xx.xx%)\")) } cph <- coxph(Surv(AVAL, CNSR == 0) ~ ACTARM + STRATA1, ties = \"exact\", data = adtte) a_cph <- function(df, .var, .in_ref_col, .ref_full, full_cox_fit) { if (.in_ref_col) { ret <- replicate(3, list(rcell(NULL))) } else { curtrt <- df[[.var]][1] coefs <- coef(full_cox_fit) sel_pos <- grep(curtrt, names(coefs), fixed = TRUE) hrval <- exp(coefs[sel_pos]) sdf <- survdiff(Surv(AVAL, CNSR == 0) ~ ACTARM + STRATA1, data = rbind(df, .ref_full)) pval <- (1 - pchisq(sdf$chisq, length(sdf$n) - 1)) / 2 ci_val <- exp(unlist(confint(full_cox_fit)[sel_pos, ])) ret <- list( rcell(hrval, format = \"xx.x\"), rcell(ci_val, format = \"(xx.x, xx.x)\"), rcell(pval, format = \"x.xxxx | (<0.0001)\") ) } in_rows( .list = ret, .names = c(\"Hazard ratio\", \"95% confidence interval\", \"p-value (one-sided stratified log rank)\") ) } surv_tbl <- as.data.frame( summary(survfit(Surv(AVAL, CNSR == 0) ~ ACTARM, data = adtte, conf.type = \"log-log\"))$table ) %>% dplyr::mutate( ACTARM = factor(gsub(\"ACTARM=\", \"\", row.names(.)), levels = levels(adtte$ACTARM)), ind = FALSE ) a_tte <- function(df, .var, kp_table) { ind <- grep(df[[.var]][1], row.names(kp_table), fixed = TRUE) minmax <- range(df[[\"AVAL\"]]) mm_val_str <- format_value(minmax, format = \"xx.x, xx.x\") rowfn <- list() if (all(df$CNSR[df$AVAL == minmax[2]])) { mm_val_str <- paste0(mm_val_str, \"*\") rowfn <- \"* indicates censoring\" } in_rows( Median = kp_table[ind, \"median\", drop = TRUE], \"95% confidence interval\" = unlist(kp_table[ind, c(\"0.95LCL\", \"0.95UCL\")]), \"Min Max\" = mm_val_str, .formats = c(\"xx.xx\", \"xx.xx - xx.xx\", \"xx\"), .row_footnotes = list(NULL, NULL, rowfn) ) } lyt <- basic_table(show_colcounts = TRUE) %>% ## Column faceting split_cols_by(\"ARM\", ref_group = \"A: Drug X\") %>% ## Overall count analyze(\"USUBJID\", a_count_subjs, show_labels = \"hidden\") %>% ## Censored subjects summary analyze(\"CNSDTDSC\", cnsr_counter, var_labels = \"Censored Subjects\", show_labels = \"visible\") %>% ## Cox P-H analysis analyze(\"ARM\", a_cph, extra_args = list(full_cox_fit = cph), show_labels = \"hidden\") %>% ## Time-to-event analysis analyze( \"ARM\", a_tte, var_labels = \"Time to first adverse event\", show_labels = \"visible\", extra_args = list(kp_table = surv_tbl), table_names = \"kapmeier\" ) tbl_tte <- build_table(lyt, adtte2) fnotes_at_path( tbl_tte, c(\"ma_USUBJID_CNSDTDSC_ARM_kapmeier\", \"kapmeier\") ) <- \"Product-limit (Kaplan-Meier) estimates.\" tbl_tte # A: Drug X B: Placebo C: Combination # (N=134) (N=134) (N=132) # ———————————————————————————————————————————————————————————————————————————————————————— # Subjects with Adverse Events n (%) 134 (100.00%) 134 (100.00%) 132 (100.00%) # Censored Subjects # Clinical Cut Off 6 (4.48%) 3 (2.24%) 14 (10.61%) # Completion or Discontinuation 9 (6.72%) 5 (3.73%) 9 (6.82%) # End of AE Reporting Period 14 (10.45%) 7 (5.22%) 14 (10.61%) # Preferred Term 11 (8.21%) 5 (3.73%) 13 (9.85%) # Hazard ratio 0.7 1.0 # 95% confidence interval (0.5, 0.9) (0.8, 1.4) # p-value (one-sided stratified log rank) 0.1070 0.4880 # Time to first adverse event {1} # Median 0.23 0.39 0.29 # 95% confidence interval 0.18 - 0.33 0.29 - 0.49 0.22 - 0.35 # Min Max {2} 0.0, 1.0* 0.0, 1.0* 0.0, 1.0* # ———————————————————————————————————————————————————————————————————————————————————————— # # {1} - Product-limit (Kaplan-Meier) estimates. # {2} - * indicates censoring # ————————————————————————————————————————————————————————————————————————————————————————"},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"the-old-way","dir":"Articles","previous_headings":"","what":"The Old Way","title":"Column Counts and Formats","text":"Many tables call column counts displayed header material table (.e., interspersed column labels). Historically, rtables supported -called leaf individual columns.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"setting-column-counts-to-visible-at-layout-time","dir":"Articles","previous_headings":"The Old Way","what":"Setting column counts to visible at Layout time","title":"Column Counts and Formats","text":"Display column counts (default) primarily achieved via passing show_colcounts = TRUE basic_table , e.g. format counts also controlled colcount_format argument basic_table. way displaying (, fact, even easily calculating) ARM facet counts.","code":"library(dplyr) # # Attaching package: 'dplyr' # The following objects are masked from 'package:stats': # # filter, lag # The following objects are masked from 'package:base': # # intersect, setdiff, setequal, union library(rtables) # Loading required package: formatters # # Attaching package: 'formatters' # The following object is masked from 'package:base': # # %||% # Loading required package: magrittr # # Attaching package: 'rtables' # The following object is masked from 'package:utils': # # str lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\") %>% split_cols_by(\"SEX\", split_fun = keep_split_levels(c(\"F\", \"M\"))) %>% analyze(\"AGE\") tbl <- build_table(lyt, ex_adsl) tbl # A: Drug X B: Placebo C: Combination # F M F M F M # (N=79) (N=51) (N=77) (N=55) (N=66) (N=60) # ———————————————————————————————————————————————————————————— # Mean 32.76 35.57 34.12 37.44 35.20 35.38"},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"modifying-counts-on-an-existing-table","dir":"Articles","previous_headings":"The Old Way","what":"Modifying counts on an existing table","title":"Column Counts and Formats","text":"(Leaf-)column counts altered fact via col_counts<- getter: NB never updated percentages appear within table calculated table-creation time, can lead misleading results used care.","code":"col_counts(tbl) <- c(17, 18, 19, 17, 18, 19) tbl # A: Drug X B: Placebo C: Combination # F M F M F M # (N=17) (N=18) (N=19) (N=17) (N=18) (N=19) # ———————————————————————————————————————————————————————————— # Mean 32.76 35.57 34.12 37.44 35.20 35.38"},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"hiding-counts","dir":"Articles","previous_headings":"The Old Way","what":"Hiding counts","title":"Column Counts and Formats","text":"provide user-visible way toggle column count display table creation, though support showing blank space particular counts setting NA: mechanisms continue work forseeable future, though new code advised use new API discussed .","code":"col_counts(tbl) <- c(17, 18, NA, 17, 18, 19) tbl # A: Drug X B: Placebo C: Combination # F M F M F M # (N=17) (N=18) (N=17) (N=18) (N=19) # ——————————————————————————————————————————————————————————— # Mean 32.76 35.57 34.12 37.44 35.20 35.38"},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"higher-level-column-counts","dir":"Articles","previous_headings":"","what":"Higher Level Column Counts","title":"Column Counts and Formats","text":"Starting rtables version 6.8.0, concept column counts modeled handled much granularity previously. facet column space now column count (whether displayed), appear directly corresponding column label (spanning number rows) set visible.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"setting-column-counts-to-visible-at-layout-time-1","dir":"Articles","previous_headings":"Higher Level Column Counts","what":"Setting Column Counts to Visible at Layout Time","title":"Column Counts and Formats","text":"primary way users create tables displays “high-level” column counts create layout specifies visible. new show_colcounts argument now accepted split_cols_by* layout functions. , column counts calculated table creation time, using alt_counts_df provided (simply df otherwise). Column formats set layout time via colcount_format argument specific split_cols_by call.","code":"lyt2 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_cols_by(\"SEX\", split_fun = keep_split_levels(c(\"F\", \"M\")), show_colcounts = TRUE ) %>% analyze(\"AGE\") tbl2 <- build_table(lyt2, ex_adsl) tbl2 # A: Drug X B: Placebo C: Combination # F M F M F M # (N=79) (N=51) (N=77) (N=55) (N=66) (N=60) # ———————————————————————————————————————————————————————————— # Mean 32.76 35.57 34.12 37.44 35.20 35.38 lyt3 <- basic_table() %>% split_cols_by(\"ARM\", show_colcounts = TRUE) %>% split_cols_by(\"SEX\", split_fun = keep_split_levels(c(\"F\", \"M\"))) %>% analyze(\"AGE\") tbl3 <- build_table(lyt3, ex_adsl) tbl3 # A: Drug X B: Placebo C: Combination # (N=134) (N=134) (N=132) # F M F M F M # ———————————————————————————————————————————————————————— # Mean 32.76 35.57 34.12 37.44 35.20 35.38"},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"manipulating-column-counts-in-an-existing-table","dir":"Articles","previous_headings":"Higher Level Column Counts","what":"Manipulating Column Counts In An Existing Table","title":"Column Counts and Formats","text":"Manipulation column counts (beyond old setters provided backwards compatibility) path based. words, set column count (e.g., NA displays blank) set visibilty set column counts, indicating via column paths. ability alter column count formats existing table currently offered exported functions. Column paths can obtained via col_paths leaf columns, via make_col_df(tbl, visible_only = FALSE)$path addressable facets.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"setting-individual-column-counts","dir":"Articles","previous_headings":"Higher Level Column Counts > Manipulating Column Counts In An Existing Table","what":"Setting individual column counts","title":"Column Counts and Formats","text":"facet_colcount getter setter queries sets column count facet column space (note needs leaf facet). E.g., convenience (primarily needed internally), also provide rm_all_colcounts sets column counts particular table NA levels nesting. expect particularly useful end-users.","code":"facet_colcount(tbl3, c(\"ARM\", \"C: Combination\")) # [1] 132 facet_colcount(tbl3, c(\"ARM\", \"C: Combination\")) <- 75 tbl3 # A: Drug X B: Placebo C: Combination # (N=134) (N=134) (N=75) # F M F M F M # ———————————————————————————————————————————————————————— # Mean 32.76 35.57 34.12 37.44 35.20 35.38"},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"setting-col-count-visibility","dir":"Articles","previous_headings":"Higher Level Column Counts > Manipulating Column Counts In An Existing Table","what":"Setting Col Count Visibility","title":"Column Counts and Formats","text":"Typically set column count visibility individually. *due constraint direct leaf siblings (e.g. F M one arms layout) must visibility column counts order rendering machinery work. Instead, can reset column count visibility groups siblings via facet_colcounts_visible (note ‘s’) setter. function accepts path ends name associated splitting instruction layout (e.g., c(\"ARM\"), c(\"ARM\", \"B: Placebo\", \"SEX\"), etc) resets visibility direct children path. NOTE can see , visibility column counts can “unbalanced design”, provided direct-siblings agreeing constraint met. leads things lining directly one might expect (generate blank spaces way setting visible column count NA ). Currently paths \"*\" work within facet_colcounts_visible, capability likely added future releases. colcount_visible getters setters also exist retrieve set individual column counts’ visiblities, largely internal detail virtually cases end users avoid calling directly. Note currently restriction currently enforced leaf columns due technical implementation details table renders considered undefined behavior contains group sibling column facets arising layout instruction whose column count visiblities disagree. may become error future versions without warning.","code":"facet_colcounts_visible(tbl3, c(\"ARM\", \"A: Drug X\", \"SEX\")) <- TRUE tbl3 # A: Drug X # (N=134) B: Placebo C: Combination # F M (N=134) (N=75) # (N=79) (N=51) F M F M # —————————————————————————————————————————————————————————— # Mean 32.76 35.57 34.12 37.44 35.20 35.38 ## BEWARE, the following is expected to show error tbl4 <- tbl3 colcount_visible(tbl4, c(\"ARM\", \"A: Drug X\", \"SEX\", \"F\")) <- FALSE tbl4 # Expected Error message # Error in h(simpleError(msg, call)) : # error in evaluating the argument 'x' in selecting a method for function 'toString': # Detected different colcount visibility among sibling facets (those arising from the # same split_cols_by* layout instruction). This is not supported. # Set count values to NA if you want a blank space to appear as the displayed count for particular facets. # First disagreement occured at paths: # ARM[A: Drug X]->SEX[F] # ARM[A: Drug X]->SEX[M]"},{"path":"https://insightsengineering.github.io/rtables/articles/col_counts.html","id":"advanced-settings","dir":"Articles","previous_headings":"Higher Level Column Counts > Manipulating Column Counts In An Existing Table","what":"Advanced Settings","title":"Column Counts and Formats","text":"using make_col_df() can see full path column count. One example application add NA value print default value \"\", show nothing. change (now uniformly ) output string case missing values column counts can use colcount_na_str:","code":"coldf <- make_col_df(tbl3) facet_colcount(tbl3, coldf$path[[1]][c(1, 2)]) <- NA_integer_ print(tbl3) # Keeps the missing space # A: Drug X # B: Placebo C: Combination # F M (N=134) (N=75) # (N=79) (N=51) F M F M # —————————————————————————————————————————————————————————— # Mean 32.76 35.57 34.12 37.44 35.20 35.38 colcount_na_str(tbl3) <- \"NaN\" tbl3 # Shows NaN # A: Drug X # NaN B: Placebo C: Combination # F M (N=134) (N=75) # (N=79) (N=51) F M F M # —————————————————————————————————————————————————————————— # Mean 32.76 35.57 34.12 37.44 35.20 35.38"},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"customizing-appearance","dir":"Articles","previous_headings":"","what":"Customizing Appearance","title":"Customizing Appearance","text":"vignette, describe various ways can modify customize appearance rtables. Loading package:","code":"library(rtables) library(dplyr)"},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"rows-and-cell-values-alignments","dir":"Articles","previous_headings":"Customizing Appearance","what":"Rows and cell values alignments","title":"Customizing Appearance","text":"possible align content assigning \"left\", \"center\" (default), \"right\" .aligns align arguments in_rows() rcell(), respectively. also possible use decimal, dec_right, dec_left decimal alignments. first takes numerical values aligns decimal character . every value column align = \"decimal\". Also numeric without decimal values aligned according imaginary . specified . dec_left dec_right behave similarly, difference column present empty spaces left right, pushes values towards left right taking one value decimal characters, right, non-decimal values left. details, please read related documentation page help(\"decimal_align\"). Please consider using ?in_rows ?rcell clarifications two arguments, use formatters::list_valid_aligns() see available alignment options. following show two simplified examples use align .aligns, respectively. concepts can well applied clinical table shown following, complex, example.","code":"# In rcell we use align. lyt <- basic_table() %>% analyze(\"AGE\", function(x) { in_rows( left = rcell(\"l\", align = \"left\"), right = rcell(\"r\", align = \"right\"), center = rcell(\"c\", align = \"center\") ) }) tbl <- build_table(lyt, DM) tbl # all obs # ———————————————— # left l # right r # center c # In in_rows, we use .aligns. This can either set the general value or the # single values (see NB). lyt2 <- basic_table() %>% analyze(\"AGE\", function(x) { in_rows( left = rcell(\"l\"), right = rcell(\"r\"), center = rcell(\"c\"), .aligns = c(\"right\") ) # NB: .aligns = c(\"right\", \"left\", \"center\") }) tbl2 <- build_table(lyt2, DM) tbl2 # all obs # ———————————————— # left l # right r # center c lyt3 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(c(\"AGE\", \"STRATA1\"), function(x) { if (is.numeric(x)) { in_rows( \"mean\" = rcell(mean(x)), \"sd\" = rcell(sd(x)), .formats = c(\"xx.x\"), .aligns = \"left\" ) } else if (is.factor(x)) { rcell(length(unique(x)), align = \"right\") } else { stop(\"Unsupported type\") } }, show_labels = \"visible\", na_str = \"NE\") tbl3 <- build_table(lyt3, ex_adsl) tbl3 # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————— # F # AGE # mean 32.8 34.1 35.2 # sd 6.1 7.1 7.4 # STRATA1 # STRATA1 3 3 3 # M # AGE # mean 35.6 37.4 35.4 # sd 7.1 8.7 8.2 # STRATA1 # STRATA1 3 3 3 # U # AGE # mean 31.7 31.0 35.2 # sd 3.2 5.7 3.1 # STRATA1 # STRATA1 3 2 3 # UNDIFFERENTIATED # AGE # mean 28.0 NE 45.0 # sd NE NE 1.4 # STRATA1 # STRATA1 1 0 2"},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"top-left-materials","dir":"Articles","previous_headings":"Customizing Appearance","what":"Top-left Materials","title":"Customizing Appearance","text":"sequence strings printed area column header display first row label can modified pre-processing using label position argument row splits split_rows_by, append_topleft function, post-processing using top_left() function. Note: Indenting automatically added label_pos = \"topleft\". Within layout initializer: Specify label position using split_rows function. Notice position STRATA1 SEX. Post-processing using top_left() function:","code":"lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"STRATA1\") %>% analyze(\"AGE\") %>% append_topleft(\"New top_left material here\") build_table(lyt, DM) # New top_left material here A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————————————— # A # Mean 32.53 32.30 35.76 # B # Mean 35.46 32.42 34.39 # C # Mean 36.34 34.45 33.54 lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"STRATA1\", label_pos = \"topleft\") %>% split_rows_by(\"SEX\", label_pos = \"topleft\") %>% analyze(\"AGE\") build_table(lyt, DM) # STRATA1 # SEX A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————— # A # F # Mean 30.91 32.91 35.95 # M # Mean 35.07 31.09 35.60 # U # Mean NA NA NA # UNDIFFERENTIATED # Mean NA NA NA # B # F # Mean 34.85 32.88 34.42 # M # Mean 36.64 32.09 34.37 # U # Mean NA NA NA # UNDIFFERENTIATED # Mean NA NA NA # C # F # Mean 35.19 36.00 34.32 # M # Mean 37.39 32.81 32.83 # U # Mean NA NA NA # UNDIFFERENTIATED # Mean NA NA NA lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(c(\"AGE\", \"STRATA1\"), function(x) { if (is.numeric(x)) { in_rows( \"mean\" = rcell(mean(x)), \"sd\" = rcell(sd(x)), .formats = c(\"xx.x\"), .aligns = \"left\" ) } else if (is.factor(x)) { rcell(length(unique(x)), align = \"right\") } else { stop(\"Unsupported type\") } }, show_labels = \"visible\", na_str = \"NE\") %>% build_table(ex_adsl) # Adding top-left material top_left(lyt) <- \"New top-left material here\" lyt # New top-left material here A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————————————— # F # AGE # mean 32.8 34.1 35.2 # sd 6.1 7.1 7.4 # STRATA1 # STRATA1 3 3 3 # M # AGE # mean 35.6 37.4 35.4 # sd 7.1 8.7 8.2 # STRATA1 # STRATA1 3 3 3 # U # AGE # mean 31.7 31.0 35.2 # sd 3.2 5.7 3.1 # STRATA1 # STRATA1 3 2 3 # UNDIFFERENTIATED # AGE # mean 28.0 NE 45.0 # sd NE NE 1.4 # STRATA1 # STRATA1 1 0 2"},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"table-inset","dir":"Articles","previous_headings":"Customizing Appearance","what":"Table Inset","title":"Customizing Appearance","text":"Table title, table body, referential footnotes main footers can inset left alignment titles provenance footer materials. can modified within layout initializer basic_table() using inset argument post-processing table_inset(). Using layout initializer: Using post-processing function: Without inset - inset 5 characters - example table produced clinical data. Compare inset table main footer two tables. Without inset - inset - Notice, inset apply title materials (main title, subtitles, page titles), provenance footer materials. Inset settings applied top-left materials, referential footnotes main footer materials horizontal dividers.","code":"lyt <- basic_table(inset = 5) %>% analyze(\"AGE\") build_table(lyt, DM) # all obs # —————————————— # Mean 34.22 lyt <- basic_table() %>% analyze(\"AGE\") tbl <- build_table(lyt, DM) tbl # all obs # —————————————— # Mean 34.22 table_inset(tbl) <- 5 tbl # all obs # —————————————— # Mean 34.22 analysisfun <- function(x, ...) { in_rows( row1 = 5, row2 = c(1, 2), .row_footnotes = list(row1 = \"row 1 rfn\"), .cell_footnotes = list(row2 = \"row 2 cfn\") ) } lyt <- basic_table( title = \"Title says Whaaaat\", subtitles = \"Oh, ok.\", main_footer = \"ha HA! Footer!\", prov_footer = \"provenaaaaance\" ) %>% split_cols_by(\"ARM\") %>% analyze(\"AGE\", afun = analysisfun) result <- build_table(lyt, ex_adsl) result # Title says Whaaaat # Oh, ok. # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # row1 {1} 5 5 5 # row2 1, 2 {2} 1, 2 {2} 1, 2 {2} # —————————————————————————————————————————————————— # # {1} - row 1 rfn # {2} - row 2 cfn # —————————————————————————————————————————————————— # # ha HA! Footer! # # provenaaaaance table_inset(result) <- 5 result # Title says Whaaaat # Oh, ok. # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # row1 {1} 5 5 5 # row2 1, 2 {2} 1, 2 {2} 1, 2 {2} # —————————————————————————————————————————————————— # # {1} - row 1 rfn # {2} - row 2 cfn # —————————————————————————————————————————————————— # # ha HA! Footer! # # provenaaaaance"},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"horizontal-separation","dir":"Articles","previous_headings":"Customizing Appearance","what":"Horizontal Separation","title":"Customizing Appearance","text":"character value can specified modify horizontal separation column headers table. Horizontal separation applies : separating title + subtitles column labels + top left materials, column labels + top left material row labels + cells, row labels + cells footer content, Referential footnotes main + provenance content something sides divider. , replace default line “=”.","code":"tbl <- basic_table() %>% split_cols_by(\"Species\") %>% add_colcounts() %>% analyze(c(\"Sepal.Length\", \"Petal.Width\"), function(x) { in_rows( mean_sd = c(mean(x), sd(x)), var = var(x), min_max = range(x), .formats = c(\"xx.xx (xx.xx)\", \"xx.xxx\", \"xx.x - xx.x\"), .labels = c(\"Mean (sd)\", \"Variance\", \"Min - Max\") ) }) %>% build_table(iris, hsep = \"=\") tbl # setosa versicolor virginica # (N=50) (N=50) (N=50) # ====================================================== # Sepal.Length # Mean (sd) 5.01 (0.35) 5.94 (0.52) 6.59 (0.64) # Variance 0.124 0.266 0.404 # Min - Max 4.3 - 5.8 4.9 - 7.0 4.9 - 7.9 # Petal.Width # Mean (sd) 0.25 (0.11) 1.33 (0.20) 2.03 (0.27) # Variance 0.011 0.039 0.075 # Min - Max 0.1 - 0.6 1.0 - 1.8 1.4 - 2.5"},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"section-dividers","dir":"Articles","previous_headings":"Customizing Appearance","what":"Section Dividers","title":"Customizing Appearance","text":"character value can specified section divider succeed every group defined split instruction. Note, trailing divider end table never printed. , “+” repeated used section divider. Section dividers can set ” ” create blank line. Separation characters can specified different row splits. However, one printed “pile ” next .","code":"lyt <- basic_table() %>% split_cols_by(\"Species\") %>% analyze(head(names(iris), -1), afun = function(x) { list( \"mean / sd\" = rcell(c(mean(x), sd(x)), format = \"xx.xx (xx.xx)\"), \"range\" = rcell(diff(range(x)), format = \"xx.xx\") ) }, section_div = \"+\") build_table(lyt, iris) # setosa versicolor virginica # —————————————————————————————————————————————————————— # Sepal.Length # mean / sd 5.01 (0.35) 5.94 (0.52) 6.59 (0.64) # range 1.50 2.10 3.00 # ++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Sepal.Width # mean / sd 3.43 (0.38) 2.77 (0.31) 2.97 (0.32) # range 2.10 1.40 1.60 # ++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Petal.Length # mean / sd 1.46 (0.17) 4.26 (0.47) 5.55 (0.55) # range 0.90 2.10 2.40 # ++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Petal.Width # mean / sd 0.25 (0.11) 1.33 (0.20) 2.03 (0.27) # range 0.50 0.80 1.10 lyt <- basic_table() %>% split_cols_by(\"Species\") %>% analyze(head(names(iris), -1), afun = function(x) { list( \"mean / sd\" = rcell(c(mean(x), sd(x)), format = \"xx.xx (xx.xx)\"), \"range\" = rcell(diff(range(x)), format = \"xx.xx\") ) }, section_div = \" \") build_table(lyt, iris) # setosa versicolor virginica # —————————————————————————————————————————————————————— # Sepal.Length # mean / sd 5.01 (0.35) 5.94 (0.52) 6.59 (0.64) # range 1.50 2.10 3.00 # # Sepal.Width # mean / sd 3.43 (0.38) 2.77 (0.31) 2.97 (0.32) # range 2.10 1.40 1.60 # # Petal.Length # mean / sd 1.46 (0.17) 4.26 (0.47) 5.55 (0.55) # range 0.90 2.10 2.40 # # Petal.Width # mean / sd 0.25 (0.11) 1.33 (0.20) 2.03 (0.27) # range 0.50 0.80 1.10 lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"RACE\", section_div = \"=\") %>% split_rows_by(\"STRATA1\", section_div = \"~\") %>% analyze(\"AGE\", mean, var_labels = \"Age\", format = \"xx.xx\") build_table(lyt, DM) # A: Drug X B: Placebo C: Combination # ——————————————————————————————————————————————————————————————————————————————————— # ASIAN # A # mean 32.19 33.90 36.81 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # B # mean 34.12 31.62 34.73 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # C # mean 36.21 33.00 32.39 # =================================================================================== # BLACK OR AFRICAN AMERICAN # A # mean 31.50 28.57 33.62 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # B # mean 35.60 30.83 33.67 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # C # mean 35.50 34.18 35.00 # =================================================================================== # WHITE # A # mean 37.67 31.33 33.17 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # B # mean 39.86 39.00 34.75 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # C # mean 39.75 44.67 36.75 # =================================================================================== # AMERICAN INDIAN OR ALASKA NATIVE # A # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # B # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # C # mean NA NA NA # =================================================================================== # MULTIPLE # A # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # B # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # C # mean NA NA NA # =================================================================================== # NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER # A # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # B # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # C # mean NA NA NA # =================================================================================== # OTHER # A # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # B # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # C # mean NA NA NA # =================================================================================== # UNKNOWN # A # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # B # mean NA NA NA # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # C # mean NA NA NA"},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"indent-modifier","dir":"Articles","previous_headings":"Customizing Appearance","what":"Indent Modifier","title":"Customizing Appearance","text":"Tables default indenting level splitting. custom indent value can supplied indent_mod argument within split function modify default. Compare indenting tables : Default Indent - Modified indent -","code":"basic_table( title = \"Study XXXXXXXX\", subtitles = c(\"subtitle YYYYYYYYYY\", \"subtitle2 ZZZZZZZZZ\"), main_footer = \"Analysis was done using cool methods that are correct\", prov_footer = \"file: /path/to/stuff/that/lives/there HASH:1ac41b242a\" ) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% split_rows_by(\"STRATA1\") %>% analyze(\"AGE\", mean, format = \"xx.x\") %>% build_table(DM) # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # # —————————————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————— # F # A # mean 30.9 32.9 36.0 # B # mean 34.9 32.9 34.4 # C # mean 35.2 36.0 34.3 # M # A # mean 35.1 31.1 35.6 # B # mean 36.6 32.1 34.4 # C # mean 37.4 32.8 32.8 # U # A # mean NA NA NA # B # mean NA NA NA # C # mean NA NA NA # UNDIFFERENTIATED # A # mean NA NA NA # B # mean NA NA NA # C # mean NA NA NA # —————————————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a basic_table( title = \"Study XXXXXXXX\", subtitles = c(\"subtitle YYYYYYYYYY\", \"subtitle2 ZZZZZZZZZ\"), main_footer = \"Analysis was done using cool methods that are correct\", prov_footer = \"file: /path/to/stuff/that/lives/there HASH:1ac41b242a\" ) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\", indent_mod = 3) %>% split_rows_by(\"STRATA1\", indent_mod = 5) %>% analyze(\"AGE\", mean, format = \"xx.x\") %>% build_table(DM) # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # # —————————————————————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————————————— # F # A # mean 30.9 32.9 36.0 # B # mean 34.9 32.9 34.4 # C # mean 35.2 36.0 34.3 # M # A # mean 35.1 31.1 35.6 # B # mean 36.6 32.1 34.4 # C # mean 37.4 32.8 32.8 # U # A # mean NA NA NA # B # mean NA NA NA # C # mean NA NA NA # UNDIFFERENTIATED # A # mean NA NA NA # B # mean NA NA NA # C # mean NA NA NA # —————————————————————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a"},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"variable-label-visibility","dir":"Articles","previous_headings":"Customizing Appearance","what":"Variable Label Visibility","title":"Customizing Appearance","text":"split instructions, visibility label variable split can modified visible, hidden topleft show_labels argument, label_pos argument, child_labels argument applicable. Note: name levels contained variable. analyze calls, indicates variable visible multiple variables analyzed level nesting. Visibility labels groups generated split can also modified using child_label argument split call. child_label argument can force labels visible addition content rows hide move content rows. Notice placement “AGE” label example: set default, label AGE repeated since one variable analyzed level nesting. Override setting show_labels argument “visible”. example using label_pos argument modifying label visibility: Label order mirror order split_rows_by calls. labels subgroups hidden, label_pos argument set hidden. “SEX” label position hidden - “SEX” label position top-left materials -","code":"lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels, child_labels = \"visible\") %>% split_rows_by(\"STRATA1\") %>% analyze(\"AGE\", mean, show_labels = \"default\") build_table(lyt, DM) # A: Drug X B: Placebo C: Combination # (N=121) (N=106) (N=129) # ————————————————————————————————————————————————————————————————— # F # A # mean 30.9090909090909 32.9090909090909 35.95 # B # mean 34.8518518518519 32.8823529411765 34.4210526315789 # C # mean 35.1904761904762 36 34.3181818181818 # M # A # mean 35.0714285714286 31.0909090909091 35.6 # B # mean 36.6428571428571 32.0869565217391 34.3684210526316 # C # mean 37.3913043478261 32.8125 32.8333333333333 lyt2 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(var = \"ARM\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels, child_labels = \"hidden\") %>% split_rows_by(\"STRATA1\") %>% analyze(\"AGE\", mean, show_labels = \"visible\") build_table(lyt2, DM) # A: Drug X B: Placebo C: Combination # (N=121) (N=106) (N=129) # ————————————————————————————————————————————————————————————————— # A # AGE # mean 30.9090909090909 32.9090909090909 35.95 # B # AGE # mean 34.8518518518519 32.8823529411765 34.4210526315789 # C # AGE # mean 35.1904761904762 36 34.3181818181818 # A # AGE # mean 35.0714285714286 31.0909090909091 35.6 # B # AGE # mean 36.6428571428571 32.0869565217391 34.3684210526316 # C # AGE # mean 37.3913043478261 32.8125 32.8333333333333 basic_table( title = \"Study XXXXXXXX\", subtitles = c(\"subtitle YYYYYYYYYY\", \"subtitle2 ZZZZZZZZZ\"), main_footer = \"Analysis was done using cool methods that are correct\", prov_footer = \"file: /path/to/stuff/that/lives/there HASH:1ac41b242a\" ) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels, label_pos = \"visible\") %>% split_rows_by(\"STRATA1\", label_pos = \"hidden\") %>% analyze(\"AGE\", mean, format = \"xx.x\") %>% build_table(DM) # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # # ———————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————— # SEX # F # A # mean 30.9 32.9 36.0 # B # mean 34.9 32.9 34.4 # C # mean 35.2 36.0 34.3 # M # A # mean 35.1 31.1 35.6 # B # mean 36.6 32.1 34.4 # C # mean 37.4 32.8 32.8 # ———————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a basic_table( title = \"Study XXXXXXXX\", subtitles = c(\"subtitle YYYYYYYYYY\", \"subtitle2 ZZZZZZZZZ\"), main_footer = \"Analysis was done using cool methods that are correct\", prov_footer = \"file: /path/to/stuff/that/lives/there HASH:1ac41b242a\" ) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels, label_pos = \"topleft\") %>% split_rows_by(\"STRATA1\", label_pos = \"hidden\") %>% analyze(\"AGE\", mean, format = \"xx.x\") %>% build_table(DM) # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # # —————————————————————————————————————————————————— # SEX A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # F # A # mean 30.9 32.9 36.0 # B # mean 34.9 32.9 34.4 # C # mean 35.2 36.0 34.3 # M # A # mean 35.1 31.1 35.6 # B # mean 36.6 32.1 34.4 # C # mean 37.4 32.8 32.8 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a"},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"cell-label-and-annotation-wrapping","dir":"Articles","previous_headings":"Customizing Appearance","what":"Cell, Label, and Annotation Wrapping","title":"Customizing Appearance","text":"rtable can rendered customized width setting custom rendering widths cell contents, row labels, titles/footers. demonstrated using sample data table . section aim render table reduced width since table wide contents several cells, labels, titles/footers. following sections use toString() function render table string form. resulting string representation ready printed written plain text file, use strsplit() function combination matrix() function preview rendered wrapped table matrix form within vignette.","code":"trimmed_data <- ex_adsl %>% filter(SEX %in% c(\"M\", \"F\")) %>% filter(RACE %in% levels(RACE)[1:2]) levels(trimmed_data$ARM)[1] <- \"Incredibly long column name to be wrapped\" levels(trimmed_data$ARM)[2] <- \"This_column_name_should_be_split_somewhere\" wide_tbl <- basic_table( title = \"Title that is too long and also needs to be wrapped to a smaller width\", subtitles = \"Subtitle that is also long and also needs to be wrapped to a smaller width\", main_footer = \"Footnote that is wider than expected for this table.\", prov_footer = \"Provenance footer material that is also wider than expected for this table.\" ) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"RACE\", split_fun = drop_split_levels) %>% analyze( c(\"AGE\", \"EOSDY\"), na_str = \"Very long cell contents to_be_wrapped_and_splitted\", inclNAs = TRUE ) %>% build_table(trimmed_data) wide_tbl # Title that is too long and also needs to be wrapped to a smaller width # Subtitle that is also long and also needs to be wrapped to a smaller width # # ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— # Incredibly long column name to be wrapped This_column_name_should_be_split_somewhere C: Combination # ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN # AGE # Mean 32.50 36.68 36.99 # EOSDY # Mean Very long cell contents to_be_wrapped_and_splitted Very long cell contents to_be_wrapped_and_splitted Very long cell contents to_be_wrapped_and_splitted # BLACK OR AFRICAN AMERICAN # AGE # Mean 34.27 34.93 33.71 # EOSDY # Mean Very long cell contents to_be_wrapped_and_splitted Very long cell contents to_be_wrapped_and_splitted Very long cell contents to_be_wrapped_and_splitted # ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— # # Footnote that is wider than expected for this table. # # Provenance footer material that is also wider than expected for this table."},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"cell-label-wrapping","dir":"Articles","previous_headings":"Customizing Appearance > Cell, Label, and Annotation Wrapping","what":"Cell & Label Wrapping","title":"Customizing Appearance","text":"width rendered table can customized wrapping column widths. done setting custom width values via widths argument toString() function. length vector passed widths argument must equal total number columns table, including row labels column, value vector corresponding maximum width (characters) allowed column, left right. Similarly, wrapping can applied exporting table via one four export_as_* functions implementing pagination via paginate_table() function rtables package. cases, rendered column widths set using colwidths argument takes input format widths argument toString(). example, wide_tbl four columns (1 row label column 3 content columns) set widths use rendered table. set width row label column 10 characters widths 3 content columns 8 characters. words longer specified width broken continued following line. default 3 spaces separating columns rendered table can customized via col_gap argument toString() width customization desired. resulting output can see table correctly rendered using wrapping total width 43 characters, titles footers remain wider rendered table.","code":"result_wrap_cells <- toString(wide_tbl, widths = c(10, 8, 8, 8)) matrix_wrap_cells <- matrix(strsplit(result_wrap_cells, \"\\n\")[[1]], ncol = 1) matrix_wrap_cells # [,1] # [1,] \"Title that is too long and also needs to be wrapped to a smaller width\" # [2,] \"Subtitle that is also long and also needs to be wrapped to a smaller width\" # [3,] \"\" # [4,] \"———————————————————————————————————————————\" # [5,] \" Incredib This_col \" # [6,] \" ly long umn_name \" # [7,] \" column _should_ \" # [8,] \" name be_split \" # [9,] \" to be _somewhe C: Combi\" # [10,] \" wrapped re nation \" # [11,] \"———————————————————————————————————————————\" # [12,] \"ASIAN \" # [13,] \" AGE \" # [14,] \" Mean 32.50 36.68 36.99 \" # [15,] \" EOSDY \" # [16,] \" Mean Very Very Very \" # [17,] \" long long long \" # [18,] \" cell cell cell \" # [19,] \" contents contents contents\" # [20,] \" to_be_wr to_be_wr to_be_wr\" # [21,] \" apped_an apped_an apped_an\" # [22,] \" d_splitt d_splitt d_splitt\" # [23,] \" ed ed ed \" # [24,] \"BLACK OR \" # [25,] \"AFRICAN \" # [26,] \"AMERICAN \" # [27,] \" AGE \" # [28,] \" Mean 34.27 34.93 33.71 \" # [29,] \" EOSDY \" # [30,] \" Mean Very Very Very \" # [31,] \" long long long \" # [32,] \" cell cell cell \" # [33,] \" contents contents contents\" # [34,] \" to_be_wr to_be_wr to_be_wr\" # [35,] \" apped_an apped_an apped_an\" # [36,] \" d_splitt d_splitt d_splitt\" # [37,] \" ed ed ed \" # [38,] \"———————————————————————————————————————————\" # [39,] \"\" # [40,] \"Footnote that is wider than expected for this table.\" # [41,] \"\" # [42,] \"Provenance footer material that is also wider than expected for this table.\""},{"path":"https://insightsengineering.github.io/rtables/articles/custom_appearance.html","id":"title-footer-wrapping","dir":"Articles","previous_headings":"Customizing Appearance > Cell, Label, and Annotation Wrapping","what":"Title & Footer Wrapping","title":"Customizing Appearance","text":"addition wrapping column widths, titles footers can wrapped setting tf_wrap = TRUE toString() setting max_width argument toString() maximum width (characters) allowed titles/footers. four export_as_* functions paginate_table() can also wrap titles/footers setting two arguments. following code, set max_width = 43 rendered table annotations maximum width 43 characters.","code":"result_wrap_cells_tf <- toString( wide_tbl, widths = c(10, 8, 8, 8), tf_wrap = TRUE, max_width = 43 ) matrix_wrap_cells_tf <- matrix(strsplit(result_wrap_cells_tf, \"\\n\")[[1]], ncol = 1) matrix_wrap_cells_tf # [,1] # [1,] \"Title that is too long and also needs to be\" # [2,] \"wrapped to a smaller width\" # [3,] \"Subtitle that is also long and also needs\" # [4,] \"to be wrapped to a smaller width\" # [5,] \"\" # [6,] \"———————————————————————————————————————————\" # [7,] \" Incredib This_col \" # [8,] \" ly long umn_name \" # [9,] \" column _should_ \" # [10,] \" name be_split \" # [11,] \" to be _somewhe C: Combi\" # [12,] \" wrapped re nation \" # [13,] \"———————————————————————————————————————————\" # [14,] \"ASIAN \" # [15,] \" AGE \" # [16,] \" Mean 32.50 36.68 36.99 \" # [17,] \" EOSDY \" # [18,] \" Mean Very Very Very \" # [19,] \" long long long \" # [20,] \" cell cell cell \" # [21,] \" contents contents contents\" # [22,] \" to_be_wr to_be_wr to_be_wr\" # [23,] \" apped_an apped_an apped_an\" # [24,] \" d_splitt d_splitt d_splitt\" # [25,] \" ed ed ed \" # [26,] \"BLACK OR \" # [27,] \"AFRICAN \" # [28,] \"AMERICAN \" # [29,] \" AGE \" # [30,] \" Mean 34.27 34.93 33.71 \" # [31,] \" EOSDY \" # [32,] \" Mean Very Very Very \" # [33,] \" long long long \" # [34,] \" cell cell cell \" # [35,] \" contents contents contents\" # [36,] \" to_be_wr to_be_wr to_be_wr\" # [37,] \" apped_an apped_an apped_an\" # [38,] \" d_splitt d_splitt d_splitt\" # [39,] \" ed ed ed \" # [40,] \"———————————————————————————————————————————\" # [41,] \"\" # [42,] \"Footnote that is wider than expected for\" # [43,] \"this table.\" # [44,] \"\" # [45,] \"Provenance footer material that is also\" # [46,] \"wider than expected for this table.\""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"debugging","dir":"Articles > Dev-guide","previous_headings":"","what":"Debugging","title":"Debugging in {rtables} and Beyond","text":"short non-comprehensive guide debugging rtables. Regardless, considered valid personal use discretion.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"coding-in-practice","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"Coding in Practice","title":"Debugging in {rtables} and Beyond","text":"easy read find problems clever impossible debug","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"some-definitions","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"Some Definitions","title":"Debugging in {rtables} and Beyond","text":"Coding Error - Code intended -> Bug punch card Unexpected Input - Defensive programming FAIL FAST FAIL LOUD (FFFL) -> useful time consuming Bug Dependency -> never use dependencies can!","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"considerations-about-fffl","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"Considerations About FFFL","title":"Debugging in {rtables} and Beyond","text":"Errors close possible source. example, bad inputs found early. worst possible example software silently giving incorrect results. Common things can catch early missing values, column length == 0, length > 1.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"general-suggestions","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"General Suggestions","title":"Debugging in {rtables} and Beyond","text":"Robust code base attempt possibly problematic operations. Read Error Messages debugcall can add signature (formals) trace powerful can add reaction tracer good precise find happens options(error = recover) one best tools debug core tool developing allows step point function call sequence. dump.frames debugger: saves file object call debugger step recover.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"warn-global-option","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"warn Global Option","title":"Debugging in {rtables} and Beyond","text":"<0 ignored 0 top level function call 1 immediately occur >=2 throws errors <<- recover debugger gives global environment","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"direct-modification-techniques","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"direct-modification techniques","title":"Debugging in {rtables} and Beyond","text":"PRINT / CAT always low level debugging can used. helpful server jobs maybe terminal console output available browser() can used. example, can print position state function certain point find break point. comment blocks -> work pipes (can use identity() step nothing break pipes) browser() bombing","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"regression-tests","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"Regression Tests","title":"Debugging in {rtables} and Beyond","text":"Almost every bug become regression test.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"debugging-with-pipes","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"Debugging with Pipes","title":"Debugging in {rtables} and Beyond","text":"Pipes better write code horrible debug T pipe %T>% print midway debug_pipe() -> like T pipe going browser()","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"shiny-debugging","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"Shiny Debugging","title":"Debugging in {rtables} and Beyond","text":"difficult due reactivity.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"general-suggestion","dir":"Articles > Dev-guide","previous_headings":"Debugging","what":"General Suggestion","title":"Debugging in {rtables} and Beyond","text":"CLEVER CODE - , CLEVER ALSO SUBJECTIVE CHANGE TIME.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_debug_rtables.html","id":"debugging-in-rtables","dir":"Articles > Dev-guide","previous_headings":"","what":"Debugging in rtables","title":"Debugging in {rtables} and Beyond","text":"invite smart developer use provided examples way get “interactive” dynamic view internal algorithms routinely executed constructing tables rtables. achieved using browser() debugonce() internal exported functions (rtables::: rtables::), see moment. invite continuously autonomously explore multiple S3 S4 objects constitute complexity power rtables. , use following functions: methods(generic_function): function lists methods available generic function. Specifically S4 generic functions, showMethods(generic_function) gives detailed information method (e.g. inheritance). class(object): function returns class object. class one built-classes R, can use information search documentation examples. help(class) may informative call documentation specific class. Similarly, ? operator bring documentation page different S4 methods. S3 methods necessary postfix class name dot (e.g. ?summary.lm). getClass(class): describes type class compact way, slots , relationships may classes may inherit inherited . getClass(object) can see values slots object assigned. possible use str(object, max.level = 2) see less formal compact descriptions slots, may problematic one objects class slots. Hence, maximum number levels always limited 2 3 (max.level = 2). Similarly, attributes() can used retrieve information, need remember storing important variables way encouraged. Information regarding type class can retrieved mode() indirectly summary() .S4(). *getAnywhere(function) useful get source code internal functions specific generics. works well S3 methods, display relevant namespace methods found. Similarly, getMethod(S4_generic, S4_class) can retrieve source code class-specific S4 methods. eval(debugcall(generic_function(obj))): useful way browse S4 method, specifically defined object, without manually insert browser() code. also possible similarly R > 3.4.0 debug*() calls can triggering signature (class) specified. modern simplified wrappers tracing function trace().","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_notes.html","id":"disclaimer","dir":"Articles > Dev-guide","previous_headings":"","what":"Disclaimer","title":"Sparse Notes on {rtables} Internals","text":"collection notes divided issues working document end developer vignette one day.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_notes.html","id":"section_div-notes","dir":"Articles > Dev-guide","previous_headings":"","what":"section_div notes","title":"Sparse Notes on {rtables} Internals","text":"Everything layout built split objects, reside 00_tabletrees.R. section_div defined internally split object child_section_div assigned NA_character default. needs split objects need separator divisor. Object-wise, virtual class Split contains section_div following sub-classes. tagged “X” constructor allows section_div assigned value different NA_character, \"NX\" otherwise. can updated related layout functions. important, covered tests analyze split_rows_by. Now relevant understand information saved table object built build_table. need see present assigned. Let’s go back 00tabletree.Rand look trailing_section_div. classes definitions goes, notice search trailing_section_div present virtual classes TableRow VTableTree. following class hierarchy makes `trailing_section_div: Always check constructors finding classes. case example, DataRow ContentRow share constructor, need add identical getter setters two classes virtual class TableRow. Different story LabelRow needs handle differently. Now, understand two feature, lets see structure table built section dividers: , show trailing_section_div methods TableRow virtual object, LabelRow, VTableTree. three make whole section_div structure VTableTree present TableTree ElementaryTable two main table objects. NA_character_ section_div printed split divisions. LabelRow TableRow different assignment allows row-wise modification separators. special case ContentRow, represented content_table(obj) one-line ElementaryTable, label row turned . Please take moment check following setter: only_sep_sections parameter used change separators (splits) data rows. happening forcefully set TRUE, automatically activated section_div(tbl) <- char_v character vector length < nrow(tbl). Notice exception ContentRow activated switcher is_content_table. content rows visible label row. see main table structure change two blocks depending only_sep_sections. TRUE VTableTree modified leading split section separators modified. Also consider looking section_div getter tests test-accessors.R insights structure. Also understand exactly bound output, please check result make_row_df() column trailing_sep. Indeed, alternative iterative method used make_row_df retrieve information separators table row. trailing separator definition, added header_section_div function parameter basic_table, possibly add empty line header (e.g. header_section_div(tbl) = \" \"). trailing separator, separator added header. close circle, please check trailing_sep header_section_div propagated printed/used formatters::toString.","code":"library(rtables) ## Loading required package: formatters ## ## Attaching package: 'formatters' ## The following object is masked from 'package:base': ## ## %||% ## Loading required package: magrittr ## ## Attaching package: 'rtables' ## The following object is masked from 'package:utils': ## ## str getClass(\"Split\") ## Virtual Class \"Split\" [package \"rtables\"] ## ## Slots: ## ## Name: payload name split_label ## Class: ANY character character ## ## Name: split_format split_na_str split_label_position ## Class: FormatSpec character character ## ## Name: content_fun content_format content_na_str ## Class: listOrNULL FormatSpec character ## ## Name: content_var label_children extra_args ## Class: character logical list ## ## Name: indent_modifier content_indent_modifier content_extra_args ## Class: integer integer list ## ## Name: page_title_prefix child_section_div child_show_colcounts ## Class: character character logical ## ## Name: child_colcount_format ## Class: FormatSpec ## ## Known Subclasses: ## Class \"CustomizableSplit\", directly ## Class \"AllSplit\", directly ## Class \"VarStaticCutSplit\", directly ## Class \"VarDynCutSplit\", directly ## Class \"VAnalyzeSplit\", directly ## Class \"CompoundSplit\", directly ## Class \"VarLevelSplit\", by class \"CustomizableSplit\", distance 2 ## Class \"MultiVarSplit\", by class \"CustomizableSplit\", distance 2 ## Class \"RootSplit\", by class \"AllSplit\", distance 2 ## Class \"ManualSplit\", by class \"AllSplit\", distance 2 ## Class \"CumulativeCutSplit\", by class \"VarStaticCutSplit\", distance 2 ## Class \"AnalyzeVarSplit\", by class \"VAnalyzeSplit\", distance 2 ## Class \"AnalyzeColVarSplit\", by class \"VAnalyzeSplit\", distance 2 ## Class \"AnalyzeMultiVars\", by class \"CompoundSplit\", distance 2 ## Class \"VarLevWBaselineSplit\", by class \"VarLevelSplit\", distance 3 # Known Subclasses: # ? Class \"CustomizableSplit\", directly # vclass used for grouping different split types (I guess) # Class \"AllSplit\", directly # NX # Class \"VarStaticCutSplit\", directly # X via make_static_cut_split # Class \"VarDynCutSplit\", directly # X # Class \"VAnalyzeSplit\", directly # X # ? Class \"CompoundSplit\", directly # Used only for AnalyzeMultiVars (maybe not needed?) # Class \"VarLevelSplit\", by class \"CustomizableSplit\", distance 2 # X # Class \"MultiVarSplit\", by class \"CustomizableSplit\", distance 2 # X # Class \"RootSplit\", by class \"AllSplit\", distance 2 # NX # Class \"ManualSplit\", by class \"AllSplit\", distance 2 # X # Class \"CumulativeCutSplit\", by class \"VarStaticCutSplit\", distance 2 # X via make_static_cut_split # Class \"AnalyzeVarSplit\", by class \"VAnalyzeSplit\", distance 2 # Virtual # Class \"AnalyzeColVarSplit\", by class \"VAnalyzeSplit\", distance 2 # X # Class \"AnalyzeMultiVars\", by class \"CompoundSplit\", distance 2 # X # Class \"VarLevWBaselineSplit\", by class \"VarLevelSplit\", distance 3 # NX getClass(\"TableRow\") ## Virtual Class \"TableRow\" [package \"rtables\"] ## ## Slots: ## ## Name: leaf_value var_analyzed label ## Class: ANY character character ## ## Name: row_footnotes trailing_section_div level ## Class: list character integer ## ## Name: name col_info format ## Class: character InstantiatedColumnInfo FormatSpec ## ## Name: na_str indent_modifier table_inset ## Class: character integer integer ## ## Extends: ## Class \"VLeaf\", directly ## Class \"VTableNodeInfo\", directly ## Class \"VNodeInfo\", by class \"VLeaf\", distance 2 ## ## Known Subclasses: \"DataRow\", \"ContentRow\", \"LabelRow\" # Extends: # Class \"VLeaf\", directly # Class \"VTableNodeInfo\", directly # Class \"VNodeInfo\", by class \"VLeaf\", distance 2 # # Known Subclasses: \"DataRow\", \"ContentRow\", \"LabelRow\" getClass(\"VTableTree\") ## Virtual Class \"VTableTree\" [package \"rtables\"] ## ## Slots: ## ## Name: children rowspans labelrow ## Class: list data.frame LabelRow ## ## Name: page_titles horizontal_sep header_section_div ## Class: character character character ## ## Name: trailing_section_div col_info format ## Class: character InstantiatedColumnInfo FormatSpec ## ## Name: na_str indent_modifier table_inset ## Class: character integer integer ## ## Name: level name main_title ## Class: integer character character ## ## Name: subtitles main_footer provenance_footer ## Class: character character character ## ## Extends: ## Class \"VTableNodeInfo\", directly ## Class \"VTree\", directly ## Class \"VTitleFooter\", directly ## Class \"VNodeInfo\", by class \"VTableNodeInfo\", distance 2 ## ## Known Subclasses: \"ElementaryTable\", \"TableTree\" # Extends: # Class \"VTableNodeInfo\", directly # Class \"VTree\", directly # Class \"VTitleFooter\", directly # Class \"VNodeInfo\", by class \"VTableNodeInfo\", distance 2 # # Known Subclasses: \"ElementaryTable\", \"TableTree\" lyt <- basic_table() %>% split_rows_by(\"ARM\", section_div = \"+\") %>% split_rows_by(\"STRATA1\", section_div = \"\") %>% analyze(\"AGE\", afun = function(x) list(\"Mean\" = mean(x), \"Standard deviation\" = sd(x)), format = list(\"Mean\" = \"xx.\", \"Standard deviation\" = \"xx.\"), section_div = \"~\" ) tbl <- build_table(lyt, DM) print(tbl) ## all obs ## ———————————————————————————————— ## A: Drug X ## A ## Mean 33 ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Standard deviation 7 ## ## B ## Mean 35 ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Standard deviation 7 ## ## C ## Mean 36 ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Standard deviation 9 ## ++++++++++++++++++++++++++++++++ ## B: Placebo ## A ## Mean 32 ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Standard deviation 6 ## ## B ## Mean 32 ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Standard deviation 6 ## ## C ## Mean 34 ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Standard deviation 7 ## ++++++++++++++++++++++++++++++++ ## C: Combination ## A ## Mean 36 ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Standard deviation 7 ## ## B ## Mean 34 ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Standard deviation 6 ## ## C ## Mean 34 ## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Standard deviation 6 print(class(tbl)) # TableTree ## [1] \"TableTree\" ## attr(,\"package\") ## [1] \"rtables\" # methods(\"trailing_section_div\") # to see this please do devtools::load_all() # [1] trailing_section_div,LabelRow-method # trailing_section_div,TableRow-method # trailing_section_div,VTableTree-method setMethod(\"section_div<-\", \"VTableTree\", function(obj, value, only_sep_sections = FALSE) { char_v <- as.character(value) tree_depths <- unname(vapply(collect_leaves(obj), tt_level, numeric(1))) max_tree_depth <- max(tree_depths) stopifnot(is.logical(only_sep_sections)) .check_char_vector_for_section_div(char_v, max_tree_depth, nrow(obj)) # Automatic establishment of intent if (length(char_v) < nrow(obj)) { only_sep_sections <- TRUE } # Case where only separators or splits need to change externally if (only_sep_sections && length(char_v) < nrow(obj)) { if (length(char_v) == 1) { char_v <- rep(char_v, max_tree_depth - 1) # -1 is the data row } # Case where char_v is longer than the max depth char_v <- char_v[seq_len(min(max_tree_depth, length(char_v)))] # Filling up with NAs the rest of the tree depth section div chr vector missing_char_v_len <- max_tree_depth - length(char_v) char_v <- c(char_v, rep(NA_character_, missing_char_v_len)) # char_v <- unlist( # lapply(tree_depths, function(tree_depth_i) char_v[seq_len(tree_depth_i)]), # use.names = FALSE # ) } # Retrieving if it is a contentRow (no need for labelrow to be visible in this case) content_row_tbl <- content_table(obj) is_content_table <- isS4(content_row_tbl) && nrow(content_row_tbl) > 0 # Main table structure change if (labelrow_visible(obj) || is_content_table) { if (only_sep_sections) { # Only tables are modified trailing_section_div(tt_labelrow(obj)) <- NA_character_ trailing_section_div(obj) <- char_v[1] section_div(tree_children(obj), only_sep_sections = only_sep_sections) <- char_v[-1] } else { # All leaves are modified trailing_section_div(tt_labelrow(obj)) <- char_v[1] trailing_section_div(obj) <- NA_character_ section_div(tree_children(obj), only_sep_sections = only_sep_sections) <- char_v[-1] } } else { section_div(tree_children(obj), only_sep_sections = only_sep_sections) <- char_v } obj })"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_printing.html","id":"disclaimer","dir":"Articles > Dev-guide","previous_headings":"","what":"Disclaimer","title":"Printing Machinery","text":"comparison entries developer guide, intended keep track general concepts processing pipeline behind printing machinery. intended complete documentation machinery , rather collection notes can used understand machinery internals. Hence, aware working document captures snapshot machinery certain point time. meant fully maintained, can used starting point one. Compared parts developer guide, contain current state rlistings’ printing machinery, often simplified version machinery used rtables.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_printing.html","id":"how-print-works","dir":"Articles > Dev-guide","previous_headings":"Disclaimer","what":"How print works","title":"Printing Machinery","text":"Lets track going hood standard table printed. following code executed table printed: see also layout object (PreDataTableLayouts) created printed. print generic function dispatches different methods depending class object. case, S4 class object PreDataTableLayouts method called print. case {rtables} method dispatched towards show method class PreDataTableLayouts. can found searching Pre-data Table Layout {rtables} source code. think R dispatcher print methods looks show S4 methods instead S3 S4 print methods available. Indeed, code executed: evident searched methods associated class PreDataTableLayouts, show connected sort printing machinery: Now, lets see result table tbl: , class show method. Nonetheless, search VTableTree\" find print method TableTree class. VTableTree virtual class inherited TableTree almost identical show method TableTree objects. different statements case (show print) thing, .e. call toString cat object. Hence, know every table printed toString \\n separator different lines cat renders final format.","code":"library(rtables) # Loading required package: formatters # # Attaching package: 'formatters' # The following object is masked from 'package:base': # # %||% # Loading required package: magrittr # # Attaching package: 'rtables' # The following object is masked from 'package:utils': # # str library(dplyr) # # Attaching package: 'dplyr' # The following objects are masked from 'package:stats': # # filter, lag # The following objects are masked from 'package:base': # # intersect, setdiff, setequal, union lyt <- basic_table() %>% split_rows_by(\"SEX\", split_fun = keep_split_levels(c(\"F\", \"M\"))) %>% split_cols_by(\"ARM\") %>% analyze(\"BMRKR1\") %>% print() # A Pre-data Table Layout # # Column-Split Structure: # ARM (lvls) # # Row-Split Structure: # SEX (lvls) -> BMRKR1 (** analysis **) tbl <- build_table(lyt, ex_adsl) %>% print() # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————— # F # Mean 5.75 5.59 5.68 # M # Mean 6.27 5.87 5.34 setMethod( \"show\", \"PreDataTableLayouts\", function(object) { cat(\"A Pre-data Table Layout\\n\") cat(\"\\nColumn-Split Structure:\\n\") docat_predataxis(object@col_layout) cat(\"\\nRow-Split Structure:\\n\") docat_predataxis(object@row_layout) cat(\"\\n\") invisible(object) } ) methods(class = \"PreDataTableLayouts\") # [1] .add_row_summary clayout clayout<- # [4] col_exprs colcount_format colcount_format<- # [7] coltree header_section_div header_section_div<- # [10] main_footer main_footer<- main_title # [13] main_title<- prov_footer prov_footer<- # [16] show subtitles subtitles<- # [19] table_inset table_inset<- top_left # [22] top_left<- top_level_section_div top_level_section_div<- # [25] vars_in_layout # see '?methods' for accessing help and source code class(tbl) %>% print() # [1] \"TableTree\" # attr(,\"package\") # [1] \"rtables\" getClass(\"TableTree\") %>% print() # Main object representing a table in {rtables} # Class \"TableTree\" [package \"rtables\"] # # Slots: # # Name: content page_title_prefix children # Class: ElementaryTable character list # # Name: rowspans labelrow page_titles # Class: data.frame LabelRow character # # Name: horizontal_sep header_section_div trailing_section_div # Class: character character character # # Name: col_info format na_str # Class: InstantiatedColumnInfo FormatSpec character # # Name: indent_modifier table_inset level # Class: integer integer integer # # Name: name main_title subtitles # Class: character character character # # Name: main_footer provenance_footer # Class: character character # # Extends: # Class \"VTableTree\", directly # Class \"VTableNodeInfo\", by class \"VTableTree\", distance 2 # Class \"VTree\", by class \"VTableTree\", distance 2 # Class \"VTitleFooter\", by class \"VTableTree\", distance 2 # Class \"VNodeInfo\", by class \"VTableTree\", distance 3 methods(class = \"TableTree\") %>% print() # more than 70 methods but no print method # [1] [ [<- as.vector # [4] cell_footnotes cell_values clayout # [7] clear_indent_mods col_counts col_counts<- # [10] col_footnotes col_info col_info<- # [13] col_total col_total<- colcount_format # [16] colcount_format<- colcount_na_str colcount_na_str<- # [19] colcount_visible colcount_visible<- collect_leaves # [22] coltree content_table content_table<- # [25] dim do_forced_paginate facet_colcount # [28] facet_colcount<- fnotes_at_path<- get_formatted_cells # [31] head header_section_div header_section_div<- # [34] horizontal_sep horizontal_sep<- indent_mod # [37] indent_mod<- insert_row_at_path main_footer # [40] main_footer<- main_title main_title<- # [43] make_row_df matrix_form names # [46] ncol no_colinfo nrow # [49] obj_format obj_format<- obj_label # [52] obj_label<- obj_na_str obj_na_str<- # [55] obj_name obj_name<- page_titles # [58] page_titles<- prov_footer prov_footer<- # [61] rbind rbind2 rm_all_colcounts # [64] row_footnotes row.names section_div # [67] section_div<- show str # [70] subtitles subtitles<- table_inset # [73] table_inset<- tail top_left # [76] top_left<- toString tree_children # [79] tree_children<- tt_at_path tt_at_path<- # [82] value_at value_formats # see '?methods' for accessing help and source code"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_printing.html","id":"from-matrix_form-to-tostring","dir":"Articles > Dev-guide","previous_headings":"Disclaimer","what":"From matrix_form to toString","title":"Printing Machinery","text":"source code formatters, rtables, rlistings local can search \"toString\" S4 method definition across source folders. find generics formatters three different setMethod(...). toString properly defined formatters, also present rlistings andrtables. Let’s take look latter first. wrapper/dispatcher core toString function formatters, beside indent_size specification. based “rendering-ready” class MatrixPrintForm produced matrix_form. latter first core transformation need know understand printing process. exporters printers based MatrixPrintForm objects, hence bug problem needs tracked function toString. take look toString \"listing_df\" rlistings, find shallow wrapper dispatches MatrixPrintForm objects: Hence lets take look \"matrix_form\" (quotes, S4 function now ). Beside generics self calls (setMethod(\"matrix_form\", \"MatrixPrintForm\", [...] obj)), rlistings rtables “constructor” MatrixPrintForm (real one can found formatters). Let’s start latter \"matrix_form\" dispatched dealing VTableTrees. Now lets see newly commented code matrix_form. #-> comment suggestions understandings. Now lets see matrix_form rlistings: device good developer search understand various methods associated MatrixPrintForm objects. relevant remember printed form meant Let’s now take look final function : toString formatters: rely future developer fill blanks description follow various functions core mechanics.","code":"setMethod(\"toString\", \"VTableTree\", function(x, widths = NULL, col_gap = 3, hsep = horizontal_sep(x), indent_size = 2, tf_wrap = FALSE, max_width = NULL) { toString( matrix_form(x, indent_rownames = TRUE, indent_size = indent_size # Only modifies the rownames in matrix_form ), widths = widths, col_gap = col_gap, hsep = hsep, tf_wrap = tf_wrap, max_width = max_width ) }) setMethod(\"toString\", \"listing_df\", function(x, ...) { toString(matrix_form(x), ...) }) # Entering matrix_form for VTableTree trace(\"matrix_form\", signature = \"VTableTree\", tracer = browser, exit = browser) matrix_form(tbl) untrace(\"matrix_form\", signature = \"VTableTree\") setMethod( \"matrix_form\", \"VTableTree\", function(obj, indent_rownames = FALSE, expand_newlines = TRUE, indent_size = 2) { stopifnot(is(obj, \"VTableTree\")) #-> Read .tbl_header_mat and subfunctions (based largely on cinfo) it can help for understanding # column structure and how it is printed (we can add a description of this process xxx) # Note: it contains the display of column counts directives and specifics header_content <- .tbl_header_mat(obj) # first col are for row.names or topleft info nr_header <- nrow(header_content$body) # colcounts were added in .tbl_header_mat #-> As before, reading this function can help understanding how the content of the table is transformed # in row content and how the structure of the table is preserved in a compact manner. It is complex # function as it is a recursive one with the different dispatcher but following how different section_div # are printed (with the dedicated assignment function) can help understanding the table structure and its # row-wise transformation. # Summary of row contents - reprint_inds specifies which rows to reprint (hence the grouping) sr <- make_row_df(obj) # With get_formatted_cells we get relevant information inside the table tree body_content_strings <- if (NROW(sr) == 0) { character() } else { #-> get_formatted_cells is an interesting function to understand the structure of the table as # it is design to extract only the \"data\" of the table as strings. Note how the label rows are # taken from make_row_df instead. Check shell = TRUE afterwards to see how the format are retrieved. cbind(as.character(sr$label), get_formatted_cells(obj)) } formats_strings <- if (NROW(sr) == 0) { character() } else { cbind(\"\", get_formatted_cells(obj, shell = TRUE)) } #-> Here spans are extracted for each row. Spans are rarely modified beyond its standard values. # Takes the flatten spans for each row and repeats them according to the number elements tsptmp <- lapply(collect_leaves(obj, TRUE, TRUE), function(rr) { sp <- row_cspans(rr) rep(sp, times = sp) }) ## the 1 is for row labels body_spans <- if (nrow(obj) > 0) { cbind(1L, do.call(rbind, tsptmp)) } else { matrix(1, nrow = 0, ncol = ncol(obj) + 1) } body_aligns <- if (NROW(sr) == 0) { character() } else { cbind(\"left\", get_cell_aligns(obj)) #-> extracts align values for each cell } body <- rbind(header_content$body, body_content_strings) # Init column format for header (empty if not for column counts) hdr_fmt_blank <- matrix(\"\", nrow = nrow(header_content$body), ncol = ncol(header_content$body) ) # If column counts are displayed, add column count format if (disp_ccounts(obj)) { hdr_fmt_blank[nrow(hdr_fmt_blank), ] <- c(\"\", rep(colcount_format(obj), ncol(obj))) } formats <- rbind(hdr_fmt_blank, formats_strings) spans <- rbind(header_content$span, body_spans) row.names(spans) <- NULL aligns <- rbind( matrix(rep(\"center\", length(header_content$body)), nrow = nrow(header_content$body) ), body_aligns ) aligns[, 1] <- \"left\" # row names and topleft (still needed for topleft) # Main indentation of the table rownames #-> Main indentation facility if (indent_rownames) { body[, 1] <- indent_string(body[, 1], c(rep(0, nr_header), sr$indent), incr = indent_size ) formats[, 1] <- indent_string(formats[, 1], c(rep(0, nr_header), sr$indent), incr = indent_size ) } #-> referential strings are added to the table. get_ref_matrix is the core of this process # along with format_fnote_ref that in this case is used to format the reference string and their # indices. Note that the footnotes for the header is taken from the output of .tbl_header_mat # Handling of references in header and body col_ref_strs <- matrix(vapply(header_content$footnotes, function(x) { if (length(x) == 0) { \"\" } else { paste(vapply(x, format_fnote_ref, \"\"), collapse = \" \") } }, \"\"), ncol = ncol(body)) body_ref_strs <- get_ref_matrix(obj) body <- matrix( paste0( body, rbind( col_ref_strs, #-> col_ref_strs are added to the body as a separate section body_ref_strs ) ), nrow = nrow(body), ncol = ncol(body) ) # Solve \\n in titles # This is something that is relevant in toString - NO MORE USED HERE # if (any(grepl(\"\\n\", all_titles(obj)))) { # if (any(grepl(\"\\n\", main_title(obj)))) { # tmp_title_vec <- .quick_handle_nl(main_title(obj)) # main_title(obj) <- tmp_title_vec[1] # subtitles(obj) <- c(tmp_title_vec[-1], .quick_handle_nl(subtitles(obj))) # } else { # subtitles(obj) <- .quick_handle_nl(subtitles(obj)) # } # } # # # Solve \\n in footers # main_footer(obj) <- .quick_handle_nl(main_footer(obj)) # prov_footer(obj) <- .quick_handle_nl(prov_footer(obj)) #-> this is still under development as indicated by xxx. The idea is to allow \\n also in peculiar # cases, such as page titles and referential footnotes. The latter are resolved in toString (pagination # will not count them as more than one line each), while for the former we do not have any coverage yet. # xxx \\n in page titles are not working atm (I think) # ref_fnotes <- strsplit(get_formatted_fnotes(obj), \"\\n\", fixed = TRUE) ref_fnotes <- get_formatted_fnotes(obj) # pagination will not count extra lines coming from here pag_titles <- page_titles(obj) MatrixPrintForm( strings = body, #-> FUNDAMENTAL: this is the matrix that contains all the cell strings spans = spans, aligns = aligns, formats = formats, ## display = display, purely a function of spans, handled in constructor now row_info = sr, #-> FUNDAMENTAL: this is the data.frame that contains all the information about the rows # it is the most complex data brought forward into toString ## line_grouping handled internally now line_grouping = 1:nrow(body), ref_fnotes = ref_fnotes, nlines_header = nr_header, ## this is fixed internally nrow_header = nr_header, expand_newlines = expand_newlines, has_rowlabs = TRUE, has_topleft = TRUE, #-> I think topleft material is handled later in toString main_title = main_title(obj), subtitles = subtitles(obj), page_titles = pag_titles, main_footer = main_footer(obj), prov_footer = prov_footer(obj), table_inset = table_inset(obj), header_section_div = header_section_div(obj), horizontal_sep = horizontal_sep(obj), indent_size = indent_size ) } ) library(rlistings) lsting <- as_listing(mtcars) trace(\"matrix_form\", signature = \"listing_df\", tracer = browser, exit = browser) mf <- matrix_form(lsting) untrace(\"matrix_form\", signature = \"listing_df\") setMethod( \"matrix_form\", \"listing_df\", rix_form <- function(obj, indent_rownames = FALSE) { #-> I have no idea why here there is an assignment xxx ## we intentionally silently ignore indent_rownames because listings have ## no rownames, but formatters::vert_pag_indices calls matrix_form(obj, TRUE) ## unconditionally. # Keeping only displayed columns cols <- attr(obj, \"listing_dispcols\") # this is the list of columns to be displayed listing <- obj[, cols] atts <- attributes(obj) atts$names <- cols attributes(listing) <- atts keycols <- get_keycols(listing) bodymat <- matrix(\"\", nrow = nrow(listing), ncol = ncol(listing) ) colnames(bodymat) <- names(listing) # Print only first appearer of key columns if repeated curkey <- \"\" for (i in seq_along(keycols)) { kcol <- keycols[i] kcolvec <- listing[[kcol]] #-> format_value transforms the values of the column into strings kcolvec <- vapply(kcolvec, format_value, \"\", format = obj_format(kcolvec), na_str = obj_na_str(kcolvec)) curkey <- paste0(curkey, kcolvec) disp <- c(TRUE, tail(curkey, -1) != head(curkey, -1)) #-> This condition only show the first appearer of a key bodymat[disp, kcol] <- kcolvec[disp] } # Print all other columns directly nonkeycols <- setdiff(names(listing), keycols) if (length(nonkeycols) > 0) { for (nonk in nonkeycols) { vec <- listing[[nonk]] vec <- vapply(vec, format_value, \"\", format = obj_format(vec), na_str = obj_na_str(vec)) bodymat[, nonk] <- vec } } fullmat <- rbind( var_labels(listing, fill = TRUE), # Extracts the variable labels bodymat ) colaligns <- rbind( rep(\"center\", length(cols)), # Col names are always centered? matrix(sapply(listing, obj_align), ncol = length(cols), nrow = nrow(fullmat) - 1, byrow = TRUE ) ) MatrixPrintForm( strings = fullmat, spans = matrix(1, nrow = nrow(fullmat), ncol = ncol(fullmat) ), ref_fnotes = list(), aligns = colaligns, formats = matrix(1, nrow = nrow(fullmat), ncol = ncol(fullmat) ), row_info = make_row_df(obj), nlines_header = 1, ## XXX this is probably wrong!!! nrow_header = 1, has_topleft = FALSE, has_rowlabs = FALSE, expand_newlines = TRUE, # Always expand newlines, but this happens later!! XXX to fix main_title = main_title(obj), subtitles = subtitles(obj), page_titles = page_titles(obj), main_footer = main_footer(obj), prov_footer = prov_footer(obj) ) } ) # Example quick table summary_list <- function(x, ...) as.list(summary(x)) a_table <- qtable(ex_adsl, row_vars = \"SEX\", col_vars = \"ARM\", avar = \"AGE\", afun = summary_list) tbl_methods <- methods(class = class(a_table)) mpf_methods <- methods(class = class(matrix_form(a_table))[1]) # it is a list of values # Cleaning values tbl_methods <- unique(sapply(strsplit(tbl_methods, \",\"), function(x) x[1])) mpf_methods <- unique(sapply(strsplit(mpf_methods, \",\"), function(x) x[1])) setdiff(tbl_methods, mpf_methods) # [1] \"[\" \"as.vector\" \"cell_footnotes\" # [4] \"cell_values\" \"clayout\" \"clear_indent_mods\" # [7] \"col_counts\" \"col_counts<-\" \"col_footnotes\" # [10] \"col_info\" \"col_info<-\" \"col_total\" # [13] \"col_total<-\" \"colcount_format\" \"colcount_format<-\" # [16] \"colcount_na_str\" \"colcount_na_str<-\" \"colcount_visible\" # [19] \"colcount_visible<-\" \"collect_leaves\" \"coltree\" # [22] \"content_table\" \"content_table<-\" \"dim\" # [25] \"do_forced_paginate\" \"facet_colcount\" \"facet_colcount<-\" # [28] \"fnotes_at_path<-\" \"get_formatted_cells\" \"head\" # [31] \"header_section_div\" \"header_section_div<-\" \"horizontal_sep\" # [34] \"horizontal_sep<-\" \"indent_mod\" \"indent_mod<-\" # [37] \"insert_row_at_path\" \"names\" \"no_colinfo\" # [40] \"nrow\" \"obj_format\" \"obj_format<-\" # [43] \"obj_label\" \"obj_label<-\" \"obj_na_str\" # [46] \"obj_na_str<-\" \"obj_name\" \"obj_name<-\" # [49] \"rbind\" \"rbind2\" \"rm_all_colcounts\" # [52] \"row_footnotes\" \"row.names\" \"show\" # [55] \"str\" \"tail\" \"top_left\" # [58] \"top_left<-\" \"tree_children\" \"tree_children<-\" # [61] \"tt_at_path\" \"tt_at_path<-\" \"value_at\" # [64] \"value_formats\" setdiff(mpf_methods, tbl_methods) # much less unique methods # [1] \"coerce\" \"coerce<-\" \"nlines\" \"num_rep_cols\" # [5] \"num_rep_cols<-\" \"Ops\" \"rawvalues\" \"value_names\" intersect(tbl_methods, mpf_methods) # interesting to discover the different behaviors of same functions # [1] \"[<-\" \"main_footer\" \"main_footer<-\" \"main_title\" # [5] \"main_title<-\" \"make_row_df\" \"matrix_form\" \"ncol\" # [9] \"page_titles\" \"page_titles<-\" \"prov_footer\" \"prov_footer<-\" # [13] \"section_div\" \"section_div<-\" \"subtitles\" \"subtitles<-\" # [17] \"table_inset\" \"table_inset<-\" \"toString\" setMethod(\"toString\", \"MatrixPrintForm\", function(x, widths = NULL, tf_wrap = FALSE, max_width = NULL, col_gap = mf_colgap(x), hsep = NULL, fontspec = font_spec(), ttype_ok = FALSE) { # part 1: checks and widths/max width estimation for columns - propose_column_widths and .handle_max_width # # part 2: wrapping for the table - do_cell_fnotes_wrap # # part 3: column gap and cell widths calculations (after wrapping) - .calc_cell_widths # # part 4: collapse text body and wrapping titles/footers # # part 5: final cat() })"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"disclaimer","dir":"Articles > Dev-guide","previous_headings":"","what":"Disclaimer","title":"Split Machinery","text":"article intended use developers contain low-level explanations topics covered. user-friendly vignettes, please see Articles page rtables website. code prose appears version article main branch repository may reflect specific state things can less recent. guide describes important pieces split machinery unlikely change. Regardless, invite reader keep mind current repository code may drifted following material document, always best practice read code directly main. Please keep mind rtables still active development, seen efforts multiple contributors across different years. Therefore, may legacy mechanisms ongoing transformations look different future. working document may subjected deprecation updates, keep xxx comments indicate placeholders warnings -’s need work.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"introduction","dir":"Articles > Dev-guide","previous_headings":"","what":"Introduction","title":"Split Machinery","text":"scope article understanding rtables creates facets splitting incoming data hierarchical groups go root node singular rcells. latter level, also called leaf-level, contains final partition subjected analysis functions. details user perspective can found Split Functions vignette function documentation like ?split_rows_by ?split_funcs. following article describe split machinery works row domain. information split machinery works column domain covered separate article.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"process-and-methods","dir":"Articles > Dev-guide","previous_headings":"","what":"Process and Methods","title":"Split Machinery","text":"Beforehand, encourage reader familiarize Debugging {rtables} article rtables Developers Guide. document generally valid R programming, tailored study understand complex packages rely heavily S3 S4 object programming like rtables. , explore study split machinery growing amount complexity, following relevant functions methods throughout execution. going basic complex discussing important special cases, hope able give good understanding split machinery works. practice, majority split engine resides source file R/split_funs.R, occasional incursion R/make_split_fun.R custom split function creation rarer references general tabulation files.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"do_split","dir":"Articles > Dev-guide","previous_headings":"","what":"do_split","title":"Split Machinery","text":"split machinery fundamental rtables relevant functions like do_split executed even split requested. following example shows can enter do_split start understanding class hierarchy main split engine. following code, copied do_split function code allow reader go general structure enhanced comments sections. section code reflects roughly one section article. see input parameters used. important parameters spl df - split objects input data.frame, respectively.","code":"library(rtables) # debugonce(rtables:::do_split) # Uncomment me to enter the function!!! basic_table() %>% build_table(DM) ## all obs ## —————————— # rtables 0.6.2 ### NB This is called at EACH level of recursive splitting do_split <- function(spl, df, vals = NULL, labels = NULL, trim = FALSE, spl_context) { # - CHECKS - # ## This will error if, e.g., df does not have columns ## required by spl, or generally any time the split (spl) ## can not be applied to df check_validsplit(spl, df) # - SPLIT FUNCTION - # ## In special cases, we need to partition data (split) ## in a very specific way, e.g. depending on the data or ## external values. These can be achieved by using a custom ## split function. ## note the <- here!!! if (!is.null(splfun <- split_fun(spl))) { ## Currently split functions take df, vals, labels and ## return list(values = ..., datasplit = ..., labels = ...), ## with an optional additional 'extras' element if (func_takes(splfun, \".spl_context\")) { ret <- tryCatch( splfun(df, spl, vals, labels, trim = trim, .spl_context = spl_context ), error = function(e) e ) ## rawvalues(spl_context)) } else { ret <- tryCatch(splfun(df, spl, vals, labels, trim = trim), error = function(e) e ) } if (is(ret, \"error\")) { stop( \"Error applying custom split function: \", ret$message, \"\\n\\tsplit: \", class(spl), \" (\", payloadmsg(spl), \")\\n\", \"\\toccured at path: \", spl_context_to_disp_path(spl_context), \"\\n\" ) } } else { # - .apply_split_inner - # ## This is called when no split function is provided. Please note that this function ## will also probably be called when the split function is provided, as long as the ## main splitting method is not willingly modified by the split function. ret <- .apply_split_inner(df = df, spl = spl, vals = vals, labels = labels, trim = trim) } # - EXTRA - # ## this adds .ref_full and .in_ref_col if (is(spl, \"VarLevWBaselineSplit\")) { ret <- .add_ref_extras(spl, df, ret) } # - FIXUPVALS - # ## This: ## - guarantees that ret$values contains SplitValue objects ## - removes the extras element since its redundant after the above ## - ensures datasplit and values lists are named according to labels ## - ensures labels are character not factor ret <- .fixupvals(ret) # - RETURN - # ret }"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"checks-and-classes","dir":"Articles > Dev-guide","previous_headings":"do_split","what":"Checks and Classes","title":"Split Machinery","text":"start looking first function called do_split. give us good overview split defined. function , course, check function (check_validsplit) used verify split valid data. following describe split-class hierarchy step--step, invite reader explore well. Let’s first search package check_validsplit. find defined generic R/split_funs.R, applied following “split” classes: VarLevelSplit, MultiVarSplit, VAnalyzeSplit, CompoundSplit, Split. Another way find information, useful spread complicated objects, using showMethods(check_validsplit). virtual class VAnalyzeSplit (convention virtual classes start “V”) defines main parent analysis split discuss detail related vignette vignette() (xxx). , can see analyze() calls actually mimic split objects create different results specific final split (node). Now, notice check_validsplit also called another location, main R/tt_dotabulation.R source file. something related making “analyze” rows mainly checks VAnalyzeSplit. See Tabulation article details. discuss classes appear examples. See class hierarchy Table Hierarchy article. moment, see class(spl) (main do_split function) dealing AllSplit object. calling showMethods(check_validsplit) produce following: means listed classes dedicated definition check_validsplit may largely differ others. class AllSplit function definition inherited Split class. Therefore, understand AllSplit parent class Split. one first definitions virtual class package one include “V” prefix. classes defined along constructors R/00tabletrees.R. Reading AllSplit structured can useful understanding split objects expected work. Please see comments following: can also print information calling getClass(\"AllSplit\") general slot definition, calling getClass(spl). Note first call give also lot information class hierarchy. information regarding class hierarchy, please refer relevant article . discuss majority slots end document. Now, let’s see can find values described constructor within object. , show compact representation given str. multiple hierarchical slots contain objects , calling str much less informative maximum level nesting set (e.g. max.level = 2). Details slots become necessary future examples, deal time. Now, gave hint complex class hierarchy makes rtables, explore autonomously. Let’s go forward do_split. case, AllSplit inherited Split, sure called function following (read comment!):","code":"# rtables 0.6.2 Function: check_validsplit (package rtables) spl=\"AllSplit\" (inherited from: spl=\"Split\") spl=\"CompoundSplit\" spl=\"MultiVarSplit\" spl=\"Split\" spl=\"VAnalyzeSplit\" spl=\"VarLevelSplit\" # rtables 0.6.2 setClass(\"AllSplit\", contains = \"Split\") AllSplit <- function(split_label = \"\", cfun = NULL, cformat = NULL, cna_str = NA_character_, split_format = NULL, split_na_str = NA_character_, split_name = NULL, extra_args = list(), indent_mod = 0L, cindent_mod = 0L, cvar = \"\", cextra_args = list(), ...) { if (is.null(split_name)) { # If the split has no name if (nzchar(split_label)) { # (std is \"\") split_name <- split_label } else { split_name <- \"all obs\" # No label, a standard split with all # observations is assigned. } } new(\"AllSplit\", split_label = split_label, content_fun = cfun, content_format = cformat, content_na_str = cna_str, split_format = split_format, split_na_str = split_na_str, name = split_name, label_children = FALSE, extra_args = extra_args, indent_modifier = as.integer(indent_mod), content_indent_modifier = as.integer(cindent_mod), content_var = cvar, split_label_position = \"hidden\", content_extra_args = cextra_args, page_title_prefix = NA_character_, child_section_div = NA_character_ ) } # rtables 0.6.2 Browse[2]> str(spl, max.level = 2) Formal class 'AllSplit' [package \"rtables\"] with 17 slots ..@ payload : NULL ..@ name : chr \"all obs\" ..@ split_label : chr \"\" ..@ split_format : NULL ..@ split_na_str : chr NA ..@ split_label_position : chr \"hidden\" ..@ content_fun : NULL ..@ content_format : NULL ..@ content_na_str : chr NA ..@ content_var : chr \"\" ..@ label_children : logi FALSE ..@ extra_args : list() ..@ indent_modifier : int 0 ..@ content_indent_modifier: int 0 ..@ content_extra_args : list() ..@ page_title_prefix : chr NA ..@ child_section_div : chr NA # rtables 0.6.2 ## Default does nothing, add methods as they become required setMethod( \"check_validsplit\", \"Split\", function(spl, df) invisible(NULL) )"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"split-functions-and--apply_split_inner","dir":"Articles > Dev-guide","previous_headings":"do_split","what":"Split Functions and .apply_split_inner","title":"Split Machinery","text":"diving custom split functions, need take moment analyze .apply_split_inner works. function routinely called whether split function. Let’s see case entering debugonce(.apply_split_inner). course, still currently browsing within do_split debug mode first example. print comment function following: reading .apply_split_inner, see fundamental functions - defined strictly internal use (convention start “.”) - generics depend kind split input. R/split_funs.R kind groups generic definitions beginning file. functions main dispatchers majority split machinery. clear example shows using S4 logic enables better clarity flexibility programming, allowing easy extension program. compactness also show showMethods result generic. Now, know .applysplit_extras function called first. specify vals therefore NULL. S4 generic function can seen showMethod(.applysplit_extras), definition can seen following: .applysplit_extras, simply extracts extra arguments split objects assigns relative split values. function covered detail later section. still split values available, function exit empty split. Otherwise, data divided different splits data subsets (facets) .applysplit_datapart. current example, resulting list comprises whole input dataset (getMethod(\".applysplit_datapart\", \"AllSplit\") list evident: function (spl, df, vals) list(df)). Next, split labels checked. present, split values (vals) used .applysplit_partlabels, transformed .character(vals) applied Split object. Otherwise, inserted labels checked names split values. Lastly, split values ordered according spl_child_order. case, concerns general AllSplit, sorting happen, .e. dependent simply number split values (seq_along(vals)).","code":"# rtables 0.6.2 .apply_split_inner <- function(spl, df, vals = NULL, labels = NULL, trim = FALSE) { # - INPUTS - # # In this case .applysplit_rawvals will attempt to find the split values if vals is NULL. # Please notice that there may be a non-mutually exclusive set or subset of elements that # will constitute the split. # - SPLIT VALS - # ## Try to calculate values first - most of the time we can if (is.null(vals)) { vals <- .applysplit_rawvals(spl, df) } # - EXTRA PARAMETERS - # # This call extracts extra parameters from the split, according to the split values extr <- .applysplit_extras(spl, df, vals) # If there are no values to do the split upon, we return an empty final split if (is.null(vals)) { return(list( values = list(), datasplit = list(), labels = list(), extras = list() )) } # - DATA SUBSETTING - # dpart <- .applysplit_datapart(spl, df, vals) # - LABEL RETRIEVAL - # if (is.null(labels)) { labels <- .applysplit_partlabels(spl, df, vals, labels) } else { stopifnot(names(labels) == names(vals)) } # - TRIM - # ## Get rid of columns that would not have any observations, ## but only if there were any rows to start with - if not ## we're in a manually constructed table column tree if (trim) { hasdata <- sapply(dpart, function(x) nrow(x) > 0) if (nrow(df) > 0 && length(dpart) > sum(hasdata)) { # some empties dpart <- dpart[hasdata] vals <- vals[hasdata] extr <- extr[hasdata] labels <- labels[hasdata] } } # - ORDER RESULTS - # # Finds relevant order depending on spl_child_order() if (is.null(spl_child_order(spl)) || is(spl, \"AllSplit\")) { vord <- seq_along(vals) } else { vord <- match( spl_child_order(spl), vals ) vord <- vord[!is.na(vord)] } ## FIXME: should be an S4 object, not a list ret <- list( values = vals[vord], datasplit = dpart[vord], labels = labels[vord], extras = extr[vord] ) ret } # rtables 0.6.2 # Retrieves the values that will constitute the splits (facets), not necessarily a unique list. # They could come from the data cuts for example -> it can be anything that produces a set of strings. setGeneric( \".applysplit_rawvals\", function(spl, df) standardGeneric(\".applysplit_rawvals\") ) # Browse[2]> showMethods(.applysplit_rawvals) # Function: .applysplit_rawvals (package rtables) # spl=\"AllSplit\" # spl=\"ManualSplit\" # spl=\"MultiVarSplit\" # spl=\"VAnalyzeSplit\" # spl=\"VarLevelSplit\" # spl=\"VarStaticCutSplit\" # Nothing here is inherited from the virtual class Split!!! # Contains the subset of the data (default, but these can overlap and can also NOT be mutually exclusive). setGeneric( \".applysplit_datapart\", function(spl, df, vals) standardGeneric(\".applysplit_datapart\") ) # Same as .applysplit_rawvals # Extract the extra parameter for the split setGeneric( \".applysplit_extras\", function(spl, df, vals) standardGeneric(\".applysplit_extras\") ) # Browse[2]> showMethods(.applysplit_extras) # Function: .applysplit_extras (package rtables) # spl=\"AllSplit\" # (inherited from: spl=\"Split\") # spl=\"Split\" # This means there is only a function for the virtual class Split. # So all splits behave the same!!! # Split label retrieval and assignment if visible. setGeneric( \".applysplit_partlabels\", function(spl, df, vals, labels) standardGeneric(\".applysplit_partlabels\") ) # Browse[2]> showMethods(.applysplit_partlabels) # Function: .applysplit_partlabels (package rtables) # spl=\"AllSplit\" # (inherited from: spl=\"Split\") # spl=\"MultiVarSplit\" # spl=\"Split\" # spl=\"VarLevelSplit\" setGeneric( \"check_validsplit\", # our friend function(spl, df) standardGeneric(\"check_validsplit\") ) # Note: check_validsplit is an internal function but may one day be exported. # This is why it does not have the \".\" prefix. setGeneric( \".applysplit_ref_vals\", function(spl, df, vals) standardGeneric(\".applysplit_ref_vals\") ) # Browse[2]> showMethods(.applysplit_ref_vals) # Function: .applysplit_ref_vals (package rtables) # spl=\"Split\" # spl=\"VarLevWBaselineSplit\" # rtables 0.6.2 Browse[3]> getMethod(\".applysplit_rawvals\", \"AllSplit\") Method Definition: function (spl, df) obj_name(spl) Signatures: spl target \"AllSplit\" defined \"AllSplit\" # What is obj_name -> slot in spl Browse[3]> obj_name(spl) [1] \"all obs\" # coming from Browse[3]> getMethod(\"obj_name\", \"Split\") Method Definition: function (obj) obj@name ##### Slot that we could see from str(spl, max.level = 2) Signatures: obj target \"Split\" defined \"Split\""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"a-simple-split","dir":"Articles > Dev-guide","previous_headings":"","what":"A Simple Split","title":"Split Machinery","text":"following, demonstrate row splits work using features already described. add two splits see behavior do_split changes. Note add analyze call split behave , giving empty table observations. default, calling analyze variable calculate mean data subset generated splits. want go beyond first call do_split design applied observations, purpose generating root split contains data splits (indeed AllSplit). achieve use debug(rtables:::do_split) instead debugonce(rtables:::do_split) need step splits. Alternatively, possible use powerful trace function enter cases input specific class. , following can used: trace(\"do_split\", quote((!(spl, \"AllSplit\")) browser()), = asNamespace(\"rtables\")). Note specify namespace . Multiple tracer elements can added expression(E1, E2), c(quote(E1), quote(E2)). Specific steps can specified parameter. Remember call untrace(\"do_split\", quote((!(spl, \"AllSplit\")) browser()), = asNamespace(\"rtables\")) finished remove trace. continuing, want check formal class spl. , can directly infer class different now (VarLevelSplit) understand split label hidden (split_label_position slot). Moreover, see specific value order specific split values. VarLevelSplit also seems three slots AllSplit. precisely? Remember always check constructor class definition R/00tabletrees.R exploratory tools suffice. Now, check_validsplit(spl, df) use different method (getMethod(\"check_validsplit\", \"VarLevelSplit\")). uses internal utility function .checkvarsok check vars, .e. payload, actually present names(df). next relevant function .apply_split_inner, exactly changes using debugonce(.apply_split_inner). course, function called directly custom split function provided. Since parameter vals specified (NULL), split values retrieved df using split payload select specific columns (varvec <- df[[spl_payload(spl)]]). Whenever split values specified retrieved selected column unique values (character) levels (factor). Next, .applysplit_datapart creates named list facets data subsets. case, result actually mutually exclusive partition data. specify split values column content retrieved via unique (case character vector) levels (case factors). .applysplit_partlabels bit less linear take account possibility specified labels payload. Instead looking function source code getMethod(\".applysplit_partlabels\", \"VarLevelSplit\"), can enter S4 generic function debugging mode follows: case, final labels vals explicitly assigned. order retrieved split object (spl_child_order(spl)) matched current split values. returned list processed . continue next call do_split, procedure followed second ARM split. applied partition created first split. main df now constituted subset (facet) total data, determined first split. repeated iteratively many data splits requested. concluding iteration, take moment discuss detail .fixupvals(partinfo) works. generic function source code can easily accessed. suggest running debugonce(.fixupvals) understand practice. fundamental aspects .fixupvals(partinfo) follows: Ensures labels character factor. Ensures splits data list values named according labels. Guarantees ret$values contains SplitValue objects. Removes list element extra since now included SplitValue. Note function can occasionally called return object (named list now). course, first call checks applied.","code":"# rtables 0.6.2 library(rtables) library(dplyr) # This filter is added to avoid having too many calls to do_split DM_tmp <- DM %>% filter(ARM %in% names(table(DM$ARM)[1:2])) %>% # limit to two filter(SEX %in% c(\"M\", \"F\")) %>% # limit to two mutate(SEX = factor(SEX), ARM = factor(ARM)) # to drop unused levels # debug(rtables:::do_split) lyt <- basic_table() %>% split_rows_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(\"BMRKR1\") # analyze() is needed for the table to have non-label rows lyt %>% build_table(DM_tmp) ## all obs ## ———————————————————— ## A: Drug X ## F ## Mean 6.06 ## M ## Mean 5.42 ## B: Placebo ## F ## Mean 6.24 ## M ## Mean 5.97 # undebug(rtables:::do_split) # rtables 0.6.2 Browse[2]> str(spl, max.level = 2) Formal class 'VarLevelSplit' [package \"rtables\"] with 20 slots ..@ value_label_var : chr \"ARM\" ..@ value_order : chr [1:2] \"A: Drug X\" \"B: Placebo\" ..@ split_fun : NULL ..@ payload : chr \"ARM\" ..@ name : chr \"ARM\" ..@ split_label : chr \"ARM\" ..@ split_format : NULL ..@ split_na_str : chr NA ..@ split_label_position : chr \"hidden\" ..@ content_fun : NULL ..@ content_format : NULL ..@ content_na_str : chr NA ..@ content_var : chr \"\" ..@ label_children : logi NA ..@ extra_args : list() ..@ indent_modifier : int 0 ..@ content_indent_modifier: int 0 ..@ content_extra_args : list() ..@ page_title_prefix : chr NA ..@ child_section_div : chr NA # rtables 0.6.2 slots_as <- getSlots(\"AllSplit\") # inherits virtual class Split and is general class for all splits # getClass(\"CustomizableSplit\") # -> Extends: \"Split\", Known Subclasses: Class \"VarLevelSplit\", directly slots_cs <- getSlots(\"CustomizableSplit\") # Adds split function slots_vls <- getSlots(\"VarLevelSplit\") slots_cs[!(names(slots_cs) %in% names(slots_as))] # split_fun # \"functionOrNULL\" slots_vls[!(names(slots_vls) %in% names(slots_cs))] # value_label_var value_order # \"character\" \"ANY\" # rtables 0.6.2 eval(debugcall(.applysplit_partlabels(spl, df, vals, labels))) # We leave to the smart developer to see how the labels are assigned # Remember to undebugcall() similarly! # rtables 0.6.2 # Can find the following core function: # vals <- make_splvalue_vec(vals, extr, labels = labels) # ---> Main list of SplitValue objects: iterative call of # new(\"SplitValue\", value = val, extra = extr, label = label) # Structure of ret before calling .fixupvals Browse[2]> str(ret, max.level = 2) List of 4 $ values : chr [1:2] \"A: Drug X\" \"B: Placebo\" $ datasplit:List of 2 ..$ A: Drug X : tibble [121 × 8] (S3: tbl_df/tbl/data.frame) ..$ B: Placebo: tibble [106 × 8] (S3: tbl_df/tbl/data.frame) $ labels : Named chr [1:2] \"A: Drug X\" \"B: Placebo\" ..- attr(*, \"names\")= chr [1:2] \"A: Drug X\" \"B: Placebo\" $ extras :List of 2 ..$ : list() ..$ : list() # Structure of ret after the function call Browse[2]> str(.fixupvals(ret), max.level = 2) List of 3 $ values :List of 2 ..$ A: Drug X :Formal class 'SplitValue' [package \"rtables\"] with 3 slots ..$ B: Placebo:Formal class 'SplitValue' [package \"rtables\"] with 3 slots $ datasplit:List of 2 ..$ A: Drug X : tibble [121 × 8] (S3: tbl_df/tbl/data.frame) ..$ B: Placebo: tibble [106 × 8] (S3: tbl_df/tbl/data.frame) $ labels : Named chr [1:2] \"A: Drug X\" \"B: Placebo\" ..- attr(*, \"names\")= chr [1:2] \"A: Drug X\" \"B: Placebo\" # The SplitValue object is fundamental Browse[2]> str(ret$values) List of 2 $ A: Drug X :Formal class 'SplitValue' [package \"rtables\"] with 3 slots .. ..@ extra: list() .. ..@ value: chr \"A: Drug X\" .. ..@ label: chr \"A: Drug X\" $ B: Placebo:Formal class 'SplitValue' [package \"rtables\"] with 3 slots .. ..@ extra: list() .. ..@ value: chr \"B: Placebo\" .. ..@ label: chr \"B: Placebo\""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"pre-made-split-functions","dir":"Articles > Dev-guide","previous_headings":"A Simple Split","what":"Pre-Made Split Functions","title":"Split Machinery","text":"start examining split function already defined rtables. scope filtering specific values follows: root split, enter split based SEX. specified split function, can retrieve split function using splfun <- split_fun(spl) enter -else statement two possible cases: whether split context . cases, error catching framework used give informative errors case failure. Later see depth works. invite reader always keep eye spl_context, fundamental sophisticated splits, e.g. cases split depends mainly preceding splits values. split function called, please take moment look drop_split_levels defined. see function fundamentally wrapper .apply_split_inner drops empty factor levels, therefore avoiding empty splits. many pre-made split functions included rtables. list functions can found Split Functions vignette, via ?split_funcs. leave developer look split functions work, particular trim_levels_to_map may interest.","code":"library(rtables) # debug(rtables:::do_split) # uncomment to see into the main split function basic_table() %>% split_rows_by(\"SEX\", split_fun = drop_split_levels) %>% analyze(\"BMRKR1\") %>% build_table(DM) ## all obs ## ———————————————— ## F ## Mean 6.04 ## M ## Mean 5.64 # undebug(rtables:::do_split) # This produces the same output as before (when filters were used) # rtables 0.6.2 # > drop_split_levels function(df, spl, vals = NULL, labels = NULL, trim = FALSE) { # Retrieve split column var <- spl_payload(spl) df2 <- df ## This call is exactly the one we used when filtering to get rid of empty levels df2[[var]] <- factor(df[[var]]) ## Our main function! .apply_split_inner(spl, df2, vals = vals, labels = labels, trim = trim ) }"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"creating-custom-split-functions","dir":"Articles > Dev-guide","previous_headings":"A Simple Split","what":"Creating Custom Split Functions","title":"Split Machinery","text":"Now create custom split function. Firstly, see system manages error messages. general understanding custom split functions created, please read Custom Split Functions section Advanced Usage vignette see ?custom_split_funs. following code use browser() enter custom split functions. invite reader activate options(error = recover) investigate cases encounter error. Note can revert default behavior restarting R session, caching default option value, using callr retrieve default follows: default_opts <- callr::r(function(){options()}); options(error = default_opts$error). commented debugging lines allow inspect error. Alternatively, using recover option allow possibility select frame number, .e. trace level, enter. Selecting last frame number (10 case) allow see value ret rtables:::do_split causes error informative error message follows created. previous split function fails exploratory_split_fun given arguments accepts. simple way avoid add ... function call. Now let’s construct interesting split function (error): Now take moment dwell machinery included rtables create custom split functions. , please read relevant documentation ?make_split_fun. pre-made split functions included rtables written make_split_fun stable constructor functions previously used. invite reader take look make_split_fun.R. majority functions understandable knowledge gained guide far. important note core split function specified, commonly case, make_split_fun calls do_base_split directly, minimal wrapper well-known do_split. drop_facet_levels, example, pre-processing function core simply removes empty factor levels split “column”, thus avoiding showing empty lines. also possible provide list functions, can seen examples ?make_split_fun. Note pre- post-processing requires list input support possibility combining multiple functions. contrast, core splitting function must single function call expected stacked features. rarely needs modified majority included split functions work pre- post-processing. Included post-processing functions interesting interact split object, e.g. reordering facets adding overall facet (add_overall_facet). attentive reader noticed core function relies do_split many post-processing functions rely make_split_result, best way get correct split return structure. Note modifying core split works row space moment.","code":"# rtables 0.6.2 # Table call with only the function changing simple_table <- function(DM, f) { lyt <- basic_table() %>% split_rows_by(\"ARM\", split_fun = f) %>% analyze(\"BMRKR1\") lyt %>% build_table(DM) } # First round will fail because there are unused arguments exploratory_split_fun <- function(df, spl) NULL # debug(rtables:::do_split) err_msg <- tryCatch(simple_table(DM, exploratory_split_fun), error = function(e) e) # undebug(rtables:::do_split) message(err_msg$message) ## Error applying custom split function: unused arguments (vals, labels, trim = trim) ## split: VarLevelSplit (ARM) ## occured at path: root # rtables 0.6.2 # Debugging level 10: tt_dotabulation.R#627: do_split(spl, df, spl_context = spl_context) # Original call and final error > simple_table(DM, exploratory_split_fun) Error in do_split(spl, df, spl_context = spl_context) : Error applying custom split function: unused arguments (vals, labels, trim = trim) # This is main error split: VarLevelSplit (ARM) # Split reference occured at path: root # Path level (where it occurred) # rtables 0.6.2 f_brakes_if <- function(split_col = NULL, error = FALSE) { function(df, spl, ...) { # order matters! more than naming # browser() # To check how it works if (is.null(split_col)) { # Retrieves the default split_col <- spl_variable(spl) # Internal accessor to split obj } my_payload <- split_col # Changing split column value vals <- levels(df[[my_payload]]) # Extracting values to split datasplit <- lapply(seq_along(vals), function(i) { df[df[[my_payload]] == vals[[i]], ] }) names(datasplit) <- as.character(vals) # Error if (isTRUE(error)) { # browser() # If you need to check how it works mystery_error_values <- sapply(datasplit, function(x) mean(x$BMRKR1)) if (any(mystery_error_values > 6)) { stop( \"It should not be more than 6! Should it be? Found in split values: \", names(datasplit)[which(mystery_error_values > 6)] ) } } # Handy function to return a split result!! make_split_result(vals, datasplit, vals) } } simple_table(DM, f_brakes_if()) # works! ## all obs ## ———————————————————————— ## A: Drug X ## Mean 5.79 ## B: Placebo ## Mean 6.11 ## C: Combination ## Mean 5.69 simple_table(DM, f_brakes_if(split_col = \"STRATA1\")) # works! ## all obs ## ———————————————— ## A ## Mean 5.95 ## B ## Mean 5.90 ## C ## Mean 5.71 # simple_table(DM, f_brakes_if(error = TRUE)) # does not work, but returns an informative message # Error in do_split(spl, df, spl_context = spl_context) : # Error applying custom split function: It should not be more than 6! Should it be? Found in split values: B: Placebo # split: VarLevelSplit (ARM) # occurred at path: root"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"spl_context---adding-context-to-our-splits","dir":"Articles > Dev-guide","previous_headings":"A Simple Split > Creating Custom Split Functions","what":".spl_context - Adding Context to Our Splits","title":"Split Machinery","text":"best way understand split context , use , read Leveraging .spl_context section Advanced Usage vignette, use browser() within split function see structured. .spl_context needed rewriting core functions, propose wrapper do_base_split , handy redirection standard do_split without split function part (.e. wrapper .apply_split_inner, real core splitting machinery). curiosity, set trim = TRUE . trimming works mixed table (values 0s content), trim 0s. rarely case, encourage using replacement functions trim_levels_to_group trim_levels_to_map trimming. Nowadays, even impossible set differently trim = FALSE. (write issue informative error list xxx). can see split column variable (split, first column) level splitting procedure. value current split value dealt . next column, let’s see number rows data frames: sapply(.spl_context$full_parent_df, nrow) # [1] 356 121 36 36. Indeed, root level contains full input data frame, levels subgroups full data according split value. all_cols_n shows exactly numbers just described. obs current filter applied columns. Applying root data (row subgroup data) reveals current column-wise facet (row-wise row split). also possible use information make complex splits column space using full data frame value splits select interested values. something change simplify within rtables need becomes apparent.","code":"# rtables 0.6.2 browsing_f <- function(df, spl, .spl_context, ...) { # browser() # do_base_split(df, spl, ...) # order matters!! This would fail if done do_base_split(spl = spl, df = df, vals = NULL, labels = NULL, trim = TRUE) } fnc_tmp <- function(innervar) { # Exploring trim_levels_in_facets (check its form) function(ret, ...) { # browser() for (var in innervar) { # of course AGE is not here, so nothing is dropped!! ret$datasplit <- lapply(ret$datasplit, function(df) { df[[var]] <- factor(df[[var]]) df }) } ret } } basic_table() %>% split_rows_by(\"ARM\") %>% split_rows_by(\"STRATA1\") %>% split_rows_by_cuts(\"AGE\", cuts = c(0, 50, 100), cutlabels = c(\"young\", \"old\") ) %>% split_rows_by(\"SEX\", split_fun = make_split_fun( pre = list(drop_facet_levels), # This is dropping the SEX levels (AGE is upper level) core_split = browsing_f, post = list(fnc_tmp(\"AGE\")) # To drop these we should use a split_fun in the above level )) %>% summarize_row_groups() %>% build_table(DM) # The following is the .spl_contest printout: Browse[1]> .spl_context split value full_parent_df all_cols_n all obs 1 root root c(\"S1\", .... 356 TRUE, TR.... 2 ARM A: Drug X c(\"S6\", .... 121 TRUE, TR.... 3 STRATA1 A c(\"S14\",.... 36 TRUE, TR.... 4 AGE young c(\"S14\",.... 36 TRUE, TR.... # NOTE: make_split_fun(pre = list(drop_facet_levels)) and drop_split_levels # do the same thing in this case"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"extra-arguments-extra_args","dir":"Articles > Dev-guide","previous_headings":"A Simple Split","what":"Extra Arguments: extra_args","title":"Split Machinery","text":"functionality well-known used setting analysis functions (somewhat complicated example can found Example Complex Analysis Function vignette), show can also apply splits. demonstrated, seem like impossible cases considered vestigial deprecated.","code":"# rtables 0.6.2 # Let's use the tracer!! my_tracer <- quote(if (length(spl@extra_args) > 0) browser()) trace( what = \"do_split\", tracer = my_tracer, where = asNamespace(\"rtables\") ) custom_mean_var <- function(var) { function(df, labelstr, na.rm = FALSE, ...) { # browser() mean(df[[var]], na.rm = na.rm) } } DM_ageNA <- DM DM_ageNA$AGE[1] <- NA basic_table() %>% split_rows_by(\"ARM\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels) %>% summarize_row_groups( cfun = custom_mean_var(\"AGE\"), extra_args = list(na.rm = TRUE), format = \"xx.x\", label_fstr = \"label %s\" ) %>% # content_extra_args, c_extra_args are different slots!! (xxx) split_rows_by(\"STRATA1\", split_fun = keep_split_levels(\"A\")) %>% analyze(\"AGE\") %>% # check with the extra_args (xxx) build_table(DM_ageNA) # You can pass extra_args down to other splits. It is possible this will not not # work. Should it? That is why extra_args lives only in splits (xxx) check if it works # as is. Difficult to find an use case for this. Maybe it could work for the ref_group # info. That does not work with nesting already (fairly sure that it will break stuff). # Does it make sense to have more than one ref_group at any point of the analysis? No docs, # send a warning if users try to nest things with ref_group (that is passed around via # extra_args) # As we can see that was not possible. What if we now force it a bit? my_split_fun <- function(df, spl, .spl_context, ...) { spl@extra_args <- list(na.rm = TRUE) # does not work because do_split is not changing the object # the split does not do anything with it drop_split_levels(df, spl) } # does not work basic_table() %>% split_rows_by(\"ARM\") %>% split_rows_by(\"SEX\", split_fun = my_split_fun) %>% analyze(\"AGE\", inclNAs = TRUE, afun = mean) %>% # include_NAs is set FALSE build_table(DM_ageNA) # extra_args is in available in cols but not in rows, because different columns # may need it for different col space. Row-wise it seems not necessary. # The only thing that works is adding it to analyze (xxx) check if it is worth adding # We invite the developer now to test all the test files of this package with the tracer on # therefore -> extra_args is not currently used in splits (xxx could be wrong) # could be not being hooked up untrace(what = \"do_split\", where = asNamespace(\"rtables\")) # Let's try with the other variables identically my_tracer <- quote(if (!is.null(vals) || !is.null(labels) || isTRUE(trim)) { print(\"A LOT TO SAY\") message(\"CANT BLOCK US ALL\") stop(\"NOW FOR SURE\") browser() }) trace( what = \"do_split\", tracer = my_tracer, where = asNamespace(\"rtables\") ) # Run tests by copying the above in setup-fakedata.R (then devtools::test()) untrace( what = \"do_split\", where = asNamespace(\"rtables\") )"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_split_machinery.html","id":"multivarsplit-compoundsplit-examples","dir":"Articles > Dev-guide","previous_headings":"","what":"MultiVarSplit & CompoundSplit Examples","title":"Split Machinery","text":"final part article still construction, hence non-specific mentions list. xxx CompoundSplit generates facets one variable (e.g. cumulative distributions) MultiVarSplit uses different variables split. See AnalyzeMultiVars, inherits CompoundSplit details analyzes facets multiple times. MultiVarColSplit works analyze_colvars, scope article. .set_kids_sect_sep adds things children (can set split). First, want see MultiVarSplit class behaves example case taken ?split_rows_by_multivar. print output, notice two groups (one called “SEX” “STRATA1”) identical along columns. subgroup actually created. interesting way personalize splits help custom split functions split context, widely different subgroups table. invite reader try understand split_rows_by_multivar can row splits (see xxx comment previous code), split_cols_by_multivar . known bug moment, work towards fix . Known issues often linked source code GitHub issue number (e.g. #690). Lastly, briefly show example split cut function replace solve empty age groups problem . propose simplified situation: row split cases (*_cuts *_cutfun), empty levels dropped. expected can avoided using dedicated split function. Intentionally looking future split possible order determine element present . moment possible add spl_fun dedicated split functions like split_rows_by_cuts. Note previous table used summarize_row_groups, analyze calls. rendered table nicely, standard method use summarize_row_groups intended decorate row groups, .e. rows labels. Internally, rows called content rows analysis functions summarize_row_groups called cfun instead afun. Indeed, tabulation machinery also presents two differently described Tabulation Row Structure section Tabulation vignette. can try construct split function cuts manually make_split_fun: Alternatively, choose prune rows prune_table! add pre-processing z-scoring","code":"# rtables 0.6.2 my_tracer <- quote(if (is(spl, \"MultiVarSplit\")) browser()) trace( what = \"do_split\", tracer = my_tracer, where = asNamespace(\"rtables\") ) # We want also to take a look at the following: debugonce(rtables:::.apply_split_inner) lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by_multivar(c(\"BMRKR1\", \"BMRKR1\"), varlabels = c(\"SD\", \"MEAN\") ) %>% split_rows_by(\"COUNTRY\", split_fun = keep_split_levels(\"PAK\") ) %>% # xxx for #690 #691 summarize_row_groups() %>% analyze(c(\"AGE\", \"SEX\")) build_table(lyt, DM) # xxx check empty space on top -> check if it is a bug, file it untrace( what = \"do_split\", where = asNamespace(\"rtables\") ) # rtables 0.6.2 cutfun <- function(x) { # browser() cutpoints <- c(0, 50, 100) names(cutpoints) <- c(\"\", \"Younger\", \"Older\") cutpoints } tbl <- basic_table(show_colcounts = TRUE) %>% split_rows_by(\"ARM\", split_fun = drop_and_remove_levels(c(\"B: Placebo\", \"C: Combination\"))) %>% split_rows_by(\"STRATA1\") %>% split_rows_by_cutfun(\"AGE\", cutfun = cutfun) %>% # split_rows_by_cuts(\"AGE\", cuts = c(0, 50, 100), # cutlabels = c(\"young\", \"old\")) %>% # Works the same split_rows_by(\"SEX\", split_fun = drop_split_levels) %>% summarize_row_groups() %>% # This is degenerate!!! build_table(DM) tbl ## all obs ## (N=356) ## ————————————————————————— ## A: Drug X ## A ## AGE ## Younger ## F 22 (6.2%) ## M 14 (3.9%) ## Older ## B ## AGE ## Younger ## F 26 (7.3%) ## M 14 (3.9%) ## Older ## F 1 (0.3%) ## C ## AGE ## Younger ## F 19 (5.3%) ## M 21 (5.9%) ## Older ## F 2 (0.6%) ## M 2 (0.6%) my_count_afun <- function(x, .N_col, .spl_context, ...) { # browser() out <- list(c(length(x), length(x) / .N_col)) names(out) <- .spl_context$value[nrow(.spl_context)] # workaround (xxx #689) in_rows( .list = out, .formats = c(\"xx (xx.x%)\") ) } # ?make_split_fun # To check for docs/examples # Core split cuts_core <- function(spl, df, vals, labels, .spl_context) { # browser() # file an issue xxx # variables that are split on are converted to factor during the original clean-up # cut split are not doing it but it is an exception. xxx # young_v <- as.numeric(df[[\"AGE\"]]) < 50 # current solution: young_v <- as.numeric(as.character(df[[\"AGE\"]])) < 50 make_split_result(c(\"young\", \"old\"), datasplit = list(df[young_v, ], df[!young_v, ]), labels = c(\"Younger\", \"Older\") ) } drop_empties <- function(splret, spl, fulldf, ...) { # browser() nrows_data_split <- vapply(splret$datasplit, nrow, numeric(1)) to_keep <- nrows_data_split > 0 make_split_result( splret$values[to_keep], splret$datasplit[to_keep], splret$labels[to_keep] ) } gen_split <- make_split_fun( core_split = cuts_core, post = list(drop_empties) ) tbl <- basic_table(show_colcounts = TRUE) %>% split_rows_by(\"ARM\", split_fun = keep_split_levels(c(\"A: Drug X\"))) %>% split_rows_by(\"STRATA1\") %>% split_rows_by(\"AGE\", split_fun = gen_split) %>% analyze(\"SEX\") %>% # It is the last step!! No need of BMRKR1 right? # split_rows_by(\"SEX\", split_fun = drop_split_levels, # child_labels = \"hidden\") %>% # close issue #689. would it work for # analyze_colvars? probably (xxx) # analyze(\"BMRKR1\", afun = my_count_afun) %>% # This is NOT degenerate!!! BMRKR1 is only placeholder build_table(DM) tbl # rtables 0.6.2 tbl <- basic_table(show_colcounts = TRUE) %>% split_rows_by(\"ARM\", split_fun = keep_split_levels(c(\"A: Drug X\"))) %>% split_rows_by(\"STRATA1\") %>% split_rows_by_cuts( \"AGE\", cuts = c(0, 50, 100), cutlabels = c(\"young\", \"old\") ) %>% split_rows_by(\"SEX\", split_fun = drop_split_levels) %>% summarize_row_groups() %>% # This is degenerate!!! # we keep it until #689 build_table(DM) tbl ## all obs ## (N=356) ## ————————————————————— ## A: Drug X ## A ## young ## F 22 (6.2%) ## M 14 (3.9%) ## old ## B ## young ## F 26 (7.3%) ## M 14 (3.9%) ## old ## F 1 (0.3%) ## C ## young ## F 19 (5.3%) ## M 21 (5.9%) ## old ## F 2 (0.6%) ## M 2 (0.6%) # Trying with pruning prune_table(tbl) # (xxx) what is going on here? it is degenerate so it has no real leaves ## NULL # It is degenerate -> what to do? # The same mechanism is applied in the case of NULL leaves, they are rolled up in the # table tree"},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_table_hierarchy.html","id":"disclaimer","dir":"Articles > Dev-guide","previous_headings":"","what":"Disclaimer","title":"Table Hierarchy","text":"article intended use developers contain low-level explanations topics covered. user-friendly vignettes, please see Articles page rtables website. code prose appears version article main branch repository may reflect specific state things can less recent. guide describes important aspects table hierarchy unlikely change. Regardless, invite reader keep mind current repository code may drifted following material document, always best practice read code directly main. Please keep mind rtables still active development, seen efforts multiple contributors across different years. Therefore, may legacy mechanisms ongoing transformations look different future.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_table_hierarchy.html","id":"introduction","dir":"Articles > Dev-guide","previous_headings":"","what":"Introduction","title":"Table Hierarchy","text":"scope vignette understand structure rtable objects, class hierarchy exploration tree structures S4 objects. Exploring table structure enables better understanding rtables concepts split machinery, tabulation, pagination export. details user’s perspective table structure can found relevant vignettes. isS4 getclass - class structure","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_table_hierarchy.html","id":"process-and-methods","dir":"Articles > Dev-guide","previous_headings":"","what":"Process and Methods","title":"Table Hierarchy","text":"invite developers use provided examples interactively explore rtables hierarchy. helpful command getClass list slots associated class, addition related classes relative distances.","code":""},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_table_hierarchy.html","id":"table-representation","dir":"Articles > Dev-guide","previous_headings":"","what":"Table Representation","title":"Table Hierarchy","text":"PredataAxisLayout class used define data subset instructions tabulation. 2 sub-classes (one axis): PredataColLayout, PredataRowLayout","code":""},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_table_hierarchy.html","id":"content-summary-row-groups","dir":"Articles > Dev-guide","previous_headings":"","what":"Content (summary row groups)","title":"Table Hierarchy","text":"Splits core functionality rtables tabulation calculations often required subsets data.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_table_hierarchy.html","id":"split-machinery","dir":"Articles > Dev-guide","previous_headings":"","what":"Split Machinery","title":"Table Hierarchy","text":"TreePos class contains split information list splits, split label values, subsets data generated split. AllSplit RootSplit MultiVarSplit VarStaticCutSplit CumulativeCutSplit VarDynCutSplit CompoundSplit VarLevWBaselineSplit highest level table hierarchy belong TableTree. code identifies slots associated class. S4 object, slots can accessed using @ (similar use $ list objects). ’ll notice classes fall “Extends”. classes contained relationship TableTree object “virtual” classes. avoid repetition slots carrying data (set slots example) multiple classes may need, rtables extensively uses virtual classes. virtual class instantiated, purpose classes inherit information .","code":"library(rtables) getClass(\"TreePos\") ## Class \"TreePos\" [package \"rtables\"] ## ## Slots: ## ## Name: splits s_values sval_labels subset ## Class: list list character SubsetDef getClass(\"TableTree\") ## Class \"TableTree\" [package \"rtables\"] ## ## Slots: ## ## Name: content page_title_prefix children ## Class: ElementaryTable character list ## ## Name: rowspans labelrow page_titles ## Class: data.frame LabelRow character ## ## Name: horizontal_sep header_section_div trailing_section_div ## Class: character character character ## ## Name: col_info format na_str ## Class: InstantiatedColumnInfo FormatSpec character ## ## Name: indent_modifier table_inset level ## Class: integer integer integer ## ## Name: name main_title subtitles ## Class: character character character ## ## Name: main_footer provenance_footer ## Class: character character ## ## Extends: ## Class \"VTableTree\", directly ## Class \"VTableNodeInfo\", by class \"VTableTree\", distance 2 ## Class \"VTree\", by class \"VTableTree\", distance 2 ## Class \"VTitleFooter\", by class \"VTableTree\", distance 2 ## Class \"VNodeInfo\", by class \"VTableTree\", distance 3 lyt <- basic_table(title = \"big title\") %>% split_rows_by(\"SEX\", page_by = TRUE) %>% analyze(\"AGE\") tt <- build_table(lyt, DM) # Though we don't recommend using str for studying rtable objects, # we do find it useful in this instance to visualize the parent/child relationships. str(tt, max.level = 2) ## Formal class 'TableTree' [package \"rtables\"] with 20 slots ## ..@ content :Formal class 'ElementaryTable' [package \"rtables\"] with 19 slots ## ..@ page_title_prefix : chr \"SEX\" ## ..@ children :List of 4 ## ..@ rowspans :'data.frame': 0 obs. of 0 variables ## ..@ labelrow :Formal class 'LabelRow' [package \"rtables\"] with 13 slots ## ..@ page_titles : chr(0) ## ..@ horizontal_sep : chr \"—\" ## ..@ header_section_div : chr NA ## ..@ trailing_section_div: chr NA ## ..@ col_info :Formal class 'InstantiatedColumnInfo' [package \"rtables\"] with 9 slots ## ..@ format : NULL ## ..@ na_str : chr NA ## ..@ indent_modifier : int 0 ## ..@ table_inset : int 0 ## ..@ level : int 1 ## ..@ name : chr \"SEX\" ## ..@ main_title : chr \"big title\" ## ..@ subtitles : chr(0) ## ..@ main_footer : chr(0) ## ..@ provenance_footer : chr(0) ## Warning: str provides a low level, implementation-detail-specific description ## of the TableTree object structure. See table_structure(.) for a summary of ## table struture intended for end users."},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_table_hierarchy.html","id":"tree-paths","dir":"Articles > Dev-guide","previous_headings":"","what":"Tree Paths","title":"Table Hierarchy","text":"Root Leaves, vectors vectors Tables tree, nodes tree can summaries associated . Tables trees nested structure. also benefit keeping repeating necessary information trying paginate table. Children ElementaryTables row objects. TableTree can children either row objects table objects.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_table_hierarchy.html","id":"todo","dir":"Articles > Dev-guide","previous_headings":"Tree Paths","what":"TODO:","title":"Table Hierarchy","text":"Create Tree Diagram showing class hierarchy.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_tabulation.html","id":"disclaimer","dir":"Articles > Dev-guide","previous_headings":"","what":"Disclaimer","title":"Tabulation","text":"article intended use developers contain low-level explanations topics covered. user-friendly vignettes, please see Articles page rtables website. code prose appears version article main branch repository may reflect specific state things can less recent. guide describes important aspects tabulation process unlikely change. Regardless, invite reader keep mind current repository code may drifted following material document, always best practice read code directly main. Please keep mind rtables still active development, seen efforts multiple contributors across different years. Therefore, may legacy mechanisms ongoing transformations look different future. working document may subjected deprecation updates, keep xxx comments indicate placeholders warnings -’s need work.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_tabulation.html","id":"introduction","dir":"Articles > Dev-guide","previous_headings":"","what":"Introduction","title":"Tabulation","text":"Tabulation rtables process takes pre-defined layout applies data. layout object, splits analyzes, can applied different data produce valid tables. process happens principally within tt_dotabulation.R file user-facing function build_table resides . occasionally use functions methods present files, like colby_construction.R make_subset_expr.R. assume reader already familiar documentation build_table. suggest reading Split Machinery article prior one, instrumental understanding layout object, essentially built splits, tabulated data supplied.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/dev-guide/dg_tabulation.html","id":"tabulation","dir":"Articles > Dev-guide","previous_headings":"","what":"Tabulation","title":"Tabulation","text":"enter build_table using debugonce see works. Now let’s look within build_table call. initial check layout pre-data table layout, checks column layout defined (clayout accessor), .e. column split. case, obs column added automatically observations. , couple defensive programming calls checks transformations finally data. can divided two categories: mainly concern layout, defined generics, concern data, instead function dependent layout class. Indeed, layout structured can divided clayout rlayout (column row layout). first one used create cinfo, general object container column splits information. second one contains obligatory data split, .e. root split (accessible root_spl), row splits’ vectors iterative splits row space. following, consider initial checks defensive programming. Along various checks defensive programming, find PreDataAxisLayout virtual class row column layouts inherit . Virtual classes handy group classes need share things like labels functions need applicable relative classes. See information rtables class hierarchy dedicated article . Now, continue build_table. checks, notice TreePos() constructor object retains representation tree position along split values labels. mainly used create_colinfo, enter now debugonce(create_colinfo). function creates object represents column splits everything else may related columns. particular, column counts calculated function. parameter inputs follows: create_colinfo make_subset_expr.R. , see topleft present build_table, override one lyt. Entering create_colinfo, see following calls: Next function determination column counts. Currently, happens leaf level, can certainly calculated independently levels (open issue rtables, .e. print levels’ totals). Precedence column counts may documented (“xxx todo”). main use case analyzing participation-level dataset, multiple records per subject, like retain total numbers subjects per column, often taken subject-level dataset, use column counts. Originally, counts able added vector, often case users like possibility use alt_counts_df. cinfo object (InstantiatedColumnInfo) created information. continue inside build_table, see .make_ctab used make root split. general procedure generates initial root split content row. ctab applied content row, row contains label. ?summarize_row_groups, know rtables defines label rows, .e. content rows. .make_ctab similar function actual creates table rows, .make_tablerows. Note function uses parent_cfun .make_caller retrieve content function inserted levels. split structural handling table object row-creation engine, divided .make_tablerows call. search package, find function called twice, .make_ctab .make_analyzed_tab. two final elements table construction: creation rows. Going back build_table, see row layout actually list split vectors. fundamental line, kids <- lapply(seq_along(rlyt), function() {, allows us appreciate . Going forward see recursive_applysplit applied split vector. may worthwhile check vector looks like test case. last print informative. can see layout construction object built 2 VarLevelSplits rows one final AnalyzeMultiVars, leaf analysis split final level rows. second split vector following AnalyzeVarSplit. xxx get multiple split vectors, need escape nesting nest = FALSE adding split_rows_by call analyze call. Continuing recursive_applysplit, made two main calls: one .make_ctab makes content row calculates counts specified, .make_split_kids. eventually contains recursive_applysplit applied split vector built Splits analyze splits. generic handy switch different downstream processes. case (rlyt[[1]]) call method getMethod(\".make_split_kids\", \"Split\") twice getting analysis split. , (xxx) multi-variable split applies .make_split_kids elements, turn calling main getMethod(\".make_split_kids\", \"VAnalyzeSplit\") turn go .make_analyzed_tab. interesting edge cases different split cases, like split_by_multivars one splits reference group. internal code , called baseline. follow variable across function layers, see split (do_split) happens (getMethod(\".make_split_kids\", \"Split\")) second split reference group. done make available row calculate, example, differences reference group. Now move towards .make_tablerows, analysis functions become key place applied analyzed. First, external tryCatch used cache errors higher level, differentiate two major blocks. function parameters quite intuitive, exception spl_context. fundamental parameter keeps information splits can visible analysis functions. look value, see carried updated everywhere split happens, except columns. Column-related information added last, gen_onerv, lowest level one result value produced. .make_tablerows go gen_rowvalues, aside row referential footers handling. gen_rowvalues unpacks cinfo object crosses arriving row split information generate rows. particular, rawvals <- mapply(gen_onerv, maps columns generate list values corresponding table row. Looking final gen_onerv see (!(val, \"RowsVerticalSection\")) function in_rows called. invite reader explore building blocks in_rows , .make_tablerows constructs data row (DataRow) content row (ContentRow) depending whether called .make_ctab .make_analyzed_tab. .make_tablerows either makes content table “analysis table”. gen_rowvalues generates list stacks (RowsVerticalSection, one rows potentially!) column. add: conceptual part -> calculating things column putting side side slicing rows putting together -> rtables row dominant.","code":"# rtables 0.6.2 library(rtables) debugonce(build_table) # A very simple layout lyt <- basic_table() %>% split_rows_by(\"STRATA1\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels) %>% split_cols_by(\"ARM\") %>% analyze(\"BMRKR1\") # lyt must be a PreDataTableLayouts object is(lyt, \"PreDataTableLayouts\") lyt %>% build_table(DM) ## do checks and defensive programming now that we have the data lyt <- fix_dyncuts(lyt, df) # Create the splits that depends on data lyt <- set_def_child_ord(lyt, df) # With the data I set the same order for all splits lyt <- fix_analyze_vis(lyt) # Checks if the analyze last split should be visible # If there is only one you will not get the variable name, otherwise you get it if you # have multivar. Default is NA. You can do it now only because you are sure to # have the whole layout. df <- fix_split_vars(lyt, df, char_ok = is.null(col_counts)) # checks if split vars are present lyt[] # preserve names - warning if names longer, repeats the name value if only one lyt@.Data # might not preserve the names # it works only when it is another class that inherits from lists # We suggest doing extensive testing about these behaviors in order to do choose the appropriate one cinfo <- create_colinfo( lyt, # Main layout with col split info df, # df used for splits and col counts if no alt_counts_df is present rtpos, # TreePos (does not change out of this function) counts = col_counts, # If we want to overwrite the calculations with df/alt_counts_df alt_counts_df = alt_counts_df, # alternative data for col counts total = col_total, # calculated from build_table inputs (nrow of df or alt_counts_df) topleft # topleft information added into build_table ) clayout <- clayout(lyt) # Extracts column split and info if (is.null(topleft)) { topleft <- top_left(lyt) # If top_left is not present in build_table, it is taken from lyt } ctree <- coltree(clayout, df = df, rtpos = rtpos) # Main constructor of LayoutColTree # The above is referenced as generic and principally represented as # setMethod(\"coltree\", \"PreDataColLayout\", (located in `tree_accessor.R`). # This is a call that restructures information from clayout, df, and rtpos # to get a more compact column tree layout. Part of this design is related # to past implementations. cexprs <- make_col_subsets(ctree, df) # extracts expressions in a compact fashion. # WARNING: removing NAs at this step is automatic. This should # be coupled with a warning for NAs in the split (xxx) colextras <- col_extra_args(ctree) # retrieves extra_args from the tree. It may not be used # rtables 0.6.2 # A very simple layout lyt <- basic_table() %>% split_rows_by(\"STRATA1\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels) %>% split_cols_by(\"ARM\") %>% analyze(\"BMRKR1\") rlyt <- rtables:::rlayout(lyt) str(rlyt, max.level = 2) Formal class 'PreDataRowLayout' [package \"rtables\"] with 2 slots ..@ .Data :List of 2 # rlyt is a rtables object (PreDataRowLayout) that is also a list! ..@ root_split:Formal class 'RootSplit' [package \"rtables\"] with 17 slots # another object! # If you do summarize_row_groups before anything you act on the root split. We need this to # have a place for the content that is valid for the whole table. str(rtables:::root_spl(rlyt), max.level = 2) # it is still a split str(rlyt[[1]], max.level = 3) # still a rtables object (SplitVector) that is a list Formal class 'SplitVector' [package \"rtables\"] with 1 slot ..@ .Data:List of 3 .. ..$ :Formal class 'VarLevelSplit' [package \"rtables\"] with 20 slots .. ..$ :Formal class 'VarLevelSplit' [package \"rtables\"] with 20 slots .. ..$ :Formal class 'AnalyzeMultiVars' [package \"rtables\"] with 17 slots # rtables 0.6.2 str(rlyt[[2]], max.level = 5) Formal class 'SplitVector' [package \"rtables\"] with 1 slot ..@ .Data:List of 1 .. ..$ :Formal class 'AnalyzeVarSplit' [package \"rtables\"] with 21 slots .. .. .. ..@ analysis_fun :function (x, ...) .. .. .. .. ..- attr(*, \"srcref\")= 'srcref' int [1:8] 1723 5 1732 5 5 5 4198 4207 .. .. .. .. .. ..- attr(*, \"srcfile\")=Classes 'srcfilealias', 'srcfile' .. .. .. ..@ default_rowlabel : chr \"Var3 Counts\" .. .. .. ..@ include_NAs : logi FALSE .. .. .. ..@ var_label_position : chr \"default\" .. .. .. ..@ payload : chr \"VAR3\" .. .. .. ..@ name : chr \"VAR3\" .. .. .. ..@ split_label : chr \"Var3 Counts\" .. .. .. ..@ split_format : NULL .. .. .. ..@ split_na_str : chr NA .. .. .. ..@ split_label_position : chr(0) .. .. .. ..@ content_fun : NULL .. .. .. ..@ content_format : NULL .. .. .. ..@ content_na_str : chr(0) .. .. .. ..@ content_var : chr \"\" .. .. .. ..@ label_children : logi FALSE .. .. .. ..@ extra_args : list() .. .. .. ..@ indent_modifier : int 0 .. .. .. ..@ content_indent_modifier: int 0 .. .. .. ..@ content_extra_args : list() .. .. .. ..@ page_title_prefix : chr NA .. .. .. ..@ child_section_div : chr NA"},{"path":"https://insightsengineering.github.io/rtables/articles/example_analysis_coxreg.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Example Complex Analysis Function: Modelling Cox Regression","text":"vignette demonstrate complex analysis function can constructed order build highly-customized tables rtables. example detail steps creating analysis function calculate basic univariable Cox regression summary table analyze treatment effect ARM variable covariate/interaction effects survival analysis. Cox regression analysis function customization options capability fitting multivariable Cox regression models, see summarize_coxreg() function tern package, builds upon concepts used construction example. packages used vignette :","code":"library(rtables) library(dplyr)"},{"path":"https://insightsengineering.github.io/rtables/articles/example_analysis_coxreg.html","id":"data-pre-processing","dir":"Articles","previous_headings":"","what":"Data Pre-Processing","title":"Example Complex Analysis Function: Modelling Cox Regression","text":"First, prepare data used generate table example. use example ADTTE (Time--Event Analysis) dataset ex_adtte formatters package, contains treatment variable ARM, several variables can chosen covariates, censor variable CNSR derive event variable EVENT required model. purpose example, use age (AGE) race (RACE) covariates. prepare data needed observe desired effects summary table. PARAMCD filtered records overall survival (OS) included, filter mutate include levels interest covariates. ARM variable mutated indicate \"B: Placebo\" used reference level treatment variable, EVENT variable derived CNSR.","code":"adtte <- ex_adtte anl <- adtte %>% dplyr::filter(PARAMCD == \"OS\") %>% dplyr::filter(ARM %in% c(\"A: Drug X\", \"B: Placebo\")) %>% dplyr::filter(RACE %in% c(\"ASIAN\", \"BLACK OR AFRICAN AMERICAN\", \"WHITE\")) %>% dplyr::mutate(RACE = droplevels(RACE)) %>% dplyr::mutate(ARM = droplevels(stats::relevel(ARM, \"B: Placebo\"))) %>% dplyr::mutate(EVENT = 1 - CNSR)"},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/articles/example_analysis_coxreg.html","id":"tidy-method-for-summary-coxph-objects-tidy-summary-coxph","dir":"Articles","previous_headings":"Creating Helper Functions: Cox Regression Model Calculations","what":"tidy Method for summary.coxph Objects: tidy.summary.coxph","title":"Example Complex Analysis Function: Modelling Cox Regression","text":"method allows tidy function broom package operate summary.coxph output, extracting values interest analysis returning tidied tibble::tibble() object.","code":"tidy.summary.coxph <- function(x, ...) { is(x, \"summary.coxph\") pval <- x$coefficients confint <- x$conf.int levels <- rownames(pval) pval <- tibble::as_tibble(pval) confint <- tibble::as_tibble(confint) ret <- cbind(pval[, grepl(\"Pr\", names(pval))], confint) ret$level <- levels ret$n <- x[[\"n\"]] ret }"},{"path":"https://insightsengineering.github.io/rtables/articles/example_analysis_coxreg.html","id":"function-to-estimate-interaction-effects-h_coxreg_inter_effect","dir":"Articles","previous_headings":"Creating Helper Functions: Cox Regression Model Calculations","what":"Function to Estimate Interaction Effects: h_coxreg_inter_effect","title":"Example Complex Analysis Function: Modelling Cox Regression","text":"h_coxreg_inter_effect helper function used within following helper function, h_coxreg_extract_interaction, estimate interaction effects given model given covariate. function calculates desired statistics given model returns data.frame label information row well statistics n, hr (hazard ratio), lcl (CI lower bound), ucl (CI upper bound), pval (effect p-value), pval_inter (interaction p-value). numeric covariate selected, median value used sole “level” interaction effect calculated. non-numeric covariates, interaction effect calculated level covariate, result returned separate row.","code":"h_coxreg_inter_effect <- function(x, effect, covar, mod, label, control, data) { if (is.numeric(x)) { betas <- stats::coef(mod) attrs <- attr(stats::terms(mod), \"term.labels\") term_indices <- grep(pattern = effect, x = attrs[!grepl(\"strata\\\\(\", attrs)]) betas <- betas[term_indices] betas_var <- diag(stats::vcov(mod))[term_indices] betas_cov <- stats::vcov(mod)[term_indices[1], term_indices[2]] xval <- stats::median(x) effect_index <- !grepl(covar, names(betas)) coef_hat <- betas[effect_index] + xval * betas[!effect_index] coef_se <- sqrt(betas_var[effect_index] + xval^2 * betas_var[!effect_index] + 2 * xval * betas_cov) q_norm <- stats::qnorm((1 + control$conf_level) / 2) } else { var_lvl <- paste0(effect, levels(data[[effect]])[-1]) # [-1]: reference level giv_lvl <- paste0(covar, levels(data[[covar]])) design_mat <- expand.grid(effect = var_lvl, covar = giv_lvl) design_mat <- design_mat[order(design_mat$effect, design_mat$covar), ] design_mat <- within(data = design_mat, expr = { inter <- paste0(effect, \":\", covar) rev_inter <- paste0(covar, \":\", effect) }) split_by_variable <- design_mat$effect interaction_names <- paste(design_mat$effect, design_mat$covar, sep = \"/\") mmat <- stats::model.matrix(mod)[1, ] mmat[!mmat == 0] <- 0 design_mat <- apply(X = design_mat, MARGIN = 1, FUN = function(x) { mmat[names(mmat) %in% x[-which(names(x) == \"covar\")]] <- 1 mmat }) colnames(design_mat) <- interaction_names coef <- stats::coef(mod) vcov <- stats::vcov(mod) betas <- as.matrix(coef) coef_hat <- t(design_mat) %*% betas dimnames(coef_hat)[2] <- \"coef\" coef_se <- apply(design_mat, 2, function(x) { vcov_el <- as.logical(x) y <- vcov[vcov_el, vcov_el] y <- sum(y) y <- sqrt(y) y }) q_norm <- stats::qnorm((1 + control$conf_level) / 2) y <- cbind(coef_hat, `se(coef)` = coef_se) y <- apply(y, 1, function(x) { x[\"hr\"] <- exp(x[\"coef\"]) x[\"lcl\"] <- exp(x[\"coef\"] - q_norm * x[\"se(coef)\"]) x[\"ucl\"] <- exp(x[\"coef\"] + q_norm * x[\"se(coef)\"]) x }) y <- t(y) y <- by(y, split_by_variable, identity) y <- lapply(y, as.matrix) attr(y, \"details\") <- paste0( \"Estimations of \", effect, \" hazard ratio given the level of \", covar, \" compared to \", effect, \" level \", levels(data[[effect]])[1], \".\" ) xval <- levels(data[[covar]]) } data.frame( effect = \"Covariate:\", term = rep(covar, length(xval)), term_label = as.character(paste0(\" \", xval)), level = as.character(xval), n = NA, hr = if (is.numeric(x)) exp(coef_hat) else y[[1]][, \"hr\"], lcl = if (is.numeric(x)) exp(coef_hat - q_norm * coef_se) else y[[1]][, \"lcl\"], ucl = if (is.numeric(x)) exp(coef_hat + q_norm * coef_se) else y[[1]][, \"ucl\"], pval = NA, pval_inter = NA, stringsAsFactors = FALSE ) }"},{"path":"https://insightsengineering.github.io/rtables/articles/example_analysis_coxreg.html","id":"function-to-extract-effect-information-h_coxreg_extract_interaction","dir":"Articles","previous_headings":"Creating Helper Functions: Cox Regression Model Calculations","what":"Function to Extract Effect Information: h_coxreg_extract_interaction","title":"Example Complex Analysis Function: Modelling Cox Regression","text":"Using previous two helper functions, h_coxreg_extract_interaction uses ANOVA extract information given model given covariate. function extract different information depending whether effect interest treatment/main effect interaction effect, returns data.frame label information row (corresponding effect) well statistics n, hr, lcl, ucl, pval, pval_inter (interaction effects ). helper function used directly within analysis function analyze Cox regression model extract relevant information processed displayed within output table.","code":"h_coxreg_extract_interaction <- function(effect, covar, mod, data) { control <- list(pval_method = \"wald\", ties = \"exact\", conf_level = 0.95, interaction = FALSE) test_statistic <- c(wald = \"Wald\", likelihood = \"LR\")[control$pval_method] mod_aov <- withCallingHandlers( expr = car::Anova(mod, test.statistic = test_statistic, type = \"III\"), message = function(m) invokeRestart(\"muffleMessage\") ) msum <- if (!any(attr(stats::terms(mod), \"order\") == 2)) summary(mod, conf.int = control$conf_level) else mod_aov sum_anova <- broom::tidy(msum) if (!any(attr(stats::terms(mod), \"order\") == 2)) { effect_aov <- mod_aov[effect, , drop = TRUE] pval <- effect_aov[[grep(pattern = \"Pr\", x = names(effect_aov)), drop = TRUE]] sum_main <- sum_anova[grepl(effect, sum_anova$level), ] term_label <- if (effect == covar) { paste0(levels(data[[covar]])[2], \" vs control (\", levels(data[[covar]])[1], \")\") } else { unname(formatters::var_labels(data, fill = TRUE)[[covar]]) } y <- data.frame( effect = ifelse(covar == effect, \"Treatment:\", \"Covariate:\"), term = covar, term_label = term_label, level = levels(data[[effect]])[2], n = mod[[\"n\"]], hr = unname(sum_main[\"exp(coef)\"]), lcl = unname(sum_main[grep(\"lower\", names(sum_main))]), ucl = unname(sum_main[grep(\"upper\", names(sum_main))]), pval = pval, stringsAsFactors = FALSE ) y$pval_inter <- NA y } else { pval <- sum_anova[sum_anova$term == effect, ][[\"p.value\"]] ## Test the interaction effect pval_inter <- sum_anova[grep(\":\", sum_anova$term), ][[\"p.value\"]] covar_test <- data.frame( effect = \"Covariate:\", term = covar, term_label = unname(formatters::var_labels(data, fill = TRUE)[[covar]]), level = \"\", n = mod$n, hr = NA, lcl = NA, ucl = NA, pval = pval, pval_inter = pval_inter, stringsAsFactors = FALSE ) ## Estimate the interaction y <- h_coxreg_inter_effect( data[[covar]], covar = covar, effect = effect, mod = mod, label = unname(formatters::var_labels(data, fill = TRUE)[[covar]]), control = control, data = data ) rbind(covar_test, y) } }"},{"path":"https://insightsengineering.github.io/rtables/articles/example_analysis_coxreg.html","id":"creating-a-helper-function-cached_model","dir":"Articles","previous_headings":"","what":"Creating a Helper Function: cached_model","title":"Example Complex Analysis Function: Modelling Cox Regression","text":"Next, create helper function, cached_model, used within analysis function cache return fitted Cox regression model current covariate. df argument directly inherited df argument passed analysis function, contains full dataset analyzed. cov argument covariate analyzed depending current row context. treatment effect currently analyzed, value empty string. cache_env parameter environment object used store model current covariate, also passed analysis function. course, function can also run outside analysis function still cache return Cox regression model. Using arguments, cached_model function first checks model given covariate cov already stored caching environment cache_env. , model retrieved returned cached_model. , model must constructed. done first constructing model formula, model_form, starting treatment effect (ARM) adding covariate effect one currently analyzed. Cox regression model fit using df model formula, model returned stored caching environment object cache_env[[cov]].","code":"cached_model <- function(df, cov, cache_env) { ## Check if a model already exists for ## `cov` in the caching environment if (!is.null(cache_env[[cov]])) { ## If model already exists, retrieve it from cache_env model <- cache_env[[cov]] } else { ## Build model formula model_form <- paste0(\"survival::Surv(AVAL, EVENT) ~ ARM\") if (length(cov) > 0) { model_form <- paste(c(model_form, cov), collapse = \" * \") } else { cov <- \"ARM\" } ## Calculate Cox regression model model <- survival::coxph( formula = stats::as.formula(model_form), data = df, ties = \"exact\" ) ## Store model in the caching environment cache_env[[cov]] <- model } model }"},{"path":"https://insightsengineering.github.io/rtables/articles/example_analysis_coxreg.html","id":"creating-the-analysis-function-a_cox_summary","dir":"Articles","previous_headings":"","what":"Creating the Analysis Function: a_cox_summary","title":"Example Complex Analysis Function: Modelling Cox Regression","text":"data prepared helper function created, can proceed construct analysis function a_cox_summary, used populate rows table. order used generate data rows (interaction effects) content rows (main effects), must create function can used afun analyze cfun summarize_row_groups. Therefore, function must accept labelstr parameter. arguments analysis function follows: df - data.frame full dataset required fit Cox regression model. labelstr - string label variable analyzed current row/column split context. .spl_context - data.frame containing value column used analysis function determine name variable/covariate current split. details information stored .spl_context see ?analyze. stat format - strings indicate statistic column currently format applied print statistic. cache_env - environment object can used store cached models can prevent repeatedly fitting model. Instead, model generated per covariate reused. argument passed directly cached_model helper function defined previously. cov_main - logical value indicating whether current row summarizing covariate main effects. analysis function works within given row/column split context using current covariate (cov) cached_model function obtain desired Cox regression model. model, h_coxreg_extract_interaction function able extract information/statistics relevant analysis store data.frame. rows data.frame interest current row/column split context extracted statistic printed current column retrieved rows. Finally, formatted cells statistic returned VerticalRowsSection object. detail see commented function code , purpose line within a_cox_summary described.","code":"a_cox_summary <- function(df, labelstr = \"\", .spl_context, stat, format, cache_env, cov_main = FALSE) { ## Get current covariate (variable used in latest row split) cov <- tail(.spl_context$value, 1) ## If currently analyzing treatment effect (ARM) replace empty ## value of cov with \"ARM\" so the correct model row is analyzed if (length(cov) == 0) cov <- \"ARM\" ## Use cached_model to get the fitted Cox regression ## model for the current covariate model <- cached_model(df = df, cov = cov, cache_env = cache_env) ## Extract levels of cov to be used as row labels for interaction effects. ## If cov is numeric, the median value of cov is used as a row label instead cov_lvls <- if (is.factor(df[[cov]])) levels(df[[cov]]) else as.character(median(df[[cov]])) ## Use function to calculate and extract information relevant to cov from the model cov_rows <- h_coxreg_extract_interaction(effect = \"ARM\", covar = cov, mod = model, data = df) ## Effect p-value is only printed for treatment effect row if (!cov == \"ARM\") cov_rows[, \"pval\"] <- NA_real_ ## Extract rows containing statistics for cov from model information if (!cov_main) { ## Extract rows for main effect cov_rows <- cov_rows[cov_rows$level %in% cov_lvls, ] } else { ## Extract all non-main effect rows cov_rows <- cov_rows[nchar(cov_rows$level) == 0, ] } ## Extract value(s) of statistic for current column and variable/levels stat_vals <- as.list(apply(cov_rows[stat], 1, function(x) x, simplify = FALSE)) ## Assign labels: covariate name for main effect (content) rows, ARM comparison description ## for treatment effect (content) row, cov_lvls for interaction effect (data) rows nms <- if (cov_main) labelstr else if (cov == \"ARM\") cov_rows$term_label else cov_lvls ## Return formatted/labelled row in_rows( .list = stat_vals, .names = nms, .labels = nms, .formats = setNames(rep(format, length(nms)), nms), .format_na_strs = setNames(rep(\"\", length(nms)), nms) ) }"},{"path":"https://insightsengineering.github.io/rtables/articles/example_analysis_coxreg.html","id":"selecting-parameters","dir":"Articles","previous_headings":"","what":"Selecting Parameters","title":"Example Complex Analysis Function: Modelling Cox Regression","text":"able customize Cox regression summary using analysis function selecting covariates (labels), statistics (labels), statistic formats use generating output table. also initialize new environment object used analysis function caching environment store models . purpose example, choose 5 possible statistics include table: n, hazard ratio, confidence interval, effect p-value, interaction p-value.","code":"my_covs <- c(\"AGE\", \"RACE\") ## Covariates my_cov_labs <- c(\"Age\", \"Race\") ## Covariate labels my_stats <- list(\"n\", \"hr\", c(\"lcl\", \"ucl\"), \"pval\", \"pval_inter\") ## Statistics my_stat_labs <- c(\"n\", \"Hazard Ratio\", \"95% CI\", \"p-value\\n(effect)\", \"p-value\\n(interaction)\") ## Statistic labels my_formats <- c( n = \"xx\", hr = \"xx.xx\", lcl = \"(xx.xx, xx.xx)\", pval = \"xx.xxxx\", pval_inter = \"xx.xxxx\" ## Statistic formats ) my_env <- new.env() ny_cache_env <- replicate(length(my_stats), list(my_env)) ## Caching environment"},{"path":"https://insightsengineering.github.io/rtables/articles/example_analysis_coxreg.html","id":"constructing-the-table","dir":"Articles","previous_headings":"","what":"Constructing the Table","title":"Example Complex Analysis Function: Modelling Cox Regression","text":"Finally, table layout can constructed used build desired table. first split basic_table using split_cols_by_multivar ensure statistic exists column. , choose variable (case STUDYID) shares value every row, use split variable every column full dataset used compute model every column. use extra_args argument list element’s element positions correspond children (columns generated ) split. arguments inherited following layout elements operating within split, use elements argument inputs. elaborate , three elements extra_args: stat, format, cache_env - arguments a_cox_summary length equal number columns (defined ). use analysis function following column split, depending current column context, corresponding element three list elements inherited extra_args used input. example, analyze_colvars called a_cox_summary afun performing calculations column 1, my_stats[1] (\"n\") given argument stat, my_formats[1] (\"xx\") argument format, my_cache_env[1] (my_env) cache_env. useful table since want column print values different statistic apply corresponding format. Next, can use summarize_row_groups generate content row treatment effect. first instance extra_args column split inherited used argument input cfun. generating treatment effect row, want add rows covariates. use split_rows_by_multivar split rows covariate apply appropriate labels. Following row split, use summarize_row_groups a_cox_summary cfun generate one content row covariate main effect. contents extra_args column split inherited input. specify cov_main = TRUE extra_args argument main effects rather interactions considered. Since split, instance extra_args inherited following layout elements. cov_main singular value, cov_main = TRUE used within every column context. last part table covariate interaction effects. use analyze_colvars a_cox_summary afun, inherit extra_args column split. Using rtables “analyze” function generates data rows, one row corresponding covariate level (median value, numeric covariates), nested content row (main effect) covariate. Using pre-processed anl dataset, can now build output final Cox regression summary table.","code":"lyt <- basic_table() %>% ## Column split: one column for each statistic split_cols_by_multivar( vars = rep(\"STUDYID\", length(my_stats)), varlabels = my_stat_labs, extra_args = list( stat = my_stats, format = my_formats, cache_env = ny_cache_env ) ) %>% ## Create content row for treatment effect summarize_row_groups(cfun = a_cox_summary) %>% ## Row split: one content row for each covariate split_rows_by_multivar( vars = my_covs, varlabels = my_cov_labs, split_label = \"Covariate:\", indent_mod = -1 ## Align split label left ) %>% ## Create content rows for covariate main effects summarize_row_groups( cfun = a_cox_summary, extra_args = list(cov_main = TRUE) ) %>% ## Create data rows for covariate interaction effects analyze_colvars(afun = a_cox_summary) cox_tbl <- build_table(lyt, anl) cox_tbl #> p-value p-value #> n Hazard Ratio 95% CI (effect) (interaction) #> ———————————————————————————————————————————————————————————————————————————————————————————————— #> A: Drug X vs control (B: Placebo) 247 0.97 (0.71, 1.32) 0.8243 #> Covariate: #> Age 247 0.7832 #> 34 0.92 (0.68, 1.26) #> Race 247 0.7441 #> ASIAN 1.03 (0.68, 1.57) #> BLACK OR AFRICAN AMERICAN 0.78 (0.41, 1.49) #> WHITE 1.06 (0.55, 2.04)"},{"path":"https://insightsengineering.github.io/rtables/articles/exploratory_analysis.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Exploratory Analysis","text":"vignette, like introduce qtable() can used easily create cross tabulations exploratory data analysis. qtable() extension table() base R can much beyond creating two-way contingency tables. function simple use interface internally builds layouts using rtables framework.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/exploratory_analysis.html","id":"getting-started","dir":"Articles","previous_headings":"","what":"Getting Started","title":"Exploratory Analysis","text":"Load packages used vignette: Let’s start seeing table() can : can easily recreate cross-tables qtable() specifying data.frame variable(s) tabulate. col_vars row_vars arguments control split data across columns rows respectively. Aside display style, main difference qtable() add (N=xx) table header default. can removed show_colcounts. variables used row column facets empty strings (““). non empty values required labels generating table. code generate error.","code":"library(rtables) library(dplyr) table(ex_adsl$ARM) # # A: Drug X B: Placebo C: Combination # 134 134 132 table(ex_adsl$SEX, ex_adsl$ARM) # # A: Drug X B: Placebo C: Combination # F 79 77 66 # M 51 55 60 # U 3 2 4 # UNDIFFERENTIATED 1 0 2 qtable(ex_adsl, col_vars = \"ARM\") # A: Drug X B: Placebo C: Combination # (N=134) (N=134) (N=132) # ——————————————————————————————————————————————— # count 134 134 132 qtable(ex_adsl, col_vars = \"ARM\", row_vars = \"SEX\") # A: Drug X B: Placebo C: Combination # count (N=134) (N=134) (N=132) # —————————————————————————————————————————————————————————— # F 79 77 66 # M 51 55 60 # U 3 2 4 # UNDIFFERENTIATED 1 0 2 qtable(ex_adsl, \"ARM\", show_colcounts = FALSE) # count all obs # ———————————————————————— # A: Drug X 134 # B: Placebo 134 # C: Combination 132 tmp_adsl <- ex_adsl tmp_adsl$new <- rep_len(c(\"\", \"A\", \"B\"), nrow(tmp_adsl)) qtable(tmp_adsl, row_vars = \"new\")"},{"path":"https://insightsengineering.github.io/rtables/articles/exploratory_analysis.html","id":"nested-tables","dir":"Articles","previous_headings":"","what":"Nested Tables","title":"Exploratory Analysis","text":"Providing one variable name row column structure qtable() create nested table. Arbitrary nesting supported dimension. Note default, unobserved factor levels within facet included table. can modified drop_levels. code adds row 0s STRATA1 level “B” nested SEX level “UNDIFFERENTIATED”. contrast, table() return nested table. Rather produces list contingency tables two variables used inputs. help stats::ftable() nested structure can achieved two steps.","code":"qtable(ex_adsl, row_vars = c(\"SEX\", \"STRATA1\"), col_vars = c(\"ARM\", \"STRATA2\")) # A: Drug X B: Placebo C: Combination # S1 S2 S1 S2 S1 S2 # count (N=73) (N=61) (N=67) (N=67) (N=56) (N=76) # ———————————————————————————————————————————————————————————————————————— # F # A 12 9 11 13 7 11 # B 14 11 12 15 9 12 # C 17 16 13 13 14 13 # M # A 5 11 10 9 6 14 # B 13 8 7 10 9 12 # C 8 6 13 6 8 11 # U # A 1 0 1 0 1 0 # B 1 0 0 1 0 1 # C 1 0 0 0 1 1 # UNDIFFERENTIATED # A 0 0 0 0 0 1 # C 1 0 0 0 1 0 qtable( ex_adsl, row_vars = c(\"SEX\", \"STRATA1\"), col_vars = c(\"ARM\", \"STRATA2\"), drop_levels = FALSE ) # A: Drug X B: Placebo C: Combination # S1 S2 S1 S2 S1 S2 # count (N=73) (N=61) (N=67) (N=67) (N=56) (N=76) # ———————————————————————————————————————————————————————————————————————— # F # A 12 9 11 13 7 11 # B 14 11 12 15 9 12 # C 17 16 13 13 14 13 # M # A 5 11 10 9 6 14 # B 13 8 7 10 9 12 # C 8 6 13 6 8 11 # U # A 1 0 1 0 1 0 # B 1 0 0 1 0 1 # C 1 0 0 0 1 1 # UNDIFFERENTIATED # A 0 0 0 0 0 1 # B 0 0 0 0 0 0 # C 1 0 0 0 1 0 table(ex_adsl$SEX, ex_adsl$STRATA1, ex_adsl$ARM, ex_adsl$STRATA2) # , , = A: Drug X, = S1 # # # A B C # F 12 14 17 # M 5 13 8 # U 1 1 1 # UNDIFFERENTIATED 0 0 1 # # , , = B: Placebo, = S1 # # # A B C # F 11 12 13 # M 10 7 13 # U 1 0 0 # UNDIFFERENTIATED 0 0 0 # # , , = C: Combination, = S1 # # # A B C # F 7 9 14 # M 6 9 8 # U 1 0 1 # UNDIFFERENTIATED 0 0 1 # # , , = A: Drug X, = S2 # # # A B C # F 9 11 16 # M 11 8 6 # U 0 0 0 # UNDIFFERENTIATED 0 0 0 # # , , = B: Placebo, = S2 # # # A B C # F 13 15 13 # M 9 10 6 # U 0 1 0 # UNDIFFERENTIATED 0 0 0 # # , , = C: Combination, = S2 # # # A B C # F 11 12 13 # M 14 12 11 # U 0 1 1 # UNDIFFERENTIATED 1 0 0 t1 <- ftable(ex_adsl[, c(\"SEX\", \"STRATA1\", \"ARM\", \"STRATA2\")]) ftable(t1, row.vars = c(\"SEX\", \"STRATA1\")) # ARM A: Drug X B: Placebo C: Combination # STRATA2 S1 S2 S1 S2 S1 S2 # SEX STRATA1 # F A 12 9 11 13 7 11 # B 14 11 12 15 9 12 # C 17 16 13 13 14 13 # M A 5 11 10 9 6 14 # B 13 8 7 10 9 12 # C 8 6 13 6 8 11 # U A 1 0 1 0 1 0 # B 1 0 0 1 0 1 # C 1 0 0 0 1 1 # UNDIFFERENTIATED A 0 0 0 0 0 1 # B 0 0 0 0 0 0 # C 1 0 0 0 1 0"},{"path":"https://insightsengineering.github.io/rtables/articles/exploratory_analysis.html","id":"na-values","dir":"Articles","previous_headings":"","what":"NA Values","title":"Exploratory Analysis","text":"far examples seen, used counts summarize data table cell default analysis used qtable(). Internally, single analysis variable specified avar used generate counts table. default analysis variable first variable data. case ex_adsl “STUDYID”. Let’s see happens introduce NA values analysis variable: resulting table showing 0’s across cells values analysis variable NA. Keep behavior mind quick exploratory analysis using default counts aggregate function qtable. suit purpose, can either pre-process data re-code NA values use another analysis function. see latter done Custom Aggregation section. addition, row column variables NA levels explicitly labelled . done, columns /rows reflect full data. Explicitly labeling NA levels column facet adds column table:","code":"tmp_adsl <- ex_adsl tmp_adsl[[1]] <- NA_character_ qtable(tmp_adsl, row_vars = \"ARM\", col_vars = \"SEX\") # F M U UNDIFFERENTIATED # count (N=222) (N=166) (N=9) (N=3) # ————————————————————————————————————————————————————————————— # A: Drug X 0 0 0 0 # B: Placebo 0 0 0 0 # C: Combination 0 0 0 0 # Recode NA values tmp_adsl[[1]] <- addNA(tmp_adsl[[1]]) qtable(tmp_adsl, row_vars = \"ARM\", col_vars = \"SEX\") # F M U UNDIFFERENTIATED # count (N=222) (N=166) (N=9) (N=3) # ————————————————————————————————————————————————————————————— # A: Drug X 79 51 3 1 # B: Placebo 77 55 2 0 # C: Combination 66 60 4 2 tmp_adsl$new1 <- factor(NA_character_, levels = c(\"X\", \"Y\", \"Z\")) qtable(tmp_adsl, row_vars = \"ARM\", col_vars = \"new1\") # X Y Z # count (N=0) (N=0) (N=0) # —————————————————————————————————————— # A: Drug X 0 0 0 # B: Placebo 0 0 0 # C: Combination 0 0 0 tmp_adsl$new2 <- addNA(tmp_adsl$new1) levels(tmp_adsl$new2)[4] <- \"\" # NA needs to be a recognizible string qtable(tmp_adsl, row_vars = \"ARM\", col_vars = \"new2\") # X Y Z # count (N=0) (N=0) (N=0) (N=400) # ———————————————————————————————————————————————— # A: Drug X 0 0 0 134 # B: Placebo 0 0 0 134 # C: Combination 0 0 0 132"},{"path":"https://insightsengineering.github.io/rtables/articles/exploratory_analysis.html","id":"custom-aggregation","dir":"Articles","previous_headings":"","what":"Custom Aggregation","title":"Exploratory Analysis","text":"powerful feature qtable() user can define type function used summarize data facet. can specify type analysis summary using afun argument: Note analysis variable AGE analysis function name included top right header table. analysis function returns vector 2 3 elements, result displayed multi-valued single cells. want use analysis function 3 summary elements, can use list. case, values displayed table multiple stacked cells within facet. list elements named, names used row labels. advanced formatting can controlled in_rows(). See function documentation details.","code":"qtable(ex_adsl, row_vars = \"STRATA2\", col_vars = \"ARM\", avar = \"AGE\", afun = mean) # A: Drug X B: Placebo C: Combination # AGE - mean (N=134) (N=134) (N=132) # ———————————————————————————————————————————————————— # S1 34.10 36.46 35.70 # S2 33.38 34.40 35.24 qtable(ex_adsl, row_vars = \"STRATA2\", col_vars = \"ARM\", avar = \"AGE\", afun = range) # A: Drug X B: Placebo C: Combination # AGE - range (N=134) (N=134) (N=132) # ———————————————————————————————————————————————————————— # S1 23.0 / 48.0 24.0 / 62.0 20.0 / 69.0 # S2 21.0 / 50.0 21.0 / 58.0 23.0 / 64.0 fivenum2 <- function(x) { setNames(as.list(fivenum(x)), c(\"min\", \"Q1\", \"MED\", \"Q3\", \"max\")) } qtable(ex_adsl, row_vars = \"STRATA2\", col_vars = \"ARM\", avar = \"AGE\", afun = fivenum2) # A: Drug X B: Placebo C: Combination # AGE - fivenum2 (N=134) (N=134) (N=132) # ———————————————————————————————————————————————————————— # S1 # min 23.00 24.00 20.00 # Q1 28.00 30.00 30.50 # MED 34.00 36.00 35.00 # Q3 39.00 40.50 40.00 # max 48.00 62.00 69.00 # S2 # min 21.00 21.00 23.00 # Q1 29.00 29.50 30.00 # MED 32.00 32.00 34.50 # Q3 38.00 39.50 38.00 # max 50.00 58.00 64.00 meansd_range <- function(x) { in_rows( \"Mean (sd)\" = rcell(c(mean(x), sd(x)), format = \"xx.xx (xx.xx)\"), \"Range\" = rcell(range(x), format = \"xx - xx\") ) } qtable(ex_adsl, row_vars = \"STRATA2\", col_vars = \"ARM\", avar = \"AGE\", afun = meansd_range) # A: Drug X B: Placebo C: Combination # AGE - meansd_range (N=134) (N=134) (N=132) # ————————————————————————————————————————————————————————————————— # S1 # Mean (sd) 34.10 (6.71) 36.46 (7.72) 35.70 (8.22) # Range 23 - 48 24 - 62 20 - 69 # S2 # Mean (sd) 33.38 (6.40) 34.40 (7.99) 35.24 (7.39) # Range 21 - 50 21 - 58 23 - 64"},{"path":"https://insightsengineering.github.io/rtables/articles/exploratory_analysis.html","id":"marginal-summaries","dir":"Articles","previous_headings":"","what":"Marginal Summaries","title":"Exploratory Analysis","text":"Another feature qtable() ability quickly add marginal summary rows summarize_groups argument. summary add table count non-NA records analysis variable level nesting. example, compare two tables: second table, marginal summary rows level two row facet variables: STRATA1 STRATA2. number 18 second row gives count observations part ARM level “: Drug X”, STRATA1 level “”, STRATA2 level “S1”. percent calculated cell count divided column count given table header. can see mean AGE 31.61 subgroup based 18 subjects correspond 13.4% subjects arm “: Drug X”. See ?summarize_row_groups add marginal summary rows using core rtables framework.","code":"qtable( ex_adsl, row_vars = c(\"STRATA1\", \"STRATA2\"), col_vars = \"ARM\", avar = \"AGE\", afun = mean ) # A: Drug X B: Placebo C: Combination # AGE - mean (N=134) (N=134) (N=132) # ———————————————————————————————————————————————————— # A # S1 31.61 36.68 34.00 # S2 34.40 33.55 34.35 # B # S1 34.57 37.68 35.83 # S2 32.79 34.77 36.68 # C # S1 35.26 35.38 36.58 # S2 32.95 34.89 34.72 qtable( ex_adsl, row_vars = c(\"STRATA1\", \"STRATA2\"), col_vars = \"ARM\", summarize_groups = TRUE, avar = \"AGE\", afun = mean ) # A: Drug X B: Placebo C: Combination # AGE - mean (N=134) (N=134) (N=132) # ————————————————————————————————————————————————————————— # A 38 (28.4%) 44 (32.8%) 40 (30.3%) # S1 18 (13.4%) 22 (16.4%) 14 (10.6%) # AGE - mean 31.61 36.68 34.00 # S2 20 (14.9%) 22 (16.4%) 26 (19.7%) # AGE - mean 34.40 33.55 34.35 # B 47 (35.1%) 45 (33.6%) 43 (32.6%) # S1 28 (20.9%) 19 (14.2%) 18 (13.6%) # AGE - mean 34.57 37.68 35.83 # S2 19 (14.2%) 26 (19.4%) 25 (18.9%) # AGE - mean 32.79 34.77 36.68 # C 49 (36.6%) 45 (33.6%) 49 (37.1%) # S1 27 (20.1%) 26 (19.4%) 24 (18.2%) # AGE - mean 35.26 35.38 36.58 # S2 22 (16.4%) 19 (14.2%) 25 (18.9%) # AGE - mean 32.95 34.89 34.72"},{"path":"https://insightsengineering.github.io/rtables/articles/exploratory_analysis.html","id":"table-decorations","dir":"Articles","previous_headings":"","what":"Table Decorations","title":"Exploratory Analysis","text":"Tables generated qtable() can include annotations titles, subtitles footnotes like :","code":"qtable( ex_adsl, row_vars = \"STRATA2\", col_vars = \"ARM\", title = \"Strata 2 Summary\", subtitle = paste0(\"STUDY \", ex_adsl$STUDYID[1]), main_footer = paste0(\"Date: \", as.character(Sys.Date())) ) # Strata 2 Summary # STUDY AB12345 # # ——————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # count (N=134) (N=134) (N=132) # ——————————————————————————————————————————————— # S1 73 67 56 # S2 61 67 76 # ——————————————————————————————————————————————— # # Date: 2024-12-12"},{"path":"https://insightsengineering.github.io/rtables/articles/exploratory_analysis.html","id":"summary","dir":"Articles","previous_headings":"","what":"Summary","title":"Exploratory Analysis","text":"learned vignette: qtable() can replace extend uses table() stats::ftable() qtable() useful exploratory data analysis intended use qtable() exploratory data analysis, limited functionality building complex tables. details get started core rtables layout functionality see introduction vignette.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/format_precedence.html","id":"formats-precedence","dir":"Articles","previous_headings":"","what":"Formats Precedence","title":"Format Precedence and NA Handling","text":"Users rtables package can specify format numbers reporting tables printed. Formatting functionality provided formatters R package. See formatters::list_valid_format_labels() list available formats. format can specified user different places. may happen , single table layout, format specified one place. case, final format applied depends format precedence rules defined rtables. vignette, describe basic rules rtables format precedence. examples shown vignette utilize example ADSL dataset, demographic table summarizes variables content different population subsets (encoded columns). Note ex_* data currently attached rtables package provided formatters package created using publicly available random.cdisc.data R package.","code":"library(rtables) ADSL <- ex_adsl"},{"path":"https://insightsengineering.github.io/rtables/articles/format_precedence.html","id":"format-precedence-and-inheritance-rules","dir":"Articles","previous_headings":"Formats Precedence","what":"Format Precedence and Inheritance Rules","title":"Format Precedence and NA Handling","text":"format numbers printed can specified user different places. context precedence, important level split hierarchy formats specified . general, two levels: cell level -called parent table level. concept cell parent table results way rtables package stores resulting tables. models resulting tables hierarchical, tree-like objects cells (leaves) containing multiple values. Particularly noteworthy context fact actual table splitting occurs row-dominant way (even column splitting present layout). rtables provides user-end function table_structure() prints structure given table object. simple illustration, consider following example: table, 4 sub-tables SEX table. : F, M, U, UNDIFFERENTIATED. sub-tables one sub-table AGE. example, first AGE sub-table, parent table F. concept hierarchical, tree-like representations resulting tables translates directly format precedence inheritance rules. general principle, format finally applied cell one specific, , one closest cell given path tree. Hence, precedence-inheritance chain looks like following: chain, outermost parent_table least specific place specify format, cell specific one. cases format specified user one place, one specific applied cell. specific format selected user split, default format applied. default format \"xx\" yields formatting .character() function. following sections vignette, illustrate format precedence rules examples.","code":"lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(vars = \"AGE\", afun = mean) adsl_analyzed <- build_table(lyt, ADSL) adsl_analyzed # A: Drug X B: Placebo C: Combination # ————————————————————————————————————————————————————————————————————————— # F # mean 32.7594936708861 34.1168831168831 35.1969696969697 # M # mean 35.5686274509804 37.4363636363636 35.3833333333333 # U # mean 31.6666666666667 31 35.25 # UNDIFFERENTIATED # mean 28 NA 45 table_structure(adsl_analyzed) # [TableTree] SEX # [TableTree] F # [ElementaryTable] AGE (1 x 3) # [TableTree] M # [ElementaryTable] AGE (1 x 3) # [TableTree] U # [ElementaryTable] AGE (1 x 3) # [TableTree] UNDIFFERENTIATED # [ElementaryTable] AGE (1 x 3) parent_table -> parent_table -> ... -> parent_table -> cell"},{"path":"https://insightsengineering.github.io/rtables/articles/format_precedence.html","id":"standard-format","dir":"Articles","previous_headings":"Formats Precedence","what":"Standard Format","title":"Format Precedence and NA Handling","text":"simple layout explicitly set format output analysis function. case, default format applied.","code":"lyt0 <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(vars = \"AGE\", afun = mean) build_table(lyt0, ADSL) # A: Drug X B: Placebo C: Combination # ————————————————————————————————————————————————————————————— # mean 33.7686567164179 35.4328358208955 35.4318181818182"},{"path":"https://insightsengineering.github.io/rtables/articles/format_precedence.html","id":"cell-format","dir":"Articles","previous_headings":"Formats Precedence","what":"Cell Format","title":"Format Precedence and NA Handling","text":"format cell can explicitly specified via rcell() in_rows() functions. former essentially collection data objects latter collection rcell() objects. previously mentioned, specific place format can specified user. format specified places time, one specified via in_rows() takes highest precedence. Technically, case, format defined rcell() simply overwritten one defined in_rows(). format specified in_rows() applied cells rows (overriding previously specified cell-specific values), indicates precedence rules described still place.","code":"lyt1 <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(vars = \"AGE\", afun = function(x) { rcell(mean(x), format = \"xx.xx\", label = \"Mean\") }) build_table(lyt1, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————— # Mean 33.77 35.43 35.43 lyt1a <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(vars = \"AGE\", afun = function(x) { in_rows( \"Mean\" = rcell(mean(x)), .formats = \"xx.xx\" ) }) build_table(lyt1a, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————— # Mean 33.77 35.43 35.43 lyt2 <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(vars = \"AGE\", afun = function(x) { in_rows( \"Mean\" = rcell(mean(x), format = \"xx.xxx\"), .formats = \"xx.xx\" ) }) build_table(lyt2, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————— # Mean 33.77 35.43 35.43"},{"path":"https://insightsengineering.github.io/rtables/articles/format_precedence.html","id":"parent-table-format-and-inheritance","dir":"Articles","previous_headings":"Formats Precedence","what":"Parent Table Format and Inheritance","title":"Format Precedence and NA Handling","text":"addition cell level, format can specified parent table level. format set user cell, specific format cell one defined innermost parent table split (). cell format also specified cell, parent table format ignored cell since cell format specific therefore takes precedence. following, slightly complicated, example, can observe partial inheritance. , SD cells inherit parent table’s format Mean cells .","code":"lyt3 <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(vars = \"AGE\", mean, format = \"xx.x\") build_table(lyt3, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————— # mean 33.8 35.4 35.4 lyt4 <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze( vars = \"AGE\", afun = function(x) { rcell(mean(x), format = \"xx.xx\", label = \"Mean\") }, format = \"xx.x\" ) build_table(lyt4, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————— # Mean 33.77 35.43 35.43 lyt4a <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze( vars = \"AGE\", afun = function(x) { in_rows( \"Mean\" = rcell(mean(x)), \"SD\" = rcell(sd(x)), .formats = \"xx.xx\" ) }, format = \"xx.x\" ) build_table(lyt4a, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————— # Mean 33.77 35.43 35.43 # SD 6.55 7.90 7.72 lyt5 <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze( vars = \"AGE\", afun = function(x) { in_rows( \"Mean\" = rcell(mean(x), format = \"xx.xx\"), \"SD\" = rcell(sd(x)) ) }, format = \"xx.x\" ) build_table(lyt5, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————— # Mean 33.77 35.43 35.43 # SD 6.6 7.9 7.7"},{"path":"https://insightsengineering.github.io/rtables/articles/format_precedence.html","id":"na-handling","dir":"Articles","previous_headings":"","what":"NA Handling","title":"Format Precedence and NA Handling","text":"Consider following layout resulting table created: output cell corresponding UNDIFFERENTIATED level SEX B: Placebo level ARM displayed NA. occurs non-NA values facet used compute mean. rtables allows user specify string display cell values NA. Similar formats numbers, user can specify string replace NA parameter format_na_str .format_na_str. can specified cell parent table level. NA string precedence inheritance rules number format precedence, described previous section vignette. illustrate examples.","code":"lyt6 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(vars = \"AGE\", afun = mean, format = \"xx.xx\") build_table(lyt6, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————— # F # mean 32.76 34.12 35.20 # M # mean 35.57 37.44 35.38 # U # mean 31.67 31.00 35.25 # UNDIFFERENTIATED # mean 28.00 NA 45.00"},{"path":"https://insightsengineering.github.io/rtables/articles/format_precedence.html","id":"replacing-na-values-at-the-cell-level","dir":"Articles","previous_headings":"NA Handling","what":"Replacing NA Values at the Cell Level","title":"Format Precedence and NA Handling","text":"cell level, possible replace NA values custom string means format_na_str parameter rcell() .format_na_str parameter in_rows(). NA string specified places time, one specified in_rows() takes precedence. Technically, case NA replacement string defined rcell() simply overwritten one defined in_rows(). NA string specified in_rows() applied cells, rows (overriding previously specified cell specific values), means precedence rules described still place.","code":"lyt7 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(vars = \"AGE\", afun = function(x) { rcell(mean(x), format = \"xx.xx\", label = \"Mean\", format_na_str = \"\") }) build_table(lyt7, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————— # F # Mean 32.76 34.12 35.20 # M # Mean 35.57 37.44 35.38 # U # Mean 31.67 31.00 35.25 # UNDIFFERENTIATED # Mean 28.00 45.00 lyt7a <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(vars = \"AGE\", afun = function(x) { in_rows( \"Mean\" = rcell(mean(x), format = \"xx.xx\"), .format_na_strs = \"\" ) }) build_table(lyt7a, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————— # F # Mean 32.76 34.12 35.20 # M # Mean 35.57 37.44 35.38 # U # Mean 31.67 31.00 35.25 # UNDIFFERENTIATED # Mean 28.00 45.00 lyt8 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(vars = \"AGE\", afun = function(x) { in_rows( \"Mean\" = rcell(mean(x), format = \"xx.xx\", format_na_str = \"\"), .format_na_strs = \"\" ) }) build_table(lyt8, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————— # F # Mean 32.76 34.12 35.20 # M # Mean 35.57 37.44 35.38 # U # Mean 31.67 31.00 35.25 # UNDIFFERENTIATED # Mean 28.00 45.00"},{"path":"https://insightsengineering.github.io/rtables/articles/format_precedence.html","id":"parent-table-replacement-of-na-values-and-inheritance-principles","dir":"Articles","previous_headings":"NA Handling","what":"Parent Table Replacement of NA Values and Inheritance Principles","title":"Format Precedence and NA Handling","text":"addition cell level, string replacement NA values can specified parent table level. replacement string specified user cell, specific NA string cell one defined innermost parent table split (). NA value replacement string also specified cell level, one set parent table level ignored cell cell level format specific therefore takes precedence. following, slightly complicated example, can observe partial inheritance NA strings. , SD cells inherit parent table’s NA string, Mean cells .","code":"lyt9 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze(vars = \"AGE\", mean, format = \"xx.xx\", na_str = \"not available\") build_table(lyt9, ADSL) # A: Drug X B: Placebo C: Combination # ————————————————————————————————————————————————————————————— # F # mean 32.76 34.12 35.20 # M # mean 35.57 37.44 35.38 # U # mean 31.67 31.00 35.25 # UNDIFFERENTIATED # mean 28.00 not available 45.00 lyt10 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze( vars = \"AGE\", afun = function(x) { rcell(mean(x), format = \"xx.xx\", label = \"Mean\", format_na_str = \"\") }, na_str = \"not available\" ) build_table(lyt10, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————— # F # Mean 32.76 34.12 35.20 # M # Mean 35.57 37.44 35.38 # U # Mean 31.67 31.00 35.25 # UNDIFFERENTIATED # Mean 28.00 45.00 lyt10a <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze( vars = \"AGE\", afun = function(x) { in_rows( \"Mean\" = rcell(mean(x)), \"SD\" = rcell(sd(x)), .formats = \"xx.xx\", .format_na_strs = \"\" ) }, na_str = \"not available\" ) build_table(lyt10a, ADSL) # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————————— # F # Mean 32.76 34.12 35.20 # SD 6.09 7.06 7.43 # M # Mean 35.57 37.44 35.38 # SD 7.08 8.69 8.24 # U # Mean 31.67 31.00 35.25 # SD 3.21 5.66 3.10 # UNDIFFERENTIATED # Mean 28.00 45.00 # SD 1.41 lyt11 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\") %>% analyze( vars = \"AGE\", afun = function(x) { in_rows( \"Mean\" = rcell(mean(x), format_na_str = \"\"), \"SD\" = rcell(sd(x)) ) }, format = \"xx.xx\", na_str = \"not available\" ) build_table(lyt11, ADSL) # A: Drug X B: Placebo C: Combination # ————————————————————————————————————————————————————————————————— # F # Mean 32.76 34.12 35.20 # SD 6.09 7.06 7.43 # M # Mean 35.57 37.44 35.38 # SD 7.08 8.69 8.24 # U # Mean 31.67 31.00 35.25 # SD 3.21 5.66 3.10 # UNDIFFERENTIATED # Mean 28.00 45.00 # SD not available not available 1.41"},{"path":"https://insightsengineering.github.io/rtables/articles/introspecting_tables.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Introspecting Tables","text":"First, let’s set simple table.","code":"lyt <- basic_table() %>% split_cols_by(\"ARMCD\", show_colcounts = TRUE, colcount_format = \"N=xx\") %>% split_cols_by(\"STRATA2\", show_colcounts = TRUE) %>% split_rows_by(\"STRATA1\") %>% add_overall_col(\"All\") %>% summarize_row_groups() %>% analyze(\"AGE\", afun = max, format = \"xx.x\") tbl <- build_table(lyt, ex_adsl) tbl # ARM A ARM B ARM C # N=134 N=134 N=132 # S1 S2 S1 S2 S1 S2 # (N=73) (N=61) (N=67) (N=67) (N=56) (N=76) All # ————————————————————————————————————————————————————————————————————————————————————————————————— # A 18 (24.7%) 20 (32.8%) 22 (32.8%) 22 (32.8%) 14 (25.0%) 26 (34.2%) 122 (30.5%) # max 40.0 46.0 62.0 50.0 47.0 45.0 62.0 # B 28 (38.4%) 19 (31.1%) 19 (28.4%) 26 (38.8%) 18 (32.1%) 25 (32.9%) 135 (33.8%) # max 48.0 47.0 58.0 58.0 46.0 64.0 64.0 # C 27 (37.0%) 22 (36.1%) 26 (38.8%) 19 (28.4%) 24 (42.9%) 25 (32.9%) 143 (35.8%) # max 48.0 50.0 48.0 51.0 69.0 50.0 69.0"},{"path":"https://insightsengineering.github.io/rtables/articles/introspecting_tables.html","id":"getting-started","dir":"Articles","previous_headings":"","what":"Getting Started","title":"Introspecting Tables","text":"can get basic table dimensions, number rows, number columns following code:","code":"dim(tbl) # [1] 6 7 nrow(tbl) # [1] 6 ncol(tbl) # [1] 7"},{"path":"https://insightsengineering.github.io/rtables/articles/introspecting_tables.html","id":"detailed-table-structure","dir":"Articles","previous_headings":"","what":"Detailed Table Structure","title":"Introspecting Tables","text":"table_structure() function prints summary table’s row structure one two levels detail. default, summarizes structure subtable level. detail argument set \"row\", however, provides detailed row-level summary acts useful alternative might normally use str() function interrogate compound nested lists. Similarly, columns can see tree structured following call: information column structure can found vignette col_counts. make_row_df() make_col_df() functions create data.frame variety information table’s structure. useful introspection purposes label, name, abs_rownumber, path node_class columns (remainder information returned data.frame used pagination) also wrapper function, row_paths() available make_row_df display row path structure: default make_row_df() summarizes visible rows, setting visible_only FALSE gives us structural summary table full hierarchy subtables, including represented directly visible rows: make_col_df() similarly accepts visible_only, though meaning slightly different, indicating whether leaf columns summarized (defaults TRUE) whether higher level groups columns - analogous subtables row space - summarized well. Similarly, wrapper function col_paths() available, displays column structure: row_paths_summary() col_paths_summary() functions wrap respective make_*_df functions, printing name, node_class, path information (row case), label path information (column case), indented illustrate table structure:","code":"table_structure(tbl) # [TableTree] STRATA1 # [TableTree] A [cont: 1 x 7] # [ElementaryTable] AGE (1 x 7) # [TableTree] B [cont: 1 x 7] # [ElementaryTable] AGE (1 x 7) # [TableTree] C [cont: 1 x 7] # [ElementaryTable] AGE (1 x 7) table_structure(tbl, detail = \"row\") # or \"subtable\" # TableTree: [STRATA1] (STRATA1) # labelrow: [STRATA1] (STRATA1) - # children: # TableTree: [A] (A) # labelrow: [A] (A) - # content: # ElementaryTable: [A@content] () # labelrow: [] () - # children: # ContentRow: [A] (A) # children: # ElementaryTable: [AGE] (AGE) # labelrow: [AGE] (AGE) - # children: # DataRow: [max] (max) # TableTree: [B] (B) # labelrow: [B] (B) - # content: # ElementaryTable: [B@content] () # labelrow: [] () - # children: # ContentRow: [B] (B) # children: # ElementaryTable: [AGE] (AGE) # labelrow: [AGE] (AGE) - # children: # DataRow: [max] (max) # TableTree: [C] (C) # labelrow: [C] (C) - # content: # ElementaryTable: [C@content] () # labelrow: [] () - # children: # ContentRow: [C] (C) # children: # ElementaryTable: [AGE] (AGE) # labelrow: [AGE] (AGE) - # children: # DataRow: [max] (max) coltree_structure(tbl) # [root] (no pos) # [ARMCD] (no pos) # [ARM A] (ARMCD: ARM A) # [S1] (ARMCD: ARM A -> STRATA2: S1) # [S2] (ARMCD: ARM A -> STRATA2: S2) # [ARM B] (ARMCD: ARM B) # [S1] (ARMCD: ARM B -> STRATA2: S1) # [S2] (ARMCD: ARM B -> STRATA2: S2) # [ARM C] (ARMCD: ARM C) # [S1] (ARMCD: ARM C -> STRATA2: S1) # [S2] (ARMCD: ARM C -> STRATA2: S2) # [All] (no pos) # [All] (All: All) make_row_df(tbl)[, c(\"label\", \"name\", \"abs_rownumber\", \"path\", \"node_class\")] # label name abs_rownumber path node_class # 1 A A 1 STRATA1,.... ContentRow # 2 max max 2 STRATA1,.... DataRow # 3 B B 3 STRATA1,.... ContentRow # 4 max max 4 STRATA1,.... DataRow # 5 C C 5 STRATA1,.... ContentRow # 6 max max 6 STRATA1,.... DataRow row_paths(tbl) # [[1]] # [1] \"STRATA1\" \"A\" \"@content\" \"A\" # # [[2]] # [1] \"STRATA1\" \"A\" \"AGE\" \"max\" # # [[3]] # [1] \"STRATA1\" \"B\" \"@content\" \"B\" # # [[4]] # [1] \"STRATA1\" \"B\" \"AGE\" \"max\" # # [[5]] # [1] \"STRATA1\" \"C\" \"@content\" \"C\" # # [[6]] # [1] \"STRATA1\" \"C\" \"AGE\" \"max\" make_row_df(tbl, visible_only = FALSE)[, c(\"label\", \"name\", \"abs_rownumber\", \"path\", \"node_class\")] # label name abs_rownumber path node_class # 1 STRATA1 NA STRATA1 TableTree # 2 A NA STRATA1, A TableTree # 3 A@content NA STRATA1,.... ElementaryTable # 4 A A 1 STRATA1,.... ContentRow # 5 AGE NA STRATA1,.... ElementaryTable # 6 max max 2 STRATA1,.... DataRow # 7 B NA STRATA1, B TableTree # 8 B@content NA STRATA1,.... ElementaryTable # 9 B B 3 STRATA1,.... ContentRow # 10 AGE NA STRATA1,.... ElementaryTable # 11 max max 4 STRATA1,.... DataRow # 12 C NA STRATA1, C TableTree # 13 C@content NA STRATA1,.... ElementaryTable # 14 C C 5 STRATA1,.... ContentRow # 15 AGE NA STRATA1,.... ElementaryTable # 16 max max 6 STRATA1,.... DataRow make_col_df(tbl)[, c(\"label\", \"name\", \"abs_pos\", \"path\", \"leaf_indices\")] # label name abs_pos path leaf_indices # 1 S1 S1 1 ARMCD, A.... 1 # 2 S2 S2 2 ARMCD, A.... 2 # 3 S1 S1 3 ARMCD, A.... 3 # 4 S2 S2 4 ARMCD, A.... 4 # 5 S1 S1 5 ARMCD, A.... 5 # 6 S2 S2 6 ARMCD, A.... 6 # 7 All All 7 All, All 7 make_col_df(tbl, visible_only = FALSE)[, c(\"label\", \"name\", \"abs_pos\", \"path\", \"leaf_indices\")] # label name abs_pos path leaf_indices # 1 ARM A ARM A NA ARMCD, ARM A 1, 2 # 2 S1 S1 1 ARMCD, A.... 1 # 3 S2 S2 2 ARMCD, A.... 2 # 4 ARM B ARM B NA ARMCD, ARM B 3, 4 # 5 S1 S1 3 ARMCD, A.... 3 # 6 S2 S2 4 ARMCD, A.... 4 # 7 ARM C ARM C NA ARMCD, ARM C 5, 6 # 8 S1 S1 5 ARMCD, A.... 5 # 9 S2 S2 6 ARMCD, A.... 6 # 10 All All 7 All, All 7 col_paths(tbl) # [[1]] # [1] \"ARMCD\" \"ARM A\" \"STRATA2\" \"S1\" # # [[2]] # [1] \"ARMCD\" \"ARM A\" \"STRATA2\" \"S2\" # # [[3]] # [1] \"ARMCD\" \"ARM B\" \"STRATA2\" \"S1\" # # [[4]] # [1] \"ARMCD\" \"ARM B\" \"STRATA2\" \"S2\" # # [[5]] # [1] \"ARMCD\" \"ARM C\" \"STRATA2\" \"S1\" # # [[6]] # [1] \"ARMCD\" \"ARM C\" \"STRATA2\" \"S2\" # # [[7]] # [1] \"All\" \"All\" row_paths_summary(tbl) # rowname node_class path # ———————————————————————————————————————————————— # A ContentRow STRATA1, A, @content, A # max DataRow STRATA1, A, AGE, max # B ContentRow STRATA1, B, @content, B # max DataRow STRATA1, B, AGE, max # C ContentRow STRATA1, C, @content, C # max DataRow STRATA1, C, AGE, max col_paths_summary(tbl) # label path # —————————————————————————————————— # ARM A ARMCD, ARM A # S1 ARMCD, ARM A, STRATA2, S1 # S2 ARMCD, ARM A, STRATA2, S2 # ARM B ARMCD, ARM B # S1 ARMCD, ARM B, STRATA2, S1 # S2 ARMCD, ARM B, STRATA2, S2 # ARM C ARMCD, ARM C # S1 ARMCD, ARM C, STRATA2, S1 # S2 ARMCD, ARM C, STRATA2, S2 # All All, All"},{"path":"https://insightsengineering.github.io/rtables/articles/introspecting_tables.html","id":"insights-on-value-format-structure","dir":"Articles","previous_headings":"","what":"Insights on Value Format Structure","title":"Introspecting Tables","text":"can gain insight value formatting structure table using table_shell(), returns table output print() cell values replaced underlying format strings (e.g. instead 40.0, xx.x displayed, ). useful understanding structure table, debugging purposes. Another useful tool value_formats() function instead table returns matrix format strings cell value table. See printout examples:","code":"table_shell(tbl) # ARM A ARM B ARM C # N=134 N=134 N=132 # S1 S2 S1 S2 S1 S2 # (N=73) (N=61) (N=67) (N=67) (N=56) (N=76) All # ———————————————————————————————————————————————————————————————————————————————————————————————— # A xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) # max xx.x xx.x xx.x xx.x xx.x xx.x xx.x # B xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) # max xx.x xx.x xx.x xx.x xx.x xx.x xx.x # C xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) xx (xx.x%) # max xx.x xx.x xx.x xx.x xx.x xx.x xx.x value_formats(tbl) # ARM A.S1 ARM A.S2 ARM B.S1 ARM B.S2 ARM C.S1 # A \"xx (xx.x%)\" \"xx (xx.x%)\" \"xx (xx.x%)\" \"xx (xx.x%)\" \"xx (xx.x%)\" # max \"xx.x\" \"xx.x\" \"xx.x\" \"xx.x\" \"xx.x\" # B \"xx (xx.x%)\" \"xx (xx.x%)\" \"xx (xx.x%)\" \"xx (xx.x%)\" \"xx (xx.x%)\" # max \"xx.x\" \"xx.x\" \"xx.x\" \"xx.x\" \"xx.x\" # C \"xx (xx.x%)\" \"xx (xx.x%)\" \"xx (xx.x%)\" \"xx (xx.x%)\" \"xx (xx.x%)\" # max \"xx.x\" \"xx.x\" \"xx.x\" \"xx.x\" \"xx.x\" # ARM C.S2 All # A \"xx (xx.x%)\" \"xx (xx.x%)\" # max \"xx.x\" \"xx.x\" # B \"xx (xx.x%)\" \"xx (xx.x%)\" # max \"xx.x\" \"xx.x\" # C \"xx (xx.x%)\" \"xx (xx.x%)\" # max \"xx.x\" \"xx.x\""},{"path":"https://insightsengineering.github.io/rtables/articles/introspecting_tables.html","id":"applications","dir":"Articles","previous_headings":"","what":"Applications","title":"Introspecting Tables","text":"Knowing structure rtable object helpful retrieving specific values table. examples, see Path Based Cell Value Accessing section Subsetting Manipulating Table Contents vignette. Understanding table structure also important post-processing processes sorting pruning. details covered Pruning Sorting Tables vignette vignette.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/introspecting_tables.html","id":"summary","dir":"Articles","previous_headings":"","what":"Summary","title":"Introspecting Tables","text":"vignette learned number utility functions available examining underlying structure rtable objects.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/manual_table_construction.html","id":"overview","dir":"Articles","previous_headings":"","what":"Overview","title":"Constructing rtables Manually","text":"main functions currently associated rtables Tables rtables can constructed via layout rtabulate tabulation frameworks also manually. Currently manual table construction way define column spans. main functions manual table constructions : rtable(): collection rrow() objects, column header default format rrow(): collection rcell() objects default format rcell(): collection data objects cell format","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/manual_table_construction.html","id":"simple-example","dir":"Articles","previous_headings":"","what":"Simple Example","title":"Constructing rtables Manually","text":"go explaining individual components used create table continue html conversion rtable() object: Next, [ operator lets access cell content. format cell run format_rcell(tbl[1,1])=. Note tbl[6, 1] tbl[6, 2] display rcell colspan.","code":"library(rtables) tbl <- rtable( header = c(\"Treatement\\nN=100\", \"Comparison\\nN=300\"), format = \"xx (xx.xx%)\", rrow(\"A\", c(104, .2), c(100, .4)), rrow(\"B\", c(23, .4), c(43, .5)), rrow(), rrow(\"this is a very long section header\"), rrow(\"estimate\", rcell(55.23, \"xx.xx\", colspan = 2)), rrow(\"95% CI\", indent = 1, rcell(c(44.8, 67.4), format = \"(xx.x, xx.x)\", colspan = 2)) ) as_html(tbl, width = \"80%\") tbl[1, 1] # Treatement # N=100 # ———————————————— # A 104 (20.00%)"},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Introduction to {rtables}","text":"rtables package provides framework create, tabulate, output tables R. design requirements rtables origin studying tables commonly used report analyses clinical trials; however, careful keep rtables general purpose toolkit. vignette, give short introduction rtables tabulating table. content vignette based following two resources: rtables useR 2020 presentation Gabriel Becker rtables - Framework Creating Complex Structured Reporting Tables Via Multi-Level Faceted Computations. packages used vignette rtables dplyr:","code":"library(rtables) library(dplyr)"},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"overview","dir":"Articles","previous_headings":"","what":"Overview","title":"Introduction to {rtables}","text":"build table using rtables two components required: layout constructed using rtables functions, data.frame unaggregated data. two elements combined build table object. Table objects contain information content structure table, well instructions information processed construct table. obtaining table object, formatted table can printed ASCII format, exported variety formats (.txt, .pdf, .docx, etc.).","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"data","dir":"Articles","previous_headings":"","what":"Data","title":"Introduction to {rtables}","text":"data used vignette made using random number generators. data content relatively simple: one row per imaginary person one column per measurement: study arm, country origin, gender, handedness, age, weight. Note use factor variables level order represented row column order tabulate information df .","code":"n <- 400 set.seed(1) df <- tibble( arm = factor(sample(c(\"Arm A\", \"Arm B\"), n, replace = TRUE), levels = c(\"Arm A\", \"Arm B\")), country = factor(sample(c(\"CAN\", \"USA\"), n, replace = TRUE, prob = c(.55, .45)), levels = c(\"CAN\", \"USA\")), gender = factor(sample(c(\"Female\", \"Male\"), n, replace = TRUE), levels = c(\"Female\", \"Male\")), handed = factor(sample(c(\"Left\", \"Right\"), n, prob = c(.6, .4), replace = TRUE), levels = c(\"Left\", \"Right\")), age = rchisq(n, 30) + 10 ) %>% mutate( weight = 35 * rnorm(n, sd = .5) + ifelse(gender == \"Female\", 140, 180) ) head(df) # # A tibble: 6 × 6 # arm country gender handed age weight # # 1 Arm A USA Female Left 31.3 139. # 2 Arm B CAN Female Right 50.5 116. # 3 Arm A USA Male Right 32.4 186. # 4 Arm A USA Male Right 34.6 169. # 5 Arm B USA Female Right 43.0 160. # 6 Arm A USA Female Right 43.2 126."},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"building-a-table","dir":"Articles","previous_headings":"","what":"Building a Table","title":"Introduction to {rtables}","text":"aim vignette build following table step step:","code":"# Arm A Arm B # Female Male Female Male # (N=96) (N=105) (N=92) (N=107) # ———————————————————————————————————————————————————————————— # CAN 45 (46.9%) 64 (61.0%) 46 (50.0%) 62 (57.9%) # Left 32 (33.3%) 42 (40.0%) 26 (28.3%) 37 (34.6%) # mean 38.87 40.43 40.33 37.68 # Right 13 (13.5%) 22 (21.0%) 20 (21.7%) 25 (23.4%) # mean 36.64 40.19 40.16 40.65 # USA 51 (53.1%) 41 (39.0%) 46 (50.0%) 45 (42.1%) # Left 34 (35.4%) 19 (18.1%) 25 (27.2%) 25 (23.4%) # mean 40.36 39.68 39.21 40.07 # Right 17 (17.7%) 22 (21.0%) 21 (22.8%) 20 (18.7%) # mean 36.94 39.80 38.53 39.02"},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"quick-start","dir":"Articles","previous_headings":"","what":"Quick Start","title":"Introduction to {rtables}","text":"table can achieved via qtable() function. new tabulation rtables layout framework, can use convenience wrapper create many types two-way frequency tables. purpose qtable enable quick exploratory data analysis. See exploratory_analysis vignette details. code recreate table : qtable function arguments can see many key concepts underlying rtables layout framework. user needs define: variables used facets row /column space? variable used summary analysis? function used summary? table include marginal summaries? labels needed clarify table content? sections look translating questions set features part rtables layout framework. Now let’s take look building example table layout.","code":"qtable(df, row_vars = c(\"country\", \"handed\"), col_vars = c(\"arm\", \"gender\"), avar = \"age\", afun = mean, summarize_groups = TRUE, row_labels = \"mean\" ) # Arm A Arm B # Female Male Female Male # age - mean (N=96) (N=105) (N=92) (N=107) # —————————————————————————————————————————————————————————————— # CAN 45 (46.9%) 64 (61.0%) 46 (50.0%) 62 (57.9%) # Left 32 (33.3%) 42 (40.0%) 26 (28.3%) 37 (34.6%) # mean 38.87 40.43 40.33 37.68 # Right 13 (13.5%) 22 (21.0%) 20 (21.7%) 25 (23.4%) # mean 36.64 40.19 40.16 40.65 # USA 51 (53.1%) 41 (39.0%) 46 (50.0%) 45 (42.1%) # Left 34 (35.4%) 19 (18.1%) 25 (27.2%) 25 (23.4%) # mean 40.36 39.68 39.21 40.07 # Right 17 (17.7%) 22 (21.0%) 21 (22.8%) 20 (18.7%) # mean 36.94 39.80 38.53 39.02"},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"layout-instructions","dir":"Articles","previous_headings":"","what":"Layout Instructions","title":"Introduction to {rtables}","text":"rtables basic table defined 0 rows one column representing data. Analyzing variable one way adding row: code first described table assigned description variable lyt. built table using actual data build_table(). description table called table layout. basic_table() start every table layout contains information one column representing data. analyze() instruction adds layout age variable analyzed mean() analysis function result rounded 1 decimal place. Hence, layout “pre-data”, , ’s description build table get data. can look layout isolated: general layouting instructions summarized : basic_table() layout representing table zero rows one column row space: split_rows_by(), split_rows_by_multivar(), split_rows_by_cuts(), split_rows_by_cutfun(), split_rows_by_quartiles() column space: split_cols_by(), split_cols_by_multivar(), split_cols_by_cuts(), split_cols_by_cutfun(), split_cols_by_quartiles() Summarizing Groups: summarize_row_groups() Analyzing Variables: analyze(), analyze_colvars() Using functions, possible create wide variety tables show document.","code":"lyt <- basic_table() %>% analyze(\"age\", mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # all obs # —————————————— # mean 39.4 lyt # A Pre-data Table Layout # # Column-Split Structure: # () # # Row-Split Structure: # age (** analysis **)"},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"adding-column-structure","dir":"Articles","previous_headings":"","what":"Adding Column Structure","title":"Introduction to {rtables}","text":"now add structure columns adding column split based factor variable arm: resulting table one column per factor level arm. data represented first column df[df$arm == \"ARM \", ]. Hence, split_cols_by() partitions data among columns default. Column splitting can done recursive/nested manner adding sequential split_cols_by() layout instruction. ’s also possible add non-nested split. splitting arm gender: first column represents data df df$arm == \"\" & df$gender == \"Female\" second column data df df$arm == \"\" & df$gender == \"Male\", . information column structure can found col_counts vignette.","code":"lyt <- basic_table() %>% split_cols_by(\"arm\") %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # Arm A Arm B # ———————————————————— # mean 39.5 39.4 lyt <- basic_table() %>% split_cols_by(\"arm\") %>% split_cols_by(\"gender\") %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # Arm A Arm B # Female Male Female Male # ———————————————————————————————————— # mean 38.8 40.1 39.6 39.2"},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"adding-row-structure","dir":"Articles","previous_headings":"","what":"Adding Row Structure","title":"Introduction to {rtables}","text":"far, created layouts analysis column splitting instructions, .e. analyze() split_cols_by(), respectively. resulted table multiple columns one data row. add row structure stratifying mean analysis country (.e. adding split row space): table data used derive first data cell (average age female Canadians Arm ) df$country == \"CAN\" & df$arm == \"Arm \" & df$gender == \"Female\". cell value can also calculated manually: Row structure can also used group table titled groups pages rendering. via ‘page splits’, declared via page_by = TRUE within call split_rows_by: go detail page-splits control page-group specific titles Title footer vignette. Note print render table without pagination, page_by splits currently rendered normal row splits. may change future releases.","code":"lyt <- basic_table() %>% split_cols_by(\"arm\") %>% split_cols_by(\"gender\") %>% split_rows_by(\"country\") %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # Arm A Arm B # Female Male Female Male # —————————————————————————————————————— # CAN # mean 38.2 40.3 40.3 38.9 # USA # mean 39.2 39.7 38.9 39.6 mean(df$age[df$country == \"CAN\" & df$arm == \"Arm A\" & df$gender == \"Female\"]) # [1] 38.22447 lyt <- basic_table() %>% split_cols_by(\"arm\") %>% split_cols_by(\"gender\") %>% split_rows_by(\"country\", page_by = TRUE) %>% split_rows_by(\"handed\") %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) cat(export_as_txt(tbl, page_type = \"letter\", page_break = \"\\n\\n~~~~~~ Page Break ~~~~~~\\n\\n\")) # # country: CAN # # ———————————————————————————————————————— # Arm A Arm B # Female Male Female Male # ———————————————————————————————————————— # Left # mean 38.9 40.4 40.3 37.7 # Right # mean 36.6 40.2 40.2 40.6 # # # ~~~~~~ Page Break ~~~~~~ # # # country: USA # # ———————————————————————————————————————— # Arm A Arm B # Female Male Female Male # ———————————————————————————————————————— # Left # mean 40.4 39.7 39.2 40.1 # Right # mean 36.9 39.8 38.5 39.0"},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"adding-group-information","dir":"Articles","previous_headings":"","what":"Adding Group Information","title":"Introduction to {rtables}","text":"adding row splits, get default label rows split level, example CAN USA table . Besides column space subsetting, now subsetted data cell. often useful defining row splitting display information row group. rtables referred content information, .e. mean() row 2 descendant CAN (visible via indenting, though table underlying tree structure importance vignette). order add content information turn CAN label row content row, summarize_row_groups() function required. default, count (nrows()) percentage data relative column associated data calculated: relative percentage average age female Canadians calculated follows: group percentages per row split sum 1 column. can split row space dividing country handedness: Next, add count percentage summary handedness within country:","code":"lyt <- basic_table() %>% split_cols_by(\"arm\") %>% split_cols_by(\"gender\") %>% split_rows_by(\"country\") %>% summarize_row_groups() %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # Arm A Arm B # Female Male Female Male # —————————————————————————————————————————————————————————— # CAN 45 (46.9%) 64 (61.0%) 46 (50.0%) 62 (57.9%) # mean 38.2 40.3 40.3 38.9 # USA 51 (53.1%) 41 (39.0%) 46 (50.0%) 45 (42.1%) # mean 39.2 39.7 38.9 39.6 df_cell <- subset(df, df$country == \"CAN\" & df$arm == \"Arm A\" & df$gender == \"Female\") df_col_1 <- subset(df, df$arm == \"Arm A\" & df$gender == \"Female\") c(count = nrow(df_cell), percentage = nrow(df_cell) / nrow(df_col_1)) # count percentage # 45.00000 0.46875 lyt <- basic_table() %>% split_cols_by(\"arm\") %>% split_cols_by(\"gender\") %>% split_rows_by(\"country\") %>% summarize_row_groups() %>% split_rows_by(\"handed\") %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # Arm A Arm B # Female Male Female Male # ———————————————————————————————————————————————————————————— # CAN 45 (46.9%) 64 (61.0%) 46 (50.0%) 62 (57.9%) # Left # mean 38.9 40.4 40.3 37.7 # Right # mean 36.6 40.2 40.2 40.6 # USA 51 (53.1%) 41 (39.0%) 46 (50.0%) 45 (42.1%) # Left # mean 40.4 39.7 39.2 40.1 # Right # mean 36.9 39.8 38.5 39.0 lyt <- basic_table() %>% split_cols_by(\"arm\") %>% split_cols_by(\"gender\") %>% split_rows_by(\"country\") %>% summarize_row_groups() %>% split_rows_by(\"handed\") %>% summarize_row_groups() %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # Arm A Arm B # Female Male Female Male # ———————————————————————————————————————————————————————————— # CAN 45 (46.9%) 64 (61.0%) 46 (50.0%) 62 (57.9%) # Left 32 (33.3%) 42 (40.0%) 26 (28.3%) 37 (34.6%) # mean 38.9 40.4 40.3 37.7 # Right 13 (13.5%) 22 (21.0%) 20 (21.7%) 25 (23.4%) # mean 36.6 40.2 40.2 40.6 # USA 51 (53.1%) 41 (39.0%) 46 (50.0%) 45 (42.1%) # Left 34 (35.4%) 19 (18.1%) 25 (27.2%) 25 (23.4%) # mean 40.4 39.7 39.2 40.1 # Right 17 (17.7%) 22 (21.0%) 21 (22.8%) 20 (18.7%) # mean 36.9 39.8 38.5 39.0"},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"comparing-with-other-tabulation-frameworks","dir":"Articles","previous_headings":"","what":"Comparing with Other Tabulation Frameworks","title":"Introduction to {rtables}","text":"number table frameworks available R, including: gt xtable tableone tables number reasons choose rtables (yet another tables R package): Output tables ASCII text files. Table rendering (ASCII, HTML, etc.) separate data model. Hence, one always access non-rounded/non-formatted numbers. Pagination horizontal vertical directions meet health authority submission requirements. Cell, row, column, table reference system. Titles, footers, referential footnotes. Path based access cell content useful automated content generation. depth comparisons various tabulation frameworks can found Overview table R packages chapter Tables Clinical Trials R book compiled R Consortium Tables Working Group.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/rtables.html","id":"summary","dir":"Articles","previous_headings":"","what":"Summary","title":"Introduction to {rtables}","text":"vignette learned: Every cell associated subset data - means much tabulation splitting/subsetting data. Tables can described pre-data using layouts. Tables form visualization data. vignettes rtables package provide detailed information rtables package. recommend continue tabulation_dplyr vignette compares information derived table vignette using dplyr.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Pruning and Sorting Tables","text":"Often want filter reorder elements table ways take account table structure. example: Sorting subtables corresponding factor levels commonly observed levels occur first table. Sorting rows within single subtable Removing subtables represent 0 observations filtering contain 0 rows.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"a-table-in-need-of-attention","dir":"Articles","previous_headings":"","what":"A Table In Need of Attention","title":"Pruning and Sorting Tables","text":"","code":"library(rtables) library(dplyr) raw_lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_cols_by(\"SEX\") %>% split_rows_by(\"RACE\") %>% summarize_row_groups() %>% split_rows_by(\"STRATA1\") %>% summarize_row_groups() %>% analyze(\"AGE\") raw_tbl <- build_table(raw_lyt, DM) raw_tbl # A: Drug X B: Placebo C: Combination # F M U UNDIFFERENTIATED F M U UNDIFFERENTIATED F M U UNDIFFERENTIATED # —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 0 (NA%) 0 (NA%) 37 (66.1%) 31 (62.0%) 0 (NA%) 0 (NA%) 40 (65.6%) 44 (64.7%) 0 (NA%) 0 (NA%) # A 15 (21.4%) 12 (23.5%) 0 (NA%) 0 (NA%) 14 (25.0%) 6 (12.0%) 0 (NA%) 0 (NA%) 15 (24.6%) 16 (23.5%) 0 (NA%) 0 (NA%) # Mean 30.40 34.42 NA NA 35.43 30.33 NA NA 37.40 36.25 NA NA # B 16 (22.9%) 8 (15.7%) 0 (NA%) 0 (NA%) 13 (23.2%) 16 (32.0%) 0 (NA%) 0 (NA%) 10 (16.4%) 12 (17.6%) 0 (NA%) 0 (NA%) # Mean 33.75 34.88 NA NA 32.46 30.94 NA NA 33.30 35.92 NA NA # C 13 (18.6%) 15 (29.4%) 0 (NA%) 0 (NA%) 10 (17.9%) 9 (18.0%) 0 (NA%) 0 (NA%) 15 (24.6%) 16 (23.5%) 0 (NA%) 0 (NA%) # Mean 36.92 35.60 NA NA 34.00 31.89 NA NA 33.47 31.38 NA NA # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 0 (NA%) 0 (NA%) 12 (21.4%) 12 (24.0%) 0 (NA%) 0 (NA%) 13 (21.3%) 14 (20.6%) 0 (NA%) 0 (NA%) # A 5 (7.1%) 1 (2.0%) 0 (NA%) 0 (NA%) 5 (8.9%) 2 (4.0%) 0 (NA%) 0 (NA%) 4 (6.6%) 4 (5.9%) 0 (NA%) 0 (NA%) # Mean 31.20 33.00 NA NA 28.00 30.00 NA NA 30.75 36.50 NA NA # B 7 (10.0%) 3 (5.9%) 0 (NA%) 0 (NA%) 3 (5.4%) 3 (6.0%) 0 (NA%) 0 (NA%) 6 (9.8%) 6 (8.8%) 0 (NA%) 0 (NA%) # Mean 36.14 34.33 NA NA 29.67 32.00 NA NA 36.33 31.00 NA NA # C 6 (8.6%) 6 (11.8%) 0 (NA%) 0 (NA%) 4 (7.1%) 7 (14.0%) 0 (NA%) 0 (NA%) 3 (4.9%) 4 (5.9%) 0 (NA%) 0 (NA%) # Mean 31.33 39.67 NA NA 34.50 34.00 NA NA 33.00 36.50 NA NA # WHITE 8 (11.4%) 6 (11.8%) 0 (NA%) 0 (NA%) 7 (12.5%) 7 (14.0%) 0 (NA%) 0 (NA%) 8 (13.1%) 10 (14.7%) 0 (NA%) 0 (NA%) # A 2 (2.9%) 1 (2.0%) 0 (NA%) 0 (NA%) 3 (5.4%) 3 (6.0%) 0 (NA%) 0 (NA%) 1 (1.6%) 5 (7.4%) 0 (NA%) 0 (NA%) # Mean 34.00 45.00 NA NA 29.33 33.33 NA NA 35.00 32.80 NA NA # B 4 (5.7%) 3 (5.9%) 0 (NA%) 0 (NA%) 1 (1.8%) 4 (8.0%) 0 (NA%) 0 (NA%) 3 (4.9%) 1 (1.5%) 0 (NA%) 0 (NA%) # Mean 37.00 43.67 NA NA 48.00 36.75 NA NA 34.33 36.00 NA NA # C 2 (2.9%) 2 (3.9%) 0 (NA%) 0 (NA%) 3 (5.4%) 0 (0.0%) 0 (NA%) 0 (NA%) 4 (6.6%) 4 (5.9%) 0 (NA%) 0 (NA%) # Mean 35.50 44.00 NA NA 44.67 NA NA NA 38.50 35.00 NA NA # AMERICAN INDIAN OR ALASKA NATIVE 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # A 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # B 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # C 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # MULTIPLE 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # A 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # B 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # C 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # A 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # B 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # C 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # OTHER 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # A 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # B 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # C 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # UNKNOWN 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # A 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # B 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA # C 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) 0 (0.0%) 0 (0.0%) 0 (NA%) 0 (NA%) # Mean NA NA NA NA NA NA NA NA NA NA NA NA"},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"trimming-rows","dir":"Articles","previous_headings":"Trimming","what":"Trimming Rows","title":"Pruning and Sorting Tables","text":"Trimming represents convenience wrapper around simple, direct subsetting rows TableTree. use trim_rows() function table criteria function. rows criteria function returns TRUE removed, others retained. NOTE: row kept removed completely independently, awareness surrounding structure. means, example, subtree analysis rows removed removed . structure-aware filtering table, use pruning described next section. trimming function accepts TableRow object returns TRUE row removed. default trimming function removes rows columns values , .e. NA values 0 values:","code":"trim_rows(raw_tbl) # A: Drug X B: Placebo C: Combination # F M U UNDIFFERENTIATED F M U UNDIFFERENTIATED F M U UNDIFFERENTIATED # —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 0 (NA%) 0 (NA%) 37 (66.1%) 31 (62.0%) 0 (NA%) 0 (NA%) 40 (65.6%) 44 (64.7%) 0 (NA%) 0 (NA%) # A 15 (21.4%) 12 (23.5%) 0 (NA%) 0 (NA%) 14 (25.0%) 6 (12.0%) 0 (NA%) 0 (NA%) 15 (24.6%) 16 (23.5%) 0 (NA%) 0 (NA%) # Mean 30.40 34.42 NA NA 35.43 30.33 NA NA 37.40 36.25 NA NA # B 16 (22.9%) 8 (15.7%) 0 (NA%) 0 (NA%) 13 (23.2%) 16 (32.0%) 0 (NA%) 0 (NA%) 10 (16.4%) 12 (17.6%) 0 (NA%) 0 (NA%) # Mean 33.75 34.88 NA NA 32.46 30.94 NA NA 33.30 35.92 NA NA # C 13 (18.6%) 15 (29.4%) 0 (NA%) 0 (NA%) 10 (17.9%) 9 (18.0%) 0 (NA%) 0 (NA%) 15 (24.6%) 16 (23.5%) 0 (NA%) 0 (NA%) # Mean 36.92 35.60 NA NA 34.00 31.89 NA NA 33.47 31.38 NA NA # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 0 (NA%) 0 (NA%) 12 (21.4%) 12 (24.0%) 0 (NA%) 0 (NA%) 13 (21.3%) 14 (20.6%) 0 (NA%) 0 (NA%) # A 5 (7.1%) 1 (2.0%) 0 (NA%) 0 (NA%) 5 (8.9%) 2 (4.0%) 0 (NA%) 0 (NA%) 4 (6.6%) 4 (5.9%) 0 (NA%) 0 (NA%) # Mean 31.20 33.00 NA NA 28.00 30.00 NA NA 30.75 36.50 NA NA # B 7 (10.0%) 3 (5.9%) 0 (NA%) 0 (NA%) 3 (5.4%) 3 (6.0%) 0 (NA%) 0 (NA%) 6 (9.8%) 6 (8.8%) 0 (NA%) 0 (NA%) # Mean 36.14 34.33 NA NA 29.67 32.00 NA NA 36.33 31.00 NA NA # C 6 (8.6%) 6 (11.8%) 0 (NA%) 0 (NA%) 4 (7.1%) 7 (14.0%) 0 (NA%) 0 (NA%) 3 (4.9%) 4 (5.9%) 0 (NA%) 0 (NA%) # Mean 31.33 39.67 NA NA 34.50 34.00 NA NA 33.00 36.50 NA NA # WHITE 8 (11.4%) 6 (11.8%) 0 (NA%) 0 (NA%) 7 (12.5%) 7 (14.0%) 0 (NA%) 0 (NA%) 8 (13.1%) 10 (14.7%) 0 (NA%) 0 (NA%) # A 2 (2.9%) 1 (2.0%) 0 (NA%) 0 (NA%) 3 (5.4%) 3 (6.0%) 0 (NA%) 0 (NA%) 1 (1.6%) 5 (7.4%) 0 (NA%) 0 (NA%) # Mean 34.00 45.00 NA NA 29.33 33.33 NA NA 35.00 32.80 NA NA # B 4 (5.7%) 3 (5.9%) 0 (NA%) 0 (NA%) 1 (1.8%) 4 (8.0%) 0 (NA%) 0 (NA%) 3 (4.9%) 1 (1.5%) 0 (NA%) 0 (NA%) # Mean 37.00 43.67 NA NA 48.00 36.75 NA NA 34.33 36.00 NA NA # C 2 (2.9%) 2 (3.9%) 0 (NA%) 0 (NA%) 3 (5.4%) 0 (0.0%) 0 (NA%) 0 (NA%) 4 (6.6%) 4 (5.9%) 0 (NA%) 0 (NA%) # Mean 35.50 44.00 NA NA 44.67 NA NA NA 38.50 35.00 NA NA"},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"trimming-columns","dir":"Articles","previous_headings":"Trimming","what":"Trimming Columns","title":"Pruning and Sorting Tables","text":"currently special utilities trimming columns can remove empty columns fairly straightforward column subsetting using col_counts() function: Now, interesting see table structured: deeper understanding fundamental structures rtables, suggest taking look slides 69-76 Slide deck. brief, important notice [TableTree] RACE root table split (split_rows_by(\"RACE\") %>%) two subtables: [TableTree] ASIAN [cont: 1 x 6] [TableTree] BLACK AFRICAN AMERICAN [cont: 1 x 6]. “described” summarize_row_groups() %>%, creates every split “content” table containing 1 row (1 cont: 1 x 6), rendered takes place LabelRow. two subtables contain STRATA1 table, representing split_rows_by(\"STRATA1\") layout, , similar RACE table, split subtables: one strata similar content tables; individual strata subtable, , contains ElementaryTable (whose children individual rows) generated analyze(\"AGE\") layout directive, .e. [ElementaryTable] AGE (1 x 6). subtable row structure important sorting pruning; values “content” (ContentRow) “value” (DataRow) rows use different access functions treated differently. Another interesting function can used understand connection row names representational path following:","code":"coltrimmed <- raw_tbl[, col_counts(raw_tbl) > 0] # Note: method with signature 'VTableTree#missing#ANY' chosen for function '[', # target signature 'TableTree#missing#logical'. # \"VTableTree#ANY#logical\" would also be valid h_coltrimmed <- head(coltrimmed, n = 14) h_coltrimmed # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 table_structure(h_coltrimmed) # [TableTree] RACE # [TableTree] ASIAN [cont: 1 x 6] # [TableTree] STRATA1 # [TableTree] A [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] B [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] C [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] BLACK OR AFRICAN AMERICAN [cont: 1 x 6] # [TableTree] STRATA1 # [TableTree] A [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] B [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] C [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) row_paths_summary(h_coltrimmed) # rowname node_class path # ——————————————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN ContentRow RACE, ASIAN, @content, ASIAN # A ContentRow RACE, ASIAN, STRATA1, A, @content, A # Mean DataRow RACE, ASIAN, STRATA1, A, AGE, Mean # B ContentRow RACE, ASIAN, STRATA1, B, @content, B # Mean DataRow RACE, ASIAN, STRATA1, B, AGE, Mean # C ContentRow RACE, ASIAN, STRATA1, C, @content, C # Mean DataRow RACE, ASIAN, STRATA1, C, AGE, Mean # BLACK OR AFRICAN AMERICAN ContentRow RACE, BLACK OR AFRICAN AMERICAN, @content, BLACK OR AFRICAN AMERICAN # A ContentRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, A, @content, A # Mean DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, A, AGE, Mean # B ContentRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, B, @content, B # Mean DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, B, AGE, Mean # C ContentRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, C, @content, C # Mean DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, C, AGE, Mean"},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"pruning","dir":"Articles","previous_headings":"","what":"Pruning","title":"Pruning and Sorting Tables","text":"Pruning similar outcome trimming, powerful complex, takes structure account. Pruning applied recursively, structural unit (subtable, row) applies pruning function level ’s children (user-specifiable maximum depth). default pruning function, example, determines subtree empty : Removing children contain single content row contains zeros NAs Removing rows contain either zeros NAs Removing full subtree unpruned children remain can also use low_obs_pruner() pruning function constructor create pruning function removes subtrees content summaries whose first entries column sum average specified number. (default summaries first entry per column count). Note pruning applied recursively, ASIAN subtree remains even though full BLACK AFRICAN AMERICAN subtree encompassed enough observations, strata within . can take care setting stop_depth pruning 1. can also see pruning lower number observations, say, total 16, stop_depth removes strata third race (WHITE).","code":"pruned <- prune_table(coltrimmed) pruned # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # A 2 (2.9%) 1 (2.0%) 3 (5.4%) 3 (6.0%) 1 (1.6%) 5 (7.4%) # Mean 34.00 45.00 29.33 33.33 35.00 32.80 # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00 # C 2 (2.9%) 2 (3.9%) 3 (5.4%) 0 (0.0%) 4 (6.6%) 4 (5.9%) # Mean 35.50 44.00 44.67 NA 38.50 35.00 pruned2 <- prune_table(coltrimmed, low_obs_pruner(10, \"mean\")) pruned2 # A: Drug X B: Placebo C: Combination # F M F M F M # —————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 pruned3 <- prune_table(coltrimmed, low_obs_pruner(10, \"sum\"), stop_depth = 1) pruned3 # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # A 2 (2.9%) 1 (2.0%) 3 (5.4%) 3 (6.0%) 1 (1.6%) 5 (7.4%) # Mean 34.00 45.00 29.33 33.33 35.00 32.80 # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00 # C 2 (2.9%) 2 (3.9%) 3 (5.4%) 0 (0.0%) 4 (6.6%) 4 (5.9%) # Mean 35.50 44.00 44.67 NA 38.50 35.00 pruned4 <- prune_table(coltrimmed, low_obs_pruner(16, \"sum\")) pruned4 # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00"},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"sorting-fundamentals","dir":"Articles","previous_headings":"Sorting","what":"Sorting Fundamentals","title":"Pruning and Sorting Tables","text":"Sorting rtables table done path, meaning sort operation occur particular location within table, direct children element path reordered. occurs whether children subtables , individual rows. Sorting done via sort_at_path() function, accepts (row) path scoring function. score function accepts subtree TableRow returns single orderable (typically numeric) value. Within subtable currently sorted, children reordered value score function. Importantly, “content” (ContentRow) “values” (DataRow) need treated differently scoring function retrieved: content subtable retrieved via content _table accessor. cont_n_allcols() scoring function provided rtables, works scoring subtables sum first elements first row subtable’s content table. Note function fails child scored content function (.e., summarize_row_groups() used corresponding point layout). can see ’s definition, : Therefore, fundamental difference pruning sorting sorting occurs particular places table, defined path. example, can sort strata values (ContentRow) observation counts within just ASIAN subtable:","code":"cont_n_allcols # function (tt) # { # ctab <- content_table(tt) # if (NROW(ctab) == 0) { # stop(\"cont_n_allcols score function used at subtable [\", # obj_name(tt), \"] that has no content table.\") # } # sum(sapply(row_values(tree_children(ctab)[[1]]), function(cv) cv[1])) # } # # sort_at_path(pruned, path = c(\"RACE\", \"ASIAN\", \"STRATA1\"), scorefun = cont_n_allcols) # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # A 2 (2.9%) 1 (2.0%) 3 (5.4%) 3 (6.0%) 1 (1.6%) 5 (7.4%) # Mean 34.00 45.00 29.33 33.33 35.00 32.80 # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00 # C 2 (2.9%) 2 (3.9%) 3 (5.4%) 0 (0.0%) 4 (6.6%) 4 (5.9%) # Mean 35.50 44.00 44.67 NA 38.50 35.00 # B and C are swapped as the global count (sum of all column counts) of strata C is higher than the one of strata B"},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"wildcards-in-sort-paths","dir":"Articles","previous_headings":"Sorting","what":"Wildcards in Sort Paths","title":"Pruning and Sorting Tables","text":"Unlike uses pathing (currently), sorting path can contain “*“. indicates children subtable matching * element path sorted separately indicated remainder path * score function. Thus can extend sorting strata within ASIAN subtable race-specific subtables using wildcard: equivalent separately calling following: possible understand better pathing table_structure() highlights tree-like structure node names: row_paths_summary: Note latter see content rows paths following @content, e.g., ASIAN, @content, ASIAN. first given path (.e., , @content, <> rows used scoring functions begin cont_. can directly sort ethnicity observations increasing order: Within ethnicity separately, sort strata number females arm C (.e. column position 5):","code":"sort_at_path(pruned, path = c(\"RACE\", \"*\", \"STRATA1\"), scorefun = cont_n_allcols) # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00 # A 2 (2.9%) 1 (2.0%) 3 (5.4%) 3 (6.0%) 1 (1.6%) 5 (7.4%) # Mean 34.00 45.00 29.33 33.33 35.00 32.80 # C 2 (2.9%) 2 (3.9%) 3 (5.4%) 0 (0.0%) 4 (6.6%) 4 (5.9%) # Mean 35.50 44.00 44.67 NA 38.50 35.00 # All subtables, i.e. ASIAN, BLACK..., and WHITE, are reordered separately tmptbl <- sort_at_path(pruned, path = c(\"RACE\", \"ASIAN\", \"STRATA1\"), scorefun = cont_n_allcols) tmptbl <- sort_at_path(tmptbl, path = c(\"RACE\", \"BLACK OR AFRICAN AMERICAN\", \"STRATA1\"), scorefun = cont_n_allcols) tmptbl <- sort_at_path(tmptbl, path = c(\"RACE\", \"WHITE\", \"STRATA1\"), scorefun = cont_n_allcols) tmptbl # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00 # A 2 (2.9%) 1 (2.0%) 3 (5.4%) 3 (6.0%) 1 (1.6%) 5 (7.4%) # Mean 34.00 45.00 29.33 33.33 35.00 32.80 # C 2 (2.9%) 2 (3.9%) 3 (5.4%) 0 (0.0%) 4 (6.6%) 4 (5.9%) # Mean 35.50 44.00 44.67 NA 38.50 35.00 table_structure(pruned) # [TableTree] RACE # [TableTree] ASIAN [cont: 1 x 6] # [TableTree] STRATA1 # [TableTree] A [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] B [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] C [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] BLACK OR AFRICAN AMERICAN [cont: 1 x 6] # [TableTree] STRATA1 # [TableTree] A [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] B [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] C [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] WHITE [cont: 1 x 6] # [TableTree] STRATA1 # [TableTree] A [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] B [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) # [TableTree] C [cont: 1 x 6] # [ElementaryTable] AGE (1 x 6) row_paths_summary(pruned) # rowname node_class path # ——————————————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN ContentRow RACE, ASIAN, @content, ASIAN # A ContentRow RACE, ASIAN, STRATA1, A, @content, A # Mean DataRow RACE, ASIAN, STRATA1, A, AGE, Mean # B ContentRow RACE, ASIAN, STRATA1, B, @content, B # Mean DataRow RACE, ASIAN, STRATA1, B, AGE, Mean # C ContentRow RACE, ASIAN, STRATA1, C, @content, C # Mean DataRow RACE, ASIAN, STRATA1, C, AGE, Mean # BLACK OR AFRICAN AMERICAN ContentRow RACE, BLACK OR AFRICAN AMERICAN, @content, BLACK OR AFRICAN AMERICAN # A ContentRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, A, @content, A # Mean DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, A, AGE, Mean # B ContentRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, B, @content, B # Mean DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, B, AGE, Mean # C ContentRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, C, @content, C # Mean DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, C, AGE, Mean # WHITE ContentRow RACE, WHITE, @content, WHITE # A ContentRow RACE, WHITE, STRATA1, A, @content, A # Mean DataRow RACE, WHITE, STRATA1, A, AGE, Mean # B ContentRow RACE, WHITE, STRATA1, B, @content, B # Mean DataRow RACE, WHITE, STRATA1, B, AGE, Mean # C ContentRow RACE, WHITE, STRATA1, C, @content, C # Mean DataRow RACE, WHITE, STRATA1, C, AGE, Mean ethsort <- sort_at_path(pruned, path = c(\"RACE\"), scorefun = cont_n_allcols, decreasing = FALSE) ethsort # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # A 2 (2.9%) 1 (2.0%) 3 (5.4%) 3 (6.0%) 1 (1.6%) 5 (7.4%) # Mean 34.00 45.00 29.33 33.33 35.00 32.80 # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00 # C 2 (2.9%) 2 (3.9%) 3 (5.4%) 0 (0.0%) 4 (6.6%) 4 (5.9%) # Mean 35.50 44.00 44.67 NA 38.50 35.00 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 sort_at_path(pruned, path = c(\"RACE\", \"*\", \"STRATA1\"), cont_n_onecol(5)) # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # C 2 (2.9%) 2 (3.9%) 3 (5.4%) 0 (0.0%) 4 (6.6%) 4 (5.9%) # Mean 35.50 44.00 44.67 NA 38.50 35.00 # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00 # A 2 (2.9%) 1 (2.0%) 3 (5.4%) 3 (6.0%) 1 (1.6%) 5 (7.4%) # Mean 34.00 45.00 29.33 33.33 35.00 32.80"},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"sorting-within-an-analysis-subtable","dir":"Articles","previous_headings":"Sorting","what":"Sorting Within an Analysis Subtable","title":"Pruning and Sorting Tables","text":"sorting within analysis subtable (e.g., subtable generated analysis function generates one row per group data), name subtable (generally name variable analyzed) must appear path, even variable label displayed table printed. show differences sorting analysis subtable (DataRow), content subtable (ContentRow), modify prune () similar raw table : now want sort median mean strata variables? need write custom score function ready-made ones moment work content nodes (content_table() access function cont_n_allcols() cont_n_onecol(), talk moment). , need think ordering, .e. need specify right path. suggest looking structure first table_structure() row_paths_summary(). see order AGE nodes need get something like : RACE, ASIAN, STRATA1, , AGE next level need sort. see now path sort first group. need wildcards: RACE, *, STRATA1, *, AGE. Now, found way select relevant paths want sort. want construct scoring function works median mean sort . , may want enter scoring function browser() see fed try retrieve single value returned sorting. allow user experiment , show possible solution considers summing column values retrieved row_values(tt) subtable fed function . Note score function defined subtable tt unique input parameter single numeric value output. help user visualize happening score function show example exploration debugging: can see powerful pragmatic might change sorting principles within custom scoring function. show selecting specific column sort. Looking pre-defined function cont_n_onecol() gives us insight proceed. see similar function cont_n_allcols() wrapped one allows parameter j used select specific column. selecting column want sort. table see mean median rows reordered values first column, compared raw table, desired. function can also columns nested within larger splits:","code":"more_analysis_fnc <- function(x) { in_rows( \"median\" = median(x), \"mean\" = mean(x), .formats = \"xx.x\" ) } raw_lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by( \"RACE\", split_fun = drop_and_remove_levels(\"WHITE\") # dropping WHITE levels ) %>% summarize_row_groups() %>% split_rows_by(\"STRATA1\") %>% summarize_row_groups() %>% analyze(\"AGE\", afun = more_analysis_fnc) tbl <- build_table(raw_lyt, DM) %>% prune_table() %>% print() # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————————————— # ASIAN 79 (65.3%) 68 (64.2%) 84 (65.1%) # A 27 (22.3%) 20 (18.9%) 31 (24.0%) # median 30.0 33.0 36.0 # mean 32.2 33.9 36.8 # B 24 (19.8%) 29 (27.4%) 22 (17.1%) # median 32.5 32.0 34.0 # mean 34.1 31.6 34.7 # C 28 (23.1%) 19 (17.9%) 31 (24.0%) # median 36.5 34.0 33.0 # mean 36.2 33.0 32.4 # BLACK OR AFRICAN AMERICAN 28 (23.1%) 24 (22.6%) 27 (20.9%) # A 6 (5.0%) 7 (6.6%) 8 (6.2%) # median 32.0 29.0 32.5 # mean 31.5 28.6 33.6 # B 10 (8.3%) 6 (5.7%) 12 (9.3%) # median 33.0 30.0 33.5 # mean 35.6 30.8 33.7 # C 12 (9.9%) 11 (10.4%) 7 (5.4%) # median 33.0 36.0 32.0 # mean 35.5 34.2 35.0 table_structure(tbl) # Direct inspection into the tree-like structure of rtables # [TableTree] RACE # [TableTree] ASIAN [cont: 1 x 3] # [TableTree] STRATA1 # [TableTree] A [cont: 1 x 3] # [ElementaryTable] AGE (2 x 3) # [TableTree] B [cont: 1 x 3] # [ElementaryTable] AGE (2 x 3) # [TableTree] C [cont: 1 x 3] # [ElementaryTable] AGE (2 x 3) # [TableTree] BLACK OR AFRICAN AMERICAN [cont: 1 x 3] # [TableTree] STRATA1 # [TableTree] A [cont: 1 x 3] # [ElementaryTable] AGE (2 x 3) # [TableTree] B [cont: 1 x 3] # [ElementaryTable] AGE (2 x 3) # [TableTree] C [cont: 1 x 3] # [ElementaryTable] AGE (2 x 3) scorefun <- function(tt) { # Here we could use browser() sum(unlist(row_values(tt))) } sort_at_path(tbl, c(\"RACE\", \"*\", \"STRATA1\", \"*\", \"AGE\"), scorefun) # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————————————— # ASIAN 79 (65.3%) 68 (64.2%) 84 (65.1%) # A 27 (22.3%) 20 (18.9%) 31 (24.0%) # mean 32.2 33.9 36.8 # median 30.0 33.0 36.0 # B 24 (19.8%) 29 (27.4%) 22 (17.1%) # mean 34.1 31.6 34.7 # median 32.5 32.0 34.0 # C 28 (23.1%) 19 (17.9%) 31 (24.0%) # median 36.5 34.0 33.0 # mean 36.2 33.0 32.4 # BLACK OR AFRICAN AMERICAN 28 (23.1%) 24 (22.6%) 27 (20.9%) # A 6 (5.0%) 7 (6.6%) 8 (6.2%) # mean 31.5 28.6 33.6 # median 32.0 29.0 32.5 # B 10 (8.3%) 6 (5.7%) 12 (9.3%) # mean 35.6 30.8 33.7 # median 33.0 30.0 33.5 # C 12 (9.9%) 11 (10.4%) 7 (5.4%) # mean 35.5 34.2 35.0 # median 33.0 36.0 32.0 > sort_at_path(tbl, c(\"RACE\", \"*\", \"STRATA1\", \"*\", \"AGE\"), scorefun) Called from: scorefun(x) Browse[1]> tt ### THIS IS THE LEAF LEVEL -> DataRow ### [DataRow indent_mod 0]: median 30.0 33.0 36.0 Browse[1]> row_values(tt) ### Extraction of values -> It will be a named list! ### $`A: Drug X` [1] 30 $`B: Placebo` [1] 33 $`C: Combination` [1] 36 Browse[1]> sum(unlist(row_values(tt))) ### Final value we want to give back to sort_at_path ### [1] 99 cont_n_onecol # function (j) # { # function(tt) { # ctab <- content_table(tt) # if (NROW(ctab) == 0) { # stop(\"cont_n_allcols score function used at subtable [\", # obj_name(tt), \"] that has no content table.\") # } # row_values(tree_children(ctab)[[1]])[[j]][1] # } # } # # scorefun_onecol <- function(colpath) { function(tt) { # Here we could use browser() unlist(cell_values(tt, colpath = colpath), use.names = FALSE)[1] # Modified to lose the list names } } sort_at_path(tbl, c(\"RACE\", \"*\", \"STRATA1\", \"*\", \"AGE\"), scorefun_onecol(colpath = c(\"ARM\", \"A: Drug X\"))) # A: Drug X B: Placebo C: Combination # ———————————————————————————————————————————————————————————————————— # ASIAN 79 (65.3%) 68 (64.2%) 84 (65.1%) # A 27 (22.3%) 20 (18.9%) 31 (24.0%) # mean 32.2 33.9 36.8 # median 30.0 33.0 36.0 # B 24 (19.8%) 29 (27.4%) 22 (17.1%) # mean 34.1 31.6 34.7 # median 32.5 32.0 34.0 # C 28 (23.1%) 19 (17.9%) 31 (24.0%) # median 36.5 34.0 33.0 # mean 36.2 33.0 32.4 # BLACK OR AFRICAN AMERICAN 28 (23.1%) 24 (22.6%) 27 (20.9%) # A 6 (5.0%) 7 (6.6%) 8 (6.2%) # median 32.0 29.0 32.5 # mean 31.5 28.6 33.6 # B 10 (8.3%) 6 (5.7%) 12 (9.3%) # mean 35.6 30.8 33.7 # median 33.0 30.0 33.5 # C 12 (9.9%) 11 (10.4%) 7 (5.4%) # mean 35.5 34.2 35.0 # median 33.0 36.0 32.0 # Simpler table tbl <- basic_table() %>% split_cols_by(\"ARM\") %>% split_cols_by(\"SEX\", split_fun = drop_and_remove_levels(c(\"U\", \"UNDIFFERENTIATED\")) ) %>% analyze(\"AGE\", afun = more_analysis_fnc) %>% build_table(DM) %>% prune_table() %>% print() # A: Drug X B: Placebo C: Combination # F M F M F M # ————————————————————————————————————————————————————————— # median 32.0 35.0 33.0 31.0 35.0 32.0 # mean 33.7 36.5 33.8 32.1 34.9 34.3 sort_at_path(tbl, c(\"AGE\"), scorefun_onecol(colpath = c(\"ARM\", \"B: Placebo\", \"SEX\", \"F\"))) # A: Drug X B: Placebo C: Combination # F M F M F M # ————————————————————————————————————————————————————————— # mean 33.7 36.5 33.8 32.1 34.9 34.3 # median 32.0 35.0 33.0 31.0 35.0 32.0"},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"writing-custom-pruning-criteria-and-scoring-functions","dir":"Articles","previous_headings":"","what":"Writing Custom Pruning Criteria and Scoring Functions","title":"Pruning and Sorting Tables","text":"Pruning criteria scoring functions map TableTree TableRow objects Boolean value (pruning criteria) sortable scalar value (scoring functions). currently need interact structure objects usual. Indeed, showed already sorting can complicated concept tree-like structure pathing well understood. important though mind following functions can used pruning sorting function retrieve relevant information table.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"useful-functions-and-accessors","dir":"Articles","previous_headings":"Writing Custom Pruning Criteria and Scoring Functions","what":"Useful Functions and Accessors","title":"Pruning and Sorting Tables","text":"accepts rowpath colpath restrict cell values returned obj_name() - Retrieves name object. Note can differ label displayed () printing. match element path. obj_label() - Retrieves display label object. Note can differ name appears path. content_table() - Retrieves TableTree object’s content table (contains summary rows). tree_children() - Retrieves TableTree object’s direct children (either subtables, rows possibly mix thereof, though happen practice)","code":""},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"sort-by-a-character-score","dir":"Articles","previous_headings":"Writing Custom Pruning Criteria and Scoring Functions > Example Custom Scoring Functions","what":"Sort by a character “score”","title":"Pruning and Sorting Tables","text":"case, convenience/simplicity, use name table element logic returns single string used . sort ethnicity alphabetical order (practice undoing previous sorting ethnicity ). NOTE: Generally appropriately done using reorder_split_levels() function within layout rather sort post-processing step, character scorers may may map easily layouting directives.","code":"silly_name_scorer <- function(tt) { nm <- obj_name(tt) print(nm) nm } sort_at_path(ethsort, \"RACE\", silly_name_scorer) # Now, it is sorted alphabetically! # [1] \"WHITE\" # [1] \"BLACK OR AFRICAN AMERICAN\" # [1] \"ASIAN\" # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # A 2 (2.9%) 1 (2.0%) 3 (5.4%) 3 (6.0%) 1 (1.6%) 5 (7.4%) # Mean 34.00 45.00 29.33 33.33 35.00 32.80 # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00 # C 2 (2.9%) 2 (3.9%) 3 (5.4%) 0 (0.0%) 4 (6.6%) 4 (5.9%) # Mean 35.50 44.00 44.67 NA 38.50 35.00"},{"path":"https://insightsengineering.github.io/rtables/articles/sorting_pruning.html","id":"sort-by-the-percent-difference-in-counts-between-genders-in-arm-c","dir":"Articles","previous_headings":"Writing Custom Pruning Criteria and Scoring Functions > Example Custom Scoring Functions","what":"Sort by the Percent Difference in Counts Between Genders in Arm C","title":"Pruning and Sorting Tables","text":"need F M percents, Arm C (.e. columns 5 6), differenced. sort strata within ethnicity percent difference counts males females arm C. Note: statistically meaningful , fact terrible idea reorders strata seemingly () random within race, illustrates various things need inside custom sorting functions.","code":"silly_gender_diffcount <- function(tt) { ## (1st) content row has same name as object (STRATA1 level) rpath <- c(obj_name(tt), \"@content\", obj_name(tt)) ## the [1] below is cause these are count (pct%) cells ## and we only want the count part! mcount <- unlist(cell_values( tt, rowpath = rpath, colpath = c(\"ARM\", \"C: Combination\", \"SEX\", \"M\") ))[1] fcount <- unlist(cell_values( tt, rowpath = rpath, colpath = c(\"ARM\", \"C: Combination\", \"SEX\", \"F\") ))[1] (mcount - fcount) / fcount } sort_at_path(pruned, c(\"RACE\", \"*\", \"STRATA1\"), silly_gender_diffcount) # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 44 (62.9%) 35 (68.6%) 37 (66.1%) 31 (62.0%) 40 (65.6%) 44 (64.7%) # B 16 (22.9%) 8 (15.7%) 13 (23.2%) 16 (32.0%) 10 (16.4%) 12 (17.6%) # Mean 33.75 34.88 32.46 30.94 33.30 35.92 # A 15 (21.4%) 12 (23.5%) 14 (25.0%) 6 (12.0%) 15 (24.6%) 16 (23.5%) # Mean 30.40 34.42 35.43 30.33 37.40 36.25 # C 13 (18.6%) 15 (29.4%) 10 (17.9%) 9 (18.0%) 15 (24.6%) 16 (23.5%) # Mean 36.92 35.60 34.00 31.89 33.47 31.38 # BLACK OR AFRICAN AMERICAN 18 (25.7%) 10 (19.6%) 12 (21.4%) 12 (24.0%) 13 (21.3%) 14 (20.6%) # C 6 (8.6%) 6 (11.8%) 4 (7.1%) 7 (14.0%) 3 (4.9%) 4 (5.9%) # Mean 31.33 39.67 34.50 34.00 33.00 36.50 # A 5 (7.1%) 1 (2.0%) 5 (8.9%) 2 (4.0%) 4 (6.6%) 4 (5.9%) # Mean 31.20 33.00 28.00 30.00 30.75 36.50 # B 7 (10.0%) 3 (5.9%) 3 (5.4%) 3 (6.0%) 6 (9.8%) 6 (8.8%) # Mean 36.14 34.33 29.67 32.00 36.33 31.00 # WHITE 8 (11.4%) 6 (11.8%) 7 (12.5%) 7 (14.0%) 8 (13.1%) 10 (14.7%) # A 2 (2.9%) 1 (2.0%) 3 (5.4%) 3 (6.0%) 1 (1.6%) 5 (7.4%) # Mean 34.00 45.00 29.33 33.33 35.00 32.80 # C 2 (2.9%) 2 (3.9%) 3 (5.4%) 0 (0.0%) 4 (6.6%) 4 (5.9%) # Mean 35.50 44.00 44.67 NA 38.50 35.00 # B 4 (5.7%) 3 (5.9%) 1 (1.8%) 4 (8.0%) 3 (4.9%) 1 (1.5%) # Mean 37.00 43.67 48.00 36.75 34.33 36.00"},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"provided-functions","dir":"Articles","previous_headings":"Controlling Facet Levels","what":"Provided Functions","title":"Controlling Splitting Behavior","text":"default, split_*_by(varname, ...) generates facet level variable varname takes data - including unobserved ones factor case. behavior can customized various ways. straightforward way customize facets generated split one split functions split function families provided rtables. predefined split functions function factories implement commonly desired customization patterns splitting behavior (.e., faceting behavior). include: remove_split_levels - remove specified levels data facet generation. keep_split_levels - keep specified levels data facet generation (removing others). drop_split_levels - drop levels unobserved within data split, .e., associated parent facet. reorder_split_levels - reorder levels (thus generated facets) specified order. trim_levels_in_group - drop unobserved levels another variable independently within data associated facet generated current split. add_overall_level, add_combo_levels - add additional “virtual” levels combine two levels variable split. See following section. trim_levels_to_map - trim levels multiple variables pre-specified set value combinations. See following section. first four fairly self-describing brevity, refer readers ?split_funcs details including working examples.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"controlling-combinations-of-levels-across-multiple-variables","dir":"Articles","previous_headings":"Controlling Facet Levels","what":"Controlling Combinations of Levels Across Multiple Variables","title":"Controlling Splitting Behavior","text":"Often nested splitting involving multiple variables, values variables question logically nested; meaning certain values inner variable coherent combination specific value values outer variable. example, suppose variable vehicle_class, can take values \"automobile\", \"boat\", variable vehicle_type, can take values \"car\", \"truck\", \"suv\",\"sailboat\", \"cruiseliner\". combination (\"automobile\", \"cruiseliner\") make sense never occur (correctly cleaned) data set; combination (\"boat\", \"truck\"). showcase strategies deal next sections using following artificial data:","code":"set.seed(0) levs_type <- c(\"car\", \"truck\", \"suv\", \"sailboat\", \"cruiseliner\") vclass <- sample(c(\"auto\", \"boat\"), 1000, replace = TRUE) auto_inds <- which(vclass == \"auto\") vtype <- rep(NA_character_, 1000) vtype[auto_inds] <- sample( c(\"car\", \"truck\"), ## suv missing on purpose length(auto_inds), replace = TRUE ) vtype[-auto_inds] <- sample( c(\"sailboat\", \"cruiseliner\"), 1000 - length(auto_inds), replace = TRUE ) vehic_data <- data.frame( vehicle_class = factor(vclass), vehicle_type = factor(vtype, levels = levs_type), color = sample( c(\"white\", \"black\", \"red\"), 1000, prob = c(1, 2, 1), replace = TRUE ), cost = ifelse( vclass == \"boat\", rnorm(1000, 100000, sd = 5000), rnorm(1000, 40000, sd = 5000) ) ) head(vehic_data) #> vehicle_class vehicle_type color cost #> 1 boat sailboat black 100393.81 #> 2 auto car white 38150.17 #> 3 boat sailboat white 98696.13 #> 4 auto truck white 37677.16 #> 5 auto truck black 38489.27 #> 6 boat cruiseliner black 108709.72"},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"trim_levels_in_group","dir":"Articles","previous_headings":"Controlling Facet Levels > Controlling Combinations of Levels Across Multiple Variables","what":"trim_levels_in_group","title":"Controlling Splitting Behavior","text":"trim_levels_in_group split function factory creates split functions deal issue empirically; combination observed data tabulated appear nested facets within table, , . use default level-based faceting, get several logically incoherent cells within table: obviously table want, majority space taken meaningless combinations. use trim_levels_in_group trim levels vehicle_type separately within level vehicle_class, get table meaningful combinations: Note, however, contain meaningful combinations, actually observed data; happens include perfectly valid \"auto\", \"suv\" combination. restrict level combinations valid regardless whether combination observed, must use trim_levels_to_map() instead.","code":"library(rtables) lyt <- basic_table() %>% split_cols_by(\"color\") %>% split_rows_by(\"vehicle_class\") %>% split_rows_by(\"vehicle_type\") %>% analyze(\"cost\") build_table(lyt, vehic_data) #> black white red #> ———————————————————————————————————————————————— #> auto #> car #> Mean 40431.92 40518.92 38713.14 #> truck #> Mean 40061.70 40635.74 40024.41 #> suv #> Mean NA NA NA #> sailboat #> Mean NA NA NA #> cruiseliner #> Mean NA NA NA #> boat #> car #> Mean NA NA NA #> truck #> Mean NA NA NA #> suv #> Mean NA NA NA #> sailboat #> Mean 99349.69 99996.54 101865.73 #> cruiseliner #> Mean 100212.00 99340.25 100363.52 lyt2 <- basic_table() %>% split_cols_by(\"color\") %>% split_rows_by(\"vehicle_class\", split_fun = trim_levels_in_group(\"vehicle_type\")) %>% split_rows_by(\"vehicle_type\") %>% analyze(\"cost\") build_table(lyt2, vehic_data) #> black white red #> ———————————————————————————————————————————————— #> auto #> car #> Mean 40431.92 40518.92 38713.14 #> truck #> Mean 40061.70 40635.74 40024.41 #> boat #> sailboat #> Mean 99349.69 99996.54 101865.73 #> cruiseliner #> Mean 100212.00 99340.25 100363.52"},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"trim_levels_to_map","dir":"Articles","previous_headings":"Controlling Facet Levels > Controlling Combinations of Levels Across Multiple Variables","what":"trim_levels_to_map","title":"Controlling Splitting Behavior","text":"trim_levels_to_map similar trim_levels_in_group purpose avoid combinatorial explosion nesting splitting logically nested variables. Unlike sibling function, however, trim_levels_to_map define exact set allowed combinations priori, exact set combinations produced resulting table, regardless whether observed . Now see \"auto\", \"suv\" combination present, even though populated NAs (data category), logically invalid combinations still absent.","code":"library(tibble) map <- tribble( ~vehicle_class, ~vehicle_type, \"auto\", \"truck\", \"auto\", \"suv\", \"auto\", \"car\", \"boat\", \"sailboat\", \"boat\", \"cruiseliner\" ) lyt3 <- basic_table() %>% split_cols_by(\"color\") %>% split_rows_by(\"vehicle_class\", split_fun = trim_levels_to_map(map)) %>% split_rows_by(\"vehicle_type\") %>% analyze(\"cost\") build_table(lyt3, vehic_data) #> black white red #> ———————————————————————————————————————————————— #> auto #> car #> Mean 40431.92 40518.92 38713.14 #> truck #> Mean 40061.70 40635.74 40024.41 #> suv #> Mean NA NA NA #> boat #> sailboat #> Mean 99349.69 99996.54 101865.73 #> cruiseliner #> Mean 100212.00 99340.25 100363.52"},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"combining-levels","dir":"Articles","previous_headings":"Controlling Facet Levels","what":"Combining Levels","title":"Controlling Splitting Behavior","text":"Another common manipulation faceting table context introduction combination levels explicitly modeled data. often, involves addition “overall” category, principle practice can involve arbitrary combination levels. rtables explicitly supports via add_overall_level (case) add_combo_levels split function factories.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"add_overall_level","dir":"Articles","previous_headings":"Controlling Facet Levels > Combining Levels","what":"add_overall_level","title":"Controlling Splitting Behavior","text":"add_overall_level accepts valname name new level, well label, first (whether come first, TRUE, last, FALSE, ordering). Building arbitrary vehicles table, can use create “colors” category: column counts turned , can see “Colors” column encompasses full 1000 (completely fake) vehicles data set. add arbitrary combinations, use add_combo_levels.","code":"lyt4 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"color\", split_fun = add_overall_level(\"allcolors\", label = \"All Colors\")) %>% split_rows_by(\"vehicle_class\", split_fun = trim_levels_to_map(map)) %>% split_rows_by(\"vehicle_type\") %>% analyze(\"cost\") build_table(lyt4, vehic_data) #> All Colors black white red #> (N=1000) (N=521) (N=251) (N=228) #> ————————————————————————————————————————————————————————————— #> auto #> car #> Mean 40095.49 40431.92 40518.92 38713.14 #> truck #> Mean 40194.68 40061.70 40635.74 40024.41 #> suv #> Mean NA NA NA NA #> boat #> sailboat #> Mean 100133.22 99349.69 99996.54 101865.73 #> cruiseliner #> Mean 100036.76 100212.00 99340.25 100363.52"},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"add_combo_levels","dir":"Articles","previous_headings":"Controlling Facet Levels > Combining Levels","what":"add_combo_levels","title":"Controlling Splitting Behavior","text":"add_combo_levels allows us add one arbitrary combination levels faceting structure table. defining combination data.frame describes levels want add. combination data.frame following columns one row combination add: valname - string indicating name value, appear paths. label - string indicating label displayed rendering. levelcombo - character vector individual levels combined combination level. exargs - list (usually list()) extra arguments passed analysis content functions tabulated within column row. Suppose wanted combinations levels non-white colors, white black colors. like :","code":"combodf <- tribble( ~valname, ~label, ~levelcombo, ~exargs, \"non-white\", \"Non-White\", c(\"black\", \"red\"), list(), \"blackwhite\", \"Black or White\", c(\"black\", \"white\"), list() ) lyt5 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"color\", split_fun = add_combo_levels(combodf)) %>% split_rows_by(\"vehicle_class\", split_fun = trim_levels_to_map(map)) %>% split_rows_by(\"vehicle_type\") %>% analyze(\"cost\") build_table(lyt5, vehic_data) #> black white red Non-White Black or White #> (N=521) (N=251) (N=228) (N=749) (N=772) #> ————————————————————————————————————————————————————————————————————————————— #> auto #> car #> Mean 40431.92 40518.92 38713.14 39944.93 40460.77 #> truck #> Mean 40061.70 40635.74 40024.41 40050.66 40243.57 #> suv #> Mean NA NA NA NA NA #> boat #> sailboat #> Mean 99349.69 99996.54 101865.73 100179.72 99567.50 #> cruiseliner #> Mean 100212.00 99340.25 100363.52 100258.56 99937.47"},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"fully-customizing-split-facet-behavior","dir":"Articles","previous_headings":"","what":"Fully Customizing Split (Facet) Behavior","title":"Controlling Splitting Behavior","text":"Beyond ability select common splitting customizations split functions split function factories rtables provides, can also fully customize every aspect splitting behavior creating split functions. possible hand, primary way via make_split_fun() function, accepts functions implementing different component behaviors combines split function can used layout. Splitting, faceting done rtables, can thought combination 3 steps: preprocessing - transformation incoming data faceted e.g., dropping unused factor levels, etc. splitting - mapping incoming data set 1 subsets representing individual facets. postprocessing - operations facets - e.g., combining , removing , etc. make_split_fun() function allows us specify custom behaviors steps independently defining custom splitting behavior via pre, core_split, post arguments, dictate steps, respectively. pre argument accepts zero pre-processing functions, must accept: df, spl, vals, labels, can optionally accept .spl_context. manipulate df (incoming data split) return modified data.frame. modified data.frame must contain columns present incoming data.frame, can add columns necessary. Although, note new columns used layout split analysis variables, present validity checking done. pre-processing component useful things manipulating factor levels, e.g., trim unobserved ones reorder levels based observed counts, etc. detailed discussion custom split functions , example custom split function implemented via make_split_fun(), see ?custom_split_funs.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"an-example-custom-split-function","dir":"Articles","previous_headings":"Fully Customizing Split (Facet) Behavior","what":"An Example Custom Split Function","title":"Controlling Splitting Behavior","text":"implement arbitrary, custom split function specify pre- post-processing instructions. unusual users need override core splitting logic - , fact, supported row space currently - leave example provide another narrow example usage .","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"an-illustrative-example-of-a-custom-split-function","dir":"Articles","previous_headings":"Fully Customizing Split (Facet) Behavior > An Example Custom Split Function","what":"An Illustrative Example of A Custom Split Function","title":"Controlling Splitting Behavior","text":"First, define two aspects ‘pre-processing step’ behavior: function reverses order levels variable (retaining level associated observation), function factory creates function removes level data associated . Finally implement post-processing function. reorder facets based amount data represents. Finally, construct custom split function use create table:","code":"## reverse order of levels rev_lev <- function(df, spl, vals, labels, ...) { ## in the split_rows_by() and split_cols_by() cases, ## spl_variable() gives us the variable var <- spl_variable(spl) vec <- df[[var]] levs <- if (is.character(vec)) unique(vec) else levels(vec) df[[var]] <- factor(vec, levels = rev(levs)) df } rem_lev_facet <- function(torem) { function(df, spl, vals, labels, ...) { var <- spl_variable(spl) vec <- df[[var]] bad <- vec == torem df <- df[!bad, ] levs <- if (is.character(vec)) unique(vec) else levels(vec) df[[var]] <- factor(as.character(vec[!bad]), levels = setdiff(levs, torem)) df } } sort_them_facets <- function(splret, spl, fulldf, ...) { ord <- order(sapply(splret$datasplit, nrow)) make_split_result( splret$values[ord], splret$datasplit[ord], splret$labels[ord] ) } silly_splfun1 <- make_split_fun( pre = list( rev_lev, rem_lev_facet(\"white\") ), post = list(sort_them_facets) ) lyt6 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"color\", split_fun = silly_splfun1) %>% split_rows_by(\"vehicle_class\", split_fun = trim_levels_to_map(map)) %>% split_rows_by(\"vehicle_type\") %>% analyze(\"cost\") build_table(lyt6, vehic_data) #> red black #> (N=228) (N=521) #> ————————————————————————————————————— #> auto #> car #> Mean 38713.14 40431.92 #> truck #> Mean 40024.41 40061.70 #> suv #> Mean NA NA #> boat #> sailboat #> Mean 101865.73 99349.69 #> cruiseliner #> Mean 100363.52 100212.00"},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"overriding-the-core-split-function","dir":"Articles","previous_headings":"Fully Customizing Split (Facet) Behavior > An Example Custom Split Function","what":"Overriding the Core Split Function","title":"Controlling Splitting Behavior","text":"Currently, overriding core split behavior supported functions used row splits. Next, write custom core-splitting function divides observations 4 groups: first 100, observations 101-500, observations 501-900, last hundred. claim test structural bias first last observations, really simply illustrate overriding core splitting machinery meaningful statistical purpose. can use construct splitting function. can combined pre- post-processing functions, stages performed independently, case, won’t, core splitting behavior pre- post-processing make much sense.","code":"silly_core_split <- function(spl, df, vals, labels, .spl_context) { make_split_result( c(\"first\", \"lowmid\", \"highmid\", \"last\"), datasplit = list( df[1:100, ], df[101:500, ], df[501:900, ], df[901:1000, ] ), labels = c( \"first 100\", \"obs 101-500\", \"obs 501-900\", \"last 100\" ) ) } even_sillier_splfun <- make_split_fun(core_split = silly_core_split) lyt7 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"color\") %>% split_rows_by(\"vehicle_class\", split_fun = even_sillier_splfun) %>% split_rows_by(\"vehicle_type\") %>% analyze(\"cost\") build_table(lyt7, vehic_data) #> black white red #> (N=521) (N=251) (N=228) #> ————————————————————————————————————————————————— #> first 100 #> car #> Mean 40496.05 37785.41 37623.17 #> truck #> Mean 41094.17 40437.29 37866.81 #> suv #> Mean NA NA NA #> sailboat #> Mean 100560.80 102017.05 101185.96 #> cruiseliner #> Mean 100838.12 96952.27 100610.71 #> obs 101-500 #> car #> Mean 39350.88 41185.98 37978.72 #> truck #> Mean 40166.87 41385.32 39885.72 #> suv #> Mean NA NA NA #> sailboat #> Mean 98845.47 99563.02 101462.79 #> cruiseliner #> Mean 101558.62 99039.91 97335.05 #> obs 501-900 #> car #> Mean 40721.82 40379.48 38681.26 #> truck #> Mean 39951.92 39846.89 39840.39 #> suv #> Mean NA NA NA #> sailboat #> Mean 99533.20 100347.18 102732.12 #> cruiseliner #> Mean 99140.43 100074.43 101994.99 #> last 100 #> car #> Mean 45204.44 40626.95 41214.33 #> truck #> Mean 38920.70 40620.47 42899.14 #> suv #> Mean NA NA NA #> sailboat #> Mean 99380.21 97644.77 101691.92 #> cruiseliner #> Mean 100017.53 99581.94 100751.30"},{"path":"https://insightsengineering.github.io/rtables/articles/split_functions.html","id":"design-of-pre--and-post-processing-functions-for-use-in-make_split_fun","dir":"Articles","previous_headings":"Fully Customizing Split (Facet) Behavior > An Example Custom Split Function","what":"Design of Pre- and Post-Processing Functions For Use in make_split_fun","title":"Controlling Splitting Behavior","text":"Pre-processing post-processing functions custom-splitting context best thought (implemented ) independent, atomic building blocks desired overall behavior. allows reused flexible mix--match way. rtables provides several behavior components implemented either functions function factories: drop_facet_levels - drop unobserved levels variable split trim_levels_in_facets - provides trim_levels_in_group behavior add_overall_facet - add combination facet full data add_combo_facet - add single combination facet (can used single make_split_fun call)","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/subsetting_tables.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Subsetting and Manipulating Table Contents","text":"TableTree objects based tree data structure name indicates. package written user need walk trees many basic table manipulations. Walking trees still necessary certain manipulation subject different vignette. vignette show methods subset tables extract cell values. use following table illustrative purposes:","code":"library(rtables) library(dplyr) lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels) %>% analyze(c(\"AGE\", \"STRATA1\")) tbl <- build_table(lyt, ex_adsl %>% filter(SEX %in% c(\"M\", \"F\"))) tbl # A: Drug X B: Placebo C: Combination # ——————————————————————————————————————————————————— # F # AGE # Mean 32.76 34.12 35.20 # STRATA1 # A 21 24 18 # B 25 27 21 # C 33 26 27 # M # AGE # Mean 35.57 37.44 35.38 # STRATA1 # A 16 19 20 # B 21 17 21 # C 14 19 19"},{"path":"https://insightsengineering.github.io/rtables/articles/subsetting_tables.html","id":"traditional-subsetting-and-modification-with","dir":"Articles","previous_headings":"","what":"Traditional Subsetting and modification with [","title":"Subsetting and Manipulating Table Contents","text":"[ [<- accessor functions operate largely data.frame cousins: particular means label rows treated rows empty cell values, rather rows without cells multiple values can specified row column position negative numeric positions supported, though like [.data.frame mixed positive ones [ always returns class object subset unless drop = TRUE [ , drop = TRUE returns raw (possibly multi-element) value associated cell. Known Differences [.data.frame - absolute position currently used reorder columns rows. Note general result ordering unlikely structurally valid. change order values, please read sorting pruning vignette relevant function (sort_at_path()). - character indices treated paths, vectors names [ [<- [ accessor function always returns TableTree object drop=TRUE set. first argument row indices second argument column indices. Alternatively logical subsetting can used. indices based visible rows tree structure. : table empty cell first row label row. need access cell actual cell data: retrieve value, use drop = TRUE: One can access multiple rows columns: Note repeat label rows descending children, e.g. show first row derived AGE. order repeat content/label information, one use pagination feature. Please read related vignette. Character indices interpreted paths (see ), elements matched names(tbl):","code":"tbl[1, 1] # A: Drug X # ————————————— # F tbl[3, 1] # A: Drug X # ———————————————— # Mean 32.76 tbl[3, 1, drop = TRUE] # [1] 32.75949 tbl[1:3, 1:2] # A: Drug X B: Placebo # ————————————————————————————————— # F # AGE # Mean 32.76 34.12 tbl[2:4, ] # A: Drug X B: Placebo C: Combination # ————————————————————————————————————————————————— # AGE # Mean 32.76 34.12 35.20 # STRATA1 tbl[, c(\"ARM\", \"A: Drug X\")] # Note: method with signature 'VTableTree#missing#ANY' chosen for function '[', # target signature 'TableTree#missing#character'. # \"VTableTree#ANY#character\" would also be valid # A: Drug X # ————————————————————— # F # AGE # Mean 32.76 # STRATA1 # A 21 # B 25 # C 33 # M # AGE # Mean 35.57 # STRATA1 # A 16 # B 21 # C 14"},{"path":"https://insightsengineering.github.io/rtables/articles/subsetting_tables.html","id":"dealing-with-titles-foot-notes-and-top-left-information","dir":"Articles","previous_headings":"Traditional Subsetting and modification with [","what":"Dealing with titles, foot notes, and top left information","title":"Subsetting and Manipulating Table Contents","text":"standard additional information kept subsetting. , show complete table still possible keep (possibly) relevant information. Normal subsetting loses information showed . rows kept, top left information also kept. can also imposed adding keep_topleft = TRUE subsetting follows: referenced entry present subsetting, also referential footnote appear. Please consider reading relevant vignette referential footnotes. case subsetting, referential footnotes default indexed , produced table new one. Similar used keep top left information, can specify keep information original table. standard foot notes always present titles kept.","code":"top_left(tbl) <- \"SEX\" main_title(tbl) <- \"Table 1\" subtitles(tbl) <- c(\"Authors:\", \" - Abcd Zabcd\", \" - Cde Zbcd\") main_footer(tbl) <- \"Please regard this table as an example of smart subsetting\" prov_footer(tbl) <- \"Do remember where you read this though\" fnotes_at_path(tbl, rowpath = c(\"M\", \"AGE\", \"Mean\"), colpath = c(\"ARM\", \"A: Drug X\")) <- \"Very important mean\" tbl[3, 3] # C: Combination # ————————————————————— # Mean 35.20 tbl[, 2:3] # SEX B: Placebo C: Combination # ——————————————————————————————————————— # F # AGE # Mean 34.12 35.20 # STRATA1 # A 24 18 # B 27 21 # C 26 27 # M # AGE # Mean 37.44 35.38 # STRATA1 # A 19 20 # B 17 21 # C 19 19 tbl[1:3, 3, keep_topleft = TRUE] # SEX C: Combination # ————————————————————————— # F # AGE # Mean 35.20 tbl[10, 1] # A: Drug X # ———————————————— # Mean 35.57 {1} # ———————————————— # # {1} - Very important mean # ———————————————— col_paths_summary(tbl) # Use these to find the right path to value or label # label path # ————————————————————————————————————— # A: Drug X ARM, A: Drug X # B: Placebo ARM, B: Placebo # C: Combination ARM, C: Combination row_paths_summary(tbl) # # rowname node_class path # ————————————————————————————————————————————— # F LabelRow SEX, F # AGE LabelRow SEX, F, AGE # Mean DataRow SEX, F, AGE, Mean # STRATA1 LabelRow SEX, F, STRATA1 # A DataRow SEX, F, STRATA1, A # B DataRow SEX, F, STRATA1, B # C DataRow SEX, F, STRATA1, C # M LabelRow SEX, M # AGE LabelRow SEX, M, AGE # Mean DataRow SEX, M, AGE, Mean # STRATA1 LabelRow SEX, M, STRATA1 # A DataRow SEX, M, STRATA1, A # B DataRow SEX, M, STRATA1, B # C DataRow SEX, M, STRATA1, C # To select column value, use `NULL` for `rowpath` fnotes_at_path(tbl, rowpath = NULL, colpath = c(\"ARM\", \"A: Drug X\")) <- \"Interesting\" tbl[3, 1] # A: Drug X {1} # ———————————————————— # Mean 32.76 # ———————————————————— # # {1} - Interesting # ———————————————————— # reindexing of {2} as {1} fnotes_at_path(tbl, rowpath = c(\"M\", \"AGE\", \"Mean\"), colpath = NULL) <- \"THIS mean\" tbl # {1}, {2}, and {3} are present # Table 1 # Authors: # - Abcd Zabcd # - Cde Zbcd # # —————————————————————————————————————————————————————————— # SEX A: Drug X {1} B: Placebo C: Combination # —————————————————————————————————————————————————————————— # F # AGE # Mean 32.76 34.12 35.20 # STRATA1 # A 21 24 18 # B 25 27 21 # C 33 26 27 # M # AGE # Mean {2} 35.57 {3} 37.44 35.38 # STRATA1 # A 16 19 20 # B 21 17 21 # C 14 19 19 # —————————————————————————————————————————————————————————— # # {1} - Interesting # {2} - THIS mean # {3} - Very important mean # —————————————————————————————————————————————————————————— # # Please regard this table as an example of smart subsetting # # Do remember where you read this though tbl[10, 2] # only {1} which was previously {2} # B: Placebo # ————————————————————— # Mean {1} 37.44 # ————————————————————— # # {1} - THIS mean # ————————————————————— tbl[1:3, 2:3, keep_titles = TRUE] # Table 1 # Authors: # - Abcd Zabcd # - Cde Zbcd # # —————————————————————————————————————— # B: Placebo C: Combination # —————————————————————————————————————— # F # AGE # Mean 34.12 35.20 # —————————————————————————————————————— # # Please regard this table as an example of smart subsetting # # Do remember where you read this though tbl[1:3, 2:3, keep_titles = FALSE, keep_footers = TRUE] # B: Placebo C: Combination # —————————————————————————————————————— # F # AGE # Mean 34.12 35.20 # —————————————————————————————————————— # # Please regard this table as an example of smart subsetting # # Do remember where you read this though # Referential footnotes are not influenced by `keep_footers = FALSE` tbl[1:3, keep_titles = TRUE, keep_footers = FALSE] # Table 1 # Authors: # - Abcd Zabcd # - Cde Zbcd # # —————————————————————————————————————————————————————— # A: Drug X {1} B: Placebo C: Combination # —————————————————————————————————————————————————————— # F # AGE # Mean 32.76 34.12 35.20 # —————————————————————————————————————————————————————— # # {1} - Interesting # ——————————————————————————————————————————————————————"},{"path":"https://insightsengineering.github.io/rtables/articles/subsetting_tables.html","id":"path-based-cell-value-accessing","dir":"Articles","previous_headings":"","what":"Path Based Cell Value Accessing:","title":"Subsetting and Manipulating Table Contents","text":"Tables can subset modified structurally aware manner via pathing. Paths define semantically meaningful positions within constructed table correspond logic layout used create . path ordered set split names, names subgroups generated split, @content directive, steps position’s content (row group summary) table. can see row column paths existing table via row_paths(), col_paths(), row_paths_summary(), col_paths_summary(), functions, portion general make_row_df() function output. column paths follows: row paths follows: get semantically meaningful subset table, , can use [ (tt_at_path() underlies ) can also retrieve individual cell-values via value_at() convenience function, takes pair row column paths resolve together individual cell, e.g. average age Asian female patients arm : can also request information non-cell specific paths cell_values() function: Note return value cell_values() always list even specify path cell:","code":"lyt2 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_cols_by(\"SEX\", split_fun = drop_split_levels) %>% split_rows_by(\"RACE\", split_fun = drop_split_levels) %>% summarize_row_groups() %>% analyze(c(\"AGE\", \"STRATA1\")) tbl2 <- build_table(lyt2, ex_adsl %>% filter(SEX %in% c(\"M\", \"F\") & RACE %in% (levels(RACE)[1:3]))) tbl2 # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN 41 (53.9%) 25 (54.3%) 36 (52.2%) 30 (60.0%) 39 (60.9%) 32 (57.1%) # AGE # Mean 31.22 34.60 35.06 38.63 36.44 37.66 # STRATA1 # A 11 10 14 10 11 7 # B 11 9 15 7 11 14 # C 19 6 7 13 17 11 # BLACK OR AFRICAN AMERICAN 18 (23.7%) 12 (26.1%) 16 (23.2%) 12 (24.0%) 14 (21.9%) 14 (25.0%) # AGE # Mean 34.06 34.58 33.88 36.33 33.21 34.21 # STRATA1 # A 5 2 5 6 3 7 # B 6 5 3 4 4 4 # C 7 5 8 2 7 3 # WHITE 17 (22.4%) 9 (19.6%) 17 (24.6%) 8 (16.0%) 11 (17.2%) 10 (17.9%) # AGE # Mean 34.12 40.00 32.41 34.62 33.00 30.80 # STRATA1 # A 5 3 3 3 3 5 # B 5 4 8 4 5 2 # C 7 2 6 1 3 3 col_paths_summary(tbl2) # label path # ————————————————————————————————————————————— # A: Drug X ARM, A: Drug X # F ARM, A: Drug X, SEX, F # M ARM, A: Drug X, SEX, M # B: Placebo ARM, B: Placebo # F ARM, B: Placebo, SEX, F # M ARM, B: Placebo, SEX, M # C: Combination ARM, C: Combination # F ARM, C: Combination, SEX, F # M ARM, C: Combination, SEX, M row_paths_summary(tbl2) # rowname node_class path # ——————————————————————————————————————————————————————————————————————————————————————————————————————————————— # ASIAN ContentRow RACE, ASIAN, @content, ASIAN # AGE LabelRow RACE, ASIAN, AGE # Mean DataRow RACE, ASIAN, AGE, Mean # STRATA1 LabelRow RACE, ASIAN, STRATA1 # A DataRow RACE, ASIAN, STRATA1, A # B DataRow RACE, ASIAN, STRATA1, B # C DataRow RACE, ASIAN, STRATA1, C # BLACK OR AFRICAN AMERICAN ContentRow RACE, BLACK OR AFRICAN AMERICAN, @content, BLACK OR AFRICAN AMERICAN # AGE LabelRow RACE, BLACK OR AFRICAN AMERICAN, AGE # Mean DataRow RACE, BLACK OR AFRICAN AMERICAN, AGE, Mean # STRATA1 LabelRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1 # A DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, A # B DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, B # C DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, C # WHITE ContentRow RACE, WHITE, @content, WHITE # AGE LabelRow RACE, WHITE, AGE # Mean DataRow RACE, WHITE, AGE, Mean # STRATA1 LabelRow RACE, WHITE, STRATA1 # A DataRow RACE, WHITE, STRATA1, A # B DataRow RACE, WHITE, STRATA1, B # C DataRow RACE, WHITE, STRATA1, C tbl2[c(\"RACE\", \"ASIAN\"), c(\"ARM\", \"C: Combination\")] # C: Combination # F M # ——————————————————————————————————— # ASIAN 39 (60.9%) 32 (57.1%) # AGE # Mean 36.44 37.66 # STRATA1 # A 11 7 # B 11 14 # C 17 11 value_at(tbl2, c(\"RACE\", \"ASIAN\", \"AGE\", \"Mean\"), c(\"ARM\", \"A: Drug X\", \"SEX\", \"F\")) # [1] 31.21951 cell_values(tbl2, c(\"RACE\", \"ASIAN\", \"AGE\", \"Mean\"), c(\"ARM\", \"A: Drug X\")) # $`A: Drug X.F` # [1] 31.21951 # # $`A: Drug X.M` # [1] 34.6 cell_values(tbl2, c(\"RACE\", \"ASIAN\", \"AGE\", \"Mean\"), c(\"ARM\", \"A: Drug X\", \"SEX\", \"F\")) # $`A: Drug X.F` # [1] 31.21951"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_concepts.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Tabulation Concepts","text":"vignette introduce theory behind using layouts table creation. Much theory also holds true using table packages. vignette use following packages: data use following, created random number generators:","code":"library(dplyr) library(tibble) library(rtables) add_subgroup <- function(x) paste0(tolower(x), sample(1:3, length(x), TRUE)) set.seed(1) df <- tibble( x = rnorm(100), c1 = factor(sample(c(\"A\", \"B\", \"C\"), 100, replace = TRUE), levels = c(\"A\", \"B\", \"C\")), r1 = factor(sample(c(\"U\", \"V\", \"W\"), 100, replace = TRUE), levels = c(\"U\", \"V\", \"W\")) ) %>% mutate( c2 = add_subgroup(c1), r2 = add_subgroup(r1), y = as.numeric(2 * as.numeric(c1) - 3 * as.numeric(r1)) ) %>% select(c1, c2, r1, r2, x, y) df # # A tibble: 100 × 6 # c1 c2 r1 r2 x y # # 1 B b2 U u3 -0.626 1 # 2 A a3 V v2 0.184 -4 # 3 B b1 V v2 -0.836 -2 # 4 B b3 V v2 1.60 -2 # 5 B b1 U u1 0.330 1 # 6 C c1 U u3 -0.820 3 # 7 A a3 U u3 0.487 -1 # 8 B b1 U u3 0.738 1 # 9 C c3 V v2 0.576 0 # 10 C c3 U u2 -0.305 3 # # ℹ 90 more rows"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_concepts.html","id":"building-a-table-row-by-row","dir":"Articles","previous_headings":"","what":"Building A Table Row By Row","title":"Tabulation Concepts","text":"Let’s look table 3 columns 3 rows. row represents different analysis (functions foo, bar, zoo return rcell() object): data passed analysis functions subset defined respective column : Let’s concrete data analyze(): wanted x variable instead data frame: : function passed afun evaluated using argument matching. afun argument x analysis variable specified vars analyze() passed function, afun argument df subset dataset passed afun: Note also possible function returns multiple rows in_rows(): recommend specify row names explicitly.","code":"A B C ------------------------------------------------ foo_label foo(df_A) foo(df_B) foo(df_C) bar_label bar(df_A) bar(df_B) bar(df_C) zoo_label zoo(df_A) zoo(df_B) zoo(df_C) df_A <- df %>% filter(c1 == \"A\") df_B <- df %>% filter(c1 == \"B\") df_C <- df %>% filter(c1 == \"C\") foo <- prod bar <- sum zoo <- mean lyt <- basic_table() %>% split_cols_by(\"c1\") %>% analyze(\"x\", function(df) foo(df$x), var_labels = \"foo label\", format = \"xx.xx\") %>% analyze(\"x\", function(df) bar(df$x), var_labels = \"bar label\", format = \"xx.xx\") %>% analyze(\"x\", function(df) zoo(df$x), var_labels = \"zoo label\", format = \"xx.xx\") tbl <- build_table(lyt, df) # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: root tbl # A B C # —————————————————————————————————— # foo label # foo label 0.00 -0.00 -0.00 # bar label # bar label 1.87 4.37 4.64 # zoo label # zoo label 0.05 0.13 0.18 A B C ------------------------------------------------ foo_label foo(x_A) foo(x_B) foo(x_C) bar_label bar(x_A) bar(x_B) bar(x_C) zoo_label zoo(x_A) zoo(x_B) zoo(x_C) x_A <- df_A$x x_B <- df_B$x x_C <- df_C$x lyt2 <- basic_table() %>% split_cols_by(\"c1\") %>% analyze(\"x\", foo, var_labels = \"foo label\", format = \"xx.xx\") %>% analyze(\"x\", bar, var_labels = \"bar label\", format = \"xx.xx\") %>% analyze(\"x\", zoo, var_labels = \"zoo label\", format = \"xx.xx\") tbl2 <- build_table(lyt2, df) # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: root tbl2 # A B C # ———————————————————————————————— # foo label # foo 0.00 -0.00 -0.00 # bar label # bar 1.87 4.37 4.64 # zoo label # zoo 0.05 0.13 0.18 lyt3 <- basic_table() %>% split_cols_by(\"c1\") %>% analyze(\"x\", function(x) { in_rows( \"row 1\" = rcell(mean(x), format = \"xx.xx\"), \"row 2\" = rcell(sd(x), format = \"xx.xxx\") ) }, var_labels = \"foo label\") %>% analyze(\"x\", function(x) { in_rows( \"more rows 1\" = rcell(median(x), format = \"xx.x\"), \"even more rows 1\" = rcell(IQR(x), format = \"xx.xx\") ) }, var_labels = \"bar label\", format = \"xx.xx\") tbl3 <- build_table(lyt3, df) # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: root tbl3 # A B C # —————————————————————————————————————————— # foo label # row 1 0.05 0.13 0.18 # row 2 0.985 0.815 0.890 # bar label # more rows 1 -0.0 0.2 0.3 # even more rows 1 1.20 1.15 1.16"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_concepts.html","id":"tabulation-with-row-structure","dir":"Articles","previous_headings":"","what":"Tabulation With Row Structure","title":"Tabulation Concepts","text":"Let’s say like create following table: df_* subsets df follows: note df_* class df, .e. tibbles. Hence foo aggregates subset data cell value. Given function foo (ignore ... now): can start calculating cell values individually: Now still missing table structure: rtables type tabulation done layouts: want see foo label use: now row labels disappeared. cfun needs define row label. let’s redefine foo:","code":"A B C -------------------------------------- U foo(df_UA) foo(df_UB) foo(df_UC) V foo(df_VA) foo(df_VB) foo(df_VC) W foo(df_WA) foo(df_WB) foo(df_WC) df_UA <- df %>% filter(r1 == \"U\", c1 == \"A\") df_VA <- df %>% filter(r1 == \"V\", c1 == \"A\") df_WA <- df %>% filter(r1 == \"W\", c1 == \"A\") df_UB <- df %>% filter(r1 == \"U\", c1 == \"B\") df_VB <- df %>% filter(r1 == \"V\", c1 == \"B\") df_WB <- df %>% filter(r1 == \"W\", c1 == \"C\") df_UC <- df %>% filter(r1 == \"U\", c1 == \"C\") df_VC <- df %>% filter(r1 == \"V\", c1 == \"C\") df_WC <- df %>% filter(r1 == \"W\", c1 == \"C\") foo <- function(df, labelstr = \"\", ...) { paste(dim(df), collapse = \" x \") } foo(df_UA) # [1] \"17 x 6\" foo(df_VA) # [1] \"9 x 6\" foo(df_WA) # [1] \"14 x 6\" foo(df_UB) # [1] \"13 x 6\" foo(df_VB) # [1] \"15 x 6\" foo(df_WB) # [1] \"11 x 6\" foo(df_UC) # [1] \"10 x 6\" foo(df_VC) # [1] \"5 x 6\" foo(df_WC) # [1] \"11 x 6\" matrix( list( foo(df_UA), foo(df_VA), foo(df_WA), foo(df_UB), foo(df_VB), foo(df_WB), foo(df_UC), foo(df_VC), foo(df_WC) ), byrow = FALSE, ncol = 3 ) # [,1] [,2] [,3] # [1,] \"17 x 6\" \"13 x 6\" \"10 x 6\" # [2,] \"9 x 6\" \"15 x 6\" \"5 x 6\" # [3,] \"14 x 6\" \"11 x 6\" \"11 x 6\" lyt4 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% analyze(\"x\", foo) tbl4 <- build_table(lyt4, df) tbl4 # A B C # ———————————————————————————————— # U # foo 17 x 6 13 x 6 10 x 6 # V # foo 9 x 6 15 x 6 5 x 6 # W # foo 14 x 6 6 x 6 11 x 6 lyt5 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% summarize_row_groups(cfun = foo, format = \"xx\") tbl5 <- build_table(lyt5, df) tbl5 # A B C # ——————————————————————————— # 17 x 6 13 x 6 10 x 6 # 9 x 6 15 x 6 5 x 6 # 14 x 6 6 x 6 11 x 6 foo <- function(df, labelstr) { rcell(paste(dim(df), collapse = \" x \"), format = \"xx\", label = labelstr) } lyt6 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% summarize_row_groups(cfun = foo) tbl6 <- build_table(lyt6, df) tbl6 # A B C # ———————————————————————————— # U 17 x 6 13 x 6 10 x 6 # V 9 x 6 15 x 6 5 x 6 # W 14 x 6 6 x 6 11 x 6"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_concepts.html","id":"calculating-the-mean","dir":"Articles","previous_headings":"Tabulation With Row Structure","what":"Calculating the Mean","title":"Tabulation Concepts","text":"Now let’s calculate mean df$y pattern : Note foo variable information hard-encoded function body. Let’s try alternatives returning analyze(): Note subset y variable passed x argument mean(). also get data.frame instead variable: contrast : function receives subset y.","code":"foo <- function(df, labelstr) { rcell(mean(df$y), label = labelstr, format = \"xx.xx\") } lyt7 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% summarize_row_groups(cfun = foo) tbl7 <- build_table(lyt7, df) tbl7 # A B C # ————————————————————————— # U -1.00 1.00 3.00 # V -4.00 -2.00 0.00 # W -7.00 -5.00 -3.00 lyt8 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% analyze(\"y\", afun = mean) tbl8 <- build_table(lyt8, df) tbl8 # A B C # ————————————————————— # U # mean -1 1 3 # V # mean -4 -2 0 # W # mean -7 -5 -3 lyt9 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% analyze(\"y\", afun = function(df) mean(df$y)) tbl9 <- build_table(lyt9, df) tbl9 # A B C # —————————————————— # U # y -1 1 3 # V # y -4 -2 0 # W # y -7 -5 -3 lyt10 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% analyze(\"y\", afun = function(x) mean(x)) tbl10 <- build_table(lyt10, df) tbl10 # A B C # —————————————————— # U # y -1 1 3 # V # y -4 -2 0 # W # y -7 -5 -3"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_concepts.html","id":"group-summaries","dir":"Articles","previous_headings":"Tabulation With Row Structure","what":"Group Summaries","title":"Tabulation Concepts","text":"Pattern interesting one can add row structure (splits). Consider following table: <> represents data represented cell. cell U > u1, subset: . can get table follows: , wanted calculate two summaries per row split: following structure: rows U, u1, u2, …, W, w1, w2, w3 label rows rows (mean_sd range) data rows. Currently content rows table. Content rows summarize data defined splitting (.e. V > v1, B). wanted add content rows r2 split level get: s_cfun_2 content function either returns one row via rcell() multiple rows via in_rows(). data represented <> content rows data ’s descendant, .e. U > u1, content row cell df %>% filter(r1 == \"U\", r2 == \"u1\", c1 == \"\"). Note content functions cfun operate data frames vectors/variables must take df argument. , cfun must also labelstr argument split level. way, cfun can define row name. order get table can use layout framework follows: manner, want content rows r1 split can follows: pagination, content rows label rows get repeated page split descendant content row. , example, split following table ***: get following two tables: ","code":"A B C -------------------------------------- U u1 foo(<>) foo(<>) foo(<>) u2 foo(<>) foo(<>) foo(<>) u3 foo(<>) foo(<>) foo(<>) V v1 foo(<>) foo(<>) foo(<>) v2 foo(<>) foo(<>) foo(<>) v3 foo(<>) foo(<>) foo(<>) W w1 foo(<>) foo(<>) foo(<>) w2 foo(<>) foo(<>) foo(<>) w3 foo(<>) foo(<>) foo(<>) df %>% filter(r1 == \"U\", r2 == \"u1\", c1 == \"A\") # # A tibble: 2 × 6 # c1 c2 r1 r2 x y # # 1 A a2 U u1 1.12 -1 # 2 A a1 U u1 0.594 -1 lyt11 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% split_rows_by(\"r2\") %>% summarize_row_groups(cfun = function(df, labelstr) { rcell(mean(df$x), format = \"xx.xx\", label = paste(\"mean x for\", labelstr)) }) tbl11 <- build_table(lyt11, df) tbl11 # A B C # ——————————————————————————————————————— # U # mean x for u3 -0.04 0.36 -0.25 # mean x for u1 0.86 0.32 NA # mean x for u2 -0.28 0.38 0.08 # V # mean x for v2 0.01 0.55 0.60 # mean x for v3 -0.03 -0.30 1.06 # mean x for v1 0.56 -0.27 -0.54 # W # mean x for w1 -0.58 0.42 0.67 # mean x for w3 0.56 0.69 -0.39 # mean x for w2 -1.99 -0.10 0.53 s_mean_sd <- function(x) { in_rows(\"mean (sd)\" = rcell(c(mean(x), sd(x)), format = \"xx.xx (xx.xx)\")) } s_range <- function(x) { in_rows(\"range\" = rcell(range(x), format = \"xx.xx - xx.xx\")) } lyt12 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% split_rows_by(\"r2\") %>% analyze(\"x\", s_mean_sd, show_labels = \"hidden\") %>% analyze(\"x\", s_range, show_labels = \"hidden\") tbl12 <- build_table(lyt12, df) # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[U]->r2[u3] # Warning in min(x): no non-missing arguments to min; returning Inf # Warning in max(x): no non-missing arguments to max; returning -Inf # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[U]->r2[u1] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[U]->r2[u2] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[V]->r2[v2] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[V]->r2[v3] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[V]->r2[v1] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[W]->r2[w1] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[W]->r2[w3] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[W]->r2[w2] tbl12 # A B C # ——————————————————————————————————————————————————————————— # U # u3 # mean (sd) -0.04 (1.18) 0.36 (1.41) -0.25 (0.72) # range -1.80 - 1.47 -1.28 - 2.40 -0.82 - 0.56 # u1 # mean (sd) 0.86 (0.38) 0.32 (0.51) NA # range 0.59 - 1.12 -0.48 - 0.94 Inf - -Inf # u2 # mean (sd) -0.28 (0.96) 0.38 (0.67) 0.08 (0.91) # range -1.52 - 1.43 -0.39 - 0.82 -0.93 - 1.51 # V # v2 # mean (sd) 0.01 (0.25) 0.55 (1.14) 0.60 (0.03) # range -0.16 - 0.18 -0.84 - 1.60 0.58 - 0.62 # v3 # mean (sd) -0.03 (0.37) -0.30 (0.36) 1.06 (NA) # range -0.41 - 0.33 -0.62 - 0.03 1.06 - 1.06 # v1 # mean (sd) 0.56 (1.10) -0.27 (0.73) -0.54 (1.18) # range -0.16 - 2.17 -1.22 - 0.59 -1.38 - 0.29 # W # w1 # mean (sd) -0.58 (0.85) 0.42 (NA) 0.67 (0.39) # range -1.25 - 0.61 0.42 - 0.42 0.37 - 1.21 # w3 # mean (sd) 0.56 (0.85) 0.69 (NA) -0.39 (1.68) # range -0.71 - 1.98 0.69 - 0.69 -2.21 - 1.10 # w2 # mean (sd) -1.99 (NA) -0.10 (0.47) 0.53 (0.60) # range -1.99 - -1.99 -0.61 - 0.39 -0.10 - 1.16 A B C --------------------------------------------------------- U u1 mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) u2 mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) u3 mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) V v1 mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) v2 mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) v3 mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) W w1 mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) w2 mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) w3 mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) A B C --------------------------------------------------------- U u1 s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) u2 s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) u3 s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) V v1 s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) v2 s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) v3 s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) W w1 s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) w2 s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) w3 s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) s_mean_sd <- function(x) { in_rows(\"mean (sd)\" = rcell(c(mean(x), sd(x)), format = \"xx.xx (xx.xx)\")) } s_range <- function(x) { in_rows(\"range\" = rcell(range(x), format = \"xx.xx - xx.xx\")) } s_cfun_2 <- function(df, labelstr) { rcell(nrow(df), format = \"xx\", label = paste(labelstr, \"(n)\")) } lyt13 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% split_rows_by(\"r2\") %>% summarize_row_groups(cfun = s_cfun_2) %>% analyze(\"x\", s_mean_sd, show_labels = \"hidden\") %>% analyze(\"x\", s_range, show_labels = \"hidden\") tbl13 <- build_table(lyt13, df) # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[U]->r2[u3] # Warning in min(x): no non-missing arguments to min; returning Inf # Warning in max(x): no non-missing arguments to max; returning -Inf # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[U]->r2[u1] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[U]->r2[u2] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[V]->r2[v2] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[V]->r2[v3] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[V]->r2[v1] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[W]->r2[w1] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[W]->r2[w3] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[W]->r2[w2] tbl13 # A B C # ——————————————————————————————————————————————————————————— # U # u3 (n) 6 5 3 # mean (sd) -0.04 (1.18) 0.36 (1.41) -0.25 (0.72) # range -1.80 - 1.47 -1.28 - 2.40 -0.82 - 0.56 # u1 (n) 2 5 0 # mean (sd) 0.86 (0.38) 0.32 (0.51) NA # range 0.59 - 1.12 -0.48 - 0.94 Inf - -Inf # u2 (n) 9 3 7 # mean (sd) -0.28 (0.96) 0.38 (0.67) 0.08 (0.91) # range -1.52 - 1.43 -0.39 - 0.82 -0.93 - 1.51 # V # v2 (n) 2 4 2 # mean (sd) 0.01 (0.25) 0.55 (1.14) 0.60 (0.03) # range -0.16 - 0.18 -0.84 - 1.60 0.58 - 0.62 # v3 (n) 3 4 1 # mean (sd) -0.03 (0.37) -0.30 (0.36) 1.06 (NA) # range -0.41 - 0.33 -0.62 - 0.03 1.06 - 1.06 # v1 (n) 4 7 2 # mean (sd) 0.56 (1.10) -0.27 (0.73) -0.54 (1.18) # range -0.16 - 2.17 -1.22 - 0.59 -1.38 - 0.29 # W # w1 (n) 4 1 4 # mean (sd) -0.58 (0.85) 0.42 (NA) 0.67 (0.39) # range -1.25 - 0.61 0.42 - 0.42 0.37 - 1.21 # w3 (n) 9 1 3 # mean (sd) 0.56 (0.85) 0.69 (NA) -0.39 (1.68) # range -0.71 - 1.98 0.69 - 0.69 -2.21 - 1.10 # w2 (n) 1 4 4 # mean (sd) -1.99 (NA) -0.10 (0.47) 0.53 (0.60) # range -1.99 - -1.99 -0.61 - 0.39 -0.10 - 1.16 lyt14 <- basic_table() %>% split_cols_by(\"c1\") %>% split_rows_by(\"r1\") %>% summarize_row_groups(cfun = s_cfun_2) %>% split_rows_by(\"r2\") %>% summarize_row_groups(cfun = s_cfun_2) %>% analyze(\"x\", s_mean_sd, show_labels = \"hidden\") %>% analyze(\"x\", s_range, show_labels = \"hidden\") tbl14 <- build_table(lyt14, df) # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[U]->r2[u3] # Warning in min(x): no non-missing arguments to min; returning Inf # Warning in max(x): no non-missing arguments to max; returning -Inf # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[U]->r2[u1] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[U]->r2[u2] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[V]->r2[v2] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[V]->r2[v3] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[V]->r2[v1] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[W]->r2[w1] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[W]->r2[w3] # Warning: Non-unique sibling analysis table names. Using Labels instead. Use the table_names argument to analyze to avoid this when analyzing the same variable multiple times. # occured at (row) path: r1[W]->r2[w2] tbl14 # A B C # ——————————————————————————————————————————————————————————— # U (n) 17 13 10 # u3 (n) 6 5 3 # mean (sd) -0.04 (1.18) 0.36 (1.41) -0.25 (0.72) # range -1.80 - 1.47 -1.28 - 2.40 -0.82 - 0.56 # u1 (n) 2 5 0 # mean (sd) 0.86 (0.38) 0.32 (0.51) NA # range 0.59 - 1.12 -0.48 - 0.94 Inf - -Inf # u2 (n) 9 3 7 # mean (sd) -0.28 (0.96) 0.38 (0.67) 0.08 (0.91) # range -1.52 - 1.43 -0.39 - 0.82 -0.93 - 1.51 # V (n) 9 15 5 # v2 (n) 2 4 2 # mean (sd) 0.01 (0.25) 0.55 (1.14) 0.60 (0.03) # range -0.16 - 0.18 -0.84 - 1.60 0.58 - 0.62 # v3 (n) 3 4 1 # mean (sd) -0.03 (0.37) -0.30 (0.36) 1.06 (NA) # range -0.41 - 0.33 -0.62 - 0.03 1.06 - 1.06 # v1 (n) 4 7 2 # mean (sd) 0.56 (1.10) -0.27 (0.73) -0.54 (1.18) # range -0.16 - 2.17 -1.22 - 0.59 -1.38 - 0.29 # W (n) 14 6 11 # w1 (n) 4 1 4 # mean (sd) -0.58 (0.85) 0.42 (NA) 0.67 (0.39) # range -1.25 - 0.61 0.42 - 0.42 0.37 - 1.21 # w3 (n) 9 1 3 # mean (sd) 0.56 (0.85) 0.69 (NA) -0.39 (1.68) # range -0.71 - 1.98 0.69 - 0.69 -2.21 - 1.10 # w2 (n) 1 4 4 # mean (sd) -1.99 (NA) -0.10 (0.47) 0.53 (0.60) # range -1.99 - -1.99 -0.61 - 0.39 -0.10 - 1.16 A B C --------------------------------------------------------- U u1 (n) s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) *** range s_range(<>) s_range(<>) s_range(<>) u2 (n) s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>) A B C --------------------------------------------------------- U u1 (n) s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) A B C --------------------------------------------------------- U u1 (n) s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) range s_range(<>) s_range(<>) s_range(<>) u2 (n) s_cfun_2(<>) s_cfun_2(<>) s_cfun_2(<>) mean_sd s_mean_sd(<>) s_mean_sd(<>) s_mean_sd(<>) range s_range(<>) s_range(<>) s_range(<>)"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_concepts.html","id":"pattern-iii","dir":"Articles","previous_headings":"Tabulation With Row Structure","what":"Pattern III","title":"Tabulation Concepts","text":"Let’s consider following tabulation pattern: discuss future release rtables.","code":"A B C ------------------------------------------------ label 1 foo(x_A) bar(x_B) zoo(x_C) label 2 foo(x_A) bar(x_B) zoo(x_C) label 3 foo(x_A) bar(x_B) zoo(x_C)"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_dplyr.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Comparison with dplyr Tabulation","text":"vignette, like discuss similarities differences dplyr rtable. Much rtables framework focuses tabulation/summarizing data visualization table. vignette, focus summarizing data using dplyr contrast rtables. won’t pay attention table visualization/markup just derive cell content. Using dplyr summarize data gt visualize table good way tabulation certain nature complexity. However, tables table created introduction vignette take effort create dplyr. Part effort due fact using dplyr table data stored data.frames tibbles natural way represent table show vignette. know elegant way deriving table content dplyr please let us know update vignette. table data used introduction vignette:","code":"library(rtables) library(dplyr) n <- 400 set.seed(1) df <- tibble( arm = factor(sample(c(\"Arm A\", \"Arm B\"), n, replace = TRUE), levels = c(\"Arm A\", \"Arm B\")), country = factor(sample(c(\"CAN\", \"USA\"), n, replace = TRUE, prob = c(.55, .45)), levels = c(\"CAN\", \"USA\")), gender = factor(sample(c(\"Female\", \"Male\"), n, replace = TRUE), levels = c(\"Female\", \"Male\")), handed = factor(sample(c(\"Left\", \"Right\"), n, prob = c(.6, .4), replace = TRUE), levels = c(\"Left\", \"Right\")), age = rchisq(n, 30) + 10 ) %>% mutate( weight = 35 * rnorm(n, sd = .5) + ifelse(gender == \"Female\", 140, 180) ) lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"arm\") %>% split_cols_by(\"gender\") %>% split_rows_by(\"country\") %>% summarize_row_groups() %>% split_rows_by(\"handed\") %>% summarize_row_groups() %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # Arm A Arm B # Female Male Female Male # (N=96) (N=105) (N=92) (N=107) # ———————————————————————————————————————————————————————————— # CAN 45 (46.9%) 64 (61.0%) 46 (50.0%) 62 (57.9%) # Left 32 (33.3%) 42 (40.0%) 26 (28.3%) 37 (34.6%) # mean 38.9 40.4 40.3 37.7 # Right 13 (13.5%) 22 (21.0%) 20 (21.7%) 25 (23.4%) # mean 36.6 40.2 40.2 40.6 # USA 51 (53.1%) 41 (39.0%) 46 (50.0%) 45 (42.1%) # Left 34 (35.4%) 19 (18.1%) 25 (27.2%) 25 (23.4%) # mean 40.4 39.7 39.2 40.1 # Right 17 (17.7%) 22 (21.0%) 21 (22.8%) 20 (18.7%) # mean 36.9 39.8 38.5 39.0"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_dplyr.html","id":"getting-started","dir":"Articles","previous_headings":"","what":"Getting Started","title":"Comparison with dplyr Tabulation","text":"start deriving first data cell row 3 (note, row 1 2 content cells, see introduction vignette). Cell 3,1 contains mean age left handed & female Canadians “Arm ”: dplyr: , dplyr gives us verbs easily get average age left handed Canadians group defined 4 columns: can get average age cell values : rtable syntax, need following code get content: mentioned introduction vignette, please ignore difference arranging formatting data: ’s possible condense rtable possible make tibble look like reference table using gt R package. terms tabulation example arguably much added rtables dplyr.","code":"mean(df$age[df$country == \"CAN\" & df$arm == \"Arm A\" & df$gender == \"Female\" & df$handed == \"Left\"]) # [1] 38.86979 df %>% filter(country == \"CAN\", arm == \"Arm A\", gender == \"Female\", handed == \"Left\") %>% summarise(mean_age = mean(age)) # # A tibble: 1 × 1 # mean_age # # 1 38.9 df %>% group_by(arm, gender) %>% filter(country == \"CAN\", handed == \"Left\") %>% summarise(mean_age = mean(age)) # `summarise()` has grouped output by 'arm'. You can override using the `.groups` # argument. # # A tibble: 4 × 3 # # Groups: arm [2] # arm gender mean_age # # 1 Arm A Female 38.9 # 2 Arm A Male 40.4 # 3 Arm B Female 40.3 # 4 Arm B Male 37.7 average_age <- df %>% group_by(arm, gender, country, handed) %>% summarise(mean_age = mean(age)) # `summarise()` has grouped output by 'arm', 'gender', 'country'. You can # override using the `.groups` argument. average_age # # A tibble: 16 × 5 # # Groups: arm, gender, country [8] # arm gender country handed mean_age # # 1 Arm A Female CAN Left 38.9 # 2 Arm A Female CAN Right 36.6 # 3 Arm A Female USA Left 40.4 # 4 Arm A Female USA Right 36.9 # 5 Arm A Male CAN Left 40.4 # 6 Arm A Male CAN Right 40.2 # 7 Arm A Male USA Left 39.7 # 8 Arm A Male USA Right 39.8 # 9 Arm B Female CAN Left 40.3 # 10 Arm B Female CAN Right 40.2 # 11 Arm B Female USA Left 39.2 # 12 Arm B Female USA Right 38.5 # 13 Arm B Male CAN Left 37.7 # 14 Arm B Male CAN Right 40.6 # 15 Arm B Male USA Left 40.1 # 16 Arm B Male USA Right 39.0 lyt <- basic_table() %>% split_cols_by(\"arm\") %>% split_cols_by(\"gender\") %>% split_rows_by(\"country\") %>% split_rows_by(\"handed\") %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # Arm A Arm B # Female Male Female Male # ———————————————————————————————————————— # CAN # Left # mean 38.9 40.4 40.3 37.7 # Right # mean 36.6 40.2 40.2 40.6 # USA # Left # mean 40.4 39.7 39.2 40.1 # Right # mean 36.9 39.8 38.5 39.0"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_dplyr.html","id":"content-information","dir":"Articles","previous_headings":"","what":"Content Information","title":"Comparison with dplyr Tabulation","text":"Unlike rtables different levels summarization discrete computations dplyr need combine first focus count percentage information handedness within country (arm-gender pair), along analysis row mean values: 16 rows (cells) like average_age data frame defined . Next, derive group information countries: Finally, left_join() two levels summary get data.frame containing full set values make body table (note, however, order): Alternatively, calculate counts c_h_df, use mutate() left_join() divide counts n_col values naturally calculated within c_df. simplify c_h_df’s creation somewhat requiring explicit ungroup(), prevents level summarization self-contained set computations. rtables call contrast : can now spot check values , rtable syntax hopefully also become bit straightforward derive cell values dplyr particular table.","code":"c_h_df <- df %>% group_by(arm, gender, country, handed) %>% summarize(mean = mean(age), c_h_count = n()) %>% ## we need the sum below to *not* be by country, so that we're dividing by the column counts ungroup(country) %>% # now the `handed` grouping has been removed, therefore we can calculate percent now: mutate(n_col = sum(c_h_count), c_h_percent = c_h_count / n_col) # `summarise()` has grouped output by 'arm', 'gender', 'country'. You can # override using the `.groups` argument. c_h_df # # A tibble: 16 × 8 # # Groups: arm, gender [4] # arm gender country handed mean c_h_count n_col c_h_percent # # 1 Arm A Female CAN Left 38.9 32 96 0.333 # 2 Arm A Female CAN Right 36.6 13 96 0.135 # 3 Arm A Female USA Left 40.4 34 96 0.354 # 4 Arm A Female USA Right 36.9 17 96 0.177 # 5 Arm A Male CAN Left 40.4 42 105 0.4 # 6 Arm A Male CAN Right 40.2 22 105 0.210 # 7 Arm A Male USA Left 39.7 19 105 0.181 # 8 Arm A Male USA Right 39.8 22 105 0.210 # 9 Arm B Female CAN Left 40.3 26 92 0.283 # 10 Arm B Female CAN Right 40.2 20 92 0.217 # 11 Arm B Female USA Left 39.2 25 92 0.272 # 12 Arm B Female USA Right 38.5 21 92 0.228 # 13 Arm B Male CAN Left 37.7 37 107 0.346 # 14 Arm B Male CAN Right 40.6 25 107 0.234 # 15 Arm B Male USA Left 40.1 25 107 0.234 # 16 Arm B Male USA Right 39.0 20 107 0.187 c_df <- df %>% group_by(arm, gender, country) %>% summarize(c_count = n()) %>% # now the `handed` grouping has been removed, therefore we can calculate percent now: mutate(n_col = sum(c_count), c_percent = c_count / n_col) # `summarise()` has grouped output by 'arm', 'gender'. You can override using the # `.groups` argument. c_df # # A tibble: 8 × 6 # # Groups: arm, gender [4] # arm gender country c_count n_col c_percent # # 1 Arm A Female CAN 45 96 0.469 # 2 Arm A Female USA 51 96 0.531 # 3 Arm A Male CAN 64 105 0.610 # 4 Arm A Male USA 41 105 0.390 # 5 Arm B Female CAN 46 92 0.5 # 6 Arm B Female USA 46 92 0.5 # 7 Arm B Male CAN 62 107 0.579 # 8 Arm B Male USA 45 107 0.421 full_dplyr <- left_join(c_h_df, c_df) %>% ungroup() # Joining with `by = join_by(arm, gender, country, n_col)` lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"arm\") %>% split_cols_by(\"gender\") %>% split_rows_by(\"country\") %>% summarize_row_groups() %>% split_rows_by(\"handed\") %>% summarize_row_groups() %>% analyze(\"age\", afun = mean, format = \"xx.x\") tbl <- build_table(lyt, df) tbl # Arm A Arm B # Female Male Female Male # (N=96) (N=105) (N=92) (N=107) # ———————————————————————————————————————————————————————————— # CAN 45 (46.9%) 64 (61.0%) 46 (50.0%) 62 (57.9%) # Left 32 (33.3%) 42 (40.0%) 26 (28.3%) 37 (34.6%) # mean 38.9 40.4 40.3 37.7 # Right 13 (13.5%) 22 (21.0%) 20 (21.7%) 25 (23.4%) # mean 36.6 40.2 40.2 40.6 # USA 51 (53.1%) 41 (39.0%) 46 (50.0%) 45 (42.1%) # Left 34 (35.4%) 19 (18.1%) 25 (27.2%) 25 (23.4%) # mean 40.4 39.7 39.2 40.1 # Right 17 (17.7%) 22 (21.0%) 21 (22.8%) 20 (18.7%) # mean 36.9 39.8 38.5 39.0 frm_rtables_h <- cell_values( tbl, rowpath = c(\"country\", \"CAN\", \"handed\", \"Right\", \"@content\"), colpath = c(\"arm\", \"Arm B\", \"gender\", \"Female\") )[[1]] frm_rtables_h # [1] 20.0000000 0.2173913 frm_dplyr_h <- full_dplyr %>% filter(country == \"CAN\" & handed == \"Right\" & arm == \"Arm B\" & gender == \"Female\") %>% select(c_h_count, c_h_percent) frm_dplyr_h # # A tibble: 1 × 2 # c_h_count c_h_percent # # 1 20 0.217 frm_rtables_c <- cell_values( tbl, rowpath = c(\"country\", \"CAN\", \"@content\"), colpath = c(\"arm\", \"Arm A\", \"gender\", \"Male\") )[[1]] frm_rtables_c # [1] 64.0000000 0.6095238 frm_dplyr_c <- full_dplyr %>% filter(country == \"CAN\" & arm == \"Arm A\" & gender == \"Male\") %>% select(c_count, c_percent) frm_dplyr_c # # A tibble: 2 × 2 # c_count c_percent # # 1 64 0.610 # 2 64 0.610"},{"path":"https://insightsengineering.github.io/rtables/articles/tabulation_dplyr.html","id":"summary","dir":"Articles","previous_headings":"","what":"Summary","title":"Comparison with dplyr Tabulation","text":"vignette learned : dplyr keeps simple things simple tables group summaries repeating information required rtables streamlines construction complex tables recommend continue reading clinical_trials vignette create number advanced tables using layouts.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/title_footer.html","id":"titles-and-non-referential-footer-materials","dir":"Articles","previous_headings":"","what":"Titles and Non-Referential Footer Materials","title":"Titles, Footers, and Referential Footnotes","text":"rtables table can annotated three types header (title) information, well three types footer information. Header information comes two forms specified directly (main title subtitles), well one populated automatically necessary (page title, see next section). Similarly, footer materials come two directly specified components: main footer provenance footer, addition one computed necessary: referential footnotes. basic_table() accepts values static title footer element layout construction:","code":"library(rtables) library(dplyr) lyt <- basic_table( title = \"Study XXXXXXXX\", subtitles = c(\"subtitle YYYYYYYYYY\", \"subtitle2 ZZZZZZZZZ\"), main_footer = \"Analysis was done using cool methods that are correct\", prov_footer = \"file: /path/to/stuff/that/lives/there HASH:1ac41b242a\" ) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\", split_fun = drop_split_levels) %>% split_rows_by(\"STRATA1\") %>% analyze(\"AGE\", mean, format = \"xx.x\") tbl <- build_table(lyt, DM) cat(export_as_txt(tbl, paginate = TRUE, page_break = \"\\n\\n\\n\")) # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # F # A # mean 30.9 32.9 36.0 # B # mean 34.9 32.9 34.4 # C # mean 35.2 36.0 34.3 # M # A # mean 35.1 31.1 35.6 # B # mean 36.6 32.1 34.4 # C # mean 37.4 32.8 32.8 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a"},{"path":"https://insightsengineering.github.io/rtables/articles/title_footer.html","id":"page-by-splitting","dir":"Articles","previous_headings":"","what":"Page-by splitting","title":"Titles, Footers, and Referential Footnotes","text":"often want split tables based values one variables (e.g., lab measurement) paginate separately within table subsections. rtables via page row splits. Row splits can declared page splits setting page_by = TRUE split_rows_by*() call, . page splits present, page titles generated automatically appending split value (typically factor level, though need ), page_prefix, separated :. default, page_prefix name variable split. Page row splits can nested, within page_by splits, nested within traditional row splits. case, page title page split present every resulting page, seen :","code":"lyt2 <- basic_table( title = \"Study XXXXXXXX\", subtitles = c(\"subtitle YYYYYYYYYY\", \"subtitle2 ZZZZZZZZZ\"), main_footer = \"Analysis was done using cool methods that are correct\", prov_footer = \"file: /path/to/stuff/that/lives/there HASH:1ac41b242a\" ) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\", page_by = TRUE, page_prefix = \"Patient Subset - Gender\", split_fun = drop_split_levels) %>% split_rows_by(\"STRATA1\") %>% analyze(\"AGE\", mean, format = \"xx.x\") tbl2 <- build_table(lyt2, DM) cat(export_as_txt(tbl2, paginate = TRUE, page_break = \"\\n\\n~~~~ Page Break ~~~~\\n\\n\")) # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: F # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # A # mean 30.9 32.9 36.0 # B # mean 34.9 32.9 34.4 # C # mean 35.2 36.0 34.3 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a # # # ~~~~ Page Break ~~~~ # # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: M # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # A # mean 35.1 31.1 35.6 # B # mean 36.6 32.1 34.4 # C # mean 37.4 32.8 32.8 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a lyt3 <- basic_table( title = \"Study XXXXXXXX\", subtitles = c(\"subtitle YYYYYYYYYY\", \"subtitle2 ZZZZZZZZZ\"), main_footer = \"Analysis was done using cool methods that are correct\", prov_footer = \"file: /path/to/stuff/that/lives/there HASH:1ac41b242a\" ) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\", page_by = TRUE, page_prefix = \"Patient Subset - Gender\", split_fun = drop_split_levels) %>% split_rows_by(\"STRATA1\", page_by = TRUE, page_prefix = \"Stratification - Strata\") %>% analyze(\"AGE\", mean, format = \"xx.x\") tbl3 <- build_table(lyt3, DM) cat(export_as_txt(tbl3, paginate = TRUE, page_break = \"\\n\\n~~~~ Page Break ~~~~\\n\\n\")) # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: F # Stratification - Strata: A # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # mean 30.9 32.9 36.0 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a # # # ~~~~ Page Break ~~~~ # # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: F # Stratification - Strata: B # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # mean 34.9 32.9 34.4 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a # # # ~~~~ Page Break ~~~~ # # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: F # Stratification - Strata: C # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # mean 35.2 36.0 34.3 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a # # # ~~~~ Page Break ~~~~ # # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: M # Stratification - Strata: A # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # mean 35.1 31.1 35.6 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a # # # ~~~~ Page Break ~~~~ # # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: M # Stratification - Strata: B # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # mean 36.6 32.1 34.4 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a # # # ~~~~ Page Break ~~~~ # # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: M # Stratification - Strata: C # # —————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————— # mean 37.4 32.8 32.8 # —————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a"},{"path":"https://insightsengineering.github.io/rtables/articles/title_footer.html","id":"referential-footnotes","dir":"Articles","previous_headings":"","what":"Referential Footnotes","title":"Titles, Footers, and Referential Footnotes","text":"Referential footnotes footnotes associated particular component table: column, row, cell. can added tabulation via analysis functions, can also added post-hoc table created. rendered number within curly braces within table body, row, column labels, followed message associated number printed table rendering.","code":""},{"path":"https://insightsengineering.github.io/rtables/articles/title_footer.html","id":"adding-cell--and-analysis-row-referential-footnotes-at-tabulation-time","dir":"Articles","previous_headings":"Referential Footnotes","what":"Adding Cell- and Analysis-row Referential Footnotes At Tabulation Time","title":"Titles, Footers, and Referential Footnotes","text":"note typically type footnote added within analysis function dependent computations done calculate cell value(s), e.g., model converging. simply use context information illustrative proxy . procedure adding footnotes content (summary row) rows cells identical , done within content function.","code":"afun <- function(df, .var, .spl_context) { val <- .spl_context$value[NROW(.spl_context)] rw_fnotes <- if (val == \"C\") list(\"This is strata level C for these patients\") else list() cl_fnotes <- if (val == \"B\" && df[1, \"ARM\", drop = TRUE] == \"C: Combination\") { list(\"these Strata B patients got the drug combination\") } else { list() } in_rows( mean = mean(df[[.var]]), .row_footnotes = rw_fnotes, .cell_footnotes = cl_fnotes, .formats = c(mean = \"xx.x\") ) } lyt <- basic_table( title = \"Study XXXXXXXX\", subtitles = c(\"subtitle YYYYYYYYYY\", \"subtitle2 ZZZZZZZZZ\"), main_footer = \"Analysis was done using cool methods that are correct\", prov_footer = \"file: /path/to/stuff/that/lives/there HASH:1ac41b242a\" ) %>% split_cols_by(\"ARM\") %>% split_rows_by(\"SEX\", page_by = TRUE, page_prefix = \"Patient Subset - Gender\", split_fun = drop_split_levels) %>% split_rows_by(\"STRATA1\") %>% analyze(\"AGE\", afun, format = \"xx.x\") tbl <- build_table(lyt, DM) cat(export_as_txt(tbl, paginate = TRUE, page_break = \"\\n\\n\\n\")) # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: F # # —————————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————— # A # mean 30.9 32.9 36.0 # B # mean 34.9 32.9 34.4 {1} # C # mean {2} 35.2 36.0 34.3 # —————————————————————————————————————————————————————— # # {1} - these Strata B patients got the drug combination # {2} - This is strata level C for these patients # —————————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a # # # # Study XXXXXXXX # subtitle YYYYYYYYYY # subtitle2 ZZZZZZZZZ # Patient Subset - Gender: M # # —————————————————————————————————————————————————————— # A: Drug X B: Placebo C: Combination # —————————————————————————————————————————————————————— # A # mean 35.1 31.1 35.6 # B # mean 36.6 32.1 34.4 {1} # C # mean {2} 37.4 32.8 32.8 # —————————————————————————————————————————————————————— # # {1} - these Strata B patients got the drug combination # {2} - This is strata level C for these patients # —————————————————————————————————————————————————————— # # Analysis was done using cool methods that are correct # # file: /path/to/stuff/that/lives/there HASH:1ac41b242a"},{"path":"https://insightsengineering.github.io/rtables/articles/title_footer.html","id":"annotating-an-existing-table-with-referential-footnotes","dir":"Articles","previous_headings":"Referential Footnotes","what":"Annotating an Existing Table with Referential Footnotes","title":"Titles, Footers, and Referential Footnotes","text":"addition inserting referential footnotes tabulation time within analysis functions, can also annotate tables post-hoc. also way add footnotes column labels, controlled within analysis content function. fnotes_at_path<- function accepts row path, column path, value full set footnotes defined locations (NULL character vector). non-NULL row path NULL column path specifies footnote(s) attached row, NULL row path non-NULL column path indicates go column. non-NULL indicates cell (must resolve individual cell). Note step content row must add path, even though didn’t need put footnote full row. Currently, content rows default named label rather name corresponding facet. reflected output , e.g., row_paths_summary. can add footnotes cell like :","code":"## from ?tolower example slightly modified .simpleCap <- function(x) { if (length(x) > 1) { return(sapply(x, .simpleCap)) } s <- strsplit(tolower(x), \" \")[[1]] paste(toupper(substring(s, 1, 1)), substring(s, 2), sep = \"\", collapse = \" \") } adsl2 <- ex_adsl %>% filter(SEX %in% c(\"M\", \"F\") & RACE %in% (levels(RACE)[1:3])) %>% ## we trim the level names here solely due to space considerations mutate(ethnicity = .simpleCap(gsub(\"(.*)OR.*\", \"\\\\1\", RACE)), RACE = factor(RACE)) lyt2 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_cols_by(\"SEX\", split_fun = drop_split_levels) %>% split_rows_by(\"RACE\", labels_var = \"ethnicity\", split_fun = drop_split_levels) %>% summarize_row_groups() %>% analyze(c(\"AGE\", \"STRATA1\")) tbl2 <- build_table(lyt2, adsl2) tbl2 # A: Drug X B: Placebo C: Combination # F M F M F M # ——————————————————————————————————————————————————————————————————————————————————————— # Asian 41 (53.9%) 25 (54.3%) 36 (52.2%) 30 (60.0%) 39 (60.9%) 32 (57.1%) # AGE # Mean 31.22 34.60 35.06 38.63 36.44 37.66 # STRATA1 # A 11 10 14 10 11 7 # B 11 9 15 7 11 14 # C 19 6 7 13 17 11 # Black 18 (23.7%) 12 (26.1%) 16 (23.2%) 12 (24.0%) 14 (21.9%) 14 (25.0%) # AGE # Mean 34.06 34.58 33.88 36.33 33.21 34.21 # STRATA1 # A 5 2 5 6 3 7 # B 6 5 3 4 4 4 # C 7 5 8 2 7 3 # White 17 (22.4%) 9 (19.6%) 17 (24.6%) 8 (16.0%) 11 (17.2%) 10 (17.9%) # AGE # Mean 34.12 40.00 32.41 34.62 33.00 30.80 # STRATA1 # A 5 3 3 3 3 5 # B 5 4 8 4 5 2 # C 7 2 6 1 3 3 fnotes_at_path(tbl2, c(\"RACE\", \"ASIAN\")) <- c(\"hi\", \"there\") tbl2 # A: Drug X B: Placebo C: Combination # F M F M F M # —————————————————————————————————————————————————————————————————————————————————————————— # Asian {1, 2} 41 (53.9%) 25 (54.3%) 36 (52.2%) 30 (60.0%) 39 (60.9%) 32 (57.1%) # AGE # Mean 31.22 34.60 35.06 38.63 36.44 37.66 # STRATA1 # A 11 10 14 10 11 7 # B 11 9 15 7 11 14 # C 19 6 7 13 17 11 # Black 18 (23.7%) 12 (26.1%) 16 (23.2%) 12 (24.0%) 14 (21.9%) 14 (25.0%) # AGE # Mean 34.06 34.58 33.88 36.33 33.21 34.21 # STRATA1 # A 5 2 5 6 3 7 # B 6 5 3 4 4 4 # C 7 5 8 2 7 3 # White 17 (22.4%) 9 (19.6%) 17 (24.6%) 8 (16.0%) 11 (17.2%) 10 (17.9%) # AGE # Mean 34.12 40.00 32.41 34.62 33.00 30.80 # STRATA1 # A 5 3 3 3 3 5 # B 5 4 8 4 5 2 # C 7 2 6 1 3 3 # —————————————————————————————————————————————————————————————————————————————————————————— # # {1} - hi # {2} - there # —————————————————————————————————————————————————————————————————————————————————————————— fnotes_at_path(tbl2, rowpath = NULL, c(\"ARM\", \"B: Placebo\")) <- c(\"this is a placebo\") tbl2 # A: Drug X B: Placebo {NA} C: Combination # F M F M F M # —————————————————————————————————————————————————————————————————————————————————————————— # Asian {1, 2} 41 (53.9%) 25 (54.3%) 36 (52.2%) 30 (60.0%) 39 (60.9%) 32 (57.1%) # AGE # Mean 31.22 34.60 35.06 38.63 36.44 37.66 # STRATA1 # A 11 10 14 10 11 7 # B 11 9 15 7 11 14 # C 19 6 7 13 17 11 # Black 18 (23.7%) 12 (26.1%) 16 (23.2%) 12 (24.0%) 14 (21.9%) 14 (25.0%) # AGE # Mean 34.06 34.58 33.88 36.33 33.21 34.21 # STRATA1 # A 5 2 5 6 3 7 # B 6 5 3 4 4 4 # C 7 5 8 2 7 3 # White 17 (22.4%) 9 (19.6%) 17 (24.6%) 8 (16.0%) 11 (17.2%) 10 (17.9%) # AGE # Mean 34.12 40.00 32.41 34.62 33.00 30.80 # STRATA1 # A 5 3 3 3 3 5 # B 5 4 8 4 5 2 # C 7 2 6 1 3 3 # —————————————————————————————————————————————————————————————————————————————————————————— # # {1} - hi # {2} - there # {NA} - this is a placebo # —————————————————————————————————————————————————————————————————————————————————————————— row_paths_summary(tbl2) # rowname node_class path # ——————————————————————————————————————————————————————————————————————————— # Asian ContentRow RACE, ASIAN, @content, Asian # AGE LabelRow RACE, ASIAN, AGE # Mean DataRow RACE, ASIAN, AGE, Mean # STRATA1 LabelRow RACE, ASIAN, STRATA1 # A DataRow RACE, ASIAN, STRATA1, A # B DataRow RACE, ASIAN, STRATA1, B # C DataRow RACE, ASIAN, STRATA1, C # Black ContentRow RACE, BLACK OR AFRICAN AMERICAN, @content, Black # AGE LabelRow RACE, BLACK OR AFRICAN AMERICAN, AGE # Mean DataRow RACE, BLACK OR AFRICAN AMERICAN, AGE, Mean # STRATA1 LabelRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1 # A DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, A # B DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, B # C DataRow RACE, BLACK OR AFRICAN AMERICAN, STRATA1, C # White ContentRow RACE, WHITE, @content, White # AGE LabelRow RACE, WHITE, AGE # Mean DataRow RACE, WHITE, AGE, Mean # STRATA1 LabelRow RACE, WHITE, STRATA1 # A DataRow RACE, WHITE, STRATA1, A # B DataRow RACE, WHITE, STRATA1, B # C DataRow RACE, WHITE, STRATA1, C fnotes_at_path( tbl2, rowpath = c(\"RACE\", \"ASIAN\", \"@content\", \"Asian\"), colpath = c(\"ARM\", \"B: Placebo\", \"SEX\", \"F\") ) <- \"These asian women got placebo treatments\" tbl2 # A: Drug X B: Placebo {NA} C: Combination # F M F M F M # —————————————————————————————————————————————————————————————————————————————————————————————— # Asian {1, 2} 41 (53.9%) 25 (54.3%) 36 (52.2%) {3} 30 (60.0%) 39 (60.9%) 32 (57.1%) # AGE # Mean 31.22 34.60 35.06 38.63 36.44 37.66 # STRATA1 # A 11 10 14 10 11 7 # B 11 9 15 7 11 14 # C 19 6 7 13 17 11 # Black 18 (23.7%) 12 (26.1%) 16 (23.2%) 12 (24.0%) 14 (21.9%) 14 (25.0%) # AGE # Mean 34.06 34.58 33.88 36.33 33.21 34.21 # STRATA1 # A 5 2 5 6 3 7 # B 6 5 3 4 4 4 # C 7 5 8 2 7 3 # White 17 (22.4%) 9 (19.6%) 17 (24.6%) 8 (16.0%) 11 (17.2%) 10 (17.9%) # AGE # Mean 34.12 40.00 32.41 34.62 33.00 30.80 # STRATA1 # A 5 3 3 3 3 5 # B 5 4 8 4 5 2 # C 7 2 6 1 3 3 # —————————————————————————————————————————————————————————————————————————————————————————————— # # {1} - hi # {2} - there # {3} - These asian women got placebo treatments # {NA} - this is a placebo # ——————————————————————————————————————————————————————————————————————————————————————————————"},{"path":"https://insightsengineering.github.io/rtables/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Gabriel Becker. Author. Original creator package Adrian Waddell. Author. Daniel Sabanés Bové. Contributor. Maximilian Mordig. Contributor. Davide Garolini. Contributor. Emily de la Rua. Contributor. Abinaya Yogasekaram. Contributor. Joe Zhu. Contributor, maintainer. F. Hoffmann-La Roche AG. Copyright holder, funder.","code":""},{"path":"https://insightsengineering.github.io/rtables/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Becker G, Waddell (2024). rtables: Reporting Tables. R package version 0.6.10.9011, https://insightsengineering.github.io/rtables/, https://github.com/insightsengineering/rtables.","code":"@Manual{, title = {rtables: Reporting Tables}, author = {Gabriel Becker and Adrian Waddell}, year = {2024}, note = {R package version 0.6.10.9011, https://insightsengineering.github.io/rtables/}, url = {https://github.com/insightsengineering/rtables}, }"},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/index.html","id":"reporting-tables-with-r","dir":"","previous_headings":"","what":"Reporting Tables with R","title":"Reporting Tables","text":"rtables R package designed create display complex tables R. cells rtable may contain high-dimensional data structure can displayed cell-specific formatting instructions. Currently, rtables can outputted ascii html, pdf, well Power Point (via conversion flextable objects). rtf support development future release. rtables developed copy written F. Hoffmann-La Roche released open source Apache License Version 2. rtables development driven need create regulatory ready tables health authority review. key requirements undertaking listed : values need programmatically accessible non-rounded state cross-checking multiple values displayed within cell flexible tabulation framework flexible formatting (cell spans, rounding, alignment, etc.) multiple output formats (html, ascii, latex, pdf, xml) flexible pagination horizontal vertical directions distinguish name label data structure work CDISC standards title, footnotes, cell cell/row/column references rtables currently covers virtually requirements, advances remain active development.","code":""},{"path":"https://insightsengineering.github.io/rtables/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"Reporting Tables","text":"rtables available CRAN can install latest released version : can install latest development version directly GitHub : Packaged releases (CRAN official CRAN releases) can found releases list. understand use package, please refer Introduction rtables article, provides multiple examples code implementation.","code":"install.packages(\"rtables\") # install.packages(\"pak\") pak::pak(\"insightsengineering/rtables\")"},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/index.html","id":"usage","dir":"","previous_headings":"","what":"Usage","title":"Reporting Tables","text":"first demonstrate demographic table-like example show creation complex table.","code":"library(rtables) lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(c(\"AGE\", \"BMRKR1\", \"BMRKR2\"), function(x, ...) { if (is.numeric(x)) { in_rows( \"Mean (sd)\" = c(mean(x), sd(x)), \"Median\" = median(x), \"Min - Max\" = range(x), .formats = c(\"xx.xx (xx.xx)\", \"xx.xx\", \"xx.xx - xx.xx\") ) } else if (is.factor(x) || is.character(x)) { in_rows(.list = list_wrap_x(table)(x)) } else { stop(\"type not supported\") } }) build_table(lyt, ex_adsl) #> A: Drug X B: Placebo C: Combination #> ———————————————————————————————————————————————————————————— #> AGE #> Mean (sd) 33.77 (6.55) 35.43 (7.90) 35.43 (7.72) #> Median 33.00 35.00 35.00 #> Min - Max 21.00 - 50.00 21.00 - 62.00 20.00 - 69.00 #> BMRKR1 #> Mean (sd) 5.97 (3.55) 5.70 (3.31) 5.62 (3.49) #> Median 5.39 4.81 4.61 #> Min - Max 0.41 - 17.67 0.65 - 14.24 0.17 - 21.39 #> BMRKR2 #> LOW 50 45 40 #> MEDIUM 37 56 42 #> HIGH 47 33 50 library(rtables) library(dplyr) ## for simplicity grab non-sparse subset ADSL <- ex_adsl %>% filter(RACE %in% levels(RACE)[1:3]) biomarker_ave <- function(x, ...) { val <- if (length(x) > 0) round(mean(x), 2) else \"no data\" in_rows( \"Biomarker 1 (mean)\" = rcell(val) ) } basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\") %>% split_cols_by(\"BMRKR2\") %>% split_rows_by(\"RACE\", split_fun = trim_levels_in_group(\"SEX\")) %>% split_rows_by(\"SEX\") %>% summarize_row_groups() %>% analyze(\"BMRKR1\", biomarker_ave) %>% build_table(ADSL) #> A: Drug X B: Placebo C: Combination #> LOW MEDIUM HIGH LOW MEDIUM HIGH LOW MEDIUM HIGH #> (N=45) (N=35) (N=46) (N=42) (N=48) (N=31) (N=40) (N=39) (N=47) #> ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— #> ASIAN #> F 13 (28.9%) 9 (25.7%) 19 (41.3%) 9 (21.4%) 18 (37.5%) 9 (29.0%) 13 (32.5%) 9 (23.1%) 17 (36.2%) #> Biomarker 1 (mean) 5.23 6.17 5.38 5.64 5.55 4.33 5.46 5.48 5.19 #> M 8 (17.8%) 7 (20.0%) 10 (21.7%) 12 (28.6%) 10 (20.8%) 8 (25.8%) 5 (12.5%) 11 (28.2%) 16 (34.0%) #> Biomarker 1 (mean) 6.77 6.06 5.54 4.9 4.98 6.81 6.53 5.47 4.98 #> U 1 (2.2%) 1 (2.9%) 0 (0.0%) 0 (0.0%) 0 (0.0%) 1 (3.2%) 0 (0.0%) 1 (2.6%) 1 (2.1%) #> Biomarker 1 (mean) 4.68 7.7 no data no data no data 6.97 no data 11.93 9.01 #> BLACK OR AFRICAN AMERICAN #> F 6 (13.3%) 3 (8.6%) 9 (19.6%) 6 (14.3%) 8 (16.7%) 2 (6.5%) 7 (17.5%) 4 (10.3%) 3 (6.4%) #> Biomarker 1 (mean) 5.01 7.2 6.79 6.15 5.26 8.57 5.72 5.76 4.58 #> M 5 (11.1%) 5 (14.3%) 2 (4.3%) 3 (7.1%) 5 (10.4%) 4 (12.9%) 4 (10.0%) 5 (12.8%) 5 (10.6%) #> Biomarker 1 (mean) 6.92 5.82 11.66 4.46 6.14 8.47 6.16 5.25 4.83 #> U 0 (0.0%) 0 (0.0%) 0 (0.0%) 0 (0.0%) 0 (0.0%) 0 (0.0%) 1 (2.5%) 1 (2.6%) 0 (0.0%) #> Biomarker 1 (mean) no data no data no data no data no data no data 2.79 9.82 no data #> UNDIFFERENTIATED 1 (2.2%) 0 (0.0%) 0 (0.0%) 0 (0.0%) 0 (0.0%) 0 (0.0%) 2 (5.0%) 0 (0.0%) 0 (0.0%) #> Biomarker 1 (mean) 9.48 no data no data no data no data no data 6.46 no data no data #> WHITE #> F 6 (13.3%) 7 (20.0%) 4 (8.7%) 5 (11.9%) 6 (12.5%) 6 (19.4%) 6 (15.0%) 3 (7.7%) 2 (4.3%) #> Biomarker 1 (mean) 4.43 7.83 4.52 6.42 5.07 7.83 6.71 5.87 10.7 #> M 4 (8.9%) 3 (8.6%) 2 (4.3%) 6 (14.3%) 1 (2.1%) 1 (3.2%) 2 (5.0%) 5 (12.8%) 3 (6.4%) #> Biomarker 1 (mean) 5.81 7.23 1.39 4.72 4.58 12.87 2.3 5.1 5.98 #> U 1 (2.2%) 0 (0.0%) 0 (0.0%) 1 (2.4%) 0 (0.0%) 0 (0.0%) 0 (0.0%) 0 (0.0%) 0 (0.0%) #> Biomarker 1 (mean) 3.94 no data no data 3.77 no data no data no data no data no data"},{"path":"https://insightsengineering.github.io/rtables/index.html","id":"acknowledgments","dir":"","previous_headings":"","what":"Acknowledgments","title":"Reporting Tables","text":"like thank everyone made rtables better project providing feedback improving examples & vignettes. following list contributors alphabetical: Maximo Carreras, Francois Collins, Saibah Chohan, Tadeusz Lewandowski, Nick Paszty, Nina Qi, Jana Stoilova, Heng Wang, Godwin Yung","code":""},{"path":"https://insightsengineering.github.io/rtables/index.html","id":"presentations","dir":"","previous_headings":"","what":"Presentations","title":"Reporting Tables","text":"Generating Tables, Listings, Graphs using NEST / cardinal [Video] BBS Session Regulatory Submissions Clinical Trials [Video] R Medicine Virtual Conference 2023 [Video] Advanced rtables Training 2023 [Part 1 Slides] [Part 2 Slides] R Pharma 2022 - Creating Submission-Quality Clinical Trial Reporting Tables R rtables [Slides] [Video] R Adoption Series - Reporting Table Creation R [Video] [Slides] Tables Clinical Trials R [Book] useR! 2020 - rtables Layouting Tabulation Framework [Video]","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/CellValue.html","id":null,"dir":"Reference","previous_headings":"","what":"Constructor for Cell Value — CellValue","title":"Constructor for Cell Value — CellValue","text":"Constructor Cell Value","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/CellValue.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Constructor for Cell Value — CellValue","text":"","code":"CellValue( val, format = NULL, colspan = 1L, label = NULL, indent_mod = NULL, footnotes = NULL, align = NULL, format_na_str = NULL, stat_names = NA_character_ )"},{"path":"https://insightsengineering.github.io/rtables/reference/CellValue.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Constructor for Cell Value — CellValue","text":"val () value cell exactly passed formatter returned extracted. format (string, function, list) format associated split. Formats can declared via strings (\"xx.x\") function. cases analyze calls, can character vectors lists functions. See formatters::list_valid_format_labels() list available format strings. colspan (integer(1)) column span value. label (string) label (confused name) object/structure. indent_mod (numeric) modifier default indent position structure created function (subtable, content table, row) structure's children. Defaults 0, corresponds unmodified default behavior. footnotes (list NULL) referential footnote messages cell. align (string NULL) alignment value rendered . Defaults \"center\" NULL used. See formatters::list_valid_aligns() currently supported alignments. format_na_str (string) string displayed formatted cell's value(s) NA. stat_names (character NA) names statistics cell. can vector strings. NA, statistic names specified.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/CellValue.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Constructor for Cell Value — CellValue","text":"object representing value within single cell within populated table. underlying structure object implementation detail relied upon beyond calling accessors class.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/EmptyColInfo.html","id":null,"dir":"Reference","previous_headings":"","what":"Empty table, column, split objects — EmptyColInfo","title":"Empty table, column, split objects — EmptyColInfo","text":"Empty objects various types compare efficiently.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/ManualSplit.html","id":null,"dir":"Reference","previous_headings":"","what":"Manually defined split — ManualSplit","title":"Manually defined split — ManualSplit","text":"Manually defined split","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/ManualSplit.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Manually defined split — ManualSplit","text":"","code":"ManualSplit( levels, label, name = \"manual\", extra_args = list(), indent_mod = 0L, cindent_mod = 0L, cvar = \"\", cextra_args = list(), label_pos = \"visible\", page_prefix = NA_character_, section_div = NA_character_ )"},{"path":"https://insightsengineering.github.io/rtables/reference/ManualSplit.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Manually defined split — ManualSplit","text":"levels (character) levels split (.e. children manual split). label (string) label (confused name) object/structure. name (string) name split/table/row created. Defaults value corresponding label, required . extra_args (list) extra arguments passed tabulation function. Element position list corresponds children split. Named elements child-specific lists ignored match formal argument tabulation function. indent_mod (numeric) modifier default indent position structure created function (subtable, content table, row) structure's children. Defaults 0, corresponds unmodified default behavior. cindent_mod (numeric(1)) indent modifier content tables generated split. cvar (string) variable, , content function accept. Defaults NA. cextra_args (list) extra arguments passed content function tabulating row group summaries. label_pos (string) location variable label displayed. Accepts \"hidden\" (default non-analyze row splits), \"visible\", \"topleft\", \"default\" (analyze splits ). analyze calls, \"default\" indicates variable visible multiple variables analyzed level nesting. page_prefix (string) prefix appended split value forcing pagination children split/table. section_div (string) string repeated section divider group defined split instruction, NA_character_ (default) section divider.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/ManualSplit.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Manually defined split — ManualSplit","text":"ManualSplit object.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/ManualSplit.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Manually defined split — ManualSplit","text":"Gabriel Becker","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/MultiVarSplit.html","id":null,"dir":"Reference","previous_headings":"","what":"Split between two or more different variables — MultiVarSplit","title":"Split between two or more different variables — MultiVarSplit","text":"Split two different variables","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/MultiVarSplit.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Split between two or more different variables — MultiVarSplit","text":"","code":"MultiVarSplit( vars, split_label = \"\", varlabels = NULL, varnames = NULL, cfun = NULL, cformat = NULL, cna_str = NA_character_, split_format = NULL, split_na_str = NA_character_, split_name = \"multivars\", child_labels = c(\"default\", \"visible\", \"hidden\"), extra_args = list(), indent_mod = 0L, cindent_mod = 0L, cvar = \"\", cextra_args = list(), label_pos = \"visible\", split_fun = NULL, page_prefix = NA_character_, section_div = NA_character_, show_colcounts = FALSE, colcount_format = NULL )"},{"path":"https://insightsengineering.github.io/rtables/reference/MultiVarSplit.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Split between two or more different variables — MultiVarSplit","text":"vars (character) vector variable names. split_label (string) label associated table generated split. confused labels assigned child (based data type split tabulation). varlabels (character) vector labels vars. varnames (character) vector names vars appear pathing. vars unique variable names. , variable names suffixes necessary enforce uniqueness. cfun (list, function, NULL) tabulation function(s) creating content rows. Must accept x df first parameter. Must accept labelstr second argument. Can optionally accept optional arguments accepted analysis functions. See analyze(). cformat (string, function, list) format content rows. cna_str (character) NA string use cformat content table. split_format (string, function, list) default format associated split created. split_na_str (character) NA string vector use split_format. split_name (string) name associated split (pathing, etc.). child_labels (string) display behavior labels (.e. label rows) children split. Accepts \"default\", \"visible\", \"hidden\". Defaults \"default\" flags label row visible child 0 content rows. extra_args (list) extra arguments passed tabulation function. Element position list corresponds children split. Named elements child-specific lists ignored match formal argument tabulation function. indent_mod (numeric) modifier default indent position structure created function (subtable, content table, row) structure's children. Defaults 0, corresponds unmodified default behavior. cindent_mod (numeric(1)) indent modifier content tables generated split. cvar (string) variable, , content function accept. Defaults NA. cextra_args (list) extra arguments passed content function tabulating row group summaries. label_pos (string) location variable label displayed. Accepts \"hidden\" (default non-analyze row splits), \"visible\", \"topleft\", \"default\" (analyze splits ). analyze calls, \"default\" indicates variable visible multiple variables analyzed level nesting. split_fun (function NULL) custom splitting function. See custom_split_funs. page_prefix (string) prefix appended split value forcing pagination children split/table. section_div (string) string repeated section divider group defined split instruction, NA_character_ (default) section divider. show_colcounts (logical(1)) column counts displayed level facets created split. Defaults FALSE. colcount_format (character(1)) show_colcounts TRUE, format used display column counts facets generated split. Defaults \"(N=xx)\".","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/MultiVarSplit.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Split between two or more different variables — MultiVarSplit","text":"MultiVarSplit object.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/MultiVarSplit.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Split between two or more different variables — MultiVarSplit","text":"Gabriel Becker","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/VarLevelSplit.html","id":null,"dir":"Reference","previous_headings":"","what":"Split on levels within a variable — VarLevelSplit-class","title":"Split on levels within a variable — VarLevelSplit-class","text":"Split levels within variable","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/VarLevelSplit.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Split on levels within a variable — VarLevelSplit-class","text":"","code":"VarLevelSplit( var, split_label, labels_var = NULL, cfun = NULL, cformat = NULL, cna_str = NA_character_, split_fun = NULL, split_format = NULL, split_na_str = NA_character_, valorder = NULL, split_name = var, child_labels = c(\"default\", \"visible\", \"hidden\"), extra_args = list(), indent_mod = 0L, label_pos = c(\"topleft\", \"hidden\", \"visible\"), cindent_mod = 0L, cvar = \"\", cextra_args = list(), page_prefix = NA_character_, section_div = NA_character_, show_colcounts = FALSE, colcount_format = NULL ) VarLevWBaselineSplit( var, ref_group, labels_var = var, split_label, split_fun = NULL, label_fstr = \"%s - %s\", cfun = NULL, cformat = NULL, cna_str = NA_character_, cvar = \"\", split_format = NULL, split_na_str = NA_character_, valorder = NULL, split_name = var, extra_args = list(), show_colcounts = FALSE, colcount_format = NULL )"},{"path":"https://insightsengineering.github.io/rtables/reference/VarLevelSplit.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Split on levels within a variable — VarLevelSplit-class","text":"var (string) variable name. split_label (string) label associated table generated split. confused labels assigned child (based data type split tabulation). labels_var (string) name variable containing labels displayed values var. cfun (list, function, NULL) tabulation function(s) creating content rows. Must accept x df first parameter. Must accept labelstr second argument. Can optionally accept optional arguments accepted analysis functions. See analyze(). cformat (string, function, list) format content rows. cna_str (character) NA string use cformat content table. split_fun (function NULL) custom splitting function. See custom_split_funs. split_format (string, function, list) default format associated split created. split_na_str (character) NA string vector use split_format. valorder (character) order split children appear resulting table. split_name (string) name associated split (pathing, etc.). child_labels (string) display behavior labels (.e. label rows) children split. Accepts \"default\", \"visible\", \"hidden\". Defaults \"default\" flags label row visible child 0 content rows. extra_args (list) extra arguments passed tabulation function. Element position list corresponds children split. Named elements child-specific lists ignored match formal argument tabulation function. indent_mod (numeric) modifier default indent position structure created function (subtable, content table, row) structure's children. Defaults 0, corresponds unmodified default behavior. label_pos (string) location variable label displayed. Accepts \"hidden\" (default non-analyze row splits), \"visible\", \"topleft\", \"default\" (analyze splits ). analyze calls, \"default\" indicates variable visible multiple variables analyzed level nesting. cindent_mod (numeric(1)) indent modifier content tables generated split. cvar (string) variable, , content function accept. Defaults NA. cextra_args (list) extra arguments passed content function tabulating row group summaries. page_prefix (string) prefix appended split value forcing pagination children split/table. section_div (string) string repeated section divider group defined split instruction, NA_character_ (default) section divider. show_colcounts (logical(1)) column counts displayed level facets created split. Defaults FALSE. colcount_format (character(1)) show_colcounts TRUE, format used display column counts facets generated split. Defaults \"(N=xx)\". ref_group (character) value var taken ref_group/control compared . label_fstr (string) sprintf style format string. non-comparison splits, can contain one \"\\%s\" takes current split value generates row/column label. comparison-based splits can contain two \"\\%s\".","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/VarLevelSplit.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Split on levels within a variable — VarLevelSplit-class","text":"VarLevelSplit object.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/VarLevelSplit.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Split on levels within a variable — VarLevelSplit-class","text":"Gabriel Becker","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/Viewer.html","id":null,"dir":"Reference","previous_headings":"","what":"Display an rtable object in the Viewer pane in RStudio or in a browser — Viewer","title":"Display an rtable object in the Viewer pane in RStudio or in a browser — Viewer","text":"table displayed using bootstrap styling.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/Viewer.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Display an rtable object in the Viewer pane in RStudio or in a browser — Viewer","text":"","code":"Viewer(x, y = NULL, ...)"},{"path":"https://insightsengineering.github.io/rtables/reference/Viewer.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Display an rtable object in the Viewer pane in RStudio or in a browser — Viewer","text":"x (rtable shiny.tag) object class rtable shiny.tag (defined htmltools package). y (rtable shiny.tag) optional second argument type x. ... arguments passed as_html().","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/Viewer.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Display an rtable object in the Viewer pane in RStudio or in a browser — Viewer","text":"meaningful. Called side effect opening browser viewer pane.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/Viewer.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Display an rtable object in the Viewer pane in RStudio or in a browser — Viewer","text":"","code":"if (interactive()) { sl5 <- factor(iris$Sepal.Length > 5, levels = c(TRUE, FALSE), labels = c(\"S.L > 5\", \"S.L <= 5\") ) df <- cbind(iris, sl5 = sl5) lyt <- basic_table() %>% split_cols_by(\"sl5\") %>% analyze(\"Sepal.Length\") tbl <- build_table(lyt, df) Viewer(tbl) Viewer(tbl, tbl) tbl2 <- htmltools::tags$div( class = \"table-responsive\", as_html(tbl, class_table = \"table\") ) Viewer(tbl, tbl2) }"},{"path":"https://insightsengineering.github.io/rtables/reference/add_colcounts.html","id":null,"dir":"Reference","previous_headings":"","what":"Add the column population counts to the header — add_colcounts","title":"Add the column population counts to the header — add_colcounts","text":"Add data derived column counts.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_colcounts.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add the column population counts to the header — add_colcounts","text":"","code":"add_colcounts(lyt, format = \"(N=xx)\")"},{"path":"https://insightsengineering.github.io/rtables/reference/add_colcounts.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add the column population counts to the header — add_colcounts","text":"lyt (PreDataTableLayouts) layout object pre-data used tabulation. format (string, function, list) format associated split. Formats can declared via strings (\"xx.x\") function. cases analyze calls, can character vectors lists functions. See formatters::list_valid_format_labels() list available format strings.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_colcounts.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add the column population counts to the header — add_colcounts","text":"PreDataTableLayouts object suitable passing layouting functions, build_table().","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_colcounts.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Add the column population counts to the header — add_colcounts","text":"often case column counts derived input data build_table() representative population counts. example, events counted table header display number subjects total number events.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_colcounts.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Add the column population counts to the header — add_colcounts","text":"Gabriel Becker","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_colcounts.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Add the column population counts to the header — add_colcounts","text":"","code":"lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% add_colcounts() %>% split_rows_by(\"RACE\", split_fun = drop_split_levels) %>% analyze(\"AGE\", afun = function(x) list(min = min(x), max = max(x))) lyt #> A Pre-data Table Layout #> #> Column-Split Structure: #> ARM (lvls) #> #> Row-Split Structure: #> RACE (lvls) -> AGE (** analysis **) #> tbl <- build_table(lyt, DM) tbl #> A: Drug X B: Placebo C: Combination #> (N=121) (N=106) (N=129) #> ——————————————————————————————————————————————————————————————————— #> ASIAN #> min 20 21 22 #> max 58 55 53 #> BLACK OR AFRICAN AMERICAN #> min 23 21 24 #> max 60 42 51 #> WHITE #> min 30 25 28 #> max 47 55 47"},{"path":"https://insightsengineering.github.io/rtables/reference/add_combo_facet.html","id":null,"dir":"Reference","previous_headings":"","what":"Add a combination facet in post-processing — add_combo_facet","title":"Add a combination facet in post-processing — add_combo_facet","text":"Add combination facet post-processing stage custom split fun.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_combo_facet.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add a combination facet in post-processing — add_combo_facet","text":"","code":"add_combo_facet(name, label = name, levels, extra = list()) add_overall_facet(name, label, extra = list())"},{"path":"https://insightsengineering.github.io/rtables/reference/add_combo_facet.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add a combination facet in post-processing — add_combo_facet","text":"name (string) name resulting facet (use pathing, etc.). label (string) label resulting facet. levels (character) vector levels combine within resulting facet. extra (list) extra arguments passed analysis functions applied within resulting facet.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_combo_facet.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add a combination facet in post-processing — add_combo_facet","text":"function can used within post argument make_split_fun().","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_combo_facet.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Add a combination facet in post-processing — add_combo_facet","text":"add_combo_facet, data associated resulting facet data associated facets level levels, row-bound together. particular, means levels overlapping, data appears duplicated.","code":""},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/reference/add_combo_facet.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Add a combination facet in post-processing — add_combo_facet","text":"","code":"mysplfun <- make_split_fun(post = list( add_combo_facet(\"A_B\", label = \"Arms A+B\", levels = c(\"A: Drug X\", \"B: Placebo\") ), add_overall_facet(\"ALL\", label = \"All Arms\") )) lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\", split_fun = mysplfun) %>% analyze(\"AGE\") tbl <- build_table(lyt, DM)"},{"path":"https://insightsengineering.github.io/rtables/reference/add_existing_table.html","id":null,"dir":"Reference","previous_headings":"","what":"Add an already calculated table to the layout — add_existing_table","title":"Add an already calculated table to the layout — add_existing_table","text":"Add already calculated table layout","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_existing_table.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add an already calculated table to the layout — add_existing_table","text":"","code":"add_existing_table(lyt, tt, indent_mod = 0)"},{"path":"https://insightsengineering.github.io/rtables/reference/add_existing_table.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add an already calculated table to the layout — add_existing_table","text":"lyt (PreDataTableLayouts) layout object pre-data used tabulation. tt (TableTree related class) TableTree object representing populated table. indent_mod (numeric) modifier default indent position structure created function (subtable, content table, row) structure's children. Defaults 0, corresponds unmodified default behavior.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_existing_table.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add an already calculated table to the layout — add_existing_table","text":"PreDataTableLayouts object suitable passing layouting functions, build_table().","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_existing_table.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Add an already calculated table to the layout — add_existing_table","text":"Gabriel Becker","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_existing_table.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Add an already calculated table to the layout — add_existing_table","text":"","code":"lyt1 <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(\"AGE\", afun = mean, format = \"xx.xx\") tbl1 <- build_table(lyt1, DM) tbl1 #> A: Drug X B: Placebo C: Combination #> —————————————————————————————————————————————— #> mean 34.91 33.02 34.57 lyt2 <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(\"AGE\", afun = sd, format = \"xx.xx\") %>% add_existing_table(tbl1) tbl2 <- build_table(lyt2, DM) tbl2 #> A: Drug X B: Placebo C: Combination #> —————————————————————————————————————————————— #> sd 7.79 6.34 6.50 #> mean 34.91 33.02 34.57 table_structure(tbl2) #> [TableTree] root #> [ElementaryTable] AGE (1 x 3) #> [ElementaryTable] AGE (1 x 3) row_paths_summary(tbl2) #> rowname node_class path #> ———————————————————————————————————————— #> sd DataRow root, AGE, sd #> mean DataRow root, AGE, mean"},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_col.html","id":null,"dir":"Reference","previous_headings":"","what":"Add overall column — add_overall_col","title":"Add overall column — add_overall_col","text":"function add overall column top level splitting, within existing column splits. See add_overall_level() recommended way add overall columns generally within existing splits.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_col.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add overall column — add_overall_col","text":"","code":"add_overall_col(lyt, label)"},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_col.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add overall column — add_overall_col","text":"lyt (PreDataTableLayouts) layout object pre-data used tabulation. label (string) label (confused name) object/structure.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_col.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add overall column — add_overall_col","text":"PreDataTableLayouts object suitable passing layouting functions, build_table().","code":""},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_col.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Add overall column — add_overall_col","text":"","code":"lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% add_overall_col(\"All Patients\") %>% analyze(\"AGE\") lyt #> A Pre-data Table Layout #> #> Column-Split Structure: #> ARM (lvls) #> (all obs) #> #> Row-Split Structure: #> AGE (** analysis **) #> tbl <- build_table(lyt, DM) tbl #> A: Drug X B: Placebo C: Combination All Patients #> ————————————————————————————————————————————————————————————— #> Mean 34.91 33.02 34.57 34.22"},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_level.html","id":null,"dir":"Reference","previous_headings":"","what":"Add overall or combination levels to split groups — add_overall_level","title":"Add overall or combination levels to split groups — add_overall_level","text":"add_overall_level split function adds global level current levels split. Similarly, add_combo_df uses user-provided data.frame define combine levels added. need single overall column, splits, please check add_overall_col(). Consider also defining custom split function need flexibility (see custom_split_funs).","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_level.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add overall or combination levels to split groups — add_overall_level","text":"","code":"add_overall_level( valname = \"Overall\", label = valname, extra_args = list(), first = TRUE, trim = FALSE ) select_all_levels add_combo_levels(combosdf, trim = FALSE, first = FALSE, keep_levels = NULL)"},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_level.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Add overall or combination levels to split groups — add_overall_level","text":"object class AllLevelsSentinel length 0.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_level.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add overall or combination levels to split groups — add_overall_level","text":"valname (string) value assigned implicit -observations split level. Defaults \"Overall\". label (string) label (confused name) object/structure. extra_args (list) extra arguments passed tabulation function. Element position list corresponds children split. Named elements child-specific lists ignored match formal argument tabulation function. first (flag) whether implicit level appear first (TRUE) last (FALSE). Defaults TRUE. trim (flag) whether splits corresponding 0 observations kept tabulating. combosdf (data.frame tbl_df) data frame columns valname, label, levelcombo, exargs. levelcombo exargs list columns. Passing select_all_levels object value comblevels column indicates overall/-observations level created. keep_levels (character NULL) non-NULL, levels retain across combination individual levels.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_level.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add overall or combination levels to split groups — add_overall_level","text":"splitting function (splfun) adds changes levels split.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_level.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Add overall or combination levels to split groups — add_overall_level","text":"Analysis summary functions order matters never used within tabulation framework.","code":""},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/reference/add_overall_level.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Add overall or combination levels to split groups — add_overall_level","text":"","code":"lyt <- basic_table() %>% split_cols_by(\"ARM\", split_fun = add_overall_level(\"All Patients\", first = FALSE )) %>% analyze(\"AGE\") tbl <- build_table(lyt, DM) tbl #> A: Drug X B: Placebo C: Combination All Patients #> ————————————————————————————————————————————————————————————— #> Mean 34.91 33.02 34.57 34.22 lyt2 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_rows_by(\"RACE\", split_fun = add_overall_level(\"All Ethnicities\") ) %>% summarize_row_groups(label_fstr = \"%s (n)\") %>% analyze(\"AGE\") lyt2 #> A Pre-data Table Layout #> #> Column-Split Structure: #> ARM (lvls) #> #> Row-Split Structure: #> RACE (lvls) -> AGE (** analysis **) #> tbl2 <- build_table(lyt2, DM) tbl2 #> A: Drug X B: Placebo C: Combination #> ———————————————————————————————————————————————————————————————————————————————————————————— #> All Ethnicities (n) 121 (100.0%) 106 (100.0%) 129 (100.0%) #> Mean 34.91 33.02 34.57 #> ASIAN (n) 79 (65.3%) 68 (64.2%) 84 (65.1%) #> Mean 34.20 32.68 34.63 #> BLACK OR AFRICAN AMERICAN (n) 28 (23.1%) 24 (22.6%) 27 (20.9%) #> Mean 34.68 31.71 34.00 #> WHITE (n) 14 (11.6%) 14 (13.2%) 18 (14.0%) #> Mean 39.36 36.93 35.11 #> AMERICAN INDIAN OR ALASKA NATIVE (n) 0 (0.0%) 0 (0.0%) 0 (0.0%) #> Mean NA NA NA #> MULTIPLE (n) 0 (0.0%) 0 (0.0%) 0 (0.0%) #> Mean NA NA NA #> NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER (n) 0 (0.0%) 0 (0.0%) 0 (0.0%) #> Mean NA NA NA #> OTHER (n) 0 (0.0%) 0 (0.0%) 0 (0.0%) #> Mean NA NA NA #> UNKNOWN (n) 0 (0.0%) 0 (0.0%) 0 (0.0%) #> Mean NA NA NA library(tibble) combodf <- tribble( ~valname, ~label, ~levelcombo, ~exargs, \"A_B\", \"Arms A+B\", c(\"A: Drug X\", \"B: Placebo\"), list(), \"A_C\", \"Arms A+C\", c(\"A: Drug X\", \"C: Combination\"), list() ) lyt <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\", split_fun = add_combo_levels(combodf)) %>% analyze(\"AGE\") tbl <- build_table(lyt, DM) tbl #> A: Drug X B: Placebo C: Combination Arms A+B Arms A+C #> (N=121) (N=106) (N=129) (N=227) (N=250) #> ———————————————————————————————————————————————————————————————————— #> Mean 34.91 33.02 34.57 34.03 34.73 lyt1 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\", split_fun = add_combo_levels(combodf, keep_levels = c( \"A_B\", \"A_C\" ) ) ) %>% analyze(\"AGE\") tbl1 <- build_table(lyt1, DM) tbl1 #> Arms A+B Arms A+C #> (N=227) (N=250) #> —————————————————————————— #> Mean 34.03 34.73 smallerDM <- droplevels(subset(DM, SEX %in% c(\"M\", \"F\") & grepl(\"^(A|B)\", ARM))) lyt2 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\", split_fun = add_combo_levels(combodf[1, ])) %>% split_cols_by(\"SEX\", split_fun = add_overall_level(\"SEX_ALL\", \"All Genders\") ) %>% analyze(\"AGE\") lyt3 <- basic_table(show_colcounts = TRUE) %>% split_cols_by(\"ARM\", split_fun = add_combo_levels(combodf)) %>% split_rows_by(\"SEX\", split_fun = add_overall_level(\"SEX_ALL\", \"All Genders\") ) %>% summarize_row_groups() %>% analyze(\"AGE\") tbl3 <- build_table(lyt3, smallerDM) tbl3 #> A: Drug X B: Placebo Arms A+B Arms A+C #> (N=121) (N=106) (N=227) (N=121) #> ——————————————————————————————————————————————————————————————————————— #> All Genders 121 (100.0%) 106 (100.0%) 227 (100.0%) 121 (100.0%) #> Mean 34.91 33.02 34.03 34.91 #> F 70 (57.9%) 56 (52.8%) 126 (55.5%) 70 (57.9%) #> Mean 33.71 33.84 33.77 33.71 #> M 51 (42.1%) 50 (47.2%) 101 (44.5%) 51 (42.1%) #> Mean 36.55 32.10 34.35 36.55"},{"path":"https://insightsengineering.github.io/rtables/reference/additional_fun_params.html","id":null,"dir":"Reference","previous_headings":"","what":"Additional parameters within analysis and content functions (afun/cfun) — additional_fun_params","title":"Additional parameters within analysis and content functions (afun/cfun) — additional_fun_params","text":"possible add specific parameters afun cfun, analyze() summarize_row_groups(), respectively. parameters grant access relevant information like row split structure (see spl_context) predefined baseline (.ref_group).","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/additional_fun_params.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Additional parameters within analysis and content functions (afun/cfun) — additional_fun_params","text":"list describe parameters can added custom analysis function : .N_col Column-wise N (column count) full column tabulated within. .N_total Overall N (observation count, defined sum column counts) tabulation. .N_row Row-wise N (row group count) group observations analyzed (.e. column-based subsetting). .df_row data.frame observations row group analyzed (.e. column-based subsetting). .var Variable analyzed. .ref_group data.frame vector subset corresponding ref_group column including subsetting defined row-splitting. required/meaningful ref_group column defined. .ref_full data.frame vector subset corresponding ref_group column without subsetting defined row-splitting. required/meaningful ref_group column defined. .in_ref_col Boolean indicating calculation done cells within reference column. .spl_context data.frame row gives information previous 'ancestor' split state. See spl_context. .alt_df_row data.frame, .e. alt_count_df row splitting. can used .all_col_exprs .spl_context information retrieve current faceting, alt_count_df. can empty table entries filtered . .alt_df data.frame, .alt_df_row filtered columns expression. data present faceting main data df. also filters NAs related parameters set (e.g. inclNAs analyze()). Similarly .alt_df_row, can empty table entries filtered . .all_col_exprs List expressions. represents different column splitting. .all_col_counts Vector integers. represents global count column. differs alt_counts_df used (see build_table()).","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/additional_fun_params.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Additional parameters within analysis and content functions (afun/cfun) — additional_fun_params","text":"formals specified incorrectly present tabulation machinery, treated missing. example, .ref_group missing baseline previously defined data splitting (via ref_group parameters , e.g., split_rows_by()). Similarly, alt_counts_df provided build_table(), .alt_df_row .alt_df present.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze.html","id":null,"dir":"Reference","previous_headings":"","what":"Generate rows analyzing variables across columns — analyze","title":"Generate rows analyzing variables across columns — analyze","text":"Adding analyzed variables table layout defines primary tabulation performed. adding calls analyze /analyze_colvars() layout pipeline. adding splitting, tabulation occur current/next level nesting default.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Generate rows analyzing variables across columns — analyze","text":"","code":"analyze( lyt, vars, afun = simple_analysis, var_labels = vars, table_names = vars, format = NULL, na_str = NA_character_, nested = TRUE, inclNAs = FALSE, extra_args = list(), show_labels = c(\"default\", \"visible\", \"hidden\"), indent_mod = 0L, section_div = NA_character_ )"},{"path":"https://insightsengineering.github.io/rtables/reference/analyze.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Generate rows analyzing variables across columns — analyze","text":"lyt (PreDataTableLayouts) layout object pre-data used tabulation. vars (character) vector variable names. afun (function) analysis function. Must accept x df first parameter. Can optionally take parameters populated tabulation framework. See Details analyze(). var_labels (character) vector labels one variables. table_names (character) names tables representing atomic analysis. Defaults var. format (string, function, list) format associated split. Formats can declared via strings (\"xx.x\") function. cases analyze calls, can character vectors lists functions. See formatters::list_valid_format_labels() list available format strings. na_str (string) string displayed value x missing. Defaults \"NA\". nested (logical) whether layout instruction applied within existing layout structure possible (TRUE, default) new top-level element (FALSE). Ignored nest split underneath analyses, allowed. inclNAs (logical) whether NA observations var variable(s) included performing analysis. Defaults FALSE. extra_args (list) extra arguments passed tabulation function. Element position list corresponds children split. Named elements child-specific lists ignored match formal argument tabulation function. show_labels (string) whether variable labels corresponding variable(s) vars visible resulting table. indent_mod (numeric) modifier default indent position structure created function (subtable, content table, row) structure's children. Defaults 0, corresponds unmodified default behavior. section_div (string) string repeated section divider group defined split instruction, NA_character_ (default) section divider.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Generate rows analyzing variables across columns — analyze","text":"PreDataTableLayouts object suitable passing layouting functions, build_table().","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Generate rows analyzing variables across columns — analyze","text":"non-NULL, format used specify formats generated rows, can character vector, function, list functions. repped number rows calculated tabulation process, overridden formats specified within rcell calls afun. analysis function (afun) take first parameter either x df. Whichever function accepts change behavior tabulation performed follows: afun's first parameter x, receive corresponding subset vector data relevant column (var ) raw data used build table. afun's first parameter df, receive corresponding subset data frame (.e. columns) raw data tabulated. addition differentiation first argument, analysis function can optionally accept number parameters , present formals, passed function tabulation machinery. listed described additional_fun_params.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Generate rows analyzing variables across columns — analyze","text":"None arguments described Details section can overridden via extra_args calling make_afun(). .N_col .N_total can overridden via col_counts argument build_table(). Alternative values others must calculated within afun based combination extra arguments unmodified values provided tabulation framework.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Generate rows analyzing variables across columns — analyze","text":"Gabriel Becker","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Generate rows analyzing variables across columns — analyze","text":"","code":"lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% analyze(\"AGE\", afun = list_wrap_x(summary), format = \"xx.xx\") lyt #> A Pre-data Table Layout #> #> Column-Split Structure: #> ARM (lvls) #> #> Row-Split Structure: #> AGE (** analysis **) #> tbl <- build_table(lyt, DM) tbl #> A: Drug X B: Placebo C: Combination #> ————————————————————————————————————————————————— #> Min. 20.00 21.00 22.00 #> 1st Qu. 29.00 29.00 30.00 #> Median 33.00 32.00 33.00 #> Mean 34.91 33.02 34.57 #> 3rd Qu. 39.00 37.00 38.00 #> Max. 60.00 55.00 53.00 lyt2 <- basic_table() %>% split_cols_by(\"Species\") %>% analyze(head(names(iris), -1), afun = function(x) { list( \"mean / sd\" = rcell(c(mean(x), sd(x)), format = \"xx.xx (xx.xx)\"), \"range\" = rcell(diff(range(x)), format = \"xx.xx\") ) }) lyt2 #> A Pre-data Table Layout #> #> Column-Split Structure: #> Species (lvls) #> #> Row-Split Structure: #> Sepal.Length:Sepal.Width:Petal.Length:Petal.Width (** multivar analysis **) #> tbl2 <- build_table(lyt2, iris) tbl2 #> setosa versicolor virginica #> —————————————————————————————————————————————————————— #> Sepal.Length #> mean / sd 5.01 (0.35) 5.94 (0.52) 6.59 (0.64) #> range 1.50 2.10 3.00 #> Sepal.Width #> mean / sd 3.43 (0.38) 2.77 (0.31) 2.97 (0.32) #> range 2.10 1.40 1.60 #> Petal.Length #> mean / sd 1.46 (0.17) 4.26 (0.47) 5.55 (0.55) #> range 0.90 2.10 2.40 #> Petal.Width #> mean / sd 0.25 (0.11) 1.33 (0.20) 2.03 (0.27) #> range 0.50 0.80 1.10"},{"path":"https://insightsengineering.github.io/rtables/reference/analyze_colvars.html","id":null,"dir":"Reference","previous_headings":"","what":"Generate rows analyzing different variables across columns — analyze_colvars","title":"Generate rows analyzing different variables across columns — analyze_colvars","text":"Generate rows analyzing different variables across columns","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze_colvars.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Generate rows analyzing different variables across columns — analyze_colvars","text":"","code":"analyze_colvars( lyt, afun, format = NULL, na_str = NA_character_, nested = TRUE, extra_args = list(), indent_mod = 0L, inclNAs = FALSE )"},{"path":"https://insightsengineering.github.io/rtables/reference/analyze_colvars.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Generate rows analyzing different variables across columns — analyze_colvars","text":"lyt (PreDataTableLayouts) layout object pre-data used tabulation. afun (function list) function(s) used calculate values column. list repped needed matched position columns tabulation. functions accepts parameters analyze() like afun format. information see additional_fun_params. format (string, function, list) format associated split. Formats can declared via strings (\"xx.x\") function. cases analyze calls, can character vectors lists functions. See formatters::list_valid_format_labels() list available format strings. na_str (string) string displayed value x missing. Defaults \"NA\". nested (logical) whether layout instruction applied within existing layout structure possible (TRUE, default) new top-level element (FALSE). Ignored nest split underneath analyses, allowed. extra_args (list) extra arguments passed tabulation function. Element position list corresponds children split. Named elements child-specific lists ignored match formal argument tabulation function. indent_mod (numeric) modifier default indent position structure created function (subtable, content table, row) structure's children. Defaults 0, corresponds unmodified default behavior. inclNAs (logical) whether NA observations var variable(s) included performing analysis. Defaults FALSE.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze_colvars.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Generate rows analyzing different variables across columns — analyze_colvars","text":"PreDataTableLayouts object suitable passing layouting functions, build_table().","code":""},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/reference/analyze_colvars.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Generate rows analyzing different variables across columns — analyze_colvars","text":"Gabriel Becker","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/analyze_colvars.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Generate rows analyzing different variables across columns — analyze_colvars","text":"","code":"library(dplyr) ANL <- DM %>% mutate(value = rnorm(n()), pctdiff = runif(n())) ## toy example where we take the mean of the first variable and the ## count of >.5 for the second. colfuns <- list( function(x) rcell(mean(x), format = \"xx.x\"), function(x) rcell(sum(x > .5), format = \"xx\") ) lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_cols_by_multivar(c(\"value\", \"pctdiff\")) %>% split_rows_by(\"RACE\", split_label = \"ethnicity\", split_fun = drop_split_levels ) %>% summarize_row_groups() %>% analyze_colvars(afun = colfuns) lyt #> A Pre-data Table Layout #> #> Column-Split Structure: #> ARM (lvls) -> value:pctdiff (vars) #> #> Row-Split Structure: #> RACE (lvls) -> NA (** col-var analysis **) #> tbl <- build_table(lyt, ANL) tbl #> A: Drug X B: Placebo C: Combination #> value pctdiff value pctdiff value pctdiff #> ——————————————————————————————————————————————————————————————————————————————————————————————————————— #> ASIAN 79 (65.3%) 79 (65.3%) 68 (64.2%) 68 (64.2%) 84 (65.1%) 84 (65.1%) #> 0.0 32 0.2 28 0.1 42 #> BLACK OR AFRICAN AMERICAN 28 (23.1%) 28 (23.1%) 24 (22.6%) 24 (22.6%) 27 (20.9%) 27 (20.9%) #> -0.0 15 0.1 9 0.1 15 #> WHITE 14 (11.6%) 14 (11.6%) 14 (13.2%) 14 (13.2%) 18 (14.0%) 18 (14.0%) #> -0.2 10 0.3 7 -0.3 12 lyt2 <- basic_table() %>% split_cols_by(\"ARM\") %>% split_cols_by_multivar(c(\"value\", \"pctdiff\"), varlabels = c(\"Measurement\", \"Pct Diff\") ) %>% split_rows_by(\"RACE\", split_label = \"ethnicity\", split_fun = drop_split_levels ) %>% summarize_row_groups() %>% analyze_colvars(afun = mean, format = \"xx.xx\") tbl2 <- build_table(lyt2, ANL) tbl2 #> A: Drug X B: Placebo C: Combination #> Measurement Pct Diff Measurement Pct Diff Measurement Pct Diff #> —————————————————————————————————————————————————————————————————————————————————————————————————————————— #> ASIAN 79 (65.3%) 79 (65.3%) 68 (64.2%) 68 (64.2%) 84 (65.1%) 84 (65.1%) #> mean 0.04 0.45 0.19 0.44 0.14 0.51 #> BLACK OR AFRICAN AMERICAN 28 (23.1%) 28 (23.1%) 24 (22.6%) 24 (22.6%) 27 (20.9%) 27 (20.9%) #> mean -0.04 0.53 0.13 0.46 0.06 0.57 #> WHITE 14 (11.6%) 14 (11.6%) 14 (13.2%) 14 (13.2%) 18 (14.0%) 18 (14.0%) #> mean -0.19 0.61 0.33 0.48 -0.27 0.55"},{"path":"https://insightsengineering.github.io/rtables/reference/append_topleft.html","id":null,"dir":"Reference","previous_headings":"","what":"Append a description to the 'top-left' materials for the layout — append_topleft","title":"Append a description to the 'top-left' materials for the layout — append_topleft","text":"function adds newlines current set \"top-left materials\".","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/append_topleft.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Append a description to the 'top-left' materials for the layout — append_topleft","text":"","code":"append_topleft(lyt, newlines)"},{"path":"https://insightsengineering.github.io/rtables/reference/append_topleft.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Append a description to the 'top-left' materials for the layout — append_topleft","text":"lyt (PreDataTableLayouts) layout object pre-data used tabulation. newlines (character) new line(s) added materials.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/append_topleft.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Append a description to the 'top-left' materials for the layout — append_topleft","text":"PreDataTableLayouts object suitable passing layouting functions, build_table().","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/append_topleft.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Append a description to the 'top-left' materials for the layout — append_topleft","text":"Adds newlines set strings representing 'top-left' materials declared layout (content displayed left column labels resulting tables printed). Top-left material strings stored displayed exactly , structure indenting applied either added displayed.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/append_topleft.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Append a description to the 'top-left' materials for the layout — append_topleft","text":"Currently, construction layout called makes difference, independent actual splitting keywords. may change future. function experimental, name details behavior subject change future versions.","code":""},{"path":[]},{"path":"https://insightsengineering.github.io/rtables/reference/append_topleft.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Append a description to the 'top-left' materials for the layout — append_topleft","text":"","code":"library(dplyr) DM2 <- DM %>% mutate(RACE = factor(RACE), SEX = factor(SEX)) lyt <- basic_table() %>% split_cols_by(\"ARM\") %>% split_cols_by(\"SEX\") %>% split_rows_by(\"RACE\") %>% append_topleft(\"Ethnicity\") %>% analyze(\"AGE\") %>% append_topleft(\" Age\") tbl <- build_table(lyt, DM2) tbl #> Ethnicity A: Drug X B: Placebo C: Combination #> Age F M F M F M #> ————————————————————————————————————————————————————————————————————————————— #> ASIAN #> Mean 33.55 35.03 34.00 31.10 34.90 34.39 #> BLACK OR AFRICAN AMERICAN #> Mean 33.17 37.40 30.58 32.83 33.85 34.14 #> WHITE #> Mean 35.88 44.00 38.57 35.29 36.50 34.00"},{"path":"https://insightsengineering.github.io/rtables/reference/as_html.html","id":null,"dir":"Reference","previous_headings":"","what":"Convert an rtable object to a shiny.tag HTML object — as_html","title":"Convert an rtable object to a shiny.tag HTML object — as_html","text":"returned HTML object can immediately used shiny rmarkdown.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/as_html.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Convert an rtable object to a shiny.tag HTML object — as_html","text":"","code":"as_html( x, width = NULL, class_table = \"table table-condensed table-hover\", class_tr = NULL, class_th = NULL, link_label = NULL, bold = c(\"header\"), header_sep_line = TRUE, no_spaces_between_cells = FALSE, expand_newlines = FALSE )"},{"path":"https://insightsengineering.github.io/rtables/reference/as_html.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Convert an rtable object to a shiny.tag HTML object — as_html","text":"x (VTableTree) TableTree object. width (character) string indicate desired width table. Common input formats include percentage viewer window width (e.g. \"100%\") distance value (e.g. \"300px\"). Defaults NULL. class_table (character) class table tag. class_tr (character) class tr tag. class_th (character) class th tag. link_label (character) link anchor label (including tab: prefix) table. bold (character) elements table output bold. Options \"main_title\", \"subtitles\", \"header\", \"row_names\", \"label_rows\", \"content_rows\" (includes non-label rows). Defaults \"header\". header_sep_line (flag) whether black line printed table header. Defaults TRUE. no_spaces_between_cells (flag) whether spaces table cells collapsed. Defaults FALSE. expand_newlines (flag) Defaults FALSE, relying html output solve newline characters (\\n). keeps structure cells may depend output device.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/as_html.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Convert an rtable object to a shiny.tag HTML object — as_html","text":"shiny.tag object representing x HTML.","code":""},{"path":"https://insightsengineering.github.io/rtables/reference/as_html.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Convert an rtable object to a shiny.tag HTML object — as_html","text":"","code":"tbl <- rtable( header = LETTERS[1:3], format = \"xx\", rrow(\"r1\", 1, 2, 3), rrow(\"r2\", 4, 3, 2, indent = 1), rrow(\"r3\", indent = 2) ) as_html(tbl) #>