From b167abee8d0a9afd0fac0856b56fdcd99c4cb22d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Todor=20Kondi=C4=87?= <todor.kondic@uni.lu> Date: Wed, 15 Jun 2022 10:19:56 +0200 Subject: [PATCH] api, mix, shiny-ui-base: Introduce the concept of "project" and "data"directories for script-based workflow. --- DESCRIPTION | 2 +- NAMESPACE | 3 +- R/api.R | 128 +++++++++++++++++++++------------------------- R/mix.R | 20 ++++---- R/shiny-ui-base.R | 10 ++-- 5 files changed, 76 insertions(+), 87 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index a7bc2bc..832e125 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: shinyscreen Title: Pre-screening of Mass Spectrometry Data -Version: 1.0.13 +Version: 1.1.0 Author: Todor Kondić Maintainer: Todor Kondić <todor.kondic@uni.lu> Authors@R: diff --git a/NAMESPACE b/NAMESPACE index 75bc9d3..915ee97 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,15 +23,14 @@ export(merge2rev) export(mk_comp_tab) export(mk_tol_funcs) export(mz_input) +export(new_project) export(new_rv_state) export(new_state) -export(new_state_fn_conf) export(plot_struct) export(plot_struct_nowrap) export(prescreen) export(read_rt) export(report) -export(report_old) export(rev2list) export(rt_input) export(run) diff --git a/R/api.R b/R/api.R index 44d4308..a3f7260 100644 --- a/R/api.R +++ b/R/api.R @@ -23,14 +23,52 @@ new_state <- function() { new_rv_state <- function() react_v(m=list2rev(new_state())) ##' @export -new_state_fn_conf <- function(fn_conf) { +new_project <- function(project) { m <- new_state() + if (!is.character(project)) stop("Argument `project' must be a character string.") + if (!dir.exists(project)) stop('Project directory either does not exist, or is unreadable.') + project_path <- normalizePath(project) + project <- basename(project) + fn_conf <- file.path(project_path,FN_CONF) m$conf <- read_conf(fn_conf) - init_state(m) + m$conf$project <- project + m$conf$paths$project <- project_path + if (is.null(m$conf$paths$data)) { + m$conf$paths$data <- m$conf$paths$project + } + if (!dir.exists(m$conf$paths$data)) stop("Path to data directory either does not exist, or is inaccesible.") + lst_cmpl <- m$conf$compounds$lists + lst_fn_cmpl <- lapply(names(lst_cmpl),function (nm) { + bfn_cmpl <- lst_cmpl[[nm]] + fn <- file.path(m$conf$paths$project,bfn_cmpl) + if (!file.exists(fn)) stop("File ", fn, " does not exist in ", m$conf$paths$project," .") + fn + }) + names(lst_fn_cmpl) <- names(lst_cmpl) + m$conf$paths$compounds$lists <- lst_fn_cmpl + + fn_sets <- m$conf$compounds$sets[[1]] #It's always only one. + if (!file.exists(fn_sets)) stop("File ", fn_sets, " does not exist in ", m$conf$paths$project," .") + m$conf$paths$compounds$sets <- fn_sets + + tmp <- m$conf$paths$datatab + datatab <- if (!is.null(tmp)) { + if (file.exists(tmp)) { + tmp + } else { + file.path(m$conf$paths$project,tmp) + } + } else { + file.path(m$conf$paths$project,FN_DATA_TAB) + } + if (!file.exists(datatab)) stop("A CSV file with data file entries does not exist (`paths$datatab' in config).") + datatab <- normalizePath(datatab) + m$conf$paths$datatab <-datatab + m } ##' @export -run <- function(fn_conf="",m=NULL,phases=NULL,help=F) { +run <- function(project="",m=NULL,phases=NULL,help=F) { all_phases=list(setup=setup_phase, comptab=mk_comp_tab, extract=extr_data, @@ -54,14 +92,11 @@ run <- function(fn_conf="",m=NULL,phases=NULL,help=F) { all_phases[phases] } - m <- if (nchar(fn_conf)!=0) new_state_fn_conf(fn_conf) else if (!is.null(m)) m else stop("(run): Either the YAML config file (fn_conf),\n or the starting state (m) must be provided\n as the argument to the run function.") - - dir.create(m$conf$project, - showWarnings = F, - recursive = T) - m <- withr::with_dir(new=m$conf$project,code = Reduce(function (prev,f) f(prev), - x = the_phases, - init = m)) + m <- if (nchar(project)!=0) new_project(project) else if (!is.null(m)) m else stop("(run): Either the YAML config file (project),\n or the starting state (m) must be provided\n as the argument to the run function.") + ## m$conf$project <- normalizePath(m$conf$project) #FIXME: Test in all workflows! + m <- withr::with_dir(new=m$conf$paths$project,code = Reduce(function (prev,f) f(prev), + x = the_phases, + init = m)) return(invisible(m)) } @@ -95,7 +130,7 @@ run_in_dir <- function(m) { load_compound_input <- function(m) { coll <- list() fields <- colnames(EMPTY_CMPD_LIST) - fns <- m$conf$compounds$lists + fns <- m$conf$paths$compounds$lists coltypes <- c(ID="character", SMILES="character", Formula="character", @@ -138,15 +173,18 @@ load_compound_input <- function(m) { cmpds[,("known"):=.(the_ifelse(!is.na(SMILES),"structure",the_ifelse(!is.na(Formula),"formula","mz")))] m$input$tab$cmpds <- cmpds - m$input$tab$setid <- read_setid(m$conf$compounds$sets, + m$input$tab$setid <- read_setid(m$conf$paths$compounds$sets, m$input$tab$cmpds) m } ##' @export load_data_input <- function(m) { - m$input$tab$mzml <- file2tab(m$conf$data) + m$input$tab$mzml <- file2tab(m$conf$paths$datatab) assert(all(unique(m$input$tab$mzml[,.N,by=c("adduct","tag")]$N)<=1),msg="Some rows in the data table contain multiple entries with same tag and adduct fields.") + pref<-m$conf$paths$data + m$input$tab$mzml[,file:=fifelse(file.exists(file),file,file.path(..pref,file))] + m$input$tab$mzml[,file:=normalizePath(file)] m } @@ -168,8 +206,9 @@ mk_comp_tab <- function(m) { setkey(cmpds,ID) ## mzml[,`:=`(wd=sapply(file,add_wd_to_mzml,m$conf$project))] assert(nrow(cmpds)>0,msg="No compound lists have been provided.") + assert(all(mzml[,unique(set)] %in% setid[,unique(set)]),msg="Not all set names in the `datatab' data file table match those in the provided set list.") message("Begin generation of the comprehensive table.") - + comp <- cmpds[setid,on="ID"][mzml,.(tag,adduct,ID,RT,set,Name,file,SMILES,Formula,mz,known),on="set",allow.cartesian=T] tab2file(tab=comp,file=paste0("setidmerge",".csv")) setkey(comp,known,set,ID) @@ -272,7 +311,7 @@ verify_data_df <- function(mzml,all_sets) { verify_data <- function(conf,all_sets) { ## * Existence of input files - fn_data <- conf$data + fn_data <- conf$paths$data assert(isThingFile(fn_data),msg=paste("Data table does not exist:",fn_data)) mzml <- file2tab(fn_data) verify_data_df(mzml=mzml,all_sets) @@ -439,7 +478,7 @@ extr_data_future <- function(m) { fn_ex <- get_fn_extr(m) timetag <- format(Sys.time(), "%Y%m%d_%H%M%S") - saveRDS(object = m, file = file.path(m$conf$project, + saveRDS(object = m, file = file.path(m$conf$paths$project, paste0(timetag,"_",FN_EXTR_STATE))) m @@ -514,7 +553,7 @@ extr_data_serial <- function(m) { fn_ex <- get_fn_extr(m) timetag <- format(Sys.time(), "%Y%m%d_%H%M%S") - saveRDS(object = m, file = file.path(m$conf$project, + saveRDS(object = m, file = file.path(m$conf$paths$project, paste0(timetag,"_",FN_EXTR_STATE))) m @@ -689,55 +728,6 @@ create_plots <- function(m) { m } -#' @export -report_old <- function(m) { - figtopdir <- FIG_TOPDIR #file.path(m$conf$project,FIG_TOPDIR) - pander::evalsOptions("graph.output","pdf") - author <- if (!is.null(m$conf$report$author)) m$conf$report$author else REPORT_AUTHOR - title <- if (!is.null(m$conf$report$title)) m$conf$report$title else REPORT_TITLE - doc <- pander::Pandoc$new(author,title) - doc$add(pander::pandoc.header.return("Plots",level = 1)) - sets <- m$out$tab$flt_summ[,unique(set)] - rep_theme <- ggplot2::labs(title = NULL) - for (s in sets) { - doc$add(pander::pandoc.header.return(paste('Set', s), level = 2)) - sdf <- m$out$tab$flt_summ[set==s,] - group <- sdf[,unique(adduct)] - for (g in group) { - asdf <- sdf[adduct==g,] - ids <- asdf[,unique(ID)] - for (id in ids) { - message("Image ","set: ",s," group: ", g, " id: ",id) - doc$add(pander::pandoc.header.return(paste('ID',id),level = 3)) - tab <- asdf[ID==id,.(tag,ms1_int,ms1_rt,adduct,mz,file)] - ms2info <- m$out$tab$ms2_spec[adduct==g & ID==id,.(tag,ID,rt,ms2_max_int,file)] - tab2 <- tab[ms2info,on="file"][,.(tag,mz,adduct,"$RT_{ms1}$[min]"=ms1_rt,"$RT_{ms2}$[min]"=rt,"$I{ms1}$"=formatC(ms1_int, format="e",digits = 2), "$I(ms2)$"= formatC(ms2_max_int, format="e",digits = 2))] - data.table::setorderv(tab2,c("$I{ms1}$","$I(ms2)$"),c(-1,-1)) - doc$add.paragraph("") - figpath <- fig_path(top=figtopdir,set=s,group=g,id=id,suff="all",ext="pdf") - doc$add(pander::pandoc.image.return(img=paste0("file:",figpath))) - doc$add.paragraph("") - message("Adding table.") - doc$add.paragraph(pander::pandoc.table.return(tab2)) - message("Done adding table.") - ## doc$add(print(tab)) - doc$add.paragraph("") - - } - - } - } - doc$add(pander::pandoc.header.return("Appendix", level = 1)) - doc$add(pander::pandoc.header.return("Configuration",level = 2)) - doc$add(m$conf) - doc$add(pander::pandoc.header.return("R Session Info",level = 2)) - doc$add(sessionInfo()) - m$out$report <- doc - m$out$report$export('report.pdf') - m -} - - #' @export #' @title app #' @param shiny_args `list`, optional list of arguments conveyed to @@ -870,12 +860,12 @@ report <- function(m) { message("(report) Knitting of chunk ",n," out of ",NROW(keytab)," has been completed.") } - fn_rep <- file.path(m$conf$project,"report.Rmd") + fn_rep <- file.path(m$conf$paths$project,"report.Rmd") message("(report) Writing Rmd...") cat(repdoc,file=fn_rep,sep = "\n") message("(report) ...done.") message("(report) Render start ...") - rmarkdown::render(fn_rep,output_dir = m$conf$project) + rmarkdown::render(fn_rep,output_dir = m$conf$paths$project) message("(report) ...done.") m } diff --git a/R/mix.R b/R/mix.R index 223972b..361bee9 100644 --- a/R/mix.R +++ b/R/mix.R @@ -497,8 +497,8 @@ read_setid <- function(fn,cmpds) { write_conf <- function(m,fn) { - m$conf$data <- get_fn_ftab(m) - if (NROW(m$input$tab$mzml)>0) tab2file(tab=m$input$tab$mzml,file=file.path(m$conf$project,FN_DATA_TAB)) + m$conf$paths$data <- get_fn_ftab(m) + if (NROW(m$input$tab$mzml)>0) tab2file(tab=m$input$tab$mzml,file=file.path(m$conf$paths$project,FN_DATA_TAB)) yaml::write_yaml(x=m$conf,file=fn) @@ -506,12 +506,12 @@ write_conf <- function(m,fn) { } write_state <- function(m,fn_conf) { write_conf(m,fn_conf) - tab2file(tab=m$input$tab$mzml,file=file.path(m$conf$project,FN_DATA_TAB)) + tab2file(tab=m$input$tab$mzml,file=file.path(m$conf$paths$project,FN_DATA_TAB)) } read_conf <- function(fn) { cf <- yaml::yaml.load_file(fn) - fnl <- cf$compound$lists + fnl <- cf$compounds$lists if (length(fnl)>0) { nms <- character(0) for (i in 1:length(fnl)) { @@ -520,7 +520,7 @@ read_conf <- function(fn) { names(fnl) <- nms } - cf$compound$lists <- fnl + cf$compounds$lists <- fnl ## conf_trans(cf) cf } @@ -529,28 +529,28 @@ read_conf <- function(fn) { ##' @export get_fn_comp <- function(m) { - file.path(m$conf$project,FN_COMP_TAB) + file.path(m$conf$paths$project,FN_COMP_TAB) } ##' @export get_fn_summ <- function(m) { - file.path(m$conf$project, FN_SUMM) + file.path(m$conf$paths$project, FN_SUMM) } ##' @export get_fn_extr <- function(m) { - file.path(m$conf$project, "extracted.rds") + file.path(m$conf$paths$project, "extracted.rds") } ##' @export get_fn_conf <- function(m) { - file.path(m$conf$project, FN_CONF) + file.path(m$conf$paths$project, FN_CONF) } ##' @export get_fn_ftab <- function(m) { - file.path(m$conf$project, FN_DATA_TAB) + file.path(m$conf$paths$project, FN_DATA_TAB) } init_state <- function(m) { diff --git a/R/shiny-ui-base.R b/R/shiny-ui-base.R index 993910e..ffad906 100644 --- a/R/shiny-ui-base.R +++ b/R/shiny-ui-base.R @@ -658,7 +658,7 @@ mk_shinyscreen_server <- function(projects,init) { isolate({ rvs$m$conf$project <- in_conf$project - rvs$m$conf$data <- in_conf$data + rvs$m$conf$paths <- in_conf$paths ## Lists rvs$m$conf$compounds$lists <- in_conf$compounds$lists rvs$m$conf$compounds$sets <- in_conf$compounds$sets @@ -696,8 +696,8 @@ mk_shinyscreen_server <- function(projects,init) { choices=c("min","s")) ## Files - if (isTruthy(in_conf$data)) { - df <- shinyscreen:::file2tab(in_conf$data) + if (isTruthy(in_conf$paths$data)) { + df <- shinyscreen:::file2tab(in_conf$paths$data) dfile <- data.table::copy(df[,tag:=as.character(tag),with=T]) dfile <- dfile[,unique(.SD),.SDcol=c("file","tag")] ## rv_dfile(df[,.(file,tag),by=c("file","tag"),mult="first"][,file:=NULL]) @@ -827,7 +827,7 @@ mk_shinyscreen_server <- function(projects,init) { rf_conf_state <- reactive({ state <- rf_conf_proj() ftab <- get_fn_ftab(state) - state$conf$data <- ftab + state$conf$paths$data <- ftab state$conf[["summary table"]]$filter <- rf_get_subset() state$conf[["summary table"]]$order <- rf_get_order() state @@ -1170,7 +1170,7 @@ mk_shinyscreen_server <- function(projects,init) { yaml::write_yaml(m$conf, file = fconf) shinyscreen:::tab2file(tab=m$input$tab$mzml,file=ftab) - m$conf$data <- ftab + m$conf$paths$data <- ftab saveRDS(object=m,file=fn) } shinymsg("Saving state completed.") -- GitLab