├── .Rbuildignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── config.yml │ ├── feature.yml │ ├── new_template.yml │ └── question.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── check.yaml │ ├── docs.yaml │ └── release.yaml ├── .gitignore ├── .lintr ├── .pre-commit-config.yaml ├── DESCRIPTION ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── archive │ ├── fda-table_02.R │ ├── fda-table_05.R │ ├── fda-table_06.R │ ├── fda-table_11.R │ ├── fda-table_12.R │ ├── fda-table_32.R │ ├── fda-table_33.R │ ├── fda-table_34.R │ ├── fda-table_35.R │ ├── fda-table_36.R │ └── fda-table_38.R ├── argument_convention.R ├── cardinal.R ├── fda-fig_01.R ├── fda-fig_02.R ├── fda-fig_03.R ├── fda-fig_14.R ├── fda-table_03.R ├── fda-table_04.R ├── fda-table_07.R ├── fda-table_08.R ├── fda-table_09.R ├── fda-table_10.R ├── fda-table_13.R ├── fda-table_14.R ├── fda-table_15.R ├── fda-table_16.R ├── fda-table_17.R ├── fda-table_18.R ├── fda-table_20.R ├── fda-table_21.R ├── fda-table_22.R └── utils.R ├── README.md ├── _quarto.yml ├── cardinal.Rproj ├── index.qmd ├── inst ├── WORDLIST └── empty-template.qmd ├── man ├── a_count_occurrences_ser_ae.Rd ├── a_count_occurrences_trtem_ae.Rd ├── alt_counts_df_preproc.Rd ├── ard_make_table_10.Rd ├── argument_convention.Rd ├── assert_flag_variables.Rd ├── basic_table_annot.Rd ├── cardinal-package.Rd ├── h_make_table_09.Rd ├── make_fig_01.Rd ├── make_fig_02.Rd ├── make_fig_03.Rd ├── make_fig_14.Rd ├── make_table_03.Rd ├── make_table_04.Rd ├── make_table_07.Rd ├── make_table_08.Rd ├── make_table_09.Rd ├── make_table_09_gtsummary.Rd ├── make_table_09_rtables.Rd ├── make_table_10.Rd ├── make_table_13.Rd ├── make_table_14.Rd ├── make_table_15.Rd ├── make_table_16.Rd ├── make_table_17.Rd ├── make_table_18.Rd ├── make_table_20.Rd ├── make_table_21.Rd ├── make_table_22.Rd ├── preproc_df_table_10.Rd ├── split_cols_by_arm.Rd └── tbl_make_table_10.Rd ├── quarto ├── about.qmd ├── assets │ ├── images │ │ ├── getting-started │ │ │ ├── gs-pan1.png │ │ │ ├── gs-pan2.png │ │ │ ├── gs-pan3.png │ │ │ ├── gs-pan4.png │ │ │ └── gs-pan4b.png │ │ ├── image-placeholder.png │ │ ├── logo-bi.png │ │ ├── logo-moderna.jpg │ │ ├── logo-roche.png │ │ ├── logo-sanofi.png │ │ ├── logo │ │ │ ├── cardinal.pdf │ │ │ ├── cardinal.png │ │ │ ├── cardinal.svg │ │ │ └── cardinal.webp │ │ ├── pharmaverse.png │ │ └── screenshots │ │ │ ├── fig_01.png │ │ │ ├── fig_02.png │ │ │ ├── fig_03.png │ │ │ ├── fig_14.png │ │ │ ├── table_02.png │ │ │ ├── table_03.png │ │ │ ├── table_04.png │ │ │ ├── table_05.png │ │ │ ├── table_06.png │ │ │ ├── table_07.png │ │ │ ├── table_08.png │ │ │ ├── table_09.png │ │ │ ├── table_10.png │ │ │ ├── table_13.png │ │ │ ├── table_14.png │ │ │ ├── table_15.png │ │ │ ├── table_16.png │ │ │ ├── table_17.png │ │ │ ├── table_18.png │ │ │ ├── table_20.png │ │ │ ├── table_21.png │ │ │ ├── table_22.png │ │ │ ├── table_32.png │ │ │ ├── table_33.png │ │ │ ├── table_34.png │ │ │ ├── table_35.png │ │ │ ├── table_36.png │ │ │ └── table_38.png │ ├── resources │ │ ├── FDA-STF-IG-2022-N-1961-0002.pdf │ │ ├── cardinal_PHUSE_EU_2023.pptx │ │ └── cardinal_RinPharma_Workshop_2023.pptx │ ├── style-dark.scss │ ├── style-light.scss │ └── style.scss ├── catalog │ ├── fda-table_02 │ │ ├── index.qmd │ │ └── result.png │ ├── fda-table_05 │ │ ├── index.qmd │ │ └── result.png │ ├── fda-table_06 │ │ ├── index.qmd │ │ └── result.png │ ├── fda-table_11 │ │ ├── index.qmd │ │ └── result.png │ ├── fda-table_12 │ │ ├── index.qmd │ │ └── result.png │ ├── fda-table_32 │ │ ├── index.qmd │ │ └── result.png │ ├── fda-table_33 │ │ ├── index.qmd │ │ └── result.png │ ├── fda-table_34 │ │ ├── index.qmd │ │ └── result.png │ ├── fda-table_35 │ │ ├── index.qmd │ │ └── result.png │ ├── fda-table_36 │ │ ├── index.qmd │ │ └── result.png │ └── fda-table_38 │ │ ├── index.qmd │ │ └── result.png ├── faq.qmd ├── figure-templates │ ├── template-fig_01.qmd │ ├── template-fig_02.qmd │ ├── template-fig_03.qmd │ └── template-fig_14.qmd ├── getting_started.qmd ├── index-catalog.qmd ├── resources.qmd └── table-templates │ ├── template-table_03.qmd │ ├── template-table_04.qmd │ ├── template-table_07.qmd │ ├── template-table_08.qmd │ ├── template-table_09.qmd │ ├── template-table_10.qmd │ ├── template-table_13.qmd │ ├── template-table_14.qmd │ ├── template-table_15.qmd │ ├── template-table_16.qmd │ ├── template-table_17.qmd │ ├── template-table_18.qmd │ ├── template-table_20.qmd │ ├── template-table_21.qmd │ └── template-table_22.qmd ├── staged_dependencies.yaml └── tests ├── testthat.R └── testthat ├── _snaps ├── fda-fig_01 │ ├── fig_01_custom.svg │ ├── fig_01_default.svg │ ├── fig_01_notbl.svg │ └── fig_01_theme.svg ├── fda-fig_02 │ ├── fig_02_custom.svg │ ├── fig_02_default.svg │ ├── fig_02_notbl.svg │ └── fig_02_theme.svg ├── fda-fig_03 │ ├── fig_03_custom.svg │ ├── fig_03_default.svg │ ├── fig_03_notbl.svg │ └── fig_03_theme.svg ├── fda-fig_14 │ ├── fig_14_custom.svg │ ├── fig_14_default.svg │ ├── fig_14_notbl.svg │ └── fig_14_theme.svg ├── fda-table_03.md ├── fda-table_04.md ├── fda-table_07.md ├── fda-table_08.md ├── fda-table_09.md ├── fda-table_10.md ├── fda-table_13.md ├── fda-table_14.md ├── fda-table_15.md ├── fda-table_16.md ├── fda-table_17.md ├── fda-table_18.md ├── fda-table_20.md ├── fda-table_21.md └── fda-table_22.md ├── setup-options.R ├── setup.R ├── test-fda-fig_01.R ├── test-fda-fig_02.R ├── test-fda-fig_03.R ├── test-fda-fig_14.R ├── test-fda-table_03.R ├── test-fda-table_04.R ├── test-fda-table_07.R ├── test-fda-table_08.R ├── test-fda-table_09.R ├── test-fda-table_10.R ├── test-fda-table_13.R ├── test-fda-table_14.R ├── test-fda-table_15.R ├── test-fda-table_16.R ├── test-fda-table_17.R ├── test-fda-table_18.R ├── test-fda-table_20.R ├── test-fda-table_21.R └── test-fda-table_22.R /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^renv$ 2 | ^renv\.lock$ 3 | CODE_OF_CONDUCT.md 4 | SECURITY.md 5 | ^.*\.Rproj$ 6 | ^\.Rproj\.user$ 7 | ^_pkgdown\.yml$ 8 | ^vignettes/hello\.Rmd$ 9 | ^docs$ 10 | ^\.github$ 11 | README.* 12 | ^\.lintr$ 13 | ^staged_dependencies\.yaml$ 14 | coverage.* 15 | ^\.pre-commit-config\.yaml$ 16 | ^codemeta\.json$ 17 | init.sh 18 | workflows.md 19 | images 20 | ^LICENSE\.md$ 21 | 22 | ^quarto$ 23 | ^\.quarto$ 24 | ^_quarto\.yml$ 25 | ^assets$ 26 | ^table-templates$ 27 | ^figure-templates$ 28 | ^_freeze$ 29 | ^_site$ 30 | ^.*\.qmd$ 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐞 Bug Report 3 | description: File a bug report 4 | title: "[Bug]: " 5 | labels: ["bug"] 6 | projects: ["cardinal"] 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to fill out this bug report! 12 | - type: textarea 13 | id: what-happened 14 | attributes: 15 | label: What happened? 16 | description: Also tell us, what did you expect to happen? 17 | placeholder: Tell us what you see! 18 | value: "A bug happened!" 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: session-info 23 | attributes: 24 | label: sessionInfo() 25 | description: Please copy and paste your output from `sessionInfo()`. This will be automatically formatted into code, so no need for backticks. 26 | render: R 27 | - type: textarea 28 | id: logs 29 | attributes: 30 | label: Relevant log output 31 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 32 | render: R 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | blank_issues_enabled: true 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: ✨ Feature Request 3 | description: Request or propose a new feature 4 | title: "[Feature Request]: <title>" 5 | labels: ["enhancement"] 6 | projects: ["cardinal"] 7 | body: 8 | - type: textarea 9 | attributes: 10 | label: Feature description 11 | validations: 12 | required: true 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new_template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🔨 New Table Template 3 | description: Add a new table template 4 | title: "[New Table]: Table XX" 5 | labels: ["new template"] 6 | projects: ["cardinal"] 7 | body: 8 | - type: textarea 9 | id: table-layout 10 | attributes: 11 | label: Table Layout & Design 12 | description: Take a screenshot of the table and paste it here. 13 | value: | 14 | [Replace this line with your table screenshot by dragging the file here.] 15 | 16 | Please refer to page XX of the [FDA guideline document](https://github.com/pharmaverse/cardinal/files/10744259/FDA-2022-N-1961-0002_attachment_1.pdf) for more details. 17 | - type: textarea 18 | id: table-description 19 | attributes: 20 | label: Table Description 21 | description: Full title/description of the table. 22 | placeholder: Table title 23 | - type: textarea 24 | id: analysis-datasets 25 | attributes: 26 | label: Analysis Datasets 27 | description: Datasets that are used to generate the table. 28 | value: | 29 | [List required datasets here] 30 | 31 | Data from the `random.cdisc.data` package, can be retrieved by `random.cdisc.data::c` followed by your 32 | dataset name. 33 | - type: textarea 34 | id: analysis-filters 35 | attributes: 36 | label: Analysis Filters 37 | description: Filters applied to the data to generate the table. 38 | value: | 39 | Safety population: `SAFFL == "Y"` 40 | [List any additional filters here] 41 | - type: textarea 42 | id: additional-considerations 43 | attributes: 44 | label: Additional Information 45 | description: Any additional information that the developer should know before creating the table function. 46 | placeholder: Additional info 47 | - type: textarea 48 | id: todo 49 | attributes: 50 | label: Developer To Dos 51 | description: Steps to complete as a developer when creating your pull request. 52 | value: | 53 | - [ ] **Table Function:** Create `R/fda-table_XX.R` file with your table-generating function. 54 | - [ ] **Roxygen Documentation:** title, `@details`, document all parameters, `@return`, `@examples`, `@export`. 55 | - [ ] **Tests:** Create `tests/testthat/test-table_XX.R` file with tests for the table function and then run these tests. 56 | - [ ] **Quarto Template:** Create `quarto/table-templates/template-table_XX.qmd` file your table template. 57 | - [ ] **Screenshot:** Add table screenshot as `table_XX.png` to the `quarto/assets/images/screenshots` folder. 58 | - [ ] **_quarto.yml:** Add template to the "Template Library" section of the `_quarto.yml` file. 59 | - [ ] **Template Index:** Run `quarto/assets/generate-template_index.R` script to update the template index. 60 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: ❓ Question 3 | description: Question about usage or documentation 4 | title: "[Question]: <title>" 5 | labels: ["question"] 6 | projects: ["cardinal"] 7 | body: 8 | - type: textarea 9 | attributes: 10 | label: What is your question? 11 | validations: 12 | required: true 13 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Pull Request 2 | 3 | <!--- Replace `#nnn` with your issue link for reference. --> 4 | 5 | Closes #nnn 6 | -------------------------------------------------------------------------------- /.github/workflows/check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Check 🛠 3 | 4 | on: 5 | pull_request: 6 | types: 7 | - opened 8 | - synchronize 9 | - reopened 10 | - ready_for_review 11 | branches: 12 | - main 13 | push: 14 | branches: 15 | - main 16 | workflow_dispatch: 17 | 18 | jobs: 19 | audit: 20 | name: Audit Dependencies 🕵️‍♂️ 21 | uses: insightsengineering/r.pkg.template/.github/workflows/audit.yaml@main 22 | r-cmd: 23 | name: R CMD Check 🧬 24 | uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@main 25 | secrets: 26 | REPO_GITHUB_TOKEN: ${{ secrets.PHARMAVERSE_BOT }} 27 | with: 28 | additional-r-cmd-check-params: --as-cran 29 | additional-env-vars: | 30 | _R_CHECK_CRAN_INCOMING_REMOTE_=false 31 | coverage: 32 | name: Coverage 📔 33 | uses: insightsengineering/r.pkg.template/.github/workflows/test-coverage.yaml@main 34 | secrets: 35 | REPO_GITHUB_TOKEN: ${{ secrets.PHARMAVERSE_BOT }} 36 | linter: 37 | if: github.event_name == 'pull_request' 38 | name: SuperLinter 🦸‍♀️ 39 | uses: insightsengineering/r.pkg.template/.github/workflows/linter.yaml@main 40 | roxygen: 41 | name: Roxygen 🅾 42 | uses: insightsengineering/r.pkg.template/.github/workflows/roxygen.yaml@main 43 | secrets: 44 | REPO_GITHUB_TOKEN: ${{ secrets.PHARMAVERSE_BOT }} 45 | with: 46 | auto-update: true 47 | gitleaks: 48 | name: gitleaks 💧 49 | uses: insightsengineering/r.pkg.template/.github/workflows/gitleaks.yaml@main 50 | spelling: 51 | if: github.event_name == 'pull_request' 52 | name: Spell Check 🆎 53 | uses: insightsengineering/r.pkg.template/.github/workflows/spelling.yaml@main 54 | links: 55 | if: github.event_name == 'pull_request' 56 | name: Check URLs 🌐 57 | uses: insightsengineering/r.pkg.template/.github/workflows/links.yaml@main 58 | vbump: 59 | name: Version Bump 🤜🤛 60 | if: github.event_name == 'push' 61 | uses: insightsengineering/r.pkg.template/.github/workflows/version-bump.yaml@main 62 | secrets: 63 | REPO_GITHUB_TOKEN: ${{ secrets.PHARMAVERSE_BOT }} 64 | version: 65 | name: Version Check 🏁 66 | uses: insightsengineering/r.pkg.template/.github/workflows/version.yaml@main 67 | licenses: 68 | name: License Check 🃏 69 | uses: insightsengineering/r.pkg.template/.github/workflows/licenses.yaml@main 70 | style: 71 | if: github.event_name == 'pull_request' 72 | name: Style Check 👗 73 | uses: insightsengineering/r.pkg.template/.github/workflows/style.yaml@main 74 | with: 75 | auto-update: true 76 | grammar: 77 | if: github.event_name == 'pull_request' 78 | name: Grammar Check 🔤 79 | uses: insightsengineering/r.pkg.template/.github/workflows/grammar.yaml@main 80 | -------------------------------------------------------------------------------- /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Docs 📚 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - "inst/templates/**" 10 | - "_pkgdown.y[a]ml" 11 | - DESCRIPTION 12 | - "**.md" 13 | - "**.Rmd" 14 | - "man/**" 15 | - "LICENSE.*" 16 | - NAMESPACE 17 | - "_quarto.yml" 18 | - "quarto/**" 19 | - "index.qmd" 20 | pull_request: 21 | types: 22 | - opened 23 | - synchronize 24 | - reopened 25 | - ready_for_review 26 | branches: 27 | - main 28 | paths: 29 | - "inst/templates/**" 30 | - "_pkgdown.y[a]ml" 31 | - DESCRIPTION 32 | - "**.md" 33 | - "**.Rmd" 34 | - "man/**" 35 | - "LICENSE.*" 36 | - NAMESPACE 37 | - "_quarto.yml" 38 | - "quarto/**" 39 | - "index.qmd" 40 | workflow_dispatch: 41 | 42 | jobs: 43 | docs: 44 | name: Quarto Docs 📕 45 | runs-on: ubuntu-latest 46 | container: 47 | image: rocker/verse:4.4.0 48 | permissions: 49 | contents: write 50 | steps: 51 | - name: Check out repository 🛎️ 52 | uses: actions/checkout@v4.1.1 53 | 54 | - name: Run Staged dependencies 🎦 55 | uses: insightsengineering/staged-dependencies-action@v1 56 | env: 57 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 58 | with: 59 | enable-check: false 60 | direction: upstream 61 | 62 | - name: Install package 📦 63 | run: R CMD INSTALL . 64 | 65 | - name: Render Quarto Project 📑 66 | run: quarto render --output-dir _site 67 | shell: bash 68 | 69 | - name: Upload Docs ⬆️ 70 | if: github.event_name != 'push' 71 | uses: actions/upload-artifact@v4 72 | with: 73 | name: site 74 | path: ./_site 75 | 76 | - name: Publish Site 🗺️ 77 | if: github.event_name != 'pull_request' 78 | uses: peaceiris/actions-gh-pages@v3 79 | with: 80 | github_token: ${{ secrets.GITHUB_TOKEN }} 81 | publish_dir: ./_site 82 | destination_dir: "." 83 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release 🎈 3 | 4 | on: 5 | push: 6 | tags: 7 | - "v*" 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | name: Build package 🎁 13 | needs: release 14 | uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@main 15 | secrets: 16 | REPO_GITHUB_TOKEN: ${{ secrets.PHARMAVERSE_BOT }} 17 | with: 18 | skip-r-cmd-check: true 19 | skip-r-cmd-install: true 20 | docs: 21 | name: Pkgdown Docs 📚 22 | needs: release 23 | uses: insightsengineering/r.pkg.template/.github/workflows/pkgdown.yaml@main 24 | secrets: 25 | REPO_GITHUB_TOKEN: ${{ secrets.PHARMAVERSE_BOT }} 26 | validation: 27 | name: R Package Validation report 📃 28 | needs: release 29 | uses: insightsengineering/r.pkg.template/.github/workflows/validation.yaml@main 30 | secrets: 31 | REPO_GITHUB_TOKEN: ${{ secrets.PHARMAVERSE_BOT }} 32 | release: 33 | name: Create release 🎉 34 | uses: insightsengineering/r.pkg.template/.github/workflows/release.yaml@main 35 | permissions: 36 | contents: write 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .httr-oauth 3 | .project 4 | .RData 5 | .Rhistory 6 | .Rproj.user 7 | .Ruserdata 8 | .settings/** 9 | *.html 10 | *.Rcheck 11 | *.rprof 12 | *.sas.txt 13 | *~ 14 | /.project 15 | devel/* 16 | doc 17 | docs 18 | inst/outputs/* 19 | logs 20 | Meta 21 | packrat/lib*/ 22 | temp 23 | temp_w 24 | templates/ 25 | tmp.* 26 | vignettes/*.html 27 | vignettes/*.md 28 | vignettes/*.R 29 | coverage.* 30 | .vscode/ 31 | node_modules/ 32 | package-lock.json 33 | package.json 34 | 35 | quarto/.quarto/ 36 | quarto/site_libs/ 37 | /.quarto/ 38 | site_libs 39 | _site 40 | _freeze 41 | _cache 42 | cache 43 | *_cache 44 | *_data 45 | *_files 46 | figures 47 | -------------------------------------------------------------------------------- /.lintr: -------------------------------------------------------------------------------- 1 | linters: linters_with_defaults( 2 | line_length_linter = line_length_linter(120), 3 | cyclocomp_linter = NULL, 4 | object_usage_linter = NULL 5 | ) 6 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # All available hooks: https://pre-commit.com/hooks.html 3 | # R specific hooks: https://github.com/lorenzwalthert/precommit 4 | repos: 5 | - repo: https://github.com/lorenzwalthert/precommit 6 | rev: v0.4.3.9009 7 | hooks: 8 | - id: style-files 9 | args: [--style_pkg=styler, --style_fun=tidyverse_style] 10 | - id: roxygenize 11 | additional_dependencies: 12 | - stringr 13 | # codemeta must be above use-tidy-description when both are used 14 | # - id: codemeta-description-updated 15 | - id: use-tidy-description 16 | - id: spell-check 17 | exclude: > 18 | (?x)^( 19 | data/.*| 20 | (.*/|)\.Rprofile| 21 | (.*/|)\.Renviron| 22 | (.*/|)\.gitignore| 23 | (.*/|)NAMESPACE| 24 | (.*/|)DESCRIPTION| 25 | (.*/|)WORDLIST| 26 | (.*/|)LICENSE| 27 | (.*/|)\.Rbuildignore| 28 | (.*/|)\.lintr| 29 | (.*/|)_pkgdown.yaml| 30 | (.*/|)staged_dependencies.yaml| 31 | (.*/|)\.pre-commit-.*| 32 | \.github/.*| 33 | .*\.[rR]| 34 | .*\.Rproj| 35 | .*\.py| 36 | .*\.png| 37 | .*\.feather| 38 | .*\.rds| 39 | .*\.Rds| 40 | .*\.sh| 41 | .*\.RData 42 | )$ 43 | - id: lintr 44 | - id: readme-rmd-rendered 45 | - id: parsable-R 46 | - id: no-browser-statement 47 | - id: deps-in-desc 48 | - repo: https://github.com/pre-commit/mirrors-prettier 49 | rev: v4.0.0-alpha.8 50 | hooks: 51 | - id: prettier 52 | - repo: https://github.com/pre-commit/pre-commit-hooks 53 | rev: v5.0.0 54 | hooks: 55 | - id: check-added-large-files 56 | args: ["--maxkb=200"] 57 | - id: end-of-file-fixer 58 | exclude: '\.Rd' 59 | - id: trailing-whitespace 60 | exclude: '\.Rd' 61 | - id: check-yaml 62 | - id: no-commit-to-branch 63 | - id: mixed-line-ending 64 | args: ["--fix=lf"] 65 | - id: detect-aws-credentials 66 | args: ["--allow-missing-credentials"] 67 | - id: detect-private-key 68 | - id: forbid-new-submodules 69 | - id: check-symlinks 70 | - repo: local 71 | hooks: 72 | - id: forbid-to-commit 73 | name: Don't commit common R artifacts 74 | entry: Cannot commit .Rhistory, .RData, .Rds or .rds. 75 | language: fail 76 | files: '\.Rhistory|\.RData|\.Rds|\.rds$' 77 | # `exclude: <regex>` to allow committing specific files. 78 | - repo: https://github.com/igorshubovych/markdownlint-cli 79 | rev: v0.45.0 80 | hooks: 81 | - id: markdownlint 82 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Type: Package 2 | Package: cardinal 3 | Title: FDA Safety Tables and Figures 4 | Version: 0.1.0.9067 5 | Date: 2025-05-23 6 | Authors@R: 7 | person("Pawel", "Rucki", , "pawel.rucki@roche.com", role = c("aut", "cre")) 8 | Description: R package with implementation of Safety Tables and Figures 9 | issued by FDA. 10 | License: Apache License (>= 2) 11 | URL: https://github.com/pharmaverse/cardinal/ 12 | BugReports: https://github.com/pharmaverse/cardinal/issues 13 | Depends: 14 | R (>= 3.6), 15 | tern (>= 0.9.5) 16 | Imports: 17 | admiraldev (>= 1.1.0), 18 | cards (>= 0.4.0), 19 | cardx (>= 0.2.2), 20 | checkmate (>= 2.1.0), 21 | cowplot (>= 1.0.0), 22 | dplyr (>= 1.0.0), 23 | formatters (>= 0.5.8), 24 | ggplot2 (>= 3.5.0), 25 | ggsurvfit (>= 1.1.0), 26 | gt (>= 0.10.1), 27 | gtsummary (>= 2.0.4), 28 | lubridate (>= 1.7.10), 29 | magrittr (>= 1.5), 30 | purrr (>= 1.0.1), 31 | rlang (>= 0.4.11), 32 | rlistings (>= 0.2.9), 33 | rtables (>= 0.6.9), 34 | tfrmt (>= 0.1.1), 35 | tidyr (>= 0.8.3), 36 | Tplyr (>= 1.2.1) 37 | Suggests: 38 | knitr (>= 1.42), 39 | pharmaverseadam (>= 1.1.0), 40 | random.cdisc.data (>= 0.3.15), 41 | svglite (>= 2.1.2), 42 | testthat (>= 3.1.9), 43 | withr (>= 2.0.0) 44 | biocViews: 45 | Config/testthat/edition: 3 46 | Encoding: UTF-8 47 | Language: en-US 48 | LazyData: true 49 | Roxygen: list(markdown = TRUE) 50 | RoxygenNote: 7.3.2 51 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(alt_counts_df_preproc) 4 | export(basic_table_annot) 5 | export(make_fig_01) 6 | export(make_fig_02) 7 | export(make_fig_03) 8 | export(make_fig_14) 9 | export(make_table_03) 10 | export(make_table_04) 11 | export(make_table_07) 12 | export(make_table_08) 13 | export(make_table_09) 14 | export(make_table_09_gtsum) 15 | export(make_table_09_gtsummary) 16 | export(make_table_09_rtables) 17 | export(make_table_09_tplyr) 18 | export(make_table_10) 19 | export(make_table_10_gtsummary) 20 | export(make_table_10_rtables) 21 | export(make_table_13) 22 | export(make_table_14) 23 | export(make_table_15) 24 | export(make_table_16) 25 | export(make_table_17) 26 | export(make_table_18) 27 | export(make_table_20) 28 | export(make_table_21) 29 | export(make_table_22) 30 | export(split_cols_by_arm) 31 | import(Tplyr) 32 | import(cards) 33 | import(cardx) 34 | import(checkmate) 35 | import(dplyr) 36 | import(ggplot2) 37 | import(gt) 38 | import(gtsummary) 39 | import(rtables) 40 | import(tern) 41 | import(tfrmt) 42 | importFrom(admiraldev,assert_filter_cond) 43 | importFrom(cowplot,get_legend) 44 | importFrom(cowplot,plot_grid) 45 | importFrom(formatters,var_labels) 46 | importFrom(formatters,var_relabel) 47 | importFrom(formatters,with_label) 48 | importFrom(magrittr,"%>%") 49 | importFrom(purrr,walk) 50 | importFrom(rlang,":=") 51 | importFrom(rlang,.data) 52 | importFrom(rlistings,as_listing) 53 | importFrom(stats,median) 54 | importFrom(stats,prop.test) 55 | importFrom(stats,qt) 56 | importFrom(stats,quantile) 57 | importFrom(stats,sd) 58 | importFrom(stats,setNames) 59 | importFrom(tidyr,pivot_longer) 60 | importFrom(tidyr,pivot_wider) 61 | importFrom(tidyr,separate_rows) 62 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # cardinal 0.1.0.9067 2 | 3 | * Initial release. 4 | -------------------------------------------------------------------------------- /R/archive/fda-table_34.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 34: Patients With Serious Adverse Events by System Organ Class, FDA Medical Query (Narrow) and 2 | #' Preferred Term, Safety Population, Pooled Analysis (or Trial X) 3 | #' 4 | #' @details 5 | #' * `adae` must contain the variables `AEBODSYS`, `AESER`, and the variables specified by 6 | #' `arm_var`, `id_var`, `saffl_var`, `trtemfl_var`, `fmqsc_var`, `fmqnam_var`, and `pref_var`. 7 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. 8 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 9 | #' flag variables are treated as `"N"`. 10 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 11 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 12 | #' * All-zero rows are removed by default (see `prune_0` argument). 13 | #' 14 | #' @inheritParams argument_convention 15 | #' 16 | #' @examples 17 | #' library(dplyr) 18 | #' 19 | #' adae <- random.cdisc.data::cadae 20 | #' adsl <- random.cdisc.data::cadsl 21 | #' 22 | #' set.seed(1) 23 | #' adae <- adae %>% 24 | #' rename(FMQ01SC = SMQ01SC) %>% 25 | #' mutate( 26 | #' AESER = sample(c("Y", "N"), size = nrow(adae), replace = TRUE), 27 | #' FMQ01NAM = sample(c("FMQ1", "FMQ2", "FMQ3"), size = nrow(adae), replace = TRUE) 28 | #' ) 29 | #' adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 30 | #' 31 | #' tbl <- make_table_34(adae = adae, alt_counts_df = adsl) 32 | #' tbl 33 | #' 34 | #' @export 35 | make_table_34 <- function(adae, 36 | alt_counts_df = NULL, 37 | show_colcounts = TRUE, 38 | id_var = "USUBJID", 39 | arm_var = "ARM", 40 | saffl_var = "SAFFL", 41 | trtemfl_var = "TRTEMFL", 42 | fmqsc_var = "FMQ01SC", 43 | fmqnam_var = "FMQ01NAM", 44 | fmq_scope = "NARROW", 45 | pref_var = "AEDECOD", 46 | lbl_pref_var = formatters::var_labels(adae, fill = TRUE)[pref_var], 47 | lbl_overall = NULL, 48 | risk_diff = NULL, 49 | prune_0 = TRUE, 50 | na_level = "<Missing>", 51 | annotations = NULL) { 52 | checkmate::assert_subset(c( 53 | "AEBODSYS", arm_var, id_var, saffl_var, trtemfl_var, fmqsc_var, fmqnam_var, 54 | pref_var 55 | ), names(adae)) 56 | assert_flag_variables(adae, saffl_var, trtemfl_var) 57 | checkmate::assert_subset(toupper(fmq_scope), c("NARROW", "BROAD")) 58 | 59 | adae <- adae %>% 60 | filter(.data[[saffl_var]] == "Y", AESER == "Y", .data[[trtemfl_var]] == "Y", .data[[fmqsc_var]] == fmq_scope) %>% 61 | df_explicit_na(na_level = na_level) 62 | adae[[fmqnam_var]] <- with_label(adae[[fmqnam_var]], paste0("FMQ (", tools::toTitleCase(tolower(fmq_scope)), ")")) 63 | 64 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) 65 | 66 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 67 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 68 | split_rows_by( 69 | "AEBODSYS", 70 | child_labels = "visible", 71 | split_fun = drop_split_levels, 72 | label_pos = "topleft", 73 | split_label = obj_label(adae$AEBODSYS) 74 | ) %>% 75 | split_rows_by( 76 | fmqnam_var, 77 | child_labels = "hidden", 78 | label_pos = "topleft", 79 | split_label = obj_label(adae[[fmqnam_var]]) 80 | ) %>% 81 | summarize_num_patients( 82 | var = id_var, 83 | .stats = "unique", 84 | .labels = c(unique = NULL), 85 | riskdiff = !is.null(risk_diff) 86 | ) %>% 87 | count_occurrences( 88 | vars = pref_var, 89 | drop = FALSE, 90 | riskdiff = !is.null(risk_diff) 91 | ) %>% 92 | append_topleft(paste(" ", lbl_pref_var)) 93 | 94 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 95 | if (prune_0) tbl <- prune_table(tbl) 96 | 97 | tbl 98 | } 99 | -------------------------------------------------------------------------------- /R/archive/fda-table_36.R: -------------------------------------------------------------------------------- 1 | #' Table 36. Patients With Adverse Events by System Organ Class and Preferred Term, Safety 2 | #' Population, Pooled Analysis (or Trial X) 3 | #' 4 | #' @details 5 | #' * `adae` must contain the variables specified by `id_var`, `arm_var`, `saffl_var`, `soc_var`, 6 | #' and `pref_var`. 7 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. 8 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 9 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 10 | #' * All-zero rows are removed by default (see `prune_0` argument). 11 | #' 12 | #' @inheritParams argument_convention 13 | #' 14 | #' @return 15 | #' * `make_table_36` returns an `rtables` table object. 16 | #' 17 | #' @examples 18 | #' adsl <- random.cdisc.data::cadsl 19 | #' adae <- random.cdisc.data::cadae 20 | #' 21 | #' tbl <- make_table_36(adae = adae, alt_counts_df = adsl) 22 | #' tbl 23 | #' 24 | #' @export 25 | make_table_36 <- function( 26 | adae, 27 | alt_counts_df = NULL, 28 | show_colcounts = TRUE, 29 | id_var = "USUBJID", 30 | arm_var = "ARM", 31 | saffl_var = "SAFFL", 32 | soc_var = "AESOC", 33 | pref_var = "AEDECOD", 34 | lbl_soc_var = formatters::var_labels(adae, fill = TRUE)[soc_var], 35 | lbl_overall = NULL, 36 | risk_diff = NULL, 37 | prune_0 = FALSE, 38 | annotations = NULL) { 39 | adae <- adae %>% 40 | filter(.data[[saffl_var]] == "Y") %>% 41 | df_explicit_na() 42 | 43 | alt_counts_df <- alt_counts_df_preproc( 44 | alt_counts_df, 45 | id_var, 46 | arm_var, 47 | saffl_var 48 | ) 49 | 50 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 51 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 52 | split_rows_by( 53 | soc_var, 54 | label_pos = "topleft", 55 | split_label = lbl_soc_var 56 | ) %>% 57 | summarize_num_patients( 58 | var = id_var, 59 | riskdiff = !is.null(risk_diff), 60 | .stats = "unique", 61 | .labels = c(unique = NULL) 62 | ) %>% 63 | count_occurrences( 64 | vars = pref_var, 65 | drop = FALSE, 66 | riskdiff = !is.null(risk_diff) 67 | ) 68 | 69 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 70 | if (prune_0) tbl <- prune_table(tbl) 71 | 72 | tbl 73 | } 74 | -------------------------------------------------------------------------------- /R/archive/fda-table_38.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 38: Patients With Adverse Events by System Organ Class, FDA Medical Query (Broad) and Preferred Term, 2 | #' Safety Population, Pooled Analysis (or Trial X) 3 | #' 4 | #' @details 5 | #' * `adae` must contain the variables `AEBODSYS`, `AESER`, and the variables specified by 6 | #' `arm_var`, `id_var`, `saffl_var`, `trtemfl_var`, `fmqsc_var`, `fmqnam_var`, and `pref_var`. 7 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. 8 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 9 | #' flag variables are treated as `"N"`. 10 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 11 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 12 | #' * All-zero rows are removed by default (see `prune_0` argument). 13 | #' 14 | #' @inheritParams argument_convention 15 | #' 16 | #' @examples 17 | #' library(dplyr) 18 | #' 19 | #' adae <- random.cdisc.data::cadae 20 | #' adsl <- random.cdisc.data::cadsl 21 | #' 22 | #' set.seed(1) 23 | #' adae <- adae %>% 24 | #' rename(FMQ01SC = SMQ01SC) %>% 25 | #' mutate( 26 | #' AESER = sample(c("Y", "N"), size = nrow(adae), replace = TRUE), 27 | #' FMQ01NAM = sample(c("FMQ1", "FMQ2", "FMQ3"), size = nrow(adae), replace = TRUE) 28 | #' ) 29 | #' adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "Broad" 30 | #' 31 | #' tbl <- make_table_38(adae = adae, alt_counts_df = adsl) 32 | #' tbl 33 | #' 34 | #' @export 35 | make_table_38 <- function(adae, 36 | alt_counts_df = NULL, 37 | show_colcounts = TRUE, 38 | id_var = "USUBJID", 39 | arm_var = "ARM", 40 | saffl_var = "SAFFL", 41 | trtemfl_var = "TRTEMFL", 42 | fmqsc_var = "FMQ01SC", 43 | fmqnam_var = "FMQ01NAM", 44 | fmq_scope = "BROAD", 45 | pref_var = "AEDECOD", 46 | lbl_overall = NULL, 47 | lbl_pref_var = formatters::var_labels(adae, fill = TRUE)[pref_var], 48 | risk_diff = NULL, 49 | prune_0 = TRUE, 50 | na_level = "<Missing>", 51 | annotations = NULL) { 52 | assert_subset(c( 53 | "AEBODSYS", arm_var, id_var, saffl_var, trtemfl_var, fmqsc_var, 54 | fmqnam_var, pref_var 55 | ), names(adae)) 56 | assert_flag_variables(adae, saffl_var, trtemfl_var) 57 | assert_subset(toupper(fmq_scope), c("NARROW", "BROAD")) 58 | 59 | adae <- adae %>% 60 | filter(.data[[saffl_var]] == "Y", .data[[trtemfl_var]] == "Y", .data[[fmqsc_var]] == fmq_scope) %>% 61 | df_explicit_na(na_level = na_level) 62 | adae[[fmqnam_var]] <- with_label(adae[[fmqnam_var]], paste0("FMQ (", tools::toTitleCase(tolower(fmq_scope)), ")")) 63 | 64 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) 65 | 66 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 67 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 68 | split_rows_by( 69 | var = "AEBODSYS", 70 | split_fun = drop_split_levels, 71 | split_label = obj_label(adae$AEBODSYS), 72 | label_pos = "topleft" 73 | ) %>% 74 | split_rows_by( 75 | fmqnam_var, 76 | child_labels = "hidden", 77 | label_pos = "topleft", 78 | split_label = obj_label(adae[[fmqnam_var]]) 79 | ) %>% 80 | summarize_num_patients( 81 | var = id_var, 82 | .stats = "unique", 83 | .labels = c(unique = NULL), 84 | riskdiff = !is.null(risk_diff) 85 | ) %>% 86 | count_occurrences( 87 | vars = pref_var, 88 | riskdiff = !is.null(risk_diff) 89 | ) %>% 90 | append_topleft(paste(" ", lbl_pref_var)) 91 | 92 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 93 | if (prune_0) tbl <- prune_table(tbl) 94 | 95 | tbl 96 | } 97 | -------------------------------------------------------------------------------- /R/cardinal.R: -------------------------------------------------------------------------------- 1 | #' cardinal Package 2 | #' 3 | #' Implementation of FDA Safety Tables and Figures 4 | #' 5 | #' @keywords internal 6 | "_PACKAGE" 7 | 8 | #' @import dplyr ggplot2 cards cardx checkmate gt gtsummary rtables tern tfrmt Tplyr 9 | #' @importFrom rlang .data := 10 | #' @importFrom magrittr %>% 11 | #' @importFrom purrr walk 12 | #' @importFrom stats median sd quantile prop.test qt setNames 13 | #' @importFrom tidyr pivot_longer separate_rows pivot_wider 14 | #' @importFrom formatters with_label var_labels var_relabel 15 | #' @importFrom rlistings as_listing 16 | #' @importFrom cowplot plot_grid get_legend 17 | #' @importFrom admiraldev assert_filter_cond 18 | NULL 19 | 20 | # Fix R CMD check warning for missing global definitions 21 | utils::globalVariables(c( 22 | ".", "AEACN", "AESCONG", "AESDISAB", "AESDTH", "AESER", "AESHOSP", "AESIFL", "AESLIFE", "AESMIE", "AGE", 23 | "AGESEX", "AVAL", "AVALU", "AVISITN", "DOSAGE", "DOSDUR", "DTHADY", "DTHCAT", "DTHCAUS", "DTHFL", "DCSREAS", 24 | "MAX_DIABP", "MAX_SYSBP", "PARAMCD", "SEX", "TRTDUR", "TRTDUR_MONTHS", "TRTEDT", "ASER", "EOSSTT", "EOTSTT", 25 | "ITTFL", "PPROTFL", "RANDFL", "TRTEMFL", "TRTSDT", "USUBJID", "column", "median", "ord_layer_1", "ord_layer_2", 26 | "ord_layer_index", "param", "pct", "row_label1", "row_label2", "sd", "tbl_lbl", "value", "ENRLDT", "RANDDT", 27 | "G110", "G60", "G90", "GE120", "L60", "N", "val", "id_var", "PT_PCT", "arm", "x", "TLSTFU", "se", "lower_ci", 28 | "upper_ci", "SBP90", "DBP60", "STATUS", "D_ANY", "D_LT1", "D_GT1", "D_GT3", "D_GT6", "D_GT12", 29 | "MIN_DIABP", "MIN_SYSBP" 30 | )) 31 | -------------------------------------------------------------------------------- /R/fda-table_03.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 3: Patient Screening and Enrollment, Trials A and B 2 | #' 3 | #' @details 4 | #' * `adsl` must contain `ENRLDT`, `RANDDT`, and the variables specified by `id_var`, `arm_var`, `scrnfl_var`, 5 | #' `scrnfailfl_var`, and `scrnfail_var`. 6 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var` and `id_var`. 7 | #' * Patients are considered enrolled in they have an enrollment date (`ENRLDT` is not missing), and are considered 8 | #' randomized if they have a randomization date (`RANDDT` is not missing). 9 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 10 | #' flag variables are treated as `"N"`. 11 | #' * Columns are split by arm. 12 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 13 | #' * All-zero rows are removed by default (see `prune_0` argument). 14 | #' 15 | #' @inheritParams argument_convention 16 | #' @param scrnfl_var (`character`)\cr variable from `df` that indicates whether patients were screened. 17 | #' @param scrnfailfl_var (`character`)\cr variable from `df` that indicates screening failure. 18 | #' @param scrnfail_var (`character`)\cr variable from `df` that contains reasons for screening failure. 19 | #' 20 | #' @examples 21 | #' library(dplyr) 22 | #' 23 | #' set.seed(1) 24 | #' adsl <- random.cdisc.data::cadsl 25 | #' adsl$RANDDT[sample(seq_len(nrow(adsl)), 100)] <- NA 26 | #' scrnfail_reas_lvls <- c( 27 | #' "Inclusion/exclusion criteria not met", "Patient noncompliance", "Consent withdrawn", "Other" 28 | #' ) 29 | #' adsl <- adsl %>% 30 | #' mutate( 31 | #' ENRLDT = RANDDT, 32 | #' SCRNFL = "Y", 33 | #' SCRNFRS = factor(sample(scrnfail_reas_lvls, size = nrow(adsl), replace = TRUE), 34 | #' levels = scrnfail_reas_lvls 35 | #' ), 36 | #' SCRNFAILFL = ifelse(is.na(ENRLDT), "Y", "N") 37 | #' ) 38 | #' adsl$SCRNFRS[adsl$SCRNFL == "N" | !is.na(adsl$ENRLDT)] <- NA 39 | #' 40 | #' tbl <- make_table_03( 41 | #' df = adsl, scrnfl_var = "SCRNFL", scrnfailfl_var = "SCRNFAILFL", scrnfail_var = "SCRNFRS" 42 | #' ) 43 | #' tbl 44 | #' 45 | #' @export 46 | make_table_03 <- function(df, 47 | alt_counts_df = NULL, 48 | show_colcounts = FALSE, 49 | arm_var = "ARM", 50 | id_var = "USUBJID", 51 | scrnfl_var, 52 | scrnfailfl_var, 53 | scrnfail_var, 54 | lbl_overall = NULL, 55 | prune_0 = TRUE, 56 | annotations = NULL) { 57 | assert_subset( 58 | c(id_var, scrnfl_var, scrnfailfl_var, scrnfail_var, "ENRLDT", "RANDDT", arm_var), names(df) 59 | ) 60 | assert_flag_variables(df, c(scrnfl_var, scrnfailfl_var)) 61 | 62 | df <- df %>% 63 | mutate( 64 | SCRNFL = with_label(.data[[scrnfl_var]] == "Y", "Patients screened"), 65 | ENRLFL = with_label(!is.na(ENRLDT), "Patients enrolled"), 66 | RANDFL = with_label(!is.na(RANDDT), "Patients randomized") 67 | ) %>% 68 | df_explicit_na() 69 | 70 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var) 71 | 72 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 73 | split_cols_by_arm(arm_var, lbl_overall) %>% 74 | count_patients_with_flags( 75 | var = id_var, 76 | flag_variables = "SCRNFL", 77 | .stats = "count" 78 | ) %>% 79 | split_rows_by(scrnfailfl_var, split_fun = keep_split_levels("Y")) %>% 80 | summarize_num_patients( 81 | var = id_var, 82 | .stats = "unique", 83 | .labels = c(unique = "Screening failures") 84 | ) %>% 85 | count_occurrences(vars = scrnfail_var) %>% 86 | count_patients_with_flags( 87 | var = id_var, 88 | flag_variables = c("ENRLFL", "RANDFL"), 89 | nested = FALSE 90 | ) %>% 91 | append_topleft("Disposition") 92 | 93 | tbl <- build_table(lyt, df = df, alt_counts_df = alt_counts_df) 94 | if (prune_0) tbl <- prune_table(tbl) 95 | 96 | tbl 97 | } 98 | -------------------------------------------------------------------------------- /R/fda-table_07.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 7: Deaths, Safety Population, Pooled Analyses 2 | #' 3 | #' @details 4 | #' * `adae` must contain `TRTEMFL`, `DTHFL`, `DTHCAUS`, and the variables specified by `arm_var`, `id_var`, and 5 | #' `saffl_var`. 6 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. 7 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 8 | #' flag variables are treated as `"N"`. 9 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 10 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N` for category summary rows and 11 | #' fraction of `n` (number of patients in current category) for all other rows. 12 | #' * All-zero rows are removed by default (see `prune_0` argument). 13 | #' 14 | #' @inheritParams argument_convention 15 | #' 16 | #' @return An `rtable` object. 17 | #' 18 | #' @examples 19 | #' adsl <- random.cdisc.data::cadsl 20 | #' adae <- random.cdisc.data::cadae 21 | #' 22 | #' set.seed(1) 23 | #' adae$TRTEMFL <- ifelse( 24 | #' adae$USUBJID %in% sample(adsl$USUBJID, size = as.integer(nrow(adsl) / 3)), "N", "Y" 25 | #' ) 26 | #' 27 | #' tbl <- make_table_07(adae = adae, alt_counts_df = adsl) 28 | #' tbl 29 | #' 30 | #' @export 31 | make_table_07 <- function(adae, 32 | alt_counts_df = NULL, 33 | show_colcounts = TRUE, 34 | arm_var = "ARM", 35 | id_var = "USUBJID", 36 | saffl_var = "SAFFL", 37 | lbl_overall = NULL, 38 | risk_diff = NULL, 39 | prune_0 = TRUE, 40 | na_level = "MISSING", 41 | annotations = NULL) { 42 | assert_subset(c( 43 | "TRTEMFL", "DTHFL", "DTHCAUS", arm_var, id_var, saffl_var 44 | ), names(adae)) 45 | assert_flag_variables(adae, c(saffl_var, "TRTEMFL", "DTHFL"), na_level = na_level) 46 | 47 | adae <- adae %>% 48 | filter(.data[[saffl_var]] == "Y", DTHFL == "Y") %>% 49 | mutate( 50 | TRTEMFL = ifelse(TRTEMFL == "Y", "Y", "N") %>% factor(levels = c("Y", "N")), 51 | trtem_lab = ifelse(TRTEMFL == "Y", "Treatment-emergent deaths", "Nontreatment-emergent deaths") 52 | ) %>% 53 | df_explicit_na(na_level = na_level) 54 | 55 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) 56 | 57 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 58 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 59 | split_rows_by( 60 | "TRTEMFL", 61 | labels_var = "trtem_lab", 62 | split_fun = add_overall_level("Total deaths") 63 | ) %>% 64 | summarize_num_patients( 65 | var = id_var, 66 | riskdiff = !is.null(risk_diff), 67 | .stats = "unique", 68 | .labels = c(unique = NULL) 69 | ) %>% 70 | count_occurrences( 71 | vars = "DTHCAUS", 72 | denom = "n", 73 | drop = FALSE, 74 | riskdiff = !is.null(risk_diff) 75 | ) %>% 76 | rtables::append_topleft("Deaths") 77 | 78 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 79 | if (prune_0) tbl <- prune_table(tbl) 80 | 81 | tbl 82 | } 83 | -------------------------------------------------------------------------------- /R/fda-table_08.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 8: All Individual Patient Deaths, Safety Population, Pooled Analyses 2 | #' 3 | #' @details 4 | #' * `adae` must contain `AGE`, `SEX`, `AESDTH`, `DTHADY`, and the variables specified by 5 | #' `dth_vars`, `arm_var`, `id_var`, and `saffl_var`. 6 | #' * `adex` must contain `PARAMCD`, `TRTSDT`, `TRTEDT`, `AVAL`, `AVALU`, and the variables specified 7 | #' by `arm_var`, `id_var`, and `saffl_var`. 8 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 9 | #' flag variables are treated as `"N"`. 10 | #' 11 | #' @inheritParams argument_convention 12 | #' @param dth_vars (`vector` of `character`)\cr additional death variables from `adae` to include in the table. 13 | #' @param lbl_dth_vars (`vector` of `character`)\cr labels corresponding to variables in `dth_vars` to print 14 | #' in the table. Labels should be ordered according to the order of variables in `dth_vars`. 15 | #' 16 | #' @return A `listing_df` object. 17 | #' 18 | #' @examples 19 | #' adae <- random.cdisc.data::cadae 20 | #' adex <- random.cdisc.data::cadex 21 | #' 22 | #' tbl <- make_table_08(adae = adae, adex = adex) 23 | #' head(tbl, 20) 24 | #' 25 | #' @export 26 | make_table_08 <- function(adae, 27 | adex, 28 | arm_var = "ARM", 29 | id_var = "USUBJID", 30 | saffl_var = "SAFFL", 31 | dth_vars = c("DTHCAUS", "DTHCAT"), 32 | lbl_dth_vars = c("Cause of Death\nMedDRA\nPreferred Term", "Cause of Death\nVerbatim Term"), 33 | na_level = "NA", 34 | annotations = NULL) { 35 | assert_subset(c( 36 | "AGE", "SEX", "AESDTH", "DTHADY", dth_vars, arm_var, id_var, saffl_var 37 | ), names(adae)) 38 | assert_subset(c( 39 | saffl_var, id_var, "PARAMCD", "TRTSDT", "TRTEDT", "AVAL", "AVALU" 40 | ), names(adex)) 41 | assert_flag_variables(adae, saffl_var) 42 | assert_flag_variables(adex, saffl_var) 43 | 44 | # Deaths 45 | adae <- adae %>% 46 | filter(.data[[saffl_var]] == "Y" & AESDTH == "Y") %>% 47 | select(all_of(id_var), all_of(arm_var), AGE, SEX, DTHADY, all_of(dth_vars)) %>% 48 | mutate( 49 | AGESEX = paste0(AGE, "/", SEX), 50 | DTHADY = as.character(DTHADY) 51 | ) %>% 52 | distinct(.data[[id_var]], DTHCAT, DTHCAUS, DTHADY, .keep_all = TRUE) 53 | 54 | # Dosing 55 | adex <- adex %>% 56 | filter(.data[[saffl_var]] == "Y", PARAMCD == "TDOSE") %>% 57 | select(all_of(id_var), AVAL, AVALU, TRTSDT, TRTEDT) %>% 58 | mutate( 59 | DOSDUR = (TRTEDT - TRTSDT + 1) %>% as.character(), 60 | DOSAGE = paste0(AVAL, " ", AVALU) 61 | ) 62 | 63 | tbl_join <- left_join(adae, adex, by = id_var) %>% 64 | select(all_of(c(arm_var, id_var)), AGESEX, DOSAGE, DOSDUR, DTHADY, all_of(dth_vars)) %>% 65 | var_relabel( 66 | AGESEX = "Age/\nGender", 67 | DOSAGE = "Dosage", 68 | DTHADY = "Study\nDay of\nDeath", 69 | DOSDUR = "Dosing\nDuration\n(Days)" 70 | ) %>% 71 | df_explicit_na(na_level = na_level) %>% 72 | arrange(across(all_of(c(arm_var, id_var, "AGESEX", "DOSAGE", "DOSDUR", "DTHADY")))) 73 | 74 | tbl_join[[arm_var]] <- with_label(tbl_join[[arm_var]], "Study Arm") 75 | tbl_join[[id_var]] <- with_label(tbl_join[[id_var]], "Patient ID") 76 | for (i in seq_len(length(dth_vars))) { 77 | tbl_join[[dth_vars[i]]] <- with_label(tbl_join[[dth_vars[i]]], lbl_dth_vars[i]) 78 | } 79 | 80 | lsting <- as_listing( 81 | tbl_join, 82 | key_cols = c(arm_var, id_var, "AGESEX", "DOSAGE", "DOSDUR", "DTHADY"), 83 | main_title = if (!is.null(annotations$title)) annotations$title else "", 84 | subtitles = if (!is.null(annotations$subtitles)) annotations$subtitles else character(), 85 | main_footer = if (!is.null(annotations$main_footer)) annotations$main_footer else character(), 86 | prov_footer = if (!is.null(annotations$prov_footer)) annotations$prov_footer else character() 87 | ) 88 | 89 | lsting 90 | } 91 | -------------------------------------------------------------------------------- /R/fda-table_13.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 13: Patients With Common Adverse Events Occurring at >=XX% Frequency, Safety Population, Pooled Analyses 2 | #' 3 | #' @details 4 | #' * `adae` must contain the variables specified by `arm_var`, `id_var`, `saffl_var`, and `pref_var`. 5 | #' * If specified, `alt_counts_df` must contain `USUBJID` and the variables specified by `arm_var` and `saffl_var`. 6 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 7 | #' flag variables are treated as `"N"`. 8 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 9 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 10 | #' 11 | #' @inheritParams argument_convention 12 | #' @param min_freq (`proportion`)\cr minimum % frequency (fraction of `N`) required in any column to include each row. 13 | #' 14 | #' @return An `rtable` object. 15 | #' 16 | #' @examples 17 | #' adsl <- random.cdisc.data::cadsl 18 | #' adae <- random.cdisc.data::cadae 19 | #' 20 | #' tbl <- make_table_13(adae = adae, alt_counts_df = adsl) 21 | #' tbl 22 | #' 23 | #' @export 24 | make_table_13 <- function(adae, 25 | alt_counts_df = NULL, 26 | show_colcounts = TRUE, 27 | min_freq = 0.05, 28 | id_var = "USUBJID", 29 | arm_var = "ARM", 30 | saffl_var = "SAFFL", 31 | pref_var = "AEDECOD", 32 | lbl_pref_var = formatters::var_labels(adae, fill = TRUE)[pref_var], 33 | lbl_overall = NULL, 34 | risk_diff = NULL, 35 | annotations = NULL) { 36 | assert_subset(c(id_var, arm_var, saffl_var, pref_var), names(adae)) 37 | assert_flag_variables(adae, saffl_var) 38 | 39 | adae <- adae %>% 40 | filter(.data[[saffl_var]] == "Y") %>% 41 | df_explicit_na() 42 | 43 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) 44 | 45 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 46 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 47 | count_occurrences( 48 | vars = pref_var, 49 | riskdiff = !is.null(risk_diff) 50 | ) %>% 51 | append_topleft(lbl_pref_var) 52 | 53 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 54 | 55 | row_condition <- has_fraction_in_any_col( 56 | atleast = min_freq, 57 | col_names = names(table(adae[[arm_var]])) 58 | ) 59 | tbl <- prune_table(tbl, keep_rows(row_condition)) 60 | 61 | tbl 62 | } 63 | -------------------------------------------------------------------------------- /R/fda-table_14.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 14: Patients With Adverse Events by System Organ Class and FDA Medical Query, Safety Population, 2 | #' Pooled Analyses 3 | #' 4 | #' @details 5 | #' * `adae` must contain the variables specified by `arm_var`, `saffl_var`, `id_var`, `soc_var`, 6 | #' `fmqsc_var`, and `fmqnam_var`. 7 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. 8 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 9 | #' flag variables are treated as `"N"`. 10 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 11 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 12 | #' * All-zero rows are not removed by default (see `prune_0` argument). 13 | #' 14 | #' @inheritParams argument_convention 15 | #' 16 | #' @return An `rtable` object. 17 | #' 18 | #' @examples 19 | #' adae <- random.cdisc.data::cadae 20 | #' adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 21 | #' levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 22 | #' adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 23 | #' 24 | #' tbl <- make_table_14(adae = adae) 25 | #' tbl 26 | #' 27 | #' @export 28 | make_table_14 <- function(adae, 29 | alt_counts_df = NULL, 30 | show_colcounts = TRUE, 31 | id_var = "USUBJID", 32 | soc_var = "AEBODSYS", 33 | arm_var = "ARM", 34 | saffl_var = "SAFFL", 35 | fmqsc_var = "FMQ01SC", 36 | fmqnam_var = "FMQ01NAM", 37 | lbl_overall = NULL, 38 | risk_diff = NULL, 39 | prune_0 = FALSE, 40 | na_level = "<Missing>", 41 | annotations = NULL) { 42 | assert_subset(c( 43 | id_var, soc_var, arm_var, saffl_var, fmqsc_var, fmqnam_var 44 | ), names(adae)) 45 | assert_flag_variables(adae, saffl_var) 46 | 47 | adae <- adae %>% 48 | filter(.data[[saffl_var]] == "Y") %>% 49 | df_explicit_na(na_level = na_level) 50 | adae[[fmqnam_var]] <- with_label(adae[[fmqnam_var]], "FMQ") 51 | 52 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) 53 | 54 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 55 | split_cols_by(fmqsc_var) %>% 56 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 57 | split_rows_by( 58 | soc_var, 59 | child_labels = "visible", 60 | label_pos = "topleft", 61 | split_label = obj_label(adae[[soc_var]]) 62 | ) %>% 63 | count_occurrences( 64 | vars = fmqnam_var, 65 | drop = FALSE, 66 | riskdiff = !is.null(risk_diff) 67 | ) %>% 68 | append_varlabels(adae, fmqnam_var, indent = 1L) 69 | 70 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 71 | if (prune_0) tbl <- prune_table(tbl) 72 | 73 | tbl 74 | } 75 | -------------------------------------------------------------------------------- /R/fda-table_15.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 15: Patients With Adverse Events by Male-Specific FDA Medical Query (Narrow) and Preferred Term, 2 | #' Male Safety Population, Pooled Analyses 3 | #' 4 | #' @details 5 | #' * `adae` must contain `SEX`, and the variables specified by `arm_var`, `id_var`, `saffl_var`, `pref_var`, 6 | #' `fmqsc_var` and `fmqnam_var`. 7 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. 8 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 9 | #' flag variables are treated as `"N"`. 10 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 11 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 12 | #' * All-zero rows are removed by default (see `prune_0` argument). 13 | #' 14 | #' @inheritParams argument_convention 15 | #' 16 | #' @return An `rtable` object. 17 | #' 18 | #' @examples 19 | #' adsl <- random.cdisc.data::cadsl 20 | #' adae <- random.cdisc.data::cadae 21 | #' 22 | #' set.seed(1) 23 | #' adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 24 | #' levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 25 | #' adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 26 | #' adae$FMQ01NAM <- factor( 27 | #' adae$FMQ01NAM, 28 | #' levels = c(unique(adae$FMQ01NAM), "Erectile Dysfunction", "Gynecomastia") 29 | #' ) 30 | #' adae$FMQ01NAM[adae$SEX == "M"] <- as.factor( 31 | #' sample(c("Erectile Dysfunction", "Gynecomastia"), sum(adae$SEX == "M"), replace = TRUE) 32 | #' ) 33 | #' 34 | #' tbl <- make_table_15(adae = adae, alt_counts_df = adsl) 35 | #' tbl 36 | #' 37 | #' @export 38 | make_table_15 <- function(adae, 39 | alt_counts_df = NULL, 40 | show_colcounts = TRUE, 41 | id_var = "USUBJID", 42 | arm_var = "ARM", 43 | saffl_var = "SAFFL", 44 | pref_var = "AEDECOD", 45 | sex_scope = "M", 46 | fmq_scope = "NARROW", 47 | fmqsc_var = "FMQ01SC", 48 | fmqnam_var = "FMQ01NAM", 49 | lbl_overall = NULL, 50 | risk_diff = NULL, 51 | prune_0 = TRUE, 52 | na_level = "<Missing>", 53 | annotations = NULL) { 54 | assert_subset(c("SEX", arm_var, id_var, fmqsc_var, fmqnam_var, saffl_var, pref_var), names(adae)) 55 | assert_flag_variables(adae, saffl_var) 56 | assert_subset(toupper(fmq_scope), c("NARROW", "BROAD")) 57 | 58 | fmq_other_sexes <- unique(adae[adae[["SEX"]] != sex_scope, ][[fmqnam_var]]) 59 | adae <- adae %>% 60 | as_tibble() %>% 61 | filter( 62 | .data[[saffl_var]] == "Y", 63 | .data[[fmqsc_var]] == fmq_scope, 64 | .data[["SEX"]] == sex_scope, 65 | !.data[[fmqnam_var]] %in% fmq_other_sexes 66 | ) %>% 67 | df_explicit_na(na_level = na_level) 68 | 69 | adae[[fmqnam_var]] <- with_label(adae[[fmqnam_var]], paste0("FMQ (", tools::toTitleCase(tolower(fmq_scope)), ")")) 70 | adae[[pref_var]] <- with_label(adae[[pref_var]], "Preferred Term") 71 | 72 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) 73 | 74 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 75 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 76 | split_rows_by( 77 | fmqnam_var, 78 | label_pos = "topleft", 79 | split_label = obj_label(adae[[fmqnam_var]]) 80 | ) %>% 81 | count_occurrences( 82 | vars = pref_var, 83 | drop = FALSE, 84 | riskdiff = !is.null(risk_diff) 85 | ) %>% 86 | append_varlabels(adae, pref_var, indent = 1L) 87 | 88 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 89 | if (prune_0) tbl <- prune_table(tbl) 90 | 91 | tbl 92 | } 93 | -------------------------------------------------------------------------------- /R/fda-table_16.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 16: Patients With Adverse Events by Male-Specific FDA Medical Query (Broad) and Preferred Term, 2 | #' Male Safety Population, Pooled Analyses 3 | #' 4 | #' @details 5 | #' * `adae` must contain `SEX`, and the variables specified by `arm_var`, `id_var`, `saffl_var`, `pref_var`, 6 | #' `fmqsc_var` and `fmqnam_var`. 7 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. 8 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 9 | #' flag variables are treated as `"N"`. 10 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 11 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 12 | #' * All-zero rows are removed by default (see `prune_0` argument). 13 | #' 14 | #' @inheritParams argument_convention 15 | #' 16 | #' @return An `rtable` object. 17 | #' 18 | #' @examples 19 | #' adsl <- random.cdisc.data::cadsl 20 | #' adae <- random.cdisc.data::cadae 21 | #' 22 | #' set.seed(1) 23 | #' adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 24 | #' levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 25 | #' adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 26 | #' adae$FMQ01NAM <- factor( 27 | #' adae$FMQ01NAM, 28 | #' levels = c(unique(adae$FMQ01NAM), "Erectile Dysfunction", "Gynecomastia") 29 | #' ) 30 | #' adae$FMQ01NAM[adae$SEX == "M"] <- as.factor( 31 | #' sample(c("Erectile Dysfunction", "Gynecomastia"), sum(adae$SEX == "M"), replace = TRUE) 32 | #' ) 33 | #' 34 | #' tbl <- make_table_16(adae = adae, alt_counts_df = adsl) 35 | #' tbl 36 | #' 37 | #' @export 38 | make_table_16 <- function(adae, 39 | alt_counts_df = NULL, 40 | show_colcounts = TRUE, 41 | id_var = "USUBJID", 42 | arm_var = "ARM", 43 | saffl_var = "SAFFL", 44 | pref_var = "AEDECOD", 45 | sex_scope = "M", 46 | fmq_scope = "BROAD", 47 | fmqsc_var = "FMQ01SC", 48 | fmqnam_var = "FMQ01NAM", 49 | lbl_overall = NULL, 50 | risk_diff = NULL, 51 | prune_0 = TRUE, 52 | na_level = "<Missing>", 53 | annotations = NULL) { 54 | assert_subset(c("SEX", arm_var, id_var, fmqsc_var, fmqnam_var, saffl_var, pref_var), names(adae)) 55 | assert_flag_variables(adae, saffl_var) 56 | assert_subset(toupper(fmq_scope), c("NARROW", "BROAD")) 57 | 58 | fmq_other_sexes <- unique(adae[adae[["SEX"]] != sex_scope, ][[fmqnam_var]]) 59 | adae <- adae %>% 60 | as_tibble() %>% 61 | filter( 62 | .data[[saffl_var]] == "Y", 63 | .data[[fmqsc_var]] == fmq_scope, 64 | .data[["SEX"]] == sex_scope, 65 | !.data[[fmqnam_var]] %in% fmq_other_sexes 66 | ) %>% 67 | df_explicit_na(na_level = na_level) 68 | 69 | adae[[fmqnam_var]] <- with_label(adae[[fmqnam_var]], paste0("FMQ (", tools::toTitleCase(tolower(fmq_scope)), ")")) 70 | adae[[pref_var]] <- with_label(adae[[pref_var]], "Preferred Term") 71 | 72 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) 73 | 74 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 75 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 76 | split_rows_by( 77 | fmqnam_var, 78 | label_pos = "topleft", 79 | split_label = obj_label(adae[[fmqnam_var]]) 80 | ) %>% 81 | count_occurrences( 82 | vars = pref_var, 83 | drop = FALSE, 84 | riskdiff = !is.null(risk_diff) 85 | ) %>% 86 | append_varlabels(adae, pref_var, indent = 1L) 87 | 88 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 89 | if (prune_0) tbl <- prune_table(tbl) 90 | 91 | tbl 92 | } 93 | -------------------------------------------------------------------------------- /R/fda-table_17.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 17: Patients With Adverse Events by Female-Specific FDA Medical Query (Narrow) and Preferred Term, 2 | #' Female Safety Population, Pooled Analyses 3 | #' 4 | #' @details 5 | #' * `adae` must contain `SEX`, and the variables specified by `arm_var`, `id_var`, `saffl_var`, `pref_var`, 6 | #' `fmqsc_var` and `fmqnam_var`. 7 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. 8 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 9 | #' flag variables are treated as `"N"`. 10 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 11 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 12 | #' * All-zero rows are removed by default (see `prune_0` argument). 13 | #' 14 | #' @inheritParams argument_convention 15 | #' 16 | #' @return An `rtable` object. 17 | #' 18 | #' @examples 19 | #' adsl <- random.cdisc.data::cadsl 20 | #' adae <- random.cdisc.data::cadae 21 | #' 22 | #' set.seed(1) 23 | #' adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 24 | #' levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 25 | #' adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 26 | #' adae$FMQ01NAM <- factor(adae$FMQ01NAM, levels = c( 27 | #' unique(adae$FMQ01NAM), "Abnormal Uterine Bleeding", "Amenorrhea", 28 | #' "Bacterial Vaginosis", "Decreased Menstrual Bleeding" 29 | #' )) 30 | #' adae$FMQ01NAM[adae$SEX == "F"] <- as.factor( 31 | #' sample(c( 32 | #' "Abnormal Uterine Bleeding", "Amenorrhea", 33 | #' "Bacterial Vaginosis", "Decreased Menstrual Bleeding" 34 | #' ), sum(adae$SEX == "F"), replace = TRUE) 35 | #' ) 36 | #' 37 | #' tbl <- make_table_17(adae = adae, alt_counts_df = adsl) 38 | #' tbl 39 | #' 40 | #' @export 41 | make_table_17 <- function(adae, 42 | alt_counts_df = NULL, 43 | show_colcounts = TRUE, 44 | id_var = "USUBJID", 45 | arm_var = "ARM", 46 | saffl_var = "SAFFL", 47 | pref_var = "AEDECOD", 48 | sex_scope = "F", 49 | fmq_scope = "NARROW", 50 | fmqsc_var = "FMQ01SC", 51 | fmqnam_var = "FMQ01NAM", 52 | lbl_overall = NULL, 53 | risk_diff = NULL, 54 | prune_0 = TRUE, 55 | na_level = "<Missing>", 56 | annotations = NULL) { 57 | assert_subset(c("SEX", arm_var, id_var, fmqsc_var, fmqnam_var, saffl_var, pref_var), names(adae)) 58 | assert_flag_variables(adae, saffl_var) 59 | assert_subset(toupper(fmq_scope), c("NARROW", "BROAD")) 60 | 61 | fmq_other_sexes <- unique(adae[adae[["SEX"]] != sex_scope, ][[fmqnam_var]]) 62 | adae <- adae %>% 63 | as_tibble() %>% 64 | filter( 65 | .data[[saffl_var]] == "Y", 66 | .data[[fmqsc_var]] == fmq_scope, 67 | .data[["SEX"]] == sex_scope, 68 | !.data[[fmqnam_var]] %in% fmq_other_sexes 69 | ) %>% 70 | df_explicit_na(na_level = na_level) 71 | 72 | adae[[fmqnam_var]] <- with_label(adae[[fmqnam_var]], paste0("FMQ (", tools::toTitleCase(tolower(fmq_scope)), ")")) 73 | adae[[pref_var]] <- with_label(adae[[pref_var]], "Preferred Term") 74 | 75 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) 76 | 77 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 78 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 79 | split_rows_by( 80 | fmqnam_var, 81 | label_pos = "topleft", 82 | split_label = obj_label(adae[[fmqnam_var]]) 83 | ) %>% 84 | count_occurrences( 85 | vars = pref_var, 86 | drop = FALSE, 87 | riskdiff = !is.null(risk_diff) 88 | ) %>% 89 | append_varlabels(adae, pref_var, indent = 1L) 90 | 91 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 92 | if (prune_0) tbl <- prune_table(tbl) 93 | 94 | tbl 95 | } 96 | -------------------------------------------------------------------------------- /R/fda-table_18.R: -------------------------------------------------------------------------------- 1 | #' FDA Table 18: Patients With Adverse Events by Female-Specific FDA Medical Query (Broad) and Preferred Term, 2 | #' Female Safety Population, Pooled Analyses 3 | #' 4 | #' @details 5 | #' * `adae` must contain `SEX`, and the variables specified by `arm_var`, `id_var`, `saffl_var`, `pref_var`, 6 | #' `fmqsc_var` and `fmqnam_var`. 7 | #' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. 8 | #' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in 9 | #' flag variables are treated as `"N"`. 10 | #' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). 11 | #' * Numbers in table represent the absolute numbers of patients and fraction of `N`. 12 | #' * All-zero rows are removed by default (see `prune_0` argument). 13 | #' 14 | #' @inheritParams argument_convention 15 | #' 16 | #' @return An `rtable` object. 17 | #' 18 | #' @examples 19 | #' adsl <- random.cdisc.data::cadsl 20 | #' adae <- random.cdisc.data::cadae 21 | #' 22 | #' set.seed(1) 23 | #' adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 24 | #' levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 25 | #' adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 26 | #' adae$FMQ01NAM <- factor(adae$FMQ01NAM, levels = c( 27 | #' unique(adae$FMQ01NAM), "Abnormal Uterine Bleeding", "Amenorrhea", 28 | #' "Bacterial Vaginosis", "Decreased Menstrual Bleeding" 29 | #' )) 30 | #' adae$FMQ01NAM[adae$SEX == "F"] <- as.factor( 31 | #' sample(c( 32 | #' "Abnormal Uterine Bleeding", "Amenorrhea", 33 | #' "Bacterial Vaginosis", "Decreased Menstrual Bleeding" 34 | #' ), sum(adae$SEX == "F"), replace = TRUE) 35 | #' ) 36 | #' 37 | #' tbl <- make_table_18(adae = adae, alt_counts_df = adsl) 38 | #' tbl 39 | #' 40 | #' @export 41 | make_table_18 <- function(adae, 42 | alt_counts_df = NULL, 43 | show_colcounts = TRUE, 44 | id_var = "USUBJID", 45 | arm_var = "ARM", 46 | saffl_var = "SAFFL", 47 | pref_var = "AEDECOD", 48 | sex_scope = "F", 49 | fmq_scope = "BROAD", 50 | fmqsc_var = "FMQ01SC", 51 | fmqnam_var = "FMQ01NAM", 52 | lbl_overall = NULL, 53 | risk_diff = NULL, 54 | prune_0 = TRUE, 55 | na_level = "<Missing>", 56 | annotations = NULL) { 57 | assert_subset(c("SEX", arm_var, id_var, fmqsc_var, fmqnam_var, saffl_var, pref_var), names(adae)) 58 | assert_flag_variables(adae, saffl_var) 59 | assert_subset(toupper(fmq_scope), c("NARROW", "BROAD")) 60 | 61 | fmq_other_sexes <- unique(adae[adae[["SEX"]] != sex_scope, ][[fmqnam_var]]) 62 | adae <- adae %>% 63 | as_tibble() %>% 64 | filter( 65 | .data[[saffl_var]] == "Y", 66 | .data[[fmqsc_var]] == fmq_scope, 67 | .data[["SEX"]] == sex_scope, 68 | !.data[[fmqnam_var]] %in% fmq_other_sexes 69 | ) %>% 70 | df_explicit_na(na_level = na_level) 71 | 72 | adae[[fmqnam_var]] <- with_label(adae[[fmqnam_var]], paste0("FMQ (", tools::toTitleCase(tolower(fmq_scope)), ")")) 73 | adae[[pref_var]] <- with_label(adae[[pref_var]], "Preferred Term") 74 | 75 | alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) 76 | 77 | lyt <- basic_table_annot(show_colcounts, annotations) %>% 78 | split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% 79 | split_rows_by( 80 | fmqnam_var, 81 | label_pos = "topleft", 82 | split_label = obj_label(adae[[fmqnam_var]]) 83 | ) %>% 84 | count_occurrences( 85 | vars = pref_var, 86 | drop = FALSE, 87 | riskdiff = !is.null(risk_diff) 88 | ) %>% 89 | append_varlabels(adae, pref_var, indent = 1L) 90 | 91 | tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) 92 | if (prune_0) tbl <- prune_table(tbl) 93 | 94 | tbl 95 | } 96 | -------------------------------------------------------------------------------- /_quarto.yml: -------------------------------------------------------------------------------- 1 | --- 2 | project: 3 | type: website 4 | preview: 5 | port: 4200 6 | browser: true 7 | watch-inputs: true 8 | navigate: true 9 | timeout: 300 10 | render: 11 | - "*.qmd" 12 | - "!inst/" 13 | - "!quarto/figure-templates/" 14 | - "!quarto/table-templates/" 15 | 16 | format: 17 | html: 18 | search: true 19 | theme: 20 | light: [flatly, quarto/assets/style.scss, quarto/assets/style-light.scss] 21 | dark: [darkly, quarto/assets/style.scss, quarto/assets/style-dark.scss] 22 | anchor-sections: true 23 | smooth-scroll: true 24 | code-link: true 25 | code-fold: false 26 | code-overflow: scroll 27 | code-line-numbers: true 28 | code-copy: true 29 | code-tools: 30 | source: true 31 | toggle: false 32 | caption: none 33 | code-block-bg: true 34 | css: quarto/assets/style.scss 35 | toc: false 36 | number-sections: false 37 | lang: en-US 38 | page-layout: full 39 | df-print: kable 40 | 41 | execute: 42 | freeze: auto 43 | cache: true 44 | code-line-numbers: true 45 | 46 | knitr: 47 | opts_chunk: 48 | echo: true 49 | code-fold: show 50 | fig.width: 15 51 | 52 | editor: source 53 | highlight-style: github 54 | 55 | website: 56 | title: cardinal 57 | open-graph: true 58 | favicon: quarto/assets/images/logo/cardinal.png 59 | search: 60 | location: navbar 61 | type: overlay 62 | copy-button: true 63 | page-navigation: true 64 | site-url: https://pharmaverse.github.io/cardinal 65 | repo-url: https://github.com/pharmaverse/cardinal 66 | repo-branch: main 67 | google-analytics: UA-125641273-1 68 | cookie-consent: true 69 | page-footer: 70 | center: 71 | - text: "This website as well as code examples are licensed under the Apache License, Version 2.0." # nolint 72 | navbar: 73 | pinned: true 74 | collapse: true 75 | logo: quarto/assets/images/logo/cardinal.png 76 | search: true 77 | left: 78 | - text: Home 79 | file: index.qmd 80 | - text: Template Catalog 81 | file: quarto/index-catalog.qmd 82 | right: 83 | - text: About 84 | file: quarto/about.qmd 85 | - text: Resources 86 | file: quarto/resources.qmd 87 | - text: Help 88 | menu: 89 | - quarto/getting_started.qmd 90 | - text: Report a Bug 91 | url: https://github.com/pharmaverse/cardinal/issues/new/choose 92 | - text: FAQ 93 | file: quarto/faq.qmd 94 | - aria-label: GitHub 95 | href: https://github.com/pharmaverse/cardinal 96 | icon: github 97 | - aria-label: Slack 98 | href: https://app.slack.com/client/T028PB489D3/C04MQS12MND 99 | icon: slack 100 | -------------------------------------------------------------------------------- /cardinal.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | ProjectId: e2dab20b-0a4a-49ed-b52f-a43d9f5ab1b6 3 | 4 | RestoreWorkspace: No 5 | SaveWorkspace: No 6 | AlwaysSaveHistory: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 2 11 | Encoding: UTF-8 12 | 13 | RnwWeave: Sweave 14 | LaTeX: pdfLaTeX 15 | 16 | AutoAppendNewline: Yes 17 | StripTrailingWhitespace: Yes 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: cardinal 3 | --- 4 | 5 | ::: {.callout-warning} 6 | Please note that the cardinal project is currently undergoing major structural changes and is subject to change without notice. 7 | 8 | Some informational pages may show outdated information while the restructuring is in progress. 9 | ::: 10 | 11 | ```{css, echo=FALSE} 12 | h3 { 13 | text-align: center; 14 | } 15 | ``` 16 | 17 | ### Implementation of FDA Safety Tables and Figures 18 | 19 | #### 20 | 21 | ```{r, echo=FALSE} 22 | #| fig-align: "center" 23 | #| out-width: "2.0in" 24 | knitr::include_graphics("quarto/assets/images/logo/cardinal.png") 25 | ``` 26 | 27 | 28 | #### What is cardinal? 29 | 30 | The cardinal initiative (formerly "falcon") is an industry collaborative effort under pharmaverse that brings together pharmaceutical companies with the aspiration of building and open-sourcing a catalog of harmonized tables, listings, and graphs (TLGs) in clinical study reporting. Leveraging existing open-source R packages, cardinal aims to simplify the process of output review, comparison, and meta-analyses, fostering efficient communication among stakeholders in the pharmaceutical sector while aligning with CDISC's ARD/ARM effort at the same time. Drawing inspiration from the FDA Standard Safety Tables and Figures Integrated Guide, we develop open-source templates. Future plans entail expanding the catalog of templates through continuous collaboration from participating companies and inviting wider industry to promote harmonization of TLGs for clinical reporting. 31 | 32 | ```{=html} 33 | <div class="divButton"> 34 | <button onclick="window.location.href = 'quarto/getting_started.html';" class="button">Getting Started</button> 35 | <button onclick="window.location.href = 'quarto/index-catalog.html';" class="button">Template Catalog</button> 36 | </div> 37 | 38 | <div class="divButton"> 39 | <button onclick="window.location.href = 'quarto/about.html#our-collaboration-journey';" class="button">Our Collaboration Journey</button> 40 | <button onclick="window.location.href = 'quarto/faq.html';" class="button">FAQ</button> 41 | </div> 42 | ``` 43 | 44 | #### Upcoming Talks & Presentations 45 | 46 | No upcoming talks or presentations currently scheduled. Stay tuned! 47 | 48 | See resources from past talks & presentations [here](quarto/resources.html#past-talks-presentations). 49 | 50 | #### Contributors 51 | 52 | ::: {layout-ncol="4"} 53 | ::: flip-card 54 | ::: flip-card-inner 55 | ::: flip-card-front 56 | ![](quarto/assets/images/logo-roche.png){width="150"} 57 | ::: 58 | 59 | ::: flip-card-back 60 | Emily de la Rua\ 61 | Abinaya Yogasekaram 62 | ::: 63 | ::: 64 | ::: 65 | 66 | ::: flip-card 67 | ::: flip-card-inner 68 | ::: flip-card-front 69 | ![](quarto/assets/images/logo-bi.png){width="150"} 70 | ::: 71 | 72 | ::: flip-card-back 73 | Jessica Knizia\ 74 | Yoshito Koujin\ 75 | Korbinian Matthias 76 | ::: 77 | ::: 78 | ::: 79 | 80 | ::: flip-card 81 | ::: flip-card-inner 82 | ::: flip-card-front 83 | ![](quarto/assets/images/logo-sanofi.png){width="150"} 84 | ::: 85 | 86 | ::: flip-card-back 87 | Huan Lu\ 88 | Harsha Kalikivayi\ 89 | Alex Assuied 90 | ::: 91 | ::: 92 | ::: 93 | 94 | ::: flip-card 95 | ::: flip-card-inner 96 | ::: flip-card-front 97 | ![](quarto/assets/images/logo-moderna.jpg){width="150"} 98 | ::: 99 | 100 | ::: flip-card-back 101 | Yichen Wang\ 102 | Yuye Wang 103 | ::: 104 | ::: 105 | ::: 106 | ::: 107 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | ADAE 2 | ADEX 3 | ADSL 4 | ADSUB 5 | ADVS 6 | ADaM 7 | AE 8 | AEACN 9 | AEACNOTH 10 | AESCONG 11 | AESDISAB 12 | AESDTH 13 | AESER 14 | AESEV 15 | AESHOSP 16 | AESLIFE 17 | AESMIE 18 | AEs 19 | ARD 20 | Abinaya 21 | Assuied 22 | CDISC 23 | CDISC's 24 | FMQ 25 | Harsha 26 | Huan 27 | Hypotension 28 | Kalikivayi 29 | Knizia 30 | Korbinian 31 | Koujin 32 | PARAMCD 33 | Pharmaverse 34 | Postbaseline 35 | Pre 36 | Rua 37 | TLGs 38 | Yichen 39 | Yogasekaram 40 | Yoshito 41 | Yuye 42 | callout 43 | datetime 44 | de 45 | ncol 46 | pharmaverse 47 | pre 48 | -------------------------------------------------------------------------------- /inst/empty-template.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: Your TLG Title 3 | subtitle: (Optional Field) Short Description of TLG 4 | categories: [table, FDA, safety] ## ** REPLACE WITH RELEVANT TAGS ** 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='60%'} 11 | ## ** (OPTIONAL) INCLUDE AN IMAGE OF YOUR TLG HERE ** 12 | ## If no image to show, the `Table Preview` section can be removed 13 | knitr::include_graphics("result.png") 14 | ``` 15 | 16 | ## Setup 17 | 18 | ```{r setup, message=FALSE} 19 | # Load libraries & data ------------------------------------- 20 | library(dplyr) 21 | library(cards) 22 | library(gtsummary) 23 | 24 | ## ** LOAD ADDITIONAL PACKAGES USED HERE ** 25 | 26 | ## ** LOAD ALL DATASETS USED IN EXAMPLES HERE ** 27 | 28 | # Pre-processing -------------------------------------------- 29 | 30 | ## ** ADD CODE FOR ANY NECESSARY DATA PRE-PROCESSING HERE ** 31 | ``` 32 | 33 | ## Build ARD 34 | 35 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 36 | ## ** INSERT YOUR ARD CODE HERE ** 37 | ## `ard` should return an ARD of class `card` 38 | ard <- NULL 39 | 40 | ard 41 | ``` 42 | 43 | ```{r, echo=FALSE} 44 | # Print ARD 45 | withr::local_options(width = 9999) 46 | print(ard, columns = "all", n = 40) 47 | ``` 48 | 49 | ## Build Table 50 | 51 | ```{r tbl, results = 'hide'} 52 | ## ** INSERT YOUR TABLE CODE HERE ** 53 | ## `tbl` should return a `gtsummary` table 54 | tbl <- NULL 55 | 56 | tbl 57 | ``` 58 | 59 | ```{r eval=FALSE, include=FALSE} 60 | ## ** (OPTIONAL) RUN THIS CHUNK LOCALLY TO GENERATE AN IMAGE FILE ** 61 | gt::gtsave(as_gt(tbl), filename = "result.png") 62 | ``` 63 | 64 | ```{r img, echo=FALSE, fig.align='center', out.width='60%'} 65 | ``` 66 | ::: 67 | -------------------------------------------------------------------------------- /man/a_count_occurrences_ser_ae.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-table_21.R 3 | \name{a_count_occurrences_ser_ae} 4 | \alias{a_count_occurrences_ser_ae} 5 | \title{Analysis Function to Calculate Count/Fraction of Serious Adverse Event Occurrences} 6 | \usage{ 7 | a_count_occurrences_ser_ae( 8 | df, 9 | .var, 10 | .N_col, 11 | df_denom = NULL, 12 | denom = c("N_s", "N_col", "n"), 13 | id_var = "USUBJID", 14 | arm_var = "ARM" 15 | ) 16 | } 17 | \arguments{ 18 | \item{df}{(\code{data.frame})\cr data set containing all analysis variables.} 19 | 20 | \item{.var}{(\code{string})\cr single variable name that is passed by \code{rtables} when requested 21 | by a statistics function.} 22 | 23 | \item{.N_col}{(\code{integer(1)})\cr column-wise N (column count) for the full column being analyzed that is typically 24 | passed by \code{rtables}.} 25 | 26 | \item{df_denom}{(\code{data.frame})\cr Full data frame used to calculate denominator subgroup counts 27 | when \code{denom = "N_s"}.} 28 | 29 | \item{denom}{(\code{character})\cr Denominator to use to calculate fractions. Can be \code{"N_s"} (total \code{df_denom} 30 | subgroup/row counts), \code{"N_col"} (total \code{df} column counts), or \code{"n"} (total \code{df} overall patient count). 31 | Note that \code{df} is filtered to only include serious adverse events (\code{ASER == "Y"}).} 32 | 33 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 34 | 35 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 36 | } 37 | \description{ 38 | Analysis Function to Calculate Count/Fraction of Serious Adverse Event Occurrences 39 | } 40 | \keyword{internal} 41 | -------------------------------------------------------------------------------- /man/a_count_occurrences_trtem_ae.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-table_22.R 3 | \name{a_count_occurrences_trtem_ae} 4 | \alias{a_count_occurrences_trtem_ae} 5 | \title{Analysis Function to Calculate Count/Fraction of Any Adverse Event Occurrences} 6 | \usage{ 7 | a_count_occurrences_trtem_ae( 8 | df, 9 | .var, 10 | .N_col, 11 | df_denom = NULL, 12 | denom = c("N_s", "N_col", "n"), 13 | id_var = "USUBJID", 14 | arm_var = "ARM" 15 | ) 16 | } 17 | \arguments{ 18 | \item{df}{(\code{data.frame})\cr data set containing all analysis variables.} 19 | 20 | \item{.var}{(\code{string})\cr single variable name that is passed by \code{rtables} when requested 21 | by a statistics function.} 22 | 23 | \item{.N_col}{(\code{integer(1)})\cr column-wise N (column count) for the full column being analyzed that is typically 24 | passed by \code{rtables}.} 25 | 26 | \item{df_denom}{(\code{data.frame})\cr Full data frame used to calculate denominator subgroup counts 27 | when \code{denom = "N_s"}.} 28 | 29 | \item{denom}{(\code{character})\cr Denominator to use to calculate fractions. Can be \code{"N_s"} (total \code{df_denom} 30 | subgroup/row counts), \code{"N_col"} (total \code{df} column counts), or \code{"n"} (total \code{df} overall patient count). 31 | Note that \code{df} is filtered to only include treatment-emergent adverse events (\code{TRTEMFL == "Y"}).} 32 | 33 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 34 | 35 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 36 | } 37 | \description{ 38 | Analysis Function to Calculate Count/Fraction of Any Adverse Event Occurrences 39 | } 40 | \keyword{internal} 41 | -------------------------------------------------------------------------------- /man/alt_counts_df_preproc.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{alt_counts_df_preproc} 4 | \alias{alt_counts_df_preproc} 5 | \title{Pre-Process \code{alt_counts_df} for Safety Population} 6 | \usage{ 7 | alt_counts_df_preproc( 8 | alt_counts_df, 9 | id_var = "USUBJID", 10 | arm_var = "ARM", 11 | saffl_var = NULL 12 | ) 13 | } 14 | \arguments{ 15 | \item{alt_counts_df}{(\code{character})\cr alternative dataset (typically ADSL) used only to calculate column counts.} 16 | 17 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 18 | 19 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 20 | 21 | \item{saffl_var}{(\code{character})\cr Name of the safety flag variable which must contain at least "Y" for "Yes".} 22 | } 23 | \value{ 24 | A \code{data.frame} (modified \code{alt_counts_df}) or \code{NULL}. 25 | } 26 | \description{ 27 | If \code{alt_counts_df} is not \code{NULL}, will check for required variables (\code{arm_var}) and filter 28 | to include only safety population (\code{saffl_var}, if specified), then apply \code{\link[tern:df_explicit_na]{tern::df_explicit_na()}}. 29 | } 30 | \examples{ 31 | adsl <- random.cdisc.data::cadsl 32 | alt_counts_df_preproc(adsl) 33 | 34 | } 35 | -------------------------------------------------------------------------------- /man/ard_make_table_10.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-table_10.R 3 | \name{ard_make_table_10} 4 | \alias{ard_make_table_10} 5 | \alias{ard_table_10} 6 | \title{Make ARD: Table 10} 7 | \usage{ 8 | ard_table_10( 9 | df, 10 | denominator = NULL, 11 | id_var = "USUBJID", 12 | arm_var = "ARM", 13 | saffl_var = "SAFFL", 14 | fmqsc_var = "FMQ01SC", 15 | fmqnam_var = "FMQ01NAM", 16 | fmq_scope = "NARROW", 17 | na_level = "<Missing>" 18 | ) 19 | } 20 | \description{ 21 | Make ARD: Table 10 22 | } 23 | \examples{ 24 | library(dplyr) 25 | 26 | adsl <- random.cdisc.data::cadsl 27 | adae <- random.cdisc.data::cadae 28 | 29 | set.seed(1) 30 | adae <- adae \%>\% 31 | rename(FMQ01SC = SMQ01SC) \%>\% 32 | mutate( 33 | AESER = sample(c("Y", "N"), size = nrow(adae), replace = TRUE), 34 | FMQ01NAM = sample(c("FMQ1", "FMQ2", "FMQ3"), size = nrow(adae), replace = TRUE) 35 | ) 36 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 37 | 38 | ard <- cardinal:::ard_table_10(adae, adsl) 39 | ard 40 | 41 | } 42 | \keyword{internal} 43 | -------------------------------------------------------------------------------- /man/assert_flag_variables.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{assert_flag_variables} 4 | \alias{assert_flag_variables} 5 | \title{Check Values of Flag Variables} 6 | \usage{ 7 | assert_flag_variables(df, flag_vars, na_level = "<Missing>") 8 | } 9 | \arguments{ 10 | \item{df}{(\code{data.frame})\cr dataset required to build table.} 11 | 12 | \item{flag_vars}{(\code{vector} of \code{character})\cr names of flag variables within \code{df} to check.} 13 | 14 | \item{na_level}{(\code{character})\cr String to represent missing values.} 15 | } 16 | \value{ 17 | A \code{logical} indicating whether the given flag variables (\code{flag_vars}) in \code{df} are formatted correctly. 18 | } 19 | \description{ 20 | Flag variables are expected to take one of two values: \code{"Y"} (yes/true) or 21 | \code{"N"} (no/false). Missing values are also accepted and treated as \code{"N"}. 22 | } 23 | \examples{ 24 | adsl <- random.cdisc.data::cadsl 25 | cardinal:::assert_flag_variables(adsl, c("SAFFL", "ITTFL")) 26 | 27 | } 28 | \keyword{internal} 29 | -------------------------------------------------------------------------------- /man/basic_table_annot.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{basic_table_annot} 4 | \alias{basic_table_annot} 5 | \title{Initialize Table Layout with Annotations} 6 | \usage{ 7 | basic_table_annot(show_colcounts = TRUE, annotations = NULL) 8 | } 9 | \arguments{ 10 | \item{show_colcounts}{(\code{flag})\cr Whether column counts should be printed. Boolean.} 11 | 12 | \item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the table. Valid 13 | annotation types are \code{title}, \code{subtitles}, \code{main_footer}, and \code{prov_footer}. Each name-value pair should 14 | use the annotation type as name and the desired string as value.} 15 | } 16 | \value{ 17 | An \code{rtables} \code{PreDataTableLayouts} object suitable for passing to further layout functions, and 18 | to \code{build_table}. 19 | } 20 | \description{ 21 | Initializes a table layout via \code{\link[rtables:basic_table]{rtables::basic_table()}} and applies \code{show_colcounts} 22 | argument. Adds any annotations supplied via the \code{annotations} argument. 23 | } 24 | \examples{ 25 | lyt <- basic_table_annot(annotations = list(title = "Title", main_footer = "Main Footer")) 26 | rtables::build_table(lyt, df = data.frame()) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /man/cardinal-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cardinal.R 3 | \docType{package} 4 | \name{cardinal-package} 5 | \alias{cardinal} 6 | \alias{cardinal-package} 7 | \title{cardinal Package} 8 | \description{ 9 | Implementation of FDA Safety Tables and Figures 10 | } 11 | \seealso{ 12 | Useful links: 13 | \itemize{ 14 | \item \url{https://github.com/pharmaverse/cardinal/} 15 | \item Report bugs at \url{https://github.com/pharmaverse/cardinal/issues} 16 | } 17 | 18 | } 19 | \author{ 20 | \strong{Maintainer}: Pawel Rucki \email{pawel.rucki@roche.com} 21 | 22 | } 23 | \keyword{internal} 24 | -------------------------------------------------------------------------------- /man/make_fig_01.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-fig_01.R 3 | \name{make_fig_01} 4 | \alias{make_fig_01} 5 | \title{FDA Figure 1: Time to Permanent Discontinuation of Study Drug, Safety Population, Pooled Analyses} 6 | \usage{ 7 | make_fig_01( 8 | df, 9 | arm_var = "ARM", 10 | id_var = "USUBJID", 11 | saffl_var = "SAFFL", 12 | trtsdtm_var = "TRTSDTM", 13 | trtedtm_var = "TRTEDTM", 14 | u_trtdur = "days", 15 | x_lab = paste0("Time from first dose (", u_trtdur, ")"), 16 | y_lab = "Percent of Patients (\%)", 17 | xticks = NA, 18 | ggtheme = NULL, 19 | add_table = TRUE, 20 | annotations = NULL 21 | ) 22 | } 23 | \arguments{ 24 | \item{df}{(\code{data.frame})\cr dataset required to build table.} 25 | 26 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 27 | 28 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 29 | 30 | \item{saffl_var}{(\code{character})\cr Name of the safety flag variable which must contain at least "Y" for "Yes".} 31 | 32 | \item{trtsdtm_var}{(\code{character})\cr treatment start datetime variable.} 33 | 34 | \item{trtedtm_var}{(\code{character})\cr treatment end datetime variable.} 35 | 36 | \item{u_trtdur}{(\code{character})\cr unit for duration of treatment. Options are \code{"days"}, \code{"weeks"}, \code{"months"}, 37 | and \code{"years"}.} 38 | 39 | \item{x_lab}{(\code{character})\cr x-axis label.} 40 | 41 | \item{y_lab}{(\code{character})\cr y-axis label.} 42 | 43 | \item{xticks}{(\code{vector} of \code{numeric})\cr x-axis tick positions. If \code{NA} (default), tick mark positions are 44 | automatically calculated.} 45 | 46 | \item{ggtheme}{(\code{theme})\cr a graphical theme as provided by \code{ggplot2} to control styling of the \code{ggplot} object.} 47 | 48 | \item{add_table}{(\code{flag})\cr whether "Number of Patients" table should be printed under the plot.} 49 | 50 | \item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the figure. Valid annotation types 51 | are \code{title}, \code{subtitles}, and \code{caption}. Each name-value pair should use the annotation type as name and the 52 | desired string as value.} 53 | } 54 | \value{ 55 | A \code{ggplot2} object. 56 | } 57 | \description{ 58 | FDA Figure 1: Time to Permanent Discontinuation of Study Drug, Safety Population, Pooled Analyses 59 | } 60 | \details{ 61 | \itemize{ 62 | \item \code{df} must contain the variables specified by \code{arm_var}, \code{id_var}, \code{saffl_var}, \code{trtsdtm_var}, and \code{trtedtm_var}. 63 | \item Flag variables (i.e. \code{XXXFL}) are expected to have two levels: \code{"Y"} (true) and \code{"N"} (false). Missing values in 64 | flag variables are treated as \code{"N"}. 65 | \item It is assumed that every record for a unique patient in \code{df} has the same treatment start and end datetime. 66 | \item Values in the "Number of Patients" table are the number of patients for each arm with treatment duration equal to 67 | or greater than the given time (times corresponding to the figure's x-ticks labels). 68 | \item Records with missing treatment start and/or end datetime are excluded from all calculations. 69 | } 70 | } 71 | \examples{ 72 | adsl <- random.cdisc.data::cadsl 73 | adsl$TRTSDTM <- adsl$TRTSDTM[1] 74 | adsl$TRTEDTM <- adsl$TRTSDTM + lubridate::days(sample(0:400, nrow(adsl), replace = TRUE)) 75 | 76 | fig <- make_fig_01(df = adsl) 77 | fig 78 | 79 | } 80 | -------------------------------------------------------------------------------- /man/make_fig_02.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-fig_02.R 3 | \name{make_fig_02} 4 | \alias{make_fig_02} 5 | \title{FDA Figure 2: Time to Last Follow Up, Safety Population, Pooled Analyses} 6 | \usage{ 7 | make_fig_02( 8 | df, 9 | arm_var = "ARM", 10 | id_var = "USUBJID", 11 | saffl_var = "SAFFL", 12 | eosdy_var = "EOSDY", 13 | u_trtdur = "days", 14 | x_lab = paste0("Time from first dose (", u_trtdur, ")"), 15 | y_lab = "Percent of Patients (\%)", 16 | xticks = NA, 17 | ggtheme = NULL, 18 | add_table = TRUE, 19 | annotations = NULL 20 | ) 21 | } 22 | \arguments{ 23 | \item{df}{(\code{data.frame})\cr dataset required to build table.} 24 | 25 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 26 | 27 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 28 | 29 | \item{saffl_var}{(\code{character})\cr Name of the safety flag variable which must contain at least "Y" for "Yes".} 30 | 31 | \item{eosdy_var}{(\code{character})\cr variable denoting last recorded (relative) study day.} 32 | 33 | \item{u_trtdur}{(\code{character})\cr unit for duration of treatment. Options are \code{"days"}, \code{"weeks"}, \code{"months"}, 34 | and \code{"years"}.} 35 | 36 | \item{x_lab}{(\code{character})\cr x-axis label.} 37 | 38 | \item{y_lab}{(\code{character})\cr y-axis label.} 39 | 40 | \item{xticks}{(\code{vector} of \code{numeric})\cr x-axis tick positions. If \code{NA} (default), tick mark positions are 41 | automatically calculated.} 42 | 43 | \item{ggtheme}{(\code{theme})\cr a graphical theme as provided by \code{ggplot2} to control styling of the \code{ggplot} object.} 44 | 45 | \item{add_table}{(\code{flag})\cr whether "Number of Patients" table should be printed under the plot.} 46 | 47 | \item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the figure. Valid annotation types 48 | are \code{title}, \code{subtitles}, and \code{caption}. Each name-value pair should use the annotation type as name and the 49 | desired string as value.} 50 | } 51 | \value{ 52 | A \code{ggplot2} object. 53 | } 54 | \description{ 55 | FDA Figure 2: Time to Last Follow Up, Safety Population, Pooled Analyses 56 | } 57 | \details{ 58 | \itemize{ 59 | \item \code{df} must contain the variables specified by \code{arm_var}, \code{id_var}, \code{saffl_var}, and \code{eosdy_var}. 60 | \item Flag variables (i.e. \code{XXXFL}) are expected to have two levels: \code{"Y"} (true) and \code{"N"} (false). Missing values in 61 | flag variables are treated as \code{"N"}. 62 | \item It is assumed that every record for a unique patient in \code{df} has the same last recorded (relative) study day. 63 | \item Values in the "Number of Patients" table are the number of patients for each arm with treatment duration equal to 64 | or greater than the given time (times corresponding to the figure's x-ticks labels). 65 | \item Records with missing treatment start and/or end datetime are excluded from all calculations. 66 | } 67 | } 68 | \examples{ 69 | adsl <- random.cdisc.data::cadsl 70 | adsl$EOSDY <- sample(0:400, nrow(adsl), replace = TRUE) 71 | 72 | fig <- make_fig_02(df = adsl) 73 | fig 74 | 75 | } 76 | -------------------------------------------------------------------------------- /man/make_fig_03.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-fig_03.R 3 | \name{make_fig_03} 4 | \alias{make_fig_03} 5 | \title{FDA Figure 3: Time to Adverse Event Leading to Treatment Discontinuation, Safety Population, Trial X} 6 | \usage{ 7 | make_fig_03( 8 | df, 9 | arm_var = "ARM", 10 | id_var = "USUBJID", 11 | saffl_var = "SAFFL", 12 | trtsdtm_var = "TRTSDTM", 13 | trtedtm_var = "TRTEDTM", 14 | u_trtdur = "days", 15 | dcsreas_var = "DCSREAS", 16 | x_lab = paste0("Time from first dose (", u_trtdur, ")"), 17 | y_lab = "Cumulative Incidence (\%)\\nAEs Leading to Treatment\\nDiscontinuation", 18 | xticks = NA, 19 | ggtheme = NULL, 20 | add_table = TRUE, 21 | annotations = NULL 22 | ) 23 | } 24 | \arguments{ 25 | \item{df}{(\code{data.frame})\cr dataset required to build table.} 26 | 27 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 28 | 29 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 30 | 31 | \item{saffl_var}{(\code{character})\cr Name of the safety flag variable which must contain at least "Y" for "Yes".} 32 | 33 | \item{trtsdtm_var}{(\code{character})\cr treatment start datetime variable.} 34 | 35 | \item{trtedtm_var}{(\code{character})\cr treatment end datetime variable.} 36 | 37 | \item{u_trtdur}{(\code{character})\cr unit for duration of treatment. Options are \code{"days"}, \code{"weeks"}, \code{"months"}, 38 | and \code{"years"}.} 39 | 40 | \item{dcsreas_var}{(\code{character})\cr reason for treatment discontinuation variable used to split figure into lines.} 41 | 42 | \item{x_lab}{(\code{character})\cr x-axis label.} 43 | 44 | \item{y_lab}{(\code{character})\cr y-axis label.} 45 | 46 | \item{xticks}{(\code{vector} of \code{numeric})\cr x-axis tick positions. If \code{NA} (default), tick mark positions are 47 | automatically calculated.} 48 | 49 | \item{ggtheme}{(\code{theme})\cr a graphical theme as provided by \code{ggplot2} to control styling of the \code{ggplot} object.} 50 | 51 | \item{add_table}{(\code{flag})\cr whether tables should be printed under the plot.} 52 | 53 | \item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the figure. Valid annotation types 54 | are \code{title}, \code{subtitles}, and \code{caption}. Each name-value pair should use the annotation type as name and the 55 | desired string as value.} 56 | } 57 | \value{ 58 | A \code{ggplot2} object. 59 | } 60 | \description{ 61 | FDA Figure 3: Time to Adverse Event Leading to Treatment Discontinuation, Safety Population, Trial X 62 | } 63 | \details{ 64 | \itemize{ 65 | \item \code{df} must contain the variables specified by \code{arm_var}, \code{id_var}, \code{saffl_var}, \code{trtsdtm_var}, \code{trtedtm_var} and 66 | \code{dcsreas_var}. 67 | \item Flag variables (i.e. \code{XXXFL}) are expected to have two levels: \code{"Y"} (true) and \code{"N"} (false). Missing values in 68 | flag variables are treated as \code{"N"}. 69 | \item It is assumed that every record for a unique patient in \code{df} has the same treatment start and end datetime. 70 | \item Values in the "Number at risk" table are the number of patients at risk for each arm with treatment duration equal 71 | to 72 | or greater than the given time (times corresponding to the figure's x-ticks labels). 73 | \item Values in the "Cumulative Number of Patients with Event" table are the cumulative number of patients given time to 74 | AEs leading to treatment discontinuation for each arm throughout the trial (times corresponding to the figure's 75 | x-ticks labels). 76 | \item Records with missing treatment start and/or end datetime are excluded from all calculations. 77 | } 78 | } 79 | \examples{ 80 | adsl <- random.cdisc.data::cadsl 81 | 82 | fig <- make_fig_03(df = adsl, dcsreas_var = "DCSREAS") 83 | fig 84 | 85 | } 86 | -------------------------------------------------------------------------------- /man/make_fig_14.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-fig_14.R 3 | \name{make_fig_14} 4 | \alias{make_fig_14} 5 | \title{FDA Figure 14: Mean and 95\% Confidence Interval of Systolic Blood Pressure Over Time 6 | by Treatment Arm, Safety Population, Trial X} 7 | \usage{ 8 | make_fig_14( 9 | df, 10 | arm_var = "ARM", 11 | saffl_var = "SAFFL", 12 | visit_var = "AVISIT", 13 | paramcd_val = "SYSBP", 14 | add_cond = NULL, 15 | x_lab = "", 16 | y_lab = NULL, 17 | yticks = NA, 18 | ggtheme = NULL, 19 | add_table = TRUE, 20 | annotations = NULL 21 | ) 22 | } 23 | \arguments{ 24 | \item{df}{(\code{data.frame})\cr dataset required to build table.} 25 | 26 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 27 | 28 | \item{saffl_var}{(\code{character})\cr Name of the safety flag variable which must contain at least "Y" for "Yes".} 29 | 30 | \item{visit_var}{(\code{character})\cr visit variable to put on the x-axis} 31 | 32 | \item{paramcd_val}{(\code{character})\cr value of \code{PARAMCD} to plot} 33 | 34 | \item{add_cond}{(\code{expr})\cr expression that provides additional filters for the analysis 35 | (for instance on \code{ATPT} or \code{VSPOS})} 36 | 37 | \item{x_lab}{(\code{character})\cr x-axis label.} 38 | 39 | \item{y_lab}{(\code{character})\cr y-axis label.} 40 | 41 | \item{yticks}{(\code{vector} of \code{numeric})\cr y-axis tick positions. If \code{NA} (default), tick mark positions are 42 | automatically calculated.} 43 | 44 | \item{ggtheme}{(\code{theme})\cr a graphical theme as provided by \code{ggplot2} to control styling of the \code{ggplot} object.} 45 | 46 | \item{add_table}{(\code{flag})\cr whether "Mean Value" and "Number of Patients" tables should be printed under the plot} 47 | 48 | \item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the figure. Valid annotation types 49 | are \code{title}, \code{subtitles}, and \code{caption}. Each name-value pair should use the annotation type as name and the 50 | desired string as value.} 51 | } 52 | \value{ 53 | A \code{ggplot2} object. 54 | } 55 | \description{ 56 | FDA Figure 14: Mean and 95\% Confidence Interval of Systolic Blood Pressure Over Time 57 | by Treatment Arm, Safety Population, Trial X 58 | } 59 | \details{ 60 | \itemize{ 61 | \item \code{df} must contain the variables \code{AVAL} and \code{PARAMCD}, and the variables specified by \code{arm_var}, 62 | \code{saffl_var}, \code{visit_var}, and \code{add_cond}. 63 | \item Flag variables (i.e. \code{XXXFL}) are expected to have two levels: \code{"Y"} (true) and \code{"N"} (false). Missing values in 64 | flag variables are treated as \code{"N"}. 65 | \item It is assumed that \code{df} contains one unique record per patient. 66 | } 67 | } 68 | \examples{ 69 | advs <- random.cdisc.data::cadvs 70 | 71 | fig <- make_fig_14( 72 | df = advs, 73 | add_cond = bquote("ONTRTFL == 'Y' | ABLFL == 'Y'"), 74 | add_table = TRUE, 75 | yticks = c(135, 140, 145, 150, 155, 160) 76 | ) 77 | fig 78 | 79 | } 80 | -------------------------------------------------------------------------------- /man/make_table_03.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-table_03.R 3 | \name{make_table_03} 4 | \alias{make_table_03} 5 | \title{FDA Table 3: Patient Screening and Enrollment, Trials A and B} 6 | \usage{ 7 | make_table_03( 8 | df, 9 | alt_counts_df = NULL, 10 | show_colcounts = FALSE, 11 | arm_var = "ARM", 12 | id_var = "USUBJID", 13 | scrnfl_var, 14 | scrnfailfl_var, 15 | scrnfail_var, 16 | lbl_overall = NULL, 17 | prune_0 = TRUE, 18 | annotations = NULL 19 | ) 20 | } 21 | \arguments{ 22 | \item{df}{(\code{data.frame})\cr dataset required to build table.} 23 | 24 | \item{alt_counts_df}{(\code{character})\cr alternative dataset (typically ADSL) used only to calculate column counts.} 25 | 26 | \item{show_colcounts}{(\code{flag})\cr Whether column counts should be printed. Boolean.} 27 | 28 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 29 | 30 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 31 | 32 | \item{scrnfl_var}{(\code{character})\cr variable from \code{df} that indicates whether patients were screened.} 33 | 34 | \item{scrnfailfl_var}{(\code{character})\cr variable from \code{df} that indicates screening failure.} 35 | 36 | \item{scrnfail_var}{(\code{character})\cr variable from \code{df} that contains reasons for screening failure.} 37 | 38 | \item{lbl_overall}{(\code{character})\cr Optional. If specified, an overall column will be added to the table with 39 | the given value as the column label.} 40 | 41 | \item{prune_0}{(\code{flag})\cr Whether all-zero rows should be removed from the table. Boolean.} 42 | 43 | \item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the table. Valid 44 | annotation types are \code{title}, \code{subtitles}, \code{main_footer}, and \code{prov_footer}. Each name-value pair should 45 | use the annotation type as name and the desired string as value.} 46 | } 47 | \description{ 48 | FDA Table 3: Patient Screening and Enrollment, Trials A and B 49 | } 50 | \details{ 51 | \itemize{ 52 | \item \code{adsl} must contain \code{ENRLDT}, \code{RANDDT}, and the variables specified by \code{id_var}, \code{arm_var}, \code{scrnfl_var}, 53 | \code{scrnfailfl_var}, and \code{scrnfail_var}. 54 | \item If specified, \code{alt_counts_df} must contain the variables specified by \code{arm_var} and \code{id_var}. 55 | \item Patients are considered enrolled in they have an enrollment date (\code{ENRLDT} is not missing), and are considered 56 | randomized if they have a randomization date (\code{RANDDT} is not missing). 57 | \item Flag variables (i.e. \code{XXXFL}) are expected to have two levels: \code{"Y"} (true) and \code{"N"} (false). Missing values in 58 | flag variables are treated as \code{"N"}. 59 | \item Columns are split by arm. 60 | \item Numbers in table represent the absolute numbers of patients and fraction of \code{N}. 61 | \item All-zero rows are removed by default (see \code{prune_0} argument). 62 | } 63 | } 64 | \examples{ 65 | library(dplyr) 66 | 67 | set.seed(1) 68 | adsl <- random.cdisc.data::cadsl 69 | adsl$RANDDT[sample(seq_len(nrow(adsl)), 100)] <- NA 70 | scrnfail_reas_lvls <- c( 71 | "Inclusion/exclusion criteria not met", "Patient noncompliance", "Consent withdrawn", "Other" 72 | ) 73 | adsl <- adsl \%>\% 74 | mutate( 75 | ENRLDT = RANDDT, 76 | SCRNFL = "Y", 77 | SCRNFRS = factor(sample(scrnfail_reas_lvls, size = nrow(adsl), replace = TRUE), 78 | levels = scrnfail_reas_lvls 79 | ), 80 | SCRNFAILFL = ifelse(is.na(ENRLDT), "Y", "N") 81 | ) 82 | adsl$SCRNFRS[adsl$SCRNFL == "N" | !is.na(adsl$ENRLDT)] <- NA 83 | 84 | tbl <- make_table_03( 85 | df = adsl, scrnfl_var = "SCRNFL", scrnfailfl_var = "SCRNFAILFL", scrnfail_var = "SCRNFRS" 86 | ) 87 | tbl 88 | 89 | } 90 | -------------------------------------------------------------------------------- /man/make_table_08.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-table_08.R 3 | \name{make_table_08} 4 | \alias{make_table_08} 5 | \title{FDA Table 8: All Individual Patient Deaths, Safety Population, Pooled Analyses} 6 | \usage{ 7 | make_table_08( 8 | adae, 9 | adex, 10 | arm_var = "ARM", 11 | id_var = "USUBJID", 12 | saffl_var = "SAFFL", 13 | dth_vars = c("DTHCAUS", "DTHCAT"), 14 | lbl_dth_vars = c("Cause of Death\\nMedDRA\\nPreferred Term", 15 | "Cause of Death\\nVerbatim Term"), 16 | na_level = "NA", 17 | annotations = NULL 18 | ) 19 | } 20 | \arguments{ 21 | \item{adae}{(\code{data.frame})\cr dataset (typically ADAE) required to build table.} 22 | 23 | \item{adex}{(\code{data.frame})\cr dataset (typically ADEX) required to build table.} 24 | 25 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 26 | 27 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 28 | 29 | \item{saffl_var}{(\code{character})\cr Name of the safety flag variable which must contain at least "Y" for "Yes".} 30 | 31 | \item{dth_vars}{(\code{vector} of \code{character})\cr additional death variables from \code{adae} to include in the table.} 32 | 33 | \item{lbl_dth_vars}{(\code{vector} of \code{character})\cr labels corresponding to variables in \code{dth_vars} to print 34 | in the table. Labels should be ordered according to the order of variables in \code{dth_vars}.} 35 | 36 | \item{na_level}{(\code{character})\cr String to represent missing values.} 37 | 38 | \item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the table. Valid 39 | annotation types are \code{title}, \code{subtitles}, \code{main_footer}, and \code{prov_footer}. Each name-value pair should 40 | use the annotation type as name and the desired string as value.} 41 | } 42 | \value{ 43 | A \code{listing_df} object. 44 | } 45 | \description{ 46 | FDA Table 8: All Individual Patient Deaths, Safety Population, Pooled Analyses 47 | } 48 | \details{ 49 | \itemize{ 50 | \item \code{adae} must contain \code{AGE}, \code{SEX}, \code{AESDTH}, \code{DTHADY}, and the variables specified by 51 | \code{dth_vars}, \code{arm_var}, \code{id_var}, and \code{saffl_var}. 52 | \item \code{adex} must contain \code{PARAMCD}, \code{TRTSDT}, \code{TRTEDT}, \code{AVAL}, \code{AVALU}, and the variables specified 53 | by \code{arm_var}, \code{id_var}, and \code{saffl_var}. 54 | \item Flag variables (i.e. \code{XXXFL}) are expected to have two levels: \code{"Y"} (true) and \code{"N"} (false). Missing values in 55 | flag variables are treated as \code{"N"}. 56 | } 57 | } 58 | \examples{ 59 | adae <- random.cdisc.data::cadae 60 | adex <- random.cdisc.data::cadex 61 | 62 | tbl <- make_table_08(adae = adae, adex = adex) 63 | head(tbl, 20) 64 | 65 | } 66 | -------------------------------------------------------------------------------- /man/make_table_09_gtsummary.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-table_09.R 3 | \name{make_table_09_gtsummary} 4 | \alias{make_table_09_gtsummary} 5 | \title{Engine-Specific Functions: Table 09} 6 | \usage{ 7 | make_table_09_gtsummary( 8 | df, 9 | denominator = NULL, 10 | saffl_var = "SAFFL", 11 | ser_var = "AESER", 12 | arm_var = "ARM", 13 | pref_var = "AEDECOD", 14 | id_var = "USUBJID", 15 | soc_var = "AESOC", 16 | lbl_overall = NULL 17 | ) 18 | } 19 | \arguments{ 20 | \item{df}{(\code{data.frame})\cr dataset required to build table.} 21 | 22 | \item{denominator}{(\code{data.frame})\cr alternative dataset (typically ADSL) used only to calculate denominator counts.} 23 | 24 | \item{saffl_var}{(\code{character})\cr Name of the safety flag variable which must contain at least "Y" for "Yes".} 25 | 26 | \item{ser_var}{(\code{character})\cr Name of the serious adverse event flag variable which must contain at least 27 | "Y" for "Yes".} 28 | 29 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 30 | 31 | \item{pref_var}{(\code{character})\cr Name of the preferred term variable from \code{adae} to include in the table.} 32 | 33 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 34 | 35 | \item{soc_var}{(\code{character})\cr Name of the system organ class variable from \code{adae} to include in the table.} 36 | 37 | \item{lbl_overall}{(\code{character})\cr Optional. If specified, an overall column will be added to the table with 38 | the given value as the column label.} 39 | } 40 | \value{ 41 | \itemize{ 42 | \item \code{make_table_09_gtsummary()} returns a \code{gtsummary} object. 43 | } 44 | } 45 | \description{ 46 | The table engine used by each engine-specific function is identified by its suffix. 47 | } 48 | \examples{ 49 | adsl <- random.cdisc.data::cadsl 50 | adae <- random.cdisc.data::cadae 51 | 52 | tbl_gtsummary <- make_table_09_gtsummary(df = adae, denominator = adsl) 53 | tbl_gtsummary 54 | } 55 | \seealso{ 56 | \code{\link[=make_table_09]{make_table_09()}} 57 | } 58 | -------------------------------------------------------------------------------- /man/make_table_10.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-table_10.R 3 | \name{make_table_10} 4 | \alias{make_table_10} 5 | \title{FDA Table 10: Patients With Serious Adverse Events by System Organ Class and 6 | FDA Medical Query (Narrow), Safety Population, Pooled Analyses} 7 | \usage{ 8 | make_table_10( 9 | df, 10 | denominator = NULL, 11 | return_ard = TRUE, 12 | id_var = "USUBJID", 13 | arm_var = "ARM", 14 | saffl_var = "SAFFL", 15 | fmqsc_var = "FMQ01SC", 16 | fmqnam_var = "FMQ01NAM", 17 | fmq_scope = "NARROW", 18 | na_level = "<Missing>" 19 | ) 20 | } 21 | \arguments{ 22 | \item{df}{(\code{data.frame})\cr dataset required to build table.} 23 | 24 | \item{denominator}{(\code{data.frame})\cr alternative dataset (typically ADSL) used only to calculate denominator counts.} 25 | 26 | \item{return_ard}{(\code{flag})\cr whether an ARD should be returned. Defaults to \code{TRUE}.} 27 | 28 | \item{id_var}{(\code{character})\cr Name of the unique subject identifiers variable.} 29 | 30 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 31 | 32 | \item{saffl_var}{(\code{character})\cr Name of the safety flag variable which must contain at least "Y" for "Yes".} 33 | 34 | \item{fmqsc_var}{(\code{character})\cr FMQ scope variable to use in table.} 35 | 36 | \item{fmqnam_var}{(\code{character})\cr FMQ reference name variable to use in table.} 37 | 38 | \item{fmq_scope}{(\code{character})\cr FMQ scope ("NARROW" or "BROAD") to output in table.} 39 | 40 | \item{na_level}{(\code{character})\cr String to represent missing values.} 41 | } 42 | \value{ 43 | A \code{gtsummary} table and, if \code{return_ard = TRUE}, an ARD. 44 | If \code{return_ard = TRUE}, they will be returned as a list with named elements \code{table} and \code{ard}. 45 | } 46 | \description{ 47 | FDA Table 10: Patients With Serious Adverse Events by System Organ Class and 48 | FDA Medical Query (Narrow), Safety Population, Pooled Analyses 49 | } 50 | \details{ 51 | \itemize{ 52 | \item \code{adae} must contain the variables \code{AEBODSYS}, \code{AESER}, and the variables specified by 53 | \code{arm_var}, \code{id_var}, \code{saffl_var}, \code{fmqsc_var}, and \code{fmqnam_var}. 54 | \item If specified, \code{denominator} must contain \code{USUBJID} and the variables specified by \code{arm_var} and \code{saffl_var}. 55 | \item \code{fmqsc_var} must contain "BROAD" or "NARROW" values, one of which will be displayed in the table. Narrow is 56 | selected by default (see \code{fmq_scope} argument). 57 | \item Flag variables (i.e. \code{XXXFL}) are expected to have two levels: \code{"Y"} (true) and \code{"N"} (false). Missing values in 58 | flag variables are treated as \code{"N"}. 59 | \item Numbers in table represent the absolute numbers of patients and fraction of \code{N}. 60 | } 61 | } 62 | \examples{ 63 | library(dplyr) 64 | 65 | adsl <- random.cdisc.data::cadsl 66 | adae <- random.cdisc.data::cadae 67 | 68 | set.seed(1) 69 | adae <- adae \%>\% 70 | rename(FMQ01SC = SMQ01SC) \%>\% 71 | mutate( 72 | AESER = sample(c("Y", "N"), size = nrow(adae), replace = TRUE), 73 | FMQ01NAM = sample(c("FMQ1", "FMQ2", "FMQ3"), size = nrow(adae), replace = TRUE) 74 | ) 75 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 76 | 77 | tbl <- make_table_10(df = adae, denominator = adsl) 78 | tbl 79 | 80 | } 81 | \seealso{ 82 | \code{\link{tbl_make_table_10}} 83 | } 84 | -------------------------------------------------------------------------------- /man/make_table_22.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-table_22.R 3 | \name{make_table_22} 4 | \alias{make_table_22} 5 | \title{FDA Table 22. Overview of Adverse Events by Demographic Subgroup, Safety Population, Pooled Analysis (or Trial X)} 6 | \usage{ 7 | make_table_22( 8 | df, 9 | alt_counts_df = NULL, 10 | show_colcounts = TRUE, 11 | arm_var = "ARM", 12 | saffl_var = "SAFFL", 13 | vars = c("SEX", "AGEGR1", "RACE", "ETHNIC"), 14 | denom = c("N_s", "N_col", "n"), 15 | lbl_overall = NULL, 16 | lbl_vars = formatters::var_labels(df, fill = TRUE)[vars], 17 | prune_0 = FALSE, 18 | annotations = NULL 19 | ) 20 | } 21 | \arguments{ 22 | \item{df}{(\code{data.frame})\cr dataset required to build table.} 23 | 24 | \item{alt_counts_df}{(\code{character})\cr alternative dataset (typically ADSL) used only to calculate column counts.} 25 | 26 | \item{show_colcounts}{(\code{flag})\cr Whether column counts should be printed. Boolean.} 27 | 28 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 29 | 30 | \item{saffl_var}{(\code{character})\cr Name of the safety flag variable which must contain at least "Y" for "Yes".} 31 | 32 | \item{vars}{(\code{vector} of \code{character})\cr Variables from \code{df} to include in the table.} 33 | 34 | \item{denom}{(\code{character})\cr Denominator to use to calculate fractions. Can be \code{"N_s"} (total \code{df_denom} 35 | subgroup/row counts), \code{"N_col"} (total \code{df} column counts), or \code{"n"} (total \code{df} overall patient count). 36 | Note that \code{df} is filtered to only include treatment-emergent adverse events (\code{TRTEMFL == "Y"}).} 37 | 38 | \item{lbl_overall}{(\code{character})\cr Optional. If specified, an overall column will be added to the table with 39 | the given value as the column label.} 40 | 41 | \item{lbl_vars}{(\code{vector} of \code{character})\cr Labels corresponding to variables in \code{vars} to print 42 | in the table. Labels should be ordered according to the order of variables in \code{vars}.} 43 | 44 | \item{prune_0}{(\code{flag})\cr Whether all-zero rows should be removed from the table. Boolean.} 45 | 46 | \item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the table. Valid 47 | annotation types are \code{title}, \code{subtitles}, \code{main_footer}, and \code{prov_footer}. Each name-value pair should 48 | use the annotation type as name and the desired string as value.} 49 | } 50 | \value{ 51 | An \code{rtable} object. 52 | } 53 | \description{ 54 | FDA Table 22. Overview of Adverse Events by Demographic Subgroup, Safety Population, Pooled Analysis (or Trial X) 55 | } 56 | \details{ 57 | \itemize{ 58 | \item \code{df} must contain the variables specified by \code{vars}, \code{arm_var}, and \code{saffl_var}. 59 | \item If specified, \code{alt_counts_df} must contain \code{USUBJID} and the variables specified by \code{arm_var} and \code{saffl_var}. 60 | \item Flag variables (i.e. \code{XXXFL}) are expected to have two levels: \code{"Y"} (true) and \code{"N"} (false). Missing values in 61 | flag variables are treated as \code{"N"}. 62 | \item Columns are split by arm. 63 | \item Information from either ADSUB or ADVS is generally included into \code{df} prior to analysis. 64 | \item Numbers in the table for non-numeric variables represent the absolute number of patients and fraction of \code{n}. 65 | \item All-zero rows are removed by default (see \code{prune_0} argument). 66 | } 67 | } 68 | \examples{ 69 | library(dplyr) 70 | 71 | adsl <- random.cdisc.data::cadsl \%>\% 72 | mutate(AGEGR1 = as.factor(case_when( 73 | AGE >= 17 & AGE < 65 ~ ">=17 to <65", 74 | AGE >= 65 ~ ">=65", 75 | AGE >= 65 & AGE < 75 ~ ">=65 to <75", 76 | AGE >= 75 ~ ">=75" 77 | )) \%>\% formatters::with_label("Age Group, years")) \%>\% 78 | formatters::var_relabel(AGE = "Age, years") 79 | 80 | adae <- random.cdisc.data::cadae 81 | 82 | df <- left_join(adsl, adae, by = intersect(names(adsl), names(adae))) 83 | 84 | tbl <- make_table_22(df = df, alt_counts_df = adsl) 85 | tbl 86 | 87 | } 88 | -------------------------------------------------------------------------------- /man/preproc_df_table_10.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fda-table_10.R 3 | \name{preproc_df_table_10} 4 | \alias{preproc_df_table_10} 5 | \title{Pre-Process Data for Table 10 Creation} 6 | \usage{ 7 | preproc_df_table_10( 8 | df, 9 | id_var = "USUBJID", 10 | arm_var = "ARM", 11 | saffl_var = "SAFFL", 12 | fmqsc_var = "FMQ01SC", 13 | fmqnam_var = "FMQ01NAM", 14 | fmq_scope = "NARROW", 15 | na_level = "<Missing>" 16 | ) 17 | } 18 | \description{ 19 | Pre-Process Data for Table 10 Creation 20 | } 21 | \keyword{internal} 22 | -------------------------------------------------------------------------------- /man/split_cols_by_arm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{split_cols_by_arm} 4 | \alias{split_cols_by_arm} 5 | \title{Split Columns by Arm Variable} 6 | \usage{ 7 | split_cols_by_arm(lyt, arm_var = "ARM", lbl_overall = NULL, risk_diff = NULL) 8 | } 9 | \arguments{ 10 | \item{lyt}{(\code{rtables} layout object)\cr Layout object pre-data used for tabulation.} 11 | 12 | \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} 13 | 14 | \item{lbl_overall}{(\code{character})\cr Optional. If specified, an overall column will be added to the table with 15 | the given value as the column label.} 16 | 17 | \item{risk_diff}{(named \code{list})\cr list of settings to apply to add one or more risk difference columns to the table. 18 | Defaults to \code{NULL} (no risk difference column added). See \code{\link[tern:add_riskdiff]{tern::add_riskdiff()}} for more details. List should 19 | contain the following elements: 20 | \itemize{ 21 | \item \code{arm_x}: (required) the name of reference arm. 22 | \item \code{arm_y}: (required) the names of the arms to compare to the reference arm. A new column will be added for each 23 | element of \code{arm_y}. 24 | \item \code{col_label}: (optional) labels to use for the risk difference columns. Defaults to 25 | \code{"Risk Difference (\%) (95\% CI)"}. For more than one risk difference column, \code{"arm x vs. arm y"} text will also 26 | be included in the column labels by default. The length of \code{col_label} must be equal to the length of \code{arm_y}. 27 | \item \code{pct}: (optional) whether the output should be returned as percentages. Defaults to \code{TRUE}. 28 | }} 29 | } 30 | \value{ 31 | An \code{rtables} \code{PreDataTableLayouts} object suitable for passing to further layout functions, and 32 | to \code{build_table}. 33 | } 34 | \description{ 35 | Splits \code{rtables} layout into columns by arm variable. Appends an "overall" column as the 36 | rightmost column if \code{lbl_overall} is supplied. 37 | } 38 | \examples{ 39 | library(magrittr) 40 | 41 | adsl <- random.cdisc.data::cadsl 42 | 43 | lyt <- rtables::basic_table() \%>\% split_cols_by_arm(lbl_overall = "All Arms") 44 | rtables::build_table(lyt, df = adsl) 45 | 46 | } 47 | -------------------------------------------------------------------------------- /quarto/about.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: About the Project 3 | --- 4 | 5 | The cardinal project (previously "falcon") is a product of industry collaboration to encourage the development of shared code, expertise, knowledge, and products. 6 | 7 | In the near future, the goal is to develop functionality to create regulatory reporting tables suitable for FDA filing. The long-term objective of this collaboration is to develop an R package that can be used industry wide - developing a cross-industry standard and reducing manual work from a reporting perspective. 8 | 9 | ## Our Collaboration Journey 10 | 11 | Current collaborators are from Roche, Sanofi, Boehringer Ingelheim, and Moderna. Developers are connected via [Slack](https://app.slack.com/client/T028PB489D3/C04MQS12MND) and [GitHub](https://github.com/pharmaverse/cardinal) for the creation of shared solutions using publicly available analysis packages for R. Developers are invited to browse the cardinal project repository and related packages for insight into our template designs. 12 | 13 | ### Joining as a Collaborator 14 | 15 | As always we invite further collaboration and welcome additional companies to join the cardinal initiative and contribute to the project. Please feel free to contact any of the repository maintainers for more information and check out the section below for more information on joining the project as a developer. 16 | 17 | #### Information for Developers 18 | 19 | As a pharmaverse collaboration, we invite any interested developers to join the cardinal team and contribute to template development. To onboard as a developer, please reach out to one of the cardinal Product Owners ([Vincent Shen](https://github.com/telepath37), [Freeman Wang](https://github.com/freestatman), Kavitha Allala, Lian Lin) to receive access to the cardinal GitHub repository. 20 | 21 | Tasks are assigned and prioritized via issues on our GitHub project board and worked on in development branches. Members of the team will review each other's code and make suggestions before new functions and features are incorporated into the package. 22 | 23 | We encourage onboarding developers to familiarize themselves with the following packages as they contain functions leveraged by cardinal for table creation: 24 | 25 | - [`gtsummary`](https://www.danieldsjoberg.com/gtsummary/): Table creation 26 | - [`cards`](https://insightsengineering.github.io/cards/main/): Analysis Results Dataset creation 27 | - [`cardx`](https://insightsengineering.github.io/cardx/main/): Extended ARD creation functions 28 | 29 | 30 | -------------------------------------------------------------------------------- /quarto/assets/images/getting-started/gs-pan1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/getting-started/gs-pan1.png -------------------------------------------------------------------------------- /quarto/assets/images/getting-started/gs-pan2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/getting-started/gs-pan2.png -------------------------------------------------------------------------------- /quarto/assets/images/getting-started/gs-pan3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/getting-started/gs-pan3.png -------------------------------------------------------------------------------- /quarto/assets/images/getting-started/gs-pan4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/getting-started/gs-pan4.png -------------------------------------------------------------------------------- /quarto/assets/images/getting-started/gs-pan4b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/getting-started/gs-pan4b.png -------------------------------------------------------------------------------- /quarto/assets/images/image-placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/image-placeholder.png -------------------------------------------------------------------------------- /quarto/assets/images/logo-bi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/logo-bi.png -------------------------------------------------------------------------------- /quarto/assets/images/logo-moderna.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/logo-moderna.jpg -------------------------------------------------------------------------------- /quarto/assets/images/logo-roche.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/logo-roche.png -------------------------------------------------------------------------------- /quarto/assets/images/logo-sanofi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/logo-sanofi.png -------------------------------------------------------------------------------- /quarto/assets/images/logo/cardinal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/logo/cardinal.pdf -------------------------------------------------------------------------------- /quarto/assets/images/logo/cardinal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/logo/cardinal.png -------------------------------------------------------------------------------- /quarto/assets/images/logo/cardinal.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/logo/cardinal.webp -------------------------------------------------------------------------------- /quarto/assets/images/pharmaverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/pharmaverse.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/fig_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/fig_01.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/fig_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/fig_02.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/fig_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/fig_03.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/fig_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/fig_14.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_02.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_03.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_04.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_05.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_06.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_07.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_08.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_09.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_10.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_13.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_14.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_15.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_16.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_17.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_18.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_20.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_21.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_22.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_32.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_33.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_34.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_35.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_36.png -------------------------------------------------------------------------------- /quarto/assets/images/screenshots/table_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/images/screenshots/table_38.png -------------------------------------------------------------------------------- /quarto/assets/resources/FDA-STF-IG-2022-N-1961-0002.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/resources/FDA-STF-IG-2022-N-1961-0002.pdf -------------------------------------------------------------------------------- /quarto/assets/resources/cardinal_PHUSE_EU_2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/resources/cardinal_PHUSE_EU_2023.pptx -------------------------------------------------------------------------------- /quarto/assets/resources/cardinal_RinPharma_Workshop_2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/assets/resources/cardinal_RinPharma_Workshop_2023.pptx -------------------------------------------------------------------------------- /quarto/assets/style-dark.scss: -------------------------------------------------------------------------------- 1 | /*-- scss:defaults --*/ 2 | 3 | $toc-color: #E21318; 4 | $navbar-bg: #323232; 5 | 6 | /*-- scss:rules --*/ 7 | 8 | /* css styles */ 9 | .navbar .navbar-brand { 10 | color: white !important; 11 | } 12 | 13 | .navbar li.nav-item a.nav-link span { 14 | color: white !important; 15 | } 16 | 17 | .panel-tabset li.nav-item a.nav-link { 18 | color: #A3070B; 19 | } 20 | 21 | .panel-tabset li.nav-item a.nav-link.active { 22 | color: #E21318; 23 | } 24 | -------------------------------------------------------------------------------- /quarto/assets/style-light.scss: -------------------------------------------------------------------------------- 1 | /*-- scss:defaults --*/ 2 | 3 | $toc-color: #A3070B; 4 | $navbar-bg: #F8F9FA; 5 | $navbar-fg: #212529; 6 | 7 | /*-- scss:rules --*/ 8 | 9 | /* css styles */ 10 | .navbar .navbar-brand { 11 | color: #212529 !important; 12 | } 13 | 14 | .navbar .navbar-tools { 15 | color: #212529 !important; 16 | } 17 | 18 | .navbar li.nav-item a.nav-link span { 19 | color: #212529 !important; 20 | } 21 | 22 | .panel-tabset li.nav-item a.nav-link { 23 | color: #E21318; 24 | } 25 | 26 | .panel-tabset li.nav-item a.nav-link.active { 27 | color: #A3070B; 28 | } 29 | -------------------------------------------------------------------------------- /quarto/assets/style.scss: -------------------------------------------------------------------------------- 1 | /*-- scss:defaults --*/ 2 | 3 | $primary: #E21318 !default; 4 | $secondary: #A3070B !default; 5 | $dark: #212529 !default; 6 | $light: #F8F9FA !default; 7 | $code-color: #212529 !default; 8 | 9 | /*-- scss:rules --*/ 10 | 11 | pre { 12 | background-color: rgba(233, 236, 239, 0.65); 13 | } 14 | 15 | /* css styles */ 16 | h1, h2, .subtitle { 17 | text-align: center; 18 | } 19 | 20 | ul { 21 | max-height: 400px; 22 | overflow-y: auto; 23 | } 24 | 25 | ul.nav.nav-tabs { 26 | overflow: hidden; 27 | } 28 | 29 | .button { 30 | width: 25%; 31 | font: bold 16px Arial; 32 | text-decoration: none; 33 | background-color: #E21318; 34 | color: #FFFFFF; 35 | margin: 5px; 36 | padding: 10px 14px 10px 14px; 37 | border-top: 1px solid #A3070B; 38 | border-right: 2px solid #A3070B; 39 | border-bottom: 2px solid #A3070B; 40 | border-left: 1px solid #A3070B; 41 | border-radius: 4px; 42 | } 43 | 44 | .divButton{ 45 | display: block; 46 | margin-left: 24%; 47 | margin-right: auto; 48 | width: 100%; 49 | } 50 | 51 | a:link, a:visited { 52 | color: #E21318; 53 | } 54 | 55 | a:hover, a:active { 56 | color: #A3070B; 57 | } 58 | 59 | /***************************************/ 60 | /***** flipcard settings *****/ 61 | /***************************************/ 62 | .flip-card { 63 | background-color: transparent; 64 | width: 150px; 65 | height: 150px; 66 | perspective: 1000px; /* required for 3D effect */ 67 | } 68 | 69 | /* This container is needed to position the front and back side */ 70 | .flip-card-inner { 71 | position: relative; 72 | width: 100%; 73 | height: 100%; 74 | text-align: center; 75 | transition: transform 0.8s; 76 | transform-style: preserve-3d; 77 | } 78 | 79 | /* Do an horizontal flip when you move the mouse over the flip box container */ 80 | .flip-card:hover .flip-card-inner { 81 | transform: rotateY(180deg); 82 | } 83 | 84 | /* Position the front and back side */ 85 | .flip-card-front, .flip-card-back { 86 | position: absolute; 87 | width: 100%; 88 | height: 100%; 89 | display: flex; 90 | justify-content: center; 91 | align-items: center; 92 | -webkit-backface-visibility: hidden; /* Safari */ 93 | backface-visibility: hidden; 94 | } 95 | 96 | /* Style the front side (fallback if image is missing) */ 97 | .flip-card-front { 98 | background-color: white; 99 | color: black; 100 | } 101 | 102 | /* Style the back side */ 103 | .flip-card-back { 104 | background-color: #A3070B; 105 | color: white; 106 | transform: rotateY(180deg); 107 | } 108 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_02/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: FDA Table 02 3 | subtitle: Baseline Demographic and Clinical Characteristics, Safety Population, Pooled Analyses 4 | categories: [table, FDA, safety, demographics] 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='60%'} 11 | knitr::include_graphics("result.png") 12 | ``` 13 | 14 | ## Setup 15 | 16 | ```{r setup, message=FALSE} 17 | # Load libraries & data ------------------------------------- 18 | library(dplyr) 19 | library(gtsummary) 20 | 21 | adsl <- random.cdisc.data::cadsl |> 22 | mutate( 23 | AGEGR1 = factor( 24 | dplyr::case_when( 25 | AGE >= 17 & AGE < 65 ~ ">=17 to <65", 26 | AGE >= 65 & AGE < 75 ~ "65-74", 27 | AGE >= 75 ~ ">=75" 28 | ), 29 | levels = c(">=17 to <65", "65-74", ">=75") 30 | ) 31 | ) 32 | 33 | # Pre-processing -------------------------------------------- 34 | # Filter for the safety population, x 35 | data <- adsl |> 36 | filter(SAFFL == "Y") 37 | ``` 38 | 39 | ## Build Table 40 | 41 | ```{r tbl, results='hide'} 42 | tbl <- data |> 43 | tbl_summary( 44 | by = "ARM", 45 | include = c("SEX", "AGE", "AGEGR1", "ETHNIC", "RACE", "BMRKR1", "BMRKR2"), 46 | type = all_continuous() ~ "continuous2", # arranges statistics into multiple lines 47 | statistic = list( 48 | all_continuous() ~ c( 49 | "{mean} ({sd})", 50 | "{median} ({min}, {max})" 51 | ), 52 | all_categorical() ~ "{n} ({p}%)" 53 | ), 54 | label = list(AGEGR1 = "Age Group, Years") 55 | ) |> 56 | add_overall(last = TRUE, col_label = "**Total Population** \nN = {N}") |> 57 | # remove default footnote 58 | gtsummary::remove_footnote_header(columns = everything()) 59 | ``` 60 | 61 | ```{r eval=FALSE, include=FALSE} 62 | # Run chunk locally to generate image file 63 | gt::gtsave(as_gt(tbl), filename = "result.png") 64 | ``` 65 | 66 | ```{r img, echo=FALSE, fig.align='center', out.width='60%'} 67 | ``` 68 | 69 | ## Build ARD 70 | 71 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 72 | ard <- gather_ard(tbl) 73 | ard 74 | ``` 75 | 76 | ```{r, echo=FALSE} 77 | # Print full ARD 78 | withr::local_options(width = 9999) 79 | print(ard, columns = "all") 80 | ``` 81 | ::: 82 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_02/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_02/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_05/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_05/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_06/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_06/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_11/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: FDA Table 11 3 | subtitle: Patients with FDA Medical Query (Narrow) Leading to Treatment Discontinuation, Safety Population, Pooled Analyses 4 | categories: [table, FDA, safety] 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='60%'} 11 | knitr::include_graphics("result.png") 12 | ``` 13 | 14 | ## Setup 15 | 16 | ```{r setup, message=FALSE} 17 | # Load libraries & data ------------------------------------- 18 | library(dplyr) 19 | library(cards) 20 | library(gtsummary) 21 | 22 | set.seed(1) 23 | adsl <- random.cdisc.data::cadsl 24 | adae <- random.cdisc.data::cadae %>% 25 | rename(FMQ01SC = SMQ01SC) %>% 26 | mutate( 27 | AESER = sample(c("Y", "N"), size = nrow(.), replace = TRUE), 28 | FMQ01NAM = sample(c("FMQ1", "FMQ2", "FMQ3"), size = nrow(.), replace = TRUE) 29 | ) 30 | adae$DCSREAS[is.na(adae$DCSREAS)] <- "ADVERSE EVENT" 31 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 32 | 33 | # Pre-processing -------------------------------------------- 34 | adsl <- adsl %>% 35 | filter(SAFFL == "Y") # safety population 36 | 37 | data <- adae %>% 38 | filter( 39 | # safety population 40 | SAFFL == "Y", 41 | # narrow FMQ 42 | FMQ01SC == "NARROW", 43 | # discontinuation due to AE 44 | DCSREAS == "ADVERSE EVENT" 45 | ) 46 | ``` 47 | 48 | ## Build ARD 49 | 50 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 51 | ard <- ard_stack_hierarchical( 52 | data, 53 | variables = c(AEBODSYS, FMQ01NAM), 54 | by = TRT01A, 55 | denominator = adsl, 56 | id = USUBJID 57 | ) 58 | 59 | ard 60 | ``` 61 | 62 | ```{r, echo=FALSE} 63 | # Print ARD 64 | withr::local_options(width = 9999) 65 | print(ard, columns = "all", n = 40) 66 | ``` 67 | 68 | ## Build Table 69 | 70 | ```{r tbl, results = 'hide'} 71 | tbl <- tbl_hierarchical( 72 | data, 73 | variables = c(AEBODSYS, FMQ01NAM), 74 | by = TRT01A, 75 | id = USUBJID, 76 | denominator = adsl, 77 | overall_row = TRUE, 78 | label = list(..ard_hierarchical_overall.. = "Patients with at least one AE leading to discontinuation") 79 | ) %>% 80 | modify_header(FMQ01NAM = "FMQ (Narrow)") 81 | 82 | tbl 83 | ``` 84 | 85 | ```{r eval=FALSE, include=FALSE} 86 | # Run chunk locally to generate image file 87 | gt::gtsave(as_gt(tbl), filename = "result.png") 88 | ``` 89 | 90 | ```{r img, echo=FALSE, fig.align='center', out.width='60%'} 91 | ``` 92 | ::: 93 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_11/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_11/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_12/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: FDA Table 12 3 | subtitle: Patients With Adverse Events Leading to Treatment Discontinuation by System Organ Class and Preferred Term, Safety Population, Pooled Analyses 4 | categories: [table, FDA, safety] 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='70%'} 11 | knitr::include_graphics("result.png") 12 | ``` 13 | 14 | ## Setup 15 | 16 | ```{r setup, message=FALSE} 17 | # Load libraries & data ------------------------------------- 18 | library(dplyr) 19 | library(cards) 20 | library(gtsummary) 21 | 22 | adsl <- random.cdisc.data::cadsl 23 | adae <- random.cdisc.data::cadae 24 | adae$DCSREAS[is.na(adae$DCSREAS)] <- "ADVERSE EVENT" 25 | 26 | # Pre-processing -------------------------------------------- 27 | adsl <- adsl %>% 28 | filter(SAFFL == "Y") # safety population 29 | 30 | data <- adae %>% 31 | filter( 32 | # safety population 33 | SAFFL == "Y", 34 | # discontinuation due to AE 35 | DCSREAS == "ADVERSE EVENT" 36 | ) 37 | ``` 38 | 39 | ## Build ARD 40 | 41 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 42 | ard <- ard_stack_hierarchical( 43 | data, 44 | variables = c(AEBODSYS, AEDECOD), 45 | by = TRT01A, 46 | denominator = adsl, 47 | id = USUBJID 48 | ) 49 | 50 | ard 51 | ``` 52 | 53 | ```{r, echo=FALSE} 54 | # Print ARD 55 | withr::local_options(width = 9999) 56 | print(ard, columns = "all", n = 40) 57 | ``` 58 | 59 | ## Build Table 60 | 61 | ```{r tbl, results = 'hide'} 62 | tbl <- tbl_hierarchical( 63 | data, 64 | variables = c(AEBODSYS, AEDECOD), 65 | by = TRT01A, 66 | id = USUBJID, 67 | denominator = adsl, 68 | overall_row = TRUE, 69 | label = list(..ard_hierarchical_overall.. = "Patients with at least one AE leading to discontinuation") 70 | ) 71 | 72 | tbl 73 | ``` 74 | 75 | ```{r eval=FALSE, include=FALSE} 76 | # Run chunk locally to generate image file 77 | gt::gtsave(as_gt(tbl), filename = "result.png") 78 | ``` 79 | 80 | ```{r img, echo=FALSE, fig.align='center', out.width='70%'} 81 | ``` 82 | ::: 83 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_12/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_12/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_32/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: FDA Table 32 3 | subtitle: Percentage of Patients With Maximum Diastolic Blood Pressure by Category of Blood Pressure Postbaseline, Safety Population, Pooled Analysis 4 | categories: [table, FDA, safety, vital signs] 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 11 | knitr::include_graphics("result.png") 12 | ``` 13 | 14 | ## Setup 15 | 16 | ```{r setup, message=FALSE} 17 | # Load libraries & data ------------------------------------- 18 | library(dplyr) 19 | library(cards) 20 | library(gtsummary) 21 | 22 | adsl <- random.cdisc.data::cadsl 23 | advs <- random.cdisc.data::cadvs 24 | 25 | # Pre-processing -------------------------------------------- 26 | adsl <- adsl |> 27 | filter(SAFFL == "Y") # safety population 28 | 29 | data <- advs |> 30 | filter( 31 | # safety population 32 | SAFFL == "Y", 33 | # diastolic blood pressure 34 | PARAMCD == "DIABP", 35 | # post-baseline visits 36 | AVISITN >= 1 37 | ) |> 38 | # analyze maximum values of each subject 39 | slice_max(AVAL, n = 1L, by = USUBJID) |> 40 | # define analysis value cutoffs 41 | mutate( 42 | L60 = AVAL < 60, # DIABP <60 43 | G60 = AVAL > 60, # DIABP >60 44 | G90 = AVAL > 90, # DIABP >90 45 | G110 = AVAL > 110, # DIABP >110 46 | GE120 = AVAL >= 120 # DIABP >=120 47 | ) 48 | ``` 49 | 50 | ## Build ARD 51 | 52 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 53 | ard <- bind_ard( 54 | ard_dichotomous( 55 | data, 56 | variables = c(L60, G60, G90, G110, GE120), 57 | by = TRT01A, 58 | statistic = ~ c("n", "p"), 59 | denominator = adsl 60 | ), 61 | # ARD for header N values 62 | ard_categorical(adsl, variables = TRT01A) 63 | ) 64 | 65 | ard 66 | ``` 67 | 68 | ```{r, echo=FALSE} 69 | # Print ARD 70 | withr::local_options(width = 9999) 71 | print(ard, columns = "all", n = 40) 72 | ``` 73 | 74 | ## Build Table 75 | 76 | ```{r tbl, results = 'hide'} 77 | tbl <- tbl_ard_summary( 78 | ard, 79 | by = TRT01A, 80 | # Add labels for each range 81 | label = list( 82 | L60 = "<60", 83 | G60 = ">60", 84 | G90 = ">90", 85 | G110 = ">110", 86 | GE120 = ">=120" 87 | ) 88 | ) |> 89 | modify_header( 90 | # Update label, add analysis value units 91 | label ~ paste0("**Diastolic Blood Pressure \n(", data$AVALU[1], ")**"), 92 | # Add N values to `by` variable labels 93 | all_stat_cols() ~ "**{level}** \nN = {n}" 94 | ) 95 | 96 | tbl 97 | ``` 98 | 99 | ```{r eval=FALSE, include=FALSE} 100 | gt::gtsave(as_gt(tbl), filename = "result.png") 101 | ``` 102 | 103 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 104 | ``` 105 | ::: 106 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_32/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_32/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_33/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: FDA Table 33 3 | subtitle: Percentage of Patients Meeting Specific Hypotension Levels Postbaseline, Safety Population, Pooled Analysis 4 | categories: [table, FDA, safety, vital signs] 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='40%'} 11 | knitr::include_graphics("result.png") 12 | ``` 13 | 14 | ## Setup 15 | 16 | ```{r setup, message=FALSE} 17 | # Load libraries & data ------------------------------------- 18 | library(dplyr) 19 | library(cards) 20 | library(gtsummary) 21 | 22 | adsl <- random.cdisc.data::cadsl 23 | advs <- random.cdisc.data::cadvs 24 | 25 | # Pre-processing -------------------------------------------- 26 | adsl <- adsl |> 27 | filter(SAFFL == "Y") # safety population 28 | 29 | data <- advs |> 30 | filter( 31 | # safety population 32 | SAFFL == "Y", 33 | # diastolic & systolic blood pressure 34 | PARAMCD %in% c("DIABP", "SYSBP"), 35 | # post-baseline visits 36 | AVISITN >= 1 37 | ) |> 38 | # analyze minimum values per parameter of each subject 39 | slice_min(AVAL, n = 1L, by = c(USUBJID, PARAMCD)) |> 40 | # define analysis value cutoffs per parameter 41 | mutate( 42 | SBP90 = PARAMCD == "SYSBP" & AVAL < 90, # SYSBP <90 43 | DBP60 = PARAMCD == "DIABP" & AVAL < 60 # DIABP <60 44 | ) 45 | ``` 46 | 47 | ## Build ARD 48 | 49 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 50 | ard <- bind_ard( 51 | ard_dichotomous( 52 | data, 53 | variables = c(SBP90, DBP60), 54 | by = TRT01A, 55 | statistic = ~ c("n", "p"), 56 | denominator = adsl 57 | ), 58 | # ARD for header N values 59 | ard_categorical(adsl, variables = TRT01A) 60 | ) 61 | 62 | ard 63 | ``` 64 | 65 | ```{r, echo=FALSE} 66 | # Print ARD 67 | withr::local_options(width = 9999) 68 | print(ard, columns = "all", n = 40) 69 | ``` 70 | 71 | ## Build Table 72 | 73 | ```{r tbl, results = 'hide'} 74 | tbl <- tbl_ard_summary( 75 | ard, 76 | by = TRT01A, 77 | # Add labels for each range 78 | label = list( 79 | SBP90 = "SBP<90", 80 | DBP60 = "DBP<60" 81 | ) 82 | ) |> 83 | modify_header( 84 | # Update label, add analysis value units 85 | label ~ paste0("**Blood Pressure \n(", data$AVALU[1], ")**"), 86 | # Add N values to `by` variable labels 87 | all_stat_cols() ~ "**{level}** \nN = {n}" 88 | ) 89 | 90 | tbl 91 | ``` 92 | 93 | ```{r eval=FALSE, include=FALSE} 94 | gt::gtsave(as_gt(tbl), filename = "result.png") 95 | ``` 96 | 97 | ```{r img, echo=FALSE, fig.align='center', out.width='40%'} 98 | ``` 99 | ::: 100 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_33/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_33/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_34/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: FDA Table 34 3 | subtitle: Patients With Serious Adverse Events by System Organ Class, FDA Medical Query (Narrow) and Preferred Term, Safety Population, Pooled Analysis (or Trial X) 4 | categories: [table, FDA, safety, adverse events] 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 11 | knitr::include_graphics("result.png") 12 | ``` 13 | 14 | ## Setup 15 | 16 | ```{r setup, message=FALSE} 17 | # Load libraries & data ------------------------------------- 18 | library(dplyr) 19 | library(cards) 20 | library(gtsummary) 21 | 22 | adae <- random.cdisc.data::cadae 23 | adsl <- random.cdisc.data::cadsl 24 | 25 | set.seed(1) 26 | adae <- adae %>% 27 | rename(FMQ01SC = SMQ01SC) %>% 28 | mutate( 29 | AESER = sample(c("Y", "N"), size = nrow(adae), replace = TRUE), 30 | FMQ01NAM = sample(c("FMQ1", "FMQ2", "FMQ3"), size = nrow(adae), replace = TRUE) 31 | ) 32 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 33 | 34 | # Pre-processing -------------------------------------------- 35 | adsl <- adsl |> 36 | filter(SAFFL == "Y") # safety population 37 | 38 | data <- adae |> 39 | filter( 40 | # safety population 41 | SAFFL == "Y", 42 | # serious AEs 43 | AESER == "Y", 44 | # treatment-emergent 45 | TRTEMFL == "Y", 46 | # narrow FMQ scope 47 | FMQ01SC == "NARROW" 48 | ) 49 | ``` 50 | 51 | ## Build ARD 52 | 53 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 54 | ard <- ard_stack_hierarchical( 55 | data, 56 | variables = c(AEBODSYS, FMQ01NAM, AEDECOD), 57 | by = ARM, 58 | id = USUBJID, 59 | denominator = adsl, 60 | # variables to include AE rates for 61 | include = c(FMQ01NAM, AEDECOD) 62 | ) 63 | 64 | ard 65 | ``` 66 | 67 | ```{r, echo=FALSE} 68 | # Print ARD 69 | withr::local_options(width = 9999) 70 | print(ard, columns = "all", n = 40) 71 | ``` 72 | 73 | ## Build Table 74 | 75 | ```{r tbl, results = 'hide'} 76 | # create table using ARD-first approach (ARD -> table) 77 | tbl <- 78 | tbl_ard_hierarchical( 79 | ard, 80 | variables = c(AEBODSYS, FMQ01NAM, AEDECOD), 81 | by = ARM, 82 | # variables to display AE rates for 83 | include = c(FMQ01NAM, AEDECOD), 84 | # add custom variable labels 85 | label = list( 86 | AEBODSYS = "Body System or Organ Class", 87 | FMQ01NAM = "FMQ (Narrow)", 88 | AEDECOD = "Dictionary-Derived Term" 89 | ) 90 | ) 91 | 92 | tbl 93 | ``` 94 | 95 | ```{r eval=FALSE, include=FALSE} 96 | gt::gtsave(as_gt(tbl), filename = "result.png") 97 | ``` 98 | 99 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 100 | ``` 101 | ::: 102 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_34/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_34/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_35/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: FDA Table 35 3 | subtitle: Patients With Adverse Events by System Organ Class, Safety Population, Pooled Analysis (or Trial X) 4 | categories: [table, FDA, safety, adverse events] 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 11 | knitr::include_graphics("result.png") 12 | ``` 13 | 14 | ## Setup 15 | 16 | ```{r setup, message=FALSE} 17 | # Load libraries & data ------------------------------------- 18 | library(dplyr) 19 | library(cards) 20 | library(gtsummary) 21 | 22 | adsl <- random.cdisc.data::cadsl 23 | adae <- random.cdisc.data::cadae 24 | 25 | # Pre-processing -------------------------------------------- 26 | adsl <- adsl %>% 27 | filter(SAFFL == "Y") # safety population 28 | 29 | data <- adae |> 30 | filter(SAFFL == "Y") # safety population 31 | ``` 32 | 33 | ## Build Table 34 | 35 | ```{r tbl, results = 'hide'} 36 | tbl <- tbl_hierarchical( 37 | data = data, 38 | variables = AEBODSYS, # specify SOC variable 39 | by = TRT01A, 40 | id = USUBJID, 41 | denominator = adsl, 42 | label = AEBODSYS ~ "**System Organ Class**" # update variable label 43 | ) 44 | 45 | tbl 46 | ``` 47 | 48 | ```{r eval=FALSE, include=FALSE} 49 | gt::gtsave(as_gt(tbl), filename = "result.png") 50 | ``` 51 | 52 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 53 | ``` 54 | 55 | ## Build ARD 56 | 57 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 58 | # Extract ARD from table 59 | ard <- gather_ard(tbl)[[1]] 60 | 61 | ard 62 | ``` 63 | 64 | ```{r, echo=FALSE} 65 | # Print ARD 66 | withr::local_options(width = 9999) 67 | print(ard, columns = "all", n = 40) 68 | ``` 69 | ::: 70 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_35/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_35/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_36/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: FDA Table 36 3 | subtitle: Patients With Adverse Events by System Organ Class and Preferred Term, Safety Population, Pooled Analysis (or Trial X) 4 | categories: [table, FDA, safety, adverse events] 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 11 | knitr::include_graphics("result.png") 12 | ``` 13 | 14 | ## Setup 15 | 16 | ```{r setup, message=FALSE} 17 | # Load libraries & data ------------------------------------- 18 | library(dplyr) 19 | library(cards) 20 | library(gtsummary) 21 | 22 | adae <- random.cdisc.data::cadae 23 | adsl <- random.cdisc.data::cadsl 24 | 25 | # Pre-processing -------------------------------------------- 26 | adsl <- adsl |> 27 | filter(SAFFL == "Y") # safety population 28 | 29 | data <- adae |> 30 | filter(SAFFL == "Y") # safety population 31 | ``` 32 | 33 | ## Build ARD 34 | 35 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 36 | ard <- ard_stack_hierarchical( 37 | data, 38 | variables = c(AESOC, AEDECOD), 39 | by = ARM, 40 | id = USUBJID, 41 | denominator = adsl 42 | ) 43 | 44 | ard 45 | ``` 46 | 47 | ```{r, echo=FALSE} 48 | # Print ARD 49 | withr::local_options(width = 9999) 50 | print(ard, columns = "all", n = 40) 51 | ``` 52 | 53 | ## Build Table 54 | 55 | ```{r tbl, results = 'hide'} 56 | # create table using ARD-first approach (ARD -> table) 57 | tbl <- 58 | tbl_ard_hierarchical( 59 | ard, 60 | variables = c(AESOC, AEDECOD), 61 | by = ARM, 62 | # add custom variable labels 63 | label = list( 64 | AESOC = "System Organ Class", 65 | AEDECOD = "Preferred Term" 66 | ) 67 | ) 68 | 69 | tbl 70 | ``` 71 | 72 | ```{r eval=FALSE, include=FALSE} 73 | gt::gtsave(as_gt(tbl), filename = "result.png") 74 | ``` 75 | 76 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 77 | ``` 78 | ::: 79 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_36/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_36/result.png -------------------------------------------------------------------------------- /quarto/catalog/fda-table_38/index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: FDA Table 38 3 | subtitle: Patients With Adverse Events by System Organ Class, FDA Medical Query (Broad) and Preferred Term, Safety Population, Pooled Analysis (or Trial X) 4 | categories: [table, FDA, safety, adverse events] 5 | --- 6 | 7 | ::: panel-tabset 8 | ## Table Preview 9 | 10 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 11 | knitr::include_graphics("result.png") 12 | ``` 13 | 14 | ## Setup 15 | 16 | ```{r setup, message=FALSE} 17 | # Load libraries & data ------------------------------------- 18 | library(dplyr) 19 | library(cards) 20 | library(gtsummary) 21 | 22 | adae <- random.cdisc.data::cadae 23 | adsl <- random.cdisc.data::cadsl 24 | 25 | set.seed(1) 26 | adae <- adae %>% 27 | rename(FMQ01SC = SMQ01SC) %>% 28 | mutate( 29 | AESER = sample(c("Y", "N"), size = nrow(adae), replace = TRUE), 30 | FMQ01NAM = sample(c("FMQ1", "FMQ2", "FMQ3"), size = nrow(adae), replace = TRUE) 31 | ) 32 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "BROAD" 33 | 34 | # Pre-processing -------------------------------------------- 35 | adsl <- adsl |> 36 | filter(SAFFL == "Y") # safety population 37 | 38 | data <- adae |> 39 | filter( 40 | # safety population 41 | SAFFL == "Y", 42 | # treatment-emergent 43 | TRTEMFL == "Y", 44 | # broad FMQ scope 45 | FMQ01SC == "BROAD" 46 | ) 47 | ``` 48 | 49 | ## Build ARD 50 | 51 | ```{r ard, message=FALSE, warning=FALSE, results='hide'} 52 | ard <- ard_stack_hierarchical( 53 | data, 54 | variables = c(AEBODSYS, FMQ01NAM, AEDECOD), 55 | by = ARM, 56 | id = USUBJID, 57 | denominator = adsl, 58 | # variables to include AE rates for 59 | include = c(FMQ01NAM, AEDECOD) 60 | ) 61 | 62 | ard 63 | ``` 64 | 65 | ```{r, echo=FALSE} 66 | # Print ARD 67 | withr::local_options(width = 9999) 68 | print(ard, columns = "all", n = 40) 69 | ``` 70 | 71 | ## Build Table 72 | 73 | ```{r tbl, results = 'hide'} 74 | # create table using ARD-first approach (ARD -> table) 75 | tbl <- 76 | tbl_ard_hierarchical( 77 | ard, 78 | variables = c(AEBODSYS, FMQ01NAM, AEDECOD), 79 | by = ARM, 80 | # variables to display AE rates for 81 | include = c(FMQ01NAM, AEDECOD), 82 | # Add custom variable labels 83 | label = list( 84 | AEBODSYS = "Body System or Organ Class", 85 | FMQ01NAM = "FMQ (Broad)", 86 | AEDECOD = "Dictionary-Derived Term" 87 | ) 88 | ) 89 | 90 | tbl 91 | ``` 92 | 93 | ```{r eval=FALSE, include=FALSE} 94 | gt::gtsave(as_gt(tbl), filename = "result.png") 95 | ``` 96 | 97 | ```{r img, echo=FALSE, fig.align='center', out.width='45%'} 98 | ``` 99 | ::: 100 | -------------------------------------------------------------------------------- /quarto/catalog/fda-table_38/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pharmaverse/cardinal/8d21ef65cb50db81fd228d6b01c951c2630dfde7/quarto/catalog/fda-table_38/result.png -------------------------------------------------------------------------------- /quarto/faq.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: Frequently Asked Questions 3 | format: 4 | html: 5 | toc: true 6 | toc-location: body 7 | toc-depth: 4 8 | toc-title: " " 9 | --- 10 | 11 | ------------------------------------------------------------------------ 12 | 13 | #### 1. \ How do I install the cardinal package? 14 | 15 | For instructions on installing the cardinal package please see the [Environment Setup and Package Installation](https://pharmaverse.github.io/cardinal/quarto/getting_started.html#environment-setup-and-package-installation) section of the Getting Started page. 16 | <br/><br/> 17 | 18 | 19 | #### 2. \ How can I join this initiative? 20 | 21 | For information on how to join the cardinal initiative please see the [Joining as a Collaborator](https://pharmaverse.github.io/cardinal/quarto/about.html#joining-as-a-collaborator) section of the About page. 22 | <br/><br/> 23 | 24 | 25 | #### 3. \ I copied the example "Table Setup" code for one of the cardinal tables. How can I customize the table? 26 | 27 | For each table template page, next to the "Table Setup" tab is the "Function Details" tab. This tab contains information about each of the customizable parameters available for the table, and what the default settings for each are. If you require a customization option that is not available for a given table, please file a Feature Request issue on GitHub [here](https://github.com/pharmaverse/cardinal/issues/new/choose). 28 | <br/><br/> 29 | 30 | 31 | #### 4. \ I need a table that isn't available on the cardinal website. Can I request a table be added? 32 | 33 | The cardinal team is actively maintaining and adding new table functions to the package. If you would like an FDA safety table that is not listed on the cardinal website, please file a New Table Template issue on GitHub [here](https://github.com/pharmaverse/cardinal/issues/new/choose) with the table number and the team will work on adding it to the package. 34 | <br/><br/> 35 | 36 | 37 | #### 5. \ I don't know the number of the FDA safety table I am interested in. Is there a list of tables by title? 38 | 39 | A list of all available tables by title is available on the [Template Catalog](index-catalog.qmd) page. 40 | <br/><br/> 41 | 42 | 43 | ------------------------------------------------------------------------ 44 | 45 | 46 | #### Other Questions - Contact Us 47 | 48 | If you have questions not listed above please contact us by filing an issue on GitHub [here](https://github.com/pharmaverse/cardinal/issues/new/choose) or reaching out to the cardinal team directly via our Slack channel [here](https://app.slack.com/client/T028PB489D3/C04MQS12MND). 49 | -------------------------------------------------------------------------------- /quarto/getting_started.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Getting Started" 3 | toc: true 4 | toc-depth: 4 5 | --- 6 | 7 | ### Environment Setup and Package Installation 8 | 9 | #### Environment Setup 10 | 11 | Please ensure that R version 3.6 or higher is installed on your computer. This is required to install the `cardinal` package and its dependencies. You can check your current version of R by running `sessionInfo()` within the R console. 12 | 13 | #### Installing Package Dependencies 14 | 15 | The `cardinal` package requires several packages available on CRAN. 16 | 17 | To use the `cardinal` package, ensure you have these necessary package dependencies installed by running the following code: 18 | 19 | ```{r, echo=TRUE, eval=FALSE} 20 | if (!require("gtsummary")) install.packages("gtsummary") 21 | if (!require("cards")) install.packages("cards") 22 | if (!require("cardx")) install.packages("cardx") 23 | if (!require("formatters")) install.packages("formatters") 24 | if (!require("rtables")) install.packages("rtables") 25 | if (!require("rlistings")) install.packages("rlistings") 26 | if (!require("tern")) install.packages("tern") 27 | ``` 28 | 29 | Optionally, to run the examples provided within the `cardinal` package and on this site you can also install the random CDISC data package, which contains example datasets, by running the following: 30 | 31 | ```{r, echo=TRUE, eval=FALSE} 32 | if (!require("random.cdisc.data")) install.packages("random.cdisc.data") 33 | ``` 34 | 35 | For more information on these packages, see the [Additional Resources](#additional-resources) section below. 36 | 37 | #### Installing the cardinal Package 38 | 39 | To install the `cardinal` package, run the following line of code: 40 | 41 | ```{r, echo=TRUE, eval=FALSE} 42 | if (!require("cardinal")) remotes::install_github("pharmaverse/cardinal") 43 | ``` 44 | 45 | ### Loading Data 46 | 47 | The table functions provided by `cardinal` are designed to work with any datasets which adhere to CDISC standards. If you have access to CDISC data, load this into your R environment as usual to use when generating tables. 48 | 49 | If you do not have access to CDISC data, or want to run the examples provided within the package, you can use the `random.cdisc.data` package to load a selection of datasets containing example synthetic randomized CDISC data. Datasets are stored in the package by name, prefixed by the letter `"c"` (for "cached"). For example, after loading the `random.cdisc.data` package you can access an ADSL dataset by running `cadsl`, or ADAE with `cadae`. This data is loaded in where necessary as part of the provided examples. 50 | 51 | ### Template Navigation 52 | 53 | A list of all templates currently available in `cardinal` is provided in the [Template Catalog](index-catalog.qmd), with tables designed based on the [FDA Standard Safety Tables and Figures: Integrated Guide](https://downloads.regulations.gov/FDA-2022-N-1961-0046/attachment_1.pdf). 54 | 55 | ### Feature Requests 56 | 57 | If you would like to request the addition of a new feature to a pre-existing function within `cardinal`, or would like a specific table template to be added, please file an issue on GitHub [here](https://github.com/pharmaverse/cardinal/issues) or reach out to the cardinal team directly via our Slack channel [here](https://app.slack.com/client/T028PB489D3/C04MQS12MND). 58 | 59 | You can access the source code for all currently available functions in the `cardinal` GitHub repository [here](https://github.com/pharmaverse/cardinal/tree/main/R). 60 | 61 | ### Additional Resources {#additional-resources} 62 | 63 | See the following packages used by `cardinal` for more information: 64 | 65 | - [`tern`](https://insightsengineering.github.io/tern): Clinical trials analysis functions 66 | - [`rtables`](https://insightsengineering.github.io/rtables): Table creation 67 | - [`rlistings`](https://insightsengineering.github.io/rlistings): Listing creation 68 | - [`formatters`](https://insightsengineering.github.io/formatters): Additional rendering formatting 69 | - [`random.cdisc.data`](https://insightsengineering.github.io/random.cdisc.data): Example synthetic randomized CDISC datasets (required for examples only) 70 | -------------------------------------------------------------------------------- /quarto/index-catalog.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Template Catalog" 3 | listing: 4 | contents: "catalog/*/index.qmd" 5 | type: grid 6 | image-placeholder: assets/images/image-placeholder.png 7 | categories: true 8 | fields: [image, title, subtitle, categories] 9 | sort-ui: [title] 10 | filter-ui: [title, subtitle, categories] 11 | title-block-banner: true 12 | --- 13 | 14 | -------------------------------------------------------------------------------- /quarto/resources.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: Resources 3 | --- 4 | 5 | #### FDA Standard Safety Tables and Figures: Integrated Guide 6 | 7 | Click [here](assets/resources/FDA-STF-IG-2022-N-1961-0002.pdf) to download. 8 | 9 | --- 10 | 11 | #### Past Talks & Presentations 12 | 13 | ##### PHUSE EU Connect Presentation 14 | 15 | - Date: November 6, 2023 16 | - Click [here](assets/resources/cardinal_PHUSE_EU_2023.pptx) to download the presentation slide deck. 17 | 18 | ##### R/Pharma Online Workshop 19 | 20 | - Date: October 20, 2023 21 | - Click [here](assets/resources/cardinal_RinPharma_Workshop_2023.pptx) to download the workshop slide deck. 22 | -------------------------------------------------------------------------------- /staged_dependencies.yaml: -------------------------------------------------------------------------------- 1 | current_repo: 2 | repo: pharmaverse/cardinal 3 | host: https://github.com 4 | upstream_repos: 5 | downstream_repos: 6 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | 3 | pkg_name <- "cardinal" 4 | library(pkg_name, character.only = TRUE) 5 | testthat::test_check(pkg_name) 6 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/fda-table_03.md: -------------------------------------------------------------------------------- 1 | # Table 3 generation works with default values 2 | 3 | Code 4 | res 5 | Output 6 | Disposition A: Drug X B: Placebo C: Combination 7 | —————————————————————————————————————————————————————————————————————————————————— 8 | Patients screened 134 134 132 9 | Screening failures 42 (31.3%) 32 (23.9%) 26 (19.7%) 10 | Inclusion/exclusion criteria not met 6 (4.5%) 10 (7.5%) 10 (7.6%) 11 | Patient noncompliance 12 (9.0%) 2 (1.5%) 6 (4.5%) 12 | Consent withdrawn 13 (9.7%) 12 (9.0%) 5 (3.8%) 13 | Other 11 (8.2%) 8 (6.0%) 5 (3.8%) 14 | Patients enrolled 92 (68.7%) 102 (76.1%) 106 (80.3%) 15 | Patients randomized 92 (68.7%) 102 (76.1%) 106 (80.3%) 16 | 17 | # Table 3 generation works with custom values 18 | 19 | Code 20 | res 21 | Output 22 | Table 3. Patients Screening and Enrollment, Trials A and B 23 | 24 | ———————————————————————————————————————————————————————————————————————————————————————————————— 25 | Total 26 | A: Drug X B: Placebo C: Combination Population 27 | Disposition (N=134) (N=134) (N=132) (N=400) 28 | ———————————————————————————————————————————————————————————————————————————————————————————————— 29 | Patients screened 134 134 132 400 30 | Screening failures 42 (31.3%) 32 (23.9%) 26 (19.7%) 100 (25.0%) 31 | Inclusion/exclusion criteria not met 6 (4.5%) 10 (7.5%) 10 (7.6%) 26 (6.5%) 32 | Patient noncompliance 12 (9.0%) 2 (1.5%) 6 (4.5%) 20 (5.0%) 33 | Consent withdrawn 13 (9.7%) 12 (9.0%) 5 (3.8%) 30 (7.5%) 34 | Other 11 (8.2%) 8 (6.0%) 5 (3.8%) 24 (6.0%) 35 | Patients enrolled 92 (68.7%) 102 (76.1%) 106 (80.3%) 300 (75.0%) 36 | Patients randomized 92 (68.7%) 102 (76.1%) 106 (80.3%) 300 (75.0%) 37 | ———————————————————————————————————————————————————————————————————————————————————————————————— 38 | 39 | Source: [include Applicant source, datasets and/or software tools used]. 40 | 41 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/fda-table_04.md: -------------------------------------------------------------------------------- 1 | # Table 04 generation works with default values 2 | 3 | Code 4 | res 5 | Output 6 | A: Drug X B: Placebo C: Combination 7 | (N=134) (N=134) (N=132) 8 | —————————————————————————————————————————————————————————————————— 9 | Safety population 134 (100%) 134 (100%) 132 (100%) 10 | Discontinued study drug 42 (31.3%) 40 (29.9%) 38 (28.8%) 11 | Adverse event 3 (2.2%) 6 (4.5%) 5 (3.8%) 12 | Lack of efficacy 2 (1.5%) 2 (1.5%) 3 (2.3%) 13 | Protocol deviation 0 0 0 14 | Death 25 (18.7%) 23 (17.2%) 22 (16.7%) 15 | Withdrawal by subject 0 0 0 16 | Other 3 (2.2%) 4 (3.0%) 3 (2.3%) 17 | Discontinued study 42 (31.3%) 40 (29.9%) 38 (28.8%) 18 | Death 25 (18.7%) 23 (17.2%) 22 (16.7%) 19 | Lost to follow-up 0 0 0 20 | Withdrawal by subject 0 0 0 21 | Physician decision 0 0 0 22 | Protocol deviation 5 (3.7%) 3 (2.2%) 4 (3.0%) 23 | Other 3 (2.2%) 4 (3.0%) 3 (2.3%) 24 | 25 | # Table 04 generation works with custom values 26 | 27 | Code 28 | res 29 | Output 30 | Patient Disposition, Pooled Analyses (1,2) 31 | 32 | —————————————————————————————————————————————————————————————————— 33 | A: Drug X B: Placebo C: Combination 34 | (N=134) (N=134) (N=132) 35 | —————————————————————————————————————————————————————————————————— 36 | Patients randomized 58 (43.3%) 62 (46.3%) 72 (54.5%) 37 | ITT/mITT population 134 (100%) 134 (100%) 132 (100%) 38 | Safety population 134 (100%) 134 (100%) 132 (100%) 39 | Per-protocol population 58 (43.3%) 62 (46.3%) 72 (54.5%) 40 | Discontinued study drug 42 (31.3%) 40 (29.9%) 38 (28.8%) 41 | Adverse event 3 (2.2%) 6 (4.5%) 5 (3.8%) 42 | Lack of efficacy 2 (1.5%) 2 (1.5%) 3 (2.3%) 43 | Death 25 (18.7%) 23 (17.2%) 22 (16.7%) 44 | Other 3 (2.2%) 4 (3.0%) 3 (2.3%) 45 | Discontinued study 42 (31.3%) 40 (29.9%) 38 (28.8%) 46 | Death 25 (18.7%) 23 (17.2%) 22 (16.7%) 47 | Protocol deviation 5 (3.7%) 3 (2.2%) 4 (3.0%) 48 | Other 3 (2.2%) 4 (3.0%) 3 (2.3%) 49 | —————————————————————————————————————————————————————————————————— 50 | 51 | Source: [include Applicant source, datasets and/or software tools used]. 52 | (1) Duration = [e.g., X week double-blind treatment period or median and a range indicating pooled 53 | trial durations]. 54 | (2) [Include route of administration for all treatment arms if different ROA were used in the drug 55 | development]. 56 | (3) Difference is shown between [treatment arms] (e.g., difference is shown between Drug Name 57 | dosage X vs. placebo). 58 | 59 | Abbreviations: CI, confidence interval; ITT, intention-to-treat; mITT, modified intention-to-treat; 60 | N, number of patients in treatment arm; n, number of patients in specified population or group 61 | 62 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/fda-table_13.md: -------------------------------------------------------------------------------- 1 | # Table 13 generation works with default values 2 | 3 | Code 4 | res 5 | Output 6 | A: Drug X B: Placebo C: Combination 7 | Dictionary-Derived Term (N=134) (N=134) (N=132) 8 | —————————————————————————————————————————————————————————————————— 9 | dcd A.1.1.1.1 50 (37.3%) 45 (33.6%) 63 (47.7%) 10 | dcd A.1.1.1.2 48 (35.8%) 48 (35.8%) 50 (37.9%) 11 | dcd B.1.1.1.1 47 (35.1%) 49 (36.6%) 43 (32.6%) 12 | dcd B.2.1.2.1 49 (36.6%) 44 (32.8%) 52 (39.4%) 13 | dcd B.2.2.3.1 48 (35.8%) 54 (40.3%) 51 (38.6%) 14 | dcd C.1.1.1.3 43 (32.1%) 46 (34.3%) 43 (32.6%) 15 | dcd C.2.1.2.1 35 (26.1%) 48 (35.8%) 55 (41.7%) 16 | dcd D.1.1.1.1 50 (37.3%) 42 (31.3%) 51 (38.6%) 17 | dcd D.1.1.4.2 48 (35.8%) 42 (31.3%) 50 (37.9%) 18 | dcd D.2.1.5.3 47 (35.1%) 58 (43.3%) 57 (43.2%) 19 | 20 | # Table 13 generation works with custom values 21 | 22 | Code 23 | res 24 | Output 25 | Table 13. Patients With Common Adverse Events(1) Occurring at >=40% Frequency, Safety Population, Pooled Analyses(2) 26 | 27 | —————————————————————————————————————————————————————————————————————————— 28 | A: Drug X B: Placebo C: Combination Total 29 | Preferred Term(3) (N=134) (N=134) (N=132) (N=400) 30 | —————————————————————————————————————————————————————————————————————————— 31 | dcd A.1.1.1.1 50 (37.3%) 45 (33.6%) 63 (47.7%) 158 (39.5%) 32 | dcd B.2.2.3.1 48 (35.8%) 54 (40.3%) 51 (38.6%) 153 (38.2%) 33 | dcd C.2.1.2.1 35 (26.1%) 48 (35.8%) 55 (41.7%) 138 (34.5%) 34 | dcd D.2.1.5.3 47 (35.1%) 58 (43.3%) 57 (43.2%) 162 (40.5%) 35 | —————————————————————————————————————————————————————————————————————————— 36 | 37 | Source: [include Applicant source, datasets and/or software tools used]. 38 | (1) Treatment-emergent adverse event defined as [definition]. MedDRA version X. 39 | (2) Duration = [e.g., X week double-blind treatment period or median and a range indicating 40 | pooled trial durations]. 41 | (3) Coded as MedDRA preferred terms. 42 | 43 | Abbreviations: CI, confidence interval; MedDRA, Medical Dictionary for Regulatory Activities; 44 | N, number of patients in treatment arm; n, number of patients with adverse event; PT, preferred term 45 | 46 | # Table 13 generation works with risk difference column 47 | 48 | Code 49 | res 50 | Output 51 | A: Drug X B: Placebo C: Combination Risk Difference (%) (95% CI) 52 | Dictionary-Derived Term (N=134) (N=134) (N=132) (N=268) 53 | ————————————————————————————————————————————————————————————————————————————————————————————————— 54 | dcd A.1.1.1.1 50 (37.3%) 45 (33.6%) 63 (47.7%) -3.7 (-15.2 - 7.7) 55 | dcd A.1.1.1.2 48 (35.8%) 48 (35.8%) 50 (37.9%) 0.0 (-11.5 - 11.5) 56 | dcd B.1.1.1.1 47 (35.1%) 49 (36.6%) 43 (32.6%) 1.5 (-10.0 - 13.0) 57 | dcd B.2.1.2.1 49 (36.6%) 44 (32.8%) 52 (39.4%) -3.7 (-15.1 - 7.7) 58 | dcd B.2.2.3.1 48 (35.8%) 54 (40.3%) 51 (38.6%) 4.5 (-7.1 - 16.1) 59 | dcd C.1.1.1.3 43 (32.1%) 46 (34.3%) 43 (32.6%) 2.2 (-9.0 - 13.5) 60 | dcd C.2.1.2.1 35 (26.1%) 48 (35.8%) 55 (41.7%) 9.7 (-1.3 - 20.7) 61 | dcd D.1.1.1.1 50 (37.3%) 42 (31.3%) 51 (38.6%) -6.0 (-17.3 - 5.4) 62 | dcd D.1.1.4.2 48 (35.8%) 42 (31.3%) 50 (37.9%) -4.5 (-15.8 - 6.8) 63 | dcd D.2.1.5.3 47 (35.1%) 58 (43.3%) 57 (43.2%) 8.2 (-3.4 - 19.9) 64 | 65 | -------------------------------------------------------------------------------- /tests/testthat/setup-options.R: -------------------------------------------------------------------------------- 1 | # `opts_partial_match_old` is left for exclusions due to partial matching in dependent packages (i.e. not fixable here) 2 | # it might happen that it is not used right now, but it is left for possible future use 3 | # use with: `withr::with_options(opts_partial_match_old, { ... })` inside the test 4 | opts_partial_match_old <- list( 5 | warnPartialMatchDollar = getOption("warnPartialMatchDollar"), 6 | warnPartialMatchArgs = getOption("warnPartialMatchArgs"), 7 | warnPartialMatchAttr = getOption("warnPartialMatchAttr") 8 | ) 9 | opts_partial_match_new <- list( 10 | warnPartialMatchDollar = TRUE, 11 | warnPartialMatchArgs = TRUE, 12 | warnPartialMatchAttr = TRUE 13 | ) 14 | 15 | if (isFALSE(getFromNamespace("on_cran", "testthat")()) && requireNamespace("withr", quietly = TRUE)) { 16 | withr::local_options( 17 | opts_partial_match_new, 18 | .local_envir = testthat::teardown_env() 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /tests/testthat/setup.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(ggplot2) 3 | 4 | adsl_raw <- random.cdisc.data::cadsl 5 | adae_raw <- random.cdisc.data::cadae 6 | adex_raw <- random.cdisc.data::cadex 7 | advs_raw <- random.cdisc.data::cadvs 8 | 9 | adsl_raw <- adsl_raw %>% 10 | mutate(AGEGR1 = as.factor(case_when( 11 | AGE >= 17 & AGE < 65 ~ ">=17 to <65", 12 | AGE >= 65 ~ ">=65", 13 | AGE >= 65 & AGE < 75 ~ ">=65 to <75", 14 | AGE >= 75 ~ ">=75" 15 | )) %>% 16 | formatters::with_label("Age Group")) 17 | 18 | # Temporary fix for disparity between package versions 19 | adsl_raw$ETHNIC <- as.character(adsl_raw$ETHNIC) 20 | adsl_raw$ETHNIC[adsl_raw$ETHNIC == " NOT REPORTED"] <- "NOT REPORTED" 21 | adsl_raw$ETHNIC <- formatters::with_label(factor(adsl_raw$ETHNIC, levels = sort(unique(adsl_raw$ETHNIC))), "Ethnicity") 22 | adae_raw$ETHNIC <- as.character(adae_raw$ETHNIC) 23 | adae_raw$ETHNIC[adae_raw$ETHNIC == " NOT REPORTED"] <- "NOT REPORTED" 24 | adae_raw$ETHNIC <- formatters::with_label(factor(adae_raw$ETHNIC, levels = sort(unique(adae_raw$ETHNIC))), "Ethnicity") 25 | 26 | # expect_snapshot_ggplot - set custom plot dimensions 27 | expect_snapshot_ggplot <- function(title, fig, width = NA, height = NA) { 28 | testthat::skip_on_ci() 29 | testthat::skip_if_not_installed("svglite") 30 | 31 | name <- paste0(title, ".svg") 32 | path <- tempdir() 33 | withr::with_options( 34 | opts_partial_match_old, 35 | suppressMessages(ggplot2::ggsave(name, fig, path = path, width = width, height = height)) 36 | ) 37 | path <- file.path(path, name) 38 | 39 | testthat::announce_snapshot_file(name = name) 40 | testthat::expect_snapshot_file(path, name) 41 | } 42 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-fig_01.R: -------------------------------------------------------------------------------- 1 | set.seed(1) 2 | adsl <- adsl_raw 3 | adsl$TRTSDTM <- adsl$TRTSDTM[1] 4 | adsl$TRTEDTM <- adsl$TRTSDTM + lubridate::days(sample(0:400, nrow(adsl), replace = TRUE)) 5 | 6 | test_that("Figure 01 generation works with default values", { 7 | fig_01_default <- withr::with_options( 8 | opts_partial_match_old, 9 | make_fig_01(adsl) 10 | ) 11 | 12 | expect_snapshot_ggplot("fig_01_default", fig_01_default, width = 8, height = 5) 13 | }) 14 | 15 | test_that("Figure 01 generation works with no table", { 16 | fig_01_notbl <- withr::with_options( 17 | opts_partial_match_old, 18 | make_fig_01(adsl, add_table = FALSE) 19 | ) 20 | 21 | expect_snapshot_ggplot("fig_01_notbl", fig_01_notbl, width = 8, height = 3) 22 | }) 23 | 24 | test_that("Figure 01 generation works with custom values", { 25 | fig_01_custom <- withr::with_options( 26 | opts_partial_match_old, 27 | make_fig_01( 28 | adsl, 29 | u_trtdur = "years", 30 | annotations = list( 31 | title = "Figure 1. Time to Permanent Discontinuation of Study Drug, Safety Population, Pooled Analyses" 32 | ), 33 | xticks = c(0, 0.25, 0.5, 0.75, 1, 1.1) 34 | ) 35 | ) 36 | 37 | expect_snapshot_ggplot("fig_01_custom", fig_01_custom, width = 10, height = 5) 38 | }) 39 | 40 | test_that("Figure 01 generation works with ggtheme argument specified", { 41 | fig_01_theme <- withr::with_options( 42 | opts_partial_match_old, 43 | make_fig_01( 44 | adsl, 45 | ggtheme = theme_dark() 46 | ) 47 | ) 48 | 49 | expect_snapshot_ggplot("fig_01_theme", fig_01_theme, width = 10, height = 6) 50 | }) 51 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-fig_02.R: -------------------------------------------------------------------------------- 1 | set.seed(1) 2 | adsl <- adsl_raw 3 | adsl$EOSDY <- sample(0:400, nrow(adsl), replace = TRUE) 4 | 5 | test_that("Figure 02 generation works with default values", { 6 | fig_02_default <- withr::with_options( 7 | opts_partial_match_old, 8 | make_fig_02(adsl) 9 | ) 10 | 11 | expect_snapshot_ggplot("fig_02_default", fig_02_default, width = 8, height = 5) 12 | }) 13 | 14 | test_that("Figure 02 generation works with no table", { 15 | fig_02_notbl <- withr::with_options( 16 | opts_partial_match_old, 17 | make_fig_02(adsl, add_table = FALSE) 18 | ) 19 | 20 | expect_snapshot_ggplot("fig_02_notbl", fig_02_notbl, width = 8, height = 3) 21 | }) 22 | 23 | test_that("Figure 02 generation works with custom values", { 24 | fig_02_custom <- withr::with_options( 25 | opts_partial_match_old, 26 | make_fig_02( 27 | adsl, 28 | u_trtdur = "years", 29 | annotations = list( 30 | title = "Figure 2. Time to Last Follow Up, Safety Population, Pooled Analyses" 31 | ), 32 | xticks = c(0, 0.25, 0.5, 0.75, 1, 1.1) 33 | ) 34 | ) 35 | 36 | expect_snapshot_ggplot("fig_02_custom", fig_02_custom, width = 10, height = 5) 37 | }) 38 | 39 | test_that("Figure 02 generation works with ggtheme argument specified", { 40 | fig_02_theme <- withr::with_options( 41 | opts_partial_match_old, 42 | make_fig_02( 43 | adsl, 44 | ggtheme = theme_dark() 45 | ) 46 | ) 47 | 48 | expect_snapshot_ggplot("fig_02_theme", fig_02_theme, width = 10, height = 6) 49 | }) 50 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-fig_03.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw 2 | 3 | test_that("Figure 03 generation works with default values", { 4 | fig_03_default <- withr::with_options( 5 | opts_partial_match_old, 6 | make_fig_03(adsl, dcsreas_var = "DCSREAS") 7 | ) 8 | 9 | expect_snapshot_ggplot("fig_03_default", fig_03_default, width = 8, height = 5) 10 | }) 11 | 12 | test_that("Figure 03 generation works with no table", { 13 | fig_03_notbl <- withr::with_options( 14 | opts_partial_match_old, 15 | make_fig_03(adsl, dcsreas_var = "DCSREAS", add_table = FALSE) 16 | ) 17 | 18 | expect_snapshot_ggplot("fig_03_notbl", fig_03_notbl, width = 8, height = 3) 19 | }) 20 | 21 | test_that("Figure 03 generation works with custom values", { 22 | fig_03_custom <- withr::with_options( 23 | opts_partial_match_old, 24 | make_fig_03( 25 | adsl, 26 | dcsreas_var = "DCSREAS", 27 | u_trtdur = "years", 28 | annotations = list( 29 | title = "Figure 3. Time to Adverse Event Leading to Treatment Discontinuation, Safety Population, Trial X" 30 | ), 31 | xticks = c(0, 0.25, 0.5, 0.75, 1, 1.15) 32 | ) 33 | ) 34 | 35 | expect_snapshot_ggplot("fig_03_custom", fig_03_custom, width = 10, height = 5) 36 | }) 37 | 38 | test_that("Figure 03 generation works with ggtheme argument specified", { 39 | fig_03_theme <- withr::with_options( 40 | opts_partial_match_old, 41 | make_fig_03( 42 | adsl, 43 | dcsreas_var = "DCSREAS", 44 | ggtheme = theme_dark() 45 | ) 46 | ) 47 | 48 | expect_snapshot_ggplot("fig_03_theme", fig_03_theme, width = 10, height = 6) 49 | }) 50 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-fig_14.R: -------------------------------------------------------------------------------- 1 | test_that("Figure 14 generation works with default values", { 2 | fig_14_default <- withr::with_options( 3 | opts_partial_match_old, 4 | make_fig_14(advs_raw) 5 | ) 6 | 7 | expect_snapshot_ggplot("fig_14_default", fig_14_default, width = 8, height = 6) 8 | }) 9 | 10 | test_that("Figure 14 generation works with no table", { 11 | fig_14_notbl <- withr::with_options( 12 | opts_partial_match_old, 13 | make_fig_14(advs_raw, add_table = FALSE) 14 | ) 15 | 16 | expect_snapshot_ggplot("fig_14_notbl", fig_14_notbl, width = 8, height = 4) 17 | }) 18 | 19 | test_that("Figure 14 generation works with custom values", { 20 | fig_14_custom <- withr::with_options( 21 | opts_partial_match_old, 22 | make_fig_14( 23 | advs_raw, 24 | paramcd_val = "SYSBP", 25 | add_cond = bquote("ONTRTFL == 'Y' | ABLFL == 'Y'"), 26 | x_lab = "Analysis Visit", 27 | y_lab = "Systolic (unit)", 28 | annotations = list( 29 | title = paste( 30 | "Figure 14. Mean and 95% Confidence Interval of Systolic Blood Pressure Over Time by Treatment", 31 | "Arm, Safety Population, Trial X", 32 | sep = "\n" 33 | ), 34 | subtitle = "Source: [include source]" 35 | ), 36 | yticks = c(135, 140, 145, 150, 155, 160) 37 | ) 38 | ) 39 | 40 | expect_snapshot_ggplot("fig_14_custom", fig_14_custom, width = 10, height = 6) 41 | }) 42 | 43 | test_that("Figure 14 generation works with ggtheme argument specified", { 44 | fig_14_theme <- withr::with_options( 45 | opts_partial_match_old, 46 | make_fig_14( 47 | advs_raw, 48 | ggtheme = theme_dark() 49 | ) 50 | ) 51 | 52 | expect_snapshot_ggplot("fig_14_theme", fig_14_theme, width = 10, height = 6) 53 | }) 54 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_03.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw 2 | 3 | set.seed(1) 4 | adsl$RANDDT[sample(seq_len(nrow(adsl)), 100)] <- NA 5 | adsl <- adsl %>% 6 | mutate( 7 | ENRLDT = RANDDT, 8 | SCRNFL = "Y", 9 | SCRNFRS = factor(sample( 10 | c("Inclusion/exclusion criteria not met", "Patient noncompliance", "Consent withdrawn", "Other"), 11 | size = nrow(adsl), replace = TRUE 12 | ), levels = c("Inclusion/exclusion criteria not met", "Patient noncompliance", "Consent withdrawn", "Other")), 13 | SCRNFAILFL = ifelse(is.na(ENRLDT), "Y", "N") 14 | ) 15 | adsl$SCRNFRS[adsl$SCRNFL == "N" | !is.na(adsl$ENRLDT)] <- NA 16 | 17 | test_that("Table 3 generation works with default values", { 18 | result <- make_table_03(adsl, scrnfl_var = "SCRNFL", scrnfailfl_var = "SCRNFAILFL", scrnfail_var = "SCRNFRS") 19 | 20 | res <- expect_silent(result) 21 | expect_snapshot(res) 22 | }) 23 | 24 | test_that("Table 3 generation works with custom values", { 25 | result <- make_table_03( 26 | adsl, 27 | scrnfl_var = "SCRNFL", scrnfailfl_var = "SCRNFAILFL", scrnfail_var = "SCRNFRS", 28 | show_colcounts = TRUE, 29 | lbl_overall = "Total\nPopulation", 30 | annotations = list( 31 | title = paste( 32 | "Table 3. Patients Screening and Enrollment, Trials A and B" 33 | ), 34 | main_footer = c( 35 | "Source: [include Applicant source, datasets and/or software tools used]." 36 | ) 37 | ) 38 | ) 39 | 40 | res <- expect_silent(result) 41 | expect_snapshot(res) 42 | }) 43 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_04.R: -------------------------------------------------------------------------------- 1 | set.seed(4) 2 | adsl <- adsl_raw %>% 3 | mutate(test = rbinom(400, 1, 0.5)) %>% 4 | mutate( 5 | RANDFL = ifelse(test == 0, "N", "Y"), 6 | PPROTFL = ifelse(test == 0, "N", "Y"), 7 | DCSREAS = if_else(DCSREAS %in% c( 8 | "ADVERSE EVENT", "LACK OF EFFICACY", "PROTOCOL VIOLATION", 9 | "DEATH", "WITHDRAWAL BY PARENT/GUARDIAN" 10 | ), DCSREAS, "OTHER") 11 | ) 12 | 13 | test_that("Table 04 generation works with default values", { 14 | result <- make_table_04(adsl) 15 | 16 | res <- expect_silent(result) 17 | expect_snapshot(res) 18 | }) 19 | 20 | test_that("Table 04 generation works with custom values", { 21 | result <- make_table_04( 22 | adsl, 23 | pop_vars = c("RANDFL", "ITTFL", "SAFFL", "PPROTFL"), 24 | lbl_pop_vars = c("Patients randomized", "ITT/mITT population", "Safety population", "Per-protocol population"), 25 | annotations = list( 26 | title = "Patient Disposition, Pooled Analyses (1,2)", 27 | main_footer = c( 28 | "Source: [include Applicant source, datasets and/or software tools used].", 29 | "(1) Duration = [e.g., X week double-blind treatment period or median and a range indicating pooled", 30 | "trial durations].", 31 | "(2) [Include route of administration for all treatment arms if different ROA were used in the drug", 32 | "development].", 33 | "(3) Difference is shown between [treatment arms] (e.g., difference is shown between Drug Name", 34 | "dosage X vs. placebo)." 35 | ), 36 | prov_footer = c( 37 | "Abbreviations: CI, confidence interval; ITT, intention-to-treat; mITT, modified intention-to-treat;", 38 | "N, number of patients in treatment arm; n, number of patients in specified population or group" 39 | ) 40 | ), 41 | prune_0 = TRUE 42 | ) 43 | 44 | res <- expect_silent(result) 45 | expect_snapshot(res) 46 | }) 47 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_07.R: -------------------------------------------------------------------------------- 1 | set.seed(1) 2 | 3 | adsl <- adsl_raw 4 | adae <- adae_raw %>% 5 | mutate(TRTEMFL = ifelse( 6 | USUBJID %in% sample(adsl[["USUBJID"]], size = as.integer(nrow(adsl) / 3)), "N", "Y" 7 | )) 8 | 9 | test_that("Table 07 generation works with default values", { 10 | result <- make_table_07(adae, adsl) 11 | 12 | res <- expect_silent(result) 13 | expect_snapshot(res) 14 | }) 15 | 16 | test_that("Table 07 generation works with custom values", { 17 | result <- make_table_07( 18 | adae, 19 | adsl, 20 | annotations = list( 21 | title = "Table 7. Deaths, Safety Population, Pooled Analyses (1)", 22 | main_footer = c( 23 | "Source: [include Applicant source, datasets and/or software tools used].", 24 | "(1) Duration = [e.g., X week double-blind treatment period or median and a range indicating pooled trial", 25 | "durations]." 26 | ), 27 | prov_footer = c( 28 | "Abbreviations: AE, adverse event; MedDRA, Medical Dictionary for Regulatory Activities;", 29 | "N, number of patients in treatment arm; n, number of patients with adverse event" 30 | ) 31 | ) 32 | ) 33 | 34 | fnotes_at_path(result, c("TRTEMFL", "Y")) <- "Treatment-emergent AE defined as [definition]. MedDRA version X." # nolint 35 | fnotes_at_path(result, c("TRTEMFL", "N")) <- paste( # nolint 36 | "Defined as [(e.g., deaths beyond the protocol-defined, treatment-emergent adverse event period in the", 37 | "same trial or deaths from other trials with drug)].", 38 | sep = "\n " 39 | ) 40 | 41 | res <- expect_silent(result) 42 | expect_snapshot(res) 43 | }) 44 | 45 | test_that("Table 07 generation works with NA values/pruned rows", { 46 | set.seed(1) 47 | adae$DTHCAUS[adae$DTHCAUS == "LOST TO FOLLOW UP"] <- NA 48 | 49 | result <- make_table_07(adae, adsl, prune_0 = FALSE) 50 | 51 | res <- expect_silent(result) 52 | expect_snapshot(res) 53 | 54 | result <- make_table_07(adae, adsl) 55 | 56 | res <- expect_silent(result) 57 | expect_snapshot(res) 58 | }) 59 | 60 | test_that("Table 07 generation works with risk difference column", { 61 | risk_diff <- list(arm_x = "B: Placebo", arm_y = "A: Drug X") 62 | result <- make_table_07(adae, adsl, risk_diff = risk_diff) 63 | 64 | res <- expect_silent(result) 65 | expect_snapshot(res) 66 | }) 67 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_08.R: -------------------------------------------------------------------------------- 1 | set.seed(1) 2 | 3 | adae <- adae_raw 4 | adex <- adex_raw 5 | 6 | test_that("Table 08 generation works with default values", { 7 | result <- make_table_08(adae, adex) 8 | rand_rows <- sort(sample(seq_len(nrow(result)), as.integer(nrow(result) / 5))) 9 | res <- expect_silent(result[rand_rows, ]) 10 | expect_snapshot(res) 11 | }) 12 | 13 | test_that("Table 08 generation works with custom values", { 14 | result <- make_table_08( 15 | adae, 16 | adex, 17 | na_level = "-", 18 | annotations = list( 19 | title = "Table 8. All Individual Patient Deaths, Safety Population, Pooled Analyses (1)", 20 | main_footer = c( 21 | "Source: [include Applicant source, datasets and/or software tools used].", 22 | "(1) Duration = [e.g., X week double-blind treatment period or median and a range indicating", 23 | "pooled trial durations].", 24 | "Abbreviations: MedDRA, Medical Dictionary for Regulatory Activities; PT, preferred term" 25 | ) 26 | ) 27 | ) 28 | 29 | rand_rows <- sort(sample(seq_len(nrow(result)), as.integer(nrow(result) / 5))) 30 | res <- expect_silent(result[rand_rows, ]) 31 | expect_snapshot(res) 32 | }) 33 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_10.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw 2 | adae <- adae_raw 3 | 4 | set.seed(1) 5 | adae <- adae %>% 6 | dplyr::rename(FMQ01SC = SMQ01SC) %>% 7 | dplyr::mutate( 8 | AESER = sample(c("Y", "N"), size = nrow(adae), replace = TRUE), 9 | FMQ01NAM = sample(c("FMQ1", "FMQ2", "FMQ3"), size = nrow(adae), replace = TRUE) 10 | ) 11 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 12 | 13 | test_that("Table 10 generation(gtsummary) works with default values", { 14 | result <- make_table_10(df = adae, denominator = adsl, ) 15 | 16 | res <- expect_silent(result) 17 | expect_snapshot(res) 18 | }) 19 | 20 | test_that("Table 10 generation(gtsummary) works with default values", { 21 | result <- make_table_10(df = adae, denominator = adsl, ) 22 | 23 | res <- expect_silent(result) 24 | expect_snapshot(res) 25 | }) 26 | 27 | 28 | test_that("Table 10 generation(rtables) works with default values, BROAD", { 29 | result <- make_table_10_rtables(df = adae, alt_counts_df = adsl, fmq_scope = "BROAD") 30 | 31 | res <- expect_silent(result) 32 | expect_snapshot(res) 33 | }) 34 | 35 | test_that("Table 10 generation(rtables) works with default values", { 36 | adae <- formatters::var_relabel(adae, AEBODSYS = "Body System or Organ Class(3)") 37 | result <- make_table_10_rtables( 38 | df = adae, 39 | alt_counts_df = adsl, 40 | fmq_scope = "BROAD", 41 | annotations = list( 42 | title = paste( 43 | "Table 10. Patients With Serious Adverse Events(1) by System Organ Class and FDA Medical Query\n", 44 | "(Broad), Safety Population, Pooled Analyses(2)" 45 | ), 46 | main_footer = paste( 47 | "Source: [include Applicant source, datasets and/or software tools used].\n", 48 | "(1) Defined as any untoward medical occurrence that, at any dose that results in death,", 49 | "is life-threatening,\n requires hospitalization or prolongation of existing hospitalization, results in", 50 | "persistent incapacity or substantial\n", 51 | "disruption of the ability to conduct normal life functions, or is a congenital anomaly or birth defect.\n", 52 | "(2) Duration = [e.g., X-week double-blind treatment period or, median and a range indicating pooled trial\n", 53 | "durations].\n", 54 | "(3) Each FMQ is aligned to a single SOC based on clinical judgement.", 55 | "However, please be aware that some FMQs\n", 56 | "may contain PTs from more than one SOC." 57 | ), 58 | prov_footer = c( 59 | "Abbreviations: CI, confidence interval; FMQ, FDA Medical Query;", 60 | "MedDRA, Medical Dictionary for Regulatory Activities; N, number of patients in treatment arm;", 61 | "n, number of patients with adverse event; SOC, System Organ Class" 62 | ) 63 | ) 64 | ) 65 | 66 | res <- expect_silent(result) 67 | expect_snapshot(res) 68 | }) 69 | 70 | test_that("Table 10 generation (rtables) works with risk difference column", { 71 | risk_diff <- list(arm_x = "B: Placebo", arm_y = "A: Drug X") 72 | result <- make_table_10_rtables(adae, adsl, risk_diff = risk_diff) 73 | 74 | res <- expect_silent(result) 75 | expect_snapshot(res) 76 | }) 77 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_13.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw 2 | adae <- adae_raw 3 | 4 | test_that("Table 13 generation works with default values", { 5 | result <- make_table_13(adae, adsl) 6 | 7 | res <- expect_silent(result) 8 | expect_snapshot(res) 9 | }) 10 | 11 | test_that("Table 13 generation works with custom values", { 12 | adae <- adae %>% var_relabel(AEDECOD = "Preferred Term(3)") 13 | result <- make_table_13( 14 | adae, 15 | adsl, 16 | lbl_overall = "Total", 17 | min_freq = 0.40, 18 | annotations = list( 19 | title = paste0( 20 | "Table 13. Patients With Common Adverse Events(1) Occurring at >=", 0.40 * 100, 21 | "% Frequency, Safety Population, Pooled Analyses(2)" 22 | ), 23 | main_footer = c( 24 | "Source: [include Applicant source, datasets and/or software tools used].", 25 | "(1) Treatment-emergent adverse event defined as [definition]. MedDRA version X.", 26 | "(2) Duration = [e.g., X week double-blind treatment period or median and a range indicating", 27 | "pooled trial durations].", 28 | "(3) Coded as MedDRA preferred terms." 29 | ), 30 | prov_footer = c( 31 | "Abbreviations: CI, confidence interval; MedDRA, Medical Dictionary for Regulatory Activities;", 32 | "N, number of patients in treatment arm; n, number of patients with adverse event; PT, preferred term" 33 | ) 34 | ) 35 | ) 36 | 37 | res <- expect_silent(result) 38 | expect_snapshot(res) 39 | }) 40 | 41 | test_that("Table 13 generation works with risk difference column", { 42 | risk_diff <- list(arm_x = "B: Placebo", arm_y = "A: Drug X") 43 | result <- make_table_13(adae, adsl, risk_diff = risk_diff) 44 | 45 | res <- expect_silent(result) 46 | expect_snapshot(res) 47 | }) 48 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_14.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw 2 | adae <- adae_raw 3 | adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 4 | levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 5 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 6 | adsl <- adsl %>% 7 | dplyr::left_join( 8 | adae, 9 | by = c("USUBJID", "SAFFL", "ARM") 10 | ) 11 | 12 | test_that("Table 14 generation works with default values", { 13 | result <- make_table_14(adae) 14 | 15 | res <- expect_silent(result) 16 | expect_snapshot(res) 17 | }) 18 | 19 | test_that("Table 14 generation works with custom values", { 20 | adae <- formatters::var_relabel(adae, AEBODSYS = "Body System or Organ Class(3)") 21 | result <- make_table_14( 22 | adae, 23 | adsl, 24 | annotations = list( 25 | title = paste( 26 | "Table 14. Patients With Adverse Events(1) by System Organ Class and FDA Medical Query,", 27 | "Safety Population, Pooled Analyses(2)" 28 | ), 29 | main_footer = paste( 30 | "Source: [include Applicant source, datasets and/or software tools used\n", 31 | "(1) Treatment-emergent AE defined as [definition]. MedDRA version X.\n", 32 | "(2) Duration = [e.g., X-week double-blind treatment period or, median and a range indicating pooled trial", 33 | "durations].\n", 34 | "(3) Each FMQ is aligned to a single SOC based on clinical judgement. However, please beaware that some FMQs", 35 | "may contain PTs from more than one SOC." 36 | ), 37 | prov_footer = c( 38 | "Abbreviations: CI, confidence interval; FMQ, FDA Medical Query;", 39 | "MedDRA, Medical Dictionary for Regulatory Activities; N, number of patients in treatment arm;", 40 | "n, number of patients with at least one event; SOC, System Organ Class" 41 | ) 42 | ) 43 | ) 44 | 45 | res <- expect_silent(result) 46 | expect_snapshot(res) 47 | }) 48 | 49 | test_that("Table 14 generation works with NA values/pruned rows", { 50 | result <- make_table_14(adae, prune_0 = TRUE) 51 | 52 | res <- expect_silent(result) 53 | expect_snapshot(res) 54 | }) 55 | 56 | test_that("Table 14 generation works with risk difference column", { 57 | risk_diff <- list(arm_x = "B: Placebo", arm_y = "A: Drug X") 58 | result <- make_table_14(adae, risk_diff = risk_diff) 59 | 60 | res <- expect_silent(result) 61 | expect_snapshot(res) 62 | }) 63 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_15.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw 2 | adae <- adae_raw 3 | 4 | set.seed(1) 5 | adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 6 | levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 7 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 8 | adae$FMQ01NAM <- factor(adae$FMQ01NAM, levels = c(unique(adae$FMQ01NAM), "Erectile Dysfunction", "Gynecomastia")) 9 | adae$FMQ01NAM[adae$SEX == "M"] <- as.factor( 10 | sample(c("Erectile Dysfunction", "Gynecomastia"), sum(adae$SEX == "M"), replace = TRUE) 11 | ) 12 | 13 | risk_diff <- list(arm_x = "A: Drug X", arm_y = "C: Combination") 14 | 15 | test_that("Table 15 generation works with default values", { 16 | result <- make_table_15(adae, adsl) 17 | 18 | res <- expect_silent(result) 19 | expect_snapshot(res) 20 | }) 21 | 22 | test_that("Table 15 generation works with custom values", { 23 | result <- make_table_15( 24 | adae, 25 | adsl, 26 | annotations = list( 27 | title = paste( 28 | "Table 15: Patients With Adverse Events by Male-Specific FDA Medical Query (Narrow) and Preferred Term,", 29 | "Male Safety Population, Pooled Analyses" 30 | ), 31 | main_footer = paste( 32 | "Source: [include Applicant source, datasets and/or software tools used].\n", 33 | "(1) Treatment-emergent adverse event defined as [definition]. MedDRA version X.\n", 34 | "(2) Duration = [e.g., X week double-blind treatment period or median and a range indicating pooled", 35 | "trial durations].\n", 36 | "(3) Difference is shown between [treatment arms] (e.g., difference is shown between Drug Name dosage", 37 | "X vs. placebo).\n" 38 | ), 39 | prov_footer = c( 40 | "Abbreviations: CI, confidence interval;", 41 | "FMQ, FDA Medical Query;", 42 | "MedDRA, Medical Dictionary for Regulatory Activities;", 43 | "N, number of patients in treatment arm;", 44 | "n, number of patients with at least one event;", 45 | "PT, preferred term" 46 | ) 47 | ) 48 | ) 49 | 50 | res <- expect_silent(result) 51 | expect_snapshot(res) 52 | }) 53 | 54 | test_that("Table 15 generation works with NA values/pruned rows", { 55 | result <- make_table_15(adae, adsl, prune_0 = TRUE) 56 | 57 | res <- expect_silent(result) 58 | expect_snapshot(res) 59 | }) 60 | 61 | test_that("Table 15 generation works with risk difference column", { 62 | risk_diff <- list(arm_x = "A: Drug X", arm_y = "C: Combination") 63 | result <- make_table_15(adae, adsl, risk_diff = risk_diff) 64 | 65 | res <- expect_silent(result) 66 | expect_snapshot(res) 67 | }) 68 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_16.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw 2 | adae <- adae_raw 3 | 4 | set.seed(1) 5 | adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 6 | levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 7 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 8 | adae$FMQ01NAM <- factor(adae$FMQ01NAM, levels = c(unique(adae$FMQ01NAM), "Erectile Dysfunction", "Gynecomastia")) 9 | adae$FMQ01NAM[adae$SEX == "M"] <- as.factor( 10 | sample(c("Erectile Dysfunction", "Gynecomastia"), sum(adae$SEX == "M"), replace = TRUE) 11 | ) 12 | 13 | risk_diff <- list(arm_x = "A: Drug X", arm_y = "C: Combination") 14 | 15 | test_that("Table 16 generation works with default values", { 16 | result <- make_table_16(adae, adsl) 17 | 18 | res <- expect_silent(result) 19 | expect_snapshot(res) 20 | }) 21 | 22 | test_that("Table 16 generation works with custom values", { 23 | result <- make_table_16( 24 | adae, 25 | adsl, 26 | annotations = list( 27 | title = paste( 28 | "Table 16: Patients With Adverse Events by Male-Specific FDA Medical Query (Broad) and Preferred Term,", 29 | "Male Safety Population, Pooled Analyses" 30 | ), 31 | main_footer = paste( 32 | "Source: [include Applicant source, datasets and/or software tools used].\n", 33 | "(1) Treatment-emergent adverse event defined as [definition]. MedDRA version X.\n", 34 | "(2) Duration = [e.g., X week double-blind treatment period or median and a range indicating pooled", 35 | "trial durations].\n", 36 | "(3) Difference is shown between [treatment arms] (e.g., difference is shown between Drug Name dosage", 37 | "X vs. placebo).\n" 38 | ), 39 | prov_footer = c( 40 | "Abbreviations: CI, confidence interval;", 41 | "FMQ, FDA Medical Query;", 42 | "MedDRA, Medical Dictionary for Regulatory Activities;", 43 | "N, number of patients in treatment arm;", 44 | "n, number of patients with at least one event;", 45 | "PT, preferred term" 46 | ) 47 | ) 48 | ) 49 | 50 | res <- expect_silent(result) 51 | expect_snapshot(res) 52 | }) 53 | 54 | test_that("Table 16 generation works with NA values/pruned rows", { 55 | result <- make_table_16(adae, adsl, prune_0 = TRUE) 56 | 57 | res <- expect_silent(result) 58 | expect_snapshot(res) 59 | }) 60 | 61 | test_that("Table 16 generation works with risk difference column", { 62 | risk_diff <- list(arm_x = "A: Drug X", arm_y = "C: Combination") 63 | result <- make_table_16(adae, adsl, risk_diff = risk_diff) 64 | 65 | res <- expect_silent(result) 66 | expect_snapshot(res) 67 | }) 68 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_17.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw 2 | adae <- adae_raw 3 | 4 | set.seed(1) 5 | adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 6 | levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 7 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 8 | adae$FMQ01NAM <- factor(adae$FMQ01NAM, levels = c( 9 | unique(adae$FMQ01NAM), "Abnormal Uterine Bleeding", "Amenorrhea", 10 | "Bacterial Vaginosis", "Decreased Menstrual Bleeding" 11 | )) 12 | adae$FMQ01NAM[adae$SEX == "F"] <- as.factor( 13 | sample(c( 14 | "Abnormal Uterine Bleeding", "Amenorrhea", 15 | "Bacterial Vaginosis", "Decreased Menstrual Bleeding" 16 | ), sum(adae$SEX == "F"), replace = TRUE) 17 | ) 18 | 19 | risk_diff <- list(arm_x = "A: Drug X", arm_y = "C: Combination") 20 | 21 | test_that("Table 17 generation works with default values", { 22 | result <- make_table_17(adae, adsl) 23 | 24 | res <- expect_silent(result) 25 | expect_snapshot(res) 26 | }) 27 | 28 | test_that("Table 17 generation works with custom values", { 29 | result <- make_table_17( 30 | adae, 31 | adsl, 32 | annotations = list( 33 | title = paste( 34 | "Table 17: Patients With Adverse Events by Female-Specific FDA Medical Query (Narrow) and Preferred Term,", 35 | "Female Safety Population, Pooled Analyses" 36 | ), 37 | main_footer = paste( 38 | "Source: [include Applicant source, datasets and/or software tools used].\n", 39 | "(1) Treatment-emergent adverse event defined as [definition]. MedDRA version X.\n", 40 | "(2) Duration = [e.g., X week double-blind treatment period or median and a range indicating pooled", 41 | "trial durations].\n", 42 | "(3) Difference is shown between [treatment arms] (e.g., difference is shown between Drug Name dosage", 43 | "X vs. placebo).\n" 44 | ), 45 | prov_footer = c( 46 | "Abbreviations: CI, confidence interval;", 47 | "FMQ, FDA Medical Query;", 48 | "MedDRA, Medical Dictionary for Regulatory Activities;", 49 | "N, number of patients in treatment arm;", 50 | "n, number of patients with at least one event;", 51 | "PT, preferred term" 52 | ) 53 | ) 54 | ) 55 | 56 | res <- expect_silent(result) 57 | expect_snapshot(res) 58 | }) 59 | 60 | test_that("Table 17 generation works with NA values/pruned rows", { 61 | result <- make_table_17(adae, adsl, prune_0 = TRUE) 62 | 63 | res <- expect_silent(result) 64 | expect_snapshot(res) 65 | }) 66 | 67 | test_that("Table 17 generation works with risk difference column", { 68 | risk_diff <- list(arm_x = "A: Drug X", arm_y = "C: Combination") 69 | result <- make_table_17(adae, adsl, risk_diff = risk_diff) 70 | 71 | res <- expect_silent(result) 72 | expect_snapshot(res) 73 | }) 74 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_18.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw 2 | adae <- adae_raw 3 | 4 | set.seed(1) 5 | adae <- dplyr::rename(adae, FMQ01SC = SMQ01SC, FMQ01NAM = SMQ01NAM) 6 | levels(adae$FMQ01SC) <- c("BROAD", "NARROW") 7 | adae$FMQ01SC[is.na(adae$FMQ01SC)] <- "NARROW" 8 | adae$FMQ01NAM <- factor(adae$FMQ01NAM, levels = c( 9 | unique(adae$FMQ01NAM), "Abnormal Uterine Bleeding", "Amenorrhea", 10 | "Bacterial Vaginosis", "Decreased Menstrual Bleeding" 11 | )) 12 | adae$FMQ01NAM[adae$SEX == "F"] <- as.factor( 13 | sample(c( 14 | "Abnormal Uterine Bleeding", "Amenorrhea", 15 | "Bacterial Vaginosis", "Decreased Menstrual Bleeding" 16 | ), sum(adae$SEX == "F"), replace = TRUE) 17 | ) 18 | 19 | risk_diff <- list(arm_x = "A: Drug X", arm_y = "C: Combination") 20 | 21 | test_that("Table 18 generation works with default values", { 22 | result <- make_table_18(adae, adsl) 23 | 24 | res <- expect_silent(result) 25 | expect_snapshot(res) 26 | }) 27 | 28 | test_that("Table 18 generation works with custom values", { 29 | result <- make_table_18( 30 | adae, 31 | adsl, 32 | annotations = list( 33 | title = paste( 34 | "Table 18: Patients With Adverse Events by Female-Specific FDA Medical Query (Broad) and Preferred Term,", 35 | "Female Safety Population, Pooled Analyses" 36 | ), 37 | main_footer = paste( 38 | "Source: [include Applicant source, datasets and/or software tools used].\n", 39 | "(1) Treatment-emergent adverse event defined as [definition]. MedDRA version X.\n", 40 | "(2) Duration = [e.g., X week double-blind treatment period or median and a range indicating pooled", 41 | "trial durations].\n", 42 | "(3) Difference is shown between [treatment arms] (e.g., difference is shown between Drug Name dosage", 43 | "X vs. placebo).\n" 44 | ), 45 | prov_footer = c( 46 | "Abbreviations: CI, confidence interval;", 47 | "FMQ, FDA Medical Query;", 48 | "MedDRA, Medical Dictionary for Regulatory Activities;", 49 | "N, number of patients in treatment arm;", 50 | "n, number of patients with at least one event;", 51 | "PT, preferred term" 52 | ) 53 | ) 54 | ) 55 | 56 | res <- expect_silent(result) 57 | expect_snapshot(res) 58 | }) 59 | 60 | test_that("Table 18 generation works with NA values/pruned rows", { 61 | result <- make_table_18(adae, adsl, prune_0 = TRUE) 62 | 63 | res <- expect_silent(result) 64 | expect_snapshot(res) 65 | }) 66 | 67 | test_that("Table 18 generation works with risk difference column", { 68 | risk_diff <- list(arm_x = "A: Drug X", arm_y = "C: Combination") 69 | result <- make_table_18(adae, adsl, risk_diff = risk_diff) 70 | 71 | res <- expect_silent(result) 72 | expect_snapshot(res) 73 | }) 74 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_20.R: -------------------------------------------------------------------------------- 1 | set.seed(1) 2 | 3 | adsl <- adsl_raw 4 | adae <- adae_raw %>% 5 | mutate( 6 | AESIFL = case_when( 7 | AESOC %in% c("cl A", "cl D") ~ "Y", 8 | TRUE ~ "N" 9 | ), 10 | AELABFL = sample(c("Y", "N"), n(), replace = TRUE) 11 | ) 12 | 13 | test_that("Table 20 generation works with default values", { 14 | result <- make_table_20(adae, adsl) 15 | 16 | res <- expect_silent(result) 17 | expect_snapshot(res) 18 | }) 19 | 20 | test_that("Table 20 generation works with custom values", { 21 | result <- make_table_20( 22 | adae, 23 | adsl, 24 | annotations = list( 25 | title = paste( 26 | "Table 20. Adverse Events of Special Interest Assessment, Safety Population,", 27 | "Pooled Analysis (or Trial X) (1)" 28 | ), 29 | main_footer = c( 30 | "Source: [include Applicant source, datasets and/or software tools used].", 31 | "(1) Duration = [e.g., X week double-blind treatment period or median and", 32 | "a range indicating pooled trial durations].", 33 | "(2) Difference is shown between [treatment arms]", 34 | "(e.g., difference is shown between Drug Name dosage X vs. placebo)." 35 | ), 36 | prov_footer = c( 37 | "Abbreviations: AESI, adverse event of special interest; CI, confidence interval;", 38 | "N, number of patients in treatment arm; n, number of patients with at least one event" 39 | ) 40 | ) 41 | ) 42 | 43 | fnotes_at_path( 44 | result, 45 | rowpath = c("ma_tbl_aesi_AEDECOD_AESEV_tbl_ser_tbl_death_tbl_dis_tbl_rel_tbl_lab", "tbl_aesi", "count_fraction.AESIFL") # nolint 46 | ) <- c("Use FMQ grouping if appropriate.") 47 | fnotes_at_path( 48 | result, 49 | rowpath = c("ma_tbl_aesi_AEDECOD_AESEV_tbl_ser_tbl_death_tbl_dis_tbl_rel_tbl_lab", "AESEV") # nolint 50 | ) <- c("Use FMQ grouping if appropriate.") 51 | fnotes_at_path( 52 | result, 53 | rowpath = c("ma_tbl_aesi_AEDECOD_AESEV_tbl_ser_tbl_death_tbl_dis_tbl_rel_tbl_lab", "tbl_ser", "count_fraction") # nolint 54 | ) <- c("Use FMQ grouping if appropriate.") 55 | fnotes_at_path( 56 | result, 57 | rowpath = c("ma_tbl_aesi_AEDECOD_AESEV_tbl_ser_tbl_death_tbl_dis_tbl_rel_tbl_lab", "tbl_rel", "count_fraction") # nolint 58 | ) <- c("As determined by investigator.") 59 | fnotes_at_path( 60 | result, 61 | rowpath = c("ma_tbl_aesi_AEDECOD_AESEV_tbl_ser_tbl_death_tbl_dis_tbl_rel_tbl_lab", "tbl_lab", "count_fraction.AELABFL") # nolint 62 | ) <- c("Include relevant laboratory results as appropriate for AESI evaluation.") 63 | 64 | res <- expect_silent(result) 65 | expect_snapshot(res) 66 | }) 67 | 68 | test_that("Table 20 generation works with missing values/pruned rows", { 69 | adae$AESEV[adae$AESEV == "MILD"] <- "MODERATE" 70 | 71 | result <- make_table_20(adae, adsl) 72 | 73 | res <- expect_silent(result) 74 | expect_snapshot(res) 75 | }) 76 | 77 | test_that("Table 20 generation works with risk difference column", { 78 | risk_diff <- list(arm_x = "B: Placebo", arm_y = "A: Drug X") 79 | result <- make_table_20(adae, adsl, risk_diff = risk_diff) 80 | 81 | res <- expect_silent(result) 82 | expect_snapshot(res) 83 | }) 84 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_21.R: -------------------------------------------------------------------------------- 1 | adsl <- adsl_raw %>% 2 | formatters::var_relabel( 3 | AGE = "Age, years", 4 | AGEGR1 = "Age Group, years" 5 | ) 6 | 7 | adae <- adae_raw 8 | adae$ASER <- adae$AESER 9 | 10 | df <- left_join(adsl, adae, by = intersect(names(adsl), names(adae))) 11 | 12 | test_that("Table 21 generation works with default values", { 13 | result <- make_table_21(df = df) 14 | 15 | res <- expect_silent(result) 16 | expect_snapshot(res) 17 | }) 18 | 19 | test_that("Table 21 generation works with custom values: N_s denominator and overall column", { 20 | result <- make_table_21( 21 | df = df, 22 | alt_counts_df = adsl, 23 | denom = "N_s", 24 | lbl_overall = "Total population", 25 | ) 26 | 27 | res <- expect_silent(result) 28 | expect_snapshot(res) 29 | }) 30 | 31 | test_that("Table 21 generation works with custom values: N_col denominator and no overall column", { 32 | result <- make_table_21( 33 | df = df, 34 | alt_counts_df = adsl, 35 | denom = "N_col", 36 | lbl_overall = NULL, 37 | prune_0 = TRUE, 38 | annotations = list( 39 | title = "Table 21. Overview of Serious Adverse Events1 by Demographic Subgroup, Safety Population, 40 | Pooled Analysis (or Trial X)", 41 | main_footer = c( 42 | "Source: [include Applicant source, datasets and/or software tools used].", 43 | "(1) Defined as any untoward medical occurrence that, at any dose that results in death, is life-threatening,", 44 | "requires hospitalization or prolongation of existing hospitalization, results in persistent incapacity or", 45 | "substantial disruption of the ability to conduct normal life functions, or is a congenital anomaly or", 46 | "birth defect. " 47 | ), 48 | prov_footer = c( 49 | "Abbreviations: N, number of patients in treatment arm; n, number of patients with adverse event;", 50 | "Ns, total number of patients for each specific subgroup; SAE, serious adverse event" 51 | ) 52 | ) 53 | ) 54 | 55 | res <- expect_silent(result) 56 | expect_snapshot(res) 57 | }) 58 | 59 | test_that("Table 21 generation works with some NA values", { 60 | set.seed(5) 61 | df[sample(seq_len(nrow(df)), 50), "SEX"] <- NA 62 | df[sample(seq_len(nrow(df)), 30), "AGEGR1"] <- NA 63 | 64 | df <- df %>% df_explicit_na() 65 | 66 | result <- make_table_21( 67 | df = df, 68 | alt_counts_df = adsl, 69 | denom = "n", 70 | lbl_overall = "Total population", 71 | vars = c("AGEGR1", "SEX"), 72 | lbl_vars = c("Age (group)", "Sex") 73 | ) 74 | 75 | res <- expect_silent(result) 76 | expect_snapshot(res) 77 | }) 78 | -------------------------------------------------------------------------------- /tests/testthat/test-fda-table_22.R: -------------------------------------------------------------------------------- 1 | adsl <- random.cdisc.data::cadsl %>% 2 | mutate(AGEGR1 = as.factor(case_when( 3 | AGE >= 17 & AGE < 65 ~ ">=17 to <65", 4 | AGE >= 65 ~ ">=65", 5 | AGE >= 65 & AGE < 75 ~ ">=65 to <75", 6 | AGE >= 75 ~ ">=75" 7 | )) %>% 8 | formatters::with_label("Age Group, years")) %>% 9 | formatters::var_relabel( 10 | AGE = "Age, years" 11 | ) 12 | 13 | adae <- random.cdisc.data::cadae 14 | 15 | df <- left_join(adsl, adae, by = intersect(names(adsl), names(adae))) 16 | 17 | test_that("Table 22 generation works with default values", { 18 | result <- make_table_22(df = df) 19 | 20 | res <- expect_silent(result) 21 | expect_snapshot(res) 22 | }) 23 | 24 | test_that("Table 22 generation works with custom values: N_s denominator and overall column", { 25 | result <- make_table_22( 26 | df = df, 27 | alt_counts_df = adsl, 28 | denom = "N_s", 29 | lbl_overall = "Total population", 30 | ) 31 | 32 | res <- expect_silent(result) 33 | expect_snapshot(res) 34 | }) 35 | 36 | test_that("Table 22 generation works with custom values: N_col denominator and no overall column", { 37 | result <- make_table_22( 38 | df = df, 39 | alt_counts_df = adsl, 40 | denom = "N_col", 41 | lbl_overall = NULL, 42 | prune_0 = TRUE, 43 | annotations = list( 44 | title = paste( 45 | "Table 22. Overview of Adverse Events1 by Demographic Subgroup, Safety Population, Pooled Analysis", 46 | "(or Trial X)" 47 | ), 48 | main_footer = c( 49 | "Source: [include Applicant source, datasets and/or software tools used].", 50 | "(1) Treatment-emergent adverse event defined as [definition]. MedDRA version X." 51 | ), 52 | prov_footer = c( 53 | "Abbreviations: MedDRA, Medical Dictionary for Regulatory Activities.;", 54 | "N, number of patients in treatment arm; n, number of patients with adverse event;", 55 | "Ns, total number of patients for each specific subgroup" 56 | ) 57 | ) 58 | ) 59 | 60 | res <- expect_silent(result) 61 | expect_snapshot(res) 62 | }) 63 | 64 | test_that("Table 22 generation works with some NA values", { 65 | set.seed(5) 66 | df[sample(seq_len(nrow(df)), 50), "SEX"] <- NA 67 | df[sample(seq_len(nrow(df)), 30), "AGEGR1"] <- NA 68 | 69 | df <- df %>% df_explicit_na() 70 | 71 | result <- make_table_22( 72 | df = df, 73 | alt_counts_df = adsl, 74 | denom = "n", 75 | lbl_overall = "Total population", 76 | vars = c("AGEGR1", "SEX"), 77 | lbl_vars = c("Age (group)", "Sex") 78 | ) 79 | 80 | res <- expect_silent(result) 81 | expect_snapshot(res) 82 | }) 83 | --------------------------------------------------------------------------------