From 18abe6ea0e63fd05471509e1100d9e0e7bf4341e Mon Sep 17 00:00:00 2001 From: Matthew Phelps Date: Fri, 12 Apr 2024 11:34:53 +0200 Subject: [PATCH] Update website (#19) * Updating website and various minor corrections --- DESCRIPTION | 17 ++- NAMESPACE | 2 +- R/building_blocks.R | 4 +- R/by_strata_by_trt.R | 5 +- R/use_chefStats.R | 43 +++++- README.Rmd | 26 +++- README.md | 34 ++++- _pkgdown.yml | 10 +- .../template-stat_by_strata_by_trt.R | 6 +- man/{n_sub_.Rd => n_subj_.Rd} | 6 +- pkgdown/extra.css | 35 +---- tests/testthat/test-use_chefStats.R | 6 + vignettes/add_functions.Rmd | 138 +++++++++++------- vignettes/function_types.Rmd | 2 +- 14 files changed, 217 insertions(+), 117 deletions(-) rename man/{n_sub_.Rd => n_subj_.Rd} (89%) create mode 100644 tests/testthat/test-use_chefStats.R diff --git a/DESCRIPTION b/DESCRIPTION index 269aeba..b683f6a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,22 +2,22 @@ Package: chefStats Title: Provide methods for different statistics Version: 0.1.1 Authors@R: - c(person(given = "MEWP (Matthew Phelps)", + c(person(given = "Matthew David Phelps", role = "aut", email = "mewp@novonordisk.com"), - person(given = "NOSJ (Nicolai Skov Johnsen)", + person(given = "Nicolai Skov Johnsen", role = "aut", email = "nosj@novonordisk.com"), - person(given = "HSPU (Henrik Sparre Spiegelhauer)", + person(given = "Henrik Sparre Spiegelhauer", role = "aut", email = "hspu@novonordisk.com"), person(given = "ABIU (Anders Bilgrau)", role = "aut", email = "abiu@novonordisk.com"), - person(given = "SCQY (scqy)", + person(given = "Simon Clancy", role = "aut", email = "scqy@novonordisk.com"), - person(given = "CINO (Christian Haargaard Olsen)", + person(given = "Christian Haargaard Olsen", role = c("aut", "cre"), email = "cino@novonordisk.com"), person(given = "Novo Nordisk A/S", @@ -28,7 +28,8 @@ License: MIT + file LICENSE Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.1 -Suggests: +Suggests: + testr, covr, pkgdown, testthat, @@ -48,10 +49,12 @@ Imports: cli, usethis Remotes: - hta-pharma/chef + hta-pharma/chef, + matthew-phelps/testr Config/testthat/edition: 3 VignetteBuilder: knitr Config/testthat/parallel: true URL: https://hta-pharma.github.io/chefStats/, + https://github.com/hta-pharma/chefStats, https://app.codecov.io/github/hta-pharma/chefStats diff --git a/NAMESPACE b/NAMESPACE index c65874d..7fb6e64 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -13,8 +13,8 @@ export(mean_value) export(n_event) export(n_event_) export(n_event_100y) -export(n_sub_) export(n_subj) +export(n_subj_) export(n_subj_event) export(n_subj_event_) export(obs_time_by_trt) diff --git a/R/building_blocks.R b/R/building_blocks.R index 4e79059..3c59b30 100644 --- a/R/building_blocks.R +++ b/R/building_blocks.R @@ -11,7 +11,7 @@ #' @return An integer #' @export #' -n_sub_ <- +n_subj_ <- function(dat, cell_index, subjectid_var) { @@ -72,7 +72,7 @@ p_subj_event_ <- cell_index, intersect_index, subjectid_var) { - n_sub <- n_sub_(dat, cell_index = cell_index,subjectid_var = subjectid_var) + n_sub <- n_subj_(dat, cell_index = cell_index,subjectid_var = subjectid_var) # If there are no subjects, no need for further calculations if (n_sub == 0) { diff --git a/R/by_strata_by_trt.R b/R/by_strata_by_trt.R index c364e78..74b691e 100644 --- a/R/by_strata_by_trt.R +++ b/R/by_strata_by_trt.R @@ -18,7 +18,7 @@ n_subj <- function(dat, subjectid_var, ...) { stat <- - n_sub_(dat = dat, + n_subj_(dat = dat, cell_index = cell_index, subjectid_var = subjectid_var) @@ -176,7 +176,6 @@ p_subj_event <- #' @param ... Optional parameters. #' @return a data.table containing all statistical outputs #' @export -#' count_set <- function(dat, event_index, cell_index, @@ -184,7 +183,7 @@ count_set <- function(dat, ...) { intersect_index <- intersect(event_index, cell_index) n_subjects <- - n_sub_(dat = dat, + n_subj_(dat = dat, cell_index = cell_index, subjectid_var = subjectid_var) n_events <- n_event_(dat = dat, intersect_index = intersect_index) diff --git a/R/use_chefStats.R b/R/use_chefStats.R index f7abfc8..4b5a0e0 100644 --- a/R/use_chefStats.R +++ b/R/use_chefStats.R @@ -18,9 +18,10 @@ use_chefStats <- "stat_across_strata_across_trt" ), file_name = NULL) { + check_use_chefStats_inputs(fn_name) type <- match.arg(fn_type) fn_path <- - normalizePath(file.path("R", paste0(fn_name, ".R")), mustWork = FALSE) + file.path("R", paste0(fn_name, ".R")) switch( type, stat_by_strata_by_trt = usethis::use_template( @@ -48,3 +49,43 @@ use_chefStats <- ) } + +error_no_dir <- function(dir){ + if (!dir.exists(dir)) { + stop(paste0("Directory ", dir, " does not exist")) + } +} + +extract_function_names <- function(dir) { + x <- list.files(dir, full.names = TRUE, pattern = "*.[Rr]") + fn_names_ls <- lapply(x, function(i) { + lang_objs <- Filter(is.language, parse(i)) + fun_entries <- + Filter(function(x) { + grepl(", function", toString(x)) + }, lang_objs) + sapply(fun_entries, function(fun_entry_i) { + trimws(strsplit(toString(fun_entry_i), ",")[[1]][2]) + }) + }) + unlist(fn_names_ls) +} +error_function_already_exists <- function(new_fn_name, existing_fn_names){ + fn_exists <- any(new_fn_name == existing_fn_names) + if (!fn_exists) { + return(invisible(TRUE)) + } + msg <- paste0( + "The function name `", + new_fn_name, + "` already exists. Please choose another name" + ) + stop(msg,call. = FALSE) +} + +check_use_chefStats_inputs <- function(new_fn_name, dir = "R/"){ + error_no_dir(dir) + existing_fn_names <- extract_function_names(dir) + error_function_already_exists(new_fn_name, existing_fn_names) + return(invisible(TRUE)) +} diff --git a/README.Rmd b/README.Rmd index f2ce755..940eeb9 100644 --- a/README.Rmd +++ b/README.Rmd @@ -3,18 +3,30 @@ output: github_document --- +# chefStats chefStats website -# A library of statistical methods for chef-style AMNOG analyses chefStats website +A library of statistical methods for chef-style AMNOG analyses -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = TRUE) -``` +# Aim The {chefStats} package aims to provide a library of fast, validated methods for use in AMNOG analysis created by the chef package. -As the functions found in chefStats are designed to be used with chef, it may be unwieldy to use these functions independently. +As the functions found in chefStats are designed to be used with [chef](https://hta-pharma.github.io/chef) in the context of the [ramnog](https://hta-pharma.github.io/ramnog) framework, it may be unwieldy to use these functions independently. + + +# Installation + +The package is available to install from GitHub: + +```{r, eval=FALSE} +remotes::install_github("hta-pharma/chefStats") +``` + + +# How to contribute +For information on how to contribute, please refer to [ramnog contributing documentation](https://hta-pharma.github.io/ramnog/articles/dev_contribute). -# Developer Documentation +# More information -Please refer to {ramnog} for general [developer documentation](https://hta-pharma.github.io/ramnog/articles/#:~:text=Debugging-,Development,-Git%20Workflow). +These site focuses on the functions of chefStats. For more context on how these functions should be utilized to produce an AMNOG-like analysis, please see the [ramnog](https://hta-pharma.github.io/ramnog) documentation. diff --git a/README.md b/README.md index abdca04..1298bbb 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,37 @@ -# A library of statistical methods for chef-style AMNOG analyses chefStats website +# chefStats chefStats website + +A library of statistical methods for chef-style AMNOG analyses + +# Aim The {chefStats} package aims to provide a library of fast, validated methods for use in AMNOG analysis created by the chef package. -As the functions found in chefStats are designed to be used with chef, -it may be unwieldy to use these functions independently. +As the functions found in chefStats are designed to be used with +[chef](https://hta-pharma.github.io/chef) in the context of the +[ramnog](https://hta-pharma.github.io/ramnog) framework, it may be +unwieldy to use these functions independently. + +# Installation + +The package is available to install from GitHub: + +``` r +remotes::install_github("hta-pharma/chefStats") +``` + +# How to contribute + +For information on how to contribute, please refer to [ramnog +contributing +documentation](https://hta-pharma.github.io/ramnog/articles/dev_contribute). -# Developer Documentation +# More information -Please refer to {ramnog} for general [developer -documentation](https://hta-pharma.github.io/ramnog/articles/#:~:text=Debugging-,Development,-Git%20Workflow). +These site focuses on the functions of chefStats. For more context on +how these functions should be utilized to produce an AMNOG-like +analysis, please see the [ramnog](https://hta-pharma.github.io/ramnog) +documentation. diff --git a/_pkgdown.yml b/_pkgdown.yml index d6e6c4b..377f33f 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,6 +1,13 @@ url: https://hta-pharma.github.io/chefStats/ template: bootstrap: 5 + bootswatch: flatly + +navbar: + structure: + left: [intro, articles, reference, news] + right: [github] + reference: - title: By strata and treatment level desc: | @@ -11,6 +18,7 @@ reference: - n_subj_event - p_subj_event - count_set + - count_set - title: By strata, across treatment levels desc: | Function that operate by strata level but across treatment levels @@ -31,7 +39,7 @@ reference: - barnard_test_ - make_two_by_two_by_k_ - make_two_by_two_ - - n_sub_ + - n_subj_ - n_event_ - n_subj_event_ - p_subj_event_ diff --git a/inst/templates/template-stat_by_strata_by_trt.R b/inst/templates/template-stat_by_strata_by_trt.R index 15cd0c3..417b418 100644 --- a/inst/templates/template-stat_by_strata_by_trt.R +++ b/inst/templates/template-stat_by_strata_by_trt.R @@ -15,11 +15,7 @@ #' @export #' #' @examples -{ - { - fn_name - } -} <- function(dat, +{{fn_name}} <- function(dat, event_index, cell_index, strata_var, diff --git a/man/n_sub_.Rd b/man/n_subj_.Rd similarity index 89% rename from man/n_sub_.Rd rename to man/n_subj_.Rd index 0a6a257..3f9be64 100644 --- a/man/n_sub_.Rd +++ b/man/n_subj_.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/building_blocks.R -\name{n_sub_} -\alias{n_sub_} +\name{n_subj_} +\alias{n_subj_} \title{Building-block: Number of subjects} \usage{ -n_sub_(dat, cell_index, subjectid_var) +n_subj_(dat, cell_index, subjectid_var) } \arguments{ \item{dat}{data.table. The analysis data set.} diff --git a/pkgdown/extra.css b/pkgdown/extra.css index 0d5030b..0d925e7 100644 --- a/pkgdown/extra.css +++ b/pkgdown/extra.css @@ -1,31 +1,8 @@ -.navbar-inverse { - background-color: #033572; +.dropdown-header { + font-size: 1.2rem; + color: #494646; + font-weight: 700; } -.navbar-inverse .navbar-brand { - color: #BDB5AB; -} -.navbar-inverse .navbar-nav>li>a { - color: #BDB5AB; -} -.navbar-inverse .navbar-nav>.active>a { - background-color: #033572; -} -.navbar-inverse .navbar-nav>.active:hover>a { - background-color: #0069B4; -} -.list-group-item.active { - background-color: #033572; - border-color: #033572; -} -item.active, .list-group-item.active:hover { - background-color: #0069B4; - border-color: #0069B4; -} - - -.center { - display: block; - margin-left: auto; - margin-right: auto; - width: 50%; +.text-muted { + color: #8f9c9d !important; } diff --git a/tests/testthat/test-use_chefStats.R b/tests/testthat/test-use_chefStats.R new file mode 100644 index 0000000..e8eb7d0 --- /dev/null +++ b/tests/testthat/test-use_chefStats.R @@ -0,0 +1,6 @@ +test_that("use_chefStats errors when given function name that already exists", { + testr::create_local_project() + dump("n_subj", file = "R/test.R") + expect_error(use_chefStats(fn_name = "n_subj",fn_type = "stat_by_strata_by_trt"),regexp = "The function name") + +}) diff --git a/vignettes/add_functions.Rmd b/vignettes/add_functions.Rmd index 653adc3..c576d86 100644 --- a/vignettes/add_functions.Rmd +++ b/vignettes/add_functions.Rmd @@ -21,52 +21,79 @@ library(data.table) library(kableExtra) ``` -To add new functions to {chefStats}, you must follow these four general steps: +To add new functions to chefStats, you follow four general steps: - 1. Consider what type of function you need: `stat_by_strata_by_trt`, `stat_by_strata_across_trt` or `stat_across_strata_across_trt`. See article [Function types](https://hta-pharma.github.io/chefStats/articles/function_types.html. - 2. Decide what information the function needs in order to compute the desired results. See section [Interface with {chef}](#interface-with-chef) + 1. Consider what type of function you need: `stat_by_strata_by_trt`, `stat_by_strata_across_trt` or `stat_across_strata_across_trt` (see article [Function types](https://hta-pharma.github.io/chefStats/articles/function_types.html). + 2. Decide what information the function needs in order to compute the desired results. See section [Interface with chef](#interface-with-chef) 3. Write the function definition (use `use_chefStats()` to help create the template) 4. Write the appropriate unit-tests for the function (using [testthat](https://testthat.r-lib.org/) framework)
-### Walkthrough example +### Walk through example -Here we show how we would add the function `n_subj_event()`, which counts the number of subjects experiencing the event by stratification level and treatment level, if it did not already exist in {chefStats}. +Here we show how we would add a function which counts the number of subjects experiencing the event by stratification level and treatment level, if it didn't already exist in chefStats (`n_subj_event()`). - 1. Since the function produces a number by stratification level and by treatment level, this will be a `stat_by_strata_by_trt` - 2. The function will need to know. See section [Interface with chef](#interface-with-chef) for more details on how to pass this information from {chef} to {chefStats}: - - Who was eligible to have the event - - Who has the event - - What the stratification "group" (e.g. SEX, AGE, etc) and level ("MALE", ">65", etc.) is - - What the treatment level is (e.g. "TreatmentA") - 3. The function definition might look like this: +This is the workflow for writing such a function from scratch: + + 1. Decide which function type it is (see article [Function types](https://hta-pharma.github.io/chefStats/articles/function_types.html). Since the function produces a number by stratification level and by treatment level, this will be a `stat_by_strata_by_trt`. + 2. Call `use_chefStats(fn_name = "num_subj_events", fn_type = "stat_by_strata_by_trt")`. This will produce a template R function that has the correct arguments for what is passed by the chef pipeline to `stat_by_strata_by_trt`-type functions (see section [Interface with chef](#interface-with-chef) for more details. The skeleton function will look like this: +```{r, eval=FALSE} +num_subj_events <- function(dat, + event_index, + cell_index, + strata_var, + strata_val, + treatment_var, + treatment_val, + subject_id, + ...) { + # Function body here: + + # The final object retuned needs to be a data.table with the following format: + return( + data.table::data.table( + label = NA_character_, + value = NA_real_, + description = NA_character_ + ) + ) +} +``` + + 3. Remove unneeded arguments. For our specific function, we only need the following variables: + - `cell_index` Who was eligible to have the event + - `event_index` Who has the event + - `subject_id` Allows us to count unique people + - `...` The elipses always have to be included in any chefStat function + So we can delete the others arguments. The additional arguments will still be passed to the function by the chef pipeline, but they will be collected by `...` and not used. + + 3. Modify the function definition for our needs. The final function definition might look like this: ```{r, eval=FALSE} - n_subj_event <- +num_subj_events <- function(dat, event_index, cell_index, subjectid_var, - ... # the `...` are required for all {chefStats} functions to "collect" any unused arguments passed from {chef} - ) { - # Please see the "Interface with {chef}" section for details on what + ...) { + # Please see the "Interface with chef" section for details on what # `event_index` and `cell_index` - + # `intersect()` provides us with a vector of rows in `dat` that match both # `event_index` and `cell_index` - aka records that were BOTH eligible to # have the event (`cell_index`) AND had the event (`event_index`) index <- intersect(event_index, cell_index) - + # Return all matching rows in `dat` where `INDEX_` # matches `index`. event_rows <- dat[INDEX_ %in% index] - + # `dat` contains event data, meaning subjects can appear more than once if # they have >1 event, so we need to remove these extra rows to get a proper # count event_rows_unique_by_subject <- unique(event_rows, by = subjectid_var) - + stat <- NROW(event_rows_unique_by_subject) # The return object has to be a data.table object with the following 3 @@ -78,10 +105,7 @@ Here we show how we would add the function `n_subj_event()`, which counts the nu value = as.double(stat) ) ) - } - - ```