route of administration

absorption

delay

distribution

elimination

output

Concentration

Parameters

Dosage regimen

pkmodelCode.R

ui.R

Download

#-------------------------------------------------------------------------
#  This application is governed by the CeCILL-B license. 
#  You can  use, modify and/ or redistribute this code under the terms
#  of the CeCILL license:  http://www.cecill.info/index.en.html
#
#  Marc Lavielle, Inria Saclay
#  May 11th, 2015
#-------------------------------------------------------------------------

library(shinydashboard)

sidebar <- dashboardSidebar(
  hr(),
  sidebarMenu(id="tabs",
              menuItem("Plot", tabName = "plot", icon = icon("line-chart"), selected=TRUE),
              menuItem("Table", tabName = "table", icon = icon("table"),
                       menuSubItem("concentration", tabName = "tabf", icon = icon("angle-right")),
                       menuSubItem("parameters & dosage", tabName = "tabparam", icon = icon("angle-right"))
#                        menuSubItem("administration", tabName = "tabadm", icon = icon("angle-right"))
              ),
              menuItem("Codes",  icon = icon("file-text-o"),
                       menuSubItem("pkmodel", tabName = "pkmodel", icon = icon("angle-right")),
                       menuSubItem("ui.R", tabName = "ui", icon = icon("angle-right")),
                       menuSubItem("server.R", tabName = "server", icon = icon("angle-right"))
              ),
              menuItem("ReadMe", tabName = "readme", icon = icon("mortar-board")),
              menuItem("About", tabName = "about", icon = icon("question"))
  ),
  hr(),
  conditionalPanel("input.tabs=='plot'",
                   sidebarMenu(
                     menuItem("Administration", tabName = "admin", icon = icon("chevron-circle-right") ,selected=TRUE),
                     menuItem("Parameterization", icon = icon("chevron-circle-right"),
                              fluidRow(
                                column(1),
                                column(10,
                                       radioButtons("parameterization","",c("rate constant" = "1","clearance" = "2"))
                                )) ),
                     menuItem("Model", icon = icon("chevron-circle-right"),
                              menuSubItem("Absorption", tabName = "absorption", icon = icon("angle-right")),
                              menuSubItem("Distribution", tabName = "distribution", icon = icon("angle-right")),
                              menuSubItem("Elimination", tabName = "elimination", icon = icon("angle-right"))
                     ),
                     menuItem("Output", tabName = "output", icon = icon("chevron-circle-right"))
                   ),
                   hr()
  )
  #   conditionalPanel("input.tabs=='plot'",
  #                    fluidRow(
  #                      column(1), column(10,
  #                    downloadButton('downloadPlot','Download Graph')), 
  #                    br(), hr()
  #   ))
)

