From 87fb85e503929f61a6173ab48c27342393c1a877 Mon Sep 17 00:00:00 2001 From: Gabe Becker Date: Thu, 6 Nov 2025 16:19:31 -0800 Subject: [PATCH 1/7] Add section splash page and split requirements vignette [skip spelling] --- inst/WORDLIST | 1 + vignettes/guided_intermediate.Rmd | 59 +++ vignettes/guided_intermediate_afun_reqs.Rmd | 1 + vignettes/guided_intermediate_split_reqs.Rmd | 506 +++++++++++++++++++ 4 files changed, 567 insertions(+) create mode 100644 vignettes/guided_intermediate.Rmd create mode 100644 vignettes/guided_intermediate_split_reqs.Rmd diff --git a/inst/WORDLIST b/inst/WORDLIST index 533b0c57a3..559d2f2799 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -132,6 +132,7 @@ Sabanés Saibah sas sep +SKELETOMUSCULAR sortable spl Stoilova diff --git a/vignettes/guided_intermediate.Rmd b/vignettes/guided_intermediate.Rmd new file mode 100644 index 0000000000..87cddd72fc --- /dev/null +++ b/vignettes/guided_intermediate.Rmd @@ -0,0 +1,59 @@ +--- +title: "A Guided Tour of rtables - Intermediate" +subtitle: Contributed by Johnson & Johnson Innovative Medicine +date: "2025-06-17" +author: +- Gabriel Becker +- Dan Hofstaedter +output: + rmarkdown::html_document: + theme: "spacelab" + highlight: "kate" + toc: true + toc_float: true +vignette: > + %\VignetteIndexEntry{A Guided Tour of rtables - Intermediate} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +editor_options: + markdown: + wrap: 72 + chunk_output_type: console +--- + +# Scope and Audience + +Now that we have an understanding of how the `rtables` framework +behaves mechanically from a user perspective, our next step is to +build up intuition for how to leverage `rtables`' flexibility to +create table outputs that go beyond simple straightforward structures. + +This portion of the guide is intended for users with a reasonable +grasp of what the individual layouting instructions do by default that +want to learn how to combine and customize their behavior to achieve +complex structured tables when a library of suitable analysis, group +summary, and split functions is already available. It is a good fit +for users looking to leverage, e.g., `tern` or `junco` to create tables +without writing custom functions themselves. + +Taking full control of tabulation behavior by creating our own +functions, and understanding the layouting engine's default behavior +will be covered in the upcoming advanced and introductory portions of +this guide, respectively. In the meantime we refer readers looking for +such content to the wide array of existing vignettes and documentation +available beyond this guided tour. + + + +# Chapters + +- [Translating Shells To + Layouts](./guided_intermediate_translating_shells.html) - + Identifying key structural features in a table shell and mapping + them to rtables concepts +- [Identifying Required Analysis + Behavior](./guided_intermediate_afun_reqs.html) - Reasoning about + analysis behaviors and choosing an `afun` +- [Identifying Required Faceting + Behavior](./guided_intermediate_split_reqs.html) - Reasoning about + faceting and choosing a split function diff --git a/vignettes/guided_intermediate_afun_reqs.Rmd b/vignettes/guided_intermediate_afun_reqs.Rmd index bf9850161e..92751dab94 100644 --- a/vignettes/guided_intermediate_afun_reqs.Rmd +++ b/vignettes/guided_intermediate_afun_reqs.Rmd @@ -12,6 +12,7 @@ output: toc: true toc_float: true code_folding: show + after_body: '`r vignette: > %\VignetteIndexEntry{Intermediate rtables - Identifying Required Analysis Behavior} %\VignetteEngine{knitr::rmarkdown} diff --git a/vignettes/guided_intermediate_split_reqs.Rmd b/vignettes/guided_intermediate_split_reqs.Rmd new file mode 100644 index 0000000000..c2444e074a --- /dev/null +++ b/vignettes/guided_intermediate_split_reqs.Rmd @@ -0,0 +1,506 @@ +--- +title: "Intermediate rtables - Identifying Required Faceting Behavior" +subtitle: Contributed by Johnson & Johnson Innovative Medicine +date: "2025-10-22" +author: +- Gabriel Becker +- Dan Hofstaedter +output: + rmarkdown::html_document: + theme: "spacelab" + highlight: "kate" + toc: true + toc_float: true + code_folding: show +vignette: > + %\VignetteIndexEntry{Intermediate rtables - Identifying Required Faceting Behavior} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +editor_options: + markdown: + wrap: 72 + chunk_output_type: console +--- + +# Introduction + +```{r init, echo = FALSE, results = "hidden"} +suppressPackageStartupMessages(library(rtables)) +suppressPackageStartupMessages(library(dplyr)) +suppressPackageStartupMessages(library(tibble)) + +## XXX put this somewhere else so everyone can share it +fixed_shell <- function(tt) { + mystr <- table_shell_str(tt) + regex_hits <- gregexpr("[(]N=[[:digit:]]+[)]", mystr)[[1]] + hit_lens <- attr(regex_hits, "match.length") + if (regex_hits[1] > 0) { + for (i in seq_along(regex_hits)) { + start <- regex_hits[i] + len <- hit_lens[i] + substr(mystr, start, start + len - 1) <- padstr("(N=xx)", len, just = "center") + } + } + cat(mystr) +} + + +knitr::opts_chunk$set(comment = "") +``` + +`rtables` supports *generalized* faceting when declaring row and +column structure. In particular it, allows faceting behavior to +deviate from that seen in e.g., `ggplot2` faceting support in four +crucial ways often required for tables: + +1. Facets need not be mutually exclusive, +2. Facets need not be exhaustive, +3. Nested faceting behavior can depend on the parent facet it occurs + within, and +4. Facets can be created that do not reflect a single categorical + value in the data. + +While this flexibility provides a cornerstone to `rtables`' power - +alongside the flexibility of analysis functions discussed in the +previous chapter - it also means we must actively think about faceting +when creating table layouts in a way simply not required of users of +`facet_grid` in `ggplot2`. + +In this chapter we will cover identifying which aspects of a shell or +desired table should be achieved by specifying the correct split +function(s) in the layout. As with the previous chapter's handling of +analysis behavior, we will leave *implementation* of fully custom +split functions for the advanced portion of this guide and focus +solely on the identification of required behavior to prepare users to +choose between a selection of pre-existing non-default split functions +available to them. + +# A Brief Review + +Faceting serves three purposes within the `rtables` layouting +framework. It declares + +1. The row- and column-labeling when the table is rendered, +2. The organization of the sets of cells that will make up the table's + body, and +3. The data to be analyzed when calculating contents for each set of + cells in the table. + +In particular, (3) means that the data passed to analysis functions +is the intersection of the data associated with the row- and +column-facets that define the location of the cell(s) whose contents +are being calculated. + +`rtables` is designed such that data should not need to be duplicated, +nor .e.g, levels of a factor, restricted in the dataset prior to +calling `build_table`. Things like adding combination levels and +restricting or reordering factor levels are all declared via faceting +in the layout and then performed automatically by the internal +`rtables` machinery during table creation. + + +## Split Function Basics + +We will leave a detailed technical discussion of how split functions +work for when we implement our own custom split functions in the +advanced portion of this guide. For our purposes here, it suffices to +consider a split function to be a mapping from an incoming dataset +(the data associated with the parent facet) to a set of one or more +facets, each of which are associated with (sub)sets of that incoming +data. + +## Default Faceting + +By default, faceting instructions: + +1. Declare facets based on a *partition* of incoming data defined by a + categorical variable, and +2. Nest within previously declared instructions in the same dimension + (row/column). + +The above behaviors combine to mean that sequential faceting +instructions (i.e., repeated calls to `split_cols_by` or +`split_rows_by`) result in *full factorial faceting*, where each +combination of levels from the variables faceted on is represented. + +This is true with column faceting: + +```{r} +lyt <- basic_table() |> + split_cols_by("ARM") |> + split_cols_by("SEX") + +build_table(lyt, ex_adsl) +``` + +as well as with row faceting, with the caveat that row faceting does +not generate individual rows, and thus an analyze call is required: + +```{r} +lyt2 <- basic_table() |> + split_rows_by("STRATA1") |> + split_rows_by("BMRKR2") |> + analyze("AGE") + +build_table(lyt2, ex_adsl) +``` + +# Recognizing Non-Full-Factorial Faceting + +Any time we need faceting that does not represent a full factorial +combination of one or more variables (i.e., the full set of +combinations of levels from those variables), we will need to use +split functions to declare our desired structure. + +The key, then, is to carefully consider how our desired faceting +structure deviates from the full factorial structure that default +faceting would generate. This will tell us what behaviors we need from +our split functions. + +## Excluding Factor Levels + +The simplest deviation from full-factorial faceting is to omit some +levels when faceting based on a single categorical variable. This can +come in two flavors: + +1. Prescriptive - when the level(s) to be omitted are set a priori, +2. Empirical - when the level(s) to be omitted depend on the data. + +Prescriptively omitting levels(/facets) is fairly straightforward: you +have a set of levels that, for whatever reason, you do not want facets +for in the resulting table. `rtables` provides the +`remove_split_levels` to create split functions which achieve this. + +Empirically omitting levels(/facets) is more open ended, as +technically the logic determining what should be omitted can be +completely arbitrary. The most common version, however, is to omit +unobserved levels (which would result in facets whose associated data +subset is empty); the `drop_split_levels` split function does this. + +We will use a slightly modified version of our synthetic data to +illustrate the difference: + +```{r} +adsl <- subset(ex_adsl, as.character(SEX) %in% c("F", "M", "U")) +qtable(adsl, col_vars = "SEX") +``` + +First we declare faceting that omits the (rare but observed) `"U"` +level using `remove_split_levels`. + +```{r} +lyt_pre <- basic_table() |> + split_cols_by("SEX", split_fun = remove_split_levels("U")) |> + analyze("STRATA1") + +build_table(lyt_pre, adsl) +``` + +Next we will use `drop_split_levels`: + +```{r} +lyt_emp <- basic_table() |> + split_cols_by("SEX", split_fun = drop_split_levels) |> + analyze("STRATA1") + +build_table(lyt_emp, adsl) +``` + +Here we get exactly -- and only -- facets for the levels of `SEX` +observed in the data. + +It is important to note that `drop_split_levels` omits facets for +levels not observed ***in the incoming data*** which is the data for +the parent facet. This only translates to the full data being +tabulated in cases of top level faceting (not nested within anything) +and other special cases. + +We can see this if we nest faceting using the empirical +`drop_split_levels` within another faceting instruction: + + + +```{r} +lyt_bad_emp <- basic_table() |> + split_cols_by("ARM") |> + split_rows_by("RACE", split_fun = drop_split_levels) |> + split_rows_by("SEX", split_fun = drop_split_levels) |> + analyze("AGE") + +build_table(lyt_bad_emp, adsl) +``` + +Here we see that different sets of `SEX` facets are generated within +different `RACE` facets, with the `"MULTIPLE"` and `"NATIVE HAWAIIAN +OR OTHER PACIFIC ISLANDER"` races each having only a (different) +single facet. This is sometimes the desired behavior, but often it is +not so care should be used with `drop_split_levels` in non-trivial +faceting structures. + +## Adding Combination Levels + +Some shells call for levels to be combined into new virtual +levels. For example, we might need an "All Drug X" category in our +table which represents both arms A (`"A: Drug X") and C (`"C: +Combination"`) as a single group of patients, either in addition to or +instead of those individual arms. + +As with omitting defined factor levels, this is a deviation from the +default full factorial behavior. In this case we want a facet for a +level not present in the data and (assuming the individual arms are +left in alongside our combination arm) our desired facets are not +mutually exclusive. + +`rtables` provides the `add_combo_levels` split function to directly +invoke this behavior. It takes a "combination data.frame" that +declares the combination levels to add. + +```{r} +combodf <- tribble( + ~valname, ~label, ~levelcombo, ~exargs, + "A_C", "Arms A+C", c("A: Drug X", "C: Combination"), list() +) + +lyt_combo1 <- basic_table() |> + split_cols_by("ARM", split_fun = add_combo_levels(combodf), show_colcounts = TRUE) + +build_table(lyt_combo1, ex_adsl) +``` + +## Nested Faceting On Non-Independent Variables + +Often times when performing nested faceting, the inner variable +represents the same information as the outer variable in more +detail. Another way to view this is that the information represented +by the outer variable is implicitly included (or embedded) within the +information for the inner variable. When this occurs, most +combinations of levels from the pair of variables are not logically +consistent, can never occur in practice, and most importantly, should +not be represented in our resulting table. Whenever this is the case, +we cannot rely on the default splitting behavior. + +An ubiquitous example of this in clinical trials are the System Organ +Class (`AESOC`) and Preferred Term (`AEDECOD`) variables used when +describing adverse events. `AESOC` represents the broad category an +adverse events falls within (e.g., "SKELETOMUSCULAR" or +"GASTROINTESTINAL") while `AEDECOD` represents the specific type of +adverse-event ("BACK PAIN", "VOMITING"). In this example, the +combination of `AESOC` being `"SKELETOMUSCULAR"` while `AEDECOD` is +`"VOMITING"`. In our alternate framing we would say that the `AEDECOD` +value `"VOMITING"` implies that `AESOC` *must* be `"SKELETOMUSCULAR"`. + +Note that our synthetic data does not contain realistic values for +`AESOC` and `AEDECOD`, but rather values of the form `"cl X`" (with X +a capital letter) and `"dcd X.m.n.o.p"` with m-p individual digits, +respectively. Note this makes the information embedding even more +explicit, as the X is the same between values of `AESOC` and the +values of `AEDECOD` they apply to. + +As with omitting facets within a single faceting instruction, there +are broadly two ways to approach this type of nested faceting: + +1. Prescriptively, and +2. Empirically. + +In both cases, we can think about this in terms of *pairs of levels we +want to represent in our table*. The goal here is to preemptively +omit pairs which are not logically consistent (and thus which we can +assume have no observations in the data). + +The empirical approach assumes that either: + +- All valid pairs of levels have at least one observation, or +- we want to display *only* observed pairs, omitting any valid +unobserved pairs. + +To this end, `rtables` provides the `trim_levels_in_group` split +function factory, which, for each observed level in variable being +split, levels of a declared `inner_var` are restricted to those +observed *in combination to that level of the split variable*. When we +then split on or analyze the inner variable, we get a table that contains only +the observed pairs: + +```{r} +lyt_tig <- basic_table() |> + split_rows_by("AESOC", split_fun = trim_levels_in_group("AEDECOD")) |> + analyze("AEDECOD") + +build_table(lyt_tig, ex_adae) +``` + + +`trim_levels_in_group` can be used in chains to further restrict the +displayed combinations of more than two variables, if desired: + +```{r} +lyt_tig2 <- basic_table(title = "Observed Toxicity Grades") |> + split_rows_by("AESOC", split_fun = trim_levels_in_group("AEDECOD")) |> + split_rows_by("AEDECOD", split_fun = trim_levels_in_group("AETOXGR")) |> + analyze("AETOXGR") + +build_table(lyt_tig2, ex_adae) +``` + +Sometimes the above is the desired behavior; many times, however, +there are certain counts or values which are important to display +*even when they are not observed*. In such cases, we still want to +omit pairs of levels that are impossible/logically inconsistent, but +cannot rely on which combinations are observed in the data. + +In such cases, we must *prescriptively* declare which combinations we +want to appear in our table. `rtables` provides the +`trim_levels_to_map` split function factory for this, which accepts a +pre-defined map of all combinations which should be included (in the +form of a data.frame). Any combinations which do not appear in the map +will be omitted *even if they are observed in the data*. + +```{r} +map <- tribble( + ~AESOC, ~AEDECOD, + "cl A", "dcd A.1.1.1.2", + "cl B", "dcd B.1.1.1.1", + "cl B", "dcd B.2.2.3.1", + "cl D", "dcd D.1.1.1.1" +) + +lyt_ttm <- basic_table() |> + split_rows_by("AESOC", split_fun = trim_levels_to_map(map)) |> + analyze("AEDECOD") + +build_table(lyt_ttm, ex_adae) +``` + +Note that because there were no pairs in the map with an `AESOC` of +`"cl C"`, that entire facet is omitted. This will be true in the case +of nested faceting as well: + +```{r} +lyt_ttm2 <- basic_table() |> + split_rows_by("AESOC", split_fun = trim_levels_to_map(map)) |> + split_rows_by("AEDECOD", split_fun = trim_levels_in_group("AETOXGR")) |> + analyze("AETOXGR") + +build_table(lyt_ttm2, ex_adae) +``` + +## Facets That Vary Meaning Instead of Data Subset + +In our examples so far, faceting has translated to mapping the +incoming data to a set of distinct (if not necessarily mutually +exclusive or exhaustive) subsets of the data. This is the most common +form of faceting, but it is not the only one `rtables` supports. + +In some cases, we want facets to be *semantically* distinct from +each other; in other words, instead of representing different subsets +of the data, we want them to represent different aspects of the same +data. This is most commonly useful column space, where individual +columns are defined via faceting, unlike individual rows. + + +An toy example of this would be + +```{r, echo = FALSE} +library(tibble) + +tpose_afun <- function(x, .var, .spl_context) { + spldf <<- .spl_context + mycol <- tail(tail(.spl_context$cur_col_split_val, 1)[[1]], 1) + cell <- switch(mycol, + n = rcell(length(x), format = "xx"), + mean = rcell(mean(x, na.rm = TRUE), format = "xx.x"), + sd = rcell(sd(x, na.rm = TRUE), format = "xx.xx") + ) + in_rows(.list = setNames(list(cell), .var)) +} + +combo_df <- tribble( + ~valname, ~label, ~levelcombo, ~exargs, + "n", "n", select_all_levels, list(), + "mean", "mean", select_all_levels, list(), + "sd", "sd", select_all_levels, list() +) + + +lyt_sem_cols <- basic_table() |> + split_cols_by("ARM") |> + split_cols_by("STUDYID", split_fun = add_combo_levels(combo_df, keep_levels = combo_df$valname)) |> + split_rows_by("SEX", split_fun = keep_split_levels(c("F", "M"))) |> + analyze(c("AGE", "BMRKR1"), afun = tpose_afun, show_labels = "hidden") + +fixed_shell(build_table(lyt_sem_cols, ex_adsl)) +``` + +Here we have individual columns for ***different statistics calculated +using the same data*** (`n`, `mean` and `sd`), within a faceting +structure that splits on arm in column space and gender in row space, +and calculated for two different continuous numeric variables (age and +"biomarker 1" value). + +To achieve this, we need faceting that creates three columns all of +whose "subsets" of the incoming (arm) data are identical: all of +it. We can achieve this with the `add_combo_levels` split function +factory we used above; the key is to use the `select_all_levels` +sentinel value provided by rtables to indicate that all levels in the +data should be combined when creating each of our new combination +levels. + + +We will turn on column counts at all levels to show that it is doing +what we want, despite it being redundant and not suitable for any +actual table output. + + +```{r} +my_combo_df <- tribble( + ~valname, ~label, ~levelcombo, ~exargs, + "n", "n", select_all_levels, list(), + "mean", "mean", select_all_levels, list(), + "sd", "sd", select_all_levels, list() +) + +lyt_tpose_cols_only <- basic_table() |> + split_cols_by("ARM", show_colcounts = TRUE) |> + split_cols_by("STUDYID", split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), show_colcounts = TRUE) + +build_table(lyt_tpose_cols_only, ex_adsl) +``` + +We split on study id in the above code largely for convenience. Given +that we are defining combination levels using `select_all_levels`, we +could split on anything and have each of the facets represent the +entirety of the incoming data. This approach, however, is a +generalization of splitting on study id in order to create a single +facet representing all the incoming data, a trick worth having in our +back pocket. + +Thus we've achieved the column structure we wanted. Now we need an +analysis function with the correct *column-conditional behavior* (see +[the previous chapter](./guided_intermediate_afun_reqs.html)) and we +will have our output. + +Without discussing how we construct it (as that will be covered in the +advanced portion of this guide), assuming we have a `tpose_afun` which +meets our requirements, we can then fully create our table: + + +```{r} +lyt_tpose_full <- basic_table() |> + split_cols_by("ARM", show_colcounts = TRUE) |> + split_cols_by("STUDYID", split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), show_colcounts = TRUE) |> + split_rows_by("SEX", split_fun = keep_split_levels(c("F", "M"))) |> + analyze(c("AGE", "BMRKR1"), afun = tpose_afun, show_labels = "hidden") + +build_table(lyt_tpose_full, ex_adsl) +``` + + +# Combining These Faceting Needs + +For some table shells, we need to combine the types of needs we +explored above; we might need `trim_levels_to_map` type behavior, but +also need to include a virtual combination treatment/arm. The split +functions/function factories we discussed here generally cannot achieve +this, though our reasoning for ***how to think about the faceting we +need*** still applies. In such cases, we will construct fully custom +split functions which exactly meet our needs, which will be the topic +of an entire chapter in the advanced portion of this guide. From 29deaea0ef4b50701da0b1295e92ca398d080c39 Mon Sep 17 00:00:00 2001 From: Gabe Becker Date: Thu, 6 Nov 2025 16:26:59 -0800 Subject: [PATCH 2/7] Fix afun reqs regression --- vignettes/guided_intermediate_afun_reqs.Rmd | 1 - 1 file changed, 1 deletion(-) diff --git a/vignettes/guided_intermediate_afun_reqs.Rmd b/vignettes/guided_intermediate_afun_reqs.Rmd index 92751dab94..bf9850161e 100644 --- a/vignettes/guided_intermediate_afun_reqs.Rmd +++ b/vignettes/guided_intermediate_afun_reqs.Rmd @@ -12,7 +12,6 @@ output: toc: true toc_float: true code_folding: show - after_body: '`r vignette: > %\VignetteIndexEntry{Intermediate rtables - Identifying Required Analysis Behavior} %\VignetteEngine{knitr::rmarkdown} From b837abdc9dfd3be967b2dd10a7e65410d701f99d Mon Sep 17 00:00:00 2001 From: Gabe Becker Date: Thu, 6 Nov 2025 16:35:16 -0800 Subject: [PATCH 3/7] NEWS and pkgdown, plus tiny tweak to section intro --- NEWS.md | 5 ++++- _pkgdown.yml | 6 ++++++ vignettes/guided_intermediate.Rmd | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 0934878375..e5dced3c18 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,9 +1,12 @@ ## rtables 0.6.13.9003 ### New Features + * Added Guided Tour section to the pkgdown site + * Added vignette: Guided Tour (Intermediate) * Added vignette: Guided Tour (Intermediate) - Translating Shells To Layouts @gmbecker * Added vignette: Guided Tour (Intermediate) - Identifying Required Analysis Behavior @gmbecker - + * Added vignette: Guided Tour (Intermediate) - Identifying Required Faceting Behavior @gmbecker + ## rtables 0.6.13 ### New Features diff --git a/_pkgdown.yml b/_pkgdown.yml index 2c09ac6b52..dc3cff6278 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -60,8 +60,14 @@ articles: contents: - rtables - exploratory_analysis + + - title: Guided Tour + navbar: Guided Tour + contents: + - guided_intermediate - guided_intermediate_translating_shells - guided_intermediate_afun_reqs + - guided_intermediate_split_reqs - title: Clinical Trials navbar: Clinical Trials diff --git a/vignettes/guided_intermediate.Rmd b/vignettes/guided_intermediate.Rmd index 87cddd72fc..c0412e228f 100644 --- a/vignettes/guided_intermediate.Rmd +++ b/vignettes/guided_intermediate.Rmd @@ -29,7 +29,7 @@ build up intuition for how to leverage `rtables`' flexibility to create table outputs that go beyond simple straightforward structures. This portion of the guide is intended for users with a reasonable -grasp of what the individual layouting instructions do by default that +grasp of what the individual layouting instructions do by default who want to learn how to combine and customize their behavior to achieve complex structured tables when a library of suitable analysis, group summary, and split functions is already available. It is a good fit From 83812740a537a477d01d7eed5c11fe507d35e3f1 Mon Sep 17 00:00:00 2001 From: Gabe Becker Date: Thu, 6 Nov 2025 16:54:19 -0800 Subject: [PATCH 4/7] fix lints that styler missed...somehow --- vignettes/guided_intermediate_split_reqs.Rmd | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vignettes/guided_intermediate_split_reqs.Rmd b/vignettes/guided_intermediate_split_reqs.Rmd index c2444e074a..65074dd471 100644 --- a/vignettes/guided_intermediate_split_reqs.Rmd +++ b/vignettes/guided_intermediate_split_reqs.Rmd @@ -460,7 +460,9 @@ my_combo_df <- tribble( lyt_tpose_cols_only <- basic_table() |> split_cols_by("ARM", show_colcounts = TRUE) |> - split_cols_by("STUDYID", split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), show_colcounts = TRUE) + split_cols_by("STUDYID", + split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), + show_colcounts = TRUE) build_table(lyt_tpose_cols_only, ex_adsl) ``` @@ -486,7 +488,9 @@ meets our requirements, we can then fully create our table: ```{r} lyt_tpose_full <- basic_table() |> split_cols_by("ARM", show_colcounts = TRUE) |> - split_cols_by("STUDYID", split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), show_colcounts = TRUE) |> + split_cols_by("STUDYID", + split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), + show_colcounts = TRUE) |> split_rows_by("SEX", split_fun = keep_split_levels(c("F", "M"))) |> analyze(c("AGE", "BMRKR1"), afun = tpose_afun, show_labels = "hidden") From f34b8718229c1702732a8fcb2ef27bd8c93f4054 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Nov 2025 00:56:33 +0000 Subject: [PATCH 5/7] [skip style] [skip vbump] Restyle files --- vignettes/guided_intermediate_split_reqs.Rmd | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/vignettes/guided_intermediate_split_reqs.Rmd b/vignettes/guided_intermediate_split_reqs.Rmd index 65074dd471..96468723d3 100644 --- a/vignettes/guided_intermediate_split_reqs.Rmd +++ b/vignettes/guided_intermediate_split_reqs.Rmd @@ -461,8 +461,9 @@ my_combo_df <- tribble( lyt_tpose_cols_only <- basic_table() |> split_cols_by("ARM", show_colcounts = TRUE) |> split_cols_by("STUDYID", - split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), - show_colcounts = TRUE) + split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), + show_colcounts = TRUE + ) build_table(lyt_tpose_cols_only, ex_adsl) ``` @@ -489,8 +490,9 @@ meets our requirements, we can then fully create our table: lyt_tpose_full <- basic_table() |> split_cols_by("ARM", show_colcounts = TRUE) |> split_cols_by("STUDYID", - split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), - show_colcounts = TRUE) |> + split_fun = add_combo_levels(my_combo_df, keep_levels = combo_df$valname), + show_colcounts = TRUE + ) |> split_rows_by("SEX", split_fun = keep_split_levels(c("F", "M"))) |> analyze(c("AGE", "BMRKR1"), afun = tpose_afun, show_labels = "hidden") From 91bd83410c4f51d574c5ce2523a0f29d36b3a451 Mon Sep 17 00:00:00 2001 From: Joe Zhu Date: Fri, 14 Nov 2025 07:23:51 +0800 Subject: [PATCH 6/7] Trigger Build From 733ad2b01dd2cab85599b48731f84f425dcbe6b7 Mon Sep 17 00:00:00 2001 From: Joe Zhu Date: Fri, 14 Nov 2025 07:58:03 +0800 Subject: [PATCH 7/7] Apply suggestion from @shajoezhu Signed-off-by: Joe Zhu --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 51c540f8a7..885ec0495f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,7 @@ ## rtables 0.6.13.9004 ### New Features - * Added Guided Tour section to the pkgdown site + * Added Guided Tour section to the `pkgdown` site * Added vignette: Guided Tour (Intermediate) * Added vignette: Guided Tour (Intermediate) - Translating Shells To Layouts @gmbecker * Added vignette: Guided Tour (Intermediate) - Identifying Required Analysis Behavior @gmbecker