Biomarker Analysis Catalog - Dev
  • Dev
    • Stable
  1. Graphs
  2. RFG
  3. RFG3
  • Index

  • Tables
    • CPMT
      • CPMT1
      • CPMT2
        • CPMT2A
      • CPMT3
    • DT
      • DT1
        • DT1A
        • DT1B
        • DT1C
      • DT2
        • DT2A
    • TET
      • TET1
        • TET1A

  • Graphs
    • AG
      • AG1
    • DG
      • DG1
        • DG1A
        • DG1B
      • DG2
      • DG3
        • DG3A
      • DG4
    • KG
      • KG1
        • KG1A
        • KG1B
      • KG2
        • KG2A
      • KG3
      • KG4
        • KG4A
        • KG4B
      • KG5
        • KG5A
        • KG5B
    • RFG
      • RFG1
        • RFG1A
      • RFG2
        • RFG2A
        • RFG2B
        • RFG2C
      • RFG3
    • RG
      • RG1
        • RG1A
        • RG1B
        • RG1C
      • RG2
        • RG2A
      • RG3
        • RG3A
        • RG3B
    • SPG
      • SPG1
      • SPG2
    • RNAG
      • RNAG1
      • RNAG2
      • RNAG3
      • RNAG4
      • RNAG5
      • RNAG6
      • RNAG7
      • RNAG8
      • RNAG9
      • RNAG10
    • SFG
      • SFG1
        • SFG1A
        • SFG1B
      • SFG2
        • SFG2A
        • SFG2B
        • SFG2C
        • SFG2D
      • SFG3
        • SFG3A
      • SFG4
      • SFG5
        • SFG5A
        • SFG5B
        • SFG5C
      • SFG6
        • SFG6A
        • SFG6B
        • SFG6C
  1. Graphs
  2. RFG
  3. RFG3

RFG3

Response Forest Graphs Within Treatment Arms by Continuous Biomarker Cutoff

RFG

  • Setup
  • Plot
  • Session Info

For response endpoints it is good to show how to obtain within-treatment-arms comparisons of biomarker subgroups. This is similar to SFG04.

Similarly like in RFG1.

Code
library(tern)
library(ggplot2.utils)
library(dplyr)

adrs <- random.cdisc.data::cadrs %>%
  df_explicit_na() %>%
  filter(PARAMCD == "BESRSPI", BMEASIFL == "Y") %>%
  mutate(
    is_rsp = AVALC %in% c("CR", "PR"),
    ARM_BIN = fct_collapse_only(
      ARM,
      CTRL = c("B: Placebo"),
      TRT = c("A: Drug X", "C: Combination")
    ),
    BMRKR2 = fct_explicit_na_if(BMRKR2, BEP01FL == "N")
  ) %>%
  var_relabel(
    BEP01FL = "BEP",
    BMRKR2 = "Biomarker (Categorical)"
  )

We define a vector of all cutpoints to use for a numeric biomarker (here BMRKR1).

We lapply() over this vector, each time generating a binary factor variable BMRKR1_cut and then tabulating the resulting statistics similar to SFG4, this time including the treatment arms in the subgroups argument. Then we rbind() all tables in the list together.

Code
# across arm ----
cutpoints <- c(4, 5, 8)

adrs2 <- adrs %>%
  mutate(
    BMRKR1 = ifelse(BEP01FL == "N", NA, BMRKR1),
    BMRKR1_cut = explicit_na(cut(BMRKR1, c(-Inf, cutpoints, Inf), right = FALSE))
  ) %>%
  var_relabel(BMRKR1_cut = "Biomarker (Binned Continuous)")

tables_all_cutpoints <- lapply(cutpoints, function(cutpoint) {
  adrs3 <- adrs2 %>%
    filter(!is.na(BMRKR1)) %>%
    mutate(
      BMRKR1_thresh = explicit_na(factor(
        ifelse(BMRKR1 > cutpoint, "Greater", "Less")
      ))
    )
  tbl <- extract_rsp_subgroups(
    variables = list(
      rsp = "is_rsp",
      arm = "BMRKR1_thresh",
      subgroups = c("ARM_BIN")
    ),
    label_all = paste0("BMRKR1 (", cutpoint, ")"),
    data = adrs3
  )
  basic_table() %>%
    tabulate_rsp_subgroups(
      df = tbl,
      vars = c("n_tot", "n", "n_rsp", "prop", "or", "ci")
    )
})

