Get started
Your first mighty ADaM program
Here is a minimal example that demonstrates how to specify and render a simple ADSL program with mighty to get you acquainted with the core concepts of the framework.
Study directory guidelines
The only constraints mighty has on the directory structure is the presence of a directory that contains only the following YAML specification files:
- Domain specifications (e.g.,
adsl.yml,adae.yml,adlb.yml) -
_mighty.yml— framework configuration (external dataset keys) -
_study.yml— study-level properties (optional, used by mighty.toolbox for define.xml)
All .yml/.yaml files in this directory (except _mighty.yml and _study.yml) are parsed as domain specifications. Placing non-specification YAML files (such as a connector config) in the specifications directory will cause validation errors.
Other files should live outside the specifications directory:
- A connector config file that specifies where your trial data is located (SDTM, metadata, and ADaM). The
path_connector_configargument togenerate_adam_code()is the file path to the connector config file, embedded verbatim into the generated programs. - Study-specific custom components
- A location where the compiled ADaM programs can be written out to
Set up your framework configuration file
The _mighty.yml file provides framework configuration that spans across all ADaM domains. This includes primary keys for external datasets that are used for joining tables.
For this example, we will focus on a simple ADSL table and only provide keys related to that domain.
_mighty.yml
external_data:
- id: DM
keys: [USUBJID, STUDYID]
- id: LB
keys: [USUBJID, STUDYID, LBSEQ]
repos:
- "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
- "."Set up your ADaM specification
Provide a YAML file that specifies which columns to include in ADSL and how they are derived. The specification only contains columns that belong in the final dataset; source columns needed only during derivation are handled through component dependencies instead. See vignette("adam_specification") for details.
This ADSL table contains 6 columns: 4 simple columns from the base domain, 1 renamed column, and 1 derivation using a custom component.
adsl.yml
id: ADSL
label: Subject Level Analysis Dataset
class: SUBJECT LEVEL ANALYSIS DATASET
structure: One record per subject
keys: [USUBJID, STUDYID]
population:
base:
- domain: DM
depends:
- AGE
filter: '!is.na(AGE)'
global:
- filter: NA
depends:
- NA
columns:
- id: USUBJID
- id: STUDYID
- id: ARM
- id: PLANNED_ARM
method: ARM
- id: AGE
- id: AGE_GRP1
component:
id: "age_group_01.R"Define your custom component
The column AGE_GRP1 in ADSL is derived by using a custom component that contains the logic to process the ADSL table by deriving the additional column AGE_GRP1.
age_group_01.R
#' @title Age group 01
#' @description Grouping of age
#' @type column
#' @depends ADSL AGE
#' @outputs AGE_GRP1
#' @returns `ADSL`
#' @code
ADSL <- ADSL |>
dplyr::mutate(
AGE_GRP1 = cut(
AGE,
breaks = c(-Inf, 18, 65, 75, Inf),
labels = c("< 18 years", "18 - 64 years", "65 - 74 years", ">= 75 years"),
right = FALSE
)
)Render the ADaM program
Call mighty to consolidate, analyze and render your ADSL program:
example_01_main.R
# ADSL with 1 base domain
# - 4 predecessors
# - 1 renamed predecessor
# - 1 derivation
# Load mighty
library(mighty)
# Generate ADaM program
results <- mighty::generate_adam_code(
adam_specifications = "study_dir",
path_connector_config = "_connector.yml"
)
# Print rendered ADaM program
results$programs$`1_ADSL` |> cat()Printing the rendered ADaM program yields a complete program for generating ADSL based on the specifications
#> → Downloading repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Successfully downloaded and cached "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "/tmp/Rtmpndb26W/mighty_example_study/age_group_01.R" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_read_data" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_init_domain" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_filter_domain" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "/tmp/Rtmpndb26W/mighty_example_study/age_group_01.R" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_col_mutate" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_write_data" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_read_data" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_init_domain" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_filter_domain" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "/tmp/Rtmpndb26W/mighty_example_study/age_group_01.R" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_col_mutate" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
#> → Using cached repo "NovoNordisk-OpenSource/mighty.standards@dev/internal-components"
#> → Found "mighty_write_data" in "NovoNordisk-OpenSource/mighty.standards/components@dev/internal-components"
# ADSL-1-read_data -------------------------------------------------------------
cnt <- connector::connect(config = "/tmp/Rtmpndb26W/mighty_example_study/_connector.yml")
DM <- cnt$sdtm$read_cnt(tolower('DM')) |>
dplyr::select(AGE, ARM, STUDYID, USUBJID)
# ADSL-init_domain -------------------------------------------------------------
DM <- DM |>
dplyr::mutate(SRC_ = "DM")
ADSL <- DM |>
dplyr::select(AGE, ARM, STUDYID, USUBJID, SRC_) |>
admiral::convert_blanks_to_na()
# ADSL-filter_domain -----------------------------------------------------------
ADSL <- ADSL |>
dplyr::filter((SRC_ == 'DM' & !is.na(AGE))) |>
dplyr::select(-SRC_)
ADSL <- ADSL |>
dplyr::select(AGE, ARM, STUDYID, USUBJID)
# ADSL-AGE_GRP1 ----------------------------------------------------------------
ADSL <- ADSL |>
dplyr::mutate(
AGE_GRP1 = cut(
AGE,
breaks = c(-Inf, 18, 65, 75, Inf),
labels = c("< 18 years", "18 - 64 years", "65 - 74 years", ">= 75 years"),
right = FALSE
)
)
# ADSL-PLANNED_ARM -------------------------------------------------------------
ADSL <- ADSL |> dplyr::mutate(PLANNED_ARM = ARM)
# ADSL-1-write_data ------------------------------------------------------------
# Sort rows by primary key
ADSL <- ADSL |> dplyr::arrange(USUBJID,
STUDYID)
# Sort columns
ADSL <- ADSL |> dplyr::select(USUBJID,
STUDYID,
ARM,
PLANNED_ARM,
AGE,
AGE_GRP1)
# Save ADaM table
cnt$adam$write_cnt(ADSL, tolower("ADSL.parquet"), overwrite = TRUE)