Nothing
knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
The sassy system gives you capabilities that few other R packages can match. The system not only support reports with by-groups. You can even apply a by-group to a figure.
Note the following about this example:
add_content() function, just
like the figures in the previous example.page_by() function on the create_plot() statement generates the
paging for both the report and plot.library(sassy) library(ggplot2) options("logr.autolog" = TRUE, "logr.notes" = FALSE) # Get path to temp directory tmp <- tempdir() # Get path to sample data pkg <- system.file("extdata", package = "sassy") # Open log lgpth <- log_open(file.path(tmp, "example6.log")) # Prepare Data ------------------------------------------------------------ sep("Prepare Data") put("Load data files") libname(dat, pkg, "csv", filter = c("DM", "VS")) put("Prepare factor levels") visit_levels <- c("SCREENING", "DAY 1", "WEEK 2", "WEEK 4", "WEEK 6", "WEEK 8", "WEEK 12", "WEEK 16") |> put() arm_levels <- c("ARM A", "ARM B") |> put() test_codes <- c("SYSBP", "DIABP", "PULSE", "RESP") |> put() put("Prepare data for analysis") datastep(dat$DM, merge = dat$VS, merge_by = v(STUDYID, USUBJID), keep = v(STUDYID, USUBJID, ARM, VISIT, VSTESTCD, VSORRES), merge_in = v(inDM, inVS), where = expression(VISIT != "END OF STUDY EARLY TERMINATION" & ARM %in% c("ARM A", "ARM B") & VSTESTCD %in% test_codes ), { # Assign factors to VISIT and ARM VISIT <- factor(VISIT, levels = visit_levels) ARM <- factor(ARM, levels = arm_levels) VSTESTCD <- factor(VSTESTCD, levels = test_codes) if (!inDM & inVS) { delete() } }) -> vitals # Create Plot ------------------------------------------------------------- sep("Create Plot") put("Assign Colors") arm_cols <- c("ARM B" = "#1f77b4", "ARM A" = "#2f2f2f") put("Define Boxplot") p_box <- ggplot2::ggplot( vitals, ggplot2::aes(x = VISIT, y = VSORRES, fill = ARM, colour = ARM) ) + ggplot2::geom_boxplot( position = ggplot2::position_dodge(width = 0.75), width = 0.6, outlier.size = 0.7, alpha = 0.9 ) + ggplot2::scale_fill_manual(values = arm_cols) + ggplot2::scale_colour_manual(values = arm_cols) + ggplot2::labs( x = NULL, y = "Lab Value", fill = NULL, colour = NULL ) + ggplot2::theme_bw(base_size = 10) + ggplot2::theme( legend.position = "bottom", panel.grid.major.x = ggplot2::element_blank(), plot.title = ggplot2::element_text(face = "bold", hjust = 0), plot.caption = ggplot2::element_text(hjust = 0) ) put("Create format for lab codes") lbfmt <- value(condition(x == "SYSBP", "Systolic Blood Pressure (mmHg)"), condition(x == "DIABP", "Diastolic Blood Pressure (mmHg)"), condition(x == "PULSE", "Pulse (bpm)"), condition(x == "RESP", "Respirations (bpm)")) # Report ------------------------------------------------------------------ sep("Report") put("Create plot object definition") plt <- create_plot(p_box, height = 4, width = 7, borders = "outside") |> titles("Figure 10. Box Plot: Median and Interquartile Range of Vital Signs by Treatment Arm", bold = TRUE, font_size = 12, align = "left") |> page_by(VSTESTCD, label = "Lab Test: ", format = lbfmt, blank_row = "none") |> footnotes( "Source: example6.rtf. {version$version.string}", "Note: Boxes span the interquartile range (25th to 75th percentile); horizontal line = median;", "whiskers = 1.5×IQR; individual outliers are those beyond this range.", font_size = 9, italics = TRUE, blank_row = "none" ) put("Create report output path") pth <- file.path(tempdir(), "example6.rtf") put("Create report") rpt <- create_report(pth, font = "Arial", font_size = 10, output_type = "RTF") |> page_header("Sponsor: Company", right = "Study: ABC", blank_row = "below") |> add_content(plt) |> page_footer("Date Produced: {fapply(Sys.Date(), 'date7')}", right = "Page [pg] of [tpg]") put("Write report to file system") write_report(rpt) put("Close log") log_close() # View report # file.show(pth) # View log # file.show(lgpth)
And here are the first two pages of the report:


