Skip to contents

Overview

The forestly package creates interactive forest plots for clinical trial analysis & reporting.

  • Safety analysis
    • Specific adverse events analysis
  • Efficacy analysis (future work)
    • Subgroup analysis

We assume ADaM datasets are ready for analysis and leverage metalite data structure to define inputs and outputs.

forestly_adsl$TRTA <- factor(forestly_adsl$TRT01A, levels = c("Xanomeline Low Dose", "Placebo"), labels = c("Low Dose", "Placebo"))

forestly_adae$TRTA <- factor(forestly_adae$TRTA, levels = c("Xanomeline Low Dose", "Placebo"), labels = c("Low Dose", "Placebo"))
meta_forestly(
  dataset_adsl = forestly_adsl,
  dataset_adae = forestly_adae,
  parameter_term = "any;rel;ser",
  population_subset = SAFFL == "Y",
  observation_subset = SAFFL == "Y"
) |>
  prepare_ae_forestly() |>
  format_ae_forestly() |>
  ae_forestly()

Interactive features

The interactive features of the example include:

  • Select different AE criteria.
  • Filter by incidence of AE in one more more group.
  • Revealed information by hovering the mouse over a point.
  • Search bars to find subjects with selected adverse events (AE).
  • Sort value by click the column header.
  • Drill-down listing by clicking \blacktriangleright.

Workflow

The general workflow is:

  1. meta_forestly() constructs input metadata for treatment analysis from ADaM datasets.
  2. prepare_ae_forestly() prepares datasets for interactive forest plot.
  3. format_ae_forestly() formats output layout.
  4. ae_forestly() generates an interactive forest plot.

Here meta_forestly() is a wrapper function of the metalite package. The function is for users to simplify the process to define input parameters required to generate the interactive forest plot.

meta_forestly function require dataset_adsl, dataset_adae, observation_term and population_term arguments. dataset_adsl, dataset_adae are the input ADaM dataset for population and observation. In this example, we will use “apat” for population_term and “wk12” for observation_term. For subset creteria for both terms, we are using SAFFL == "Y" by default in meta_forestly().

meta_forestly(
  dataset_adsl = forestly_adsl,
  dataset_adae = forestly_adae,
  parameter_term = "any;rel;ser",
  population_subset = SAFFL == "Y",
  observation_subset = SAFFL == "Y"
)
#> ADaM metadata: 
#>    .$data_population     Population data with 170 subjects 
#>    .$data_observation    Observation data with 736 records 
#>    .$plan    Analysis plan with 1 plans 
#> 
#> 
#>   Analysis population type:
#>     name        id  group var       subset label
#> 1 'apat' 'USUBJID' 'TRTA'     SAFFL == 'Y'    ''
#> 
#> 
#>   Analysis observation type:
#>       name        id  group var       subset label
#> 1 'safety' 'USUBJID' 'TRTA'     SAFFL == 'Y'    ''
#> 
#> 
#>   Analysis parameter type:
#>    name                         label                     subset
#> 1 'any'          'any adverse events'                           
#> 2 'rel' 'drug-related adverse events' toupper(AREL) == 'RELATED'
#> 3 'ser'      'serious adverse events'               AESER == 'Y'
#> 
#> 
#>   Analysis function:
#>            name                     label
#> 1 'ae_forestly' 'Interactive forest plot'

If user wants to customize these definitions of terms or define new terms, more tutorials can be found at this link.

For paramter level metadata, parameter_term is selected from predefined terms listed below. By default, we choose three parameter terms rel, any and ser and use “;” to concatenate them to allow the three types of AE to be displayed in one interactive forest plot.

Term Subset Criteria Label
any NULL any adverse events
rel toupper(AREL) == "RELATED" drug-related adverse events
g34 ATOXGRN %in% c(3, 4) grade 3-4 adverse events
g340rel ATOXGRN %in% c(3, 4) & AREL == "Y" drug-related grade 3-4 adverse events
g35 ATOXGRN %in% c(3, 4, 5) grade 3-5 adverse events
g350rel ATOXGRN %in% c(3, 4, 5) & AREL == "Y" drug-related grade 3-5 adverse events
nonser AESER != "Y" | is.na(AESER) non-serious adverse events
ser AESER == "Y" serious adverse events
ser0rel AESER == "Y" & AREL == "Y" serious drug-related adverse events
mod toupper(AEACN) %in% c("DOSE REDUCED", "DRUG INTERRUPTED", "DRUG WITHDRAWN") adverse events result in dose modification
dth AESDTH == "Y" adverse events result in death
dtc0rel AESDTH == "Y" & AREL == "Y" drug-related adverse events result in death
disc toupper(AEACN) == "DRUG WITHDRAWN" adverse events resulting in discontinuation
disc0drel toupper(AEACN) == "DRUG WITHDRAWN" & AREL == "Y" drug-related adverse events resulting in discontinuation
disc0ser toupper(AEACN) == "DRUG WITHDRAWN" & AESER == "Y" serious adverse events resulting in discontinuation
disc0ser0rel toupper(AEACN) == "DRUG WITHDRAWN" & AESER == "Y" & AREL == "Y" serious drug-related adverse events resulting in discontinuations
inj toupper(AECAT) == "I" injection-site
noninj toupper(AECAT) != "I" | is.na(AECAT) non-injection-site
inj0rel toupper(AECAT) == "I" & AREL == "Y" drug-related injection-site
noninj0rel (toupper(AECAT) == "I" | is.na(AECAT)) & AREL == "Y" drug-related non-injection-site

In the following example, we define ITT with subset criteria ITTFL == "Y"for population and TEAE with subset criteria TRTEMFL == "Y" for observation. For parameter, we choose ser and nonser from pre-defined parameter list.

meta <- meta_forestly(
  dataset_adsl = forestly_adsl,
  dataset_adae = forestly_adae,
  population_term = "ITT",
  population_subset = ITTFL == "Y",
  observation_term = "TEAE",
  observation_subset = TRTEMFL == "Y",
  parameter_term = "any;ser;nonser;rel"
)
meta
#> ADaM metadata: 
#>    .$data_population     Population data with 170 subjects 
#>    .$data_observation    Observation data with 736 records 
#>    .$plan    Analysis plan with 1 plans 
#> 
#> 
#>   Analysis population type:
#>    name        id  group var       subset label
#> 1 'ITT' 'USUBJID' 'TRTA'     ITTFL == 'Y'    ''
#> 
#> 
#>   Analysis observation type:
#>     name        id  group var         subset label
#> 1 'TEAE' 'USUBJID' 'TRTA'     TRTEMFL == 'Y'    ''
#> 
#> 
#>   Analysis parameter type:
#>       name                         label                      subset
#> 1    'any'          'any adverse events'                            
#> 2    'ser'      'serious adverse events'                AESER == 'Y'
#> 3 'nonser'  'non-serious adverse events' AESER != 'Y' | is.na(AESER)
#> 4    'rel' 'drug-related adverse events'  toupper(AREL) == 'RELATED'
#> 
#> 
#>   Analysis function:
#>            name                     label
#> 1 'ae_forestly' 'Interactive forest plot'

After the metadata is defined, we can create an interactive forest plot as below.

In this section, we calculate statistics and prepare plotting dataset using prepare_ae_forestly(). Argument parameter is required since we can select parameter from the one we defined in metadata.

Then we could use format_ae_forestly() to format the output and ae_forestly() to create the interactive forest plot. Default value is used for all arguments in these two functions.

In the first example, we select any, ser and nonser.

meta |>
  prepare_ae_forestly(parameter = "any;ser;nonser") |>
  format_ae_forestly() |>
  ae_forestly()