The fourth example produces an Adverse Events table by severity, with treatment groups on separate pages. The report shows statistics for All Adverse Events and System Organ Class/Preferred Term.
Note the following about this example:
libname()
function from the libr package makes it easy
to load the entire data library.library(tidyverse)
library(sassy)
options("logr.autolog" = TRUE,
"logr.notes" = FALSE)
# Get Data ----------------------------------------------------------------
# Get path to temp directory
<- tempdir()
tmp
# Get path to sample data
<- system.file("extdata", package = "sassy")
pkg
# Open log
<- log_open(file.path(tmp, "example4.log"))
lgpth
sep("Prepare Data")
# Create libname for csv data
libname(sdtm, pkg, "csv")
# Load data into workspace
lib_load(sdtm)
sep("Prepare table data")
<- sdtm.AE |>
dat inner_join(select(sdtm.DM, USUBJID, ARM, ARMCD),
c("USUBJID" = "USUBJID"),
keep = FALSE) |>
filter(ARM != "SCREEN FAILURE")
put("Get population counts")
<- dat |>
arm_pop select(USUBJID, ARM) |>
distinct() |>
count(ARM) |>
deframe() |> put()
put ("Create lookup for AE severity")
<- c(MILD = 1, MODERATE = 2, SEVERE = 3) |> put()
sevn
put("Subset ADAE for needed rows and columns")
<- dat |>
df_sub mutate(AESEVN = sevn[AESEV]) |>
select(USUBJID, ARM, AESEV, AESEVN, AESOC, AEDECOD) |>
distinct() |>
put()
# Perform Calculations ----------------------------------------------------
put("Create template for needed ARM columns")
<- paste0(c(rep("ARM A_", 3), rep("ARM B_", 3), rep("ARM C_", 3),
col_template rep("ARM D_", 3)), rep(c(1, 2, 3), 3))
put("Identify and count highest severity grade for each subject")
<- df_sub |> arrange(USUBJID, AESOC, AEDECOD, AESEVN) |>
df1 group_by(USUBJID, ARM, AESOC, AEDECOD) |>
mutate(max_sev = ifelse(row_number() == n(), TRUE, FALSE)) |>
filter(max_sev == TRUE) |>
group_by(ARM, AESOC, AEDECOD, AESEVN) |>
summarize(cnt = n()) |>
pivot_wider(names_from = c(ARM, AESEVN),
values_from = cnt,
values_fill = 0) |>
put()
put("Fill in missing columns where there were no events.")
for (nm in col_template) {
if (!nm %in% names(df1))
<- 0
df1[[nm]]
}put(df1)
put("Format counts and percents for each column")
<- df1 |>
df_events transmute(AESOC = AESOC,
AEDECOD = str_to_title(AEDECOD),
`ARM A_1` = fmt_cnt_pct(`ARM A_1`, arm_pop["ARM A"]),
`ARM A_2` = fmt_cnt_pct(`ARM A_2`, arm_pop["ARM A"]),
`ARM A_3` = fmt_cnt_pct(`ARM A_3`, arm_pop["ARM A"]),
`ARM B_1` = fmt_cnt_pct(`ARM B_1`, arm_pop["ARM B"]),
`ARM B_2` = fmt_cnt_pct(`ARM B_2`, arm_pop["ARM B"]),
`ARM B_3` = fmt_cnt_pct(`ARM B_3`, arm_pop["ARM B"]),
`ARM C_1` = fmt_cnt_pct(`ARM C_1`, arm_pop["ARM C"]),
`ARM C_2` = fmt_cnt_pct(`ARM C_2`, arm_pop["ARM C"]),
`ARM C_3` = fmt_cnt_pct(`ARM C_3`, arm_pop["ARM C"]),
`ARM D_1` = fmt_cnt_pct(`ARM D_1`, arm_pop["ARM D"]),
`ARM D_2` = fmt_cnt_pct(`ARM D_2`, arm_pop["ARM D"]),
`ARM D_3` = fmt_cnt_pct(`ARM D_3`, arm_pop["ARM D"])) |>
arrange(AESOC, AEDECOD) |>
ungroup() |>
put()
put("Get counts for All Adverse Events")
<- df_sub |>
df2 select(USUBJID, ARM, AESEVN) |>
arrange(USUBJID, AESEVN) |>
group_by(USUBJID) |>
mutate(max_sev = ifelse(row_number() == n(), TRUE, FALSE)) |>
filter(max_sev == TRUE) |>
group_by(ARM, AESEVN) |>
summarize(cnt = n()) |>
pivot_wider(names_from = c(ARM, AESEVN),
values_from = cnt,
values_fill = 0) |>
ungroup() |>
put()
put("Fill in missing columns where there were no events.")
for (nm in col_template) {
if (!nm %in% names(df2))
<- 0
df2[[nm]]
}put(df2)
put("Format counts and percents for all adverse events.")
<- df2 |>
df_all transmute(AESOC = "All System Organ Classes",
AEDECOD = "All Adverse Events",
`ARM A_1` = fmt_cnt_pct(`ARM A_1`, arm_pop["ARM A"]),
`ARM A_2` = fmt_cnt_pct(`ARM A_2`, arm_pop["ARM A"]),
`ARM A_3` = fmt_cnt_pct(`ARM A_3`, arm_pop["ARM A"]),
`ARM B_1` = fmt_cnt_pct(`ARM B_1`, arm_pop["ARM B"]),
`ARM B_2` = fmt_cnt_pct(`ARM B_2`, arm_pop["ARM B"]),
`ARM B_3` = fmt_cnt_pct(`ARM B_3`, arm_pop["ARM B"]),
`ARM C_1` = fmt_cnt_pct(`ARM C_1`, arm_pop["ARM C"]),
`ARM C_2` = fmt_cnt_pct(`ARM C_2`, arm_pop["ARM C"]),
`ARM C_3` = fmt_cnt_pct(`ARM C_3`, arm_pop["ARM C"]),
`ARM D_1` = fmt_cnt_pct(`ARM D_1`, arm_pop["ARM D"]),
`ARM D_2` = fmt_cnt_pct(`ARM D_2`, arm_pop["ARM D"]),
`ARM D_3` = fmt_cnt_pct(`ARM D_3`, arm_pop["ARM D"])) |>
put()
# Final Data --------------------------------------------------------------
sep("Create final data frame")
<- bind_rows(df_all, df_events) |> put()
final
# Print Report ----------------------------------------------------------
sep("Create and print report")
put("Create table object")
<- create_table(final, first_row_blank = TRUE, width = 9) |>
tbl column_defaults(from = `ARM A_1`, to = `ARM D_3`, width = 1) |>
spanning_header("ARM A_1", "ARM A_3", label = "ARM A", n = arm_pop["ARM A"]) |>
spanning_header("ARM B_1", "ARM B_3", label = "ARM B", n = arm_pop["ARM B"]) |>
spanning_header("ARM C_1", "ARM C_3", label = "ARM C", n = arm_pop["ARM C"]) |>
spanning_header("ARM D_1", "ARM D_3", label = "ARM D", n = arm_pop["ARM D"]) |>
stub(vars = c("AESOC", "AEDECOD"), label = "System Organ Class\n Preferred Term", width = 5) |>
define(AESOC, blank_after = TRUE, label_row = TRUE) |>
define(AEDECOD, indent = .25) |>
define(`ARM A_1`, align = "center", label = "Mild") |>
define(`ARM A_2`, align = "center", label = "Moderate") |>
define(`ARM A_3`, align = "center", label = "Severe") |>
define(`ARM B_1`, align = "center", label = "Mild", page_wrap = TRUE) |>
define(`ARM B_2`, align = "center", label = "Moderate") |>
define(`ARM B_3`, align = "center", label = "Severe") |>
define(`ARM C_1`, align = "center", label = "Mild", page_wrap = TRUE) |>
define(`ARM C_2`, align = "center", label = "Moderate") |>
define(`ARM C_3`, align = "center", label = "Severe") |>
define(`ARM D_1`, align = "center", label = "Mild", page_wrap = TRUE) |>
define(`ARM D_2`, align = "center", label = "Moderate") |>
define(`ARM D_3`, align = "center", label = "Severe")
<- file.path(tmp, "output/example4.rtf")
pth
put("Create report object")
<- create_report(pth, output_type = "RTF",
rpt font = "Arial") |>
options_fixed(font_size = 10) |>
page_header("Sponsor: Company", "Study: ABC") |>
titles("Table 5.0", "Adverse Events by Maximum Severity",
bold = TRUE, font_size = 12) |>
add_content(tbl) |>
footnotes("Program: AE_Table.R",
"Note: Adverse events were coded using MedDRA Version 9.1") |>
page_footer(Sys.time(), "Confidential", "Page [pg] of [tpg]")
put("Print report")
write_report(rpt) |> put()
# Clean Up ----------------------------------------------------------------
# Remove library from workspace
lib_unload(sdtm)
# Close log
log_close()
# View files
# file.show(pth)
# file.show(lgpth)
Here are the first four pages of the output report:
Here is part of the log from the above example:
=========================================================================
Log Path: C:/Users/dbosa/AppData/Local/Temp/RtmpKC93lu/log/example4.log
Working Directory: C:/packages/Testing
User Name: dbosa
R Version: 4.0.5 (2021-03-31)
Machine: SOCRATES x86-64
Operating System: Windows 10 x64 build 19041
Log Start Time: 2021-06-27 11:30:01
=========================================================================
=========================================================================
Prepare Data
=========================================================================
# library 'sdtm': 4 items
- attributes: csv not loaded
- path: C:/Users/dbosa/Documents/R/win-library/4.0/sassy/extdata
- items:
Name Extension Rows Cols Size LastModified
1 AE csv 150 27 88.1 Kb 2021-04-04 11:55:58
2 DM csv 87 24 45.2 Kb 2021-04-04 11:55:58
3 SV csv 685 10 69.9 Kb 2021-04-04 11:55:58
4 VS csv 3358 17 467 Kb 2021-04-04 11:55:58
lib_load: library 'sdtm' loaded
=========================================================================
Prepare table data
=========================================================================
select: dropped 21 variables (STUDYID, DOMAIN, SUBJID, RFSTDTC, RFENDTC, …)
inner_join: added 2 columns (ARM, ARMCD)
> rows only in x ( 0)
> rows only in y ( 30)
> matched rows 150
> =====
> rows total 150
filter: removed 5 rows (3%), 145 rows remaining
Get population counts
select: dropped 27 variables (STUDYID, DOMAIN, AESEQ, AETERM, AELLT, …)
distinct: removed 90 rows (62%), 55 rows remaining
count: now 4 rows and 2 columns, ungrouped
ARM A ARM B ARM C ARM D
14 14 14 13
Create lookup for AE severity
MILD MODERATE SEVERE
1 2 3
Subset ADAE for needed rows and columns
mutate: new variable 'AESEVN' (double) with 3 unique values and 0% NA
select: dropped 24 variables (STUDYID, DOMAIN, AESEQ, AETERM, AELLT, …)
distinct: removed 18 rows (12%), 127 rows remaining
# A tibble: 127 x 6
USUBJID ARM AESEV AESEVN AESOC AEDECOD
<chr> <chr> <chr> <dbl> <chr> <chr>
1 ABC-01-049 ARM D MODERATE 2 Investigations BLOOD GLUCOSE INCREASED
2 ABC-01-049 ARM D MODERATE 2 Investigations BLOOD TRIGLYCERIDES INCREASED
3 ABC-01-049 ARM D MILD 1 Nervous system disorders HEADACHE
4 ABC-01-049 ARM D MODERATE 2 Investigations LABORATORY TEST ABNORMAL
5 ABC-01-049 ARM D MILD 1 Musculoskeletal and connective tissue disorders MUSCULOSKELETAL DISCOMFORT
6 ABC-01-050 ARM B MILD 1 Skin and subcutaneous tissue disorders RASH
7 ABC-01-050 ARM B MILD 1 Respiratory, thoracic and mediastinal disorders UPPER RESPIRATORY TRACT CONGEST~
8 ABC-01-051 ARM A MILD 1 Nervous system disorders HEADACHE
9 ABC-01-051 ARM A MILD 1 General disorders and administration site cond~ INFLUENZA LIKE ILLNESS
10 ABC-01-051 ARM A MILD 1 Respiratory, thoracic and mediastinal disorders LOWER RESPIRATORY TRACT INFLAMM~
# ... with 117 more rows
Create template for needed ARM columns
Identify and count highest severity grade for each subject
group_by: 4 grouping variables (USUBJID, ARM, AESOC, AEDECOD)
mutate (grouped): new variable 'max_sev' (logical) with 2 unique values and 0% NA
filter (grouped): removed one row (1%), 126 rows remaining
group_by: 4 grouping variables (ARM, AESOC, AEDECOD, AESEVN)
summarize: now 101 rows and 5 columns, 3 group variables remaining (ARM, AESOC, AEDECOD)
pivot_wider: reorganized (ARM, AESEVN, cnt) into (ARM A_2, ARM A_1, ARM B_1, ARM B_2, ARM B_3, …) [was 101x5, now 73x11]
...
=========================================================================
Create final data frame
=========================================================================
# A tibble: 74 x 14
AESOC AEDECOD `ARM A_1` `ARM A_2` `ARM A_3` `ARM B_1` `ARM B_2` `ARM B_3` `ARM C_1` `ARM C_2` `ARM C_3` `ARM D_1`
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 All ~ All Ad~ 6 ( 42.9~ 8 ( 57.1~ 0 ( 0.0~ 8 ( 57.1~ 4 ( 28.6~ 2 ( 14.3~ 8 ( 57.1~ 6 ( 42.9~ 0 ( 0.0~ 7 ( 53.8~
2 Bloo~ Neutro~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 1 ( 7.1~ 0 ( 0.0~ 0 ( 0.0~
3 Card~ Palpit~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 1 ( 7.7~
4 Card~ Sinus ~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 1 ( 7.7~
5 Cong~ Dermoi~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 1 ( 7.1~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~
6 Ear ~ Vertigo 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 1 ( 7.1~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~
7 Endo~ Parath~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 1 ( 7.1~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~
8 Gast~ Diarrh~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 1 ( 7.1~ 1 ( 7.1~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~
9 Gast~ Food P~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 1 ( 7.1~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~
10 Gast~ Tootha~ 0 ( 0.0~ 1 ( 7.1~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 0 ( 0.0~ 2 ( 15.4~
# ... with 64 more rows, and 2 more variables: ARM D_2 <chr>, ARM D_3 <chr>
=========================================================================
Create and print report
=========================================================================
Create table object
Create report object
Print report
# A report specification: 16 pages
- file_path: 'C:\Users\dbosa\AppData\Local\Temp\RtmpKC93lu/output/example4.rtf'
- output_type: RTF
- units: inches
- orientation: landscape
- margins: top 0.5 bottom 0.5 left 1 right 1
- line size/count: 107/47
- page_header: left=Sponsor: Company right=Study: ABC
- title 1: 'Table 5.0'
- title 2: 'Adverse Events by Maximum Severity'
- footnote 1: 'Program: AE_Table.R'
- footnote 2: 'Note: Adverse events were coded using MedDRA Version 9.1'
- page_footer: left=2021-06-27 11:30:02 center=Confidential right=Page [pg] of [tpg]
- content:
# A table specification:
- data: tibble 'final' 74 rows 14 cols
- show_cols: all
- use_attributes: all
- width: 9
- spanning_header: from='ARM A_1' to='ARM A_3' 'ARM A' level=1
- spanning_header: from='ARM B_1' to='ARM B_3' 'ARM B' level=1
- spanning_header: from='ARM C_1' to='ARM C_3' 'ARM C' level=1
- spanning_header: from='ARM D_1' to='ARM D_3' 'ARM D' level=1
- stub: AESOC AEDECOD 'System Organ Class
Preferred Term' width=5 align='left'
- define: AESOC dedupe='TRUE'
- define: AEDECOD
- define: ARM A_1 'Mild' align='center'
- define: ARM A_2 'Moderate' align='center'
- define: ARM A_3 'Severe' align='center'
- define: ARM B_1 'Mild' align='center' page_wrap='TRUE'
- define: ARM B_2 'Moderate' align='center'
- define: ARM B_3 'Severe' align='center'
- define: ARM C_1 'Mild' align='center' page_wrap='TRUE'
- define: ARM C_2 'Moderate' align='center'
- define: ARM C_3 'Severe' align='center'
- define: ARM D_1 'Mild' align='center' page_wrap='TRUE'
- define: ARM D_2 'Moderate' align='center'
- define: ARM D_3 'Severe' align='center'
# A report specification: 16 pages
- file_path: 'C:\Users\dbosa\AppData\Local\Temp\RtmpKC93lu/output/example4.rtf'
- output_type: RTF
- units: inches
- orientation: landscape
- margins: top 0.5 bottom 0.5 left 1 right 1
- line size/count: 107/47
- page_header: left=Sponsor: Company right=Study: ABC
- title 1: 'Table 5.0'
- title 2: 'Adverse Events by Maximum Severity'
- footnote 1: 'Program: AE_Table.R'
- footnote 2: 'Note: Adverse events were coded using MedDRA Version 9.1'
- page_footer: left=2021-06-27 11:30:02 center=Confidential right=Page [pg] of [tpg]
- content:
# A table specification:
- data: tibble 'final' 74 rows 14 cols
- show_cols: all
- use_attributes: all
- width: 9
- spanning_header: from='ARM A_1' to='ARM A_3' 'ARM A' level=1
- spanning_header: from='ARM B_1' to='ARM B_3' 'ARM B' level=1
- spanning_header: from='ARM C_1' to='ARM C_3' 'ARM C' level=1
- spanning_header: from='ARM D_1' to='ARM D_3' 'ARM D' level=1
- stub: AESOC AEDECOD 'System Organ Class
Preferred Term' width=5 align='left'
- define: AESOC dedupe='TRUE'
- define: AEDECOD
- define: ARM A_1 'Mild' align='center'
- define: ARM A_2 'Moderate' align='center'
- define: ARM A_3 'Severe' align='center'
- define: ARM B_1 'Mild' align='center' page_wrap='TRUE'
- define: ARM B_2 'Moderate' align='center'
- define: ARM B_3 'Severe' align='center'
- define: ARM C_1 'Mild' align='center' page_wrap='TRUE'
- define: ARM C_2 'Moderate' align='center'
- define: ARM C_3 'Severe' align='center'
- define: ARM D_1 'Mild' align='center' page_wrap='TRUE'
- define: ARM D_2 'Moderate' align='center'
- define: ARM D_3 'Severe' align='center'
lib_sync: synchronized data in library 'sdtm'
lib_unload: library 'sdtm' unloaded
=========================================================================
Log End Time: 2021-06-27 11:30:04
Log Elapsed Time: 0 00:00:03
=========================================================================
Next: Example 5: VS Table