result <- do.call(rbind, tables_all_cutpoints)

We can look at the result in the console already.

Code
result
                                                  Greater                            Less                                            
Baseline Risk Factors        Total n   n    Responders   Response (%)   n    Responders   Response (%)   Odds Ratio       95% CI     
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
BMRKR1 (4)                     97      62       61          98.4%       35       34          97.1%          0.56       (0.03, 9.20)  
Description of Planned Arm                                                                                                           
  CTRL                         36      21       21          100.0%      15       15          100.0%         1.00      (0.00, >999.99)
  TRT                          61      41       40          97.6%       20       19          95.0%          0.48       (0.03, 8.01)  
BMRKR1 (5)                     97      50       49          98.0%       47       46          97.9%          0.94       (0.06, 15.45) 
Description of Planned Arm                                                                                                           
  CTRL                         36      16       16          100.0%      20       20          100.0%         1.00      (0.00, >999.99)
  TRT                          61      34       33          97.1%       27       26          96.3%          0.79       (0.05, 13.21) 
BMRKR1 (8)                     97      16       16          100.0%      81       79          97.5%         <0.01      (0.00, >999.99)
Description of Planned Arm                                                                                                           
  CTRL                         36      3        3           100.0%      33       33          100.0%         1.00      (0.00, >999.99)
  TRT                          61      13       13          100.0%      48       46          95.8%         <0.01      (0.00, >999.99)

We can now produce the forest plot using the g_forest() function. Similarly as in SFG4 we need to specify the col_x, col_y and forest_header arguments for g_forest() by recovering them from one of the original tables.

Code
one_table <- tables_all_cutpoints[[1]]
g2 <- g_forest(
  result,
  col_x = attr(one_table, "col_x"),
  col_ci = attr(one_table, "col_ci"),
  forest_header = attr(one_table, "forest_header"),
  col_symbol_size = attr(one_table, "col_symbol_size")
)

With gridExtra::grid.arrange() the plot can be combined e.g. with a between-treatment-arms comparison, like RFG1A

Code
sessionInfo()
R version 4.4.1 (2024-06-14)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 22.04.4 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so;  LAPACK version 3.10.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

time zone: Etc/UTC
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] dplyr_1.1.4           ggplot2.utils_0.3.2   ggplot2_3.5.1        
[4] tern_0.9.5.9022       rtables_0.6.9.9014    magrittr_2.0.3       
[7] formatters_0.5.9.9001

loaded via a namespace (and not attached):
 [1] utf8_1.2.4                    generics_0.1.3               
 [3] tidyr_1.3.1                   EnvStats_3.0.0               
 [5] stringi_1.8.4                 lattice_0.22-6               
 [7] digest_0.6.37                 evaluate_0.24.0              
 [9] grid_4.4.1                    fastmap_1.2.0                
[11] jsonlite_1.8.8                Matrix_1.7-0                 
[13] backports_1.5.0               survival_3.7-0               
[15] purrr_1.0.2                   fansi_1.0.6                  
[17] scales_1.3.0                  codetools_0.2-20             
[19] Rdpack_2.6.1                  cli_3.6.3                    
[21] ggpp_0.5.8-1                  rlang_1.1.4                  
[23] rbibutils_2.2.16              cowplot_1.1.3                
[25] munsell_0.5.1                 splines_4.4.1                
[27] withr_3.0.1                   yaml_2.3.10                  
[29] tools_4.4.1                   polynom_1.4-1                
[31] checkmate_2.3.2               colorspace_2.1-1             
[33] forcats_1.0.0                 ggstats_0.6.0                
[35] broom_1.0.6                   vctrs_0.6.5                  
[37] R6_2.5.1                      lifecycle_1.0.4              
[39] stringr_1.5.1                 htmlwidgets_1.6.4            
[41] MASS_7.3-61                   pkgconfig_2.0.3              
[43] pillar_1.9.0                  gtable_0.3.5                 
[45] glue_1.7.0                    xfun_0.47                    
[47] tibble_3.2.1                  tidyselect_1.2.1             
[49] knitr_1.48                    farver_2.1.2                 
[51] htmltools_0.5.8.1             labeling_0.4.3               
[53] rmarkdown_2.28                random.cdisc.data_0.3.15.9009
[55] compiler_4.4.1               

