--- title: "Complete Example 2" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{example2} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) options(rmarkdown.html_vignette.check_title = FALSE) ``` ## Program Here is another example of a complete program that demonstrates several of the key functions in the **libr** package. The example also shows how the package integrates with **sassy**. ```{r eval=FALSE, echo=TRUE} library(sassy) options("logr.autolog" = TRUE, "logr.notes" = FALSE) # Get temp location for log and report output tmp <- tempdir() # Open log lf <- log_open(file.path(tmp, "example1.log")) # Prepare Data ------------------------------------------------------------ sep("Prepare Data") # Get path to sample data pkg <- system.file("extdata", package = "libr") # Create libname for csv data libname(sdtm, pkg, "csv", quiet = TRUE) put("Join and prepare data") put("Join DM to VS and keep desired columns") datastep(sdtm$DM, merge = sdtm$VS, merge_by = USUBJID, keep = v(USUBJID, VSTESTCD, VISIT, VISITNUM, VSSTRESN, ARM, VSBLFL), where = expression(VSTESTCD %in% c("PULSE", "RESP", "TEMP", "DIABP", "SYSBP") & !(VISIT == "SCREENING" & VSBLFL != "Y")), {}) -> dm_joined put("Sort by variables") proc_sort(dm_joined, by = v(USUBJID, VSTESTCD, VISITNUM)) -> dm_sorted put("Differentiate baseline from treated vital signs") datastep(dm_sorted, by = v(USUBJID, VSTESTCD), retain = list(BSTRESN = 0), { # Combine treatment groups # And distinguish baseline time points if (ARM == "ARM A") { if (VSBLFL %eq% "Y") { GRP <- "A_BASE" } else { GRP <- "A_TRT" } } else { if (VSBLFL %eq% "Y") { GRP <- "O_BASE" } else { GRP <- "O_TRT" } } # Populate baseline value if (first.) BSTRESN = VSSTRESN }) -> prep put("Get population counts") pop_A <- subset(prep, GRP == "A_BASE", v(USUBJID, GRP)) |> proc_sort(options = nodupkey) |> proc_freq(tables = GRP, options = v(nocum, nonobs, nopercent), output = long) |> subset(select = "A_BASE", drop = TRUE) pop_O <- subset(prep, GRP == "O_BASE", v(USUBJID, GRP)) |> proc_sort(options = nodupkey) |> proc_freq(tables = GRP, options = v(nocum, nonobs, nopercent), output = long) |> subset(select = "O_BASE", drop = TRUE) # Prepare formats --------------------------------------------------------- sep("Prepare formats") put("Vital sign lookup format") vs_fmt <- c(PULSE = "Pulse", TEMP = "Temperature °C", RESP = "Respirations/min", SYSBP = "Systolic Blood Pressure", DIABP = "Diastolic Blood Pressure") |> put() put("Statistics lookup format") stat_fmt <- c(MEANSTD = "Mean (SD)", MEDIAN = "Median", Q1Q3 = "Q1 - Q3", MINMAX = "Min - Max") |> put() put("Create format catalog") fc <- fcat(MEAN = "%.1f", STD = "(%.2f)", MEDIAN = "%.1f", Q1 = "%.1f", Q3 = "%.1f", MIN = "%.1f", MAX = "%.1f") # Prepare final data frame ------------------------------------------------ sep("Prepare final data") put("Calculate statistics and prepare final data frame") proc_means(prep, var = VSSTRESN, class = VSTESTCD, by = GRP, stats = v(mean, std, median, q1, q3, min, max), options = v(notype, nofreq, nway)) |> datastep(format = fc, drop = v(MEAN, STD, Q1, Q3, MIN, MAX, VAR), rename = c("CLASS" = "VAR"), { MEANSTD <- fapply2(MEAN, STD) Q1Q3 <- fapply2(Q1, Q3, sep = " - ") MINMAX <- fapply2(MIN, MAX, sep = " - ") }) |> proc_transpose(id = BY, var = v(MEANSTD, MEDIAN, Q1Q3, MINMAX), by = VAR, name = "LABEL") -> final put("Prepare factor for sorting") final$VAR <- factor(final$VAR, names(vs_fmt)) put("Final sort") proc_sort(final, by = VAR) -> final # Create Report ----------------------------------------------------------- sep("Create Report") # Define table object tbl <- create_table(final) |> spanning_header(A_BASE, A_TRT, "Placebo", n = pop_A) |> spanning_header(O_BASE, O_TRT, "Treated", n = pop_O) |> column_defaults(width = 1.25, align = "center") |> stub(c(VAR, LABEL), width = 2.5) |> define(VAR, "Vital Sign", format = vs_fmt, blank_after = TRUE, dedupe = TRUE, label_row = TRUE) |> define(LABEL, indent = .25, format = stat_fmt) |> define(A_BASE, "Baseline") |> define(A_TRT, "After Treatment") |> define(O_BASE, "Baseline") |> define(O_TRT, "After Treatment") # Define report object rpt <- create_report(file.path(tmp, "./output/example2.rtf"), output_type = "RTF", font = "Times", font_size = 12) |> page_header("Sponsor: Company", "Study: ABC") |> titles("Table 4.0", "Selected Vital Signs", bold = TRUE) |> add_content(tbl, align = "center") |> page_footer(Sys.time(), "CONFIDENTIAL", "Page [pg] of [tpg]") # Write report to file system res <- write_report(rpt) # Clean Up ---------------------------------------------------------------- sep("Clean Up") # Close log log_close() # View report # file.show(res$file_path) # View log # file.show(lf) ``` ## Log Here is the log from the above program: ``` ========================================================================= Log Path: C:/Users/dbosa/AppData/Local/Temp/RtmpiipZo8/log/example1.log Program Path: C:/packages/Testing/Example2.R Working Directory: C:/packages/Testing User Name: dbosa R Version: 4.3.1 (2023-06-16 ucrt) Machine: SOCRATES x86-64 Operating System: Windows 10 x64 build 22621 Base Packages: stats graphics grDevices utils datasets methods base Other Packages: tidylog_1.0.2 procs_1.0.3 reporter_1.4.2 libr_1.2.8 logr_1.3.5 fmtr_1.6.1 common_1.1.0 sassy_1.2.1 Log Start Time: 2023-11-17 13:03:47.835721 ========================================================================= ========================================================================= Prepare Data ========================================================================= # library 'sdtm': 8 items - attributes: csv not loaded - path: C:/Users/dbosa/AppData/Local/R/win-library/4.3/libr/extdata - items: Name Extension Rows Cols Size LastModified 1 AE csv 150 27 88.5 Kb 2023-09-09 22:45:51 2 DA csv 3587 18 528.2 Kb 2023-09-09 22:45:51 3 DM csv 87 24 45.5 Kb 2023-09-09 22:45:51 4 DS csv 174 9 34.1 Kb 2023-09-09 22:45:51 5 EX csv 84 11 26.4 Kb 2023-09-09 22:45:51 6 IE csv 2 14 13.4 Kb 2023-09-09 22:45:51 7 SV csv 685 10 70.3 Kb 2023-09-09 22:45:51 8 VS csv 3358 17 467.4 Kb 2023-09-09 22:45:51 Join and prepare data Join DM to VS and keep desired columns datastep: columns decreased from 24 to 7 # A tibble: 2,768 × 7 USUBJID VSTESTCD VISIT VISITNUM VSSTRESN ARM VSBLFL 1 ABC-01-049 DIABP DAY 1 1 76 ARM D Y 2 ABC-01-049 DIABP WEEK 2 2 66 ARM D 3 ABC-01-049 DIABP WEEK 4 4 84 ARM D 4 ABC-01-049 DIABP WEEK 6 6 68 ARM D 5 ABC-01-049 DIABP WEEK 8 8 80 ARM D 6 ABC-01-049 DIABP WEEK 12 12 70 ARM D 7 ABC-01-049 DIABP WEEK 16 16 70 ARM D 8 ABC-01-049 PULSE DAY 1 1 84 ARM D Y 9 ABC-01-049 PULSE WEEK 2 2 84 ARM D 10 ABC-01-049 PULSE WEEK 4 4 76 ARM D # ℹ 2,758 more rows # ℹ Use `print(n = ...)` to see more rows Sort by variables proc_sort: input data set 2768 rows and 7 columns by: USUBJID VSTESTCD VISITNUM keep: USUBJID VSTESTCD VISIT VISITNUM VSSTRESN ARM VSBLFL order: a a a output data set 2768 rows and 7 columns # A tibble: 2,768 × 7 USUBJID VSTESTCD VISIT VISITNUM VSSTRESN ARM VSBLFL 1 ABC-01-049 DIABP DAY 1 1 76 ARM D Y 2 ABC-01-049 DIABP WEEK 2 2 66 ARM D 3 ABC-01-049 DIABP WEEK 4 4 84 ARM D 4 ABC-01-049 DIABP WEEK 6 6 68 ARM D 5 ABC-01-049 DIABP WEEK 8 8 80 ARM D 6 ABC-01-049 DIABP WEEK 12 12 70 ARM D 7 ABC-01-049 DIABP WEEK 16 16 70 ARM D 8 ABC-01-049 PULSE DAY 1 1 84 ARM D Y 9 ABC-01-049 PULSE WEEK 2 2 84 ARM D 10 ABC-01-049 PULSE WEEK 4 4 76 ARM D # ℹ 2,758 more rows # ℹ Use `print(n = ...)` to see more rows Differentiate baseline from treated vital signs datastep: columns increased from 7 to 9 # A tibble: 2,768 × 9 USUBJID VSTESTCD VISIT VISITNUM VSSTRESN ARM VSBLFL GRP BSTRESN 1 ABC-01-049 DIABP DAY 1 1 76 ARM D Y O_BASE 76 2 ABC-01-049 DIABP WEEK 2 2 66 ARM D O_TRT 76 3 ABC-01-049 DIABP WEEK 4 4 84 ARM D O_TRT 76 4 ABC-01-049 DIABP WEEK 6 6 68 ARM D O_TRT 76 5 ABC-01-049 DIABP WEEK 8 8 80 ARM D O_TRT 76 6 ABC-01-049 DIABP WEEK 12 12 70 ARM D O_TRT 76 7 ABC-01-049 DIABP WEEK 16 16 70 ARM D O_TRT 76 8 ABC-01-049 PULSE DAY 1 1 84 ARM D Y O_BASE 84 9 ABC-01-049 PULSE WEEK 2 2 84 ARM D O_TRT 84 10 ABC-01-049 PULSE WEEK 4 4 76 ARM D O_TRT 84 # ℹ 2,758 more rows # ℹ Use `print(n = ...)` to see more rows Get population counts proc_sort: input data set 20 rows and 2 columns by: USUBJID GRP keep: USUBJID GRP order: a options: nodupkey output data set 20 rows and 2 columns # A tibble: 20 × 2 USUBJID GRP 1 ABC-01-051 A_BASE 2 ABC-01-056 A_BASE 3 ABC-02-034 A_BASE 4 ABC-02-038 A_BASE 5 ABC-02-109 A_BASE 6 ABC-03-002 A_BASE 7 ABC-03-006 A_BASE 8 ABC-03-091 A_BASE 9 ABC-04-075 A_BASE 10 ABC-04-080 A_BASE 11 ABC-04-126 A_BASE 12 ABC-06-068 A_BASE 13 ABC-06-069 A_BASE 14 ABC-07-012 A_BASE 15 ABC-07-016 A_BASE 16 ABC-08-104 A_BASE 17 ABC-08-106 A_BASE 18 ABC-09-020 A_BASE 19 ABC-09-023 A_BASE 20 ABC-09-137 A_BASE proc_freq: input data set 20 rows and 2 columns tables: GRP output: long view: TRUE output: 1 datasets # A tibble: 1 × 3 VAR STAT A_BASE 1 GRP CNT 20 proc_sort: input data set 67 rows and 2 columns by: USUBJID GRP keep: USUBJID GRP order: a options: nodupkey output data set 67 rows and 2 columns # A tibble: 67 × 2 USUBJID GRP 1 ABC-01-049 O_BASE 2 ABC-01-050 O_BASE 3 ABC-01-052 O_BASE 4 ABC-01-053 O_BASE 5 ABC-01-054 O_BASE 6 ABC-01-055 O_BASE 7 ABC-01-113 O_BASE 8 ABC-01-114 O_BASE 9 ABC-02-033 O_BASE 10 ABC-02-035 O_BASE # ℹ 57 more rows # ℹ Use `print(n = ...)` to see more rows proc_freq: input data set 67 rows and 2 columns tables: GRP output: long view: TRUE output: 1 datasets # A tibble: 1 × 3 VAR STAT O_BASE 1 GRP CNT 67 ========================================================================= Prepare formats ========================================================================= Vital sign lookup format Pulse Temperature °C Respirations/min Systolic Blood Pressure Diastolic Blood Pressure Statistics lookup format Mean (SD) Median Q1 - Q3 Min - Max Create format catalog # A format catalog: 7 formats - $MEAN: type S, "%.1f" - $STD: type S, "(%.2f)" - $MEDIAN: type S, "%.1f" - $Q1: type S, "%.1f" - $Q3: type S, "%.1f" - $MIN: type S, "%.1f" - $MAX: type S, "%.1f" ========================================================================= Prepare final data ========================================================================= Calculate statistics and prepare final data frame proc_means: input data set 2768 rows and 9 columns by: GRP class: VSTESTCD var: VSSTRESN stats: mean std median q1 q3 min max view: TRUE output: 1 datasets CLASS BY VAR MEAN STD MEDIAN Q1 Q3 MIN MAX 1 DIABP A_BASE VSSTRESN 77.15000 10.6537614 78.5 70.0 83.0 54.0 96.0 2 PULSE A_BASE VSSTRESN 72.75000 10.0518393 72.0 66.0 76.0 60.0 103.0 3 RESP A_BASE VSSTRESN 16.50000 2.5026302 16.0 16.0 18.0 12.0 20.0 4 SYSBP A_BASE VSSTRESN 128.15000 16.7120347 125.5 117.0 140.0 98.0 161.0 5 TEMP A_BASE VSSTRESN 36.52105 0.4171050 36.4 36.2 36.9 35.9 37.4 6 DIABP A_TRT VSSTRESN 77.08547 8.1182772 78.0 72.0 82.0 50.0 98.0 7 PULSE A_TRT VSSTRESN 74.58120 10.2201958 74.0 67.0 80.0 54.0 102.0 8 RESP A_TRT VSSTRESN 15.80342 3.4372185 16.0 16.0 18.0 8.0 24.0 9 SYSBP A_TRT VSSTRESN 130.43590 17.6304911 126.0 118.0 140.0 95.0 184.0 10 TEMP A_TRT VSSTRESN 36.45431 0.2857157 36.5 36.2 36.6 35.8 37.3 11 DIABP O_BASE VSSTRESN 77.48485 8.1415221 78.0 70.0 82.0 61.0 95.0 12 PULSE O_BASE VSSTRESN 73.55224 9.7051745 72.0 67.0 80.0 52.0 100.0 13 RESP O_BASE VSSTRESN 15.97015 3.1477272 16.0 15.0 18.0 8.0 22.0 14 SYSBP O_BASE VSSTRESN 126.68182 15.4672449 123.0 116.0 138.0 100.0 164.0 15 TEMP O_BASE VSSTRESN 36.42239 0.5376213 36.4 36.2 36.6 35.3 39.8 16 DIABP O_TRT VSSTRESN 76.94286 9.2058374 78.0 70.0 84.0 50.0 104.0 17 PULSE O_TRT VSSTRESN 74.02279 9.8592694 72.0 66.0 80.0 50.0 109.0 18 RESP O_TRT VSSTRESN 15.44444 3.4312291 16.0 12.0 18.0 8.0 24.0 19 SYSBP O_TRT VSSTRESN 125.90571 15.1715962 124.0 115.0 135.0 82.0 180.0 20 TEMP O_TRT VSSTRESN 36.31057 0.3903231 36.3 36.1 36.5 34.4 38.2 datastep: columns decreased from 10 to 6 VAR BY MEDIAN MEANSTD Q1Q3 MINMAX 1 DIABP A_BASE 78.5 77.2 (10.65) 70.0 - 83.0 54.0 - 96.0 2 PULSE A_BASE 72.0 72.8 (10.05) 66.0 - 76.0 60.0 - 103.0 3 RESP A_BASE 16.0 16.5 (2.50) 16.0 - 18.0 12.0 - 20.0 4 SYSBP A_BASE 125.5 128.2 (16.71) 117.0 - 140.0 98.0 - 161.0 5 TEMP A_BASE 36.4 36.5 (0.42) 36.2 - 36.9 35.9 - 37.4 6 DIABP A_TRT 78.0 77.1 (8.12) 72.0 - 82.0 50.0 - 98.0 7 PULSE A_TRT 74.0 74.6 (10.22) 67.0 - 80.0 54.0 - 102.0 8 RESP A_TRT 16.0 15.8 (3.44) 16.0 - 18.0 8.0 - 24.0 9 SYSBP A_TRT 126.0 130.4 (17.63) 118.0 - 140.0 95.0 - 184.0 10 TEMP A_TRT 36.5 36.5 (0.29) 36.2 - 36.6 35.8 - 37.3 11 DIABP O_BASE 78.0 77.5 (8.14) 70.0 - 82.0 61.0 - 95.0 12 PULSE O_BASE 72.0 73.6 (9.71) 67.0 - 80.0 52.0 - 100.0 13 RESP O_BASE 16.0 16.0 (3.15) 15.0 - 18.0 8.0 - 22.0 14 SYSBP O_BASE 123.0 126.7 (15.47) 116.0 - 138.0 100.0 - 164.0 15 TEMP O_BASE 36.4 36.4 (0.54) 36.2 - 36.6 35.3 - 39.8 16 DIABP O_TRT 78.0 76.9 (9.21) 70.0 - 84.0 50.0 - 104.0 17 PULSE O_TRT 72.0 74.0 (9.86) 66.0 - 80.0 50.0 - 109.0 18 RESP O_TRT 16.0 15.4 (3.43) 12.0 - 18.0 8.0 - 24.0 19 SYSBP O_TRT 124.0 125.9 (15.17) 115.0 - 135.0 82.0 - 180.0 20 TEMP O_TRT 36.3 36.3 (0.39) 36.1 - 36.5 34.4 - 38.2 proc_transpose: input data set 20 rows and 6 columns by: VAR var: MEANSTD MEDIAN Q1Q3 MINMAX id: BY name: LABEL output dataset 20 rows and 6 columns VAR LABEL A_BASE A_TRT O_BASE O_TRT 1 DIABP MEANSTD 77.2 (10.65) 77.1 (8.12) 77.5 (8.14) 76.9 (9.21) 2 DIABP MEDIAN 78.5 78.0 78.0 78.0 3 DIABP Q1Q3 70.0 - 83.0 72.0 - 82.0 70.0 - 82.0 70.0 - 84.0 4 DIABP MINMAX 54.0 - 96.0 50.0 - 98.0 61.0 - 95.0 50.0 - 104.0 5 PULSE MEANSTD 72.8 (10.05) 74.6 (10.22) 73.6 (9.71) 74.0 (9.86) 6 PULSE MEDIAN 72 74 72 72 7 PULSE Q1Q3 66.0 - 76.0 67.0 - 80.0 67.0 - 80.0 66.0 - 80.0 8 PULSE MINMAX 60.0 - 103.0 54.0 - 102.0 52.0 - 100.0 50.0 - 109.0 9 RESP MEANSTD 16.5 (2.50) 15.8 (3.44) 16.0 (3.15) 15.4 (3.43) 10 RESP MEDIAN 16 16 16 16 11 RESP Q1Q3 16.0 - 18.0 16.0 - 18.0 15.0 - 18.0 12.0 - 18.0 12 RESP MINMAX 12.0 - 20.0 8.0 - 24.0 8.0 - 22.0 8.0 - 24.0 13 SYSBP MEANSTD 128.2 (16.71) 130.4 (17.63) 126.7 (15.47) 125.9 (15.17) 14 SYSBP MEDIAN 125.5 126.0 123.0 124.0 15 SYSBP Q1Q3 117.0 - 140.0 118.0 - 140.0 116.0 - 138.0 115.0 - 135.0 16 SYSBP MINMAX 98.0 - 161.0 95.0 - 184.0 100.0 - 164.0 82.0 - 180.0 17 TEMP MEANSTD 36.5 (0.42) 36.5 (0.29) 36.4 (0.54) 36.3 (0.39) 18 TEMP MEDIAN 36.4 36.5 36.4 36.3 19 TEMP Q1Q3 36.2 - 36.9 36.2 - 36.6 36.2 - 36.6 36.1 - 36.5 20 TEMP MINMAX 35.9 - 37.4 35.8 - 37.3 35.3 - 39.8 34.4 - 38.2 Prepare factor for sorting Final sort proc_sort: input data set 20 rows and 6 columns by: VAR keep: VAR LABEL A_BASE A_TRT O_BASE O_TRT order: a output data set 20 rows and 6 columns VAR LABEL A_BASE A_TRT O_BASE O_TRT 5 PULSE MEANSTD 72.8 (10.05) 74.6 (10.22) 73.6 (9.71) 74.0 (9.86) 6 PULSE MEDIAN 72 74 72 72 7 PULSE Q1Q3 66.0 - 76.0 67.0 - 80.0 67.0 - 80.0 66.0 - 80.0 8 PULSE MINMAX 60.0 - 103.0 54.0 - 102.0 52.0 - 100.0 50.0 - 109.0 17 TEMP MEANSTD 36.5 (0.42) 36.5 (0.29) 36.4 (0.54) 36.3 (0.39) 18 TEMP MEDIAN 36.4 36.5 36.4 36.3 19 TEMP Q1Q3 36.2 - 36.9 36.2 - 36.6 36.2 - 36.6 36.1 - 36.5 20 TEMP MINMAX 35.9 - 37.4 35.8 - 37.3 35.3 - 39.8 34.4 - 38.2 9 RESP MEANSTD 16.5 (2.50) 15.8 (3.44) 16.0 (3.15) 15.4 (3.43) 10 RESP MEDIAN 16 16 16 16 11 RESP Q1Q3 16.0 - 18.0 16.0 - 18.0 15.0 - 18.0 12.0 - 18.0 12 RESP MINMAX 12.0 - 20.0 8.0 - 24.0 8.0 - 22.0 8.0 - 24.0 13 SYSBP MEANSTD 128.2 (16.71) 130.4 (17.63) 126.7 (15.47) 125.9 (15.17) 14 SYSBP MEDIAN 125.5 126.0 123.0 124.0 15 SYSBP Q1Q3 117.0 - 140.0 118.0 - 140.0 116.0 - 138.0 115.0 - 135.0 16 SYSBP MINMAX 98.0 - 161.0 95.0 - 184.0 100.0 - 164.0 82.0 - 180.0 1 DIABP MEANSTD 77.2 (10.65) 77.1 (8.12) 77.5 (8.14) 76.9 (9.21) 2 DIABP MEDIAN 78.5 78.0 78.0 78.0 3 DIABP Q1Q3 70.0 - 83.0 72.0 - 82.0 70.0 - 82.0 70.0 - 84.0 4 DIABP MINMAX 54.0 - 96.0 50.0 - 98.0 61.0 - 95.0 50.0 - 104.0 ========================================================================= Create Report ========================================================================= # A report specification: 1 pages - file_path: 'C:\Users\dbosa\AppData\Local\Temp\RtmpiipZo8/./output/example2.rtf' - output_type: RTF - units: inches - orientation: landscape - margins: top 0.5 bottom 0.5 left 1 right 1 - line size/count: 9/38 - page_header: left=Sponsor: Company right=Study: ABC - title 1: 'Table 4.0' - title 2: 'Selected Vital Signs' - page_footer: left=2023-11-17 13:03:53.809731 center=CONFIDENTIAL right=Page [pg] of [tpg] - content: # A table specification: - data: data.frame 'final' 20 rows 6 cols - show_cols: all - use_attributes: all - spanning_header: from='A_BASE' to='A_TRT' 'Placebo' level=1 - spanning_header: from='O_BASE' to='O_TRT' 'Treated' level=1 - stub: VAR LABEL width=2.5 align='left' - define: VAR 'Vital Sign' dedupe='TRUE' - define: LABEL - define: A_BASE 'Baseline' - define: A_TRT 'After Treatment' - define: O_BASE 'Baseline' - define: O_TRT 'After Treatment' ========================================================================= Clean Up ========================================================================= ========================================================================= Log End Time: 2023-11-17 13:03:54.012811 Log Elapsed Time: 0 00:00:06 ========================================================================= ``` ## Output And here is the output: