Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Units edition results #146

Open
wants to merge 28 commits into
base: main
Choose a base branch
from

Conversation

Gero1999
Copy link
Collaborator

@Gero1999 Gero1999 commented Dec 17, 2024

Issue

Users would like to be able to choose the units in which the results parameters are displayed.
Closes #113

Description

Sometimes user might be interested in changing the standard format of units provided by the app. In one that this may happen frequently is for example clearance (cl.obs), where current units always make very small values (~0) that can confuse when the rounding is used in the summary statistics.

Definition of Done

  • Allow user to customize in results the units of measure for each parameter
  • Scale appropriately parameter values based on new unit measures imputed

How to test

How to test features not covered by unit tests.

Contributor checklist

  • System to change units in parameters works well before NCA

  • System to change units in parameters works well after NCA

  • Outputs post NCA still work fine and adapt well to new units (i.e, boxplots)

  • Code passes lintr checks

  • Code passes all unit tests

  • New logic covered by unit tests

  • New logic is documented

Notes to reviewer

Anything that the reviewer should know before tacking the pull request?

@Gero1999 Gero1999 linked an issue Dec 17, 2024 that may be closed by this pull request
2 tasks
@Gero1999 Gero1999 added help wanted Extra attention is needed enhancement New feature or request labels Dec 18, 2024
@Gero1999 Gero1999 removed the help wanted Extra attention is needed label Dec 31, 2024
@Gero1999
Copy link
Collaborator Author

Gero1999 commented Jan 2, 2025

Hello team @m-kolomanski @Gotfrid @js3110 !

I have a small technical problem with this units package. This is a package that I used for the function transform_unit that automatically calculates conversions. This package is also used in PKNCA and @billdenney has also participated in its development.

When the package is installed through non-Windows OS, the installation through CRAN with install.packages() won't work unless a terminal command is run before to install the udunits2 object, as indicated in their README . The problem is that the testing on the remote GitHub-workflow might require this, as it is a Linux system.

There are many potential solutions to this, as the only affected things are the transform_unit function and its testthat testing. However I am not sure what is the best approach to solve it and I would like your input if possible. Here are my current ideas:

  1. Add the package units to "Suggests" in the namespace, and only run transform_unit when possible with if (!requireNamespace("units", , quietly = TRUE) (in other cases return NA, which does not conflict with the App, as the user will be asked to manually populate the conversions).

  2. Customize somehow the installation for each OS. I know that with R we can request the Sys.info() to obtain all info we need (sysname + perhaps version) to know what action to take before doing the install.packages. However this procedure concerns me, as I am not sure if we require additional permits from the user to do this installation method.

  3. Do a new transform_unit function that is independent from the units package that is only intended for the physical units we use (concentration, time, volume, mass). I indeed did something of this in the past using regex, I would just need to refine it and create the tests.

Let me know what you think of them or if you could come up with a better solution and I will try to implement it!

@m-kolomanski
Copy link
Collaborator

Hi @Gero1999,

use whatever dependencies you need to use - there is no need to re-invent the wheel if ready solutions are available, and we are not the first to deal with system dependencies, so do not worry :)

In terms of installing the package itself, if installing a dependency (in that case units) fails due to missing system packages, the user is prompted to install those and this is alright - something that I deal with frequently as Ubuntu user. We only need to make sure that the package is present in the DESCRIPTION file. I do not think there are any other concerns, @Gotfrid?

In terms of github actions / workflows, we can install the dependency on the machine that runs the checks, I will get on that.

@billdenney
Copy link