body <- dashboardBody(
  tabItems(
    tabItem(tabName = "plot",
            fluidRow( 
              box(width = 12, status = "primary",
                  downloadButton('downloadPlot','Download'),  br(),
                  plotOutput("plot",  height="400px")
              ),
              tabItems(
                tabItem(tabName = "admin",
                        box(width = 4, status = "primary", solidHeader = TRUE, title="route of administration",          
                            radioButtons("administration", "",
                                         c("iv bolus" = "bolus","iv infusion" = "infusion","oral" = "oral"),selected="oral")
                        ),
                        box(width = 4, status = "primary",          
                            sliderInput("tfd", "Time of first dose:", value=0, min=0, max = 20, step=1),
                            sliderInput("nd", "Number of doses:", value=8, min=0, max = 20, step=1)
                        ),
                        box(width = 4, status = "primary",          
                            sliderInput("ii", "Interdose interval:", value = 9, min = 0.5, max = 15, step=0.5),
                            sliderInput("amt", "Amount:", value = 50, min = 0, max = 200, step=10),
                            conditionalPanel(condition = "input.administration == 'infusion'",
                                             sliderInput("tinf", "Infusion time:", value = 1, min = 0, max = 5, step=0.2)
                            )
                        )
                ),
                tabItem(tabName = "absorption",
                        conditionalPanel(condition = "input.administration == 'oral'",
                                         box(width = 4, status = "primary", solidHeader = TRUE, title="absorption",       
                                             radioButtons("absorption","",c("first order" = "1","zero order" = "0"))
                                         ),
                                         box(width = 4, status = "primary", solidHeader = TRUE, title="delay",          
                                             conditionalPanel(condition = "input.absorption == '0'",
                                                              radioButtons("delay0","",c("none" = "0","lag time" = "1"))
                                                              
                                             ),                            
                                             conditionalPanel(condition = "input.absorption == '1'",
                                                              radioButtons("delay1","",c("none" = "0","lag time" = "1","transit compartment" = "2"))
                                             )
                                         ),
                                         box(width = 4, status = "primary",       
                                             conditionalPanel(condition = "input.absorption == '1'",
                                                              sliderInput("ka", "rate constant ka:", value = 0.8, min = 0, max = 4, step=0.1)
                                             ),
                                             
                                             conditionalPanel(condition = "input.absorption == '0'",
                                                              sliderInput("tk0", "duration Tk0:", value = 3, min = 0, max = 10, step=0.5)
                                             ),
                                             conditionalPanel(condition = "(input.absorption == '1' & input.delay1 == '1') | (input.absorption == '0' & input.delay0 == '1')",
                                                              sliderInput("tlag", "lag time Tlag:", value = 1, min = 0, max = 10, step=0.5)
                                             ),
                                             
                                             conditionalPanel(condition = "input.absorption == '1' & input.delay1 == '2'",
                                                              sliderInput("mtt", "mean transit time Mtt:", value = 1, min = 0, max = 10, step=0.5),
                                                              sliderInput("ntr", "number of comp. Ntr:", value = 2, min = 0.5, max = 10, step=0.5)
                                             )
                                         )
                        )
                ),
                tabItem(tabName = "distribution",
                        #                         fluidRow( 
                        box(width = 4, status = "primary", solidHeader = TRUE, title="distribution",   
                            #                             h5("Number of compartments:"),
                            radioButtons("distribution","Number of compartments:",c("1" = "1","2" = "2","3" = "3"), inline=TRUE),
                            sliderInput("v", "volume V:", value = 10, min = 1, max = 20, step=1)
                        ),
                        conditionalPanel(condition = "input.distribution != '1' & input.parameterization=='1'",
                                         box(width = 4,   status = "primary",         
                                             sliderInput("k12", "transition rate constant k12:", value = 0.4, min = 0, max = 2, step=0.05),
                                             sliderInput("k21", "transition rate constant k21:", value = 0.2, min = 0, max = 2, step=0.05)
                                         )
                        ),
                        conditionalPanel(condition = "input.distribution != '1' & input.parameterization=='2'",
                                         box(width = 4,   status = "primary",         
                                             sliderInput("v2", "periph. comp. volume V2:", value = 20, min = 2, max = 40, step=2),
                                             sliderInput("q2", "inter comp. clearance Q2:", value = 4, min = 1, max = 10, step=0.5)
                                         )
                        ),
                        conditionalPanel(condition = "input.distribution == '3' & input.parameterization=='1'",
                                         box(width = 4,   status = "primary",         
                                             sliderInput("k13", "transition rate constant k13:", value = 0.3, min = 0, max = 2, step=0.05),
                                             sliderInput("k31", "transition rate constant k31:", value = 0.5, min = 0, max = 2, step=0.05)
                                         )
                        ),
                        conditionalPanel(condition = "input.distribution == '3' & input.parameterization=='2'",
                                         box(width = 4,   status = "primary",         
                                             sliderInput("v3", "periph. comp. volume V3:", value = 6, min = 1, max = 10, step=0.5),
                                             sliderInput("q3", "inter comp. clearance Q3:", value = 3, min = 0.5, max = 10, step=0.5)
                                         )
                        )
                ),
                tabItem(tabName = "elimination",
                        box(width = 4, status = "primary", solidHeader = TRUE, title="elimination",          
                            radioButtons("elimination","",c("linear" = "1","Michaelis Menten" = "2"))
                        ),
                        box(width = 4, status = "primary",          
                            conditionalPanel(condition = "input.elimination=='1' & input.parameterization=='1'",
                                             sliderInput("k", "elimination rate constant k:", value = 0.2, min = 0, max = 2, step=0.05)
                            ),
                            conditionalPanel(condition = "input.elimination == '1' & input.parameterization=='2'",
                                             sliderInput("Cl", "Clearance Cl:", value = 2, min = 0, max = 4, step=0.2)
                            ),
                            conditionalPanel(condition = "input.elimination == '2'",
                                             sliderInput("vm", "Vm:", value = 1, min = 0, max = 5, step=0.05),
                                             sliderInput("km", "Km:", value = 1, min = 0, max = 5, step=0.05)
                            )
                        )
                ),
                tabItem(tabName = "output",
                        box(width = 4, status = "primary", solidHeader = TRUE, title="output",          
                            radioButtons("log", "", c("linear scale" = FALSE,"log scale" = TRUE))  
                        ),
                        box(width = 4, status = "primary",
                            sliderInput("range", "time range", min = -10, max = 200, value = c(-5,100), step=5),
                            sliderInput("ngp", "grid size", min = 50, max = 1000, value = 500, step=50)
                        ),
                        box(width = 4, status = "primary",
                            sliderInput("lsize", "line width", min = 0, max = 5, value = 0.75, step=0.25)
                        )
                )
              )
            )
    ),
    tabItem(tabName = "tabf",
            box( width = NULL, status = "primary", solidHeader = TRUE, title="Concentration",                            
                 downloadButton('downloadTablef', 'Download'), br(), 
                 br(),
                 tableOutput("tablef")
            )
    ),
    tabItem(tabName = "tabparam",
            box( width = NULL, status = "primary", solidHeader = TRUE, title="Parameters",                            
                 downloadButton('downloadTablep', 'Download'), br(), 
                 br(),
                 tableOutput("tablep")
            ),
#     ),
#     tabItem(tabName = "tabadm",
            box( width = NULL, status = "primary", solidHeader = TRUE, title="Dosage regimen",                            
                 downloadButton('downloadTablea', 'Download'), br(), 
                 br(),
                 tableOutput("tablea")
            )
    ),
    tabItem(tabName = "pkmodel",
            box( width = NULL, status = "primary", solidHeader = TRUE, title="pkmodelCode.R",                
                 downloadButton('downloadData1', 'Download'),
                 br(),br(),
                 verbatimTextOutput("RFile")
            )
    ),
    tabItem(tabName = "ui",
            box( width = NULL, status = "primary", solidHeader = TRUE, title="ui.R",
                 downloadButton('downloadData2', 'Download'),
                 br(),br(),
                 pre(includeText("ui.R"))
            )
    ),
    tabItem(tabName = "server",
            box( width = NULL, status = "primary", solidHeader = TRUE, title="server.R",
                 downloadButton('downloadData3', 'Download'),
                 br(),br(),
                 pre(includeText("server.R"))
            )
    ),
    tabItem(tabName = "readme",
            withMathJax(), 
            includeMarkdown("readMe.Rmd")
    ),
    tabItem(tabName = "about",
            includeMarkdown("../../about/about.Rmd")
    )
  )
)

