-
Todor Kondić authored
* state(pack_project): New function. * tests: New tests.
Todor Kondić authored* state(pack_project): New function. * tests: New tests.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
shiny-ui-base.R 67.42 KiB
## Copyright (C) 2020,2021 by University of Luxembourg
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
## http://www.apache.org/licenses/LICENSE-2.0
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##' @importFrom shiny validate
##' @importFrom promises future_promise
##' @importFrom promises %...>%
react_v = shiny::reactiveValues
react_f = shiny::reactive
react_e = shiny::eventReactive
obsrv = shiny::observe
obsrv_e = shiny::observeEvent
isol = shiny::isolate
embed_rmd <- function(fn) {
}
celledit_values <- function(col,values,labels=NULL,addna=T) {
if (is.null(labels)) labels = values
if (length(values)==0 || nchar(values)==0) return(character(0))
part1 = mapply(function (v,l) {
sprintf("{value: '%s', display: '%s'},",v,l)
},
head(values,-1),
head(labels,-1),
USE.NAMES = F)
part2 = sprintf("{value: '%s', display: '%s'}",tail(values,1),tail(labels,1))
res = if (length(part1)>0 || length(part2)>0) {
a1 = c("{",sprintf("column: %s, ",col),
"type: 'list', ",
"options: [")
a2 = c(part1,part2,"]","}")
if (addna) c(a1,"{value: 'NA', display: 'NA'},",a2) else c(a1,a2)
} else character(0)
as.character(res)
}
shinymsg <- function(ui,duration=NULL,type="message",...) showNotification(ui=paste(ui,
Sys.time(),
sep="\n"),
duration=duration,
type=type,...)
# volumes <- function() c(wd=getwd(), shinyFiles::getVolumes()())
validate1 <- function(expr,msg) shiny::validate(shiny::need(expr,msg))
path2vol <- function(path) {
## This function returns shinyFiles compatible volumes.
splits = split_path(path)
file.path(tail(splits,1),'')
}
prim_box<-function(...) {shinydashboard::box(...,
status="primary",
solidHeader=T)}
good_box<-function(...) {shinydashboard::box(...,
status="success",
solidHeader=T)}
err_box<-function(...) {shinydashboard::box(...,
status="danger",
solidHeader=T)}
inact_box<-function(...) {shinydashboard::box(...,
status="danger",
solidHeader=T)}
html<-function(...) {shiny::tags$div(shiny::HTML(...))}
## num_input<-function(...,width=NUM_INP_WIDTH) {shiny::tags$div(id="inline",shiny::textInput(...,width=width))}
num_input <- function(inputId,label,...,width=NUM_INP_WIDTH) {
shiny::tags$div(style="display:inline-block",
shiny::tags$label(label, `for` = inputId),
shiny::tags$input(id = inputId, type = "text",style=paste("width:",width,sep = ""),...))
}
num_input_unit <- function(inputId,l1,l2,width=NUM_INP_WIDTH,...) {
shiny::tags$div(style="display:inline-block",
shiny::tags$label(l1, `for` = inputId),
shiny::tags$input(id = inputId, type = "text",style=paste("width:",width,sep = ""),...),
shiny::tags$label(paste(" ",l2,sep=""), `for` = inputId))
}
txt_file_input <- function(inputId,input,fileB,label,volumes,default = "") {
fnobj=shinyFiles::parseFilePaths(roots = volumes,
selection = input[[fileB]])
fn = fnobj[['datapath']]
if (isThingFile(fn)) {
shiny::textInput(inputId = inputId,
label = label,
value = fn)
} else {
shiny::isolate(currFn = input[[inputId]])
if (!isThingFile(currFn)) {
shiny::textInput(inputId = inputId,
label = label,
value = default)
} else {
shiny::textInput(inputId = inputId,
label = label,
value = currFn)
}
}
}
##' @export
mz_input <- function(input_mz,input_unit,width=NUM_INP_WIDTH,height=NUM_INP_HEIGHT,def_mz=0,def_unit="Da",pref="+/-") {
style = "display: inline-block; vertical-align:top; width: "
stylel = "display: inline-block; vertical-align:top;"
style=paste0(style,width,"; ")
shiny::div(shiny::div(style=stylel,
shiny::tags$label(pref,`for`=input_mz)),
shiny::div(style=style,
shiny::numericInput(input_mz,
label=NULL,
value = def_mz)),
shiny::div(style=style,
shiny::selectInput(input_unit,
label=NULL,
c("ppm","Da"),
selected=def_unit)))
}
##' @export
rt_input <- function(input_rt,input_unit,width=NUM_INP_WIDTH,width_u=NUM_INP_WIDTH,height=NUM_INP_HEIGHT,def_rt=0,def_unit="min",pref="+/-") {
width=paste0(as.character(width), "%")
width_u=paste0(as.character(width_u), "%")
style="display: inline-block; vertical-align:top; width: "
style=paste0(style,width,"; ")
style="display: inline-block; vertical-align:top;"
stylel = "display: inline-block; vertical-align:top;"
styleu = paste0("display: inline-block; vertical-align:top; color: black; width: ",width_u,";")
shiny::div(shiny::div(style=stylel,
shiny::tags$label(pref,`for`=input_rt)),
shiny::div(style=style,
shiny::numericInput(input_rt,
label=NULL,
value = def_rt)),
shiny::div(style=styleu,
shiny::selectInput(input_unit,
label=NULL,
c("min","s"),
selected=def_unit)))
}
##'@export
rev2list <- function(rv) {
## Take reactive values structure and convert them to nested
## lists.
if (class(rv)[[1]] != "reactivevalues")
rv else lapply(shiny::reactiveValuesToList(rv),rev2list)
}
##' @export
list2rev <- function(lst) {
## Take nested named list and create reactive values from it.
if (class(lst)[[1]] != "list")
lst else do.call(react_v,lapply(lst,list2rev))
}
mk_roots <- function(wd) local({
addons = c("project"=norm_path(wd))
def_vol <- function() {
path = addons[['project']]
svols = shinyFiles::getVolumes()()
vol = path2vol(path)
sel = match(vol,svols)
res = names(svols)[[sel]]
res
}
list(set=function (rts) {addons <<- rts},
get=function () c(addons,shinyFiles::getVolumes()()),
def_vol=def_vol,
def_path=function() {
vol = def_vol()
svols = shinyFiles::getVolumes()()
pref = svols[[vol]]
res = sub(paste0(pref,'(.*)'),'\\1',addons[["project"]])
message('Relative path: ',res)
res
})
})
#' @export
merge2rev <- function(rev,lst) {
crawllist <- function(lst,currname=""){
cls = class(lst)
if (cls[[1]]=="list" && length(names(lst)) > 0)
invisible(lapply(names(lst),
function (nm)
crawllist(lst[[nm]],
currname=paste0(currname,'[["',nm,'"]]'))))
else {
currname
}
}
vars = unlist(crawllist(lst),recursive = T)
vars
pref_r = deparse(substitute(rev))
pref_l = deparse(substitute(lst))
lhs = paste0(pref_r,vars)
rhs = paste0(pref_l,vars)
exprs = Map(function (a,b) call("<-",
parse(text=a)[[1]],
parse(text=b)[[1]]),
lhs,
rhs)
code = quote({})
for (n in 1:length(exprs)) {
code[[n+1]] = exprs[[n]]
}
code
}
## Given a data.frame/table, swap internal names for nicer-to-view
## names used in DTs.
style_tab_cols <- function (dt) {
old = colnames(dt)
new = list()
for (nm in old) {
new = c(switch(EXPR = nm,
"adduct" = "Adduct",
"tag" = "File Tag",
"ms1_int" = "I(ms1)",
"ms1_rt" = "RT(ms1) [min]",
"ms2_int" = "I(ms2)",
"ms2_rt" = "RT(ms2) [min]",
"ms2_sel" = "Selected?",
"qa_ms2_near" ="MS1/MS2 RT match?",
"qa_ms2_exists" = "MS2 Exists?",
"qa_ms2_good_int" = "Above threshold?",
"qa_ms1_exists" = "MS1 Exists?",
"qa_ms1_good_int" = "Above threshold?",
"qa_ms1_above_noise" = "Not noisy?",
nm),new)
}
rev(new)
}
## Format typical cols with typical digits for a DT `dt`.
style_tab_signif <- function(dt) {
numcols = c(mz=SIGNF_MZ,
"ms1_int"=SIGNF_I,
"ms2_int"=SIGNF_I,
"ms1_rt"=SIGNF_RT,
"ms2_rt"=SIGNF_RT)
for (col in names(numcols)) {
dt = tryCatch(DT::formatSignif(dt,col,digits = numcols[[col]]),
error = function(e) dt)
}
dt
}
## A customised DT intended for spec data.
styled_dt <- function(tab,
extensions = 'Scroller',
scrollY=200L,
dom = "t",
scroller = T,
ordering = F,
colnames = style_tab_cols(tab),
rownames = F,
filter = 'top',
...) {
options = list(scrollY=scrollY,
scrollX=T,
dom = "t",
deferRender = T,
scroller = scroller,
ordering = ordering)
dttab <- DT::datatable(tab,
options = options,
colnames = colnames,
rownames = rownames,
filter = filter,
...)
dttab
style_tab_signif(dttab)
}
dt_drop_callback = function (col_adduct,col_set,sets) DT::JS(c(
"var tbl = $(table.table().node());",
"var id = tbl.closest('.datatables').attr('id');",
"function onUpdate(updatedCell, updatedRow, oldValue) {",
" var cellinfo = [{",
" row: updatedCell.index().row + 1,",
" col: updatedCell.index().column,",
" value: updatedCell.data()",
" }];",
" Shiny.setInputValue(id + '_cell_edit:DT.cellInfo', cellinfo);",
"}",
"table.MakeCellsEditable({",
" onUpdate: onUpdate,",
" inputCss: 'my-input-class',",
sprintf(" columns: [%s, %s],",col_adduct,col_set),
" confirmationButton: false,",
" inputTypes: [",
celledit_values(col_adduct,DISP_ADDUCTS),
",",
celledit_values(col_set,sets),
" ]",
"});"))
dt_summ_subset_callback = function () DT::JS(c(
"var tbl = $(table.table().node());",
"var id = tbl.closest('.datatables').attr('id');",
"function onUpdate(updatedCell, updatedRow, oldValue) {",
" var cellinfo = [{",
" row: updatedCell.index().row + 1,",
" col: updatedCell.index().column,",
" value: updatedCell.data()",
" }];",
" Shiny.setInputValue(id + '_cell_edit:DT.cellInfo', cellinfo);",
"}",
"table.MakeCellsEditable({",
" onUpdate: onUpdate,",
" inputCss: 'my-input-class',",
" columns: [1],",
" confirmationButton: false,",
" inputTypes: [",
celledit_values('1',SUBSET_VALS,addna=F),
" ]",
"});"))
render_dt <- function(data, server = T) {
DT::renderDT(data, server = server)
}
dropdown_dt <- function(tab,callback,rownames=F,editable="cell",selection = "none",...) {
ce_path = system.file("www", package = "shinyscreen")
dep = htmltools::htmlDependency(
"CellEdit", "1.0.19", ce_path,
script = "dataTables.cellEdit.js",
stylesheet = "dataTables.cellEdit.css",
all_files = FALSE)
tab = DT::datatable(tab,
callback = callback,
rownames = rownames,
selection = selection,
fillContainer = T,
...)
tab$dependencies = c(tab$dependencies, list(dep))
tab
}
simple_style_dt <- function(tab,
rownames = F,
...) {
tab = DT::datatable(tab,
rownames = rownames,
fillContainer=T,
...)
tab
}
scroll_style_dt <- function(tab,
rownames = F,
deferRender = T,
options = list(),
...) {
DT::datatable(tab,
rownames=rownames,
options= c(list(deferRender = deferRender,
scrollY = 400L,
scroller = TRUE),
options),
extensions = 'Scroller',
...)
}
scroll_dropdown_dt <- function(tab,callback,rownames=F,editable="cell",selection = "none",...) {
ce_path = system.file("www", package = "shinyscreen")
dep = htmltools::htmlDependency(
"CellEdit", "1.0.19", ce_path,
script = "dataTables.cellEdit.js",
stylesheet = "dataTables.cellEdit.css",
all_files = FALSE)
tab = scroll_style_dt(tab,
callback = callback,
rownames = rownames,
selection = selection,
...)
tab$dependencies = c(tab$dependencies, list(dep))
tab
}
mk_shinyscreen_server <- function(projects,init) {
## This used to be context='setup'.
## library(shinydashboard)
def_state = new_state()
def_datafiles = shinyscreen:::dtable(file=character(0),
tag=character(0))
def_datatab = shinyscreen:::dtable("tag"=factor(),
"adduct"=factor(levels=shinyscreen:::DISP_ADDUCTS),
"set"=factor())
def_summ_subset = shinyscreen:::dtable("QA Column"=shinyscreen:::QA_FLAGS,
"Select"=factor("ignore",levels=shinyscreen:::SUBSET_VALS))
## RMassBank masks shiny::validate. Unmask it.
validate = shiny::validate
## def_state$input$tab$tags = def_datatab
## The reactive world.
rvs = reactiveValues(m=def_state,
gui=create_gui(),
status=reactiveValues(is_extracted_stat=NA_character_,
is_qa_stat=NA_character_,
ms1_coarse_stat=NA_character_,
ms1_fine_stat=NA_character_,
ms1_eic_stat=NA_character_,
rt_stat=NA_character_,
ms1_int_thresh_stat=NA_character_,
ms2_int_thresh_stat=NA_character_,
s2n_stat=NA_character_,
ret_time_shift_tol_stat=NA_character_))
compl_sets = eventReactive(rvs$m$input$tab$setid,
rvs$m$input$tab$setid[,unique(set)])
## Reactive values to support some of the UI elements.
## Modifiable version.
the_summ_subset = data.table::copy(def_summ_subset)
## Re-definitions.
PLOT_FEATURES = shinyscreen:::PLOT_FEATURES
## Plotting parameters.
## Transient rt range.
rv_rtrange = reactiveValues(min=Inf,
max=-Inf)
## Transient mz range.
rv_mzrange = reactiveValues(min=NA,
max=NA)
## Other transient values.
rv_tran = reactiveValues(qa_compsel_tab=dtable(), # QA clickable table for MS1.
qa_ms2sel_tab=dtable()) # QA clickable table for MS2.
rv_projects = reactiveVal(projects)
## Some more setup.
ord_nms = gsub("^-(.+)","\\1",DEF_INDEX_SUMM)
ord_asc = grepl("^-.+",DEF_INDEX_SUMM)
ord_asc = factor(ifelse(ord_asc, "descending", "ascending"),levels = c("ascending","descending"))
def_ord_summ = shinyscreen:::dtable("Column Name"=ord_nms,"Direction"=ord_asc)
## Modifiable version.
the_ord_summ = data.table::copy(def_ord_summ)
gen_compsel_tab <- function(summ,criteria=character(0)) {
## Given summary table, create a table with only adduct/tag/ID
## entries and associated MS1 quantities.
seln = logical(length(criteria))
res =if (length(seln)>0) {
names(seln) =criteria
seln[] = T
critab = do.call(data.table::data.table,as.list(seln))
summ = summ[critab,on=names(critab)]
summ[,unique(.SD),.SDcol=c("adduct","tag","ID",
"mz","ms1_rt","ms1_int",
"Name")]
} else {
summ[,unique(.SD),.SDcol=c("adduct","tag","ID",
"mz","ms1_rt","ms1_int",
"Name")]
}
data.table::setkeyv(res,c("adduct", "tag", "mz","ms1_rt"))
res
}
gen_qa_compsel_tab <- function(clicked,compsel,summ) {
## Given the info about what was clicked in compsel table,
## retrieve QA information and return it as a table.
info = get_key_sel_cmpd(clicked,compsel)
if (NROW(info$key)==0) return (dtable(qa_ms1_exists=character(0),
qa_ms1_good_int=character(0),
qa_ms1_above_noise=character(0)))
summ[info$key,.(qa_ms1_exists=fixlog2yesno(qa_ms1_exists),
qa_ms1_good_int=fixlog2yesno(qa_ms1_good_int),
qa_ms1_above_noise=fixlog2yesno(qa_ms1_above_noise)),
on=c("adduct","tag","ID")][,unique(.SD)]
}
gen_ms2_sel <- function(tab,sel_dt) {
triv = dtable(an=character(0),
ms2_rt=character(0),
ms2_int=character(0),
CE=character(0),
ms2_sel=character(0),
qa_ms2_good_int=character(0),
qa_ms2_near=character(0),
qa_ms2_exists=character(0))
coln = colnames(triv)
res = if (NROW(sel_dt)>0) {
tab[sel_dt,..coln,on=c("adduct","tag","ID")]
} else triv
data.table::setkeyv(res,c("ms2_rt","ms2_int"))
if (NROW(sel_dt)>0) {
res[,`:=`(ms2_sel=fixlog2yesno(ms2_sel),
qa_ms2_good_int=fixlog2yesno(qa_ms2_good_int),
qa_ms2_near=fixlog2yesno(qa_ms2_near),
qa_ms2_exists=fixlog2yesno(qa_ms2_exists))]
}
res
}
gen_ms2_sel_spec <- function(tab,sel_dt) {
triv = dtable(mz=numeric(0),
intensity=numeric(0))
coln = colnames(triv)
res = if (NROW(sel_dt)>0) {
tab[sel_dt,..coln,on=c("adduct","tag","ID","an")]
} else triv
data.table::setnames(res,"intensity","ms2_int")
res
}
gen_plot_comp_sel <- function(summ) {
res = summ[,unique(.SD),.SDcol=c("adduct","ID",
"mz",
"Name")]
data.table::setkeyv(res,c("adduct", "mz"))
res
}
uni_ass <- function(input,val,unit) {
paste(input[[val]],
input[[unit]])
}
adapt_range <- function(fig,x_range=NULL) {
if (is.null(x_range)) fig else fig+coord_cartesian(xlim=x_range)
}
plot_boiler <- function(m,tab,row,plot_fun,rv_x_range,adapt_x_range=T) {
plot_group = m$conf$figures$grouping$group
plot_plot = m$conf$figures$grouping$plot
req(row)
idx = get_plot_idx(tab = tab,
plot_group = plot_group,
plot_plot = plot_plot,
row =row)
fig = plot_fun(m=m,plot_index = idx)
x_range = if (adapt_x_range) c(rv_x_range$min,rv_x_range$max) else NULL
adapt_range(fig,x_range=x_range)
}
get_plot_idx <- function(tab,plot_group,plot_plot,row) {
pg = tab[row,..plot_group]
pp = tab[row,..plot_plot]
res = c(pg,pp)
names(res) = c(plot_group,plot_plot)
res
}
## This is a JavaScript callback which is meant to capture double
## clicks on DT datatables and return data in an input field of
## the form input$tblId_dbl_click_pos.
dblclick_callback <- paste0(c(
"table.on('dblclick.dt', 'td', function(){",
"var tbl = table.table().node();",
"var tblId = $(tbl).closest('.datatables').attr('id');",
"row_ = table.cell(this).index().row;",
"col_ = table.cell(this).index().column;",
"var schmuck = new Date().getTime();",
"var res = {row: row_ + 1,col: col_ + 1, chg: schmuck};",
"Shiny.setInputValue(tblId + '_dbl_click_pos', res);",
"})"
),collapse = "\n")
get_pos_from_dblclick <- function(pos,currrows=NULL) {
if (length(pos) == 0) return(NULL)
nr = pos$row
nc = pos$col
rows = if (!is.null(currrows)) currrows[nr] else nr
data.frame(row=rows,col=nc)
}
get_tab_sel <- function(clicked,selector,keys) {
nr = clicked$row
nc = clicked$col
colnms = names(selector)
the_name = colnms[[nc]]
sel_row = selector[nr,..keys]
list(col=the_name,
key=sel_row)
}
## Get info about compound selected in the browser.
get_key_sel_cmpd <- function(clicked,selector) {
if (length(clicked) == 0) return(dtable())
get_tab_sel(clicked,selector,c('adduct','tag','ID'))
}
## Info about MS2 spectrum selected.
get_ms2_sel <- function(clicked,selector) {
get_tab_sel(clicked,selector,c('CE','an'))
}
pdf(file="dummy.pdf",width = 1.9685,height = 1.9685)
dev.off()
server <- function(input,output,session) {
## REACTIVE VALUES
## RUNTIME REACTIVE VALUES
## Those that we don't care about when saving state; Usually
## can be inferred by the program.
rv_extr_flag = reactiveVal(F)
rv_presc_flag = reactiveVal(F)
rtimer1000 = reactiveTimer(1000)
rtimer_presc = reactiveTimer(500)
rv_summ_subset = reactiveVal(data.frame()) # Used to generate sel_spec list (among other things?).
## Holds single entry metfrag summary.
rv_mf1tab = reactiveVal(NULL)
## REACTIVE FUNCTIONS
rf_compound_set <- reactive({
req(rvs$gui$compounds$sets,
rvs$gui$paths$project)
get_sets(rvs$gui)
})
rf_get_sets <- reactive({
req(rvs$gui$paths$project,
rvs$gui$compounds$sets)
get_sets(rvs$gui)
})
## REACTIVE FUNCTIONS: COMPOUND INDEX
rf_get_cindex <- reactive({
## TODO: FIXME: Uncomment after rearranging everything.
## input$cmt_changes_b
rvs$status$is_qa_stat
s1 = input$sort1
s2 = input$sort2
s3 = input$sort3
s4 = input$sort4
x = cindex_from_input(clabs=input$cindex_group,
sort_catg=c(s1,s2,s3,s4),
summ=req(rvs$m$out$tab$summ))
x
})
## Get current grouping categories (`cindex key').
rf_get_cindex_key <- reactive({
cind = rf_get_cindex()
req(NROW(cind)>0L)
get_cindex_key(cind)
})
## Get currently selected cindex values as a list.
rf_get_cindex_kval <- reactive({
cind = rf_get_cindex()
key = rf_get_cindex_key()
row = input$cindex_rows_selected
get_cindex_kval(cind,row,key)
})
## Get the labels which will define plot curves in EIC MS1.
rf_get_cindex_labs <- reactive({
key = rf_get_cindex_key()
res = setdiff(CINDEX_BY,key)
if (length(res)!=0L) res else CINDEX_BY
})
rf_get_cindex_parents <- reactive({
rvs$m
isolate({
ms1 = rvs$m$extr$ms1
ms2 = rvs$m$extr$ms2
summ = req(rvs$m$out$tab$summ)
})
key = req(rf_get_cindex_key())
kvals = req(rf_get_cindex_kval())
labs = req(rf_get_cindex_labs())
get_cindex_parents(summ,key,kvals,labs)
})
rf_select_from_summ <- reactive({
input$cmt_changes_b
summ = req(rvs$m$out$tab$summ)
parent = input$sel_parent_trace
kvals = req(rf_get_cindex_kval())
ptab = rf_get_cindex_parents()
if (isTruthy(parent)) {
get_summ_subset(summ=summ,
ptab=ptab,
paritem=parent,
kvals=kvals)
} else data.frame()
})
rf_get_ltab <- reactive({
tab = rf_select_from_summ()
if (NROW(tab)!=0) get_ltab(tab) else data.frame()
})
rf_get_ltab_entry <- reactive({
ltab = rf_get_ltab()
if (NROW(ltab)>0L && isTruthy(input$sel_spec)) {
ltab[item==input$sel_spec]
} else data.frame()
})
## REACTIVE FUNCTIONS: PLOTS
## Calculate the palette.
rf_colrdata <- reactive({
keys = req(rf_get_cindex_key())
labs = req(rf_get_cindex_labs())
comp = req(rvs$m$out$tab$comp)
define_colrdata(comp,labs)
})
rf_get_rtrange <- reactive({
x1 = input$plot_rt_min
x2 = input$plot_rt_max
if (is.na(x1)) x1 = NA_real_
if (is.na(x2)) x2 = NA_real_
c(x1,x2)
})
rf_get_irange <- reactive({
y1 = input$plot_i_min
y2 = input$plot_i_max
if (is.na(y1)) y1 = NA_real_
if (is.na(y2)) y2 = NA_real_
c(y1,y2)
})
rf_plot_eic_ms1 <- reactive({
isolate({
ms1 = rvs$m$extr$ms1
summ = rvs$m$out$tab$summ
})
req(NROW(summ)>0L)
req(NROW(ms1)>0L)
p = make_eic_ms1_plot(ms1,summ,kvals=rf_get_cindex_kval(),
labs=rf_get_cindex_labs(),
asp=PLOT_EIC_ASPECT,
rt_range=rf_get_rtrange(),
i_range=rf_get_irange(),
colrdata = rf_colrdata())
p = if (!is.null(p)) p else empty_plot("Nothing to plot")
p
})
rf_get_ms2_eic_rtrange <- reactive({
pms1 = rf_plot_eic_ms1()
drng = range(pms1$data$rt)
urng = rf_get_rtrange()
if (is.na(urng[[1]])) urng[[1]] = drng[[1]]
if (is.na(urng[[2]])) urng[[2]] = drng[[2]]
urng
})
rf_plot_eic_ms2 <- reactive({
isolate({
summ = rvs$m$out$tab$summ
})
req(NROW(summ)>0L)
gg = rf_plot_eic_ms1()
rt_rng = range(gg$data$rt)
p = make_eic_ms2_plot(summ,
kvals=rf_get_cindex_kval(),
labs=rf_get_cindex_labs(),
rt_range = rf_get_ms2_eic_rtrange(),
asp=PLOT_EIC_ASPECT,
colrdata=rf_colrdata())
p = if (!is.null(p)) p else empty_plot("Nothing to plot")
p
})
rf_plot_struct <- reactive({
cind = rf_get_cindex()
key = rf_get_cindex_key()
req(NROW(cind)>0L)
row = req(input$cindex_row_last_clicked)
id = cind[row][,..key][["ID"]][[1]]
smi = rvs$m$out$tab$comp[ID==(id),SMILES][[1]]
make_struct_plot(smi)
})
rf_plot_spec_ms2 <- reactive({
isolate({
summ = rvs$m$out$tab$summ
ms2 = rvs$m$extr$ms2
})
req(NROW(summ)>0L)
req(NROW(ms2)>0L)
p = make_spec_ms2_plot(ms2,
summ,
kvals=req(rf_get_cindex_kval()),
labs=req(rf_get_cindex_labs()),
colrdata=rf_colrdata())
p = if (!is.null(p)) p else empty_plot("Nothing to plot")
p
})
## OBSERVERS
## OBSERVERS: PROJECT MANAGEMENT
observe({
top_data_dir = rvs$gui$paths$project
req(isTruthy(top_data_dir) && dir.exists(top_data_dir))
updateSelectInput(session = session,
inputId = "comp_list",
choices = list.files(path=top_data_dir,
pattern = CMPD_LIST_PATT))
updateSelectInput(session = session,
inputId = "set_list",
choices = list.files(path=top_data_dir,
pattern = SET_LIST_PATT))
updateSelectInput(session = session,
inputId = "dfile_list",
choices = list.files(path=top_data_dir,
pattern = DFILES_LIST_PATT))
updateSelectInput(session = session,
inputId = "top_data_dir_list",
selected = basename(top_data_dir),
choices = list.dirs(path = init$envopts$top_data_dir,
full.names = F,
recursive = F))
})
observe({
top_data_dir = rvs$gui$paths$data
req(isTruthy(top_data_dir) && dir.exists(top_data_dir))
updateSelectInput(session = session,
inputId = "dfile_list",
choices = list.files(path=top_data_dir,
pattern = DFILES_LIST_PATT))
})
## Update projects and data directories every second.
observeEvent(rtimer1000(),{
projects = rv_projects()
curr_projects = list.dirs(path=init$envopts$projects, full.names = F, recursive = F)
if (length(union(curr_projects,projects)) != length(intersect(curr_projects,projects))) {
updateSelectInput(session=session,
inputId="proj_list",
choices=curr_projects)
updateSelectInput(session=session,
inputId="top_data_dir_list",
choices=curr_projects)
rv_projects(curr_projects)
}
}, label = "update-proj-list")
observeEvent(input$load_proj_b,{
## A single place where a new project is initialised, or
## loaded. Everything else works off rvs$m and rvs$gui.
wd = input$proj_list
req(!is.null(wd) && !is.na(wd) && nchar(wd)>0)
fullwd = file.path(init$envopts$projects,wd)
check_dir_absent(fullwd,what="project")
## Load saved state if existing, create if it does not.
fn_packed_state = file.path(fullwd,FN_GUI_STATE)
fn_state = file.path(fullwd,FN_STATE)
if (file.exists(fn_packed_state)) {
message("Loading project: ",wd)
pack = readRDS(file=fn_packed_state)
rvs$gui = unpack_app_state(session=session,
envopt=init$envopts,
input=input,
top_data_dir=init$envopts$top_data_dir,
project_path=fullwd,
packed_state=pack)
## Load computational state.
rvs$m = readRDS(file=fn_state)
## If prescreen config invalid, reinit.
if (length(rvs$m$conf$prescreen)==0) rvs$m$conf = input2conf_prescreen(input=input,conf=rvs$m$conf)
## Update status variables.
m = rvs$m
rvs$status$ms1_coarse_stat = m$conf$tolerance[["ms1 coarse"]]
rvs$status$ms1_fine_stat = m$conf$tolerance[["ms1 fine"]]
rvs$status$ms1_eic_stat = m$conf$tolerance[["eic"]]
rvs$status$rt_stat = m$conf$tolerance[["rt"]]
rvs$status$ms1_int_thresh_stat = rvs$m$conf$prescreen[["ms1_int_thresh"]]
rvs$status$ms2_int_thresh_stat = rvs$m$conf$prescreen[["ms2_int_thresh"]]
rvs$status$s2n_stat = rvs$m$conf$prescreen[["s2n"]]
rvs$status$ret_time_shift_tol_stat = rvs$m$conf$prescreen[["ret_time_shift_tol"]]
if (NROW(m$extr$ms1)>0L) rvs$status$is_extracted_stat = "Yes."
if (NROW(m$out$tab$summ)>0L) rvs$status$is_qa_stat = "Yes."
} else {
message("Initialising project: ",wd)
rvs$gui = create_gui(project_path=fullwd)
}
message("project: ",rvs$gui$project())
}, label = "project-b")
observeEvent(input$save_proj_b,{
fn = file.path(rvs$gui$paths$project,FN_STATE)
fn_packed_state = file.path(rvs$gui$paths$project,FN_GUI_STATE)
fn_tab = file.path(rvs$gui$paths$project,FN_DATA_TAB)
fn_conf =file.path(rvs$gui$paths$project,FN_CONF)
shinymsg(paste("Saving state to: ",fn,"Please wait.",sep="\n"))
message("(config) Saving state to: ", paste(fn,collapse = ","))
message("(config) Saving app state to: ", fn_packed_state)
fn = if (length(fn)>0 && nchar(fn[[1]])>0) fn else ""
if (nchar(fn) > 0) {
m = rvs$m
yaml::write_yaml(m$conf,
file = fn_conf)
shinyscreen:::tab2file(tab=gui2datatab(rvs$gui),file=fn_tab)
pack = pack_app_state(input=input,gui=rvs$gui)
saveRDS(pack,file=fn_packed_state)
saveRDS(rvs$m,file=fn)
}
shinymsg("Saving state completed.")
})
observeEvent(input$sel_data_dir_b,{
data_dir = input$top_data_dir_list
req(isTruthy(data_dir))
rvs$gui$paths$data = file.path(init$envopts$top_data_dir, data_dir)
message("Selected data dir:",rvs$gui$paths$data)
})
observeEvent(input$comp_list_b, {
sels = input$comp_list
req(isTruthy(sels))
rvs$gui$compounds$lists = sels
message("(config) Selected compound lists: ", paste(sels,collapse = ","))
})
observeEvent(input$set_list_b, {
sels = input$set_list
req(isTruthy(sels))
message("(config) Selected set lists: ", paste(sels,collapse = ","))
rvs$gui$compounds$sets = sels
})
observeEvent(input$datafiles_b,{
new_file = input$dfile_list
if (isTruthy(new_file)) {
curr_file = rvs$gui$datatab$file
curr_tag = rvs$gui$datatab$tag
curr_adduct = rvs$gui$datatab$adduct
curr_set = rvs$gui$datatab$set
nb = length(curr_file)
nd = length(new_file)
res_file = c(curr_file,new_file)
res_adduct = c(curr_adduct,rep(NA_character_,nd))
res_set = c(curr_set,rep(NA_character_,nd))
rvs$gui$datatab$file = res_file
rvs$gui$datatab$tag = add_new_def_tag(as.character(rvs$gui$datatab$tag),nd)
rvs$gui$datatab$adduct = res_adduct
rvs$gui$datatab$set = res_set
}
updateSelectInput(session=session,
inputId="dfile_list",
selected=NULL)
})
observeEvent(input$rem_dfiles_b,{
if (isTruthy(input$datafiles_rows_selected)) {
rmv = input$datafiles_rows_selected
rvs$gui$datatab$file = rvs$gui$datatab$file[-rmv]
rvs$gui$datatab$set = rvs$gui$datatab$set[-rmv]
rvs$gui$datatab$adduct = rvs$gui$datatab$adduct[-rmv]
rvs$gui$datatab$tag = rvs$gui$datatab$tag[-rmv]
}
})
observeEvent(input$datafiles_cell_edit,{
df = gen_dfiles_tab(rvs$gui)
df = DT::editData(df,
input$datafiles_cell_edit,
rownames = F)
rvs$gui$datatab$file = as.character(df$file)
rvs$gui$datatab$tag = as.character(df$tag)
}, label = "datafiles-edit")
observeEvent(input$datatab_cell_edit,{
df = gen_dtab(rvs$gui$datatab,sets=rf_get_sets())
z = DT::editData(df,
input$datatab_cell_edit,
rownames = F)
rvs$gui$datatab$set = z$set
rvs$gui$datatab$adduct = z$adduct
}, label = "datatab-edit")
## OBSERVERS: CONFIGURATION AND EXTRACTION
observeEvent(input$extract_b,{
rvs$m = app_state2state(input,rvs$gui,envopts = init$envopts, m=rvs$m) # Update params from GUI.
## Clear out prescreen data if any.
rvs$m$out$tab$summ=EMPTY_SUMM
m = rvs$m
shinymsg("Extraction has started. This may take a while.")
rvs$status$ms1_coarse_stat = m$conf$tolerance[["ms1 coarse"]]
rvs$status$ms1_fine_stat = m$conf$tolerance[["ms1 fine"]]
rvs$status$ms1_eic_stat = m$conf$tolerance[["eic"]]
rvs$status$rt_stat = m$conf$tolerance[["rt"]]
rvs$status$is_extracted_stat = "In progress."
rvs$status$is_qa_stat = "No."
rv_extr_flag(T)
})
observe({
rtimer1000() #Just so we separate the display of status
#from extraction/prescreening. Otherwise, the
#status will only update after the extraction
#is done.
isolate({
if (rv_extr_flag()) {
rv_extr_flag(F)
rvs$m = run(m=rvs$m,
envopts=init$envopts,
phases=c("setup","comptab","extract"))
rvs$status$is_extracted_stat = "Yes."
rvs$status$is_qa_stat = "No."
fn_c_state = file.path(rvs$m$run$paths$project,
paste0("extract.",shinyscreen:::FN_CONF))
yaml::write_yaml(x=rvs$m$conf,file=fn_c_state)
message("(extract) Done extracting.")
message("(extract) Config written to ", fn_c_state)
shinymsg("Extraction has been completed.")
}
})
})
observeEvent(input$presc_b,{
if (NROW(rvs$m$extr$ms1)>0L) {
## Update just prescreening conf.
rvs$m = app_update_conf(input=input,
gui=rvs$gui,
envopts=init$envopts,
fconf="prescreen",
m=rvs$m)
## rvs$m = app_state2state(input,rvs$gui,envopts = init$envopts, m=rvs$m) # Update params from GUI.
rvs$status$ms1_int_thresh_stat = rvs$m$conf$prescreen[["ms1_int_thresh"]]
rvs$status$ms2_int_thresh_stat = rvs$m$conf$prescreen[["ms2_int_thresh"]]
rvs$status$s2n_stat = rvs$m$conf$prescreen[["s2n"]]
rvs$status$ret_time_shift_tol_stat = rvs$m$conf$prescreen[["ret_time_shift_tol"]]
rvs$status$is_qa_stat = "In progress."
rv_presc_flag(T)
} else {
shinymsg("You must extract the data first.",type="warning")
}
})
observe({
rtimer_presc() #Just so we separate the display of status
#from extraction/prescreening. Otherwise, the status
#will only update after the extraction is
#done.
isolate({
if (rv_presc_flag()) {
shinymsg("Prescreening started. Please wait.")
rv_presc_flag(F)
## If user changed prescreening params.
rvs$m = run(m=rvs$m,
envopts=init$envopts,
phases="prescreen")
rvs$status$is_qa_stat = "Yes."
shinymsg("Prescreening has been completed.")
}
})
})
## OBSERVERS: METFRAG
observeEvent(input$mf_database_type,{
dtype = input$mf_database_type
if (dtype %in% METFRAG_LOCAL_DATABASE_TYPE) {
if (dtype == "LocalCSV") patt = "(csv)|(CSV)$"
if (dtype == "LocalSDF") patt = "(sdf)|(SDF)$"
if (dtype == "LocalPSV") patt = "(psv)|(PSV)$"
updateSelectInput(session=session,
inputId="mf_local_database",
choices=list.files(path=init$envopts$metfrag$db_dir,
pattern=patt),
selected=character(0))
} else {
updateSelectInput(session=session,
inputId="mf_local_database",
choices=character(0))
}
}, label = "mf-database-type")
observeEvent(input$mf_local_database,{
fn = input$mf_local_database
if (length(fn) && nchar(fn)>0L) {
e = init$envopts
dbdir = e$metfrag$db_dir
fn = file.path(dbdir,fn)
dtnms = data.table::fread(file=fn,nrows=1L)
nms = names(dtnms)
s1 = intersect(input$mf_local_db_col_ident,
nms)
s2 = intersect(input$mf_local_db_col_scores,
nms)
s3 = intersect(input$mf_local_db_col_coll,
nms)
updateSelectInput(session=session,
inputId="mf_local_db_col_ident",
choices = c(character(0),nms),
selected = s1)
updateSelectInput(session=session,
inputId="mf_local_db_col_scores",
choices = c(character(0),nms),
selected = s2)
updateSelectInput(session=session,
inputId="mf_local_db_col_coll",
choices = c(character(0),nms),
selected = s3)
}
}, label = "mf-local-database")
observeEvent(input$metfrag_all_b,{
shinymsg("MetFrag started. Please wait.")
rvs$m = app_update_conf(input=input,
gui=rvs$gui,
envopts=init$envopts,
fconf = c("metfrag"),
m=rvs$m)
rvs$m = metfrag(rvs$m)
shinymsg("MetFrag finished. Summary file is ready.")
fr=file.path(rvs$m$run$metfrag$path,"metfrag_summary.csv")
to=file.path(rvs$m$run$metfrag$path,input$mf_summ_tab_name)
if (to != fr) file.rename(from=fr,to=to)
})
observeEvent(input$save_mf_single_entry_summ_b,{
kv = req(rf_get_cindex_kval())
fn = file.path(rvs$m$run$metfrag$path,"results",metfrag_gen_entry_fname(kv))
if (!is.null(rv_mf1tab())) {
data.table::fwrite(x=rv_mf1tab(),
file=fn,
quote=T)
shinymsg(paste0("File ",fn," written to metfrag results directory."))
}
})
## OBSERVERS: VIEWER
observeEvent(input$cindex_rows_selected,{
kval = rf_get_cindex_kval()
fname = plot_fname(kval)
updateTextInput(session=session,inputId="single_plot_fname",value=fname)
})
observeEvent(input$make_report_b,{
isolate({
ms1 = rvs$m$extr$ms1
ms2 = rvs$m$extr$ms2
summ = rvs$m$out$tab$summ
})
req(NROW(summ)>0L)
req(NROW(ms1)>0L)
req(NROW(ms2)>0L)
cind = rf_get_cindex()
key = rf_get_cindex_key()
rt_range = rf_get_rtrange()
i_range = rf_get_irange()
labs = req(rf_get_cindex_labs())
projdir = rvs$gui$paths$project
fn = paste0(file.path(projdir,input$report_name),'.pdf')
pdf(file=fn,paper="a4",height=7,width=11)
colrdata = rf_colrdata()
for (ri in 1:NROW(cind)) {
rowtab = cind[ri][,..key]
kvals = lapply(rowtab,function (x) x[[1]])
names(kvals) = key
message('Compound index row: ',ri)
p1 = make_eic_ms1_plot(ms1,summ,kvals=kvals,
labs=labs,
asp=PLOT_EIC_ASPECT,
rt_range=rt_range,
i_range=i_range,
colrdata = colrdata) + theme_print()
p2 = make_eic_ms2_plot(summ,kvals=kvals,
labs=labs,
asp=PLOT_EIC_ASPECT,
rt_range=rt_range,
colrdata = colrdata) + theme_print()
id = cind[ri][,..key][["ID"]][[1]]
smi = rvs$m$out$tab$comp[ID==(id),SMILES][[1]]
p_struc = make_struct_plot(smi)
p_spec = make_spec_ms2_plot(ms2,
summ,
kvals=kvals,
labs=labs,
colrdata=colrdata)+theme_print()
cmb = combine_plots(p1,p2,p_spec,p_struc)
print(cmb)
}
dev.off()
})
observeEvent(input$summ_tab_b,{
projdir = rvs$gui$paths$project
fn = file.path(projdir,input$summ_name)
tab2file(rvs$m$out$tab$summ,fn)
})
observeEvent(input$ms2_spectra_tab_b,{
req(NROW(rvs$m$out$tab$summ)>0L)
projdir = rvs$gui$paths$project
fn = file.path(projdir,input$ms2_spectra_tab_name)
shinymsg(paste0("Saving MS2 spectra table to: ",basename(fn)))
tab2file(pack_ms2_w_summ(rvs$m$out$tab$summ,
rvs$m$extr$ms2),
fn)
shinymsg("Done saving MS2 spectra table.")
})
observeEvent(input$plot_brush,{
xmin = round(input$plot_brush[["xmin"]],3)
xmax = round(input$plot_brush[["xmax"]],3)
ymin = round(input$plot_brush[["ymin"]],3)
ymax = round(input$plot_brush[["ymax"]],3)
if (!is.null(xmin)) updateNumericInput(session=session,
inputId="plot_rt_min",
value=xmin)
if (!is.null(xmax)) updateNumericInput(session=session,
inputId="plot_rt_max",
value=xmax)
if (!is.null(ymin)) updateNumericInput(session=session,
inputId="plot_i_min",
value=ymin)
if (!is.null(ymax)) updateNumericInput(session=session,
inputId="plot_i_max",
value=ymax)
session$resetBrush("plot_brush")
},label = "get_rt_from_selection")
observeEvent(input$plot_rt_click,
{
## TODO: update to sensible range.
updateNumericInput(session=session,
inputId="plot_rt_min",
value=NA_real_)
updateNumericInput(session=session,
inputId="plot_rt_max",
value=NA_real_)
updateNumericInput(session=session,
inputId="plot_i_min",
value=NA_real_)
updateNumericInput(session=session,
inputId="plot_i_max",
value=NA_real_)
}, label = "reset_rt_range")
## OBSERVERS: VIEWER: MEASUREMENT PROPERTIES
## observe({
## }, label = "measure-props-parent")
observeEvent(input$cindex_rows_selected,{
rv_summ_subset(data.frame())
ptab = rf_get_cindex_parents()
if (NROW(ptab)>0L) {
choices = ptab$item
} else choices = character()
updateSelectInput(session = session,
inputId = "sel_parent_trace",
choices = choices,
selected = NULL)
}, label = "sel_spec-clear")
observe({
ctab = rf_get_ltab()
rv_summ_subset(ctab)
}, label = "update-rv_summ_subset")
observe({
ctab = rv_summ_subset()
if (NROW(ctab)!=0) {
disp = if (any(ctab$ms2_sel==T)) ctab[ms2_sel==T,item] else ctab[1L,item]
choices = ctab$item
} else {
choices = character()
disp = NULL
}
updateSelectInput(session = session,
inputId = "sel_spec",
choices = choices,
selected = disp)
}, label = "update-sel_spec")
observe({
input$cmt_changes_b
ltab_entry = rf_get_ltab_entry()
## res = rf_msrprop_get_vals()
res = get_mprop_ms2_metadata(ltab_entry)
valrt = res$rt
valint = res$int
valms2sel = res$ms2_sel
selqa = res$qa
updateNumericInput(session = session,
inputId = "chg_ms1_rt",
value = valrt)
updateNumericInput(session = session,
inputId = "chg_ms1_int",
value = valint)
updateCheckboxGroupInput(session=session,
choices=QABOX_VALS,
inputId="qabox",
selected = selqa)
updateCheckboxInput(session=session,
inputId="chg_ms2sel",
value = valms2sel)
})
observeEvent(input$cmt_changes_b,{
summ = req(rvs$m$out$tab$summ)
ptab = req(rf_get_cindex_parents())
ltab = req(rf_get_ltab())
rvs$m$out$tab$summ = update_on_commit_chg(summ,
input=input,
ptab=ptab,
ltab=ltab)
})
observeEvent(input$plot_save_single,{
p1 = rf_plot_eic_ms1()
p2 = rf_plot_eic_ms2()
p3 = rf_plot_spec_ms2()
pstr = rf_plot_struct()
combo_p = combine_plots(p1,p2,p3,pstr)
dirname = file.path(rvs$gui$paths$project,
FIG_TOPDIR)
if (!is.null(dirname) && nchar(dirname)>0L && !dir.exists(dirname)) dir.create(dirname)
absfname = file.path(rvs$gui$paths$project,
FIG_TOPDIR,
input$single_plot_fname)
if (!is_fname_rds(absfname)) {
ggplot2::ggsave(filename=absfname,
width=21.0,
height=29.7,
units="cm",
plot=combo_p)
} else {
saveRDS(object=combo_p,file=absfname)
}
message("Plots saved to ",absfname)
})
## RENDER
output$curr_proj = renderText({
xx = rvs$gui$project()
txt = if (is.null(xx) || length(xx) == 0L || is.na(xx) || nchar(xx)=="") "Nothing selected." else basename(xx)
paste0("Current project: ", txt)})
output$curr_data_dir = renderText({
xx = rvs$gui$paths$data
txt = if (is.null(xx)) "Nothing selected" else basename(xx)
paste0("Current data directory: ", txt)
})
output$comp_list_report = renderUI({
lsts = rvs$gui$compounds$lists
HTML(if (length(lsts) > 0 &&
isTruthy(lsts) &&
lsts != "Nothing selected.") {
paste(c("<ul>",
sapply(lsts,
function (x) paste("<li><em>",x,"</em></li>")),
"</ul>"))
} else "No compound list selected yet.")
})
output$sets_report = renderUI({
sets = rvs$gui$compounds$sets
HTML(if (isTruthy(sets) && sets != "Nothing selected.")
paste("selected <em>setid</em> table:",
sets) else "No <em>setid</em> table selected.")
})
output$datafiles = DT::renderDT(
{
rvs$gui$datatab$file
rvs$gui$datatab$tag
res = gen_dfiles_tab(rvs$gui)
## simple_style_dt(res,editable=list(target="cell",disable=list(columns=0)))
scroll_style_dt(res,editable=list(target="cell",disable=list(columns=0)))
})
output$datatab = DT::renderDT({
rvs$gui$datatab$tag
rvs$gui$datatab$set
rvs$gui$datatab$adduct
sets = rf_get_sets()
dtab = gen_dtab(rvs$gui$datatab,
sets=sets)
tab = scroll_dropdown_dt(dtab, callback = dt_drop_callback('1','2',sets))
## tab = dropdown_dt(dtab, callback = dt_drop_callback('1','2',sets))
tab
})
output$comp_table = DT::renderDataTable({
## TODO FIXME
## cmpds = rf_get_cmpd_tab()
## validate(need(NROW(cmpds)>0,"No compound list loaded yet."))
## DT::datatable(cmpds,
## ## style = 'bootstrap',
## ## class = 'table-condensed',
## extensions = 'Scroller',
## options = list(scrollX = T,
## scrollY = 300,
## deferRender = T,
## scroller = T))
})
output$setid_table = DT::renderDataTable({
## TODO FIXME
## setid = rf_get_sets_tab()
## validate(need(NROW(setid)>0,"No set id list loaded yet."))
## DT::datatable(setid,
## ## style = 'bootstrap',
## ## class = 'table-condensed',
## extensions = 'Scroller',
## options = list(scrollX = T,
## scrollY = 300,
## deferRender = T,
## scroller = T))
})
## RENDER: METFRAG
output$cando_metfrag = renderText({
if (is_metfrag_available(init$envopts))
"available" else "unavailable"
})
output$entry_mf_summ_fname = renderText({
kv = req(rf_get_cindex_kval())
metfrag_gen_entry_fname(kv)
})
output$entry_mf_summ = DT::renderDT(
{
req(input$gen_mf_single_entry_summ_b)
shiny::isolate({
shinymsg("MetFrag proccessing of a single entry started. Please wait.")
rvs$m = app_update_conf(input=input,
gui=rvs$gui,
envopts=init$envopts,
fconf = c("metfrag"),
m=rvs$m)
kv = rf_get_cindex_kval()
## Some cols that might be needed to be specified
## explicitely. FIXME TODO: Make this more robust.
nsumm = mf_narrow_summ(rvs$m$out$tab$summ,kv,
ms2_rt_i=input$mf_entry_rt_min,
ms2_rt_f=input$mf_entry_rt_max)
if (NROW(nsumm)>0) {
stagtab = metfrag_get_stag_tab(nsumm)
ftab = metfrag_run(param = rvs$m$run$metfrag$param,
path = rvs$m$run$metfrag$path,
subpaths = rvs$m$run$metfrag$subpaths,
db_file = rvs$m$run$metfrag$db_file,
stag_tab = stagtab, ms2 = rvs$m$extr$ms2,
runtime=rvs$m$run$metfrag$runtime,
java_bin=rvs$m$run$metfrag$java_bin,
nproc = rvs$m$conf$metfrag$nproc)
tab = summarise_metfrag_results(param = rvs$m$conf$metfrag$param,
path = rvs$m$run$metfrag$path,
subpaths = rvs$m$run$metfrag$subpaths,
cand_parameters = rvs$m$conf$metfrag$cand_parameters,
db_scores = rvs$m$conf$metfrag$database_scores,
int_scores = rvs$m$conf$metfrag$intrinsic_scores,
collect_candidates= rvs$m$conf$metfrag$collect_candidates,
file_tab = ftab)
tab[stagtab,ms2_rt:=i.ms2_rt,on="stag"]
tab[,stag:=NULL]
nms = names(tab)
tkey = data.table::key(tab)
rest = setdiff(nms,union(tkey,c("ms2_rt")))
frst = union(tkey,c("ms2_rt"))
nnms = c(frst,rest)
data.table::setcolorder(tab,nnms)
tab
} else {
tab = NULL
}
rv_mf1tab(tab)
shinymsg("MetFrag finished.")
scroll_style_dt(tab,fillContainer=T)
})
})
## RENDER: STATUS
output$is_extracted_stat = renderText({
x = rvs$status$is_extracted_stat
if (isTruthy(x)) x else "No."
})
output$is_qa_stat = renderText({
x = rvs$status$is_qa_stat
if (isTruthy(x)) x else "No."
})
output$ms1_coarse_stat = renderText({
req(rvs$status$ms1_coarse_stat)
})
output$ms1_fine_stat = renderText({
req(rvs$status$ms1_fine_stat)
})
output$ms1_eic_stat = renderText({
req(rvs$status$ms1_eic_stat)
})
output$rt_stat = renderText({
req(rvs$status$rt_stat)
})
output$ms1_int_thresh_stat = renderText({
req(rvs$status$ms1_int_thresh_stat)
})
output$ms2_int_thresh_stat = renderText({
req(rvs$status$ms2_int_thresh_stat)
})
output$s2n_stat = renderText({
req(rvs$status$s2n_stat)
})
output$ret_time_shift_tol_stat = renderText({
req(rvs$status$ret_time_shift_tol_stat)
})
## RENDER: COMPOUND INDEX
output$cindex = DT::renderDT({
tab = rf_get_cindex()
validate(need(NROW(tab)>0L,message="Need to prescreen, first."))
scroll_style_dt(tab,options=list(filter=T,ordering=F),
selection="single")
})
## RENDER: PLOTS
output$plot_eic_ms1 = renderPlot({
rf_plot_eic_ms1()
})
output$plot_eic_ms2 = renderPlot({
rf_plot_eic_ms2()
})
output$plot_spec_ms2 = renderPlot({
rf_plot_spec_ms2()
})
output$plot_hover_out = renderText({
inp1 = input$plot_hover[[1]]
inp2 = input$plot_hover[[2]]
res = if (all(!(c(is.null(inp1),is.null(inp2))))) {
paste0('(',
format(inp1,digits=5),
',',
format(inp2,digits=2,scientific=T),
')')
} else "Currently not in the plot."
})
output$plot_struct = renderPlot({
rf_plot_struct()
})
output$print_spec_tab = renderPrint({
notfound = "No MS2 spectrum has been found for this entry."
ms2tabsel = rf_get_ltab()
selMS2 = req(input$sel_spec)
if (NROW(ms2tabsel)!=0L) {
lval = lapply(ms2tabsel[item==(selMS2)],function(x) x)
ms2 = rvs$m$extr$ms2
kval = rf_get_cindex_kval()
allval = c(kval,lval)
## There can be some duplicates.
common = union(names(kval),names(lval))
allval = allval[common]
#Because in current implementation, kval may contain
#more than the names existing in extr$ms2. Also,
#BASE_KEY_MS2 does not contain `an', so we need to readd
#it.
key = unique(c(names(allval)[names(allval) %in% BASE_KEY_MS2],"an"))
kval2 = allval[key]
spec = get_data_from_key(ms2,kval2)[,.(mz,intensity)]
## as.character(lapply(1L:NROW(spec),function(nr) paste0(spec[nr,mz]," ",spec[nr,intensity])))
print(as.data.frame(spec),row.names=F)
} else {
notfound
}
})
output$dwn_proj_b = downloadHandler(
filename = function() {
tempfile(pattern="project_",fileext=".tar.gz")
},
content = function(file) {
shinymsg("Preparing project for download.")
pack_project(m=rvs$m,fn_arch=file)
shinymsg("Done preparing project for download.")
})
}
server
}