I agree with @m-kolomanski, adding the dependency is the best path. Writing your own unit handling will likely be error-prone. (I've done it a few times in the past, and it always has lots of bugs the first time around.) The units package has the side-benefit that all standard unit conversions should be handled for you.

@Gero1999 Gero1999 marked this pull request as ready for review January 3, 2025 15:06
@Gero1999
Copy link
Collaborator Author

Gero1999 commented Jan 3, 2025

I think the feature itself is ready for review. The other conflicts will hopefully be solved once the workflow incorporates the dependency mentioned. Let me know if so far this convince you or you can think of improvements:

Feat characteristics

  • Parameter Units button to visualize/modify PKNCA units table present in NCA settings & NCA results
  • Modification only allowed on Custom Unit and Conversion Factor columns
  • If modifications are done before running NCA then they will apply once is run
  • If modifications are done after running NCA then they will apply to the results and to the NCA running
  • If in Custom Unit the user introduces an unrecognized unit, Conversion Factor will be NA. If NAs are in Conversion Factor user won't be able to Save Units Table and it will be notified on how to proceed

@Gero1999 Gero1999 requested a review from js3110 January 3, 2025 15:14
@Gero1999 Gero1999 requested review from m-kolomanski and js3110 and removed request for js3110 January 3, 2025 15:14
@Gotfrid
Copy link
Collaborator

Gotfrid commented Jan 6, 2025

Agreed with everything mentioned above regarding the units package. It is not uncommon to require system dependencies installed in the environment (think sf package, or any DBMS package).
Comment from my end: once units is added to the dependencies, we can recommend installation via pak - because it handles system requirements as well (99% of the time).

Copy link
Collaborator

@m-kolomanski m-kolomanski left a comment

Choose a reason for hiding this comment

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

Hey, looks nicely and seems to work fine, but I have a couple of comments and concerns regarding the code. Please let me know your thoughts.

R/calculate_summary_stats.R Outdated Show resolved Hide resolved
R/reshape_PKNCA_results.R Outdated Show resolved Hide resolved
inst/shiny/modules/tab_visuals.R Outdated Show resolved Hide resolved
inst/shiny/modules/tab_visuals.R Outdated Show resolved Hide resolved
inst/shiny/modules/units_table.R Outdated Show resolved Hide resolved
inst/shiny/modules/units_table.R Outdated Show resolved Hide resolved
Comment on lines 139 to 198
new_res_nca <- reactiveVal(NULL)
observeEvent(input$save_units_table, {

# Make sure there are no missing entries (no NA in conversion factor)
if (any(is.na(modal_units_table()$`Conversion Factor`))) {

invalid_entries <- modal_units_table() %>%
filter(is.na(`Conversion Factor`)) %>%
mutate(entry = paste0(Parameter, " (", Analytes, ")")) %>%
pull(entry)

showNotification(
paste0("Please, make sure to use only recognised convertible units in `Custom Unit`",
"(i.e, day, hr, min, sec, g/L).",
" If not, introduce yourself the corresponding `Conversion Factor` value in: ",
paste(invalid_entries, collapse = ", ")),
duration = NULL,
closeButton = TRUE,
type = "warning"
)
return()
}

# Tranform the modal units table back to the original one
modal_units_table <- modal_units_table() %>%
dplyr::mutate(Analytes = strsplit(Analytes, ", ")) %>%
tidyr::unnest(Analytes) %>%
dplyr::rename(ANALYTE = `Analytes`,
PPTESTCD = `Parameter`,
PPORRESU = `Default unit`,
PPSTRESU = `Custom unit`,
conversion_factor = `Conversion Factor`)

# Save the modified units table in my data object
mydata <- mydata()
mydata$units <- modal_units_table
mydata(mydata)

# If there are already results produced, make sure they are also adapted
if (!is.null(res_nca())) {
res_nca <- res_nca()
res_nca$data$units <- modal_units_table
res_nca$result <- res_nca$result %>%
dplyr::select(-PPSTRESU, -PPSTRES) %>%
dplyr::left_join(
modal_units_table,
by = intersect(names(.), names(modal_units_table))
) %>%
dplyr::mutate(PPSTRES = PPORRES * conversion_factor) %>%
dplyr::select(-conversion_factor)

new_res_nca(res_nca)
}
# Close the module window once all saving actions are done
removeModal()

})

return(reactive(new_res_nca()))
})
Copy link
Collaborator

Choose a reason for hiding this comment

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

suggestion: This also could be wrapped into single reactive() expression and returned directly. You can use bindEvent to bind a reactive expression to a single specific event, instead of recalculating it every time some dependency change (it is basically like wrapping it in isolate().

reactive({
  # code for pepraring the results
  removeModal()
  res_nca
})

Copy link
Collaborator

Choose a reason for hiding this comment

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

issue: There are a lot of side-effect in this module and they seem to not be consistent. You are modifying mydata() object directly in this module, but instead of also modifying res_nca() directly you return it as a reactive, and then assign the value in anca.R file (Line 37). There is nothing inherently wrong with mutating the state of the object directly, but it gets confusing as the complexity grows and might be hard to debug later on. Please make sure all side-effects of the module are desired and documented.

Comment on lines 305 to 307
units_table_server("units_table_preNCA", mydata, reactive(NULL), params_to_calculate)
res_nca2 <- units_table_server("units_table_postNCA", mydata, res_nca, params_to_calculate)
observeEvent(res_nca2(), res_nca(res_nca2()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

question: So if I understand that correctly, we are using units_table_preNCA module to modify only mydata object, but use units_table_postNCA to modify both mydata and res_nca? This is a bit confusing and relates to my previous comment about side-effects. Seems like a single instance of the module should be able to handle both cases (and just return NULL if res_nca is not available).

@@ -371,8 +384,8 @@ observeEvent(input$nca, {
})

# run the nca upon button click

res_nca <- eventReactive(rv$trigger, {
res_nca <- reactiveVal(NULL)
Copy link
Collaborator

Choose a reason for hiding this comment

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

issue: res_nca is referenced on line 307, but only defined on line 387. This does not cause any technical problems because of the even structure of the program, but is bad practice nevertheless - this should be higher. Considering the importance of that data, I would consider putting this definition on top of the module.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enhancement: allow users to modify unit values of parameter results
4 participants