Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ inst/shiny/log/*
.DS_Store
# {shinytest2}: Ignore new debug snapshots for `$expect_values()`
*_.new.png
desktop.ini
desktop.ini
CLAUDE.md
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
* DOSNOA computation fixed for specimen-level grouping — urine-only data no longer gets incorrect dose numbering (#1116)
* Dose-aware AUCint parameters now share the same PPTESTCD as their non-dose-aware counterparts in CDISC exports, with `PPANMETH` indicating the analytical method. Internal PPTESTCDs renamed from misleading `D` suffix (e.g. `AUCINTD`) to lowercase `da` suffix (e.g. `AUCINTda`). Fixed wrong PPTEST label for `AUCINTD` which said "Normalized by Dose" (#1242)
* Optional settings (`slope_rules`, `int_parameters`, `ratio_table`) are now normalized to `NULL` when empty, instead of persisting as 0-row data frames throughout the app and settings pipeline (#1262)
* Fixed `PKNCA_impute_method_FALSE` error when YAML settings contain `impute_c0: no` — the `impute` column is now initialized before BLQ imputation is applied to prevent dplyr from resolving to the boolean function parameter (#1266)
* Interval-specific parameters (`aucint.*`, `cav.int.*`) excluded from the Parameter Selection matrix — they require finite sub-intervals and must be configured via Partial Interval Calculations (#1309)

### Ratio Calculations
Expand Down
16 changes: 15 additions & 1 deletion R/PKNCA.R
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,20 @@ remove_pp_not_requested <- function(pknca_res) {
pknca_res$data$intervals$impute <- NA_character_
}

# Build explicit match columns: PKNCA groups + interval identifiers only.
# Exclude user-specified keep_interval_cols (e.g. AGE, SEX) which are
# not needed for parameter-request matching and may cause type-mismatch
# errors when dplyr strict-join sees incompatible types across data frames.
pknca_groups <- unique(c(
group_vars(pknca_res$data$conc),
group_vars(pknca_res$data$dose)
))
match_cols <- unique(c(
pknca_groups,
"start", "end", "ATPTREF", "DOSNOA", "type_interval"
))
match_cols <- intersect(match_cols, names(pknca_res$data$intervals))

# Reshape intervals, filter
params_not_requested <- pknca_res$data$intervals %>%
pivot_longer(
Expand All @@ -906,7 +920,7 @@ remove_pp_not_requested <- function(pknca_res) {
values_to = "is_requested"
) %>%
mutate(PPTESTCD = translate_terms(PPTESTCD, "PKNCA", "PPTESTCD")) %>%
group_by(across(c(-impute, -is_requested))) %>%
group_by(across(all_of(c(match_cols, "PPTESTCD")))) %>%
summarise(
is_requested = any(is_requested),
.groups = "drop"
Expand Down
7 changes: 7 additions & 0 deletions R/intervals.R
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ update_main_intervals <- function(
data <- create_start_impute(data)
}

# Ensure impute column exists so dplyr mutate below references the column
# rather than the function parameter (which could be FALSE from YAML settings,
# causing "PKNCA_impute_method_FALSE" not found error).
if (!"impute" %in% names(data$intervals)) {
data$intervals$impute <- NA_character_
}

############################################
# Define a BLQ imputation method for PKNCA
# and apply it only for non-observational parameters
Expand Down
38 changes: 38 additions & 0 deletions R/ratio_calculations.R
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ calculate_ratios.data.frame <- function(
)
group_cols <- setdiff(colnames(data), extra_res_cols)

# Parse group column values to match the types in the data.
# YAML-sourced settings store all values as character, but the
# corresponding columns in PKNCA results may be numeric (e.g. AGE).
# Without type coercion, merge() and anti_join() fail with
# "Can't join due to incompatible types".
ref_groups <- .coerce_group_types(ref_groups, data)
if (!is.null(test_groups)) {
test_groups <- .coerce_group_types(test_groups, data)
}

# Define the reference and test data based on the parameters and groups
df_ref <- as.data.frame(data)[data$PPTESTCD == ref_parameter, , drop = FALSE]
df_ref <- merge(df_ref, ref_groups)
Expand Down Expand Up @@ -468,6 +478,34 @@ calculate_ratio_app <- function(
list(test_groups = test_groups, ref_groups = ref_groups)
}

#' Coerce group column types to match the corresponding columns in data.
#'
#' When group specifications are sourced from YAML settings, all values
#' are character strings. If the PKNCA result data has those columns as
#' numeric (e.g. AGE), joins will fail with incompatible type errors.
#' This helper converts group columns to match the data column types.
#'
#' @param groups A data.frame of group values (from `.parse_ratio_groups`).
#' @param data A data.frame with the PKNCA result data.
#' @returns A data.frame with column types coerced to match `data`.
#' @noRd
.coerce_group_types <- function(groups, data) {
for (col in intersect(names(groups), names(data))) {
groups[[col]] <- utils::type.convert(groups[[col]], as.is = TRUE)
data_type <- class(data[[col]])[1]
group_type <- class(groups[[col]])[1]
if (data_type == group_type) next
if (data_type == "factor") {
groups[[col]] <- factor(groups[[col]], levels = levels(data[[col]]))
} else if (data_type %in% c("numeric", "integer")) {
groups[[col]] <- as.numeric(groups[[col]])
} else if (data_type == "character") {
groups[[col]] <- as.character(groups[[col]])
}
}
groups
}

#' Filter result data to keep only the specific interval rows for interval parameters.
#'
#' For non-interval parameters, all rows are kept. For interval parameters,
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 @@ -588,6 +588,7 @@ settings_server <- function(id, data, adnca_data, settings_override) {

if (!is.null(settings$int_parameters)) {
int_parameters(settings$int_parameters)
reset_reactable_memory()
refresh_reactable(refresh_reactable() + 1)
}

Expand Down
2 changes: 1 addition & 1 deletion inst/shiny/modules/tab_nca/setup/slope_selector.R
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ slope_selector_server <- function( # nolint
manual_slopes(click_result$manual_slopes)

# render rectable anew #
shinyjs::runjs("memory = {};") # needed to properly reset reactable.extras widgets
reset_reactable_memory()
refresh_reactable(refresh_reactable() + 1)
})

Expand Down
Loading