Skip to main content
Skip table of contents

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

  1. Load other necessary necessary packages(tidyverse) required to execute the data manipulation in the script

  2. Load gastroPlusAPI package

R
library(tidyverse)
library(gastroPlusAPI)

Set working directory

Set working directory as the current source editor context

R
if (rstudioapi::isAvailable()){
  current_working_directory <- dirname(rstudioapi::getSourceEditorContext()$path)
  setwd(current_working_directory)
}

Start GPX Service

R
gpx_service <- start_service(verbose=FALSE)
CODE
✔ Configured the GastroPlus Service
R
gpx_service$is_alive()
CODE
[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

R
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

R
#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
CODE
ℹ Input added: 5mg_iv, Dose Amount: 5, Body Weight: 70, Infusion Time: 0
CODE
ℹ Input added: 30mg_sol, Dose Amount: 30, Body Weight: 70, Infusion Time: 0
CODE
ℹ Input added: 7.5mg_sol, Dose Amount: 7.5, Body Weight: 70, Infusion Time: 0
R
#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}")
})
CODE
ℹ 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

R
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
CODE
ℹ NCA output is generated: NCA_1, Inputs: X.30mg_sol.
CODE
ℹ NCA output is generated: NCA_2, Inputs: X.5mg_iv.
CODE
ℹ NCA output is generated: NCA_3, Inputs: X.7.5mg_sol.
R
#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")
CODE
ℹ NCA outputs were copied to clipboard
R
glimpse(combined_NCA_df)
CODE
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

R
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
PKPlus_figure1.jfif

R
ylog_p
CODE
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.
PKPlus_figure2.jfif

.## Kill GPX Service

R
gpx_service$kill()
CODE
[1] TRUE
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.