Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export(PKNCA_build_units_table)
export(PKNCA_calculate_nca)
export(PKNCA_create_data_object)
export(PKNCA_hl_rules_exclusion)
export(PKNCA_impute_method_end_conc_drop)
export(PKNCA_impute_method_start_c1)
export(PKNCA_impute_method_start_logslope)
export(PKNCA_update_data_object)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* Partial interval parameters section supports calculations beyond `AUCINT`: `RCAMINT`, `AUCINTD`, `CAVGINT`, and others. Table starts empty by default with a Remove Row button (#524, #1249)
* "Min. Points for Half-life" setting added (range 2–10, default 3) (#1155)
* BLQ imputation rules via `NCA Setup > Data Imputation` (#139)
* "Drop End Concentration" switch in `NCA Setup > Data Imputation` drops the concentration at the end of each non-last main interval before regular parameter calculations, so a next-dose boundary point (e.g. an imputed C0) does not affect the previous dose profile. Partial/interval parameters and the last dose profile per group are unaffected (#1411)
* General Exclusions section for in-app NCA exclusions, with "Excl. TLG" checkbox per entry (#851, #1018)
* Parameter Exclusions tab: exclude individual PK parameter rows from descriptive statistics and ADPP export via PPSUMFL/PPSUMRSN flags (#1040)
* NCA flag rules (NCAwXRS) from ADNCA standards — flagged records are excluded from NCA (#752)
Expand Down
46 changes: 45 additions & 1 deletion R/PKNCA.R
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ PKNCA_create_data_object <- function( # nolint: object_name_linter
#' (forwarded to [update_main_intervals()]).
#' @param blq_imputation_rule Optional list defining the BLQ imputation rule
#' (forwarded to [update_main_intervals()]).
#' @param drop_end_conc Logical indicating whether to drop the concentration at
#' the end of each main interval for regular parameters (forwarded to
#' [update_main_intervals()]). Default `FALSE`.
#' @param custom_units_table Optional data frame with PPSTRESU overrides.
#' When provided, applied via [dplyr::rows_update()] on the PKNCAdata units table.
#'
Expand All @@ -308,6 +311,7 @@ PKNCA_update_data_object <- function( # nolint: object_name_linter
parameter_selections = NULL,
int_parameters = NULL,
blq_imputation_rule = NULL,
drop_end_conc = FALSE,
custom_units_table = NULL) {

data <- adnca_data
Expand Down Expand Up @@ -371,7 +375,8 @@ PKNCA_update_data_object <- function( # nolint: object_name_linter
parameter_selections = parameter_selections,
int_parameters = int_parameters,
impute = start_impute,
blq_imputation_rule = blq_imputation_rule
blq_imputation_rule = blq_imputation_rule,
drop_end_conc = drop_end_conc
)

# Apply custom units table
Expand Down Expand Up @@ -583,6 +588,45 @@ PKNCA_impute_method_start_c1 <- function(conc, time, start, end, ..., options =
d_conc_time
}

#' Drop the concentration measured exactly at the end of the interval
#'
#' Removes a concentration sitting exactly at `time == end` for an interval, if
#' one is present (no-op otherwise). This is typically used with multiple-dose
#' data where the boundary point belongs to the next dose (e.g. an imputed C0),
#' so it should not contribute to parameters on the current interval.
#'
#' @param conc Numeric vector of concentrations.
#' @param time Numeric vector of times corresponding to the concentrations.
#' @param end Numeric value (or vector) indicating the end time of the interval.
#' @param ... Additional arguments (currently not used).
#' @param options List of options (currently not used).
#'
#' @returns A data frame of `conc`/`time` with any end-boundary point removed.
#' @details
#' This function adheres to the structure required by the `PKNCA` package to work
#' with its imputation functionality. For more information, see the
#' [PKNCA Data Imputation Vignette](https://CRAN.R-project.org/package=PKNCA).
#'
#' TODO(end_conc_drop): remove this local copy once humanpred/pknca#572 is merged
#' and aNCA depends on a PKNCA release that exports
#' `PKNCA_impute_method_end_conc_drop()`. At that point drop this definition and
#' the corresponding `@export`/NAMESPACE entry and rely on the PKNCA-native method.
#' @export
#'
#' @examples
#' conc <- c(10, 5, 1)
#' time <- c(0, 12, 24)
#' end <- 24
#' PKNCA_impute_method_end_conc_drop(conc, time, end)
PKNCA_impute_method_end_conc_drop <- function(conc, time, end, ..., options = list()) { # nolint
d_conc_time <- data.frame(conc = conc, time = time)
mask_end <- time %in% end
if (any(mask_end)) {
d_conc_time <- d_conc_time[!mask_end, , drop = FALSE]
}
d_conc_time
}

#' Build Units Table for PKNCA
#'
#' This function generates a PKNCA units table including the potential unit segregating columns
Expand Down
40 changes: 38 additions & 2 deletions R/intervals.R
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,15 @@ format_pkncadata_intervals <- function(pknca_conc,
#' Each element can be a numeric value (substituting the BLQ value), or a string such as
#' `"drop"` (ignores the value) or `"keep"` (keeps the value as 0). Default is NULL,
#' which does not specify any BLQ imputation in any interval.
#' @param drop_end_conc Logical. If `TRUE`, the concentration measured exactly at
#' the end of each main interval is dropped before regular (non-partial) parameter
#' calculations via the `end_conc_drop` imputation. This does not affect
#' interval/partial parameter rows (`type_interval == "manual"`) nor the last dose
#' profile per concentration group, whose end-boundary point is a genuine terminal
#' sample rather than a next-dose C0. Default `FALSE`.
#'
#' @importFrom dplyr left_join mutate across where select all_of if_else bind_rows filter
#' @importFrom dplyr group_by ungroup slice_max distinct
#' @importFrom dplyr group_by ungroup slice_max distinct group_vars
#' @importFrom purrr pmap
#' @returns An updated PKNCAdata object with parameter intervals based on user selections.
#' @export
Expand All @@ -217,7 +223,8 @@ update_main_intervals <- function(
parameter_selections = NULL,
int_parameters = NULL,
impute = TRUE,
blq_imputation_rule = NULL
blq_imputation_rule = NULL,
drop_end_conc = FALSE
) {

if (is.null(parameter_selections)) parameter_selections <- list()
Expand Down Expand Up @@ -309,6 +316,35 @@ update_main_intervals <- function(
# Remove any imputation from the observational parameters
data <- rm_impute_obs_params(data, metadata_nca_parameters)

############################################
# Drop the end-boundary concentration for main intervals. Applied after
# rm_impute_obs_params() so it also covers observational parameters (e.g. Cmax,
# Tmax), where a spurious concentration at time == end would otherwise distort
# the result. Partial/interval parameters (type_interval == "manual") are
# untouched. The last dose profile per concentration group is also left
# untouched: its end-boundary point is a genuine terminal sample (the interval
# end is finite only because there is no next dose), not a next-dose C0.
if (isTRUE(drop_end_conc)) {
conc_groups <- intersect(group_vars(data$conc), names(data$intervals))
data$intervals <- data$intervals %>%
group_by(across(all_of(conc_groups))) %>%
mutate(
.is_last_main = type_interval == "main" &
start == suppressWarnings(max(start[type_interval == "main"])),
impute = ifelse(
type_interval == "main" & !.is_last_main,
ifelse(
is.na(impute) | impute == "",
"end_conc_drop",
paste0(impute, ", end_conc_drop")
),
impute
)
) %>%
ungroup() %>%
select(-.is_last_main)
}

data
}

Expand Down
1 change: 1 addition & 0 deletions R/zzz.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
".dose_time",
".facet_label_values",
".facet_n",
".is_last_main",
".pp_excl",
".pp_excl_reason",
".ROWID",
Expand Down
11 changes: 1 addition & 10 deletions inst/WORDLIST
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ AEFRLT
AFRLT
ARRLT
ATPTREF
AUCIFOD
Comment thread
Shaakon35 marked this conversation as resolved.
AUCINT
AUCLSTD
AUCPEO
AUCPEP
AUCall
Expand All @@ -28,7 +26,6 @@ Bioavailability
Buckeridge
CDISC
CMAX
CMAXD
CRITy
CRITyFL
Clast
Expand Down Expand Up @@ -148,7 +145,6 @@ adnca
analysing
analyte
analytes
aucint
aucpext
aucs
bioavailability
Expand Down Expand Up @@ -176,6 +172,7 @@ frac
ggplot
ggplots
hardcoded
humanpred
ifelse
img
intravascular
Expand All @@ -187,15 +184,12 @@ logslope
mL
macroparameters
md
multidose
nav
nca
ng
normalised
oligo
pak
pc
pcspec
pharmacodynamics
pharmacokinetic
pharmacokinetics
Expand All @@ -204,20 +198,17 @@ pkgdown
pknca
plotly
pptest
pptestcd
pre
pred
px
qmd
rds
renderable
reproducibility
resizable
reupload
roadmap
rpptx
runnable
scrollable
selectable
signif
src
Expand Down
3 changes: 2 additions & 1 deletion inst/shiny/modules/tab_nca/nca_setup.R
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ nca_setup_server <- function(id, data, adnca_data, extra_group_vars, settings_ov
min_hl_points = settings()$min_hl_points,
parameter_selections = parameters_output$selections(),
int_parameters = settings()$int_parameters,
blq_imputation_rule = settings()$data_imputation$blq_imputation_rule
blq_imputation_rule = settings()$data_imputation$blq_imputation_rule,
drop_end_conc = settings()$data_imputation$drop_end_conc
)

# Wait for study types to settle during reactive transitions
Expand Down
44 changes: 44 additions & 0 deletions inst/shiny/modules/tab_nca/setup/data_imputation.R
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,44 @@ data_imputation_ui <- function(id) {
width = "500px"
)
)
),
hr(),
# Drop end-of-interval concentration widget and help button
fluidRow(
column(
width = 10,
input_switch(
id = ns("drop_end_conc"),
label = "Drop End Concentration",
value = FALSE
)
),
column(
width = 2,
dropdown(
div(
tags$h2("Drop End Concentration Help"),
p(
"Drops the concentration measured exactly at the end of each",
"interval before regular (non-partial) parameter calculations.",
"Only applies to main intervals; partial/interval parameters are",
"left untouched."
),
p(
"This is useful for multiple-dose data where the concentration at",
"the interval end really belongs to the next dose (e.g. an imputed",
"C0). Including it can distort parameters such as Cmax, Tmax and AUC;",
"genuine troughs are unaffected when the point does not sit exactly",
"at the interval end."
)
),
style = "unite",
right = TRUE,
icon = icon("question"),
status = "primary",
width = "500px"
)
)
)
)
}
Expand All @@ -149,6 +187,11 @@ data_imputation_server <- function(id, settings_override) {
update_switch("should_impute_c0", value = imputation$impute_c0)
}

# Restore drop_end_conc switch
if (!is.null(imputation$drop_end_conc)) {
update_switch("drop_end_conc", value = imputation$drop_end_conc)
}

# Restore BLQ strategy dropdown
valid_strategies <- c(
"Tmax based imputation",
Expand Down Expand Up @@ -249,6 +292,7 @@ data_imputation_server <- function(id, settings_override) {

list(
should_impute_c0 = reactive(input$should_impute_c0),
drop_end_conc = reactive(input$drop_end_conc),
blq_strategy = reactive(input$select_blq_strategy),
blq_imputation_rule = blq_imputation_rule
)
Expand Down
1 change: 1 addition & 0 deletions inst/shiny/modules/tab_nca/setup/settings.R
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ settings_server <- function(id, data, adnca_data, settings_override) {
min_hl_points = input$min_hl_points,
data_imputation = list(
impute_c0 = data_imputation$should_impute_c0(),
drop_end_conc = data_imputation$drop_end_conc(),
blq_strategy = data_imputation$blq_strategy(),
blq_imputation_rule = data_imputation$blq_imputation_rule()
),
Expand Down
1 change: 1 addition & 0 deletions inst/www/templates/clinical_template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ settings:
method: lin up/log down
data_imputation:
impute_c0: yes
drop_end_conc: no
blq_strategy: No BLQ handling
blq_imputation_rule:
first: keep
Expand Down
1 change: 1 addition & 0 deletions inst/www/templates/preclinical_LM_template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ settings:
bioavailability: f_aucinf.obs
data_imputation:
impute_c0: yes
drop_end_conc: no
blq_strategy: Set value for all BLQ
blq_imputation_rule:
first: drop
Expand Down
1 change: 1 addition & 0 deletions inst/www/templates/preclinical_SM_template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ settings:
bioavailability: f_aucinf.obs
data_imputation:
impute_c0: yes
drop_end_conc: no
blq_strategy: Set value for all BLQ
blq_imputation_rule:
first: drop
Expand Down
1 change: 1 addition & 0 deletions inst/www/templates/script_template.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pknca_obj <- adnca_data %>%
selected_profile = settings_list$settings$profile,
selected_pcspec = settings_list$settings$pcspec,
start_impute = settings_list$settings$data_imputation$impute_c0,
drop_end_conc = settings_list$settings$data_imputation$drop_end_conc %||% FALSE,
exclusion_list = settings_list$settings$general_exclusions,
hl_adj_rules = slope_rules,
keep_interval_cols = setdiff(extra_vars_to_keep, c("DOSEA", "ATPTREF", "ROUTE")),
Expand Down
1 change: 1 addition & 0 deletions inst/www/templates/settings_template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ settings:
bioavailability: f_aucinf.obs
data_imputation:
impute_c0: yes
drop_end_conc: no
blq_strategy: No BLQ handling
blq_imputation_rule:
first: keep
Expand Down
44 changes: 44 additions & 0 deletions man/PKNCA_impute_method_end_conc_drop.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading