Overview
This vignette demonstrates how to generate a static AE-specific table reporting patients with drug-related adverse events by treatment group.
The workflow uses three functions from metalite.ae:
-
prepare_ae_specific()prepares the analysis datasets. -
format_ae_specific()formats the results for reporting. -
tlf_ae_specific()creates the RTF table.
Related vignettes explain how to customize displayed columns and filter or sort rows. This guide also covers basic RTF customization and mock output.
An example output is shown below.
Generate an AE-specific table
The example uses ADSL and ADAE data from the forestly package.
Step 1: Define metadata
# Define metadata
adsl <- forestly::forestly_adsl
adae <- forestly::forestly_adae
adsl$TRT01A <- factor(
adsl$TRT01A,
levels = c("Xanomeline Low Dose", "Placebo"),
labels = c("Low Dose", "Placebo")
)
adae$TRTA <- factor(
adae$TRTA,
levels = c("Xanomeline Low Dose", "Placebo"),
labels = c("Low Dose", "Placebo")
)
analysis_plan <- metalite::plan(
analysis = "ae_specific",
population = "apat",
observation = "wk12",
parameter = "rel"
)
meta <- metalite::meta_adam(observation = adae, population = adsl) |>
metalite::define_plan(analysis_plan) |>
metalite::define_population(
name = "apat",
var = c(
"USUBJID", "SAFFL", "TRT01A", "TRTDUR",
"SITEID", "SEX", "RACE", "AGE"
),
group = "TRT01A",
subset = SAFFL == "Y",
label = "All Participants as Treated"
) |>
metalite::define_observation(
name = "wk12",
var = c(
"USUBJID", "SAFFL", "TRTA", "AEDECOD", "AEBODSYS", "AEREL",
"AESER", "AEOUT", "AEACN", "AESDTH", "ASTDT", "AENDT"
),
group = "TRTA",
subset = SAFFL == "Y",
label = "Weeks 0 to 12"
) |>
metalite::define_parameter(
name = "rel",
term1 = "Drug-Related",
term2 = "",
subset = AEREL %in% c("POSSIBLE", "PROBABLE"),
var = "AEDECOD",
soc = "AEBODSYS",
label = "Drug-related AEs"
) |>
metalite::define_analysis(
name = "ae_specific",
title = "Participants with Drug-Related Adverse Events"
) |>
metalite::meta_build()Click to show the output
meta
#> ADaM metadata:
#> .$data_population Population data with 170 subjects
#> .$data_observation Observation data with 736 records
#> .$plan Analysis plan with 1 plans
#>
#>
#> Analysis population type:
#> name id group
#> 1 'apat' 'USUBJID' 'TRT01A'
#> var subset
#> 1 USUBJID, SAFFL, TRT01A, TRTDUR, SITEID, SEX, RACE, AGE SAFFL == 'Y'
#> label
#> 1 'All Participants as Treated'
#>
#>
#> Analysis observation type:
#> name id group
#> 1 'wk12' 'USUBJID' 'TRTA'
#> var
#> 1 USUBJID, SAFFL, TRTA, AEDECOD, AEBODSYS, AEREL, AESER, AEOUT, AEACN, AESDTH, ASTDT, AENDT
#> subset label
#> 1 SAFFL == 'Y' 'Weeks 0 to 12'
#>
#>
#> Analysis parameter type:
#> name label subset
#> 1 'rel' 'Drug-related AEs' AEREL %in% c('POSSIBLE', 'PROBABLE')
#>
#>
#> Analysis function:
#> name label
#> 1 'ae_specific' 'Table: specific adverse event'Analysis preparation
prepare_ae_specific() uses the population, observation,
and parameter definitions in meta to calculate the
AE-specific analysis results. It returns an outdata object
for formatting and reporting.
outdata <- prepare_ae_specific(
meta,
population = "apat",
observation = "wk12",
parameter = "rel"
)
outdata
#> List of 15
#> $ meta :List of 7
#> $ population : chr "apat"
#> $ observation : chr "wk12"
#> $ parameter : chr "rel"
#> $ n :'data.frame': 114 obs. of 3 variables:
#> $ order : num [1:114] 1 100 200 900 1000 ...
#> $ group : chr [1:3] "Low Dose" "Placebo" "Total"
#> $ reference_group: num 2
#> $ prop :'data.frame': 114 obs. of 3 variables:
#> $ diff :'data.frame': 114 obs. of 1 variable:
#> $ n_pop :'data.frame': 1 obs. of 3 variables:
#> $ name : chr [1:114] "Participants in population" "with one or more drug-related adverse events" "with no drug-related adverse events" "" ...
#> $ soc_name : chr [1:114] NA NA NA NA ...
#> $ components : chr [1:2] "soc" "par"
#> $ prepare_call : language prepare_ae_specific(meta = meta, population = "apat", observation = "wk12", parameter = "rel")The statistic columns follow the treatment-group order in
outdata$group.
outdata$group
#> [1] "Low Dose" "Placebo" "Total"Rows follow the order defined by outdata$order and
outdata$name.
head(data.frame(outdata$order, outdata$name))
#> outdata.order outdata.name
#> 1 1 Participants in population
#> 2 100 with one or more drug-related adverse events
#> 3 200 with no drug-related adverse events
#> 4 900
#> 5 1000 Cardiac disorders
#> 6 1018 Atrial fibrillation-
n_pop: number of participants in the analysis population.
outdata$n_pop
#> n_1 n_2 n_3
#> 1 84 86 170-
n: number of participants with an AE.
head(outdata$n)
#> n_1 n_2 n_3
#> 1 84 86 170
#> 2 73 44 117
#> 3 11 42 53
#> 4 NA NA NA
#> 98 7 6 13
#> 22 0 1 1-
prop: proportion of participants with an AE.
head(outdata$prop)
#> prop_1 prop_2 prop_3
#> 1 NA NA NA
#> 2 86.904762 51.162791 68.8235294
#> 3 13.095238 48.837209 31.1764706
#> 4 NA NA NA
#> 98 8.333333 6.976744 7.6470588
#> 22 0.000000 1.162791 0.5882353-
diff: risk difference compared with thereference_group.
head(outdata$diff)
#> diff_1
#> 1 NA
#> 2 35.741971
#> 3 -35.741971
#> 4 NA
#> 98 1.356589
#> 22 -1.162791Format output
format_ae_specific() converts the analysis results into
a production-ready table dataset.
tbl <- outdata |> format_ae_specific()
head(tbl$tbl)
#> name n_1 prop_1 n_2 prop_2 n_3
#> 1 Participants in population 84 <NA> 86 <NA> 170
#> 2 with one or more drug-related adverse events 73 (86.9) 44 (51.2) 117
#> 3 with no drug-related adverse events 11 (13.1) 42 (48.8) 53
#> 4 NA <NA> NA <NA> NA
#> 98 Cardiac disorders 7 (8.3) 6 (7.0) 13
#> 22 Atrial fibrillation 0 (0.0) 1 (1.2) 1
#> prop_3
#> 1 <NA>
#> 2 (68.8)
#> 3 (31.2)
#> 4 <NA>
#> 98 (7.6)
#> 22 (0.6)Additional statistics
Use display to select and order statistics. For example,
include "diff" to show the risk difference.
tbl <- outdata |> format_ae_specific(display = c("n", "prop", "diff"))
head(tbl$tbl)
#> name n_1 prop_1 n_2 prop_2
#> 1 Participants in population 84 <NA> 86 <NA>
#> 2 with one or more drug-related adverse events 73 (86.9) 44 (51.2)
#> 3 with no drug-related adverse events 11 (13.1) 42 (48.8)
#> 4 NA <NA> NA <NA>
#> 98 Cardiac disorders 7 (8.3) 6 (7.0)
#> 22 Atrial fibrillation 0 (0.0) 1 (1.2)
#> between_tbl
#> 1 <NA>
#> 2 35.7
#> 3 -35.7
#> 4 <NA>
#> 98 1.4
#> 22 -1.2Use extend_ae_specific_inference() to add confidence
intervals and p-values for the risk difference based on the Miettinen
and Nurminen (M&N) method. For details, see the rate
compare vignette.
tbl <- outdata |>
extend_ae_specific_inference() |>
format_ae_specific(display = c("n", "prop", "diff", "diff_ci"))
head(tbl$tbl)
#> name n_1 prop_1 n_2 prop_2 diff_1
#> 1 Participants in population 84 <NA> 86 <NA> <NA>
#> 2 with one or more drug-related adverse events 73 (86.9) 44 (51.2) 35.7
#> 3 with no drug-related adverse events 11 (13.1) 42 (48.8) -35.7
#> 4 NA <NA> NA <NA> <NA>
#> 98 Cardiac disorders 7 (8.3) 6 (7.0) 1.4
#> 22 Atrial fibrillation 0 (0.0) 1 (1.2) -1.2
#> ci_1
#> 1 (-4.4, 4.3)
#> 2 (22.4, 48.0)
#> 3 (-48.0, -22.4)
#> 4 <NA>
#> 98 (-7.3, 10.2)
#> 22 (-6.3, 3.3)Use extend_ae_specific_duration() to add the mean AE
duration.
tbl <- outdata |>
extend_ae_specific_duration(duration_var = "ADURN") |>
format_ae_specific(display = c("n", "prop", "dur"))
head(tbl$tbl)
#> name n_1 prop_1 dur_1 n_2
#> 1 Participants in population 84 <NA> <NA> 86
#> 2 with one or more drug-related adverse events 73 (86.9) 27.2 ( 3.2) 44
#> 3 with no drug-related adverse events 11 (13.1) <NA> 42
#> 4 NA <NA> <NA> NA
#> 98 Cardiac disorders 7 (8.3) 16.1 ( 3.5) 6
#> 22 Atrial fibrillation 0 (0.0) <NA> 1
#> prop_2 dur_2
#> 1 <NA> <NA>
#> 2 (51.2) 29.0 ( 3.5)
#> 3 (48.8) <NA>
#> 4 <NA> <NA>
#> 98 (7.0) 27.1 ( 5.9)
#> 22 (1.2) 6.0Use extend_ae_specific_events() to add the AE count and
the mean number of events per participant.
tbl <- outdata |>
extend_ae_specific_events() |>
format_ae_specific(display = c("n", "prop", "events_count", "events_avg"))
head(tbl$tbl)
#> name n_1 prop_1 eventsavg_1
#> 1 Participants in population 84 <NA> <NA>
#> 2 with one or more drug-related adverse events 73 (86.9) 2.5 ( 0.3)
#> 3 with no drug-related adverse events 11 (13.1) <NA>
#> 4 NA <NA> <NA>
#> 98 Cardiac disorders 7 (8.3) 1.9 ( 0.4)
#> 22 Atrial fibrillation 0 (0.0) <NA>
#> eventscount_1 n_2 prop_2 eventsavg_2 eventscount_2
#> 1 NA 86 <NA> <NA> NA
#> 2 292 44 (51.2) 1.1 ( 0.2) 133
#> 3 NA 42 (48.8) <NA> NA
#> 4 NA NA <NA> <NA> NA
#> 98 13 6 (7.0) 2.3 ( 0.6) 14
#> 22 0 1 (1.2) 1.0 1Use filter_method and filter_criteria to
retain rows that meet a minimum incidence threshold in at least one
treatment group:
-
filter_method = "count"applies the threshold to participant counts. -
filter_method = "percent"applies the threshold to incidence percentages from 0 to 100. -
filter_criteriasets the minimum count or percentage to retain.
tbl <- outdata |>
extend_ae_specific_events() |>
format_ae_specific(
display = c("n", "prop", "events_count", "events_avg"),
filter_method = "percent",
filter_criteria = 6
)
head(tbl$tbl)
#> name n_1 prop_1 eventsavg_1
#> 1 Participants in population 84 <NA> <NA>
#> 2 with one or more drug-related adverse events 73 (86.9) 2.5 ( 0.3)
#> 3 with no drug-related adverse events 11 (13.1) <NA>
#> 4 NA <NA> <NA>
#> 98 Cardiac disorders 7 (8.3) 1.9 ( 0.4)
#> 102 Gastrointestinal disorders 8 (9.5) 1.9 ( 0.4)
#> eventscount_1 n_2 prop_2 eventsavg_2 eventscount_2
#> 1 NA 86 <NA> <NA> NA
#> 2 292 44 (51.2) 1.1 ( 0.2) 133
#> 3 NA 42 (48.8) <NA> NA
#> 4 NA NA <NA> <NA> NA
#> 98 13 6 (7.0) 2.3 ( 0.6) 14
#> 102 15 4 (4.7) 1.8 ( 0.5) 7The example retains rows with an incidence of at least 6% in any treatment group.
Use sort_order and sort_column to control
row order:
-
sort_order = "alphabetical"sorts rows by label. -
sort_order = "count_des"sorts counts in descending order. -
sort_order = "count_asc"sorts counts in ascending order. -
sort_columnselects the treatment group whose counts determine the order.
tbl <- outdata |>
extend_ae_specific_events() |>
format_ae_specific(
display = c("n", "prop", "events_count", "events_avg"),
sort_order = c("count_des"),
sort_column = c("Placebo")
)
head(tbl$tbl)
#> name n_1 prop_1 eventsavg_1
#> 1 Participants in population 84 <NA> <NA>
#> 2 with one or more drug-related adverse events 73 (86.9) 2.5 ( 0.3)
#> 3 with no drug-related adverse events 11 (13.1) <NA>
#> 4 NA <NA> <NA>
#> 98 Cardiac disorders 7 (8.3) 1.9 ( 0.4)
#> 63 Myocardial infarction 1 (1.2) 2.0
#> eventscount_1 n_2 prop_2 eventsavg_2 eventscount_2
#> 1 NA 86 <NA> <NA> NA
#> 2 292 44 (51.2) 1.1 ( 0.2) 133
#> 3 NA 42 (48.8) <NA> NA
#> 4 NA NA <NA> <NA> NA
#> 98 13 6 (7.0) 2.3 ( 0.6) 14
#> 63 2 2 (2.3) 1.0 ( 0.0) 2Mock data preparation
Set mock = TRUE to create placeholder values while
preserving the planned table structure. The result is a starting point
and may require customization for study-specific requirements.
tbl <- outdata |> format_ae_specific(mock = TRUE)
head(tbl$tbl)
#> name n_1 prop_1 n_2 prop_2 n_3
#> 1 Participants in population xx <NA> xx <NA> xxx
#> 2 with one or more drug-related adverse events xx (xx.x) xx (xx.x) xxx
#> 3 with no drug-related adverse events xx (xx.x) xx (xx.x) xx
#> 4 <NA> <NA> <NA> <NA> <NA>
#> 5 Cardiac disorders x (x.x) x (x.x) xx
#> 6 Atrial fibrillation x (x.x) x (x.x) x
#> prop_3
#> 1 <NA>
#> 2 (xx.x)
#> 3 (xx.x)
#> 4 <NA>
#> 5 (x.x)
#> 6 (x.x)RTF tables
Pass the formatted output to tlf_ae_specific() to create
the RTF table.
outdata |>
format_ae_specific() |>
tlf_ae_specific(
meddra_version = "24.0",
source = "Source: [CDISCpilot: adam-adsl; adae]",
analysis = "ae_specific", # Provide analysis type defined in meta$analysis
path_outtable = tempfile(fileext = ".rtf")
)
#> The output is saved in/tmp/RtmpYlRLzI/file1e7167825d85.rtfUse arguments such as col_rel_width,
text_font_size, and orientation to customize
the table layout.
outdata |>
format_ae_specific() |>
tlf_ae_specific(
meddra_version = "24.0",
source = "Source: [CDISCpilot: adam-adsl; adae]",
analysis = "ae_specific", # Provide analysis type defined in meta$analysis
col_rel_width = c(6, rep(1, 6)),
text_font_size = 8,
orientation = "landscape",
path_outtable = tempfile(fileext = ".rtf")
)
#> The output is saved in/tmp/RtmpYlRLzI/file1e71169846db.rtfMock output can be written to RTF in the same way.
outdata |>
format_ae_specific(mock = TRUE) |>
tlf_ae_specific(
meddra_version = "24.0",
source = "Source: [CDISCpilot: adam-adsl; adae]",
analysis = "ae_specific", # Provide analysis type defined in meta$analysis
path_outtable = tempfile(fileext = ".rtf")
)
#> The output is saved in/tmp/RtmpYlRLzI/file1e71e8026c7.rtf