Skip to content

Commit

Permalink
Implement first draft
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalbartschi committed Aug 30, 2024
1 parent 3977cac commit c62832a
Show file tree
Hide file tree
Showing 60 changed files with 6,105 additions and 3 deletions.
4 changes: 4 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
^renv$
^renv\.lock$
^aNCA\.Rproj$
^\.Rproj\.user$
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.Rproj.user
.Rhistory
.RData
.Ruserdata
aNCA.Rproj
inst/guidelines
inst/templates
inst/shiny/data
!inst/shiny/data/DummyRO_ADNCA.csv
3 changes: 3 additions & 0 deletions .renvignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*
!inst/shiny/*

53 changes: 53 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
Package: aNCA
Title: (Pre-)clinical NCA in a dynamic shiny app.
Version: 0.0.0.9000
Authors@R: c(
person("Ercan", "Suekuer", , "[email protected]", role = c("aut", "cre"),
comment = c(ORCID = "0009-0001-1626-1526")),
person("Gerardo Jose", "Rodriguez", , "[email protected]", role = "aut",
comment = c(ORCID = "0000-0003-1413-0060")),
person("Pascal", "Baertschi", , "[email protected]", role = "aut",
comment = c(ORCID = "0000-0002-6533-0399")),
person("Jana", "Spinner", , "[email protected]", role = "aut",
comment = c(ORCID = "0009-0009-2197-9530")),
person("F. Hoffmann-La Roche AG", role = c("cph", "fnd"))
)
Description: This application enables users to upload their datasets and
perform Non-Compartment Analysis (NCA) on both pre-clinical and
clinical datasets, with the results being easily visualizable. The NCA
can be tailored to calculate pharmacokinetic parameters for various
dosing regimens and time points, given certain restrictions. It also
features manual slope selection, simplifying the process of conducting
lambda-z-regression and PK-timepoint exclusions. Furthermore, the
pharmacokinetic parameters can be dynamically visualized through
customized graphics such as line and mean plots. The calculated
pharmacokinetic parameters can be compiled in a dynamic table,
visualized using boxplots, or exported as a comprehensive report.
Designed with user-friendliness in mind, this app aims to make NCA
accessible and straightforward for all scientists.
License: MIT
Imports:
checkmate,
dplyr,
DT,
forcats,
ggplot2,
haven,
nestcolor,
PKNCA,
plotly,
rio,
rmarkdown,
shiny,
shinyBS,
shinyjqui,
shinyWidgets,
stats,
tern,
tidyr,
tools,
utils,
zip
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.1
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2024 Ercan Suekuer

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
124 changes: 124 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Generated by roxygen2: do not edit by hand

export(anonymize_pk_data)
export(app_server)
export(app_ui)
export(apply_filters)
export(as_factor_preserve_label)
export(calculate_summary_stats)
export(create_conc)
export(create_dose)
export(create_filter)
export(flexible_violinboxplot)
export(format_data)
export(general_lineplot)
export(general_meanplot)
export(geometric.mean)
export(has_label)
export(lambda_slope_plot)
export(pptestcd_dict)
export(reshape_PKNCA_results)
export(run_app)
export(set_empty_label)
import(checkmate)
import(dplyr)
import(forcats)
import(ggplot2)
import(haven)
import(nestcolor)
import(plotly)
import(shiny)
import(tidyr)
importFrom(DT,DTOutput)
importFrom(DT,datatable)
importFrom(DT,formatStyle)
importFrom(DT,renderDataTable)
importFrom(DT,styleEqual)
importFrom(PKNCA,PKNCA.options)
importFrom(PKNCA,PKNCAconc)
importFrom(PKNCA,PKNCAdata)
importFrom(PKNCA,PKNCAdose)
importFrom(PKNCA,pk.nca)
importFrom(PKNCA,pknca_units_table)
importFrom(dplyr,across)
importFrom(dplyr,arrange)
importFrom(dplyr,case_when)
importFrom(dplyr,distinct)
importFrom(dplyr,filter)
importFrom(dplyr,group_by)
importFrom(dplyr,left_join)
importFrom(dplyr,mutate)
importFrom(dplyr,pull)
importFrom(dplyr,rename)
importFrom(dplyr,rename_with)
importFrom(dplyr,select)
importFrom(dplyr,slice)
importFrom(dplyr,summarise)
importFrom(dplyr,ungroup)
importFrom(dplyr,where)
importFrom(ggplot2,aes)
importFrom(ggplot2,facet_wrap)
importFrom(ggplot2,geom_errorbar)
importFrom(ggplot2,geom_line)
importFrom(ggplot2,geom_point)
importFrom(ggplot2,ggplot)
importFrom(ggplot2,labs)
importFrom(plotly,event_data)
importFrom(plotly,plotlyOutput)
importFrom(plotly,plotly_build)
importFrom(plotly,renderPlotly)
importFrom(rio,export_list)
importFrom(rmarkdown,render)
importFrom(shiny,actionButton)
importFrom(shiny,checkboxInput)
importFrom(shiny,column)
importFrom(shiny,conditionalPanel)
importFrom(shiny,downloadButton)
importFrom(shiny,fileInput)
importFrom(shiny,fluidPage)
importFrom(shiny,fluidRow)
importFrom(shiny,helpText)
importFrom(shiny,icon)
importFrom(shiny,insertUI)
importFrom(shiny,mainPanel)
importFrom(shiny,modalButton)
importFrom(shiny,modalDialog)
importFrom(shiny,navbarPage)
importFrom(shiny,numericInput)
importFrom(shiny,observeEvent)
importFrom(shiny,plotOutput)
importFrom(shiny,radioButtons)
importFrom(shiny,reactiveVal)
importFrom(shiny,reactiveValues)
importFrom(shiny,removeUI)
importFrom(shiny,renderUI)
importFrom(shiny,req)
importFrom(shiny,selectInput)
importFrom(shiny,showModal)
importFrom(shiny,sidebarLayout)
importFrom(shiny,sidebarPanel)
importFrom(shiny,tabPanel)
importFrom(shiny,tags)
importFrom(shiny,textInput)
importFrom(shiny,uiOutput)
importFrom(shiny,updateCheckboxInput)
importFrom(shiny,updateNavbarPage)
importFrom(shiny,updateNumericInput)
importFrom(shiny,updateSelectInput)
importFrom(shiny,updateTabsetPanel)
importFrom(shinyBS,bsModal)
importFrom(shinyFiles,shinyDirChoose)
importFrom(shinyWidgets,dropdown)
importFrom(shinyWidgets,pickerInput)
importFrom(shinyWidgets,switchInput)
importFrom(shinyWidgets,updatePickerInput)
importFrom(shinyjqui,orderInput)
importFrom(shinyjqui,updateOrderInput)
importFrom(stats,sd)
importFrom(tern,g_ipp)
importFrom(tidyr,pivot_longer)
importFrom(tidyr,pivot_wider)
importFrom(tools,file_ext)
importFrom(utils,read.csv)
importFrom(utils,write.csv)
importFrom(zip,zipr)
166 changes: 166 additions & 0 deletions R/anonymize_pk_data.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#' This function anonymizes RO numbers and Study IDs of pk data files.
#'
#' @import haven
#' @import dplyr
#' @import checkmate
#'
#' @param path path to dataframe in xpt, sas or csv format
#' @param overwrite decides whether file at input location `path` is overwritten. default is TRUE
#'
#' @return anonymized dataframe file
#'
#' @export
#'
#'
#'@author Pascal Bärtschi
#'

anonymize_pk_data <- function(path,
drug_map = NULL,
overwrite = TRUE){

# assert file
checkmate::assert_file_exists(path)
# if (!is.null(drug_map)){
# # check named vector
# # checkmate::assert(checkNamed(drug_map))
# # # assert names of drug dict somewhere in values of dataframe (with regex)
# # drug_regex <- paste(names(drug_map), collapse = "|")
# # checkmate::assert(any(grep(drug_regex, strings)))
# }


# file extension
extension <- str_split_i(path, "\\.", i = -1)

# extension decision read-in
if (extension == "csv"){
data <- read.csv(path)
} else if (extension == "sas7bdat"){
data <- read_sas(path)
} else if (extension == "xpt"){
data <- read_xpt(path)
} else {
stop("This file extension is not supported yet.")
}

#assert data loading
checkmate::assert(checkDataFrame(data))

# find all ronumbers
all_ronum <- lapply(X = data, FUN = function(x) str_extract(x, "\\bRO\\d{7}\\b")) %>%
unlist() %>%
unique() %>%
na.omit()

# find all tracknumbers
all_tracknum <- lapply(X = data, FUN = function(x) str_extract(x, "\\bTrack\\d{2}\\b")) %>%
unlist() %>%
unique() %>%
na.omit()

all_studyid <- lapply(X = data, FUN = function(x) str_extract(x, "\\b..\\d{5}\\b")) %>%
unlist() %>%
unique() %>%
na.omit()

if (length(all_ronum) > 0){
# instead of seq along, generate random numbers with 7 digits
ronum_map <- setNames(paste0("Analyte", sprintf("%02d", seq_along(all_ronum))),
all_ronum)
} else {
ronum_map <- character(0)
}

if (length(all_tracknum) > 0){
# instead of seq along, generate random numbers with 7 digits
tracknum_map <- setNames(paste0("Analyte", sprintf("%02d", seq_along(all_tracknum))),
all_tracknum)
} else {
tracknum_map <- character(0)
}

if (length(all_studyid) > 0){
studyid_map <- setNames(paste0("XX", sprintf("%02d", seq_along(all_studyid))),
all_studyid)
} else {
studyid_map <- character(0)
}



# checkmate::assert(checkVector(ronum_map, min.len = 1),
# checkVector(studyid_map, min.len = 1),
# combine = "and")

# concatenate the maps
concat_map <- c(ronum_map, studyid_map, tracknum_map, drug_map)

# function to replace according to the map
replace_str_with_map <- function(x, map) {
for (str_ in names(map)) {
x <- gsub(str_, map[[str_]], x)
}
return(x)
}

# columns required for NCA
req4nca <- c("STUDYID", "USUBJID", "ANALYTE", "PCSPEC", "DOSEFRQ", 'DOSNO', "AFRLT", "ARRLT", "NRRLT", "NFRLT", "PCSTRESC", "PARAM", "TAU",
"PCSTRESU", "ROUTE", "DOSEA", "AGE", "SEX", "RACE", "ADOSEDUR", 'DOSEDURU', "NDOSEDUR", "RRLTU", "DOSEA", "DOSEU", "PCLLOQ", "DRUG",
"AVISIT", "AVAL", "AVALU", "DOSEU", "EVID", "ATPTREF", "SITEID", "TRT01A", "TRT01P", "PCRFTDTM", "WTBL", "WTBLU", "HTBL", "HTBLU")

# mutate and rename
data <- data %>%
# apply the map to all columns that hold RO and STUDYNUMBERS
mutate_all(~replace_str_with_map(., concat_map)) %>%
rename_with(~replace_str_with_map(., concat_map)) %>%
# select only columns that are needed to perform NCA
select(any_of(req4nca))

# find the req4nca columns that are not in data
if (setdiff(req4nca, colnames(data)) %>% length > 0){
message(paste("The dataframe with path", path,
"is missing the following colnames: ",
paste(setdiff(req4nca, colnames(data)), collapse = ", ")))
}

# compose a message warning that the unique values of start_with("TRT") are ... and that DRUG names have to anonymized by hand
if (any(grepl("TRT", colnames(data)))){
message(paste("The unique values of the columns starting with TRT are: ", data %>%
select(all_of(data %>%
select(starts_with("TRT")) %>%
colnames(.))) %>%
unique() %>%
paste(., collapse = ", "), toupper(". Please make sure to replace drugnames!")))

}


# save the file
if (extension == "csv"){
if (overwrite){
write.csv(data, path, row.names = F)
} else {
write.csv(data, paste0(gsub(".csv", "", path), "_anonymized.csv"), row.names = F)
}
} else if (extension == "sas7bdat"){
if (overwrite){
write_xpt(data, gsub(".sas7bdat", ".xpt", path))
file.remove(path)
message("The sas7bdat file was converted to xpt and the original file was removed, as the sas7bdat format was deprecated in haven.")
} else {
write_xpt(data, paste0(gsub(".sas7bdat", "", path), "_anonymized.xpt"))
file.remove(path)
message("The sas7bdat file was converted to xpt and the original file was removed, as the sas7bdat format was deprecated in haven.")
}
} else if (extension == "xpt"){
if (overwrite){
write_xpt(data, path)
} else {
write_xpt(data, paste0(gsub(".xpt", "", path), "_anonymized.xpt"))
}
}

}
#*~*#

22 changes: 22 additions & 0 deletions R/app_server.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#' Server function for the Shiny app
#'
#' @import shiny
#' @importFrom shiny observeEvent reactiveVal reactiveValues insertUI removeUI updateSelectInput updateNavbarPage updateTabsetPanel updateCheckboxInput updateNumericInput showModal modalDialog textInput actionButton modalButton numericInput renderUI req
#' @importFrom dplyr mutate filter select group_by summarise pull arrange ungroup rename_with across case_when left_join rename
#' @importFrom tools file_ext
#' @importFrom DT renderDataTable datatable formatStyle styleEqual
#' @importFrom PKNCA PKNCAconc PKNCAdose PKNCAdata pk.nca PKNCA.options pknca_units_table
#' @importFrom utils read.csv write.csv
#' @importFrom plotly renderPlotly plotlyOutput plotly_build event_data
#' @importFrom shinyWidgets pickerInput switchInput updatePickerInput
#' @importFrom shinyjqui orderInput
#' @importFrom ggplot2 ggplot geom_errorbar geom_point geom_line labs aes facet_wrap
#' @importFrom zip zipr
#' @importFrom rio export_list
#' @importFrom rmarkdown render
#' @importFrom shinyFiles shinyDirChoose
#'
#' @export
app_server <- function(input, output, session) {
source(system.file("shiny/server.R", package = "aNCA"), local = TRUE)$value(input, output, session)
}
Loading

0 comments on commit c62832a

Please sign in to comment.