diff --git a/DESCRIPTION b/DESCRIPTION index 1da2504..d6164de 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,19 +2,19 @@ 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 = "ABIU (Anders Bilgrau)", + person(given = "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", @@ -25,7 +25,8 @@ License: MIT + file LICENSE Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.1 -Suggests: +Suggests: + testr, covr, pkgdown, testthat, @@ -45,10 +46,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 567c2fe..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,8 +176,6 @@ p_subj_event <- #' @param ... Optional parameters. #' @return a data.table containing all statistical outputs #' @export -#' -#' @examples count_set <- function(dat, event_index, cell_index, @@ -185,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 6442840..940eeb9 100644 --- a/README.Rmd +++ b/README.Rmd @@ -3,19 +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. -[Ramnog 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 a682b6e..1298bbb 100644 --- a/README.md +++ b/README.md @@ -1,16 +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. [Ramnog -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..4bacde9 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: | @@ -31,7 +38,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 42681fe..5b2962e 100644 --- a/vignettes/add_functions.Rmd +++ b/vignettes/add_functions.Rmd @@ -32,23 +32,53 @@ To add new functions to chefStats, you follow three general steps: ### 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 didn't already exist in chefStats. - - 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: +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()`). + +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 # `event_index` and `cell_index` @@ -95,7 +125,7 @@ Here we show how we would add the function `n_subj_event()`, which counts the nu ### Interface with chef {.tabset .tabset-pills} -The statistical functions from chefStats will be called within the context of a chef pipeline. The category of the function determines what arguments are passed from chef to the function, however some arguments are passed to all categories. +The statistical functions from chefStats will be called within the context of a chef pipeline. The category of the function determines what arguments chef makes available to the function. The following table describes arguments that are passed to **all** chefStats function: @@ -122,12 +152,12 @@ dt |> table.attr = "class='table table-bordered'", caption = "Arguments always passed to chefStats functions") |> kable_styling(bootstrap_options = c("hover", "condensed", "responsive")) |> - row_spec(0, background = "lightblue") + row_spec(0, background = "#2C3E50", color="white") ```

-Additionally, each function type receives the following arguments +The tables below describe the set of arguments chef passes that vary depending on the function type: #### stat_by_strata_by_trt @@ -150,7 +180,7 @@ dt |> table.attr = "class='table table-bordered'", caption = "Additional arguments passed to by_strata_by_trt functions") |> kable_styling(bootstrap_options = c("hover", "condensed", "responsive")) |> - row_spec(0, background = "lightblue") + row_spec(0, background = "#2C3E50", color="white") ``` @@ -174,7 +204,7 @@ dt |> table.attr = "class='table table-bordered'", caption = "Additional arguments passed to by_strata_across_trt functions") |> kable_styling(bootstrap_options = c("hover", "condensed", "responsive")) |> - row_spec(0, background = "lightblue") + row_spec(0, background = "#2C3E50", color="white") ``` #### stat_by_strata_across_trt @@ -194,7 +224,7 @@ dt |> table.attr = "class='table table-bordered'", caption = "Additional arguments passed to across_strata_across_trt functions") |> kable_styling(bootstrap_options = c("hover", "condensed", "responsive")) |> - row_spec(0, background = "lightblue") + row_spec(0, background = "#2C3E50", color="white") ``` @@ -205,6 +235,6 @@ dt |> When possible, utilize building-block functions when making new statistical functions. For example, if the new functions requires a 2x2 table, use the `make_two_by_two_()` function instead of writing a new one. -This also allows you to easily write functions that collapse several chefStats functions into one function call. For example, on call to `count_set()` is the same as one call each to `n_sub()`, `n_event()`, `n_subj_event()` and `p_subj_event()`. The only rational for combining functions like this is to save compute time, due to the way chef pipelines are constructed. +This also allows you to easily write functions that collapse several chefStats functions into one function call. For example, on call to `count_set()` is the same as one call each to `n_subj()`, `n_event()`, `n_subj_event()` and `p_subj_event()`. The only rational for combining functions like this is to save compute time, due to the way chef pipelines are constructed. Building block function names are always suffixed with an underscore `_` to indicate they cannot be called from inside a chef pipeline. For example, `n_event_()` is a building block that is used to make `n_event()`, but `n_event_()` can also be use to build other functions, such as `count_set()`, because it does not format it's output for a chef pipeline. Conversely, `n_event()` does format the output, so it can be use in a chef pipeline, but not as a building block. diff --git a/vignettes/function_types.Rmd b/vignettes/function_types.Rmd index 8c4163d..5c7e643 100644 --- a/vignettes/function_types.Rmd +++ b/vignettes/function_types.Rmd @@ -71,7 +71,7 @@ dt |> table.attr = "class='table table-bordered'", caption = "Table 1") |> kable_styling(bootstrap_options = c("hover", "condensed", "responsive")) |> - row_spec(0, background = "lightblue") |> + row_spec(0, background = "#2C3E50", color="white") |> column_spec(1, bold = TRUE, width = "10em",) ```