Skip to content

Add tbl_ancova() for ANCOVA tables with treatment-vs-control contrasts#232

Open
Melkiades wants to merge 20 commits into
mainfrom
6_tbl_ancova@main
Open

Add tbl_ancova() for ANCOVA tables with treatment-vs-control contrasts#232
Melkiades wants to merge 20 commits into
mainfrom
6_tbl_ancova@main

Conversation

@Melkiades
Copy link
Copy Markdown
Contributor

What changes are proposed in this pull request?

The function fits a model via cardx::construct_model(), computes LS means with emmeans::emmeans(), and obtains contrasts with emmeans::contrast(method = "trt.vs.ctrl"). Each non-reference group is compared to the reference group only (not all pairwise). The output is a gtsummary table showing n, adjusted mean, difference in adjusted means, CI, and p-value per treatment group.

Key design decisions:

  • Uses trt.vs.ctrl instead of pairwise contrasts to match the standard ANCOVA table layout where each treatment is compared to a single control group.
  • Accepts a ref_group argument to specify the control arm.
  • Accepts a denominator argument for header Ns from a subject-level dataset.
  • Accepts conf.level for configurable CI width (default 95%).
  • Accepts method, method.args, package for flexible model specification.

Reference GitHub issue associated with pull request. closes #6


Pre-review Checklist (if item does not apply, mark is as complete)

  • All GitHub Action workflows pass with a ✅
  • PR branch has pulled the most recent updates from master branch: usethis::pr_merge_main()
  • If a bug was fixed, a unit test was added.
  • Code coverage is suitable for any new functions/features (generally, 100% coverage for new code): devtools::test_coverage()
  • Request a reviewer

Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R
Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R
Comment thread R/tbl_ancova.R
Comment thread R/tbl_ancova.R
Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R
Comment thread R/tbl_ancova.R
Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R
Comment thread R/tbl_ancova.R Outdated
Comment thread tests/testthat/test-tbl_ancova.R
Comment thread tests/testthat/test-tbl_ancova.R Outdated
Comment thread tests/testthat/test-tbl_ancova.R
Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R
Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R Outdated
@Melkiades Melkiades marked this pull request as ready for review May 10, 2026 15:35
@Melkiades Melkiades force-pushed the 6_tbl_ancova@main branch from 16d7fc0 to 6f345f9 Compare May 10, 2026 15:38
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

Unit Tests Summary

  1 files  242 suites   3m 11s ⏱️
242 tests 242 ✅ 0 💤 0 ❌
724 runs  724 ✅ 0 💤 0 ❌

Results for commit fc1ce0f.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

Unit Test Performance Difference

Test Suite $Status$ Time on main $±Time$ $±Tests$ $±Skipped$ $±Failures$ $±Errors$
tbl_ancova 👶 $+0.00$ $+5$ $0$ $0$ $0$
Additional test case details
Test Suite $Status$ Time on main $±Time$ Test Case
tbl_ancova 👶 $+0.00$ tbl_ancova_denominator_headers_align_when_ref_group_is_not_alphabetically_first
tbl_ancova 👶 $+0.00$ tbl_ancova_errors_on_invalid_ref_group
tbl_ancova 👶 $+0.00$ tbl_ancova_errors_on_non_string_label
tbl_ancova 👶 $+0.01$ tbl_ancova_works_with_Dunnett_adjustment
tbl_ancova 👶 $+0.00$ tbl_ancova_works_with_conf.level_0.90
tbl_ancova 👶 $+0.01$ tbl_ancova_works_with_custom_label
tbl_ancova 👶 $+3.15$ tbl_ancova_works_with_default_settings
tbl_ancova 👶 $+0.01$ tbl_ancova_works_with_denominator
tbl_ancova 👶 $+0.01$ tbl_ancova_works_without_covariates
tbl_baseline_chg 💚 $14.95$ $-4.50$ tbl_baseline_chg_works
tbl_hierarchical_rate_and_count 💔 $11.38$ $+4.06$ tbl_hierarchical_rate_and_count_works
tbl_hierarchical_rate_by_grade 💚 $22.43$ $-3.93$ tbl_hierarchical_rate_by_grade_works
tbl_roche_subgroups 💔 $2.40$ $+3.86$ tbl_roche_subgroups_time_to_event_NULL_works
tbl_roche_summary 💚 $4.89$ $-3.77$ tbl_roche_summary_works
tbl_shift 💔 $5.68$ $+4.55$ tbl_shift_strata_location_
tbl_with_pools 💚 $13.80$ $-4.91$ tbl_with_pools_validates_inputs_correctly

Results for commit a7bac5e

♻️ This comment has been updated with latest results.

Comment thread R/tbl_ancova.R Outdated
Comment thread R/tbl_ancova.R
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

badge

Code Coverage Summary

Filename                                 Stmts    Miss  Cover    Missing
-------------------------------------  -------  ------  -------  ------------------------------------------------------------------------------------------------
R/add_blank_rows.R                          63       0  100.00%
R/add_difference_row.R                     101       0  100.00%
R/add_forest_utils.R                        97      10  89.69%   76-79, 94-100
R/add_forest.R                             139       0  100.00%
R/add_hierarchical_count_row.R              33       0  100.00%
R/adjust_stat_columns_wrap.R                29       1  96.55%   53
R/annotate_gg_km.R                         135       0  100.00%
R/annotate_gg_pkc.R                         92       0  100.00%
R/annotate_gg.R                             81       0  100.00%
R/ard_tabulate_abnormal_by_baseline.R       65       0  100.00%
R/crane-package.R                            2       2  0.00%    26-27
R/deprecated.R                              21      21  0.00%    15-51
R/df_add_poolings.R                         41       0  100.00%
R/get_cox_pairwise_df.R                     96       6  93.75%   226-231
R/gg_km_utils.R                             35      14  60.00%   18-35
R/gg_km.R                                  143      37  74.13%   54-57, 74, 101, 175-180, 183-186, 196-198, 203-204, 238-240, 247-250, 254, 265-269, 282, 284-286
R/gg_lineplot.R                             94       0  100.00%
R/gg_mmrm_lineplot.R                       102       1  99.02%   106
R/gg_pkc_lineplot.R                         98       0  100.00%
R/gg_utils.R                               221       0  100.00%
R/label_roche.R                             72       0  100.00%
R/modify_header_rm_md.R                     18       2  88.89%   35-36
R/modify_zero_recode.R                      20       1  95.00%   64
R/reverse_difference_ci.R                   33       0  100.00%
R/tbl_ancova.R                             182       1  99.45%   338
R/tbl_baseline_chg.R                       188       0  100.00%
R/tbl_coxph.R                               90       1  98.89%   219
R/tbl_hierarchical_incidence_rate.R        209       0  100.00%
R/tbl_hierarchical_rate_and_count.R        339      13  96.17%   343, 425, 446-456
R/tbl_hierarchical_rate_by_grade.R         317       3  99.05%   169-171
R/tbl_listing.R                             35       0  100.00%
R/tbl_mmrm.R                               254       1  99.61%   393
R/tbl_null_report.R                          9       0  100.00%
R/tbl_rmpt.R                               157      12  92.36%   297-302, 314-319
R/tbl_roche_subgroups.R                    155       0  100.00%
R/tbl_roche_summary.R                       64       0  100.00%
R/tbl_shift.R                              116       0  100.00%
R/tbl_survfit_quantiles.R                  132       1  99.24%   295
R/tbl_survfit_times.R                       92       0  100.00%
R/tbl_with_pools.R                          64       0  100.00%
R/theme_gtsummary_roche.R                   84       1  98.81%   61
R/utils.R                                   36       0  100.00%
TOTAL                                     4354     128  97.06%

Diff against main

Filename          Stmts    Miss  Cover
--------------  -------  ------  -------
R/tbl_ancova.R     +182      +1  +99.45%
TOTAL              +182      +1  +0.10%

Results for commit: fc1ce0f

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

@Melkiades Melkiades requested a review from chizapoth May 11, 2026 11:16
@insightsengineering insightsengineering deleted a comment from github-actions Bot May 26, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 26, 2026

✅ All contributors have signed the CLA
Posted by the CLA Assistant Lite bot.

@Melkiades
Copy link
Copy Markdown
Contributor Author

Fixed a column-swap bug in tbl_ancova() when the reference group is not alphabetically first (e.g. "B: Placebo" vs "A: Drug X").

Root cause: tbl_ard_summary() assigns stat_1, stat_2, etc. alphabetically by group level. The denominator header logic assumed factor level order (ref first via relevel()). When these orders diverged, headers were written to the wrong columns — values appeared under incorrect treatment arms.

Fix (commit a86b83e): The denominator header logic now reads the actual column-to-group mapping from tbl$table_styling$header instead of assuming positional order. Added a regression test with non-alphabetical arm names and an example showing how to control column order via factor levels on the input data.

@Melkiades Melkiades force-pushed the 6_tbl_ancova@main branch from a86b83e to ec43a1c Compare May 26, 2026 16:32
Melkiades added 20 commits May 26, 2026 16:43
Default is adjust = "none" (unadjusted, matching tern behavior).
Users can specify "dunnett", "bonferroni", etc.
- remove ADaM BDS terminology (crane is open-source)
- change `@examplesIf` to `@examples`, remove `theme_gtsummary_roche()`
- add denominator and Dunnett examples
- add descriptive comments on `.build_ancova_ard` and `.escape_regex`
- add example values in contrast label parsing comment
- simplify `map2` to `map` in `fmt_fun`
- store by, adjust, method attributes on returned object
- use `expect_snapshot` for error test
- add header N verification in denominator test
- add attribute and label checks in Dunnett and no-covariates tests
- replace purrr::map() with standalone map() in tbl_ancova
- wrap strata/by in all_of() in tbl_mmrm to fix tidyselect deprecation
- add ANCOVA, Dunnett's, modelling to WORDLIST
- regenerate tbl_ancova.Rd, add test snapshots
- apply styler formatting
…ygen2 8.0.0

- wrap arm/visit in all_of() in second process_selectors call in tbl_mmrm
- regenerate Rd files with roxygen2 8.0.0 (fixes construct_model xref)
- fix snapshot non-breaking space encoding
…le name

Shows 'Change from Baseline' instead of 'CHG' in the table header row.
Falls back to the variable name if no label attribute exists.
Defaults to the response variable's label attribute. When used inside
tbl_strata(strata = PARAM), pass label = unique(.x$PARAM) so each
sub-table shows the parameter name instead of the variable name.
tbl_ard_summary() assigns stat columns alphabetically by group level,
but the denominator header logic ordered by factor levels (ref first).
When the reference group was not alphabetically first (e.g. 'B: Placebo'
vs 'A: Drug X'), headers were assigned to the wrong columns, making
values appear under incorrect treatment arms.

Fix reads the actual column-to-group mapping from the table styling
instead of assuming factor level order.
@Melkiades Melkiades force-pushed the 6_tbl_ancova@main branch from 2ba6ec2 to fc1ce0f Compare May 26, 2026 16:43
@Melkiades
Copy link
Copy Markdown
Contributor Author

recheck

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New tbl_*() for LS means/ANCOVA

1 participant