From 6eb0b75a221d4beaa488169fcb987a3c6ed2910b Mon Sep 17 00:00:00 2001 From: Daniel Sjoberg Date: Mon, 7 Sep 2026 15:36:27 -0700 Subject: [PATCH 1/5] Print mis-matched rows via the ARD print method; add NEWS and coverage Follow-up to the #605 fix. `compare_ard()` landed before ARDs printed through pillar/tibble (#594), so `print.compare_ard()` coerced with `as.data.frame()` to get scalar list-column values to show. `card_list_shaft()` does that now, and the frames are still `card` objects -- dplyr's default `dplyr_reconstruct` preserves the class through the `select()`/`anti_join()` in `.compare_rows()`. Dropping the coercion in the two mis-matched row blocks bounds the output (10 rows plus a `# i N more rows` footer) and renders `group1_level`/`variable_level` properly. The comparison block keeps `as.data.frame()` + `head(n = 10)`: its `difference` column holds `all.equal()` messages that pillar would truncate with `~` rather than wrap. Also adds the NEWS.md entries, a snapshot covering both mis-matched row blocks being non-empty at once, a snapshot showing a long block truncating, and an `expect_output()` assertion outside of any snapshot so that regenerating snapshots cannot quietly re-accept the missing output from #605. Co-Authored-By: Claude Opus 5 --- NEWS.md | 6 ++ R/print.R | 4 +- tests/testthat/_snaps/print.md | 149 ++++++++++++++++++++++++++++----- tests/testthat/test-print.R | 64 ++++++++++++++ 4 files changed, 201 insertions(+), 22 deletions(-) diff --git a/NEWS.md b/NEWS.md index f40bd8e4a..95a927a87 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # cards 0.9.0.9000 +## Bug Fixes + +* Fixed a bug in `print.compare_ard()` where the rows present in `x` but not in `y` were announced and then not printed. (#605, @malanbos) + +* The mis-matched row blocks of `print.compare_ard()` now print through the ARD print method rather than being coerced with `as.data.frame()`, so scalar list-column values (e.g. `group1_level`, `variable_level`) are shown and long blocks are truncated with a row count in the footer. (#605) + # cards 0.9.0 ## Performance diff --git a/R/print.R b/R/print.R index 4b6403410..e3308a6b9 100644 --- a/R/print.R +++ b/R/print.R @@ -182,13 +182,13 @@ print.compare_ard <- function(x, ...) { cli::cli_alert_success("No rows in {.arg x} that do not appear in {.arg y}.") } else { cli::cli_h3("Rows in {.arg x} that do not appear in {.arg y}.") - as.data.frame(x$rows_in_x_not_y) |> print() + print(x$rows_in_x_not_y) } if (nrow(x$rows_in_y_not_x) == 0L) { cli::cli_alert_success("No rows in {.arg y} that do not appear in {.arg x}.") } else { cli::cli_h3("Rows in {.arg y} that do not appear in {.arg x}.") - as.data.frame(x$rows_in_y_not_x) |> print() + print(x$rows_in_y_not_x) } # print comparison results --------------------------------------------------- diff --git a/tests/testthat/_snaps/print.md b/tests/testthat/_snaps/print.md index 612ce604d..afc9a4234 100644 --- a/tests/testthat/_snaps/print.md +++ b/tests/testthat/_snaps/print.md @@ -193,16 +193,18 @@ -- Rows in `x` that do not appear in `y`. Output - group1 group1_level variable variable_level stat_name - 1 ARM Placebo AGEGR1 >80 n - 2 ARM Placebo AGEGR1 >80 N - 3 ARM Placebo AGEGR1 >80 p - 4 ARM Xanomeline High Dose AGEGR1 >80 n - 5 ARM Xanomeline High Dose AGEGR1 >80 N - 6 ARM Xanomeline High Dose AGEGR1 >80 p - 7 ARM Xanomeline Low Dose AGEGR1 >80 n - 8 ARM Xanomeline Low Dose AGEGR1 >80 N - 9 ARM Xanomeline Low Dose AGEGR1 >80 p + # An ARD data frame: 9 x 5 + group1 group1_level variable variable_level stat_name + + 1 ARM Placebo AGEGR1 >80 n + 2 ARM Placebo AGEGR1 >80 N + 3 ARM Placebo AGEGR1 >80 p + 4 ARM Xanomeline High Dose AGEGR1 >80 n + 5 ARM Xanomeline High Dose AGEGR1 >80 N + 6 ARM Xanomeline High Dose AGEGR1 >80 p + 7 ARM Xanomeline Low Dose AGEGR1 >80 n + 8 ARM Xanomeline Low Dose AGEGR1 >80 N + 9 ARM Xanomeline Low Dose AGEGR1 >80 p Message v No rows in `y` that do not appear in `x`. @@ -246,16 +248,18 @@ -- Rows in `y` that do not appear in `x`. Output - group1 group1_level variable variable_level stat_name - 1 ARM Placebo AGEGR1 >80 n - 2 ARM Placebo AGEGR1 >80 N - 3 ARM Placebo AGEGR1 >80 p - 4 ARM Xanomeline High Dose AGEGR1 >80 n - 5 ARM Xanomeline High Dose AGEGR1 >80 N - 6 ARM Xanomeline High Dose AGEGR1 >80 p - 7 ARM Xanomeline Low Dose AGEGR1 >80 n - 8 ARM Xanomeline Low Dose AGEGR1 >80 N - 9 ARM Xanomeline Low Dose AGEGR1 >80 p + # An ARD data frame: 9 x 5 + group1 group1_level variable variable_level stat_name + + 1 ARM Placebo AGEGR1 >80 n + 2 ARM Placebo AGEGR1 >80 N + 3 ARM Placebo AGEGR1 >80 p + 4 ARM Xanomeline High Dose AGEGR1 >80 n + 5 ARM Xanomeline High Dose AGEGR1 >80 N + 6 ARM Xanomeline High Dose AGEGR1 >80 p + 7 ARM Xanomeline Low Dose AGEGR1 >80 n + 8 ARM Xanomeline Low Dose AGEGR1 >80 N + 9 ARM Xanomeline Low Dose AGEGR1 >80 p Message -- Comparison Results ---------------------------------------------------------- @@ -285,3 +289,108 @@ 9 84 Mean relative difference: 0.5272727 10 0.5595238 Mean relative difference: 0.3452381 +# print.compare_ard() prints both mis-matched row blocks + + Code + compare_ard(ard_no_high, ard_no_low) + Message + The comparison `keys` are "group1", "group1_level", "variable", "variable_level", and "stat_name". + The comparison columns are "stat_label" and "stat". + + -- Mis-matched Rows ------------------------------------------------------------ + + -- Rows in `x` that do not appear in `y`. + Output + # An ARD data frame: 9 x 5 + group1 group1_level variable variable_level stat_name + + 1 ARM Placebo AGEGR1 <65 n + 2 ARM Placebo AGEGR1 <65 N + 3 ARM Placebo AGEGR1 <65 p + 4 ARM Xanomeline High Dose AGEGR1 <65 n + 5 ARM Xanomeline High Dose AGEGR1 <65 N + 6 ARM Xanomeline High Dose AGEGR1 <65 p + 7 ARM Xanomeline Low Dose AGEGR1 <65 n + 8 ARM Xanomeline Low Dose AGEGR1 <65 N + 9 ARM Xanomeline Low Dose AGEGR1 <65 p + Message + + -- Rows in `y` that do not appear in `x`. + Output + # An ARD data frame: 9 x 5 + group1 group1_level variable variable_level stat_name + + 1 ARM Placebo AGEGR1 >80 n + 2 ARM Placebo AGEGR1 >80 N + 3 ARM Placebo AGEGR1 >80 p + 4 ARM Xanomeline High Dose AGEGR1 >80 n + 5 ARM Xanomeline High Dose AGEGR1 >80 N + 6 ARM Xanomeline High Dose AGEGR1 >80 p + 7 ARM Xanomeline Low Dose AGEGR1 >80 n + 8 ARM Xanomeline Low Dose AGEGR1 >80 N + 9 ARM Xanomeline Low Dose AGEGR1 >80 p + Message + + -- Comparison Results ---------------------------------------------------------- + v No differences found in column "stat_label". + ! Differences found in column "stat" for 6 rows. + Output + group1 group1_level variable variable_level stat_name stat.x + 1 ARM Placebo AGEGR1 65-80 N 56 + 2 ARM Placebo AGEGR1 65-80 p 0.75 + 3 ARM Xanomeline High Dose AGEGR1 65-80 N 66 + 4 ARM Xanomeline High Dose AGEGR1 65-80 p 0.8333333 + 5 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 + 6 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.8545455 + stat.y difference + 1 72 Mean relative difference: 0.2857143 + 2 0.5833333 Mean relative difference: 0.2222222 + 3 73 Mean relative difference: 0.1060606 + 4 0.7534247 Mean relative difference: 0.09589041 + 5 76 Mean relative difference: 0.3818182 + 6 0.6184211 Mean relative difference: 0.2763158 + +# print.compare_ard() truncates long mis-matched row blocks + + Code + compare_ard(ard, ard_two_sites) + Message + The comparison `keys` are "variable", "variable_level", and "stat_name". + The comparison columns are "stat_label" and "stat". + + -- Mis-matched Rows ------------------------------------------------------------ + + -- Rows in `x` that do not appear in `y`. + Output + # An ARD data frame: 45 x 3 + variable variable_level stat_name + + 1 SITEID 702 n + 2 SITEID 702 N + 3 SITEID 702 p + 4 SITEID 704 n + 5 SITEID 704 N + 6 SITEID 704 p + 7 SITEID 705 n + 8 SITEID 705 N + 9 SITEID 705 p + 10 SITEID 706 n + # i 35 more rows + Message + v No rows in `y` that do not appear in `x`. + + -- Comparison Results ---------------------------------------------------------- + v No differences found in column "stat_label". + ! Differences found in column "stat" for 4 rows. + Output + variable variable_level stat_name stat.x stat.y + 1 SITEID 701 N 254 59 + 2 SITEID 701 p 0.1614173 0.6949153 + 3 SITEID 703 N 254 59 + 4 SITEID 703 p 0.07086614 0.3050847 + difference + 1 Mean relative difference: 0.7677165 + 2 Mean relative difference: 3.305085 + 3 Mean relative difference: 0.7677165 + 4 Mean relative difference: 3.305085 + diff --git a/tests/testthat/test-print.R b/tests/testthat/test-print.R index 5e6b87efd..b2bda3764 100644 --- a/tests/testthat/test-print.R +++ b/tests/testthat/test-print.R @@ -88,3 +88,67 @@ test_that("print.compare_ard() works", { compare_ard(ard_subset, ard) ) }) + +test_that("print.compare_ard() prints both mis-matched row blocks", { + # each ARD holds an age group the other does not, so both blocks print + ard_no_high <- + ard_tabulate( + dplyr::filter(ADSL, AGEGR1 != ">80"), + by = "ARM", + variables = "AGEGR1" + ) + ard_no_low <- + ard_tabulate( + dplyr::filter(ADSL, AGEGR1 != "<65"), + by = "ARM", + variables = "AGEGR1" + ) + + expect_snapshot( + compare_ard(ard_no_high, ard_no_low) + ) +}) + +test_that("print.compare_ard() prints the mis-matched rows themselves (#605)", { + ard <- ard_tabulate(ADSL, by = "ARM", variables = "AGEGR1") + ard_subset <- + ard_tabulate( + dplyr::filter(ADSL, AGEGR1 != ">80"), + by = "ARM", + variables = "AGEGR1" + ) + + # the ">80" rows appear in only one of the two ARDs, so they are never part + # of the comparison tables -- seeing ">80" on stdout means the mis-matched + # row block itself printed. `cli` writes to stderr, so it is not captured + # here. Asserted outside of a snapshot so that regenerating the snapshots + # cannot quietly accept the output going missing again. + expect_output( + print(compare_ard(ard, ard_subset)), + ">80", + fixed = TRUE + ) + expect_output( + print(compare_ard(ard_subset, ard)), + ">80", + fixed = TRUE + ) +}) + +test_that("print.compare_ard() truncates long mis-matched row blocks", { + # 17 sites x 3 statistics, of which only two sites survive the filter, so the + # block is far longer than the console can hold and is truncated by the ARD + # print method with the withheld row count in the footer + ard <- ard_tabulate(ADSL, variables = "SITEID") + ard_two_sites <- + ard_tabulate( + dplyr::filter(ADSL, SITEID %in% c("701", "703")), + variables = "SITEID" + ) + + expect_equal(nrow(compare_ard(ard, ard_two_sites)$rows_in_x_not_y), 45L) + + expect_snapshot( + compare_ard(ard, ard_two_sites) + ) +}) From 4389fb8e89aee4d7e2e9fc1aa5fbe919ed38395a Mon Sep 17 00:00:00 2001 From: Daniel Sjoberg Date: Mon, 7 Sep 2026 15:49:37 -0700 Subject: [PATCH 2/5] Widen the console in the print.compare_ard() snapshot tests testthat pins `width` to 80, which splits the ~120-character comparison tables into two column chunks and makes the snapshots hard to read. Setting `withr::local_options(width = 200)` at test scope prints each table in one piece. `expect_snapshot()` does not re-pin `width`, so the option survives. `cli.width` is pinned separately by testthat, so the section rules stay 80 characters wide, and the ARD print method is unaffected -- the mis-matched row blocks are byte-identical. Net effect is 34 fewer snapshot lines, since unchunking drops the repeated row-index columns. The option is deliberately test-only: `withr` is in Suggests, and in a real session `cli` falls back to `getOption("width")`, so widening inside `print.compare_ard()` would stretch the section rules to match. Co-Authored-By: Claude Opus 5 --- tests/testthat/_snaps/print.md | 102 +++++++++++---------------------- tests/testthat/test-print.R | 12 ++++ 2 files changed, 46 insertions(+), 68 deletions(-) diff --git a/tests/testthat/_snaps/print.md b/tests/testthat/_snaps/print.md index afc9a4234..92d552e8d 100644 --- a/tests/testthat/_snaps/print.md +++ b/tests/testthat/_snaps/print.md @@ -212,28 +212,17 @@ v No differences found in column "stat_label". ! Differences found in column "stat" for 12 rows. Output - group1 group1_level variable variable_level stat_name stat.x - 1 ARM Placebo AGEGR1 65-80 N 86 - 2 ARM Placebo AGEGR1 65-80 p 0.4883721 - 3 ARM Placebo AGEGR1 <65 N 86 - 4 ARM Placebo AGEGR1 <65 p 0.1627907 - 5 ARM Xanomeline High Dose AGEGR1 65-80 N 84 - 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.6547619 - 7 ARM Xanomeline High Dose AGEGR1 <65 N 84 - 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.1309524 - 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 84 - 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.5595238 - stat.y difference - 1 56 Mean relative difference: 0.3488372 - 2 0.75 Mean relative difference: 0.5357143 - 3 56 Mean relative difference: 0.3488372 - 4 0.25 Mean relative difference: 0.5357143 - 5 66 Mean relative difference: 0.2142857 - 6 0.8333333 Mean relative difference: 0.2727273 - 7 66 Mean relative difference: 0.2142857 - 8 0.1666667 Mean relative difference: 0.2727273 - 9 55 Mean relative difference: 0.3452381 - 10 0.8545455 Mean relative difference: 0.5272727 + group1 group1_level variable variable_level stat_name stat.x stat.y difference + 1 ARM Placebo AGEGR1 65-80 N 86 56 Mean relative difference: 0.3488372 + 2 ARM Placebo AGEGR1 65-80 p 0.4883721 0.75 Mean relative difference: 0.5357143 + 3 ARM Placebo AGEGR1 <65 N 86 56 Mean relative difference: 0.3488372 + 4 ARM Placebo AGEGR1 <65 p 0.1627907 0.25 Mean relative difference: 0.5357143 + 5 ARM Xanomeline High Dose AGEGR1 65-80 N 84 66 Mean relative difference: 0.2142857 + 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.6547619 0.8333333 Mean relative difference: 0.2727273 + 7 ARM Xanomeline High Dose AGEGR1 <65 N 84 66 Mean relative difference: 0.2142857 + 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.1309524 0.1666667 Mean relative difference: 0.2727273 + 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 84 55 Mean relative difference: 0.3452381 + 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.5595238 0.8545455 Mean relative difference: 0.5272727 --- @@ -266,28 +255,17 @@ v No differences found in column "stat_label". ! Differences found in column "stat" for 12 rows. Output - group1 group1_level variable variable_level stat_name stat.x - 1 ARM Placebo AGEGR1 65-80 N 56 - 2 ARM Placebo AGEGR1 65-80 p 0.75 - 3 ARM Placebo AGEGR1 <65 N 56 - 4 ARM Placebo AGEGR1 <65 p 0.25 - 5 ARM Xanomeline High Dose AGEGR1 65-80 N 66 - 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.8333333 - 7 ARM Xanomeline High Dose AGEGR1 <65 N 66 - 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.1666667 - 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 - 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.8545455 - stat.y difference - 1 86 Mean relative difference: 0.5357143 - 2 0.4883721 Mean relative difference: 0.3488372 - 3 86 Mean relative difference: 0.5357143 - 4 0.1627907 Mean relative difference: 0.3488372 - 5 84 Mean relative difference: 0.2727273 - 6 0.6547619 Mean relative difference: 0.2142857 - 7 84 Mean relative difference: 0.2727273 - 8 0.1309524 Mean relative difference: 0.2142857 - 9 84 Mean relative difference: 0.5272727 - 10 0.5595238 Mean relative difference: 0.3452381 + group1 group1_level variable variable_level stat_name stat.x stat.y difference + 1 ARM Placebo AGEGR1 65-80 N 56 86 Mean relative difference: 0.5357143 + 2 ARM Placebo AGEGR1 65-80 p 0.75 0.4883721 Mean relative difference: 0.3488372 + 3 ARM Placebo AGEGR1 <65 N 56 86 Mean relative difference: 0.5357143 + 4 ARM Placebo AGEGR1 <65 p 0.25 0.1627907 Mean relative difference: 0.3488372 + 5 ARM Xanomeline High Dose AGEGR1 65-80 N 66 84 Mean relative difference: 0.2727273 + 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.8333333 0.6547619 Mean relative difference: 0.2142857 + 7 ARM Xanomeline High Dose AGEGR1 <65 N 66 84 Mean relative difference: 0.2727273 + 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.1666667 0.1309524 Mean relative difference: 0.2142857 + 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 84 Mean relative difference: 0.5272727 + 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.8545455 0.5595238 Mean relative difference: 0.3452381 # print.compare_ard() prints both mis-matched row blocks @@ -335,20 +313,13 @@ v No differences found in column "stat_label". ! Differences found in column "stat" for 6 rows. Output - group1 group1_level variable variable_level stat_name stat.x - 1 ARM Placebo AGEGR1 65-80 N 56 - 2 ARM Placebo AGEGR1 65-80 p 0.75 - 3 ARM Xanomeline High Dose AGEGR1 65-80 N 66 - 4 ARM Xanomeline High Dose AGEGR1 65-80 p 0.8333333 - 5 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 - 6 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.8545455 - stat.y difference - 1 72 Mean relative difference: 0.2857143 - 2 0.5833333 Mean relative difference: 0.2222222 - 3 73 Mean relative difference: 0.1060606 - 4 0.7534247 Mean relative difference: 0.09589041 - 5 76 Mean relative difference: 0.3818182 - 6 0.6184211 Mean relative difference: 0.2763158 + group1 group1_level variable variable_level stat_name stat.x stat.y difference + 1 ARM Placebo AGEGR1 65-80 N 56 72 Mean relative difference: 0.2857143 + 2 ARM Placebo AGEGR1 65-80 p 0.75 0.5833333 Mean relative difference: 0.2222222 + 3 ARM Xanomeline High Dose AGEGR1 65-80 N 66 73 Mean relative difference: 0.1060606 + 4 ARM Xanomeline High Dose AGEGR1 65-80 p 0.8333333 0.7534247 Mean relative difference: 0.09589041 + 5 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 76 Mean relative difference: 0.3818182 + 6 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.8545455 0.6184211 Mean relative difference: 0.2763158 # print.compare_ard() truncates long mis-matched row blocks @@ -383,14 +354,9 @@ v No differences found in column "stat_label". ! Differences found in column "stat" for 4 rows. Output - variable variable_level stat_name stat.x stat.y - 1 SITEID 701 N 254 59 - 2 SITEID 701 p 0.1614173 0.6949153 - 3 SITEID 703 N 254 59 - 4 SITEID 703 p 0.07086614 0.3050847 - difference - 1 Mean relative difference: 0.7677165 - 2 Mean relative difference: 3.305085 - 3 Mean relative difference: 0.7677165 - 4 Mean relative difference: 3.305085 + variable variable_level stat_name stat.x stat.y difference + 1 SITEID 701 N 254 59 Mean relative difference: 0.7677165 + 2 SITEID 701 p 0.1614173 0.6949153 Mean relative difference: 3.305085 + 3 SITEID 703 N 254 59 Mean relative difference: 0.7677165 + 4 SITEID 703 p 0.07086614 0.3050847 Mean relative difference: 3.305085 diff --git a/tests/testthat/test-print.R b/tests/testthat/test-print.R index b2bda3764..fea08dd7a 100644 --- a/tests/testthat/test-print.R +++ b/tests/testthat/test-print.R @@ -63,6 +63,10 @@ test_that("print.card() keeps non-NULL warning/error columns when narrow", { }) test_that("print.compare_ard() works", { + # widen the console so the comparison tables print in one piece rather than + # being split into column chunks by `print.data.frame()` + withr::local_options(width = 200) + ard <- ard_tabulate(ADSL, by = "ARM", variables = "AGEGR1") # equal ARDs @@ -90,6 +94,10 @@ test_that("print.compare_ard() works", { }) test_that("print.compare_ard() prints both mis-matched row blocks", { + # widen the console so the comparison tables print in one piece rather than + # being split into column chunks by `print.data.frame()` + withr::local_options(width = 200) + # each ARD holds an age group the other does not, so both blocks print ard_no_high <- ard_tabulate( @@ -136,6 +144,10 @@ test_that("print.compare_ard() prints the mis-matched rows themselves (#605)", { }) test_that("print.compare_ard() truncates long mis-matched row blocks", { + # widen the console so the comparison tables print in one piece rather than + # being split into column chunks by `print.data.frame()` + withr::local_options(width = 200) + # 17 sites x 3 statistics, of which only two sites survive the filter, so the # block is far longer than the console can hold and is truncated by the ARD # print method with the withheld row count in the footer From 51df7ba6cde444c21da3b7d5dac5fb84d1b606e4 Mon Sep 17 00:00:00 2001 From: Daniel Sjoberg Date: Mon, 7 Sep 2026 15:59:50 -0700 Subject: [PATCH 3/5] Print the comparison tables through the ARD print method too `print.compare_ard()` coerced the comparison tables with `as.data.frame()` and truncated them with `utils::head(n = 10)`. The tables are already `card` objects -- `.compare_columns()` builds them with `inner_join()`, which preserves the class -- so printing them directly gives tibble formatting with the scalar list-column values shown, and `n = 10` reports the withheld rows in the footer instead of silently dropping them. `dplyr::as_tibble()` is not used here: it strips the `card` class, which sends the `stat.x`/`stat.y`/`difference` list-columns back to printing as `` rather than their values. Note that pillar formats numbers to `pillar.sigfig` (3) significant digits, where `as.data.frame()` used `getOption("digits")` (7), so near-identical values now render alike in the side-by-side columns. The `difference` column still carries the full `all.equal()` magnitude. Co-Authored-By: Claude Opus 5 --- NEWS.md | 2 +- R/print.R | 4 +- tests/testthat/_snaps/print.md | 78 +++++++++++++++++++--------------- 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/NEWS.md b/NEWS.md index 95a927a87..a562d0474 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,7 +4,7 @@ * Fixed a bug in `print.compare_ard()` where the rows present in `x` but not in `y` were announced and then not printed. (#605, @malanbos) -* The mis-matched row blocks of `print.compare_ard()` now print through the ARD print method rather than being coerced with `as.data.frame()`, so scalar list-column values (e.g. `group1_level`, `variable_level`) are shown and long blocks are truncated with a row count in the footer. (#605) +* `print.compare_ard()` now prints its tables through the ARD print method rather than coercing them with `as.data.frame()`. Scalar list-column values (e.g. `group1_level`, `variable_level`, `stat`) are shown rather than collapsed, and long tables are truncated with the withheld row count reported in the footer. (#605) # cards 0.9.0 diff --git a/R/print.R b/R/print.R index e3308a6b9..298f78796 100644 --- a/R/print.R +++ b/R/print.R @@ -199,9 +199,7 @@ print.compare_ard <- function(x, ...) { next } cli::cli_alert_warning("Differences found in column {.val {names(x$comparison[i])}} for {.val {nrow(x$comparison[[i]])}} rows.") - as.data.frame(x$comparison[[i]]) |> - utils::head(n = 10) |> - print() + print(x$comparison[[i]], n = 10) } # return input invisibly ----------------------------------------------------- diff --git a/tests/testthat/_snaps/print.md b/tests/testthat/_snaps/print.md index 92d552e8d..b8189df90 100644 --- a/tests/testthat/_snaps/print.md +++ b/tests/testthat/_snaps/print.md @@ -212,17 +212,20 @@ v No differences found in column "stat_label". ! Differences found in column "stat" for 12 rows. Output - group1 group1_level variable variable_level stat_name stat.x stat.y difference - 1 ARM Placebo AGEGR1 65-80 N 86 56 Mean relative difference: 0.3488372 - 2 ARM Placebo AGEGR1 65-80 p 0.4883721 0.75 Mean relative difference: 0.5357143 - 3 ARM Placebo AGEGR1 <65 N 86 56 Mean relative difference: 0.3488372 - 4 ARM Placebo AGEGR1 <65 p 0.1627907 0.25 Mean relative difference: 0.5357143 - 5 ARM Xanomeline High Dose AGEGR1 65-80 N 84 66 Mean relative difference: 0.2142857 - 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.6547619 0.8333333 Mean relative difference: 0.2727273 - 7 ARM Xanomeline High Dose AGEGR1 <65 N 84 66 Mean relative difference: 0.2142857 - 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.1309524 0.1666667 Mean relative difference: 0.2727273 - 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 84 55 Mean relative difference: 0.3452381 - 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.5595238 0.8545455 Mean relative difference: 0.5272727 + # An ARD data frame: 12 x 8 + group1 group1_level variable variable_level stat_name stat.x stat.y difference + + 1 ARM Placebo AGEGR1 65-80 N 86 56 Mean relative difference: 0.3488372 + 2 ARM Placebo AGEGR1 65-80 p 0.488 0.75 Mean relative difference: 0.5357143 + 3 ARM Placebo AGEGR1 <65 N 86 56 Mean relative difference: 0.3488372 + 4 ARM Placebo AGEGR1 <65 p 0.163 0.25 Mean relative difference: 0.5357143 + 5 ARM Xanomeline High Dose AGEGR1 65-80 N 84 66 Mean relative difference: 0.2142857 + 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.655 0.833 Mean relative difference: 0.2727273 + 7 ARM Xanomeline High Dose AGEGR1 <65 N 84 66 Mean relative difference: 0.2142857 + 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.131 0.167 Mean relative difference: 0.2727273 + 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 84 55 Mean relative difference: 0.3452381 + 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.560 0.855 Mean relative difference: 0.5272727 + # i 2 more rows --- @@ -255,17 +258,20 @@ v No differences found in column "stat_label". ! Differences found in column "stat" for 12 rows. Output - group1 group1_level variable variable_level stat_name stat.x stat.y difference - 1 ARM Placebo AGEGR1 65-80 N 56 86 Mean relative difference: 0.5357143 - 2 ARM Placebo AGEGR1 65-80 p 0.75 0.4883721 Mean relative difference: 0.3488372 - 3 ARM Placebo AGEGR1 <65 N 56 86 Mean relative difference: 0.5357143 - 4 ARM Placebo AGEGR1 <65 p 0.25 0.1627907 Mean relative difference: 0.3488372 - 5 ARM Xanomeline High Dose AGEGR1 65-80 N 66 84 Mean relative difference: 0.2727273 - 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.8333333 0.6547619 Mean relative difference: 0.2142857 - 7 ARM Xanomeline High Dose AGEGR1 <65 N 66 84 Mean relative difference: 0.2727273 - 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.1666667 0.1309524 Mean relative difference: 0.2142857 - 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 84 Mean relative difference: 0.5272727 - 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.8545455 0.5595238 Mean relative difference: 0.3452381 + # An ARD data frame: 12 x 8 + group1 group1_level variable variable_level stat_name stat.x stat.y difference + + 1 ARM Placebo AGEGR1 65-80 N 56 86 Mean relative difference: 0.5357143 + 2 ARM Placebo AGEGR1 65-80 p 0.75 0.488 Mean relative difference: 0.3488372 + 3 ARM Placebo AGEGR1 <65 N 56 86 Mean relative difference: 0.5357143 + 4 ARM Placebo AGEGR1 <65 p 0.25 0.163 Mean relative difference: 0.3488372 + 5 ARM Xanomeline High Dose AGEGR1 65-80 N 66 84 Mean relative difference: 0.2727273 + 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.833 0.655 Mean relative difference: 0.2142857 + 7 ARM Xanomeline High Dose AGEGR1 <65 N 66 84 Mean relative difference: 0.2727273 + 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.167 0.131 Mean relative difference: 0.2142857 + 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 84 Mean relative difference: 0.5272727 + 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.855 0.560 Mean relative difference: 0.3452381 + # i 2 more rows # print.compare_ard() prints both mis-matched row blocks @@ -313,13 +319,15 @@ v No differences found in column "stat_label". ! Differences found in column "stat" for 6 rows. Output - group1 group1_level variable variable_level stat_name stat.x stat.y difference - 1 ARM Placebo AGEGR1 65-80 N 56 72 Mean relative difference: 0.2857143 - 2 ARM Placebo AGEGR1 65-80 p 0.75 0.5833333 Mean relative difference: 0.2222222 - 3 ARM Xanomeline High Dose AGEGR1 65-80 N 66 73 Mean relative difference: 0.1060606 - 4 ARM Xanomeline High Dose AGEGR1 65-80 p 0.8333333 0.7534247 Mean relative difference: 0.09589041 - 5 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 76 Mean relative difference: 0.3818182 - 6 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.8545455 0.6184211 Mean relative difference: 0.2763158 + # An ARD data frame: 6 x 8 + group1 group1_level variable variable_level stat_name stat.x stat.y difference + + 1 ARM Placebo AGEGR1 65-80 N 56 72 Mean relative difference: 0.2857143 + 2 ARM Placebo AGEGR1 65-80 p 0.75 0.583 Mean relative difference: 0.2222222 + 3 ARM Xanomeline High Dose AGEGR1 65-80 N 66 73 Mean relative difference: 0.1060606 + 4 ARM Xanomeline High Dose AGEGR1 65-80 p 0.833 0.753 Mean relative difference: 0.09589041 + 5 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 76 Mean relative difference: 0.3818182 + 6 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.855 0.618 Mean relative difference: 0.2763158 # print.compare_ard() truncates long mis-matched row blocks @@ -354,9 +362,11 @@ v No differences found in column "stat_label". ! Differences found in column "stat" for 4 rows. Output - variable variable_level stat_name stat.x stat.y difference - 1 SITEID 701 N 254 59 Mean relative difference: 0.7677165 - 2 SITEID 701 p 0.1614173 0.6949153 Mean relative difference: 3.305085 - 3 SITEID 703 N 254 59 Mean relative difference: 0.7677165 - 4 SITEID 703 p 0.07086614 0.3050847 Mean relative difference: 3.305085 + # An ARD data frame: 4 x 6 + variable variable_level stat_name stat.x stat.y difference + + 1 SITEID 701 N 254 59 Mean relative difference: 0.7677165 + 2 SITEID 701 p 0.161 0.695 Mean relative difference: 3.305085 + 3 SITEID 703 N 254 59 Mean relative difference: 0.7677165 + 4 SITEID 703 p 0.0709 0.305 Mean relative difference: 3.305085 From a124a8581d8581558f4cd35e129cff3b1b2a7711 Mon Sep 17 00:00:00 2001 From: Daniel Sjoberg Date: Mon, 7 Sep 2026 16:05:51 -0700 Subject: [PATCH 4/5] Drop the blank line between a section rule and its sub-header cli's builtin theme gives `h3` a `margin-top` of 1, so every "Rows in `x`/`y` that do not appear in ..." sub-header was preceded by a blank line -- both under the "Mis-matched Rows" rule and between the two row blocks. A `cli_div()` theme zeroes it; the div closes itself when the method exits. `h1` keeps its `margin-top`, so the "Mis-matched Rows" and "Comparison Results" rules still separate from what precedes them. Co-Authored-By: Claude Opus 5 --- R/print.R | 4 ++++ tests/testthat/_snaps/print.md | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/R/print.R b/R/print.R index 298f78796..f0013bc8d 100644 --- a/R/print.R +++ b/R/print.R @@ -172,6 +172,10 @@ tbl_format_setup.card <- function(x, width = NULL, ...) { #' @export #' @rdname print.card print.compare_ard <- function(x, ...) { + # sub-headers sit directly beneath their section rule; the div closes itself + # when this function exits + cli::cli_div(theme = list(h3 = list("margin-top" = 0))) + # print comparison details --------------------------------------------------- cli::cli_inform("The comparison {.arg keys} are {.val {x$keys}}.") cli::cli_inform("The comparison columns are {.val {x$columns}}.") diff --git a/tests/testthat/_snaps/print.md b/tests/testthat/_snaps/print.md index b8189df90..4bb6c59d5 100644 --- a/tests/testthat/_snaps/print.md +++ b/tests/testthat/_snaps/print.md @@ -190,7 +190,6 @@ The comparison columns are "stat_label" and "stat". -- Mis-matched Rows ------------------------------------------------------------ - -- Rows in `x` that do not appear in `y`. Output # An ARD data frame: 9 x 5 @@ -237,7 +236,6 @@ -- Mis-matched Rows ------------------------------------------------------------ v No rows in `x` that do not appear in `y`. - -- Rows in `y` that do not appear in `x`. Output # An ARD data frame: 9 x 5 @@ -282,7 +280,6 @@ The comparison columns are "stat_label" and "stat". -- Mis-matched Rows ------------------------------------------------------------ - -- Rows in `x` that do not appear in `y`. Output # An ARD data frame: 9 x 5 @@ -298,7 +295,6 @@ 8 ARM Xanomeline Low Dose AGEGR1 <65 N 9 ARM Xanomeline Low Dose AGEGR1 <65 p Message - -- Rows in `y` that do not appear in `x`. Output # An ARD data frame: 9 x 5 @@ -338,7 +334,6 @@ The comparison columns are "stat_label" and "stat". -- Mis-matched Rows ------------------------------------------------------------ - -- Rows in `x` that do not appear in `y`. Output # An ARD data frame: 45 x 3 From 0fc95675a7e356e161d613a934c68f1656c8896d Mon Sep 17 00:00:00 2001 From: Daniel Sjoberg Date: Mon, 7 Sep 2026 16:11:26 -0700 Subject: [PATCH 5/5] Rely on the tibble default row count in print.compare_ard() The hard-coded `n = 10` came from the `utils::head(n = 10)` it replaced, but it diverges from the mis-matched row blocks, which use a plain `print()`, and it overrides whatever the user set `tibble.print_min`/`tibble.print_max` to. The default prints every row up to `tibble.print_max` (20) and truncates to `tibble.print_min` (10) beyond that, so long tables are still bounded -- the 45-row block in the truncation test still reports `# i 35 more rows`. The only change is that the 12-row comparison tables now print in full. Co-Authored-By: Claude Opus 5 --- R/print.R | 2 +- tests/testthat/_snaps/print.md | 54 ++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/R/print.R b/R/print.R index f0013bc8d..306b2ea4a 100644 --- a/R/print.R +++ b/R/print.R @@ -203,7 +203,7 @@ print.compare_ard <- function(x, ...) { next } cli::cli_alert_warning("Differences found in column {.val {names(x$comparison[i])}} for {.val {nrow(x$comparison[[i]])}} rows.") - print(x$comparison[[i]], n = 10) + print(x$comparison[[i]]) } # return input invisibly ----------------------------------------------------- diff --git a/tests/testthat/_snaps/print.md b/tests/testthat/_snaps/print.md index 4bb6c59d5..f2bb1d727 100644 --- a/tests/testthat/_snaps/print.md +++ b/tests/testthat/_snaps/print.md @@ -212,19 +212,20 @@ ! Differences found in column "stat" for 12 rows. Output # An ARD data frame: 12 x 8 - group1 group1_level variable variable_level stat_name stat.x stat.y difference - - 1 ARM Placebo AGEGR1 65-80 N 86 56 Mean relative difference: 0.3488372 - 2 ARM Placebo AGEGR1 65-80 p 0.488 0.75 Mean relative difference: 0.5357143 - 3 ARM Placebo AGEGR1 <65 N 86 56 Mean relative difference: 0.3488372 - 4 ARM Placebo AGEGR1 <65 p 0.163 0.25 Mean relative difference: 0.5357143 - 5 ARM Xanomeline High Dose AGEGR1 65-80 N 84 66 Mean relative difference: 0.2142857 - 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.655 0.833 Mean relative difference: 0.2727273 - 7 ARM Xanomeline High Dose AGEGR1 <65 N 84 66 Mean relative difference: 0.2142857 - 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.131 0.167 Mean relative difference: 0.2727273 - 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 84 55 Mean relative difference: 0.3452381 - 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.560 0.855 Mean relative difference: 0.5272727 - # i 2 more rows + group1 group1_level variable variable_level stat_name stat.x stat.y difference + + 1 ARM Placebo AGEGR1 65-80 N 86 56 Mean relative difference: 0.3488372 + 2 ARM Placebo AGEGR1 65-80 p 0.488 0.75 Mean relative difference: 0.5357143 + 3 ARM Placebo AGEGR1 <65 N 86 56 Mean relative difference: 0.3488372 + 4 ARM Placebo AGEGR1 <65 p 0.163 0.25 Mean relative difference: 0.5357143 + 5 ARM Xanomeline High Dose AGEGR1 65-80 N 84 66 Mean relative difference: 0.2142857 + 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.655 0.833 Mean relative difference: 0.2727273 + 7 ARM Xanomeline High Dose AGEGR1 <65 N 84 66 Mean relative difference: 0.2142857 + 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.131 0.167 Mean relative difference: 0.2727273 + 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 84 55 Mean relative difference: 0.3452381 + 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.560 0.855 Mean relative difference: 0.5272727 + 11 ARM Xanomeline Low Dose AGEGR1 <65 N 84 55 Mean relative difference: 0.3452381 + 12 ARM Xanomeline Low Dose AGEGR1 <65 p 0.0952 0.145 Mean relative difference: 0.5272727 --- @@ -257,19 +258,20 @@ ! Differences found in column "stat" for 12 rows. Output # An ARD data frame: 12 x 8 - group1 group1_level variable variable_level stat_name stat.x stat.y difference - - 1 ARM Placebo AGEGR1 65-80 N 56 86 Mean relative difference: 0.5357143 - 2 ARM Placebo AGEGR1 65-80 p 0.75 0.488 Mean relative difference: 0.3488372 - 3 ARM Placebo AGEGR1 <65 N 56 86 Mean relative difference: 0.5357143 - 4 ARM Placebo AGEGR1 <65 p 0.25 0.163 Mean relative difference: 0.3488372 - 5 ARM Xanomeline High Dose AGEGR1 65-80 N 66 84 Mean relative difference: 0.2727273 - 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.833 0.655 Mean relative difference: 0.2142857 - 7 ARM Xanomeline High Dose AGEGR1 <65 N 66 84 Mean relative difference: 0.2727273 - 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.167 0.131 Mean relative difference: 0.2142857 - 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 84 Mean relative difference: 0.5272727 - 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.855 0.560 Mean relative difference: 0.3452381 - # i 2 more rows + group1 group1_level variable variable_level stat_name stat.x stat.y difference + + 1 ARM Placebo AGEGR1 65-80 N 56 86 Mean relative difference: 0.5357143 + 2 ARM Placebo AGEGR1 65-80 p 0.75 0.488 Mean relative difference: 0.3488372 + 3 ARM Placebo AGEGR1 <65 N 56 86 Mean relative difference: 0.5357143 + 4 ARM Placebo AGEGR1 <65 p 0.25 0.163 Mean relative difference: 0.3488372 + 5 ARM Xanomeline High Dose AGEGR1 65-80 N 66 84 Mean relative difference: 0.2727273 + 6 ARM Xanomeline High Dose AGEGR1 65-80 p 0.833 0.655 Mean relative difference: 0.2142857 + 7 ARM Xanomeline High Dose AGEGR1 <65 N 66 84 Mean relative difference: 0.2727273 + 8 ARM Xanomeline High Dose AGEGR1 <65 p 0.167 0.131 Mean relative difference: 0.2142857 + 9 ARM Xanomeline Low Dose AGEGR1 65-80 N 55 84 Mean relative difference: 0.5272727 + 10 ARM Xanomeline Low Dose AGEGR1 65-80 p 0.855 0.560 Mean relative difference: 0.3452381 + 11 ARM Xanomeline Low Dose AGEGR1 <65 N 55 84 Mean relative difference: 0.5272727 + 12 ARM Xanomeline Low Dose AGEGR1 <65 p 0.145 0.0952 Mean relative difference: 0.3452381 # print.compare_ard() prints both mis-matched row blocks