Skip to content

Conversation

@Gero1999
Copy link
Collaborator

@Gero1999 Gero1999 commented Jun 26, 2025

Issue

Closes #139

Description

This PR allows users to flexibly specify BLQ imputation rules from the UI and propagate these rules through the NCA data processing pipeline. The changes include both backend logic for applying BLQ imputation and frontend UI updates to let users select their preferred BLQ handling strategy.

BLQ Imputation Feature

  • Added support for user-defined BLQ imputation rules in NCA setup, enabling PKNCA flexible strategies (e.g., positional, tmax-based, value assignment, or no handling) via the new data_imputation_ui and data_imputation_server modules,
  • Extended the NCA pipeline to accept and apply BLQ imputation rules, updating relevant functions (update_main_intervals, rm_impute_obs_params)
  • Updated NEWS.md and function documentation to announce and describe the new BLQ imputation capability.
  • Registered new global variables and helper functions required for BLQ imputation in the package metadata.

Definition of Done

Note: Considering our latest conversations this feat is only in order to incorporate the options that PKNCA support. But we are not doing it with actual intention of internal use. That said, I would suggest against overcomplicating the feature options far from what PKNCA supports

  • Allows PKNCA imputation based on tmax, BLQ position or allows to introduce a particular BLQ value (i.e LLOQ/2)
  • The process affects the NCA results when relevant (missing concentrations!)

How to test

Map data > NCA settings > Test the different BLQ imputations in Data Imputation section

Use extreme value imputations (i.e, 10000) and check if the auclast is changed for profiles with BLQ values. I made modifications in data to include BLQ points (AVAL = 0), one case is the first profile (USUBJID = 11101, PCSPEC = "CSF", NCA_PROFILE = 1)

Contributor checklist

  • Code passes lintr checks
  • Code passes all unit tests
  • New logic covered by unit tests
  • New logic is documented
  • Package version is incremented

Notes to reviewer

Blocked until we figure out what to do with the potential bug in PKNCA! No need

@Gero1999 Gero1999 linked an issue Jun 26, 2025 that may be closed by this pull request
3 tasks
@Gero1999 Gero1999 marked this pull request as ready for review June 27, 2025 08:48
@Gero1999 Gero1999 requested review from js3110 and m-kolomanski June 27, 2025 08:48
Copy link
Collaborator

@js3110 js3110 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

I added some comments, and also I have noticed an issue in the handling of the BLQs, it seems to be dropping the last sample in all the options.

For example, subjid 11101 in the main branch has a slope with points 5, 6, 7, where the last point is time = 383.7, conc = 0.0063.
In this branch, that time point is gone and only 5 and 6 are there, which is not enough for slope calculations,

It seems to be the same trend for all the subjects.
This is not only an issue in the plots but also in the main results.

@Gero1999
Copy link
Collaborator Author

Hi,

I added some comments, and also I have noticed an issue in the handling of the BLQs, it seems to be dropping the last sample in all the options.

For example, subjid 11101 in the main branch has a slope with points 5, 6, 7, where the last point is time = 383.7, conc = 0.0063. In this branch, that time point is gone and only 5 and 6 are there, which is not enough for slope calculations,

It seems to be the same trend for all the subjects. This is not only an issue in the plots but also in the main results.

@js3110 Hey, I indeed changed the Dummy_complex_data.csv so all AVAL<0.05 = BLQ, just for the sake of creating examples that can be tested. So if you use the standard BLQ imputation, all points after tmax that were lower than 0.05 will be drop. This is in theory the right approach! Could it be that the "issue" you observed?

@js3110
Copy link
Collaborator

js3110 commented Jun 27, 2025

@js3110 Hey, I indeed changed the Dummy_complex_data.csv so all AVAL<0.05 = BLQ, just for the sake of creating examples that can be tested. So if you use the standard BLQ imputation, all points after tmax that were lower than 0.05 will be drop. This is in theory the right approach! Could it be that the "issue" you observed?

I observed that the last point was dropped for all options selected- including when I chose "keep"- so I don't think thats correct?

@Gero1999
Copy link
Collaborator Author

Gero1999 commented Jul 1, 2025

dataset is back to what it used for simplification so lambda can still be calculated for first profile. You can still test the thing thanks to the predoses

@Gero1999 Gero1999 requested a review from js3110 July 1, 2025 08:47
@Shaakon35 Shaakon35 added this to aNCA Jul 3, 2025
@Shaakon35 Shaakon35 removed this from aNCA Jul 3, 2025
@Gero1999
Copy link
Collaborator Author

Gero1999 commented Jul 7, 2025

@js3110 @m-kolomanski Not sure what is the best to do here. Due to the potential discovered bug already reported in PKNCA (here), using a BLQ rule with tmax.before = "drop" or first = "drop" seems to cause the drop of the start_conc0 imputation in extravascular studies.