Here is the log for the above program:
========================================================================= Log Path: C:/Users/dbosa/AppData/Local/Temp/Rtmpq0yZA5/log/example6.log Program Path: C:/Studies/Testing1/P6b.R Working Directory: C:/Studies/Testing1 User Name: dbosa R Version: 4.4.3 (2025-02-28 ucrt) Machine: SOCRATES x86-64 Operating System: Windows 10 x64 build 26100 Base Packages: stats graphics grDevices utils datasets methods base Other Packages: tidylog_1.1.0 ggplot2_3.5.1 procs_1.0.7 reporter_1.4.5 libr_1.3.9 logr_1.3.9 fmtr_1.7.0 common_1.1.4 sassy_1.2.9 Log Start Time: 2025-12-12 14:27:32.328372 ========================================================================= ========================================================================= Prepare Data ========================================================================= Load data files # library 'dat': 2 items - attributes: csv not loaded - path: C:/Users/dbosa/AppData/Local/R/win-library/4.4/sassy/extdata - items: Name Extension Rows Cols Size LastModified 1 DM csv 87 24 45.8 Kb 2025-12-12 08:37:33 2 VS csv 3358 17 467.7 Kb 2025-12-12 08:37:33 Prepare factor levels SCREENING DAY 1 WEEK 2 WEEK 4 WEEK 6 WEEK 8 WEEK 12 WEEK 16 ARM A ARM B SYSBP DIABP PULSE RESP Prepare data for analysis datastep: columns decreased from 24 to 6 # A tibble: 1,231 × 6 STUDYID USUBJID ARM VISIT VSTESTCD VSORRES <chr> <chr> <fct> <fct> <fct> <dbl> 1 ABC ABC-01-050 ARM B SCREENING DIABP 80 2 ABC ABC-01-050 ARM B DAY 1 DIABP 78 3 ABC ABC-01-050 ARM B WEEK 2 DIABP 64 4 ABC ABC-01-050 ARM B WEEK 4 DIABP 86 5 ABC ABC-01-050 ARM B WEEK 6 DIABP 70 6 ABC ABC-01-050 ARM B WEEK 8 DIABP 80 7 ABC ABC-01-050 ARM B WEEK 12 DIABP 64 8 ABC ABC-01-050 ARM B WEEK 16 DIABP 82 9 ABC ABC-01-050 ARM B SCREENING PULSE 76 10 ABC ABC-01-050 ARM B DAY 1 PULSE 68 # ℹ 1,221 more rows # ℹ Use `print(n = ...)` to see more rows ========================================================================= Create Plot ========================================================================= Assign Colors Define Boxplot Create format for lab codes # A user-defined format: 4 conditions Name Type Expression Label Order 1 obj U x == "SYSBP" Systolic Blood Pressure (mmHg) NA 2 obj U x == "DIABP" Diastolic Blood Pressure (mmHg) NA 3 obj U x == "PULSE" Pulse (bpm) NA 4 obj U x == "RESP" Respirations (bpm) NA ========================================================================= Report ========================================================================= Create plot object definition Create report output path Create report Write report to file system # A report specification: 4 pages - file_path: 'C:\Users\dbosa\AppData\Local\Temp\Rtmpq0yZA5/example6.rtf' - output_type: RTF - units: inches - orientation: landscape - margins: top 0.5 bottom 0.5 left 1 right 1 - line size/count: 9/42 - page_header: left=Sponsor: Company right=Study: ABC - page_footer: left=Date Produced: 12DEC25 center= right=Page [pg] of [tpg] - content: # A plot specification: - data: 1231 rows, 6 cols - layers: 1 - height: 4 - width: 7 - page by: VSTESTCD - title 1: 'Figure 10. Box Plot: Median and Interquartile Range of Vital Signs by Treatment Arm' - footnote 1: 'Source: example6.rtf. R version 4.4.3 (2025-02-28 ucrt)' - footnote 2: 'Note: Boxes span the interquartile range (25th to 75th percentile); horizontal line = median;' - footnote 3: 'whiskers = 1.5×IQR; individual outliers are those beyond this range.' Close log ========================================================================= Log End Time: 2025-12-12 14:27:40.667776 Log Elapsed Time: 0 00:00:08 =========================================================================
Next: Example 7: Survival Analysis
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.