# Example 13: Mean Change From Baseline

The following example shows a Mean Change from Baseline chart for Hematology Lab Values with supporting tables for the mean value and number of patients. The figure is accomplished using the ggplot and patchwork packages, and data preparation that features the procs package.

## Program

Note the following about this example:

- The procs package calculates mean values and confidence intervals for each treatment group and visit.
- The ggplot2 package can create small tables in addition to charts.
- The patchwork package can combine the ggplot chart and table into a single image.
- The patchwork images are dynamically added to a report object from the reporter package. Titles are customized for each page.

    library(sassy)
    library(ggplot2)
    library(patchwork)

    options("logr.notes" = FALSE,
            "logr.autolog" = TRUE,
            "procs.print" = FALSE)

    # Get temp location for log and report output
    tmp <- tempdir()

    lf <- log_open(file.path(tmp, "example13.log"))

    # Get data ----------------------------------------------------------------

    sep("Get data")

    # Get sample data path
    pth <- system.file("extdata", package = "sassy")

    put("Open data library")
    libname(sdtm, pth, "csv")

    # Create Formats ----------------------------------------------------------

    sep("Create Formats")

    put("Format for visits")
    vfmt <- value(condition(x == "DAY 1", "Day 1"),
                  condition(x == "WEEK 2", "Week 2"),
                  condition(x == "WEEK 4", "Week 4"),
                  condition(x == "WEEK 6", "Week 6"),
                  condition(x == "WEEK 12", "Week 12"),
                  as.factor = TRUE)

    put("Format for ARMs")
    afmt <- value(condition(x == "ARM A", "Placebo"),
                  condition(x == "ARM B", "Drug (10mg)"),
                  condition(x == "ARM C", "Drug (20mg)"),
                  condition(x == "ARM D", "Competitor"),
                  as.factor = TRUE)

    # Prepare data ------------------------------------------------------------

    sep("Prepare data")

    put("Pull out needed visits and columns")
    lbsub1 <- subset(sdtm$LB, VISIT %in% toupper(levels(vfmt)),
                    v(USUBJID, VISIT, VISITNUM, LBORRES, LBCAT, LBORRESU, LBTEST,
                      LBTESTCD, LBBLFL)) |> put()

    put("Pull out baseline subset")
    lbsub2 <- subset(lbsub1, LBBLFL == 'Y',
                    v(USUBJID, VISIT, LBORRES, LBCAT, LBTESTCD)) |> put()

    put("Merge and calculate change from baseline")
    datastep(lbsub1, merge = lbsub2, merge_by = v(USUBJID, LBCAT, LBTESTCD),
             rename = v(LBORRES.1 = LBORRES, LBORRES.2 = BLBORES, VISIT.1 = VISIT),
             drop = VISIT.2, {

               # Convert to double
               LBORRES.1 <- suppressWarnings(as.double(LBORRES.1))

               # Convert to double
               LBORRES.2 <- suppressWarnings(as.double(LBORRES.2))

               # Calculate Change from baseline
               if (!(is.na(LBORRES.1) | is.na(LBORRES.2))) {
                 LBCHG <- LBORRES.1 - LBORRES.2
               } else {
                 LBCHG <- NA
               }

             }) -> lbsub

    put("Pull needed ARMs and columns for DM")
    dmsub <- subset(sdtm$DM, ARM != "SCREEN FAILURE", v(USUBJID, ARMCD, ARM)) |> put()

    put("Merge DM with LB to get subject treatments")
    datastep(lbsub, merge = dmsub, merge_by = USUBJID,
             where = expression(toupper(VISIT) != 'SCREENING'),
             {
               VISIT <- fapply(VISIT, vfmt)
             }) -> lbdat

    # Prepare lab test labels -------------------------------------------------

    sep("Lab test labels")

    put("Get lookup data for lab tests")
    proc_sort(lbdat, by = v(LBTESTCD, LBTEST, LBORRESU),
              keep = v(LBTESTCD, LBTEST, LBORRESU),
              options = nodupkey) -> tcodes

    put("Create test label with units")
    datastep(tcodes, where = expression(is.na(LBORRESU) == FALSE),
             keep = v(LBTESTCD, LABEL),
             {

               LABEL <- paste0(LBTEST, " (", LBORRESU, ")")

             }) -> tfmtdat

    put("Create lab value lookup")
    tfmt <- tfmtdat$LABEL
    names(tfmt) <- tfmtdat$LBTESTCD

    put("Apply superscripts as needed")
    tfmt <- sub("(9)", supsc('9'), tfmt, fixed = TRUE)
    tfmt <- sub("(12)", supsc('12'), tfmt, fixed = TRUE)

    # Calculate statistics ----------------------------------------------------

    sep("Calculate statistics")

    put("Get statistics for change from baseline")
    proc_means(lbdat, by = LBTESTCD,
               class = v(ARM, VISIT),
               var = LBCHG,
               stats = v(n, mean, std, clm),
               options = nway) -> datcl

    put("Get statistics for mean lab value")
    proc_means(lbdat, by = LBTESTCD,
               class = v(ARM, VISIT),
               var = LBORRES,
               stats = v(n, mean),
               options = nway) -> datmn

    put("Add mean lab values to change from baseline")
    datcl$MEANV <- datmn$MEAN

    put("Apply formats")
    datcl$BY <- fapply(datcl$BY, tfmt)
    datcl$CLASS1 <- fapply(datcl$CLASS1, afmt)

    # Create report -----------------------------------------------------------

    sep("Create report")

    put("Create output path")
    pth <- file.path(tmp, "output/example13.rtf") |> put()

    put("Create report first so content can be added dynamically")
    rpt <- create_report(pth, output_type = "RTF",
                         font = "Arial", font_size = 10) |>
      page_header("Sponsor: Archytas", right = "Study: ABC") |>
      titles("Figure 1.0", "Mean Change From Baseline (HEMATOLOGY)", "Safety Population",
             bold = TRUE, blank_row = "none") |>
      page_footer("Date: " %p% fapply(Sys.time(), "%d%b%Y %H:%M:%S"),
                  "Confidential", "Page [pg] of [tpg]")

    put("Loop through lab tests")
    for (tst in unique(datcl$BY)) {

      put("**** Lab Test: " %p% tst %p% " ****")

      put("Apply subset")
      dat <- subset(datcl, BY == tst)

      put("Create plot")
      p <- ggplot(data = dat, aes(x = CLASS2, y = MEAN, group = CLASS1)) +
        geom_point(aes(color = CLASS1), size = 1.5, position = position_dodge(width = 0.5)) +
        geom_line(aes(color = CLASS1, linetype = CLASS1), position = position_dodge(width = 0.5)) +
        geom_errorbar(aes(x = CLASS2, ymin = LCLM, ymax = UCLM, color = CLASS1),
                      position = position_dodge(width = 0.5)) +
        theme_light() +
        scale_linetype(guide = "none") +
        scale_color_manual(values = c("blue", "red", "green", "purple")) +
        theme(legend.position = "bottom", plot.title = element_text(size = 11, hjust = 0)) +
        guides(color = guide_legend(title = "Treatment")) +
        labs(x = 'Visit', y = '\n\nMean Change from Baseline (95% CI)') +
        geom_hline(yintercept = 0, linetype = 'dashed')

      put("Create table for mean change/mean value")
      t1 <- ggplot(data = dat) +
        geom_text(aes(CLASS1, x = CLASS2, label = fapply2(MEAN, MEANV, "%4.2f", "%.2f", sep = "/"),
                      hjust = 0.5, vjust = 0.5), size = 8 / .pt) +
        ggtitle("Mean Change from Baseline/Mean Value") +
        scale_y_discrete(limits = rev) +
        theme_bw() +
        theme(
          axis.line = element_blank(),
          panel.grid = element_blank(),
          axis.ticks = element_blank(),
          axis.title.y = element_blank(),
          axis.title.x = element_blank(),
          axis.text.x = element_text(color = "white"),
          plot.title = element_text(size =10, hjust = 0, face = "bold")
        )

      put("Create table for patient counts")
      t2 <- ggplot(data = dat) +
        geom_text(aes(CLASS1, x = CLASS2, label = as.character(N),
                      hjust = 0.5, vjust = 0.5), size = 8 / .pt) +
        ggtitle("Number of Patients") +
        scale_y_discrete(limits = rev) +
        theme_bw() +
        theme(
          axis.line = element_blank(),
          panel.grid = element_blank(),
          axis.ticks = element_blank(),
          axis.title.y = element_blank(),
          axis.title.x = element_blank(),
          axis.text.x = element_text(color = "white"),
          plot.title = element_text(size = 10, hjust = 0, face = "bold")
        )

      put("Patch together plot and tables")
      plts <- p + t1 + t2 + plot_layout(ncol = 1, nrow = 3,
                                        widths = c(1, 2, 2), heights = c(8, 2, 2))

      put("Create plot content")
      plt1 <- create_plot(plts, height = 6, width = 9) |>
        titles("Laboratory Test: " %p% tst, align = "left", blank_row = "below")

      put("Add content to report")
      rpt <- rpt |>
        add_content(plt1, page_break = TRUE, blank_row = "none")

    }

    put("Write out report to file system")
    res <- write_report(rpt)

    # Clean Up ----------------------------------------------------------------

    sep("Clean Up")

    log_close()

    # View report
    # file.show(res$modified_path)

    # View log
    # file.show(lf)

