PKPlus
This RMarkdown file executes PKPlus analysis. The script utilizes the gastroPlusAPI package to communicate with the GastroPlus X 10.2 service.
The NCA output will be provided in the global environments as “NCA_x” and be copied to your clipboard.
The CA output will be plotted as normal and y-log scale.
To customize your study with this script for a different simulation / project / variables, please make changes to the “set-input-information” code-chunk.
Please pay attention to chunk feedbacks.
Configure required packages
Load other necessary necessary packages(tidyverse) required to execute the data manipulation in the script
Load gastroPlusAPI package
library(tidyverse)
library(gastroPlusAPI)
Set working directory
Set working directory as the current source editor context
if (rstudioapi::isAvailable()){
current_working_directory <- dirname(rstudioapi::getSourceEditorContext()$path)
setwd(current_working_directory)
}
Start GPX Service
gpx_service <- start_service(verbose=FALSE)
✔ Configured the GastroPlus Service
gpx_service$is_alive()
[1] TRUE
Setup Input Information
Make modification to the variables in this chunk to customize your analysis. Assing all related parameters in order of input_names.
project_path: Location of the project where PKPlus analysis will be executed.
input_names: Names of input for the PKPlus.
observed_data_group_names & observed_data_series_names: Observed data details to be linked to PKPlus input. Details can be retrieved by get_experimental_data_inventory(ObservedDataGroupType$ExposureData)
dose_type: Accepted values are “IV” and “Oral”.
pkplus_run_name: Name of the PKPlus run that will include all inputs.
use_individual_BW & fit_F_for_oral_doses & fit_lag_time_for_oral_doses: Accepted values are TRUE and FALSE
elimination_model_type: Accepted values are “Linear” and “NonLinear”
analyses_methods: Choose analyses methods to be executed
project_path = "../../ProjectFiles/Midazolam.gpproject"
input_names <- c("5mg_iv", "30mg_sol", "7.5mg_sol")
observed_data_group_names <- c("5 mg iv", "30 mg Solution", "7.5 mg Solution")
observed_data_series_names <- c("Plasma Conc", "Plasma Conc", "Plasma Conc")
dose_type <- c(PKPlusDoseRoute$Intravenous, PKPlusDoseRoute$Oral, PKPlusDoseRoute$Oral)
dose_mg <- c(5, 30, 7.5)
infusion_time_h <- c(0, 0, 0)
body_weight_kg <- c(70, 70, 70)
pkplus_run_name <- "Run_for_1IV_2PO"
use_individual_BW <- TRUE
fit_F_for_oral_doses <- TRUE
fit_lag_time_for_oral_doses <- TRUE
fraction_unbound_plasma <- 0
elimination_model_type <- PKPlusEliminationModel$Linear
analyses_methods <- c(PKPlusAnalysisMethod$NonCompartmentalAnalysis,
PKPlusAnalysisMethod$OneCompartment,
PKPlusAnalysisMethod$TwoCompartment,
PKPlusAnalysisMethod$ThreeCompartment)
Configure and Execute the PKPlus Analysis Run
Based on the variables assigned in the previous code chunk, the PKPlus analysis will be configured and executed
#Load the project
open_project(project_path)
#Loop begins for PKPlus inputs
for (i in (1:length(input_names))){
#Find the assigned observed data
tryCatch({
exposure_series <- get_experimental_data_inventory(group_type = ObservedDataGroupType$ExposureData) %>%
filter(
group_name == observed_data_group_names[i],
series_name == observed_data_series_names[i]
)
}, error = function(e) {
message(
"The assigned observed data is not found, please check if it truly exists or possible typos."
)
})
#exposure_series should contain a single row, check if it truly is
if (nrow(exposure_series) > 1) {
cli::cli_abort("exposure_series contains more than one data, please check!")
}
#Assign the PKPlus input details
dose_amount <- ScalarObservable$new(
scalar_type = ScalarType$Mass,
scalar_value = ScalarValue$new(value = dose_mg[i], unit = "milligram")
)
body_weight <- ScalarObservable$new(
scalar_type = ScalarType$Mass,
scalar_value = ScalarValue$new(value = body_weight_kg[i], unit = "kilogram")
)
infusion_time <- ScalarObservable$new(
scalar_type = ScalarType$Time,
scalar_value = ScalarValue$new(value = infusion_time_h[i], unit = "hour")
)
series_key <- SeriesKey$new(
group_type = exposure_series$group_type,
group_name = exposure_series$group_name,
series_type = exposure_series$series_type,
series_name = exposure_series$series_name
)
input_config <- PKPlusInputConfiguration$new(
dose_route = dose_type[i],
exposure_series_key = series_key,
dose_amount = dose_amount,
infusion_time = infusion_time,
body_weight = body_weight
)
add_pkplus_input(input_names[i], input_config)
#Info about the loop to user
cli::cli_alert_info(
"Input added: {input_names[[i]]}, Dose Amount: {dose_mg[i]}, Body Weight: {body_weight_kg[i]}, Infusion Time: {infusion_time_h[i]}"
)
} #Loop ends
ℹ Input added: 5mg_iv, Dose Amount: 5, Body Weight: 70, Infusion Time: 0
ℹ Input added: 30mg_sol, Dose Amount: 30, Body Weight: 70, Infusion Time: 0
ℹ Input added: 7.5mg_sol, Dose Amount: 7.5, Body Weight: 70, Infusion Time: 0
#Check if inputs implemented successfully
if( length(get_pkplus_inputs()$pkplus_input_name) != length(input_names)){
cli::cli_abort("An error occurred during input, please check your inputs.")
}
#Create PKPlus Run and Execute
add_pkplus_run(pkplus_run_name = pkplus_run_name, pkplus_input_names = input_names)
run_config <- PKPlusRunConfiguration$new(use_individual_body_weights = use_individual_BW,
fit_bioavailability = fit_F_for_oral_doses,
fit_time_lag = fit_lag_time_for_oral_doses,
fraction_unbound_plasma = fraction_unbound_plasma,
kinetics_type = elimination_model_type,
model_types = analyses_methods)
configure_pkplus_run(pkplus_run_name = pkplus_run_name, pkplus_run_config = run_config)
tryCatch({
execute_pkplus_run(pkplus_run_name = pkplus_run_name)
cli::cli_alert_info("Run executed: {pkplus_run_name}, Inputs: {input_names}")
}, error = function(e) {
message("A problem occurred while executing PKPlus run: {pkplus_run_name}")
})
ℹ Run executed: Run_for_1IV_2PO, Inputs: 5mg_iv, 30mg_sol, and 7.5mg_sol
Process NCA outputs
Get each NCA output as a global variable and copy the combined NCA outputs to clipboard
pkplus_output <- get_pkplus_run_output(pkplus_run_name = pkplus_run_name)
non_compartmental_analysis_output <- pkplus_output$non_compartmental_analysis_output
#Loop_1 for data manipulation of NCA outpus
for(i in (1:length(input_names))){
NCA_data_longer <- as.data.frame(non_compartmental_analysis_output[[i]]) %>%
mutate(across(everything(), as.character)) %>%
pivot_longer(
cols = everything(),
names_to = "column1",
values_to = "column2"
) %>% filter(column1 != "dose_route") #delete dose_route, unnecessary and violating data manipulation
#Warning occurrs for the following code due to NA assignment, masking it.
NCA_df <- suppressWarnings(
NCA_data_longer %>%
separate(
column1,
into = c("parameter", "attribute"),
sep = "\\.(?=[^.]+$)" # split at the last dot
) %>%
pivot_wider(
names_from = attribute,
values_from = column2
) %>%
select(parameter, value, unit)
)
NCA_df_name <- paste0("NCA_", i)
assign(NCA_df_name, NCA_df)
cli::cli_alert_info("NCA output is generated: {NCA_df_name}, Inputs: {NCA_df[1,1]}")
} #Loop_1 ends
ℹ NCA output is generated: NCA_1, Inputs: X.30mg_sol.
ℹ NCA output is generated: NCA_2, Inputs: X.5mg_iv.
ℹ NCA output is generated: NCA_3, Inputs: X.7.5mg_sol.
#Loop_2 for combining NCA outputs and copying to clipboard
NCA_df_list <- list()
for (i in (1:length(input_names))) {
NCA_df_list[[i]] <- get(paste0("NCA_", i))
} #Loop_2 ends
combined_NCA_df <- do.call(rbind, NCA_df_list)
write.table(
combined_NCA_df,
file = "clipboard",
sep = "\t",
row.names = FALSE)
cli::cli_alert_info("NCA outputs were copied to clipboard")
ℹ NCA outputs were copied to clipboard
glimpse(combined_NCA_df)
Rows: 42
Columns: 3
$ parameter <chr> "X.30mg_sol.", "auc_first_moment_last", "auc_infinity", "auc…
$ value <chr> NA, "0.00221953", "0.000429704", "0.00040325", "70", "69815.…
$ unit <chr> NA, "(mg/mL)*h*h", "(mg/mL)*h", "(mg/mL)*h", "kg", "mL/h", "…
Process Compartmental outputs
Get best fitted CA output plot
observed_conc_series <- pkplus_output$compartmental_analysis_output$observed_concentration_series
one_CA_series <- pkplus_output[["compartmental_analysis_output"]][["model_outputs"]][[1]][[2]][["predicted_concentration_series"]]
two_CA_series <- pkplus_output[["compartmental_analysis_output"]][["model_outputs"]][[2]][[2]][["predicted_concentration_series"]]
three_CA_series <- pkplus_output[["compartmental_analysis_output"]][["model_outputs"]][[3]][[2]][["predicted_concentration_series"]]
p <- ggplot()
#Plotting observed data
for (i in (1:(nrow(observed_conc_series)))) {
df_data <- observed_conc_series$series[[i]]
df_data$Legend <- observed_conc_series$input[i]
p <- p + geom_point(
data = df_data,
mapping = aes(
x = independent,
y = dependent,
color = Legend
),
size = 3.5,
alpha=0.75,
shape=22,
)
}
#Plotting the best CA
if(pkplus_output[["best_model"]] == "OneCompartment") {
best_CA <- "one_CA_series"
} else if(pkplus_output[["best_model"]] == "TwoCompartment") {
best_CA <- "two_CA_series"
} else if(pkplus_output[["best_model"]] == "ThreeCompartment") {
best_CA <- "three_CA_series"
}
for (i in (1:(nrow(get(best_CA))))) {
df_data_CA <- get(best_CA)$series[[i]]
df_data_CA$Legend <- get(best_CA)$input[i]
p <- p + geom_line(
data = df_data_CA,
mapping = aes(
x = independent,
y = dependent,
color = Legend
),
linewidth=1.25
)
}
#Styling
p <- p + theme_classic() +
labs(title= paste0("Best Model is ", pkplus_output[["best_model"]]), x= paste("Time"), y=paste("Concentration")) +
theme(
axis.title.x = element_text(face = "bold", size = 12),
axis.title.y = element_text(face = "bold", size = 12),
axis.text.x = element_text(face = "bold", size = 11),
axis.text.y = element_text(face = "bold", size = 11),
plot.title = element_text(hjust = 0.5, face = "bold", size = 12, color="#051082")
)
ylog_p <- p + scale_y_log10()
p
ylog_p
Warning in scale_y_log10(): log-10 transformation introduced infinite values.
log-10 transformation introduced infinite values.
log-10 transformation introduced infinite values.
log-10 transformation introduced infinite values.
.## Kill GPX Service
gpx_service$kill()
[1] TRUE