dashboardPage(
  dashboardHeader(title = "Build your PK model"),
  sidebar,
  body
)

server.R

Download

#-------------------------------------------------------------------------
#  This application is governed by the CeCILL-B license. 
#  You can  use, modify and/ or redistribute this code under the terms
#  of the CeCILL license:  http://www.cecill.info/index.en.html
#
#  Marc Lavielle, Inria Saclay
#  May 11th, 2015
#-------------------------------------------------------------------------

library(shinydashboard)
library(mlxR)              

shinyServer(function(input, output){
  l.text <- ("library(mlxR)\n")
  pkmodel.text <- ("
res <- pkmodel(t,adm,p)

print(ggplot(data=res, aes(x=time, y=cc)) + geom_line(size=1) +
  xlab('time (h)') + ylab('concentration (mg/L)'))
")
  
  r <- reactive({ 
    param.name=NULL
    param.value=NULL
    if (input$administration=="oral"){
      if (input$absorption=="1"){
        if (input$delay1=="1"){
          param.name=c(param.name,'Tlag')
          param.value=c(param.value,input$tlag)
        }
        if (input$delay1=="2"){
          param.name=c(param.name,'Mtt','Ktr')
          param.value=c(param.value,input$mtt,(input$ntr+1)/input$mtt)
        }
        param.name=c(param.name,'ka')
        param.value=c(param.value,input$ka)
      }else{
        param.name=c(param.name,'Tk0')
        param.value=c(param.value,input$tk0)        
        if (input$delay0=="1"){
          param.name=c(param.name,'Tlag')
          param.value=c(param.value,input$tlag)
        }
      }
    }
    param.name=c(param.name,'V')
    param.value=c(param.value,input$v)
    
    if (input$distribution!="1"){
      if (input$parameterization=="1"){
        param.name=c(param.name,'k12','k21')
        param.value=c(param.value,input$k12,input$k21)
      }else{
        param.name=c(param.name,'Q2','V2')
        param.value=c(param.value,input$q2,input$v2)
      }
    }
    if (input$distribution=="3"){
      if (input$parameterization=="1"){
        param.name=c(param.name,'k13','k31')
        param.value=c(param.value,input$k13,input$k31)
      }else{
        param.name=c(param.name,'Q3','V3')
        param.value=c(param.value,input$q3,input$v3)
      }
    }
    
    if (input$elimination=="1"){
      if (input$parameterization=="1"){
        param.name=c(param.name,'k')
        param.value=c(param.value,input$k)
      }else{
        param.name=c(param.name,'Cl')
        param.value=c(param.value,input$Cl)
      }
    }else{
      param.name=c(param.name,'Vm','Km')
      param.value=c(param.value,input$vm,input$km)      
    }
    p=list(name=param.name,value=param.value)
    t.value=seq(input$range[1],input$range[2],length.out=(input$ngp+1))
    t1=input$tfd
    t2=input$ii*(input$nd-1)+t1
    a.names <- c("amount","tfd","nd","ii")
    a.values <- c(input$amt,input$tfd,input$nd,input$ii)
    if (t2>=t1){
      t.dose=seq(t1,t2,by=input$ii)
      adm <- list(time=t.dose, amount=input$amt)
    }else{
      adm <- list(time=t1, amount=0)
    }
    if (input$administration == 'infusion'){
      adm$rate <- input$amt/input$tinf
      a.names <- c(a.names, "tinf")
      a.values <- c(a.values, input$tinf)
    }
    
    #----------------------------------------------------    
    res   <- pkmodel(time=t.value,treatment=adm,parameter=p)
    #----------------------------------------------------    
    
    a.text <- 'adm <- list('
    if (input$nd==0){
      a.text <- 'adm <- list(amount=0, time=0'
    } else if(input$nd==1){
      a.text <- paste0('adm <- list(amount=',input$amt,', time=',input$tfd)
    } else{
      t1=input$tfd
      t2=input$ii*(input$nd-1)+t1
      a.text <- paste0('adm <- list(amount=',input$amt,
                       ', time=seq(',t1,', ',t2,', by=',input$ii,')')
    }
    if (input$administration == 'infusion'){
      a.text <- paste0(a.text,', tinf=',input$tinf,')')
    }else{
      a.text <- paste0(a.text,')')      
    }
    K <- length(param.value)
    p.text <- 'p <- c('
    for (k in (1:(K-1))){
      p.text <- paste0(p.text,param.name[k],'=',param.value[k],', ')
    }
    p.text <- paste0(p.text,param.name[K],'=',param.value[K],')')
    t.text <- paste0('t <- seq(',input$range[1],', ',input$range[2],
                     ', length=',length.out=input$ngp,')')
    pkmodel.text <- paste0(l.text,a.text,'\n',p.text,'\n',t.text,'\n',pkmodel.text)
    
    parameter <- data.frame(row.names= p$name, value=p$value)
    treatment <- data.frame(row.names= a.names, value=a.values)
    res <- list(parameter=parameter, f=res, treatment=treatment)
    out <- list(res,pkmodel.text)
    return(out)
  })
  
  output$plot <- renderPlot({
    pl <- myplot(r()[[1]]$f, input$lsize, input$log)
    print(pl)
  })
  
  myplot <- function(r,lsize,ilog){
    pl=ggplotmlx(data=r, aes(x=time, y=cc)) + geom_line(size=lsize) 
    if (ilog==TRUE)
      pl=pl + scale_y_log10()
    return(pl)
  }
  
  output$tablef <- renderTable({ r()[[1]]$f })

  output$tablep <- renderTable({ r()[[1]]$parameter },include.colnames=FALSE)
  
  output$tablea <- renderTable({ r()[[1]]$treatment },include.colnames=FALSE)
  
  output$RFile  <- renderText(r()[[2]])
  
  output$downloadTablef <- downloadHandler(
    filename = paste("concentration", Sys.Date(), ".csv", sep=""),
  content = function(file) {
      write.csv(r()[[1]]$f, file, row.names=FALSE)
    }
  )
  output$downloadTablep <- downloadHandler(
    filename = paste("parameter", Sys.Date(), ".csv", sep=""),
    content = function(file) {
      write.table(r()[[1]]$parameter, file, col.names=FALSE, sep=",")
    }
  )
  output$downloadTablea <- downloadHandler(
    filename = paste("dosage", Sys.Date(), ".csv", sep=""),
    content = function(file) {
      write.table(r()[[1]]$treatment, file, col.names=FALSE, sep=",")
    }
  )
  
  output$downloadData1 <- downloadHandler(
    filename = "pkmodelCode.R",
    content = function(file) {
      write(r()[[2]], file)
    }
  )
  
  output$downloadData2 <- downloadHandler(
    filename = "ui.R",
    content = function(file) {
      con        = file("ui.R", open = "r")
      lines      = readLines(con)
      close(con)
      write(lines, file)
    }
  )
  
  output$downloadData3 <- downloadHandler(
    filename = "server.R",
    content = function(file) {
      con        = file("server.R", open = "r")
      lines      = readLines(con)
      close(con)
      write(lines, file)
    }
  )
  
  output$downloadPlot <- downloadHandler(
    filename <- function() {
      paste("concentration", Sys.Date(), ".png", sep="") },
    content <- function(file) {
      png(file, width = 980, height = 600, units = "px", pointsize = 12, bg = "white", res = NA)
      #       png(file, bg = "white", res = NA)
      pl <- myplot(r()[[1]]$f, input$lsize, input$log)
      print(pl)
      dev.off()},
    contentType = 'image/png'
  )
  
  
})
  • Use the menu Plot to plot the PK profile, modify the PK model, the PK parameters, the dosage regimen and the design of the output.

  • Use the menu Table to create and save a table with the concentration values.

  • Use the menu Codes to display and download the Simulx R code pkmodelCode.R automatically generated using the current settings, the ui.R and server.R files used for this application.

Select the administration route and the dosage regimen in the menu Administration:

  • iv bolus, iv infusion, or oral administration,
  • time of first dose,
  • number of doses,
  • interdose interval,
  • amount.
  • infusion time (only for infusion),


Select the parameterization in the menu Parameterization:

  • rate constants (\(k\), \(k_{12}\), \(k_{21}\), \(k_{13}\), \(k_{31}\)),
  • clearances (\(Cl\), \(Q_{2}\), \(V_{2}\), \(Q_{3}\), \(V_{3}\)),


Define the PK model in the menu Model:

  • Define the absorption process for oral administration in the submenu Absorption:
    • zero-order or first-order absorption process with the associated paramameters (duration of absorption \(Tk0\) or absorption rate constant \(ka\))
    • lag time \(Tlag\)
    • transit compartment model with mean transit time \(Mtt\) and number of transit compartments \(Ntr\) (only for first-order absorption)


  • Define the distribution process in the submenu Distribution:
    • 1, 2 or 3 compartments
    • volume of distribution \(V\)
    • transfer rates constants \(k_{12}\) and \(k_{21}\) between compartments 1 and 2
    • transfer rates constants \(k_{13}\) and \(k_{31}\) between compartments 1 and 3


  • Define the elimination process in the submenu Elimination:
    • linear or Michaelis Menten elimination process
    • elimination rate constant \(k\), or
    • Michaelis Menten parameters \(V_m\) and \(K_m\).


Define the output in the menu Output:

  • select the time range where the predicted concentration is computed,
  • select the number of time points of the grid where the predicted concentration is computed,
  • choose between linear and semi-log scale.



This application is governed by the CeCILL-B license.
You can use, modify and/or redistribute these codes under the terms of the CeCILL license.


This Shiny application requires the mlxR package.


Marc Lavielle
Inria Saclay, Popix team
April 29th, 2015