Reuse

Copyright 2023, Hoffmann-La Roche Ltd.
RFG2C
RG
Source Code
---
title: RFG3
subtitle: Response Forest Graphs Within Treatment Arms by Continuous Biomarker Cutoff
categories: [RFG]
---

------------------------------------------------------------------------

::: panel-tabset
## Setup

For response endpoints it is good to show how to obtain within-treatment-arms comparisons of biomarker subgroups.
This is similar to [SFG04](../graphs/sfg04.qmd).

Similarly like in [RFG1](../graphs/RFG1/rfg01.qmd).

```{r, message = FALSE}
library(tern)
library(ggplot2.utils)
library(dplyr)

adrs <- random.cdisc.data::cadrs %>%
  df_explicit_na() %>%
  filter(PARAMCD == "BESRSPI", BMEASIFL == "Y") %>%
  mutate(
    is_rsp = AVALC %in% c("CR", "PR"),
    ARM_BIN = fct_collapse_only(
      ARM,
      CTRL = c("B: Placebo"),
      TRT = c("A: Drug X", "C: Combination")
    ),
    BMRKR2 = fct_explicit_na_if(BMRKR2, BEP01FL == "N")
  ) %>%
  var_relabel(
    BEP01FL = "BEP",
    BMRKR2 = "Biomarker (Categorical)"
  )
```

## Plot

We define a vector of all cutpoints to use for a numeric biomarker (here `BMRKR1`).

We `lapply()` over this vector, each time generating a binary factor variable `BMRKR1_cut` and then tabulating the resulting statistics similar to [SFG4](../graphs/sfg04.qmd), this time including the treatment arms in the `subgroups` argument.
Then we `rbind()` all tables in the list together.

```{r}
# across arm ----
cutpoints <- c(4, 5, 8)

adrs2 <- adrs %>%
  mutate(
    BMRKR1 = ifelse(BEP01FL == "N", NA, BMRKR1),
    BMRKR1_cut = explicit_na(cut(BMRKR1, c(-Inf, cutpoints, Inf), right = FALSE))
  ) %>%
  var_relabel(BMRKR1_cut = "Biomarker (Binned Continuous)")

tables_all_cutpoints <- lapply(cutpoints, function(cutpoint) {
  adrs3 <- adrs2 %>%
    filter(!is.na(BMRKR1)) %>%
    mutate(
      BMRKR1_thresh = explicit_na(factor(
        ifelse(BMRKR1 > cutpoint, "Greater", "Less")
      ))
    )
  tbl <- extract_rsp_subgroups(
    variables = list(
      rsp = "is_rsp",
      arm = "BMRKR1_thresh",
      subgroups = c("ARM_BIN")
    ),
    label_all = paste0("BMRKR1 (", cutpoint, ")"),
    data = adrs3
  )
  basic_table() %>%
    tabulate_rsp_subgroups(
      df = tbl,
      vars = c("n_tot", "n", "n_rsp", "prop", "or", "ci")
    )
})

result <- do.call(rbind, tables_all_cutpoints)
```

We can look at the result in the console already.

```{r}
result
```

We can now produce the forest plot using the `g_forest()` function.
Similarly as in [SFG4](../graphs/sfg04.qmd) we need to specify the `col_x`, `col_y` and `forest_header` arguments for `g_forest()` by recovering them from one of the original tables.

```{r, fig.width = 15}
one_table <- tables_all_cutpoints[[1]]
g2 <- g_forest(
  result,
  col_x = attr(one_table, "col_x"),
  col_ci = attr(one_table, "col_ci"),
  forest_header = attr(one_table, "forest_header"),
  col_symbol_size = attr(one_table, "col_symbol_size")
)
```

With `gridExtra::grid.arrange()` the plot can be combined e.g. with a between-treatment-arms comparison, like [RFG1A](../graphs/RFG1/rfg01a.qmd)

{{< include ../misc/session_info.qmd >}}
:::

Made with ❤️ by the Statistical Engineering Team StatisticalEngineering

  • License

  • Edit this page
  • Report an issue
Cookie Preferences