I opened a discussion in PKNCA to figure out if this is indeed the situation and needs a fix (humanpred/pknca#447) But maybe @billdenney can confirm if this is the issue or if he knows of a workaround for it

@Gero1999 Gero1999 marked this pull request as draft July 7, 2025 06:36
@js3110
Copy link
Collaborator

js3110 commented Jul 8, 2025

@js3110 @m-kolomanski Not sure what is the best to do here. Due to the potential discovered bug already reported in PKNCA (here), using a BLQ rule with tmax.before = "drop" or first = "drop" seems to cause the drop of the start_conc0 imputation in extravascular studies.

I opened a discussion in PKNCA to figure out if this is indeed the situation and needs a fix (humanpred/pknca#447) But maybe @billdenney can confirm if this is the issue or if he knows of a workaround for it

since this issue is not a blocker I would say we can pause it for now and wait until the bugs are fixed!

@billdenney
Copy link
Contributor

For the potential bug in PKNCA, is it a real use case where you would say that you want to drop early BLQ values but also you want to impute a BLQ value? It seems like the user is giving discordant instructions at that point.

If it is a real use case (rather than option interaction testing which is useful), can you please describe the scenario for this to be intentional?

Merge remote-tracking branch 'origin/main' into 139-feat/blq-options

# Conflicts:
#	inst/shiny/modules/tab_nca.R
#	inst/shiny/modules/tab_nca/setup/settings.R
@Gero1999 Gero1999 requested review from Copilot and removed request for Copilot January 2, 2026 09:54
Copilot AI review requested due to automatic review settings January 2, 2026 10:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (2)

man/rm_impute_obs_params.Rd:5

  • The title "Apply Imputation for PKNCA Data" is misleading for a function now named rm_impute_obs_params. The function's primary purpose is to remove imputation from observational parameters, not to apply imputation. The title should be updated to something like "Remove Imputation from Observational Parameters" to accurately reflect the function's purpose.
    man/rm_impute_obs_params.Rd:16
  • The return value description states "A PKNCAdata object with imputation rules applied" which is misleading since this function removes imputation rules from observational parameters rather than applying them. The description should be updated to "A PKNCAdata object with imputation removed from observational parameters".

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings January 2, 2026 10:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (1)

man/rm_impute_obs_params.Rd:5

  • The function was renamed from apply_imputation to rm_impute_obs_params. However, the title still says "Apply Imputation for PKNCA Data" which no longer accurately reflects the function's purpose. The new name suggests it removes imputation from observational parameters, so the title should be updated to something like "Remove Imputation from Observational Parameters" to match the new function name and behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

),
conditionalPanel(
condition = sprintf("input['%s'] == 'Set value for all BLQ'", ns("select_blq_strategy")),
blq_selectize(ns("blq_value"), "Value for BLQ", selected = "0.05"),
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing comma after the last argument. While R allows trailing commas in function calls, this is inconsistent with the other conditional panels in this file where no trailing comma is used (see lines 37, 45). For consistency, consider removing the trailing comma.

Suggested change
blq_selectize(ns("blq_value"), "Value for BLQ", selected = "0.05"),
blq_selectize(ns("blq_value"), "Value for BLQ", selected = "0.05")

Copilot uses AI. Check for mistakes.
#' Apply Imputation for PKNCA Data
#'
#' Applies imputation rules to a PKNCAdata object, imputing start values and then
#' selectively removing imputation for parameters that are not dependent on AUC.
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description states this function "imputing start values and then selectively removing imputation" but this is no longer accurate. After the refactoring, this function only removes imputation from observational parameters (those not dependent on AUC). The start value imputation is now handled separately by create_start_impute. Update the description to accurately reflect that this function only removes imputation rules from parameters that are not dependent on AUC.

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +87
rule_list <- switch(
input$select_blq_strategy,
"Tmax based imputation" = list(
before.tmax = input$before_tmax,
after.tmax = input$after_tmax
),
"Positional BLQ imputation" = list(
first = input$before_first_non_blq,
middle = input$in_between_non_blqs,
last = input$after_last_non_blq
),
"Set value for all BLQ" = list(
first = input$blq_value,
middle = input$blq_value,
last = input$blq_value
),
"No BLQ handling" = list(
first = "keep",
middle = "keep",
last = "keep"
),
NULL
)
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the user switches between BLQ imputation strategies, the reactive may attempt to access input values that are not yet defined (e.g., accessing input$before_tmax when switching from "Positional BLQ imputation" to "Tmax based imputation"). This could cause the reactive to fail or produce unexpected NULL values. Consider adding req() calls or NULL checks for each input value before using them in the switch statement.

Copilot uses AI. Check for mistakes.
Comment on lines +89 to +98
# Transform text numbers in the list to numeric
rule_list <- lapply(rule_list, function(x) {
if (x %in% c("drop", "keep")) {
x
} else if (grepl("^[0-9]+(\\.[0-9]+)?$", x)) {
as.numeric(x)
} else {
NA
}
})
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the switch statement doesn't match any case, rule_list is set to NULL (line 86). However, the subsequent lapply call on line 90 will fail with an error when attempting to apply a function over NULL. This occurs when input$select_blq_strategy has an unexpected value. Add a NULL check after the switch statement before processing rule_list.

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings January 2, 2026 11:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Gero1999 Gero1999 marked this pull request as ready for review January 5, 2026 10:48
@Gero1999 Gero1999 requested review from Copilot and m-kolomanski and removed request for Copilot January 5, 2026 10:48
Copy link
Collaborator

@js3110 js3110 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For "set value for BLQ" would it not be better to allow a custom input value?
Where does 0.05 come from?

Copy link
Collaborator

@js3110 js3110 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would also be good to add some info in the description of what the program considers a BLQ value, so the user is aware

Copy link
Collaborator

@js3110 js3110 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In DoD it says " allows to introduce a particular BLQ value (i.e LLOQ/2)" I don't see where this is possible?

@Shaakon35
Copy link
Collaborator

For "set value for BLQ" would it not be better to allow a custom input value? Where does 0.05 come from?

I have the same comments as Jana.

We would need more flexibility for BLQ handling, the best would be to have these scenarios:

  • LLOQ / 2 -> for BLQ, instead of 0.5, that should cover cases when multiple analytes have different LLOQ
    But for this we would need to map LLOQ, so either we map it as optional and/or we add a text input where we can enter it manually (with no split by analyte :/, it's not optimal but it works for the single analyte studies)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enhancement: BLQ imputation Options

6 participants