## Output

Here is an image of the RTF report produced by the above example:

## Log

Here is the log produced by the above mean change from baseline example:

    =========================================================================
    Log Path: C:/Users/dbosa/AppData/Local/Temp/RtmpuCtffJ/log/example13.log
    Program Path: C:/packages/Testing/sassytests/ControlChart.R
    Working Directory: C:/packages/Testing
    User Name: dbosa
    R Version: 4.3.2 (2023-10-31 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 patchwork_1.1.3 ggplot2_3.4.4 procs_1.0.5
    reporter_1.4.4 libr_1.2.9 logr_1.3.5 fmtr_1.6.2 common_1.1.1 sassy_1.2.1
    Log Start Time: 2024-02-02 22:44:16.986801
    =========================================================================

    =========================================================================
    Get data
    =========================================================================

    Open data library

    # library 'sdtm': 15 items
    - attributes: csv not loaded
    - path: ./data/abc/SDTM
    - items:
          Name Extension  Rows Cols     Size        LastModified
    1       AE       csv   150   27  88.3 Kb 2020-09-18 14:30:23
    2       DA       csv  3587   18   528 Kb 2020-09-18 14:30:23
    3       DM       csv    87   24  45.3 Kb 2020-09-18 14:30:23
    4       DS       csv   174    9  33.9 Kb 2020-09-18 14:30:23
    5  DS_IHOR       csv   174    9  33.9 Kb 2020-09-18 14:30:23
    6       EX       csv    84   11  26.2 Kb 2020-09-18 14:30:23
    7       IE       csv     2   14  13.2 Kb 2020-09-18 14:30:23
    8       LB       csv  2069   12 211.2 Kb 2024-02-02 22:42:43
    9      LB4       csv 23607   27   5.4 Mb 2020-09-18 14:30:23
    10     LB6       csv  7810   12   879 Kb 2024-02-01 00:20:30
    11      PE       csv  1854   17 275.7 Kb 2020-09-18 14:30:24
    12      QS       csv 13316   17   1.7 Mb 2020-09-18 14:30:24
    13  SUPPEX       csv   639   10  63.8 Kb 2020-09-18 14:30:24
    14      SV       csv   685   10  70.1 Kb 2020-09-18 14:30:24
    15      VS       csv  3358   17 467.2 Kb 2020-09-18 14:30:24

    =========================================================================
    Create Formats
    =========================================================================

    Format for visits

    # A user-defined format: 5 conditions
    - as.factor: TRUE
      Name Type     Expression   Label Order
    1  obj    U   x == "DAY 1"   Day 1    NA
    2  obj    U  x == "WEEK 2"  Week 2    NA
    3  obj    U  x == "WEEK 4"  Week 4    NA
    4  obj    U  x == "WEEK 6"  Week 6    NA
    5  obj    U x == "WEEK 12" Week 12    NA

    Format for ARMs

    # A user-defined format: 4 conditions
    - as.factor: TRUE
      Name Type   Expression       Label Order
    1  obj    U x == "ARM A"     Placebo    NA
    2  obj    U x == "ARM B" Drug (10mg)    NA
    3  obj    U x == "ARM C" Drug (20mg)    NA
    4  obj    U x == "ARM D"  Competitor    NA

    =========================================================================
    Prepare data
    =========================================================================

    Pull out needed visits and columns

    # A tibble: 1,578 × 9
       USUBJID    VISIT   VISITNUM LBORRES LBCAT      LBORRESU LBTEST      LBTESTCD LBBLFL
       <chr>      <chr>      <dbl>   <dbl> <chr>      <chr>    <chr>       <chr>    <chr>
     1 ABC-01-049 DAY 1          1    0.04 HEMATOLOGY x10(9)/L Basophils   BASO     Y
     2 ABC-01-049 WEEK 2         2    0.01 HEMATOLOGY x10(9)/L Basophils   BASO     <NA>
     3 ABC-01-049 WEEK 6         6    0.06 HEMATOLOGY x10(9)/L Basophils   BASO     <NA>
     4 ABC-01-049 WEEK 12       12    0.03 HEMATOLOGY x10(9)/L Basophils   BASO     <NA>
     5 ABC-01-049 DAY 1          1    0.19 HEMATOLOGY x10(9)/L Eosinophils EOS      Y
     6 ABC-01-049 WEEK 2         2    0.19 HEMATOLOGY x10(9)/L Eosinophils EOS      <NA>
     7 ABC-01-049 WEEK 6         6    0.21 HEMATOLOGY x10(9)/L Eosinophils EOS      <NA>
     8 ABC-01-049 WEEK 12       12    0.18 HEMATOLOGY x10(9)/L Eosinophils EOS      <NA>
     9 ABC-01-049 DAY 1          1   42.6  HEMATOLOGY %        Hematocrit  HCT      Y
    10 ABC-01-049 WEEK 2         2   44.3  HEMATOLOGY %        Hematocrit  HCT      <NA>
    # ℹ 1,568 more rows
    # ℹ Use `print(n = ...)` to see more rows

    Pull out baseline subset

    # A tibble: 409 × 5
       USUBJID    VISIT LBORRES LBCAT      LBTESTCD
       <chr>      <chr>   <dbl> <chr>      <chr>
     1 ABC-01-049 DAY 1    0.04 HEMATOLOGY BASO
     2 ABC-01-049 DAY 1    0.19 HEMATOLOGY EOS
     3 ABC-01-049 DAY 1   42.6  HEMATOLOGY HCT
     4 ABC-01-049 DAY 1   15    HEMATOLOGY HGB
     5 ABC-01-049 DAY 1    1.91 HEMATOLOGY LYM
     6 ABC-01-050 DAY 1    0.04 HEMATOLOGY BASO
     7 ABC-01-050 DAY 1    0.33 HEMATOLOGY EOS
     8 ABC-01-050 DAY 1   44.6  HEMATOLOGY HCT
     9 ABC-01-050 DAY 1   15.7  HEMATOLOGY HGB
    10 ABC-01-050 DAY 1    1.23 HEMATOLOGY LYM
    # ℹ 399 more rows
    # ℹ Use `print(n = ...)` to see more rows

    Merge and calculate change from baseline

    datastep: columns increased from 9 to 11

    # A tibble: 1,578 × 11
       USUBJID    VISIT   VISITNUM LBORRES LBCAT   LBORRESU LBTEST LBTESTCD LBBLFL BLBORES
       <chr>      <chr>      <dbl>   <dbl> <chr>   <chr>    <chr>  <chr>    <chr>    <dbl>
     1 ABC-01-049 WEEK 12       12    0.03 HEMATO… x10(9)/L Basop… BASO     <NA>      0.04
     2 ABC-01-049 WEEK 2         2    0.01 HEMATO… x10(9)/L Basop… BASO     <NA>      0.04
     3 ABC-01-049 DAY 1          1    0.04 HEMATO… x10(9)/L Basop… BASO     Y         0.04
     4 ABC-01-049 WEEK 6         6    0.06 HEMATO… x10(9)/L Basop… BASO     <NA>      0.04
     5 ABC-01-049 WEEK 12       12    0.18 HEMATO… x10(9)/L Eosin… EOS      <NA>      0.19
     6 ABC-01-049 DAY 1          1    0.19 HEMATO… x10(9)/L Eosin… EOS      Y         0.19
     7 ABC-01-049 WEEK 2         2    0.19 HEMATO… x10(9)/L Eosin… EOS      <NA>      0.19
     8 ABC-01-049 WEEK 6         6    0.21 HEMATO… x10(9)/L Eosin… EOS      <NA>      0.19
     9 ABC-01-049 WEEK 12       12   45.3  HEMATO… %        Hemat… HCT      <NA>     42.6
    10 ABC-01-049 WEEK 2         2   44.3  HEMATO… %        Hemat… HCT      <NA>     42.6
    # ℹ 1,568 more rows
    # ℹ 1 more variable: LBCHG <dbl>
    # ℹ Use `print(n = ...)` to see more rows

    Pull needed ARMs and columns for DM

    # A tibble: 85 × 3
       USUBJID    ARMCD ARM
       <chr>      <chr> <chr>
     1 ABC-01-049 4     ARM D
     2 ABC-01-050 2     ARM B
     3 ABC-01-051 1     ARM A
     4 ABC-01-052 3     ARM C
     5 ABC-01-053 2     ARM B
     6 ABC-01-054 4     ARM D
     7 ABC-01-055 3     ARM C
     8 ABC-01-056 1     ARM A
     9 ABC-01-113 4     ARM D
    10 ABC-01-114 2     ARM B
    # ℹ 75 more rows
    # ℹ Use `print(n = ...)` to see more rows

    Merge DM with LB to get subject treatments

    datastep: columns increased from 11 to 13

    # A tibble: 1,578 × 13
       USUBJID    VISIT   VISITNUM LBORRES LBCAT   LBORRESU LBTEST LBTESTCD LBBLFL BLBORES
       <chr>      <ord>      <dbl>   <dbl> <chr>   <chr>    <chr>  <chr>    <chr>    <dbl>
     1 ABC-01-049 Week 12       12    2.59 HEMATO… x10(9)/L Lymph… LYM      <NA>      1.91
     2 ABC-01-049 Week 6         6    2.35 HEMATO… x10(9)/L Lymph… LYM      <NA>      1.91
     3 ABC-01-049 Week 2         2    2.59 HEMATO… x10(9)/L Lymph… LYM      <NA>      1.91
     4 ABC-01-049 Week 6         6    0.06 HEMATO… x10(9)/L Basop… BASO     <NA>      0.04
     5 ABC-01-049 Week 12       12    0.18 HEMATO… x10(9)/L Eosin… EOS      <NA>      0.19
     6 ABC-01-049 Week 12       12   15.9  HEMATO… g/dL     Hemog… HGB      <NA>     15
     7 ABC-01-049 Week 2         2    0.19 HEMATO… x10(9)/L Eosin… EOS      <NA>      0.19
     8 ABC-01-049 Week 6         6    0.21 HEMATO… x10(9)/L Eosin… EOS      <NA>      0.19
     9 ABC-01-049 Week 12       12   45.3  HEMATO… %        Hemat… HCT      <NA>     42.6
    10 ABC-01-049 Day 1          1    1.91 HEMATO… x10(9)/L Lymph… LYM      Y         1.91
    # ℹ 1,568 more rows
    # ℹ 3 more variables: LBCHG <dbl>, ARMCD <chr>, ARM <chr>
    # ℹ Use `print(n = ...)` to see more rows

    =========================================================================
    Lab test labels
    =========================================================================

    Get lookup data for lab tests

    proc_sort: input data set 10 rows and 13 columns
               by: LBTESTCD LBTEST LBORRESU
               keep: LBTESTCD LBTEST LBORRESU
               order: a a a
               options: nodupkey
               output data set 10 rows and 3 columns

    # A tibble: 10 × 3
       LBTESTCD LBTEST      LBORRESU
       <chr>    <chr>       <chr>
     1 BASO     Basophils   x10(9)/L
     2 BASO     Basophils   <NA>
     3 EOS      Eosinophils x10(9)/L
     4 EOS      Eosinophils <NA>
     5 HCT      Hematocrit  %
     6 HCT      Hematocrit  <NA>
     7 HGB      Hemoglobin  g/dL
     8 HGB      Hemoglobin  <NA>
     9 LYM      Lymphocytes x10(9)/L
    10 LYM      Lymphocytes <NA>

    Create test label with units

    datastep: columns decreased from 3 to 2

    # A tibble: 5 × 2
      LBTESTCD LABEL
      <chr>    <chr>
    1 BASO     Basophils (x10(9)/L)
    2 EOS      Eosinophils (x10(9)/L)
    3 HCT      Hematocrit (%)
    4 HGB      Hemoglobin (g/dL)
    5 LYM      Lymphocytes (x10(9)/L)

    Create lab value lookup

    Apply superscripts as needed

    =========================================================================
    Calculate statistics
    =========================================================================

    Get statistics for change from baseline

    proc_means: input data set 1578 rows and 13 columns
                by: LBTESTCD
                class: ARM VISIT
                var: LBCHG
                stats: n mean std clm
                view: TRUE
                output: 1 datasets

       CLASS1  CLASS2   BY TYPE FREQ   VAR  N          MEAN        STD         LCLM
    1   ARM A   Day 1 BASO    3   19 LBCHG 19  0.000000e+00 0.00000000  0.000000000
    2   ARM A  Week 2 BASO    3   19 LBCHG 18 -5.555556e-03 0.04591837 -0.028390224
    3   ARM A  Week 6 BASO    3   19 LBCHG 18 -3.888889e-03 0.04002042 -0.023790575
    4   ARM A Week 12 BASO    3   18 LBCHG 17 -1.294118e-02 0.02365500 -0.025103453
    5   ARM B   Day 1 BASO    3   20 LBCHG 20  0.000000e+00 0.00000000  0.000000000
    6   ARM B  Week 2 BASO    3   20 LBCHG 19  7.894737e-03 0.02839776 -0.005792545
    7   ARM B  Week 6 BASO    3   18 LBCHG 17 -4.117647e-03 0.04213947 -0.025783766
    8   ARM B Week 12 BASO    3   18 LBCHG 15 -9.333333e-03 0.03514595 -0.028796514
    9   ARM C   Day 1 BASO    3   19 LBCHG 19  0.000000e+00 0.00000000  0.000000000
    10  ARM C  Week 2 BASO    3   18 LBCHG 17  1.352941e-02 0.02956797 -0.001673034
    11  ARM C  Week 6 BASO    3   17 LBCHG 16  3.750000e-03 0.01995829 -0.006885022
    12  ARM C Week 12 BASO    3   15 LBCHG 15  1.666667e-02 0.03885259 -0.004849181
    13  ARM D   Day 1 BASO    3   25 LBCHG 21  0.000000e+00 0.00000000  0.000000000
    14  ARM D  Week 2 BASO    3   22 LBCHG 20 -1.500000e-02 0.04489754 -0.036012697
    15  ARM D  Week 6 BASO    3   19 LBCHG 18  3.333333e-03 0.04740315 -0.020239700
    16  ARM D Week 12 BASO    3   20 LBCHG 18 -1.833333e-02 0.05136375 -0.043875928
    17  ARM A   Day 1  EOS    3   19 LBCHG 19  0.000000e+00 0.00000000  0.000000000
    18  ARM A  Week 2  EOS    3   19 LBCHG 18  8.888889e-03 0.09177267 -0.036748584
    19  ARM A  Week 6  EOS    3   19 LBCHG 18 -5.555556e-04 0.11132740 -0.055917371
    20  ARM A Week 12  EOS    3   18 LBCHG 17 -2.941176e-03 0.10263800 -0.055712766
    21  ARM B   Day 1  EOS    3   20 LBCHG 20  0.000000e+00 0.00000000  0.000000000
    22  ARM B  Week 2  EOS    3   20 LBCHG 19 -2.052632e-02 0.06875671 -0.053665990
    23  ARM B  Week 6  EOS    3   18 LBCHG 17 -7.058824e-03 0.06687345 -0.041441981
    24  ARM B Week 12  EOS    3   18 LBCHG 15 -2.333333e-02 0.05924123 -0.056140035
    25  ARM C   Day 1  EOS    3   19 LBCHG 19  0.000000e+00 0.00000000  0.000000000
    26  ARM C  Week 2  EOS    3   18 LBCHG 17 -3.470588e-02 0.06549023 -0.068377853
    27  ARM C  Week 6  EOS    3   17 LBCHG 16 -2.875000e-02 0.07237633 -0.067316625
    28  ARM C Week 12  EOS    3   15 LBCHG 15 -2.533333e-02 0.10020455 -0.080824765
    29  ARM D   Day 1  EOS    3   25 LBCHG 21  0.000000e+00 0.00000000  0.000000000
    30  ARM D  Week 2  EOS    3   22 LBCHG 20  4.000000e-03 0.09150209 -0.038824294
    31  ARM D  Week 6  EOS    3   19 LBCHG 18 -1.388889e-02 0.09437964 -0.060822779
    32  ARM D Week 12  EOS    3   20 LBCHG 18 -3.111111e-02 0.13437826 -0.097935847
    33  ARM A   Day 1  HCT    3   20 LBCHG 20  0.000000e+00 0.00000000  0.000000000
    34  ARM A  Week 2  HCT    3   20 LBCHG 20  3.400000e-01 1.67438913 -0.443638233
    35  ARM A  Week 6  HCT    3   19 LBCHG 19  4.736842e-02 2.10353365 -0.966502342
    36  ARM A Week 12  HCT    3   19 LBCHG 19 -1.473684e-01 2.20185993 -1.208630934
    37  ARM B   Day 1  HCT    3   21 LBCHG 21  0.000000e+00 0.00000000  0.000000000
    38  ARM B  Week 2  HCT    3   20 LBCHG 20  5.150000e-01 1.67905832 -0.270823483
    39  ARM B  Week 6  HCT    3   18 LBCHG 18 -4.000000e-01 2.17147280 -1.479848018
    40  ARM B Week 12  HCT    3   18 LBCHG 17 -1.941176e-01 1.86395768 -1.152476254
    41  ARM C   Day 1  HCT    3   19 LBCHG 19  0.000000e+00 0.00000000  0.000000000
    42  ARM C  Week 2  HCT    3   18 LBCHG 17 -8.823529e-02 1.87078939 -1.050106442
    43  ARM C  Week 6  HCT    3   17 LBCHG 16 -3.000000e-01 1.78848167 -1.253014608
    44  ARM C Week 12  HCT    3   16 LBCHG 15 -6.066667e-01 2.42147141 -1.947632839
    45  ARM D   Day 1  HCT    3   23 LBCHG 21  0.000000e+00 0.00000000  0.000000000
    46  ARM D  Week 2  HCT    3   22 LBCHG 20  1.900000e-01 1.74654546 -0.627408438
    47  ARM D  Week 6  HCT    3   20 LBCHG 18  7.894799e-16 1.35559841 -0.674123232
    48  ARM D Week 12  HCT    3   20 LBCHG 18 -5.833333e-01 1.52286495 -1.340636255
    49  ARM A   Day 1  HGB    3   20 LBCHG 20  0.000000e+00 0.00000000  0.000000000
    50  ARM A  Week 2  HGB    3   20 LBCHG 20  7.000000e-02 0.49957877 -0.163810061
    51  ARM A  Week 6  HGB    3   19 LBCHG 19  2.105263e-02 0.63646502 -0.285713688
    52  ARM A Week 12  HGB    3   19 LBCHG 19 -1.210526e-01 0.65453881 -0.436530239
    53  ARM B   Day 1  HGB    3   21 LBCHG 21  0.000000e+00 0.00000000  0.000000000
    54  ARM B  Week 2  HGB    3   20 LBCHG 20  1.300000e-01 0.56110793 -0.132606593
    55  ARM B  Week 6  HGB    3   18 LBCHG 18 -8.333333e-02 0.74379789 -0.453215320
    56  ARM B Week 12  HGB    3   18 LBCHG 17 -3.529412e-02 0.54651301 -0.316285179
    57  ARM C   Day 1  HGB    3   19 LBCHG 19  0.000000e+00 0.00000000  0.000000000
    58  ARM C  Week 2  HGB    3   18 LBCHG 17  0.000000e+00 0.65383484 -0.336170855
    59  ARM C  Week 6  HGB    3   17 LBCHG 16 -8.750000e-02 0.61196405 -0.413592625
    60  ARM C Week 12  HGB    3   16 LBCHG 15 -1.666667e-01 0.64438971 -0.523517792
    61  ARM D   Day 1  HGB    3   23 LBCHG 21  0.000000e+00 0.00000000  0.000000000
    62  ARM D  Week 2  HGB    3   22 LBCHG 20 -2.500000e-02 0.55995771 -0.287068273
    63  ARM D  Week 6  HGB    3   20 LBCHG 18 -1.111111e-02 0.42962212 -0.224757164
    64  ARM D Week 12  HGB    3   20 LBCHG 18 -2.000000e-01 0.51449576 -0.455852720
    65  ARM A   Day 1  LYM    3   19 LBCHG 19  0.000000e+00 0.00000000  0.000000000
    66  ARM A  Week 2  LYM    3   19 LBCHG 18  6.166667e-02 0.44072467 -0.157500556
    67  ARM A  Week 6  LYM    3   19 LBCHG 18 -5.555556e-03 0.47330157 -0.240922891
    68  ARM A Week 12  LYM    3   18 LBCHG 17 -3.529412e-03 0.42161803 -0.220305401
    69  ARM B   Day 1  LYM    3   20 LBCHG 20  0.000000e+00 0.00000000  0.000000000
    70  ARM B  Week 2  LYM    3   20 LBCHG 19  2.278947e-01 0.44226160  0.014731470
    71  ARM B  Week 6  LYM    3   18 LBCHG 17  5.588235e-02 0.19624789 -0.045019003
    72  ARM B Week 12  LYM    3   18 LBCHG 15  1.166667e-01 0.30513853 -0.052313420
    73  ARM C   Day 1  LYM    3   19 LBCHG 19  0.000000e+00 0.00000000  0.000000000
    74  ARM C  Week 2  LYM    3   18 LBCHG 17  6.117647e-02 0.25458010 -0.069716541
    75  ARM C  Week 6  LYM    3   17 LBCHG 16 -3.062500e-02 0.29862951 -0.189753433
    76  ARM C Week 12  LYM    3   15 LBCHG 15 -2.133333e-02 0.25939123 -0.164979408
    77  ARM D   Day 1  LYM    3   25 LBCHG 21  0.000000e+00 0.00000000  0.000000000
    78  ARM D  Week 2  LYM    3   22 LBCHG 20 -6.450000e-02 0.53546315 -0.315104470
    79  ARM D  Week 6  LYM    3   19 LBCHG 18 -4.333333e-02 0.43414554 -0.259228833
    80  ARM D Week 12  LYM    3   20 LBCHG 18 -1.461111e-01 0.41560925 -0.352788727
                UCLM
    1   0.0000000000
    2   0.0172791128
    3   0.0160127976
    4  -0.0007788999
    5   0.0000000000
    6   0.0215820188
    7   0.0175484714
    8   0.0101298474
    9   0.0000000000
    10  0.0287318579
    11  0.0143850220
    12  0.0381825143
    13  0.0000000000
    14  0.0060126975
    15  0.0269063663
    16  0.0072092609
    17  0.0000000000
    18  0.0545263620
    19  0.0548062599
    20  0.0498304131
    21  0.0000000000
    22  0.0126133584
    23  0.0273243337
    24  0.0094733686
    25  0.0000000000
    26 -0.0010339117
    27  0.0098166246
    28  0.0301580983
    29  0.0000000000
    30  0.0468242940
    31  0.0330450016
    32  0.0357136247
    33  0.0000000000
    34  1.1236382332
    35  1.0612391846
    36  0.9138940923
    37  0.0000000000
    38  1.3008234830
    39  0.6798480184
    40  0.7642409602
    41  0.0000000000
    42  0.8736358538
    43  0.6530146081
    44  0.7342995059
    45  0.0000000000
    46  1.0074084379
    47  0.6741232315
    48  0.1739695884
    49  0.0000000000
    50  0.3038100615
    51  0.3278189507
    52  0.1944249760
    53  0.0000000000
    54  0.3926065932
    55  0.2865486531
    56  0.2456969440
    57  0.0000000000
    58  0.3361708555
    59  0.2385926247
    60  0.1901844590
    61  0.0000000000
    62  0.2370682730
    63  0.2025349414
    64  0.0558527199
    65  0.0000000000
    66  0.2808338892
    67  0.2298117794
    68  0.2132465772
    69  0.0000000000
    70  0.4410580040
    71  0.1567837086
    72  0.2856467534
    73  0.0000000000
    74  0.1920694820
    75  0.1285034325
    76  0.1223127412
    77  0.0000000000
    78  0.1861044703
    79  0.1725621663
    80  0.0605665048

    Get statistics for mean lab value

    proc_means: input data set 1578 rows and 13 columns
                by: LBTESTCD
                class: ARM VISIT
                var: LBORRES
                stats: n mean
                view: TRUE
                output: 1 datasets

       CLASS1  CLASS2   BY TYPE FREQ     VAR  N        MEAN
    1   ARM A   Day 1 BASO    3   19 LBORRES 19  0.03789474
    2   ARM A  Week 2 BASO    3   19 LBORRES 19  0.03105263
    3   ARM A  Week 6 BASO    3   19 LBORRES 19  0.03473684
    4   ARM A Week 12 BASO    3   18 LBORRES 18  0.02666667
    5   ARM B   Day 1 BASO    3   20 LBORRES 20  0.04100000
    6   ARM B  Week 2 BASO    3   20 LBORRES 20  0.04800000
    7   ARM B  Week 6 BASO    3   18 LBORRES 18  0.03333333
    8   ARM B Week 12 BASO    3   18 LBORRES 16  0.03250000
    9   ARM C   Day 1 BASO    3   19 LBORRES 19  0.02684211
    10  ARM C  Week 2 BASO    3   18 LBORRES 18  0.03944444
    11  ARM C  Week 6 BASO    3   17 LBORRES 17  0.03117647
    12  ARM C Week 12 BASO    3   15 LBORRES 15  0.04466667
    13  ARM D   Day 1 BASO    3   25 LBORRES 21  0.05333333
    14  ARM D  Week 2 BASO    3   22 LBORRES 22  0.03863636
    15  ARM D  Week 6 BASO    3   19 LBORRES 19  0.06210526
    16  ARM D Week 12 BASO    3   20 LBORRES 20  0.03950000
    17  ARM A   Day 1  EOS    3   19 LBORRES 19  0.15947368
    18  ARM A  Week 2  EOS    3   19 LBORRES 19  0.16631579
    19  ARM A  Week 6  EOS    3   19 LBORRES 19  0.16578947
    20  ARM A Week 12  EOS    3   18 LBORRES 18  0.17722222
    21  ARM B   Day 1  EOS    3   20 LBORRES 20  0.22000000
    22  ARM B  Week 2  EOS    3   20 LBORRES 20  0.19600000
    23  ARM B  Week 6  EOS    3   18 LBORRES 18  0.21722222
    24  ARM B Week 12  EOS    3   18 LBORRES 16  0.20250000
    25  ARM C   Day 1  EOS    3   19 LBORRES 19  0.20315789
    26  ARM C  Week 2  EOS    3   18 LBORRES 18  0.17944444
    27  ARM C  Week 6  EOS    3   17 LBORRES 17  0.18352941
    28  ARM C Week 12  EOS    3   15 LBORRES 15  0.18800000
    29  ARM D   Day 1  EOS    3   25 LBORRES 21  0.29095238
    30  ARM D  Week 2  EOS    3   22 LBORRES 22  0.25681818
    31  ARM D  Week 6  EOS    3   19 LBORRES 19  0.25894737
    32  ARM D Week 12  EOS    3   20 LBORRES 20  0.25650000
    33  ARM A   Day 1  HCT    3   20 LBORRES 20 41.84000000
    34  ARM A  Week 2  HCT    3   20 LBORRES 20 42.18000000
    35  ARM A  Week 6  HCT    3   19 LBORRES 19 42.46315789
    36  ARM A Week 12  HCT    3   19 LBORRES 19 42.26842105
    37  ARM B   Day 1  HCT    3   21 LBORRES 21 42.33809524
    38  ARM B  Week 2  HCT    3   20 LBORRES 20 42.86500000
    39  ARM B  Week 6  HCT    3   18 LBORRES 18 42.23888889
    40  ARM B Week 12  HCT    3   18 LBORRES 17 42.48823529
    41  ARM C   Day 1  HCT    3   19 LBORRES 19 42.48421053
    42  ARM C  Week 2  HCT    3   18 LBORRES 18 42.50000000
    43  ARM C  Week 6  HCT    3   17 LBORRES 17 42.28823529
    44  ARM C Week 12  HCT    3   16 LBORRES 16 41.83750000
    45  ARM D   Day 1  HCT    3   23 LBORRES 21 43.05714286
    46  ARM D  Week 2  HCT    3   22 LBORRES 22 43.42727273
    47  ARM D  Week 6  HCT    3   20 LBORRES 20 42.91000000
    48  ARM D Week 12  HCT    3   20 LBORRES 20 42.69000000
    49  ARM A   Day 1  HGB    3   20 LBORRES 20 14.45000000
    50  ARM A  Week 2  HGB    3   20 LBORRES 20 14.52000000
    51  ARM A  Week 6  HGB    3   19 LBORRES 19 14.65789474
    52  ARM A Week 12  HGB    3   19 LBORRES 19 14.51578947
    53  ARM B   Day 1  HGB    3   21 LBORRES 21 14.60000000
    54  ARM B  Week 2  HGB    3   20 LBORRES 20 14.74500000
    55  ARM B  Week 6  HGB    3   18 LBORRES 18 14.60000000
    56  ARM B Week 12  HGB    3   18 LBORRES 17 14.71176471
    57  ARM C   Day 1  HGB    3   19 LBORRES 19 14.54210526
    58  ARM C  Week 2  HGB    3   18 LBORRES 18 14.58333333
    59  ARM C  Week 6  HGB    3   17 LBORRES 17 14.50000000
    60  ARM C Week 12  HGB    3   16 LBORRES 16 14.36250000
    61  ARM D   Day 1  HGB    3   23 LBORRES 21 14.83333333
    62  ARM D  Week 2  HGB    3   22 LBORRES 22 14.91363636
    63  ARM D  Week 6  HGB    3   20 LBORRES 20 14.83000000
    64  ARM D Week 12  HGB    3   20 LBORRES 20 14.75500000
    65  ARM A   Day 1  LYM    3   19 LBORRES 19  1.94631579
    66  ARM A  Week 2  LYM    3   19 LBORRES 19  2.00842105
    67  ARM A  Week 6  LYM    3   19 LBORRES 19  1.90578947
    68  ARM A Week 12  LYM    3   18 LBORRES 18  1.93611111
    69  ARM B   Day 1  LYM    3   20 LBORRES 20  1.84700000
    70  ARM B  Week 2  LYM    3   20 LBORRES 20  2.00600000
    71  ARM B  Week 6  LYM    3   18 LBORRES 18  1.82333333
    72  ARM B Week 12  LYM    3   18 LBORRES 16  1.89625000
    73  ARM C   Day 1  LYM    3   19 LBORRES 19  1.77157895
    74  ARM C  Week 2  LYM    3   18 LBORRES 18  1.88111111
    75  ARM C  Week 6  LYM    3   17 LBORRES 17  1.80705882
    76  ARM C Week 12  LYM    3   15 LBORRES 15  1.78666667
    77  ARM D   Day 1  LYM    3   25 LBORRES 21  1.94476190
    78  ARM D  Week 2  LYM    3   22 LBORRES 22  1.84318182
    79  ARM D  Week 6  LYM    3   19 LBORRES 19  1.85000000
    80  ARM D Week 12  LYM    3   20 LBORRES 20  1.77800000

    Add mean lab values to change from baseline

    Apply formats

    =========================================================================
    Create report
    =========================================================================

    Create output path

    C:\Users\dbosa\AppData\Local\Temp\RtmpuCtffJ/output/example13.rtf

    Create report first so content can be added dynamically

    Loop through lab tests

    **** Lab Test: Basophils (x10⁹/L) ****

    Apply subset

    Create plot

    Create table for mean change/mean value

    Create table for patient counts

    Patch together plot and tables

    Create plot content

    Add content to report

    **** Lab Test: Eosinophils (x10⁹/L) ****

    Apply subset

    Create plot

    Create table for mean change/mean value

    Create table for patient counts

    Patch together plot and tables

    Create plot content

    Add content to report

    **** Lab Test: Hematocrit (%) ****

    Apply subset

    Create plot

    Create table for mean change/mean value

    Create table for patient counts

    Patch together plot and tables

    Create plot content

    Add content to report

    **** Lab Test: Hemoglobin (g/dL) ****

    Apply subset

    Create plot

    Create table for mean change/mean value

    Create table for patient counts

    Patch together plot and tables

    Create plot content

    Add content to report

    **** Lab Test: Lymphocytes (x10⁹/L) ****

    Apply subset

    Create plot

    Create table for mean change/mean value

    Create table for patient counts

    Patch together plot and tables

    Create plot content

    Add content to report

    Write out report to file system

    # A report specification: 5 pages
    - file_path: 'C:\Users\dbosa\AppData\Local\Temp\RtmpuCtffJ/output/example13.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: Archytas right=Study: ABC
    - title 1: 'Figure 1.0'
    - title 2: 'Mean Change From Baseline (HEMATOLOGY)'
    - title 3: 'Safety Population'
    - page_footer: left=Date: 02Feb2024 22:44:23 center=Confidential right=Page [pg] of [tpg]
    - content:
    # A plot specification:
    - height: 6
    - width: 9
    - title 1: 'Laboratory Test: Basophils (x10⁹/L)'
    # A plot specification:
    - height: 6
    - width: 9
    - title 1: 'Laboratory Test: Eosinophils (x10⁹/L)'
    # A plot specification:
    - height: 6
    - width: 9
    - title 1: 'Laboratory Test: Hematocrit (%)'
    # A plot specification:
    - height: 6
    - width: 9
    - title 1: 'Laboratory Test: Hemoglobin (g/dL)'
    # A plot specification:
    - height: 6
    - width: 9
    - title 1: 'Laboratory Test: Lymphocytes (x10⁹/L)'

    =========================================================================
    Clean Up
    =========================================================================

    =========================================================================
    Log End Time: 2024-02-02 22:44:32.173356
    Log Elapsed Time: 0 00:00:15
    =========================================================================

Next: Example 14: AE Severity in Rows