diff --git a/.Rbuildignore b/.Rbuildignore index 56888db..7fa3ec9 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,3 +1,15 @@ ^ramnog\.Rproj$ ^\.Rproj\.user$ ^LICENSE\.md$ +^README.Rmd +^_pkgdown.yml +^docs +^.vscode +^.github +^.githooks +^.pre-commit-config.yaml +RELEASE_BODY\.txt +^\.github$ +^_pkgdown\.yml$ +^docs$ +^pkgdown$ diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml new file mode 100644 index 0000000..9188ef7 --- /dev/null +++ b/.github/workflows/pkgdown.yaml @@ -0,0 +1,83 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master, dev] + release: + types: [published] + workflow_dispatch: + +name: pkgdown + +jobs: + pkgdown: + runs-on: ubuntu-latest + # Only restrict concurrency for non-PR jobs + concurrency: + group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::pkgdown, local::. + needs: website + + - name: Build site + run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) + shell: Rscript {0} + + # If not pull request a brand new webpage is deployed + - name: Deploy to GitHub pages 🚀 + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.5.0 + with: + clean: false + branch: gh-pages + folder: docs + + # If pull request the webpage is deployed inside a dev/"PR number" folder for review + - name: Add pkgdown PR Comment + uses: marocchino/sticky-pull-request-comment@v2 + if: github.event_name == 'pull_request' + with: + recreate: true + header: pkgdown + message: | + # Github pages + Review the pkgdown webpage for the PR [here](https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/dev/${{ github.event.pull_request.number }}) + + - name: Copy page to temp folder + if: github.event_name == 'pull_request' + run: | + mkdir -p /home/runner/work/dev + cp -r ./docs/* /home/runner/work/dev + + - name: Check out gh-pages branch + if: github.event_name == 'pull_request' + uses: actions/checkout@v4 + with: + ref: gh-pages + + - name: Copy and push to gh-pages + if: github.event_name == 'pull_request' + run: | + mkdir -p dev/${{ github.event.pull_request.number }} + cp -r /home/runner/work/dev/* ./dev/${{ github.event.pull_request.number }} + git config --global user.email "actions-robot@novonordisk.com" + git config --global user.name "Actions Robot From Github Actions" + git add . + git commit -m "Update gh pages from the PR" + git push \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7670a95..3e202f3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ .Rproj.user inst/doc docs/ +launch.json +.Rhistory +docs diff --git a/DESCRIPTION b/DESCRIPTION index ce5970d..457cc89 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -10,20 +10,27 @@ Description: What the package does (one paragraph). License: MIT + file LICENSE Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.0 +RoxygenNote: 7.3.1 Imports: + data.table (>= 1.14.2), +Suggests: chef, chefCriteria, chefStats, - data.table (>= 1.14.2), -Suggests: knitr, + targets, + usethis, rmarkdown, testthat (>= 3.0.0), - kableExtra (>= 1.4) + kableExtra (>= 1.4), + testr, + tidyr, + pharmaverseadam +Config/testthat/edition: 3 Remotes: + hta-pharma/chefStats, hta-pharma/chef, hta-pharma/chefCriteria, - hta-pharma/chefStats -Config/testthat/edition: 3 + matthew-phelps/testr VignetteBuilder: knitr +URL: https://hta-pharma.github.io/ramnog/ diff --git a/NAMESPACE b/NAMESPACE index d01f28a..b9d5109 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,4 +1,4 @@ # Generated by roxygen2: do not edit by hand -export(mk_adae_demo) +export(dummy_fn) import(data.table) diff --git a/R/dummy_fn.R b/R/dummy_fn.R new file mode 100644 index 0000000..0756249 --- /dev/null +++ b/R/dummy_fn.R @@ -0,0 +1,9 @@ +#' Title +#' @description exists only to import data.table +#' @return Nothing. +#' @export +#' +#' @import data.table +dummy_fn <- function(){ + +} diff --git a/R/mk_adae.R b/R/mk_adae.R deleted file mode 100644 index 84c86f2..0000000 --- a/R/mk_adae.R +++ /dev/null @@ -1,15 +0,0 @@ -#' Demo function to make ADAE data for validation purposes -#' -#' @param study_metadata -#' -#' @return data.table -#' @export -#' @import data.table -mk_adae_demo <- function(study_metadata) { - adsl <- pharmaverseadam::adsl |> data.table::setDT() - adae <- pharmaverseadam::adae |> data.table::setDT() - adae_out <- - merge(adsl, adae[, c(setdiff(names(adae), names(adsl)), "USUBJID"), with = - F], by = "USUBJID", all = TRUE) - adae_out[TRT01A %in% c('Placebo', 'Xanomeline High Dose'), ] -} diff --git a/_pkgdown.yml b/_pkgdown.yml index b9ad023..ef8c868 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,16 +1,10 @@ -url: ~ +url: https://hta-pharma.github.io/ramnog/ template: bootstrap: 5 - - - articles: - - title: Overview navbar: Overview - contents: - - ep_overview - + contents: ep_overview - title: Endpoint Population and Outcome Specification navbar: Endpoint Population and Outcome Specification contents: @@ -20,29 +14,21 @@ articles: - ep_spec_event_def - ep_spec_strata_def - ep_spec_label - - title: Endpoint Statistics navbar: Endpoint Statistics - contents: - - starts_with('methods_') - + contents: starts_with('methods_') - title: Endpoint Results navbar: Endpoint Results - contents: - - starts_with("results") - + contents: starts_with("results") - title: Endpoint Examples navbar: Endpoint Examples - contents: - - starts_with("example_") - + contents: starts_with("example_") - title: Debugging navbar: Debugging - contents: - - debugging - + contents: debugging - title: Development navbar: Development contents: - starts_with("dev") - validation + diff --git a/man/dummy_fn.Rd b/man/dummy_fn.Rd new file mode 100644 index 0000000..1c12ffb --- /dev/null +++ b/man/dummy_fn.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/dummy_fn.R +\name{dummy_fn} +\alias{dummy_fn} +\title{Title} +\usage{ +dummy_fn() +} +\value{ +Nothing. +} +\description{ +exists only to import data.table +} diff --git a/man/mk_adae_demo.Rd b/man/mk_adae_demo.Rd deleted file mode 100644 index 76a32f8..0000000 --- a/man/mk_adae_demo.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mk_adae.R -\name{mk_adae_demo} -\alias{mk_adae_demo} -\title{Demo function to make ADAE data for validation purposes} -\usage{ -mk_adae_demo(study_metadata) -} -\arguments{ -\item{study_metadata}{} -} -\value{ -data.table -} -\description{ -Demo function to make ADAE data for validation purposes -} diff --git a/tests/testthat/_snaps/mild_ae_by_sex.md b/tests/testthat/_snaps/mild_ae_by_sex.md index f2257cd..5387ea3 100644 --- a/tests/testthat/_snaps/mild_ae_by_sex.md +++ b/tests/testthat/_snaps/mild_ae_by_sex.md @@ -1,13 +1,14 @@ # Complex pipeline runs without errors Code - ep_stat[, .(stat_filter, endpoint_group_filter, label, description, qualifiers, - value)] + ep_stat[, .(stat_filter, endpoint_group_filter, stat_result_label, + stat_result_description, stat_result_qualifiers, stat_result_value)] Output stat_filter + 1: TOTAL_ == "total" & TRT01A == "Placebo" - 2: TOTAL_ == "total" & TRT01A == "Xanomeline High Dose" - 3: TOTAL_ == "total" & TRT01A == "Placebo" + 2: TOTAL_ == "total" & TRT01A == "Placebo" + 3: TOTAL_ == "total" & TRT01A == "Xanomeline High Dose" 4: TOTAL_ == "total" & TRT01A == "Xanomeline High Dose" 5: SEX == "F" & TRT01A == "Placebo" --- @@ -17,6 +18,7 @@ 4277: 4278: endpoint_group_filter + 1: AESOC == "GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS" & AESEV == "MILD" 2: AESOC == "GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS" & AESEV == "MILD" 3: AESOC == "GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS" & AESEV == "MILD" @@ -28,16 +30,30 @@ 4276: AESOC == "EAR AND LABYRINTH DISORDERS" & AESEV == "SEVERE" 4277: AESOC == "NEOPLASMS BENIGN, MALIGNANT AND UNSPECIFIED (INCL CYSTS AND POLYPS)" & AESEV == "SEVERE" 4278: AESOC == "NEOPLASMS BENIGN, MALIGNANT AND UNSPECIFIED (INCL CYSTS AND POLYPS)" & AESEV == "SEVERE" - label description qualifiers value - 1: E Number of events 36 - 2: E Number of events 75 - 3: N Number of subjects 86 - 4: N Number of subjects 72 - 5: E Number of events 18 - --- - 4274: P-value interaction not conducted NA - 4275: P-value interaction not conducted NA - 4276: P-value interaction not conducted NA - 4277: P-value interaction not conducted NA - 4278: P-value interaction not conducted NA + stat_result_label stat_result_description + + 1: E Number of events + 2: N Number of subjects + 3: E Number of events + 4: N Number of subjects + 5: E Number of events + --- + 4274: P-value interaction not conducted + 4275: P-value interaction not conducted + 4276: P-value interaction not conducted + 4277: P-value interaction not conducted + 4278: P-value interaction not conducted + stat_result_qualifiers stat_result_value + + 1: 36 + 2: 86 + 3: 75 + 4: 72 + 5: 18 + --- + 4274: NA + 4275: NA + 4276: NA + 4277: NA + 4278: NA diff --git a/tests/testthat/binary_type_2.R b/tests/testthat/binary_type_2.R index 7ac42e7..750dbe6 100644 --- a/tests/testthat/binary_type_2.R +++ b/tests/testthat/binary_type_2.R @@ -23,7 +23,7 @@ test_that("Binary outcomes of type 2 work", { mk_adam_fn = list(mk_adae), ) # ACT --------------------------------------------------------------------- - browser() + targets::tar_make() targets::tar_load(ep_stat) diff --git a/tests/testthat/test-binary_type_2.R b/tests/testthat/test-binary_type_2.R index e340007..3f2dd53 100644 --- a/tests/testthat/test-binary_type_2.R +++ b/tests/testthat/test-binary_type_2.R @@ -27,6 +27,5 @@ test_that("multiplication works", { # ACT --------------------------------------------------------------------- targets::tar_make() targets::tar_load(ep_stat) - browser() }) diff --git a/tests/testthat/test-demographics.R b/tests/testthat/test-demographics.R index 8956a8d..6c73876 100644 --- a/tests/testthat/test-demographics.R +++ b/tests/testthat/test-demographics.R @@ -44,6 +44,7 @@ test_that("Demographics work with other endpoints", { mk_adam_fn = list(mk_adae, mk_advs), ) # ACT --------------------------------------------------------------------- + targets::tar_make() targets::tar_load(ep_stat) @@ -54,7 +55,7 @@ test_that("Demographics work with other endpoints", { actual <- ep_stat[endpoint_group_filter == "AESOC == \"SOCIAL CIRCUMSTANCES\" & AESEV == \"SEVERE\"" & fn_name == "RR" & - stat_filter == "SEX == \"F\""& label == "RR", value] + stat_filter == "SEX == \"F\"" & stat_result_label == "RR", "stat_result_value"] x1 <- x[SEX == "F" & SAFFL == "Y"] x1[AESOC == "SOCIAL CIRCUMSTANCES" & AESEV == "SEVERE", event := TRUE] @@ -65,12 +66,16 @@ test_that("Demographics work with other endpoints", { c <- 0.5 # No outcome, not exposed d <- 53.5 # No outcome, not exposed expected <- (a / sum(a, b)) / (c / sum(c, d)) - expect_identical(actual, expected) + expect_identical(actual$stat_result_value, expected) # Spot check the Demographic stats x <- mk_advs() + a <- + ep_stat[stat_result_qualifiers == "SEX" & + stat_result_label == "n_missing"] |> data.table::setorder(stat_filter) + expected <- x[is.na(SEX), .N, by = .(TRT01A)] |> data.table::setorder(TRT01A) - a <- ep_stat[qualifiers=="SEX"&label=="n_missing"] |> setorder(stat_filter) - expected <- x[is.na(SEX), .N, by=.(TRT01A)] |> setorder(TRT01A) - expect_equal(a$value, expected$N) + expect_equal(a$stat_result_value |> as.integer(), as.integer(expected$N)) }) + + diff --git a/tests/testthat/test-empty_strata_level.R b/tests/testthat/test-empty_strata_level.R index d0090b5..bd4768c 100644 --- a/tests/testthat/test-empty_strata_level.R +++ b/tests/testthat/test-empty_strata_level.R @@ -44,6 +44,6 @@ test_that("stat funtion that produces a 0 returns result ", actual <- - ep_stat[grepl("Placebo", stat_filter), value] + ep_stat[grepl("Placebo", stat_filter), stat_result_value] expect_equal(actual, 0) }) diff --git a/tests/testthat/test-mild_ae_by_sex.R b/tests/testthat/test-mild_ae_by_sex.R index 966373c..6732615 100644 --- a/tests/testthat/test-mild_ae_by_sex.R +++ b/tests/testthat/test-mild_ae_by_sex.R @@ -34,13 +34,13 @@ test_that("Complex pipeline runs without errors", targets::tar_make() # EXPECT ------------------------------------------------------------------ - x <- targets::tar_meta() %>% data.table::as.data.table() + x <- targets::tar_meta() |> data.table::as.data.table() targets::tar_load(ep_stat) expect_true(all(is.na(x$error))) expect_snapshot(ep_stat[, .(stat_filter, endpoint_group_filter, - label, - description, - qualifiers, - value)]) + stat_result_label, + stat_result_description, + stat_result_qualifiers, + stat_result_value)]) }) diff --git a/tests/testthat/test-validate_aesev_aesoc_sex.R b/tests/testthat/test-validate_aesev_aesoc_sex.R index 151c4da..d0b8d56 100644 --- a/tests/testthat/test-validate_aesev_aesoc_sex.R +++ b/tests/testthat/test-validate_aesev_aesoc_sex.R @@ -35,7 +35,6 @@ test_that("Validate statistics - complex endpoint specification", ) } - chef::use_chef( pipeline_dir = "pipeline", r_functions_dir = "R/", @@ -44,17 +43,17 @@ test_that("Validate statistics - complex endpoint specification", mk_adam_fn = list(mk_adae), mk_criteria_fn = list(crit_endpoint, crit_sga, crit_sgd) ) + # ACT --------------------------------------------------------------------- targets::tar_make() targets::tar_load(ep_stat) # EXPECT ------------------------------------------------------------------ - x <- mk_adae() actual <- ep_stat[endpoint_group_filter == "AESOC == \"SOCIAL CIRCUMSTANCES\" & AESEV == \"SEVERE\"" & fn_name == "RR" & - stat_filter == "SEX == \"F\"" &label == "RR", value] + stat_filter == "SEX == \"F\"" & stat_result_label == "RR", stat_result_value] x1 <- x[SEX == "F" & SAFFL == "Y"] x1[AESOC == "SOCIAL CIRCUMSTANCES" & AESEV == "SEVERE", event := TRUE] @@ -71,7 +70,7 @@ test_that("Validate statistics - complex endpoint specification", ep_stat[endpoint_group_filter == "AESOC == \"SOCIAL CIRCUMSTANCES\" & AESEV == \"SEVERE\"" & fn_name == "OR" & stat_filter == "SEX == \"F\"" & - label == "OR", value] + stat_result_label == "OR", stat_result_value] expected <- (a / b) / (c / d) expect_identical(actual, expected) }) @@ -114,7 +113,6 @@ test_that("Valide stats when one strata level is not found", ) } - chef::use_chef( pipeline_dir = "pipeline", r_functions_dir = "R/", @@ -123,6 +121,7 @@ test_that("Valide stats when one strata level is not found", mk_adam_fn = list(mk_adae), mk_criteria_fn = list(crit_endpoint, crit_sga, crit_sgd) ) + # ACT --------------------------------------------------------------------- targets::tar_make() targets::tar_load(ep_stat) @@ -133,7 +132,7 @@ test_that("Valide stats when one strata level is not found", ep_stat[endpoint_group_filter == "AESEV == \"SEVERE\"" & fn_name == "RR" & stat_filter == "SEX == \"F\"" & - label == "RR", value] + stat_result_label == "RR", stat_result_value] x1 <- x[SEX == "F" & SAFFL == "Y"] x1[, event := FALSE] x1[AESEV == "SEVERE", event := TRUE] |> setorder(-event) @@ -158,10 +157,10 @@ test_that("Valide stats when one strata level is not found", # Numeber of Events actual <- - ep_stat[endpoint_group_filter == "AESEV == \"SEVERE\"" & - fn_name == "E" & - strata_var == "SEX"] + ep_stat[ep_stat$endpoint_group_filter == "AESEV == \"SEVERE\"" & + ep_stat$fn_name == "E" & + ep_stat$strata_var == "SEX"] expected <- x1[(event), .N, by = .(TRT01A)][order(TRT01A)][, as.double(N)] - expect_identical(actual$value, expected) + expect_identical(actual$stat_result_value, expected) }) diff --git a/vignettes/ep_spec_adam.Rmd b/vignettes/ep_spec_adam.Rmd deleted file mode 100644 index 756fa52..0000000 --- a/vignettes/ep_spec_adam.Rmd +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: "ADaM Data" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{ADaM Data} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - -# Overview - -Each endpoint needs to be generated from a single analysis data set containing information from one or more ADaM data sets. Each analysis data set is created by a custom ADaM function written by the trial programmer that is referenced in the endpoint specification via the `data_prepare` parameter. The ADaM function contains instructions to what ADaM data sets to join, how to join, and what custom variables e.g., new groupings, to create (if any). - -There are three requirements for the ADaM function: - -1. It must have exactly one input argument `study_metadata` which is an endpoint specification parameter, preferably a 1-element list, that contains any relevant information about the study that may be used to read the ADaM data sets. If no such information is needed, then leave `study_metadata` unused in the function and set it as an empty `list()` in the endpoint specification. -2. It must each return a `data.table` object. If you do not work in `data.table`, you can do this by converting your `tibble` or `data.frame` object to a `data.table` object at the end of the function via `data.table::as.data.table(my_data_frame)`. -3. The returned table must contain all the ADAM variables (and derived variables) that are mentioned in the endpoint specification and also the subject ID variable `USUBJID`. - -In summary, the analysis data set generation is controlled with the following two parameters in the endpoint specification: - -* **data_prepare**: Reference to a custom function that returns a single consolidated analysis table that contains all ADaM data needed in the endpoint. -* **study_metadata**: Object containing study specifics that are relevant for reading the ADAM data. Must be parsed as the input to the ADaM and ADSL functions. May be empty if not needed. - -# Examples - -##### Ex 1.1 - -Here is an example of an ADAM function that first reads the `ADSL` data table from {pharmaverseadam}, filters it down to two treatment arms, and enriches it with a derived variable. Then it merges the enriched ADSL with ADAE from {pharmaverseadam} and return a single table with all the ADaM information from `ADSL` and `ADAE`: - -```{r, eval = FALSE} -# Example of ADaM function that merges information from ADSL and ADAE -mk_adam_ex1_1 <- function(study_metadata) { - - # Read ADSL from {pharmaverseadam} - adsl <- data.table::as.data.table(pharmaverseadam::adsl) - - # Filter treatment arms - adsl <- adsl[adsl$TRT01A %in% c('Placebo', 'Xanomeline High Dose')] - - # New derived ADSL variable - adsl[, AGEGR2 := data.table::fcase(AGE < 70, "AGE < 70", - AGE >= 70, "AGE >= 70")] - - # Read ADAE from {pharmaverseadam} - adae <- data.table::as.data.table(pharmaverseadam::adae) - - # Merge ADSL and ADAE - adae_out <- - merge(adsl, adae[, c(setdiff(names(adae), names(adsl)), "USUBJID"), with = - F], by = "USUBJID", all = TRUE) - return(adae_out) -} -``` - -##### Ex 1.2 - -You might also have cases where information from several ADAM tables are required in your endpoint. Here is an example that returns the same ADaM information as the example above with the addition of the baseline body weight extracted from `ADVS`. So information from three ADaM tables are merged and returned in a single analysis data set: - -```{r, eval = FALSE} -# Example of ADaM function that merges information from three ADaM tables -mk_adam_ex1_2 <- function(study_metadata) { - - # Read ADSL from {pharmaverseadam} - adsl <- data.table::as.data.table(pharmaverseadam::adsl) - - # Filter treatment arms - adsl <- adsl[adsl$TRT01A %in% c('Placebo', 'Xanomeline High Dose')] - - # New derived ADSL variable - adsl[, AGEGR2 := data.table::fcase(AGE < 70, "AGE < 70", - AGE >= 70, "AGE >= 70")] - - # Read ADAE from {pharmaverseadam} - adae <- data.table::as.data.table(pharmaverseadam::adae) - - # Read ADVS from {pharmaverseadam} - advs <- data.table::as.data.table(pharmaverseadam::advs) - - # Identify baseline body weight - advs_bw <- advs[advs$PARAMCD == "WEIGHT" & advs$VISIT == "BASELINE"] - - # Create new variable bw_baseline - advs_bw[["bw_baseline"]] <- advs_bw[["AVAL"]] - - # Merge ADSL, ADAE and baseline body weight from ADVS - ax_out <- - merge(adsl, adae[, c(setdiff(names(adae), names(adsl)), "USUBJID"), with = F], - by = "USUBJID", all.x = TRUE) %>% - merge(., advs_bw[, c("bw_baseline", "USUBJID")], by = "USUBJID", all.x = TRUE) - - return(ax_out) -} -``` - -#### Ex 1.3 - -The ADaM functions, once defined, need to be linked to the corresponding endpoint specifications via the data_prepare parameter. The creation of each endpoint specification is facilitated by the mk_endpoint_str function wherein this data_prepare parameter is established. In the following example, the `mk_adam_ex1_2` function is utilized to produce the analysis data intended for an endpoint. -```{r, eval=FALSE} -# Example of endpoint specification of ADaM function. -# The dots must be replaced with other required parameters. -ep_spec_ex1_3 <- chef::mk_endpoint_str(data_prepare = mk_adam_ex1_2, - ...) -``` diff --git a/vignettes/ep_spec_adam_data.Rmd b/vignettes/ep_spec_adam_data.Rmd index 756fa52..c7b08cd 100644 --- a/vignettes/ep_spec_adam_data.Rmd +++ b/vignettes/ep_spec_adam_data.Rmd @@ -93,8 +93,8 @@ mk_adam_ex1_2 <- function(study_metadata) { # Merge ADSL, ADAE and baseline body weight from ADVS ax_out <- merge(adsl, adae[, c(setdiff(names(adae), names(adsl)), "USUBJID"), with = F], - by = "USUBJID", all.x = TRUE) %>% - merge(., advs_bw[, c("bw_baseline", "USUBJID")], by = "USUBJID", all.x = TRUE) + by = "USUBJID", all.x = TRUE) |> + merge(x=_, advs_bw[, c("bw_baseline", "USUBJID")], by = "USUBJID", all.x = TRUE) return(ax_out) } diff --git a/vignettes/example_ep_spec.Rmd b/vignettes/example_ep_spec.Rmd index 51e4876..26f49e1 100644 --- a/vignettes/example_ep_spec.Rmd +++ b/vignettes/example_ep_spec.Rmd @@ -1,12 +1,12 @@ --- -title: "Endpoint catalog" +title: "Endpoint Catalog" resource_files: - vignettes/figures output: rmarkdown::html_vignette: toc: false vignette: > - %\VignetteIndexEntry{Endpoint catalog} + %\VignetteIndexEntry{Endpoint Catalog} %\VignetteEncoding{UTF-8} %\VignetteEngine{knitr::rmarkdown} editor_options: @@ -15,7 +15,6 @@ editor_options: --- ```{r, include = FALSE} -library(magrittr) library(ramnog) library(testthat) library(data.table) @@ -407,13 +406,13 @@ mk_adlb <- function(study_metadata) { )] # Read ADLB - adlb <- data.table::as.data.table(pharmaverseadam::adlb) %>% - .[.[["PARAMCD"]] == "SODIUM" & - .[["AVISIT"]] %in% c("Baseline", "Week 8", "Week 16"), ] + adlb_0 <- data.table::as.data.table(pharmaverseadam::adlb) + adlb_1 <- adlb_0[adlb_0[["PARAMCD"]] == "SODIUM" & + adlb_0[["AVISIT"]] %in% c("Baseline", "Week 8", "Week 16"), ] adlb2 <- - merge(adlb, - adlb[adlb$AVISIT == "Baseline", c("USUBJID", "AVAL")], + merge(adlb_1, + adlb_1[adlb_1$AVISIT == "Baseline", c("USUBJID", "AVAL")], by = "USUBJID", all.x = TRUE ) diff --git a/vignettes/methods_criteria.Rmd b/vignettes/methods_criteria.Rmd index b05d21d..dd0269f 100644 --- a/vignettes/methods_criteria.Rmd +++ b/vignettes/methods_criteria.Rmd @@ -13,7 +13,6 @@ editor_options: --- ```{r, include = FALSE} -library(magrittr) knitr::opts_chunk$set( collapse = TRUE, comment = "#>" diff --git a/vignettes/ramnog.Rmd b/vignettes/ramnog.Rmd index 6d68636..8280616 100644 --- a/vignettes/ramnog.Rmd +++ b/vignettes/ramnog.Rmd @@ -1,8 +1,8 @@ --- -title: "Quick start" +title: "Quick Start" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{ramnog} + %\VignetteIndexEntry{Quick Start} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -139,14 +139,14 @@ Our goal for this analysis is to count the number of events experiencing an even Now that all the inputs are defined, we can run the pipeline. This is achieved by a call to `tar_make()` from the {targets} package. ```{r,eval=FALSE} -tar_make() +targets::tar_make() ``` Targets will show you which steps in the pipeline are executed and how long each step took: ```{r, echo=FALSE} setwd(tmp_dir) # Do not run, only needed to get the markdown file to run -tar_make() +targets::tar_make() ``` @@ -154,7 +154,7 @@ tar_make() Then, to see the results, you load the cached step of the pipeline corresponding to the results. In our case it will be `ep_stat`, so to load it into the sessions as an object we call ```{r, eval=FALSE} -tar_load(ep_stat) +targets::tar_load(ep_stat) ``` @@ -172,10 +172,10 @@ ep_stat[, .( treatment_refval, strata_var, stat_filter, - label, - description, - qualifiers, - value + stat_result_label, + stat_result_description, + stat_result_qualifiers, + stat_result_value )] |> head() ``` @@ -183,16 +183,16 @@ ep_stat[, .( ```{r, echo=FALSE} setwd(tmp_dir) # Do not run, only needed to get the markdown file to run -tar_load(ep_stat) +targets::tar_load(ep_stat) ep_stat[, .( treatment_var, treatment_refval, strata_var, stat_filter, - label, - description, - qualifiers, - value + stat_result_label, + stat_result_description, + stat_result_qualifiers, + stat_result_value )] |> head() ``` diff --git a/vignettes/results_datamodel.Rmd b/vignettes/results_datamodel.Rmd index 971203e..8f952cf 100644 --- a/vignettes/results_datamodel.Rmd +++ b/vignettes/results_datamodel.Rmd @@ -217,7 +217,7 @@ The table below describes all the columns in the output table. Note that informa Indices (rows) in the analysis data included in the stratum. - Level 6: Statistics + Level 6: Statistics `stat_result_description` char Description of the statistics (returned from statistical function). @@ -225,7 +225,12 @@ The table below describes all the columns in the output table. Note that informa `stat_result_label` char - Label to the statistical value (returned from statistical function). + Label to the statistics (returned from statistical function). + + + `stat_result_qualifiers` + char + Qualifiers to the statistics (returned from statistical function). `stat_result_value` @@ -234,3 +239,4 @@ The table below describes all the columns in the output table. Note that informa + diff --git a/vignettes/validation.Rmd b/vignettes/validation.Rmd index dd84668..faaebd3 100644 --- a/vignettes/validation.Rmd +++ b/vignettes/validation.Rmd @@ -1,8 +1,8 @@ --- -title: "Validation" +title: "Quality control for ramnog ecosystem" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Validation} + %\VignetteIndexEntry{Quality control for ramnog ecosystem} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -19,6 +19,7 @@ library(ramnog) library(testthat) library(data.table) library(chef) +library(testr) library(chefStats) ``` @@ -47,20 +48,27 @@ For example, below is the unit test to ensure the results of an endpoint definit Example of integration test using {testthat} framework ```{r} -test_that("Valide stats when one strata level is not found", +testthat::test_that("Valide stats when one strata level is not found", { # SETUP ------------------------------------------------------------------- testr::create_local_project() - + mk_adae <- function(study_metadata) { + adsl <- pharmaverseadam::adsl |> data.table::setDT() + adae <- pharmaverseadam::adae |> data.table::setDT() + adae_out <- + merge(adsl, adae[, c(setdiff(names(adae), names(adsl)), "USUBJID"), with = + F], by = "USUBJID", all = TRUE) + adae_out[TRT01A %in% c('Placebo', 'Xanomeline High Dose'),] + } mk_ep_def <- function() { - ep <- chef::mk_endpoint_str( + chef::mk_endpoint_str( study_metadata = list(), pop_var = "SAFFL", pop_value = "Y", treatment_var = "TRT01A", treatment_refval = "Xanomeline High Dose", stratify_by = list(c("SEX")), - data_prepare = ramnog::mk_adae_demo, + data_prepare = mk_adae, endpoint_label = "A", custom_pop_filter = "SEX == 'F'", group_by = list(list(AESEV = c())), @@ -75,28 +83,27 @@ test_that("Valide stats when one strata level is not found", ) } - chef::use_chef( pipeline_dir = "pipeline", r_functions_dir = "R/", pipeline_id = "01", mk_endpoint_def_fn = mk_ep_def, - mk_adam_fn = list(mk_adae_demo) + mk_adam_fn = list(mk_adae) ) # ACT --------------------------------------------------------------------- targets::tar_make() targets::tar_load(ep_stat) # EXPECT ------------------------------------------------------------------ - browser() - x <- mk_adae_demo() + # Manually calculated expected results + x <- mk_adae(study_metadata = NULL) # Relative Risk actual <- ep_stat[endpoint_group_filter == "AESEV == \"SEVERE\"" & fn_name == "RR" & - stat_filter == "SEX == \"F\"" & label == "RR", value] + stat_filter == "SEX == \"F\"" & stat_result_label == "RR", stat_result_value] x1 <- x[SEX == "F" & SAFFL == "Y"] x1[, event := FALSE] - x1[AESEV == "SEVERE", event := TRUE] |> setorder(-event) + x1[AESEV == "SEVERE", event := TRUE] |> data.table::setorder(-event) x1_unique <- unique(x1, by = "USUBJID", fromLast = FALSE) two_by_two <- @@ -132,7 +139,10 @@ test_that("Valide stats when one strata level is not found", strata_var == "SEX"] expected <- x1[(event), .N, by = .(TRT01A)][order(TRT01A)][, as.double(N)] - expect_identical(actual$value, expected) + expect_identical(actual$stat_result_value, expected) }) ``` + +## CI/CD +To be added